Merge branch 'master' into include_fs_config_in_api_config

pull/2101/head
Isaac Connor 2018-06-21 21:41:54 -04:00
commit 24ceb75936
70 changed files with 1448 additions and 1359 deletions

26
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,26 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- "Under Review"
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -36,8 +36,8 @@ env:
- SMPFLAGS=-j4
matrix:
- OS=el DIST=7
- OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack
- OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack
- OS=fedora DIST=28 DOCKER_REPO=knnniggett/packpack
- OS=ubuntu DIST=trusty
- OS=ubuntu DIST=xenial
- OS=ubuntu DIST=trusty ARCH=i386

View File

@ -559,7 +559,7 @@ CREATE TABLE `Servers` (
`Name` varchar(64) NOT NULL default '',
`State_Id` int(10) unsigned,
`Status` enum('Unknown','NotRunning','Running') NOT NULL default 'Unknown',
`Load` DECIMAL(5,1),
`CpuLoad` DECIMAL(5,1) default NULL,
`TotalMem` bigint unsigned default null,
`FreeMem` bigint unsigned default null,
`TotalSwap` bigint unsigned default null,

View File

@ -1,20 +0,0 @@
DROP TABLE IF EXISTS `Monitor_Status`;
CREATE TABLE `Monitor_Status` (
`MonitorId` int(10) unsigned NOT NULL,
`Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown',
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
PRIMARY KEY (`MonitorId`)
) ENGINE=MEMORY;
SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO';
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='/var/cache/zoneminder/events'
) > 0,
"SELECT 'Default Storage Area already exists.'",
"INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','/var/cache/zoneminder/events','Medium',NULL)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -3,6 +3,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
============
@ -80,7 +85,7 @@ New installs
When in doubt, proceed with the default:
sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/
sudo dnf install mod_ssl
sudo yum install mod_ssl
7. Now start the web server:

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

@ -1,7 +1,7 @@
Viewing Monitors
================
ZoneMinder allows you to view a live feed of your configured monitors. Once can access this view by clicking on the "Name" column of any of the monitors
ZoneMinder allows you to view a live feed of your configured monitors. One can access this view by clicking on the "Name" column of any of the monitors
.. image:: images/viewmonitor-main.png
:width: 500px

View File

@ -53,6 +53,7 @@ use HTTP::Cookies;
my $ChannelID = 1; # Usually...
my $DefaultFocusSpeed = 50; # Should be between 1 and 100
my $DefaultIrisSpeed = 50; # Should be between 1 and 100
my ($user,$pass,$host,$port);
sub open {
my $self = shift;
@ -65,7 +66,6 @@ sub open {
#
# Extract the username/password host/port from ControlAddress
#
my ($user,$pass,$host,$port);
if ( $self->{Monitor}{ControlAddress} =~ /^([^:]+):([^@]+)@(.+)/ ) { # user:pass@host...
$user = $1;
$pass = $2;
@ -126,6 +126,8 @@ sub PutCmd {
Control Device should be set to \"$1\".
Control Device currently set to \"$self->{Monitor}{ControlDevice}\".");
$self->{Monitor}{ControlDevice} = $1;
$self->{UA}->credentials("$host:$port", $self->{Monitor}{ControlDevice}, $user, $pass);
return PutCmd($self,$cmd,$content);
}
}
}

View File

@ -108,9 +108,18 @@ sub zmDbConnect {
, $Config{ZM_DB_PASS}
);
};
Error("Error reconnecting to db: errstr:$DBI::errstr error val:$@") if (! $dbh) or $@;
$dbh->trace(0) if $dbh;
}
if ( !$dbh or $@ ) {
Error("Error reconnecting to db: errstr:$DBI::errstr error val:$@");
} else {
$dbh->{AutoCommit} = 1;
Fatal('Can\'t set AutoCommit on in database connection')
unless $dbh->{AutoCommit};
$dbh->{mysql_auto_reconnect} = 1;
Fatal('Can\'t set mysql_auto_reconnect on in database connection')
unless $dbh->{mysql_auto_reconnect};
$dbh->trace( 0 );
} # end if success connecting
} # end if ! connected
return $dbh;
} # end sub zmDbConnect

View File

@ -602,7 +602,7 @@ Debug("Files to move @files");
die "Unable to add key for $filename";
}
my $duration = time - $starttime;
Debug("PUT to S3 " . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($size/$duration) . "/sec");
Debug("PUT to S3 " . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($duration?$size/$duration:$size) . '/sec');
} # end foreach file.
$moved = 1;

View File

@ -307,7 +307,7 @@ sub Sql {
if ( $self->{AutoMessage} ) {
# Include all events, including events that are still ongoing
# and have no EndTime yet
$sql .= ' AND ( '.$self->{Sql}.' )';
$sql .= ' WHERE ( '.$self->{Sql}.' )';
} else {
# Only include closed events (events with valid EndTime)
$sql .= ' WHERE (E.EndTime IS NOT NULL) AND ( '.$self->{Sql}.' )';

View File

@ -198,6 +198,7 @@ sub initialise( @ ) {
my $this = shift;
my %options = @_;
$this->{hasTerm} = -t STDERR;
$this->{id} = $options{id} if defined($options{id});
$this->{logPath} = $options{logPath} if defined($options{logPath});
@ -245,7 +246,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 +280,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 +324,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 +399,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};
}
@ -429,54 +442,10 @@ sub databaseLevel {
if ( $this->{databaseLevel} != $databaseLevel ) {
if ( $databaseLevel > NOLOG and $this->{databaseLevel} <= NOLOG ) {
if ( !$this->{dbh} ) {
my $socket;
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
$socket = ';mysql_socket='.$portOrSocket;
} else {
$socket = ';host='.$host.';port='.$portOrSocket;
}
} else {
$socket = ';host='.$Config{ZM_DB_HOST};
}
my $sslOptions = '';
if ( $Config{ZM_DB_SSL_CA_CERT} ) {
$sslOptions = join(';','',
'mysql_ssl=1',
'mysql_ssl_ca_file='.$Config{ZM_DB_SSL_CA_CERT},
'mysql_ssl_client_key='.$Config{ZM_DB_SSL_CLIENT_KEY},
'mysql_ssl_client_cert='.$Config{ZM_DB_SSL_CLIENT_CERT}
);
}
$this->{dbh} = DBI->connect( 'DBI:mysql:database='.$Config{ZM_DB_NAME}
.$socket.$sslOptions
, $Config{ZM_DB_USER}
, $Config{ZM_DB_PASS}
);
if ( !$this->{dbh} ) {
$databaseLevel = NOLOG;
Error( 'Unable to write log entries to DB, can\'t connect to database '
.$Config{ZM_DB_NAME}
.' on host '
.$Config{ZM_DB_HOST}
);
} else {
$this->{dbh}->{AutoCommit} = 1;
Fatal('Can\'t set AutoCommit on in database connection' )
unless( $this->{dbh}->{AutoCommit} );
$this->{dbh}->{mysql_auto_reconnect} = 1;
Fatal('Can\'t set mysql_auto_reconnect on in database connection' )
unless( $this->{dbh}->{mysql_auto_reconnect} );
$this->{dbh}->trace( 0 );
}
$this->{dbh} = ZoneMinder::Database::zmDbConnect();
}
} elsif ( $databaseLevel <= NOLOG && $this->{databaseLevel} > NOLOG ) {
if ( $this->{dbh} ) {
$this->{dbh}->disconnect();
undef($this->{dbh});
}
undef($this->{dbh});
}
$this->{databaseLevel} = $databaseLevel;
}
@ -586,29 +555,34 @@ sub logPrint {
print(STDERR $message) if $level <= $this->{termLevel};
if ( $level <= $this->{databaseLevel} ) {
if ( ( $this->{dbh} and $this->{dbh}->ping() ) or ( $this->{dbh} = 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
, $code
, $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);
@ -172,7 +172,7 @@ if ( !$server_up ) {
exit();
} elsif ( $command ne 'startup' ) {
print("Unable to connect to server using socket at " . SOCK_FILE . "\n");
exit( -1 );
exit(-1);
}
# The server isn't there
@ -210,7 +210,7 @@ if ( ($command eq 'check') && !$daemon ) {
# The server is there, connect to it
CLIENT->autoflush();
my $message = join(';', $command, ( $daemon ? $daemon : () ), @args );
my $message = join(';', $command, ( $daemon ? $daemon : () ), @args);
print(CLIENT $message);
shutdown(CLIENT, 1);
while( my $line = <CLIENT> ) {
@ -242,9 +242,20 @@ use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sendin
our %cmd_hash;
our %pid_hash;
our %terminating_processes;
our %pids_to_reap;
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 +263,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,24 +272,16 @@ 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 . ": $!");
listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
$SIG{CHLD} = \&reaper;
$SIG{CHLD} = \&chld_sig_handler;
$SIG{INT} = \&shutdown_sig_handler;
$SIG{TERM} = \&shutdown_sig_handler;
$SIG{ABRT} = \&shutdown_sig_handler;
@ -287,26 +292,19 @@ sub run {
my $win = $rin;
my $ein = $win;
my $timeout = 1;
my $Server = undef;
my $secs_count = 0;
if ( $Config{ZM_SERVER_ID} ) {
require ZoneMinder::Server;
$Server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
dPrint(ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name});
}
while( !$zm_terminate ) {
if ( $Config{ZM_SERVER_ID} ) {
if ( ! ( $secs_count % 60 ) ) {
Debug("Connecting");
while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) {
Warning("Not connected to db ($dbh)".($dbh?" ping(".$dbh->ping().")":''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting');
Warning("Not connected to db ($dbh)".($dbh?' ping('.$dbh->ping().')':''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting');
$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 +313,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);
@ -337,7 +334,7 @@ Debug("Aftere select $nfound");
# Do nothing, this is all we're here for
dPrint(ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n");
} elsif ( $command eq 'shutdown' ) {
# Breka out of while loop
# Break out of while loop
last;
} elsif ( $command eq 'check' ) {
check($daemon, @args);
@ -370,10 +367,9 @@ Debug("Aftere select $nfound");
#print( "Select timed out\n" );
}
Debug("restartPending");
restartPending();
Debug("check_for_processes_to_kill");
check_for_processes_to_kill();
check_for_processes_to_kill() if %terminating_processes;
reaper() if %pids_to_reap;
} # end while
@ -382,7 +378,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());
}
@ -391,6 +387,7 @@ Debug("check_for_processes_to_kill");
}
sub cPrint {
# One thought here, if no client exists to read these... does it block?
if ( fileno(CLIENT) ) {
print CLIENT @_
}
@ -399,9 +396,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;
if ( fileno(CLIENT) ) {
print CLIENT @_
}
cPrint(@_);
if ( $logLevel == ZoneMinder::Logger::DEBUG ) {
Debug(@_);
} elsif ( $logLevel == ZoneMinder::Logger::INFO ) {
@ -435,10 +430,12 @@ 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");
# Apparently the child closing the db connection can affect the parent.
zmDbDisconnect();
if ( my $cpid = fork() ) {
$dbh = zmDbConnect(1);
# This logReinit is required. Not sure why.
logReinit();
@ -453,9 +450,10 @@ sub start {
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!");
Debug("unblocko child");
} elsif ( defined($cpid) ) {
# Force reconnection to the db.
# Child process
# Force reconnection to the db. $dbh got copied, but isn't really valid anymore.
$dbh = zmDbConnect(1);
logReinit();
@ -472,7 +470,7 @@ sub start {
my @good_args;
foreach my $arg ( @args ) {
# Detaint arguments, if they look ok
# Detaint arguments, if they look ok
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
push @good_args, $1;
} else {
@ -488,8 +486,8 @@ sub start {
POSIX::close($fd++);
}
# Child process
$SIG{CHLD} = 'DEFAULT';
$SIG{HUP} = 'DEFAULT';
$SIG{INT} = 'DEFAULT';
$SIG{TERM} = 'DEFAULT';
$SIG{ABRT} = 'DEFAULT';
@ -635,15 +633,25 @@ sub shutdown_sig_handler {
$zm_terminate = 1;
}
sub reaper {
sub chld_sig_handler {
my $saved_status = $!;
# Wait for a child to terminate
while ( (my $cpid = waitpid(-1, WNOHANG)) > 0 ) {
my $status = $?;
$pids_to_reap{$cpid} = { status=>$?, stopped=>time() };
} # end while waitpid
$SIG{CHLD} = \&chld_sig_handler;
$! = $saved_status;
}
sub reaper {
foreach my $cpid ( keys %pids_to_reap ) {
my $process = $pid_hash{$cpid};
Debug("Reaping pricess $cpid");
delete $pid_hash{$cpid};
my $reap_info = $pids_to_reap{$cpid};
my ( $status, $stopped ) = @$reap_info{'status','stopped'};
delete $pids_to_reap{$cpid};
if ( !$process ) {
dPrint(ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n");
@ -652,7 +660,7 @@ sub reaper {
delete $terminating_processes{$$process{command}};
delete $$process{term_sent_at};
$process->{stopped} = time();
$process->{stopped} = $stopped;
$process->{runtime} = ($process->{stopped}-$process->{started});
delete $process->{pid};
@ -705,11 +713,9 @@ sub reaper {
} else {
delete $cmd_hash{$$process{command}};
}
} # end while waitpid
$SIG{CHLD} = \&reaper;
$! = $saved_status;
Debug("Leaving reaper");
}
Debug("Reaping pricess $cpid");
} # end foreach pid_to_reap
} # end sub reaper
sub restartPending {
# Restart any pending processes, we list them first because cmd_hash may change in foreach
@ -720,7 +726,6 @@ sub restartPending {
start($process->{daemon}, @{$process->{args}});
}
}
Debug("done restartPending");
}
sub shutdownAll {
@ -730,6 +735,8 @@ sub shutdownAll {
send_stop(1, $pid_hash{$pid});
}
while ( keys %terminating_processes ) {
reaper() if %pids_to_reap;
check_for_processes_to_kill();
if ( %terminating_processes ) {
Debug("Still " . %terminating_processes . ' to die. sleeping');
@ -808,7 +815,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

@ -309,7 +309,7 @@ sub checkFilter {
}
if ( $Config{ZM_OPT_MESSAGE} && $filter->{AutoMessage} ) {
if ( !$event->{Messaged} ) {
$delete_ok = undef if !sendMessage($filter, $event);
$delete_ok = undef if !sendMessage($filter, $Event);
}
}
if ( $Config{ZM_OPT_UPLOAD} && $filter->{AutoUpload} ) {
@ -833,7 +833,7 @@ sub sendEmail {
sub sendMessage {
my $filter = shift;
my $event = shift;
my $Event = shift;
if ( ! $Config{ZM_FROM_EMAIL} ) {
Error('No from email address defined, not sending message');
@ -846,10 +846,10 @@ sub sendMessage {
Info('Creating notification message');
my $subject = substituteTags($Config{ZM_MESSAGE_SUBJECT}, $filter, $event);
my $subject = substituteTags($Config{ZM_MESSAGE_SUBJECT}, $filter, $Event);
return 0 if !$subject;
my @attachments;
my $body = substituteTags($Config{ZM_MESSAGE_BODY}, $filter, $event, \@attachments);
my $body = substituteTags($Config{ZM_MESSAGE_BODY}, $filter, $Event, \@attachments);
return 0 if !$body;
Info("Sending notification message '$subject'");
@ -930,11 +930,11 @@ sub sendMessage {
my $sql = 'UPDATE Events SET Messaged = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($event->{Id})
my $res = $sth->execute($Event->{Id})
or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
return 1;
}
} # end sub sendMessage
sub executeCommand {
my $filter = shift;

View File

@ -69,41 +69,44 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
logInit();
logSetSignal();
Info( "Watchdog starting, pausing for ".START_DELAY." seconds\n" );
sleep( START_DELAY );
Info('Watchdog starting, pausing for '.START_DELAY.' seconds');
sleep(START_DELAY);
my $dbh = zmDbConnect();
my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'SELECT * FROM Monitors';
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());
while( 1 ) {
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
or Fatal( "Can't execute: ".$sth->errstr() );
or Fatal('Can\'t execute: '.$sth->errstr());
while( my $monitor = $sth->fetchrow_hashref() ) {
my $now = time();
next if $monitor->{Function} eq 'None';
next if $monitor->{Type} eq 'WebSite';
my $now = time();
my $restart = 0;
if ( zmMemVerify( $monitor ) ) {
if ( zmMemVerify($monitor) ) {
# Check we have got an image recently
my $capture_time = zmGetLastWriteTime( $monitor );
my $capture_time = zmGetLastWriteTime($monitor);
if ( !defined($capture_time) ) {
# Can't read from shared data
Debug( "LastWriteTime is not defined." );
zmMemInvalidate( $monitor );
Debug('LastWriteTime is not defined.');
zmMemInvalidate($monitor);
next;
}
Debug( "LastWriteTime is = $capture_time." );
Debug("Monitor $$monitor{Id} LastWriteTime is $capture_time.");
if ( !$capture_time ) {
my $startup_time = zmGetStartupTime( $monitor );
my $startup_time = zmGetStartupTime($monitor);
if ( $now - $startup_time > $Config{ZM_WATCH_MAX_DELAY} ) {
Info( "Restarting capture daemon for ".$monitor->{Name}.", no image since startup. Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}\n" );
Info(
"Restarting capture daemon for $$monitor{Name}, no image since startup. ".
"Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}"
);
$restart = 1;
} else {
# We can't get the last capture time so can't be sure it's died, it might just be starting up.
zmMemInvalidate( $monitor );
zmMemInvalidate($monitor);
next;
}
}
@ -115,44 +118,44 @@ while( 1 ) {
: $Config{ZM_WATCH_MAX_DELAY}
;
my $image_delay = $now-$capture_time;
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
Debug("Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay");
if ( $image_delay > $max_image_delay ) {
Info( "Restarting capture daemon for "
.$monitor->{Name}.", time since last capture $image_delay seconds ($now-$capture_time)\n"
Info("Restarting capture daemon for "
.$monitor->{Name}.", time since last capture $image_delay seconds ($now-$capture_time)"
);
$restart = 1;
}
} # end if ! restart
} else {
Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" );
Info("Restarting capture daemon for $monitor->{Name}, shared data not valid");
$restart = 1;
}
if ( $restart ) {
# Because zma depends on zmc, and zma can hold the shm in place, preventing zmc from using the space in /dev/shm,
# we need to stop zma before restarting zmc.
runCommand( "zmdc.pl stop zma -m $$monitor{Id}" ) if $monitor->{Function} ne 'Monitor';
runCommand("zmdc.pl stop zma -m $$monitor{Id}") if $monitor->{Function} ne 'Monitor';
my $command;
if ( $monitor->{Type} eq 'Local' ) {
$command = "zmdc.pl restart zmc -d $monitor->{Device}";
} else {
$command = "zmdc.pl restart zmc -m $monitor->{Id}";
}
runCommand( $command );
runCommand( "zmdc.pl start zma -m $$monitor{Id}" ) if $monitor->{Function} ne 'Monitor';
runCommand($command);
runCommand("zmdc.pl start zma -m $$monitor{Id}") if $monitor->{Function} ne 'Monitor';
} elsif ( $monitor->{Function} ne 'Monitor' ) {
# Now check analysis daemon
$restart = 0;
# Check we have got an image recently
my $image_time = zmGetLastReadTime( $monitor );
my $image_time = zmGetLastReadTime($monitor);
if ( !defined($image_time) ) {
# Can't read from shared data
$restart = 1;
Error("Error reading shared data for $$monitor{Id} $$monitor{Name}\n");
Error("Error reading shared data for $$monitor{Id} $$monitor{Name}");
} elsif ( !$image_time ) {
# We can't get the last capture time so can't be sure it's died.
$restart = 1;
Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero.\n");
Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero.");
} else {
my $max_image_delay = ( $monitor->{MaxFPS}
@ -162,29 +165,29 @@ while( 1 ) {
: $Config{ZM_WATCH_MAX_DELAY}
;
my $image_delay = $now-$image_time;
Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" );
Debug("Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay");
if ( $image_delay > $max_image_delay ) {
Info( "Analysis daemon for $$monitor{Id} $$monitor{Name} needs restarting,"
." time since last analysis $image_delay seconds ($now-$image_time)\n"
Info("Analysis daemon for $$monitor{Id} $$monitor{Name} needs restarting,"
." time since last analysis $image_delay seconds ($now-$image_time)"
);
$restart = 1;
}
}
if ( $restart ) {
Info( "Restarting analysis daemon for $$monitor{Id} $$monitor{Name}\n");
Info("Restarting analysis daemon for $$monitor{Id} $$monitor{Name}");
my $command = 'zmdc.pl restart zma -m '.$monitor->{Id};
runCommand( $command );
runCommand($command);
} # end if restart
} # end if check analysis daemon
# Prevent open handles building up if we have connect to shared memory
zmMemInvalidate( $monitor ); # Close our file handle to the zmc process we are about to end
zmMemInvalidate($monitor); # Close our file handle to the zmc process we are about to end
} # end foreach monitor
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
sleep($Config{ZM_WATCH_CHECK_INTERVAL});
} # end while (1)
Info( "Watchdog exiting\n" );
Info("Watchdog exiting");
exit();
1;

View File

@ -85,7 +85,10 @@ public:
bool CanCapture() const { return( capture ); }
bool SupportsNativeVideo() const { return( (type == FFMPEG_SRC )||(type == REMOTE_SRC)); }
bool SupportsNativeVideo() const {
return (type == FFMPEG_SRC);
//return (type == FFMPEG_SRC )||(type == REMOTE_SRC);
}
virtual int PrimeCapture() { return( 0 ); }
virtual int PreCapture()=0;

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

@ -69,7 +69,8 @@ Event::Event(
untimedEvent = true;
start_time = now;
} else if ( start_time.tv_sec > now.tv_sec ) {
Error("StartTime in the future %u.%u > %u.%u",
Error(
"StartTime in the future %u.%u > %u.%u",
start_time.tv_sec, start_time.tv_usec, now.tv_sec, now.tv_usec
);
start_time = now;
@ -520,7 +521,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
}
} else {
//If this is the first frame, we should add a thumbnail to the event directory
if ( frames == 1 ) {
if ( frames == 1 || score > (int)max_score ) {
char snapshot_file[PATH_MAX];
snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path);
WriteFrameImage(image, timestamp, snapshot_file);

View File

@ -24,7 +24,6 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
Group::Group() {
Warning("Instantiating default Group Object. Should not happen.");
@ -33,30 +32,31 @@ Group::Group() {
strcpy(name, "Default");
}
Group::Group( MYSQL_ROW &dbrow ) {
// The order of columns is: Id, ParentId, Name
Group::Group(MYSQL_ROW &dbrow) {
unsigned int index = 0;
id = atoi( dbrow[index++] );
parent_id = dbrow[index] ? atoi( dbrow[index] ): 0; index++;
strncpy( name, dbrow[index++], sizeof(name)-1 );
id = atoi(dbrow[index++]);
parent_id = dbrow[index] ? atoi(dbrow[index]): 0; index++;
strncpy(name, dbrow[index++], sizeof(name)-1);
}
/* If a zero or invalid p_id is passed, then the old default path will be assumed. */
Group::Group( unsigned int p_id ) {
Group::Group(unsigned int p_id) {
id = 0;
if ( p_id ) {
char sql[ZM_SQL_SML_BUFSIZ];
snprintf( sql, sizeof(sql), "SELECT Id, ParentId, Name FROM Group WHERE Id=%d", p_id );
Debug(2,"Loading Group for %d using %s", p_id, sql );
snprintf(sql, sizeof(sql), "SELECT Id, ParentId, Name FROM Group WHERE Id=%d", p_id);
Debug(2,"Loading Group for %d using %s", p_id, sql);
zmDbRow dbrow;
if ( ! dbrow.fetch( sql ) ) {
Error( "Unable to load group for id %d: %s", p_id, mysql_error( &dbconn ) );
if ( !dbrow.fetch(sql) ) {
Error("Unable to load group for id %d: %s", p_id, mysql_error(&dbconn));
} else {
unsigned int index = 0;
id = atoi( dbrow[index++] );
parent_id = dbrow[index] ? atoi( dbrow[index] ): 0; index++;
strncpy( name, dbrow[index++], sizeof(name)-1 );
Debug( 1, "Loaded Group area %d '%s'", id, this->Name() );
id = atoi(dbrow[index++]);
parent_id = dbrow[index] ? atoi(dbrow[index]): 0; index++;
strncpy(name, dbrow[index++], sizeof(name)-1);
Debug(1, "Loaded Group area %d '%s'", id, this->Name());
}
}
if ( ! id ) {

View File

@ -551,7 +551,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
} else {
Level tempDatabaseLevel = mDatabaseLevel;
databaseLevel(NOLOG);
Error("Can't insert log entry: sql(%s) error(db is locked)", sql);
Error("Can't insert log entry: sql(%s) error(db is locked)", logString);
databaseLevel(tempDatabaseLevel);
}
}

View File

@ -1397,9 +1397,12 @@ bool Monitor::Analyse() {
int motion_score = last_motion_score;
if ( !(image_count % (motion_frame_skip+1) ) ) {
// Get new score.
motion_score = DetectMotion( *snap_image, zoneSet );
motion_score = DetectMotion(*snap_image, zoneSet);
Debug( 3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score );
Debug(3,
"After motion detection, last_motion_score(%d), new motion score(%d)",
last_motion_score, motion_score
);
// Why are we updating the last_motion_score too?
last_motion_score = motion_score;
}
@ -1542,15 +1545,16 @@ bool Monitor::Analyse() {
} // end if ! event
}
if ( score ) {
if ( (state == IDLE || state == TAPE || state == PREALARM ) ) {
if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) {
Info( "%s: %03d - Gone into alarm state", name, image_count );
if ( state == IDLE || state == TAPE || state == PREALARM ) {
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count) ) {
Info("%s: %03d - Gone into alarm state %u > %u",
name, image_count, Event::PreAlarmCount(), alarm_frame_count);
shared_data->state = state = ALARM;
if ( signal_change || (function != MOCORD && state != ALERT) ) {
int pre_index;
int pre_event_images = pre_event_count;
if ( analysis_fps ) {
if ( analysis_fps && pre_event_count ) {
// If analysis fps is set,
// compute the index for pre event images in the dedicated buffer
pre_index = pre_event_buffer_count ? image_count%pre_event_buffer_count : 0;
@ -1563,7 +1567,7 @@ bool Monitor::Analyse() {
pre_event_images--;
}
event = new Event( this, *(pre_event_buffer[pre_index].timestamp), cause, noteSetMap );
event = new Event(this, *(pre_event_buffer[pre_index].timestamp), cause, noteSetMap);
} else {
// If analysis fps is not set (analysis performed at capturing framerate),
// compute the index for pre event images in the capturing buffer
@ -1580,7 +1584,7 @@ bool Monitor::Analyse() {
pre_event_images--;
}
event = new Event( this, *(image_buffer[pre_index].timestamp), cause, noteSetMap );
event = new Event(this, *(image_buffer[pre_index].timestamp), cause, noteSetMap);
}
shared_data->last_event = event->Id();
// lets construct alarm cause. It will contain cause + names of zones alarmed
@ -2799,19 +2803,21 @@ Monitor::Snapshot *Monitor::getSnapshot() const {
return &image_buffer[ shared_data->last_write_index%image_buffer_count ];
}
std::list<Group *> Monitor::Groups() {
std::vector<Group *> Monitor::Groups() {
// At the moment, only load groups once.
if ( ! groups.size() ) {
std::string sql = stringtf("SELECT GroupId FROM Groups_Monitors WHERE MonitorId=%d",id);
std::string sql = stringtf(
"SELECT Id,ParentId,Name FROM Groups WHERE Groups.Id IN "
"(SELECT GroupId FROM Groups_Monitors WHERE MonitorId=%d)",id);
MYSQL_RES *result = zmDbFetch(sql.c_str());
if ( !result ) {
Error("Can't load groups: %s", mysql_error(&dbconn));
return groups;
}
int n_groups = mysql_num_rows(result);
Debug( 1, "Got %d groups", n_groups );
Debug(1, "Got %d groups", n_groups);
while ( MYSQL_ROW dbrow = mysql_fetch_row(result) ) {
groups.push_back( new Group(dbrow) );
groups.push_back(new Group(dbrow));
}
if ( mysql_errno(&dbconn) ) {
Error("Can't fetch row: %s", mysql_error(&dbconn));
@ -2820,3 +2826,13 @@ std::list<Group *> Monitor::Groups() {
}
return groups;
}
StringVector Monitor::GroupNames() {
StringVector groupnames;
for(Group * g: Groups()) {
groupnames.push_back(std::string(g->Name()));
Debug(1,"Groups: %s", g->Name());
}
return groupnames;
}

View File

@ -344,7 +344,7 @@ protected:
int n_linked_monitors;
MonitorLink **linked_monitors;
std::list<Group *> groups;
std::vector<Group *> groups;
public:
explicit Monitor( int p_id );
@ -506,7 +506,8 @@ public:
bool DumpSettings( char *output, bool verbose );
void DumpZoneImage( const char *zone_string=0 );
std::list<Group *> Groups();
std::vector<Group *> Groups();
StringVector GroupNames();
static int LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose); // Returns # of Monitors loaded, 0 on failure.
#if ZM_HAS_V4L

View File

@ -533,7 +533,7 @@ int RemoteCameraRtsp::CaptureAndRecord(Image &image, timeval recording, char* ev
zm_av_packet_unref( &packet );
} // end while ! framecomplete and buffer.size()
if(frameComplete)
return (0);
return (1);
} /* getFrame() */
} // end while true

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

@ -94,26 +94,22 @@ const std::string stringtf( const std::string format, ... )
return( tempString );
}
bool startsWith( const std::string &haystack, const std::string &needle )
{
return( haystack.substr( 0, needle.length() ) == needle );
bool startsWith(const std::string &haystack, const std::string &needle) {
return( haystack.substr(0, needle.length()) == needle );
}
StringVector split( const std::string &string, const std::string &chars, int limit )
{
StringVector split(const std::string &string, const std::string &chars, int limit) {
StringVector stringVector;
std::string tempString = string;
std::string::size_type startIndex = 0;
std::string::size_type endIndex = 0;
//Info( "Looking for '%s' in '%s', limit %d", chars.c_str(), string.c_str(), limit );
do
{
do {
// Find delimiters
endIndex = string.find_first_of( chars, startIndex );
//Info( "Got endIndex at %d", endIndex );
if ( endIndex > 0 )
{
if ( endIndex > 0 ) {
//Info( "Adding '%s'", string.substr( startIndex, endIndex-startIndex ).c_str() );
stringVector.push_back( string.substr( startIndex, endIndex-startIndex ) );
}
@ -121,8 +117,7 @@ StringVector split( const std::string &string, const std::string &chars, int lim
break;
// Find non-delimiters
startIndex = tempString.find_first_not_of( chars, endIndex );
if ( limit && (stringVector.size() == (unsigned int)(limit-1)) )
{
if ( limit && (stringVector.size() == (unsigned int)(limit-1)) ) {
stringVector.push_back( string.substr( startIndex ) );
break;
}
@ -130,22 +125,21 @@ StringVector split( const std::string &string, const std::string &chars, int lim
} while ( startIndex != std::string::npos );
//Info( "Finished with %d strings", stringVector.size() );
return( stringVector );
return stringVector;
}
const std::string join(const StringVector &v, const char * delim ) {
const std::string join(const StringVector &v, const char * delim=",") {
std::stringstream ss;
for(size_t i = 0; i < v.size(); ++i) {
if(i != 0)
ss << ",";
for (size_t i = 0; i < v.size(); ++i) {
if ( i != 0 )
ss << delim;
ss << v[i];
}
return ss.str();
}
const std::string base64Encode( const std::string &inString )
{
const std::string base64Encode(const std::string &inString) {
static char base64_table[64] = { '\0' };
if ( !base64_table[0] )

View File

@ -17,12 +17,15 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#define __STDC_FORMAT_MACROS 1
#include <cinttypes>
#include "zm.h"
#include "zm_db.h"
#include "zm_zone.h"
#include "zm_image.h"
#include "zm_monitor.h"
void Zone::Setup(
Monitor *p_monitor,
int p_id,

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

@ -257,11 +257,14 @@ execpackpack () {
fi
if [ "${TRAVIS}" == "true" ]; then
utils/packpack/heartbeat.sh &
mypid=$!
packpack/packpack $parms > buildlog.txt 2>&1
kill $mypid
tail -n 3000 buildlog.txt | grep -v ONVIF
# Travis will fail the build if the output gets too long
# To mitigate that, use grep to filter out some of the noise
if [ "${ARCH}" != "armhf" ]; then
packpack/packpack $parms | grep -Ev '^(-- Installing:|-- Up-to-date:|Skip blib|Manifying|Installing /build|cp lib|writing output...|copying images...|reading sources...|[Working])'
else
# Travis never ceases to amaze. For the case of arm emulation, Travis fails the build due to too little output over a 10 minute period. Facepalm.
packpack/packpack $parms | grep -Ev '^(-- Installing:|-- Up-to-date:|Skip blib|Installing /build|cp lib|writing output...|copying images...|reading sources...|[Working])'
fi
else
packpack/packpack $parms
fi

View File

@ -4,443 +4,404 @@
# These are the valid columns that you can filter on.
$filterFields = array( 'Component', 'ServerId', 'Pid', 'Level', 'File', 'Line' );
switch ( $_REQUEST['task'] )
{
case 'create' :
{
// Silently ignore bogus requests
if ( !empty($_POST['level']) && !empty($_POST['message']) )
{
logInit( array( 'id' => "web_js" ) );
switch ( $_REQUEST['task'] ) {
case 'create' :
{
// Silently ignore bogus requests
if ( !empty($_POST['level']) && !empty($_POST['message']) ) {
logInit(array('id'=>'web_js'));
$string = $_POST['message'];
$string = $_POST['message'];
$file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/\w+\//', '', $_POST['file'] ) : '';
if ( !empty( $_POST['line'] ) )
$line = $_POST['line'];
else
$line = NULL;
$file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/\w+\//', '', $_POST['file'] ) : '';
if ( !empty( $_POST['line'] ) )
$line = $_POST['line'];
else
$line = NULL;
$levels = array_flip(Logger::$codes);
if ( !isset($levels[$_POST['level']]) )
Panic( "Unexpected logger level '".$_POST['level']."'" );
$level = $levels[$_POST['level']];
Logger::fetch()->logPrint( $level, $string, $file, $line );
}
ajaxResponse();
break;
$levels = array_flip(Logger::$codes);
if ( !isset($levels[$_POST['level']]) )
Panic("Unexpected logger level '".$_POST['level']."'");
$level = $levels[$_POST['level']];
Logger::fetch()->logPrint( $level, $string, $file, $line );
}
case 'query' :
{
if ( !canView( 'System' ) )
ajaxError( 'Insufficient permissions to view log entries' );
ajaxResponse();
break;
}
case 'query' :
{
if ( !canView('System') )
ajaxError('Insufficient permissions to view log entries');
$servers = Server::find_all();
$servers_by_Id = array();
# There is probably a better way to do this.
foreach ( $servers as $server ) {
$servers_by_Id[$server->Id()] = $server;
}
$minTime = isset($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL;
$maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL;
$limit = 100;
if ( isset($_REQUEST['limit']) ) {
if ( ( !is_integer( $_REQUEST['limit'] ) and !ctype_digit($_REQUEST['limit']) ) ) {
Error("Invalid value for limit " . $_REQUEST['limit'] );
} else {
$limit = $_REQUEST['limit'];
}
}
$sortField = 'TimeKey';
if ( isset($_REQUEST['sortField']) ) {
if ( ! in_array( $_REQUEST['sortField'], $filterFields ) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) {
Error("Invalid sort field " . $_REQUEST['sortField'] );
} else {
$sortField = $_REQUEST['sortField'];
}
}
$sortOrder = (isset($_REQUEST['sortOrder']) and $_REQUEST['sortOrder']) == 'asc' ? 'asc':'desc';
$filter = isset($_REQUEST['filter'])?$_REQUEST['filter']:array();
$total = dbFetchOne( 'SELECT count(*) AS Total FROM Logs', 'Total' );
$sql = 'SELECT * FROM Logs';
$where = array();
$values = array();
if ( $minTime ) {
$where[] = "TimeKey > ?";
$values[] = $minTime;
} elseif ( $maxTime ) {
$where[] = "TimeKey < ?";
$values[] = $maxTime;
}
foreach ( $filter as $field=>$value ) {
if ( ! in_array( $field, $filterFields ) ) {
Error("$field is not in valid filter fields");
continue;
}
if ( $field == 'Level' ){
$where[] = $field." <= ?";
$values[] = $value;
} else {
$where[] = $field." = ?";
$values[] = $value;
}
}
if ( count($where) )
$sql.= ' WHERE '.join( ' AND ', $where );
$sql .= " order by ".$sortField." ".$sortOrder." limit ".$limit;
$logs = array();
foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) {
$log['DateTime'] = preg_replace( '/^\d+/', strftime( '%Y-%m-%d %H:%M:%S', intval($log['TimeKey']) ), $log['TimeKey'] );
$log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : '';
$log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message'] );
$logs[] = $log;
}
$options = array();
$where = array();
$values = array();
foreach( $filter as $field=>$value ) {
if ( $field == 'Level' ) {
$where[$field] = $field." <= ?";
$values[$field] = $value;
} else {
$where[$field] = $field." = ?";
$values[$field] = $value;
}
}
foreach( $filterFields as $field )
{
$sql = "SELECT DISTINCT $field FROM Logs WHERE NOT isnull($field)";
$fieldWhere = array_diff_key( $where, array( $field=>true ) );
$fieldValues = array_diff_key( $values, array( $field=>true ) );
if ( count($fieldWhere) )
$sql.= " AND ".join( ' AND ', $fieldWhere );
$sql.= " ORDER BY $field ASC";
if ( $field == 'Level' )
{
foreach( dbFetchAll( $sql, $field, array_values($fieldValues) ) as $value )
if ( $value <= Logger::INFO )
$options[$field][$value] = Logger::$codes[$value];
else
$options[$field][$value] = "DB".$value;
}
elseif ( $field == 'ServerId' )
{
foreach( dbFetchAll( $sql, $field, array_values($fieldValues) ) as $value )
$options['ServerId'][$value] = ( $value and isset($servers_by_Id[$value]) ) ? $servers_by_Id[$value]->Name() : '';
}
else
{
foreach( dbFetchAll( $sql, $field, array_values( $fieldValues ) ) as $value )
if ( $value != '' )
$options[$field][] = $value;
}
}
if ( count($filter) )
{
$sql = "SELECT count(*) AS Available FROM Logs WHERE ".join( ' AND ', $where );
$available = dbFetchOne( $sql, 'Available', array_values($values) );
}
ajaxResponse( array(
'updated' => preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG ),
'total' => $total,
'available' => isset($available)?$available:$total,
'logs' => $logs,
'state' => logState(),
'options' => $options
) );
break;
$servers = Server::find_all();
$servers_by_Id = array();
# There is probably a better way to do this.
foreach ( $servers as $server ) {
$servers_by_Id[$server->Id()] = $server;
}
case 'export' :
$minTime = isset($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL;
$maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL;
$limit = 100;
if ( isset($_REQUEST['limit']) ) {
if ( ( !is_integer( $_REQUEST['limit'] ) and !ctype_digit($_REQUEST['limit']) ) ) {
Error('Invalid value for limit ' . $_REQUEST['limit'] );
} else {
$limit = $_REQUEST['limit'];
}
}
$sortField = 'TimeKey';
if ( isset($_REQUEST['sortField']) ) {
if ( ! in_array( $_REQUEST['sortField'], $filterFields ) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) {
Error("Invalid sort field " . $_REQUEST['sortField'] );
} else {
$sortField = $_REQUEST['sortField'];
}
}
$sortOrder = (isset($_REQUEST['sortOrder']) and $_REQUEST['sortOrder']) == 'asc' ? 'asc':'desc';
$filter = isset($_REQUEST['filter'])?$_REQUEST['filter']:array();
$total = dbFetchOne('SELECT count(*) AS Total FROM Logs', 'Total');
$sql = 'SELECT * FROM Logs';
$where = array();
$values = array();
if ( $minTime ) {
$where[] = 'TimeKey > ?';
$values[] = $minTime;
} elseif ( $maxTime ) {
$where[] = 'TimeKey < ?';
$values[] = $maxTime;
}
foreach ( $filter as $field=>$value ) {
if ( ! in_array($field, $filterFields) ) {
Error("$field is not in valid filter fields");
continue;
}
if ( $field == 'Level' ){
$where[] = $field.' <= ?';
$values[] = $value;
} else {
$where[] = $field.' = ?';
$values[] = $value;
}
}
$options = array();
if ( count($where) )
$sql.= ' WHERE '.join( ' AND ', $where );
$sql .= ' ORDER BY '.$sortField.' '.$sortOrder.' LIMIT '.$limit;
$logs = array();
foreach ( dbFetchAll($sql, NULL, $values) as $log ) {
$log['DateTime'] = preg_replace('/^\d+/', strftime('%Y-%m-%d %H:%M:%S', intval($log['TimeKey'])), $log['TimeKey']);
$log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : '';
$log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message'] );
foreach( $filterFields as $field ) {
if ( ! isset( $options[$field] ) )
$options[$field] = array();
$value = $log[$field];
if ( $field == 'Level' ) {
if ( $value <= Logger::INFO )
$options[$field][$value] = Logger::$codes[$value];
else
$options[$field][$value] = 'DB'.$value;
} else if ( $field == 'ServerId' ) {
$options['ServerId'][$value] = ( $value and isset($servers_by_Id[$value]) ) ? $servers_by_Id[$value]->Name() : '';
} else if ( isset($log[$field]) ) {
$options[$field][$log[$field]] = $log[$field];
}
}
$logs[] = $log;
}
$available = count($logs);
ajaxResponse( array(
'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG)?strftime(DATE_FMT_CONSOLE_LONG):date(DATE_FMT_CONSOLE_LONG),
'total' => $total,
'available' => isset($available)?$available:$total,
'logs' => $logs,
'state' => logState(),
'options' => $options
) );
break;
}
case 'export' :
{
if ( !canView('System') )
ajaxError('Insufficient permissions to export logs');
$minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL;
$maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL;
if ( !is_null($minTime) && !is_null($maxTime) && $minTime > $maxTime ) {
$tempTime = $minTime;
$minTime = $maxTime;
$maxTime = $tempTime;
}
//$limit = isset($_POST['limit'])?$_POST['limit']:1000;
$filter = isset($_POST['filter'])?$_POST['filter']:array();
$sortField = 'TimeKey';
if ( isset($_POST['sortField']) ) {
if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) {
Error("Invalid sort field " . $_POST['sortField'] );
} else {
$sortField = $_POST['sortField'];
}
}
$sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc';
$servers = Server::find_all();
$servers_by_Id = array();
# There is probably a better way to do this.
foreach ( $servers as $server ) {
$servers_by_Id[$server->Id()] = $server;
}
$sql = 'SELECT * FROM Logs';
$where = array();
$values = array();
if ( $minTime ) {
preg_match('/(.+)(\.\d+)/', $minTime, $matches);
$minTime = strtotime($matches[1]).$matches[2];
$where[] = 'TimeKey >= ?';
$values[] = $minTime;
}
if ( $maxTime ) {
preg_match('/(.+)(\.\d+)/', $maxTime, $matches);
$maxTime = strtotime($matches[1]).$matches[2];
$where[] = 'TimeKey <= ?';
$values[] = $maxTime;
}
foreach ( $filter as $field=>$value ) {
if ( $value != '' ) {
if ( $field == 'Level' ) {
$where[] = $field.' <= ?';
$values[] = $value;
} else {
$where[] = $field.' = ?';
$values[] = $value;
}
}
}
if ( count($where) )
$sql.= ' WHERE '.join( ' AND ', $where );
$sql .= ' ORDER BY '.$sortField.' '.$sortOrder;
//$sql .= " limit ".dbEscape($limit);
$format = isset($_POST['format'])?$_POST['format']:'text';
switch( $format ) {
case 'text' :
$exportExt = 'txt';
break;
case 'tsv' :
$exportExt = 'tsv';
break;
case 'html' :
$exportExt = 'html';
break;
case 'xml' :
$exportExt = 'xml';
break;
default :
Fatal("Unrecognised log export format '$format'");
}
$exportKey = substr(md5(rand()),0,8);
$exportFile = "zm-log.$exportExt";
$exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt";
if ( !($exportFP = fopen( $exportPath, "w" )) )
Fatal("Unable to open log export file $exportPath");
$logs = array();
foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) {
$log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] );
$log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : '';
$logs[] = $log;
}
switch( $format ) {
case 'text' :
{
if ( !canView( 'System' ) )
ajaxError( 'Insufficient permissions to export logs' );
$minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL;
$maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL;
if ( !is_null($minTime) && !is_null($maxTime) && $minTime > $maxTime )
{
$tempTime = $minTime;
$minTime = $maxTime;
$maxTime = $tempTime;
}
//$limit = isset($_POST['limit'])?$_POST['limit']:1000;
$filter = isset($_POST['filter'])?$_POST['filter']:array();
$sortField = 'TimeKey';
if ( isset($_POST['sortField']) ) {
if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) {
Error("Invalid sort field " . $_POST['sortField'] );
} else {
$sortField = $_POST['sortField'];
}
}
$sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc';
$servers = Server::find_all();
$servers_by_Id = array();
# There is probably a better way to do this.
foreach ( $servers as $server ) {
$servers_by_Id[$server->Id()] = $server;
}
$sql = "select * from Logs";
$where = array();
$values = array();
if ( $minTime )
{
preg_match( '/(.+)(\.\d+)/', $minTime, $matches );
$minTime = strtotime($matches[1]).$matches[2];
$where[] = "TimeKey >= ?";
$values[] = $minTime;
}
if ( $maxTime )
{
preg_match( '/(.+)(\.\d+)/', $maxTime, $matches );
$maxTime = strtotime($matches[1]).$matches[2];
$where[] = "TimeKey <= ?";
$values[] = $maxTime;
}
foreach ( $filter as $field=>$value ) {
if ( $value != '' ) {
if ( $field == 'Level' ) {
$where[] = $field." <= ?";
$values[] = $value;
} else {
$where[] = $field." = ?'";
$values[] = $value;
}
}
}
if ( count($where) )
$sql.= " where ".join( " and ", $where );
$sql .= " order by ".$sortField." ".$sortOrder;
//$sql .= " limit ".dbEscape($limit);
$format = isset($_POST['format'])?$_POST['format']:'text';
switch( $format )
{
case 'text' :
$exportExt = "txt";
break;
case 'tsv' :
$exportExt = "tsv";
break;
case 'html' :
$exportExt = "html";
break;
case 'xml' :
$exportExt = "xml";
break;
default :
Fatal( "Unrecognised log export format '$format'" );
}
$exportKey = substr(md5(rand()),0,8);
$exportFile = "zm-log.$exportExt";
$exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt";
if ( !($exportFP = fopen( $exportPath, "w" )) )
Fatal( "Unable to open log export file $exportPath" );
$logs = array();
foreach ( dbFetchAll( $sql, NULL, $values ) as $log )
{
$log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] );
$log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : '';
$logs[] = $log;
}
switch( $format )
{
case 'text' :
{
foreach ( $logs as $log )
{
if ( $log['Line'] )
fprintf( $exportFP, "%s %s[%d].%s-%s/%d [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message'] );
else
fprintf( $exportFP, "%s %s[%d].%s-%s [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message'] );
}
break;
}
case 'tsv' :
{
# This line doesn't need fprintf, it could use fwrite
fprintf( $exportFP, join( "\t",
translate('DateTime'),
translate('Component'),
translate('Server'),
translate('Pid'),
translate('Level'),
translate('Message'),
translate('File'),
translate('Line')
)."\n" );
foreach ( $logs as $log )
{
fprintf( $exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] );
}
break;
}
case 'html' :
{
fwrite( $exportFP,
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>'.translate('ZoneMinderLog').'</title>
<style type="text/css">
body, h3, p, table, td {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
}
table {
border-collapse: collapse;
width: 100%;
}
th {
font-weight: bold;
}
th, td {
border: 1px solid #888888;
padding: 1px 2px;
}
tr.log-fat td {
background-color:#ffcccc;
font-weight: bold;
font-style: italic;
}
tr.log-err td {
background-color:#ffcccc;
}
tr.log-war td {
background-color: #ffe4b5;
}
tr.log-dbg td {
color: #666666;
font-style: italic;
}
</style>
</head>
<body>
foreach ( $logs as $log ) {
if ( $log['Line'] )
fprintf( $exportFP, "%s %s[%d].%s-%s/%d [%s]\n",
$log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message'] );
else
fprintf( $exportFP, "%s %s[%d].%s-%s [%s]\n",
$log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message'] );
}
break;
}
case 'tsv' :
{
# This line doesn't need fprintf, it could use fwrite
fprintf( $exportFP, join( "\t",
translate('DateTime'),
translate('Component'),
translate('Server'),
translate('Pid'),
translate('Level'),
translate('Message'),
translate('File'),
translate('Line')
)."\n" );
foreach ( $logs as $log ) {
fprintf( $exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] );
}
break;
}
case 'html' :
{
fwrite( $exportFP,
'
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>'.translate('ZoneMinderLog').'</title>
<style type="text/css">
body, h3, p, table, td {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
}
table {
border-collapse: collapse;
width: 100%;
}
th {
font-weight: bold;
}
th, td {
border: 1px solid #888888;
padding: 1px 2px;
}
tr.log-fat td {
background-color:#ffcccc;
font-weight: bold;
font-style: italic;
}
tr.log-err td {
background-color:#ffcccc;
}
tr.log-war td {
background-color: #ffe4b5;
}
tr.log-dbg td {
color: #666666;
font-style: italic;
}
</style>
</head>
<body>
<h3>'.translate('ZoneMinderLog').'</h3>
<p>'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'</p>
<p>'.count($logs).' '.translate('Logs').'</p>
<table>
<tbody>
<tr><th>'.translate('DateTime').'</th><th>'.translate('Component').'</th><th>'.translate('Server').'</th><th>'.translate('Pid').'</th><th>'.translate('Level').'</th><th>'.translate('Message').'</th><th>'.translate('File').'</th><th>'.translate('Line').'</th></tr>
' );
foreach ( $logs as $log )
{
$classLevel = $log['Level'];
if ( $classLevel < Logger::FATAL )
$classLevel = Logger::FATAL;
elseif ( $classLevel > Logger::DEBUG )
$classLevel = Logger::DEBUG;
$logClass = 'log-'.strtolower(Logger::$codes[$classLevel]);
fprintf( $exportFP, " <tr class=\"%s\"><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] );
}
fwrite( $exportFP,
' </tbody>
</table>
</body>
</html>' );
break;
}
case 'xml' :
{
fwrite( $exportFP,
'<?xml version="1.0" encoding="utf-8"?>
<logexport title="'.translate('ZoneMinderLog').'" date="'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'">
<selector>'.$_POST['selector'].'</selector>' );
foreach ( $filter as $field=>$value )
if ( $value != '' )
fwrite( $exportFP,
' <filter>
<'.strtolower($field).'>'.htmlspecialchars($value).'</'.strtolower($field).'>
</filter>' );
fwrite( $exportFP,
' <columns>
<column field="datetime">'.translate('DateTime').'</column><column field="component">'.translate('Component').'</column><column field="'.translate('Server').'</column><column field="pid">'.translate('Pid').'</column><column field="level">'.translate('Level').'</column><column field="message">'.translate('Message').'</column><column field="file">'.translate('File').'</column><column field="line">'.translate('Line').'</column>
</columns>
<logs count="'.count($logs).'">
' );
foreach ( $logs as $log )
{
fprintf( $exportFP,
" <log>
<datetime>%s</datetime>
<component>%s</component>
<server>%s</server>
<pid>%d</pid>
<level>%s</level>
<message><![CDATA[%s]]></message>
<file>%s</file>
<line>%d</line>
</log>\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] );
}
fwrite( $exportFP,
' </logs>
</logexport>' );
break;
}
$exportExt = "xml";
break;
}
fclose( $exportFP );
ajaxResponse( array(
'key' => $exportKey,
'format' => $format,
) );
break;
<tbody>
<tr><th>'.translate('DateTime').'</th><th>'.translate('Component').'</th><th>'.translate('Server').'</th><th>'.translate('Pid').'</th><th>'.translate('Level').'</th><th>'.translate('Message').'</th><th>'.translate('File').'</th><th>'.translate('Line').'</th></tr>
' );
foreach ( $logs as $log ) {
$classLevel = $log['Level'];
if ( $classLevel < Logger::FATAL )
$classLevel = Logger::FATAL;
elseif ( $classLevel > Logger::DEBUG )
$classLevel = Logger::DEBUG;
$logClass = 'log-'.strtolower(Logger::$codes[$classLevel]);
fprintf( $exportFP, " <tr class=\"%s\"><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] );
}
case 'download' :
fwrite( $exportFP,
' </tbody>
</table>
</body>
</html>' );
break;
}
case 'xml' :
{
if ( !canView( 'System' ) )
ajaxError( 'Insufficient permissions to download logs' );
if ( empty($_REQUEST['key']) )
Fatal( "No log export key given" );
$exportKey = $_REQUEST['key'];
if ( empty($_REQUEST['format']) )
Fatal( "No log export format given" );
$format = $_REQUEST['format'];
switch( $format )
{
case 'text' :
$exportExt = "txt";
break;
case 'tsv' :
$exportExt = "tsv";
break;
case 'html' :
$exportExt = "html";
break;
case 'xml' :
$exportExt = "xml";
break;
default :
Fatal( "Unrecognised log export format '$format'" );
}
$exportFile = "zm-log.$exportExt";
$exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt";
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="'.$exportFile.'"' );
header( "Content-Transfer-Encoding: binary" );
header( "Content-Type: application/force-download" );
header( "Content-Length: ".filesize($exportPath) );
readfile( $exportPath );
exit( 0 );
break;
fwrite( $exportFP,
'<?xml version="1.0" encoding="utf-8"?>
<logexport title="'.translate('ZoneMinderLog').'" date="'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'">
<selector>'.$_POST['selector'].'</selector>' );
foreach ( $filter as $field=>$value )
if ( $value != '' )
fwrite( $exportFP,
' <filter>
<'.strtolower($field).'>'.htmlspecialchars($value).'</'.strtolower($field).'>
</filter>' );
fwrite( $exportFP,
' <columns>
<column field="datetime">'.translate('DateTime').'</column><column field="component">'.translate('Component').'</column><column field="'.translate('Server').'</column><column field="pid">'.translate('Pid').'</column><column field="level">'.translate('Level').'</column><column field="message">'.translate('Message').'</column><column field="file">'.translate('File').'</column><column field="line">'.translate('Line').'</column>
</columns>
<logs count="'.count($logs).'">
' );
foreach ( $logs as $log ) {
fprintf( $exportFP,
" <log>
<datetime>%s</datetime>
<component>%s</component>
<server>%s</server>
<pid>%d</pid>
<level>%s</level>
<message><![CDATA[%s]]></message>
<file>%s</file>
<line>%d</line>
</log>\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] );
}
fwrite( $exportFP,
' </logs>
</logexport>' );
break;
}
$exportExt = "xml";
break;
}
fclose( $exportFP );
ajaxResponse( array(
'key' => $exportKey,
'format' => $format,
) );
break;
}
case 'download' :
{
if ( !canView('System') )
ajaxError('Insufficient permissions to download logs');
if ( empty($_REQUEST['key']) )
Fatal( "No log export key given" );
$exportKey = $_REQUEST['key'];
if ( empty($_REQUEST['format']) )
Fatal( "No log export format given" );
$format = $_REQUEST['format'];
switch( $format ) {
case 'text' :
$exportExt = 'txt';
break;
case 'tsv' :
$exportExt = 'tsv';
break;
case 'html' :
$exportExt = 'html';
break;
case 'xml' :
$exportExt = 'xml';
break;
default :
Fatal("Unrecognised log export format '$format'");
}
$exportFile = "zm-log.$exportExt";
$exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt";
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="'.$exportFile.'"' );
header( "Content-Transfer-Encoding: binary" );
header( "Content-Type: application/force-download" );
header( "Content-Length: ".filesize($exportPath) );
readfile( $exportPath );
exit( 0 );
break;
}
}
ajaxError( 'Unrecognised action or insufficient permissions' );
ajaxError('Unrecognised action or insufficient permissions');
?>

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

@ -126,6 +126,7 @@ class EventsController extends AppController {
$event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id'];
$event['Event']['fileExists'] = $this->Event->fileExists($event['Event']);
$event['Event']['fileSize'] = $this->Event->fileSize($event['Event']);
# Also get the previous and next events for the same monitor
$event_monitor_neighbors = $this->Event->find('neighbors', array(

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

@ -115,13 +115,13 @@ class Event extends AppModel {
} // end function Relative_Path()
public function fileExists( $event ) {
public function fileExists($event) {
//$data = $this->findById($id);
//return $data['Event']['dataset_filename'];
$storage = $this->Storage->findById( $event['StorageId'] );
$storage = $this->Storage->findById($event['StorageId']);
if ( $event['DefaultVideo'] ) {
if ( file_exists( $storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo'] ) ) {
if ( file_exists($storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo']) ) {
return 1;
} else {
Logger::Debug("FIle does not exist at " . $storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo'] );
@ -130,5 +130,10 @@ class Event extends AppModel {
Logger::Debug("No DefaultVideo in Event" . $this->Event);
return 0;
}
} // end function fileExists($event)
public function fileSize($event) {
$storage = $this->Storage->findById($event['StorageId']);
return filesize($storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo']);
}
}

@ -1 +1 @@
Subproject commit ca91b87fda8e006e4fca2ed870f24f9a29c2905d
Subproject commit ea90c0cd7f6e24333a90885e563b5d30b793db29

@ -1 +1 @@
Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5
Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef

View File

@ -10,9 +10,31 @@ class Event {
'MonitorId',
'StorageId',
'Name',
'DiskSpace',
'Cause',
'StartTime',
'EndTime',
'Width',
'Height',
'Length',
'Frames',
'AlarmFrames',
'DefaultVideo',
'SaveJPEGs',
'TotScore',
'AvgScore',
'MaxScore',
'Archived',
'Videoed',
'Uploaded',
'Emailed',
'Messaged',
'Executed',
'Notes',
'StateId',
'Orientation',
'DiskSpace',
'Scheme',
'Locked',
);
public function __construct( $IdOrRow = null ) {
$row = NULL;
@ -566,6 +588,50 @@ class Event {
return false;
} # end public function file_exists()
public function file_size() {
if ( file_exists($this->Path().'/'.$this->DefaultVideo()) ) {
return filesize($this->Path().'/'.$this->DefaultVideo());
}
$Storage= $this->Storage();
$Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server();
if ( $Server->Id() != ZM_SERVER_ID ) {
$url = $Server->Url() . '/zm/api/events/'.$this->{'Id'}.'.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
$url = '?user='.$_SESSION['username'];
$url = '?pass='.$_SESSION['password'];
} elseif ( ZM_AUTH_RELAY == 'none' ) {
$url = '?user='.$_SESSION['username'];
}
}
Logger::Debug("sending command to $url");
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'GET',
'content' => ''
)
);
$context = stream_context_create($options);
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
Error("Error restarting zmc using $url");
}
$event_data = json_decode($result,true);
Logger::Debug(print_r($event_data['event']['Event'],1));
return $event_data['event']['Event']['fileSize'];
} catch ( Exception $e ) {
Error("Except $e thrown trying to get event data");
}
} # end if not local
return 0;
} # end public function file_size()
} # end class
?>

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

@ -1,6 +1,6 @@
<?php
require_once( 'database.php' );
require_once( 'Server.php' );
require_once('database.php');
require_once('Server.php');
class Monitor {
@ -130,12 +130,12 @@ private $control_fields = array(
public function __construct( $IdOrRow = NULL ) {
if ( $IdOrRow ) {
$row = NULL;
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
$row = dbFetchOne( 'SELECT * FROM Monitors WHERE Id=?', NULL, array( $IdOrRow ) );
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
$row = dbFetchOne('SELECT * FROM Monitors WHERE Id=?', NULL, array($IdOrRow));
if ( ! $row ) {
Error("Unable to load Monitor record for Id=" . $IdOrRow );
Error("Unable to load Monitor record for Id=" . $IdOrRow);
}
} elseif ( is_array( $IdOrRow ) ) {
} elseif ( is_array($IdOrRow) ) {
$row = $IdOrRow;
} else {
Error("Unknown argument passed to Monitor Constructor ($IdOrRow)");
@ -147,7 +147,7 @@ private $control_fields = array(
$this->{$k} = $v;
}
if ( $this->{'Controllable'} ) {
$s = dbFetchOne( 'SELECT * FROM Controls WHERE Id=?', NULL, array( $this->{'ControlId'} ) );
$s = dbFetchOne('SELECT * FROM Controls WHERE Id=?', NULL, array($this->{'ControlId'}) );
foreach ($s as $k => $v) {
if ( $k == 'Id' ) {
continue;
@ -165,13 +165,13 @@ private $control_fields = array(
}
} else {
Error('No row for Monitor ' . $IdOrRow );
Error('No row for Monitor ' . $IdOrRow);
}
} # end if isset($IdOrRow)
} // end function __construct
public function Server() {
return new Server( $this->{'ServerId'} );
return new Server($this->{'ServerId'});
}
public function __call($fn, array $args){
if ( count($args) ) {
@ -235,24 +235,25 @@ private $control_fields = array(
return( $streamSrc );
} // end function getStreamSrc
public function Width( $new = null ) {
public function Width($new = null) {
if ( $new )
$this->{'Width'} = $new;
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
return $this->{'Height'};
}
return $this->{'Width'};
}
$field = ( $this->Orientation() == '90' or $this->Orientation() == '270' ) ? 'Height' : 'Width';
if ( array_key_exists($field, $this) )
return $this->{$field};
return $this->defaults{$field};
} // end function Width
public function Height( $new=null ) {
public function Height($new=null) {
if ( $new )
$this->{'Height'} = $new;
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
return $this->{'Width'};
}
return $this->{'Height'};
}
$field = ( $this->Orientation() == '90' or $this->Orientation() == '270' ) ? 'Width' : 'Height';
if ( array_key_exists($field, $this) )
return $this->{$field};
return $this->defaults{$field};
} // end function Height
public function set($data) {
foreach ($data as $k => $v) {
@ -334,13 +335,13 @@ private $control_fields = array(
}
if ( $mode == 'stop' ) {
daemonControl( 'stop', 'zmc', $zmcArgs );
daemonControl('stop', 'zmc', $zmcArgs);
} else {
if ( $mode == 'restart' ) {
daemonControl( 'stop', 'zmc', $zmcArgs );
daemonControl('stop', 'zmc', $zmcArgs);
}
if ( $this->{'Function'} != 'None' ) {
daemonControl( 'start', 'zmc', $zmcArgs );
daemonControl('start', 'zmc', $zmcArgs);
}
}
} else if ( $this->ServerId() ) {
@ -377,6 +378,8 @@ private $control_fields = array(
} catch ( Exception $e ) {
Error("Except $e thrown trying to restart zmc");
}
} else {
Error("Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.");
}
} // end function zmcControl
@ -384,9 +387,9 @@ private $control_fields = array(
if ( (!defined('ZM_SERVER_ID')) or ( array_key_exists('ServerId', $this) and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) {
if ( $this->{'Function'} == 'None' || $this->{'Function'} == 'Monitor' || $mode == 'stop' ) {
if ( ZM_OPT_CONTROL ) {
daemonControl( 'stop', 'zmtrack.pl', '-m '.$this->{'Id'} );
daemonControl('stop', 'zmtrack.pl', '-m '.$this->{'Id'});
}
daemonControl( 'stop', 'zma', '-m '.$this->{'Id'} );
daemonControl('stop', 'zma', '-m '.$this->{'Id'});
} else {
if ( $mode == 'restart' ) {
if ( ZM_OPT_CONTROL ) {
@ -403,7 +406,8 @@ private $control_fields = array(
}
}
} // end if we are on the recording server
}
} // end public function zmaControl
public function GroupIds( $new='') {
if ( $new != '' ) {
if(!is_array($new)) {
@ -464,6 +468,8 @@ private $control_fields = array(
$this->{'Storage'} = isset($this->{'StorageId'}) ?
Storage::find_one(array('Id'=>$this->{'StorageId'})) :
new Storage(NULL);
if ( ! $this->{'Storage'} )
$this->{'Storage'} = new Storage(NULL);
}
return $this->{'Storage'};
}
@ -483,9 +489,9 @@ private $control_fields = array(
$url_parts = parse_url( $this->{'Path'} );
unset($url_parts['user']);
unset($url_parts['pass']);
unset($url_parts['scheme']);
#unset($url_parts['scheme']);
unset($url_parts['query']);
unset($url_parts['path']);
#unset($url_parts['path']);
if ( isset($url_parts['port']) and ( $url_parts['port'] == '80' or $url_parts['port'] == '554' ) )
unset($url_parts['port']);
$source = unparse_url($url_parts);

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');
@ -495,8 +492,8 @@ if ( canEdit( 'Monitors' ) ) {
# If we change anything that changes the shared mem size, zma can complain. So let's stop first.
if ( $monitor['Type'] != 'WebSite' ) {
zmaControl( $monitor, 'stop' );
zmcControl( $monitor, 'stop' );
zmaControl($monitor, 'stop');
zmcControl($monitor, 'stop');
}
dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) );
// Groups will be added below
@ -570,23 +567,26 @@ if ( canEdit( 'Monitors' ) ) {
}
$restart = true;
} else {
Logger::Debug("No action due to no changes to Monitor");
} # 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

@ -355,7 +355,7 @@ function getEventDefaultVideoPath( $event ) {
function deletePath( $path ) {
if ( is_dir( $path ) ) {
system( escapeshellcmd( 'rm -rf '.$path ) );
} else {
} else if ( file_exists($path) ) {
unlink( $path );
}
}

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') {
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

@ -18,126 +18,113 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
function getControlCommands( $monitor )
{
$cmds = array();
function getControlCommands( $monitor ) {
$cmds = array();
$cmds['Wake'] = "wake";
$cmds['Sleep'] = "sleep";
$cmds['Reset'] = "reset";
$cmds['Wake'] = "wake";
$cmds['Sleep'] = "sleep";
$cmds['Reset'] = "reset";
$cmds['PresetSet'] = "presetSet";
$cmds['PresetGoto'] = "presetGoto";
$cmds['PresetHome'] = "presetHome";
$cmds['PresetSet'] = "presetSet";
$cmds['PresetGoto'] = "presetGoto";
$cmds['PresetHome'] = "presetHome";
if ( $monitor->CanZoom() )
{
if ( $monitor->CanZoomCon() )
$cmds['ZoomRoot'] = "zoomCon";
elseif ( $monitor->CanZoomRel() )
$cmds['ZoomRoot'] = "zoomRel";
elseif ( $monitor->CanZoomAbs() )
$cmds['ZoomRoot'] = "zoomAbs";
$cmds['ZoomTele'] = $cmds['ZoomRoot']."Tele";
$cmds['ZoomWide'] = $cmds['ZoomRoot']."Wide";
$cmds['ZoomStop'] = "zoomStop";
$cmds['ZoomAuto'] = "zoomAuto";
$cmds['ZoomMan'] = "zoomMan";
if ( $monitor->CanZoom() ) {
if ( $monitor->CanZoomCon() )
$cmds['ZoomRoot'] = "zoomCon";
elseif ( $monitor->CanZoomRel() )
$cmds['ZoomRoot'] = "zoomRel";
elseif ( $monitor->CanZoomAbs() )
$cmds['ZoomRoot'] = "zoomAbs";
$cmds['ZoomTele'] = $cmds['ZoomRoot']."Tele";
$cmds['ZoomWide'] = $cmds['ZoomRoot']."Wide";
$cmds['ZoomStop'] = "zoomStop";
$cmds['ZoomAuto'] = "zoomAuto";
$cmds['ZoomMan'] = "zoomMan";
}
if ( $monitor->CanFocus() ) {
if ( $monitor->CanFocusCon() )
$cmds['FocusRoot'] = "focusCon";
elseif ( $monitor->CanFocusRel() )
$cmds['FocusRoot'] = "focusRel";
elseif ( $monitor->CanFocusAbs() )
$cmds['FocusRoot'] = "focusAbs";
$cmds['FocusFar'] = $cmds['FocusRoot']."Far";
$cmds['FocusNear'] = $cmds['FocusRoot']."Near";
$cmds['FocusStop'] = "focusStop";
$cmds['FocusAuto'] = "focusAuto";
$cmds['FocusMan'] = "focusMan";
}
if ( $monitor->CanIris() ) {
if ( $monitor->CanIrisCon() )
$cmds['IrisRoot'] = "irisCon";
elseif ( $monitor->CanIrisRel() )
$cmds['IrisRoot'] = "irisRel";
elseif ( $monitor->CanIrisAbs() )
$cmds['IrisRoot'] = "irisAbs";
$cmds['IrisOpen'] = $cmds['IrisRoot']."Open";
$cmds['IrisClose'] = $cmds['IrisRoot']."Close";
$cmds['IrisStop'] = "irisStop";
$cmds['IrisAuto'] = "irisAuto";
$cmds['IrisMan'] = "irisMan";
}
if ( $monitor->CanWhite() ) {
if ( $monitor->CanWhiteCon() )
$cmds['WhiteRoot'] = "whiteCon";
elseif ( $monitor->CanWhiteRel() )
$cmds['WhiteRoot'] = "whiteRel";
elseif ( $monitor->CanWhiteAbs() )
$cmds['WhiteRoot'] = "whiteAbs";
$cmds['WhiteIn'] = $cmds['WhiteRoot']."In";
$cmds['WhiteOut'] = $cmds['WhiteRoot']."Out";
$cmds['WhiteAuto'] = "whiteAuto";
$cmds['WhiteMan'] = "whiteMan";
}
if ( $monitor->CanGain() ) {
if ( $monitor->CanGainCon() )
$cmds['GainRoot'] = "gainCon";
elseif ( $monitor->CanGainRel() )
$cmds['GainRoot'] = "gainRel";
elseif ( $monitor->CanGainAbs() )
$cmds['GainRoot'] = "gainAbs";
$cmds['GainUp'] = $cmds['GainRoot']."Up";
$cmds['GainDown'] = $cmds['GainRoot']."Down";
$cmds['GainAuto'] = "gainAuto";
$cmds['GainMan'] = "gainMan";
}
if ( $monitor->CanMove() ) {
if ( $monitor->CanMoveCon() ) {
$cmds['MoveRoot'] = "moveCon";
$cmds['Center'] = "moveStop";
} elseif ( $monitor->CanMoveRel() ) {
$cmds['MoveRoot'] = "moveRel";
$cmds['Center'] = $cmds['PresetHome'];
} elseif ( $monitor->CanMoveAbs() ) {
$cmds['MoveRoot'] = "moveAbs";
$cmds['Center'] = $cmds['PresetHome'];
} else {
$cmds['MoveRoot'] = '';
}
if ( $monitor->CanFocus() )
{
if ( $monitor->CanFocusCon() )
$cmds['FocusRoot'] = "focusCon";
elseif ( $monitor->CanFocusRel() )
$cmds['FocusRoot'] = "focusRel";
elseif ( $monitor->CanFocusAbs() )
$cmds['FocusRoot'] = "focusAbs";
$cmds['FocusFar'] = $cmds['FocusRoot']."Far";
$cmds['FocusNear'] = $cmds['FocusRoot']."Near";
$cmds['FocusStop'] = "focusStop";
$cmds['FocusAuto'] = "focusAuto";
$cmds['FocusMan'] = "focusMan";
}
if ( $monitor->CanIris() )
{
if ( $monitor->CanIrisCon() )
$cmds['IrisRoot'] = "irisCon";
elseif ( $monitor->CanIrisRel() )
$cmds['IrisRoot'] = "irisRel";
elseif ( $monitor->CanIrisAbs() )
$cmds['IrisRoot'] = "irisAbs";
$cmds['IrisOpen'] = $cmds['IrisRoot']."Open";
$cmds['IrisClose'] = $cmds['IrisRoot']."Close";
$cmds['IrisStop'] = "irisStop";
$cmds['IrisAuto'] = "irisAuto";
$cmds['IrisMan'] = "irisMan";
}
if ( $monitor->CanWhite() )
{
if ( $monitor->CanWhiteCon() )
$cmds['WhiteRoot'] = "whiteCon";
elseif ( $monitor->CanWhiteRel() )
$cmds['WhiteRoot'] = "whiteRel";
elseif ( $monitor->CanWhiteAbs() )
$cmds['WhiteRoot'] = "whiteAbs";
$cmds['WhiteIn'] = $cmds['WhiteRoot']."In";
$cmds['WhiteOut'] = $cmds['WhiteRoot']."Out";
$cmds['WhiteAuto'] = "whiteAuto";
$cmds['WhiteMan'] = "whiteMan";
}
if ( $monitor->CanGain() )
{
if ( $monitor->CanGainCon() )
$cmds['GainRoot'] = "gainCon";
elseif ( $monitor->CanGainRel() )
$cmds['GainRoot'] = "gainRel";
elseif ( $monitor->CanGainAbs() )
$cmds['GainRoot'] = "gainAbs";
$cmds['GainUp'] = $cmds['GainRoot']."Up";
$cmds['GainDown'] = $cmds['GainRoot']."Down";
$cmds['GainAuto'] = "gainAuto";
$cmds['GainMan'] = "gainMan";
}
if ( $monitor->CanMove() )
{
if ( $monitor->CanMoveCon() )
{
$cmds['MoveRoot'] = "moveCon";
$cmds['Center'] = "moveStop";
}
elseif ( $monitor->CanMoveRel() )
{
$cmds['MoveRoot'] = "moveRel";
$cmds['Center'] = $cmds['PresetHome'];
}
elseif ( $monitor->CanMoveAbs() )
{
$cmds['MoveRoot'] = "moveAbs";
$cmds['Center'] = $cmds['PresetHome'];
} else {
$cmds['MoveRoot'] = '';
}
$cmds['MoveUp'] = $cmds['MoveRoot']."Up";
$cmds['MoveDown'] = $cmds['MoveRoot']."Down";
$cmds['MoveLeft'] = $cmds['MoveRoot']."Left";
$cmds['MoveRight'] = $cmds['MoveRoot']."Right";
$cmds['MoveUpLeft'] = $cmds['MoveRoot']."UpLeft";
$cmds['MoveUpRight'] = $cmds['MoveRoot']."UpRight";
$cmds['MoveDownLeft'] = $cmds['MoveRoot']."DownLeft";
$cmds['MoveDownRight'] = $cmds['MoveRoot']."DownRight";
}
return( $cmds );
$cmds['MoveUp'] = $cmds['MoveRoot']."Up";
$cmds['MoveDown'] = $cmds['MoveRoot']."Down";
$cmds['MoveLeft'] = $cmds['MoveRoot']."Left";
$cmds['MoveRight'] = $cmds['MoveRoot']."Right";
$cmds['MoveUpLeft'] = $cmds['MoveRoot']."UpLeft";
$cmds['MoveUpRight'] = $cmds['MoveRoot']."UpRight";
$cmds['MoveDownLeft'] = $cmds['MoveRoot']."DownLeft";
$cmds['MoveDownRight'] = $cmds['MoveRoot']."DownRight";
}
return( $cmds );
}
function controlFocus( $monitor, $cmds )
{
ob_start();
function controlFocus( $monitor, $cmds ) {
ob_start();
?>
<div class="arrowControl focusControls">
<div class="arrowLabel"><?php echo translate('Near') ?></div>
@ -146,24 +133,22 @@ function controlFocus( $monitor, $cmds )
<div class="longArrowBtn downBtn" onclick="controlCmd('<?php echo $cmds['FocusFar'] ?>',event,0,1)"></div>
<div class="arrowLabel"><?php echo translate('Far') ?></div>
<?php
if ( $monitor->CanAutoFocus() )
{
if ( $monitor->CanAutoFocus() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Auto') ?>" onclick="controlCmd('<?php echo $cmds['FocusAuto'] ?>')"/>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Man') ?>" onclick="controlCmd('<?php echo $cmds['FocusMan'] ?>')"/>
<?php
}
}
?>
</div>
<?php
return( ob_get_clean() );
return ob_get_clean();
}
function controlZoom( $monitor, $cmds )
{
global $SLANG;
function controlZoom( $monitor, $cmds ) {
global $SLANG;
ob_start();
ob_start();
?>
<div class="arrowControl zoomControls">
<div class="arrowLabel"><?php echo translate('Tele') ?></div>
@ -172,23 +157,21 @@ function controlZoom( $monitor, $cmds )
<div class="longArrowBtn downBtn" onclick="controlCmd('<?php echo $cmds['ZoomWide'] ?>',event,0,1)"></div>
<div class="arrowLabel"><?php echo translate('Wide') ?></div>
<?php
if ( $monitor->CanAutoZoom() )
{
if ( $monitor->CanAutoZoom() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Auto') ?>" onclick="controlCmd('<?php echo $cmds['ZoomAuto'] ?>')"/>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Man') ?>" onclick="controlCmd('<?php echo $cmds['ZoomMan'] ?>')"/>
<?php
}
}
?>
</div><?php
return( ob_get_clean() );
return ob_get_clean();
}
function controlIris( $monitor, $cmds )
{
global $SLANG;
function controlIris( $monitor, $cmds ) {
global $SLANG;
ob_start();
ob_start();
?>
<div class="arrowControl irisControls">
<div class="arrowLabel"><?php echo translate('Open') ?></div>
@ -197,24 +180,22 @@ function controlIris( $monitor, $cmds )
<div class="longArrowBtn downBtn" onclick="controlCmd('<?php echo $cmds['IrisClose'] ?>',event,0,1)"></div>
<div class="arrowLabel"><?php echo translate('Close') ?></div>
<?php
if ( $monitor->CanAutoIris() )
{
if ( $monitor->CanAutoIris() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Auto') ?>" onclick="controlCmd('<?php echo $cmds['IrisAuto'] ?>')"/>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Man') ?>" onclick="controlCmd('<?php echo $cmds['IrisMan'] ?>')"/>
<?php
}
}
?>
</div>
<?php
return( ob_get_clean() );
return ob_get_clean();
}
function controlWhite( $monitor, $cmds )
{
global $SLANG;
function controlWhite( $monitor, $cmds ) {
global $SLANG;
ob_start();
ob_start();
?>
<div class="arrowControl whiteControls">
<div class="arrowLabel"><?php echo translate('In') ?></div>
@ -223,170 +204,158 @@ function controlWhite( $monitor, $cmds )
<div class="longArrowBtn downBtn" onclick="controlCmd('<?php echo $cmds['WhiteOut'] ?>',event,0,1)"></div>
<div class="arrowLabel"><?php echo translate('Out') ?></div>
<?php
if ( $monitor->CanAutoWhite() )
{
if ( $monitor->CanAutoWhite() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Auto') ?>" onclick="controlCmd('<?php echo $cmds['WhiteAuto'] ?>')"/>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Man') ?>" onclick="controlCmd('<?php echo $cmds['WhiteMan'] ?>')"/>
<?php
}
}
?>
</div>
<?php
return( ob_get_clean() );
return ob_get_clean();
}
function controlPanTilt( $monitor, $cmds )
{
global $SLANG;
function controlPanTilt( $monitor, $cmds ) {
global $SLANG;
ob_start();
ob_start();
?>
<div class="pantiltControls">
<div class="pantiltLabel"><?php echo translate('PanTilt') ?></div>
<div class="pantiltButtons">
<?php
$hasPan = $monitor->CanPan();
$hasTilt = $monitor->CanTilt();
$hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag();
$hasPan = $monitor->CanPan();
$hasTilt = $monitor->CanTilt();
$hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag();
?>
<div class="arrowBtn upLeftBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUpLeft'] ?>',event,-1,-1)"></div>
<div class="arrowBtn upBtn<?php echo $hasTilt?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUp'] ?>',event,0,-1)"></div>
<div class="arrowBtn upRightBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUpRight'] ?>',event,1,-1)"></div>
<div class="arrowBtn leftBtn<?php echo $hasPan?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveLeft'] ?>',event,1,0)"></div>
<div class="arrowBtn upLeftBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUpLeft'] ?>',event,-1,-1)"></div>
<div class="arrowBtn upBtn<?php echo $hasTilt?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUp'] ?>',event,0,-1)"></div>
<div class="arrowBtn upRightBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUpRight'] ?>',event,1,-1)"></div>
<div class="arrowBtn leftBtn<?php echo $hasPan?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveLeft'] ?>',event,1,0)"></div>
<?php if ( isset($cmds['Center']) ) { ?>
<div class="arrowBtn centerBtn" onclick="controlCmd('<?php echo $cmds['Center'] ?>')"></div>
<div class="arrowBtn centerBtn" onclick="controlCmd('<?php echo $cmds['Center'] ?>')"></div>
<?php } else { ?>
<div class="arrowBtn NocenterBtn"></div>
<div class="arrowBtn NocenterBtn"></div>
<?php } ?>
<div class="arrowBtn rightBtn<?php echo $hasPan?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveRight'] ?>',event,1,0)"></div>
<div class="arrowBtn downLeftBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveDownLeft'] ?>',event,-1,1)"></div>
<div class="arrowBtn downBtn<?php echo $hasTilt?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveDown'] ?>',event,0,1)"></div>
<div class="arrowBtn downRightBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveDownRight'] ?>',event,1,1)"></div>
<div class="arrowBtn rightBtn<?php echo $hasPan?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveRight'] ?>',event,1,0)"></div>
<div class="arrowBtn downLeftBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveDownLeft'] ?>',event,-1,1)"></div>
<div class="arrowBtn downBtn<?php echo $hasTilt?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveDown'] ?>',event,0,1)"></div>
<div class="arrowBtn downRightBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveDownRight'] ?>',event,1,1)"></div>
</div>
</div>
<?php
return( ob_get_clean() );
return ob_get_clean();
}
function controlPresets( $monitor, $cmds )
{
global $SLANG;
function controlPresets( $monitor, $cmds ) {
global $SLANG;
define( "MAX_PRESETS", "12" );
// MAX_PRESETS IS PER LINE
define( "MAX_PRESETS", "12" );
$sql = 'select * from ControlPresets where MonitorId = ?';
$labels = array();
foreach( dbFetchAll( $sql, NULL, array( $monitor->Id() ) ) as $row )
{
$labels[$row['Preset']] = $row['Label'];
}
$sql = 'SELECT * FROM ControlPresets WHERE MonitorId = ?';
$labels = array();
foreach( dbFetchAll( $sql, NULL, array( $monitor->Id() ) ) as $row ) {
$labels[$row['Preset']] = $row['Label'];
}
$presetBreak = (int)(($monitor->NumPresets()+1)/((int)(($monitor->NumPresets()-1)/MAX_PRESETS)+1));
$presetBreak = (int)(($monitor->NumPresets()+1)/((int)(($monitor->NumPresets()-1)/MAX_PRESETS)+1));
ob_start();
ob_start();
?>
<div class="presetControls">
<!--<div><?php echo translate('Presets') ?></div>-->
<div>
<?php
for ( $i = 1; $i <= $monitor->NumPresets(); $i++ )
{
?><input type="button" class="ptzNumBtn" title="<?php echo isset($labels[$i])?$labels[$i]:"" ?>" value="<?php echo $i ?>" onclick="controlCmd('<?php echo $cmds['PresetGoto'] ?><?php echo $i ?>');"/><?php
if ( $i && (($i%$presetBreak) == 0) )
{
for ( $i = 1; $i <= $monitor->NumPresets(); $i++ ) {
?>
<input type="button" class="ptzNumBtn" title="<?php echo isset($labels[$i])?$labels[$i]:"" ?>" value="<?php echo $i ?>" onclick="controlCmd('<?php echo $cmds['PresetGoto'] ?><?php echo $i ?>');"/>
<?php
if ( $i && (($i%$presetBreak) == 0) ) {
?><br/><?php
}
}
} // end foreach preset
?>
</div>
<div>
<?php
if ( $monitor->HasHomePreset() )
{
if ( $monitor->HasHomePreset() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Home') ?>" onclick="controlCmd('<?php echo $cmds['PresetHome'] ?>');"/>
<?php
}
if ( canEdit( 'Monitors') && $monitor->CanSetPresets() )
{
}
if ( canEdit('Monitors') && $monitor->CanSetPresets() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Set') ?>" onclick="createPopup( '?view=controlpreset&amp;mid=<?php echo $monitor->Id() ?>', 'zmPreset', 'preset' );"/>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Set') ?>" onclick="createPopup('?view=controlpreset&amp;mid=<?php echo $monitor->Id() ?>', 'zmPreset', 'preset');"/>
<?php
}
}
?>
</div>
</div>
<?php
return( ob_get_clean() );
return ob_get_clean();
}
function controlPower( $monitor, $cmds )
{
global $SLANG;
function controlPower( $monitor, $cmds ) {
global $SLANG;
ob_start();
ob_start();
?>
<div class="powerControls">
<div class="powerLabel"><?php echo translate('Control') ?></div>
<div>
<?php
if ( $monitor->CanWake() )
{
if ( $monitor->CanWake() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Wake') ?>" onclick="controlCmd('<?php echo $cmds['Wake'] ?>')"/>
<?php
}
if ( $monitor->CanSleep() )
{
}
if ( $monitor->CanSleep() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Sleep') ?>" onclick="controlCmd('<?php echo $cmds['Sleep'] ?>')"/>
<?php
}
if ( $monitor->CanReset() )
{
}
if ( $monitor->CanReset() ) {
?>
<input type="button" class="ptzTextBtn" value="<?php echo translate('Reset') ?>" onclick="controlCmd('<?php echo $cmds['Reset'] ?>')"/>
<?php
}
}
?>
</div>
</div>
<?php
return( ob_get_clean() );
return ob_get_clean();
}
function ptzControls( $monitor )
{
$cmds = getControlCommands( $monitor );
ob_start();
function ptzControls( $monitor ) {
$cmds = getControlCommands($monitor);
ob_start();
?>
<div class="controlsPanel">
<div class="controlsPanel">
<?php
if ( $monitor->CanFocus() )
echo controlFocus( $monitor, $cmds );
if ( $monitor->CanZoom() )
echo controlZoom( $monitor, $cmds );
if ( $monitor->CanIris() )
echo controlIris( $monitor, $cmds );
if ( $monitor->CanWhite() )
echo controlWhite( $monitor, $cmds );
if ( $monitor->CanMove() ) {
if ( $monitor->CanFocus() )
echo controlFocus($monitor, $cmds);
if ( $monitor->CanZoom() )
echo controlZoom($monitor, $cmds);
if ( $monitor->CanIris() )
echo controlIris($monitor, $cmds);
if ( $monitor->CanWhite() )
echo controlWhite($monitor, $cmds);
if ( $monitor->CanMove() ) {
?>
<div class="pantiltPanel">
<div class="pantiltPanel">
<?php echo controlPanTilt($monitor, $cmds); ?>
</div>
<?php
echo controlPanTilt( $monitor, $cmds );
}
if ( $monitor->CanWake() || $monitor->CanSleep() || $monitor->CanReset() )
echo controlPower($monitor, $cmds);
if ( $monitor->HasPresets() )
echo controlPresets($monitor, $cmds);
?>
</div>
</div>
<?php
}
if ( $monitor->CanWake() || $monitor->CanSleep() || $monitor->CanReset() )
echo controlPower( $monitor, $cmds );
if ( $monitor->HasPresets() )
echo controlPresets( $monitor, $cmds );
?>
</div>
<?php
return( ob_get_clean() );
return ob_get_clean();
}
?>

View File

@ -732,11 +732,6 @@ function loadintoIframe(iframeid, url){
return( ob_get_clean() );
}
function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc ) {
if ( (!canView('Events')) or ! $eid ) {
@ -816,7 +811,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp
}
$files = array();
}
return( array_values( $exportFileList ) );
return array_values($exportFileList);
}
function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat, $exportStructure = false ) {
@ -900,5 +895,5 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo
unlink($monitorPath.'/'.$html_eventMaster);
}
return( '?view=archive%26type='.$exportFormat );
return '?view=archive%26type='.$exportFormat;
}

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

@ -56,7 +56,7 @@ var popupSizes = {
'onvifprobe': { 'width': 700, 'height': 550 },
'optionhelp': { 'width': 400, 'height': 320 },
'options': { 'width': 1000, 'height': 660 },
'preset': { 'width': 300, 'height': 120 },
'preset': { 'width': 300, 'height': 220 },
'server': { 'width': 600, 'height': 405 },
'settings': { 'width': 220, 'height': 235 },
'state': { 'width': 400, 'height': 170 },

View File

@ -182,7 +182,7 @@ function refreshParentWindow() {
}
}
if ( currentView != 'none' ) {
if ( currentView != 'none' && currentView != 'login' ) {
$j.ajaxSetup ({timeout: AJAX_TIMEOUT }); //sets timeout for all getJSON.
$j(document).ready(function() {
@ -192,7 +192,15 @@ 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 );
// The idea is that this should only fail due to auth, so reload the page
// which should go to login if it can't stay logged in.
window.location.href = thisUrl;
});
}
function setNavBar(data) {

View File

@ -34,6 +34,8 @@ var skinPath = "<?php echo ZM_SKIN_PATH ?>";
var canEditSystem = <?php echo canEdit('System' )?'true':'false' ?>;
var canViewSystem = <?php echo canView('System' )?'true':'false' ?>;
var canEditEvents = <?php echo canEdit('Events' )?'true':'false' ?>;
var canViewEvents = <?php echo canView('Events' )?'true':'false' ?>;
var canEditGroups = <?php echo canEdit('Groups' )?'true':'false' ?>;

View File

@ -218,7 +218,9 @@ $html .= htmlSelect( 'Status[]', $status_options,
$regexp = '/'.preg_quote($regexp,'/').'/i';
}
if ( !preg_match($regexp, $Monitor->Source()) ) {
continue;
if ( !preg_match($regexp, $Monitor->Path()) ) {
continue;
}
}
}

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();

View File

@ -18,30 +18,26 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit( 'Monitors' ) )
{
$view = "error";
return;
if ( !canEdit('Monitors') ) {
$view = 'error';
return;
}
$monitor = dbFetchOne( 'SELECT C.*,M.* FROM Monitors AS M INNER JOIN Controls AS C ON (M.ControlId = C.Id ) WHERE M.Id = ?', NULL, array( $_REQUEST['mid']) );
$monitor = dbFetchOne('SELECT C.*,M.* FROM Monitors AS M INNER JOIN Controls AS C ON (M.ControlId = C.Id ) WHERE M.Id = ?', NULL, array( $_REQUEST['mid']) );
$labels = array();
foreach( dbFetchAll( 'SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, array( $monitor['Id'] ) ) as $row ) {
$labels[$row['Preset']] = $row['Label'];
$labels[$row['Preset']] = $row['Label'];
}
$presets = array();
for ( $i = 1; $i <= $monitor['NumPresets']; $i++ )
{
$presets[$i] = translate('Preset')." ".$i;
if ( !empty($labels[$i]) )
{
$presets[$i] .= " (".validHtmlStr($labels[$i]).")";
}
for ( $i = 1; $i <= $monitor['NumPresets']; $i++ ) {
$presets[$i] = translate('Preset').' '.$i;
if ( !empty($labels[$i]) ) {
$presets[$i] .= ' ('.validHtmlStr($labels[$i]).')';
}
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('SetPreset') );
@ -58,10 +54,14 @@ xhtmlHeaders(__FILE__, translate('SetPreset') );
<input type="hidden" name="action" value="control"/>
<input type="hidden" name="control" value="presetSet"/>
<input type="hidden" name="showControls" value="1"/>
<p><?php echo buildSelect( "preset", $presets, "updateLabel()" ) ?></p>
<p><label for="newLabel"><?php echo translate('NewLabel') ?></label><input type="text" name="newLabel" id="newLabel" value="" size="16"/></p>
<p><?php echo buildSelect('preset', $presets, 'updateLabel()' ) ?></p>
<p>
<label for="newLabel"><?php echo translate('NewLabel') ?></label>
<input type="text" name="newLabel" id="newLabel" value="" size="16"/>
</p>
<div id="contentButtons">
<input type="submit" value="<?php echo translate('Save') ?>"/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
<input type="submit" value="<?php echo translate('Save') ?>"/>
<input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
</div>
</form>
</div>

View File

@ -66,7 +66,10 @@ if ( !empty($_REQUEST['eid']) ) {
$Event = new Event( $_REQUEST['eid'] );
echo 'Downloading event ' . $_REQUEST['eid'] . ' Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() );
} else if ( !empty($_REQUEST['eids']) ) {
$total_size = 0;
foreach ( $_REQUEST['eids'] as $eid ) {
$Event = new Event($eid);
$total_size += $Event->DiskSpace();
?>
<input type="hidden" name="eids[]" value="<?php echo validInt($eid) ?>"/>
<?php
@ -74,7 +77,7 @@ if ( !empty($_REQUEST['eid']) ) {
unset( $eid );
echo "Downloading " . count($_REQUEST['eids']) . ' events. Resulting file should be approximately ' . human_filesize($total_size);
} else {
echo '<div class="warning">There are no events found. Resulting download will be empty.</div>';
echo '<div class="warning">There are no events found. Resulting download will be empty.</div>';
}
?>
<table id="contentTable" class="minor" cellspacing="0">

View File

@ -142,7 +142,6 @@ if ( $pages > 1 ) {
$count = 0;
$disk_space_total = 0;
Logger::Debug("EventSql: $eventsSql");
$results = dbQuery($eventsSql);
while ( $event_row = dbFetchNext($results) ) {
$event = new Event($event_row);
@ -173,7 +172,7 @@ while ( $event_row = dbFetchNext($results) ) {
}
if ( ZM_WEB_EVENT_DISK_SPACE ) {
?>
<th class="colDiskSpace"><a href="<?php echo sortHeader( 'DiskSpace' ) ?>"><?php echo translate('DiskSpace') ?><?php echo sortTag( 'DiskSpace' ) ?></a></th>
<th class="colDiskSpace"><a href="<?php echo sortHeader('DiskSpace') ?>"><?php echo translate('DiskSpace') ?><?php echo sortTag('DiskSpace') ?></a></th>
<?php
}
if ( ZM_WEB_LIST_THUMBS ) {
@ -182,7 +181,7 @@ while ( $event_row = dbFetchNext($results) ) {
<?php
}
?>
<th class="colMark"><input type="checkbox" name="toggleCheck" value="1" onclick="toggleCheckbox( this, 'markEids' );"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/></th>
<th class="colMark"><input type="checkbox" name="toggleCheck" value="1" onclick="toggleCheckbox(this, 'markEids');"/></th>
</tr>
<?php
}
@ -226,7 +225,7 @@ while ( $event_row = dbFetchNext($results) ) {
echo '</td>';
} // end if ZM_WEB_LIST_THUMBS
?>
<td class="colMark"><input type="checkbox" name="markEids[]" value="<?php echo $event->Id() ?>" onclick="configureButton( this, 'markEids' );"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/></td>
<td class="colMark"><input type="checkbox" name="markEids[]" value="<?php echo $event->Id() ?>" onclick="configureButton(this, 'markEids');"/></td>
</tr>
<?php
}

View File

@ -18,7 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canView( 'Events' ) ) {
if ( !canView('Events') ) {
$view = 'error';
return;
}
@ -53,16 +53,12 @@ xhtmlHeaders(__FILE__, translate('Export') );
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<?php
if ( !empty($_REQUEST['eid']) )
{
if ( !empty($_REQUEST['eid']) ) {
?>
<input type="hidden" name="id" value="<?php echo validInt($_REQUEST['eid']) ?>"/>
<?php
}
elseif ( !empty($_REQUEST['eids']) )
{
foreach ( $_REQUEST['eids'] as $eid )
{
} elseif ( !empty($_REQUEST['eids']) ) {
foreach ( $_REQUEST['eids'] as $eid ) {
?>
<input type="hidden" name="eids[]" value="<?php echo validInt($eid) ?>"/>
<?php
@ -70,7 +66,7 @@ elseif ( !empty($_REQUEST['eids']) )
unset( $eid );
}
?>
<table id="contentTable" class="minor" cellspacing="0">
<table id="contentTable" class="minor">
<tbody>
<tr>
<th scope="row"><?php echo translate('ExportDetails') ?></th>
@ -101,7 +97,7 @@ elseif ( !empty($_REQUEST['eids']) )
</tr>
</tbody>
</table>
<button id="exportButton" name="exportButton" value="Export" onclick="exportEvent(this.form);" disabled="disabled"><?php echo translate('Export') ?></button>
<button type="button" id="exportButton" name="exportButton" value="Export" onclick="exportEvent(this.form);" disabled="disabled"><?php echo translate('Export') ?></button>
</form>
</div>
<?php

View File

@ -346,17 +346,17 @@ echo htmlSelect( 'filter[Query][sort_asc]', $sort_dirns, $filter->sort_asc() );
<div id="actionsTable" class="filterTable">
<p>
<label><?php echo translate('FilterArchiveEvents') ?></label>
<input type="checkbox" name="filter[AutoArchive]" value="1"<?php if ( !empty($filter->AutoArchive()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
<input type="checkbox" name="filter[AutoArchive]" value="1"<?php if ( $filter->AutoArchive() ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
</p>
<p><label><?php echo translate('FilterUpdateDiskSpace') ?></label>
<input type="checkbox" name="filter[UpdateDiskSpace]" value="1"<?php echo empty($filter->UpdateDiskSpace()) ? '' : ' checked="checked"' ?> onclick="updateButtons(this);"/>
<input type="checkbox" name="filter[UpdateDiskSpace]" value="1"<?php echo !$filter->UpdateDiskSpace() ? '' : ' checked="checked"' ?> onclick="updateButtons(this);"/>
</p>
<?php
if ( ZM_OPT_FFMPEG ) {
?>
<p>
<label><?php echo translate('FilterVideoEvents') ?></label>
<input type="checkbox" name="filter[AutoVideo]" value="1"<?php if ( !empty($filter->AutoVideo()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
<input type="checkbox" name="filter[AutoVideo]" value="1"<?php if ( $filter->AutoVideo() ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
</p>
<?php
}
@ -364,7 +364,7 @@ if ( ZM_OPT_UPLOAD ) {
?>
<p>
<label><?php echo translate('FilterUploadEvents') ?></label>
<input type="checkbox" name="filter[AutoUpload]" value="1"<?php if ( !empty($filter->AutoUpload()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
<input type="checkbox" name="filter[AutoUpload]" value="1"<?php if ( $filter->AutoUpload() ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
</p>
<?php
}
@ -372,7 +372,7 @@ if ( ZM_OPT_EMAIL ) {
?>
<p>
<label><?php echo translate('FilterEmailEvents') ?></label>
<input type="checkbox" name="filter[AutoEmail]" value="1"<?php if ( !empty($filter->AutoEmail()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
<input type="checkbox" name="filter[AutoEmail]" value="1"<?php if ( $filter->AutoEmail() ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
</p>
<?php
}
@ -380,7 +380,7 @@ if ( ZM_OPT_MESSAGE ) {
?>
<p>
<label><?php echo translate('FilterMessageEvents') ?></label>
<input type="checkbox" name="filter[AutoMessage]" value="1"<?php if ( !empty($filter->AutoMessage()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
<input type="checkbox" name="filter[AutoMessage]" value="1"<?php if ( $filter->AutoMessage() ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
</p>
<?php
}
@ -388,24 +388,24 @@ if ( ZM_OPT_MESSAGE ) {
<p>
<label><?php echo translate('FilterExecuteEvents') ?></label>
<input type="checkbox" name="filter[AutoExecute]" value="1"<?php if ( !empty($filter->AutoExecute()) ) { ?> checked="checked"<?php } ?>/>
<input type="checkbox" name="filter[AutoExecute]" value="1"<?php if ( $filter->AutoExecute() ) { ?> checked="checked"<?php } ?>/>
<input type="text" name="filter[AutoExecuteCmd]" value="<?php echo (null !==$filter->AutoExecuteCmd())?$filter->AutoExecuteCmd():'' ?>" maxlength="255" onchange="updateButtons( this )"/>
</p>
<p>
<label><?php echo translate('FilterDeleteEvents') ?></label>
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( !empty($filter->AutoDelete()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this)"/>
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( $filter->AutoDelete() ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this)"/>
</p>
<p><label><?php echo translate('FilterMoveEvents') ?></label>
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( !empty($filter->AutoMove()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);if(this.checked){$j(this.form.elements['filter[AutoMoveTo]']).css('display','inline');}else{this.form.elements['filter[AutoMoveTo]'].hide();};"/>
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( $filter->AutoMove() ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);if(this.checked){$j(this.form.elements['filter[AutoMoveTo]']).css('display','inline');}else{this.form.elements['filter[AutoMoveTo]'].hide();};"/>
<?php echo htmlSelect( "filter[AutoMoveTo]", $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;' ) ); ?>
</p>
<p>
<label for="background"><?php echo translate('BackgroundFilter') ?></label>
<input type="checkbox" id="filter[Background]" name="filter[Background]" value="1"<?php if ( !empty($filter->Background()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);"/>
<input type="checkbox" id="filter[Background]" name="filter[Background]" value="1"<?php if ( $filter->Background() ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);"/>
</p>
<p>
<label for="Concurrent"><?php echo translate('ConcurrentFilter') ?></label>
<input type="checkbox" id="filter[Concurrent]" name="filter[Concurrent]" value="1"<?php if ( !empty($filter->Concurrent()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);"/>
<input type="checkbox" id="filter[Concurrent]" name="filter[Concurrent]" value="1"<?php if ( $filter->Concurrent() ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);"/>
</p>
</div>
<hr/>

View File

@ -1,10 +1,12 @@
function updateLabel() {
var presetIndex = $('contentForm').preset.getValue();
var form = $('contentForm');
var preset_ddm = form.elements['preset'];
var presetIndex = preset_ddm[preset_ddm.selectedIndex].value;
if ( labels[presetIndex] ) {
$('contentForm').newLabel.value = labels[presetIndex];
form.newLabel.value = labels[presetIndex];
} else {
$('contentForm').newLabel.value = "";
form.newLabel.value = '';
}
}
window.addEvent( 'domready', updateLabel );
window.addEvent('domready', updateLabel);

View File

@ -1,9 +1,8 @@
var labels = new Array();
<?php
foreach ( $labels as $index=>$label )
{
foreach ( $labels as $index=>$label ) {
?>
labels[<?php echo validInt($index) ?>] = "<?php echo validJsStr($label) ?>";
labels[<?php echo validInt($index) ?>] = '<?php echo validJsStr($label) ?>';
<?php
}
?>

View File

@ -2,9 +2,9 @@
if ( isset($_REQUEST['eids']) ) {
$eidParms = array();
foreach ( $_REQUEST['eids'] as $eid )
$eidParms[] = "eids[]=".validInt($eid);
$eidParms[] = 'eids[]='.validInt($eid);
?>
var eidParm = '<?php echo join( '&', $eidParms ) ?>';
var eidParm = '<?php echo join('&', $eidParms) ?>';
<?php
} else if (isset($_REQUEST['eid'])) {
?>

View File

@ -11,13 +11,13 @@ function toggleCheckbox( element, name ) {
for (var i = 0; i < form.elements.length; i++)
if (form.elements[i].name.indexOf(name) == 0)
form.elements[i].checked = checked;
form.viewBtn.disabled = !checked;
form.editBtn.disabled = !checked;
form.viewBtn.disabled = !(canViewEvents && checked);
form.editBtn.disabled = !(canEditEvents && checked);
form.archiveBtn.disabled = unarchivedEvents?!checked:true;
form.unarchiveBtn.disabled = archivedEvents?!checked:true;
form.downloadBtn.disabled = !checked;
form.exportBtn.disabled = !checked;
form.deleteBtn.disabled = !checked;
form.unarchiveBtn.disabled = !(canEditEvents && archivedEvents && checked);
form.downloadBtn.disabled = !(canViewEvents && checked);
form.exportBtn.disabled = !(canViewEvents && checked);
form.deleteBtn.disabled = !(canEditEvents && checked);
}
function configureButton( element, name ) {
@ -35,16 +35,20 @@ function configureButton( element, name ) {
}
if ( !element.checked )
form.toggleCheck.checked = false;
form.viewBtn.disabled = !checked;
form.editBtn.disabled = !checked;
form.viewBtn.disabled = !(canViewEvents && checked);
form.editBtn.disabled = !(canEditEvents && checked);
form.archiveBtn.disabled = (!checked)||(!unarchivedEvents);
form.unarchiveBtn.disabled = (!checked)||(!archivedEvents);
form.downloadBtn.disabled = !checked;
form.exportBtn.disabled = !checked;
form.deleteBtn.disabled = !checked;
form.unarchiveBtn.disabled = !(canEditEvents && checked && archivedEvents);
form.downloadBtn.disabled = !(canViewEvents && checked);
form.exportBtn.disabled = !(canViewEvents && checked);
form.deleteBtn.disabled = !(canEditEvents && checked);
}
function deleteEvents( element, name ) {
if ( ! canEditEvents ) {
alert("You do not have permission to delete events.");
return;
}
var form = element.form;
var count = 0;
for (var i = 0; i < form.elements.length; i++) {
@ -64,6 +68,10 @@ function deleteEvents( element, name ) {
}
function editEvents( element, name ) {
if ( ! canEditEvents ) {
alert("You do not have permission to delete events.");
return;
}
var form = element.form;
var eids = new Array();
for (var i = 0; i < form.elements.length; i++) {
@ -125,6 +133,10 @@ function archiveEvents( element, name ) {
}
function unarchiveEvents(element, name) {
if ( ! canEditEvents ) {
alert("You do not have permission to delete events.");
return;
}
var form = element.form;
form.elements['action'].value = 'unarchive';
form.submit();

View File

@ -34,7 +34,7 @@ function buildFetchParms( parms ) {
fetchParms += '&filter['+key+']='+value;
}
);
return( fetchParms );
return fetchParms;
}
function fetchNextLogs() {
@ -229,24 +229,25 @@ function updateFilterSelectors() {
if ( key == 'Level' ) {
Object.each(values,
function( value, label ) {
selector.options[selector.options.length] = new Option( value, label );
selector.options[selector.options.length] = new Option(value, label);
}
);
} else if ( key == 'ServerId' ) {
Object.each(values,
function( value, label ) {
selector.options[selector.options.length] = new Option( value, label );
selector.options[selector.options.length] = new Option(value, label);
}
);
} else {
values.each(
function( value ) {
selector.options[selector.options.length] = new Option( value );
Object.each(values,
function( value, label ) {
selector.options[selector.options.length] = new Option(value, label);
}
);
}
if ( filter[key] )
selector.set('value', filter[key]);
}
);
}
@ -257,11 +258,11 @@ function initPage() {
logCodes[''+i] = 'DB'+i;
logTable = new HtmlTable( $('logTable'),
{
zebra: true,
sortable: true,
sortReverse: true
}
);
zebra: true,
sortable: true,
sortReverse: true
}
);
logTable.addEvent( 'sort', function( tbody, index ) {
var header = tbody.getParent( 'table' ).getElement( 'thead' );
var columns = header.getElement( 'tr' ).getElements( 'th' );

View File

@ -18,10 +18,9 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canView( 'System' ) )
{
$view = "error";
return;
if ( !canView('System') ) {
$view = 'error';
return;
}
$focusWindow = true;
@ -31,92 +30,90 @@ xhtmlHeaders(__FILE__, translate('SystemLog') );
<body>
<div id="page">
<div id="header">
<table class="table">
<tr class="row">
<td class="col text-center">
<div id="logSummary">
<?php echo translate('State') ?>: <span id="logState"></span>/
<?php echo translate('Total') ?>: <span id="totalLogs"></span>/
<?php echo translate('Available') ?>: <span id="availLogs"></span>/
<?php echo translate('Displaying') ?>: <span id="displayLogs"></span>/
<?php echo translate('Updated') ?>: <span id="lastUpdate"></span>
</div>
</td>
</tr>
<tr class="row">
<table class="table">
<tr class="row">
<td class="col text-center">
<div id="logSummary">
<?php echo translate('State') ?>: <span id="logState"></span>/
<?php echo translate('Total') ?>: <span id="totalLogs"></span>/
<?php echo translate('Available') ?>: <span id="availLogs"></span>/
<?php echo translate('Displaying') ?>: <span id="displayLogs"></span>/
<?php echo translate('Updated') ?>: <span id="lastUpdate"></span>
</div>
</td>
</tr>
<tr class="row">
<td class="col text-center">
<div class="btn-group">
<button type="button" class="btn btn-sm" onclick="expandLog()"> <?php echo translate('More') ?></button>
<button type="button" class="btn btn-sm" onclick="clearLog()"> <?php echo translate('Clear') ?></button>
<button type="button" class="btn btn-sm" onclick="refreshLog()"> <?php echo translate('Refresh') ?></button>
<button type="button" class="btn btn-sm" onclick="exportLog()"> <?php echo translate('Export') ?></button>
<button type="button" class="btn btn-sm" onclick="closeWindow()"> <?php echo translate('Close') ?></button>
</div> <!--btn-->
</td>
</tr>
<div class="btn-group">
<button type="button" class="btn btn-sm" onclick="expandLog()"> <?php echo translate('More') ?></button>
<button type="button" class="btn btn-sm" onclick="clearLog()"> <?php echo translate('Clear') ?></button>
<button type="button" class="btn btn-sm" onclick="refreshLog()"> <?php echo translate('Refresh') ?></button>
<button type="button" class="btn btn-sm" onclick="exportLog()"> <?php echo translate('Export') ?></button>
<button type="button" class="btn btn-sm" onclick="closeWindow()"> <?php echo translate('Close') ?></button>
</div> <!--btn-->
</td>
</tr>
</table>
</div> <!--header-->
<div id="content">
<div id="filters">
<table cellpadding="5" class="table-condensed">
<tr class="row">
<td class="col">
<?php echo translate('Component') ?>
<select class="form-control chosen" id="filter[Component]" onchange="filterLog(this)"><option value="">-----</option></select>
</td>
<td class="col">
<?php echo translate('Server') ?>
<select class="form-control chosen" id="filter[ServerId]" onchange="filterLog(this)"><option value="">-----</option></select>
</td>
<td class="col">
<?php echo translate('Pid') ?>
<select class="form-control chosen" id="filter[Pid]" onchange="filterLog(this)"><option value="">-----</option></select>
</td>
</tr>
<tr class="row">
<td class="col">
<?php echo translate('Level') ?>
<select class="form-control chosen" id="filter[Level]" onchange="filterLog(this)"><option value="">---</option></select>
</td>
<td class="col">
<?php echo translate('File') ?>
<select class="form-control chosen" id="filter[File]" onchange="filterLog(this)"><option value="">------</option></select>
</td>
<td class="col">
<?php echo translate('Line') ?>
<select class="form-control chosen" id="filter[Line]" onchange="filterLog(this)"><option value="">----</option></select>
</td>
</tr>
</div> <!--header-->
<div id="content">
<div id="filters">
</table>
<input type="reset" value="<?php echo translate('Reset') ?>" onclick="resetLog()"/>
</div>
<form name="logForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<table id="logTable" class="major" cellspacing="0">
<thead class="thead-highlight">
<tr>
<th><?php echo translate('DateTime') ?></th>
<th class="table-th-nosort"><?php echo translate('Component') ?></th>
<th class="table-th-nosort"><?php echo translate('Server') ?></th>
<th class="table-th-nosort"><?php echo translate('Pid') ?></th>
<th class="table-th-nosort"><?php echo translate('Level') ?></th>
<th class="table-th-nosort"><?php echo translate('Message') ?></th>
<th class="table-th-nosort"><?php echo translate('File') ?></th>
<th class="table-th-nosort"><?php echo translate('Line') ?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="contentButtons">
</div>
</form>
<table class="table-condensed">
<tr class="row">
<td class="col">
<?php echo translate('Component') ?>
<select class="form-control chosen" id="filter[Component]" onchange="filterLog(this)"><option value="">-----</option></select>
</td>
<td class="col">
<?php echo translate('Server') ?>
<select class="form-control chosen" id="filter[ServerId]" onchange="filterLog(this)"><option value="">-----</option></select>
</td>
<td class="col">
<?php echo translate('Pid') ?>
<select class="form-control chosen" id="filter[Pid]" onchange="filterLog(this)"><option value="">-----</option></select>
</td>
</tr>
<tr class="row">
<td class="col">
<?php echo translate('Level') ?>
<select class="form-control chosen" id="filter[Level]" onchange="filterLog(this)"><option value="">---</option></select>
</td>
<td class="col">
<?php echo translate('File') ?>
<select class="form-control chosen" id="filter[File]" onchange="filterLog(this)"><option value="">------</option></select>
</td>
<td class="col">
<?php echo translate('Line') ?>
<select class="form-control chosen" id="filter[Line]" onchange="filterLog(this)"><option value="">----</option></select>
</td>
</tr>
</table>
<input type="reset" value="<?php echo translate('Reset') ?>" onclick="resetLog()"/>
</div>
<form name="logForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<table id="logTable" class="major">
<thead class="thead-highlight">
<tr>
<th><?php echo translate('DateTime') ?></th>
<th class="table-th-nosort"><?php echo translate('Component') ?></th>
<th class="table-th-nosort"><?php echo translate('Server') ?></th>
<th class="table-th-nosort"><?php echo translate('Pid') ?></th>
<th class="table-th-nosort"><?php echo translate('Level') ?></th>
<th class="table-th-nosort"><?php echo translate('Message') ?></th>
<th class="table-th-nosort"><?php echo translate('File') ?></th>
<th class="table-th-nosort"><?php echo translate('Line') ?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="contentButtons">
</div>
</form>
</div>
</div>
<div id="exportLog" class="overlay">
<div class="overlayHeader">
<div class="overlayTitle"><?php echo translate('ExportLog') ?></div>

View File

@ -452,11 +452,6 @@ $savejpegopts = array(
'Frames + Analysis images (if available)' => 3,
);
$videowriteropts = array(
'Disabled' => 0,
'X264 Encode' => 1,
'H264 Camera Passthrough' => 2
);
xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor->Name()) );
?>
@ -922,7 +917,17 @@ if ( $monitor->Type() == 'Local' ) {
case 'storage' :
?>
<tr><td><?php echo translate('SaveJPEGs') ?></td><td><select name="newMonitor[SaveJPEGs]"><?php foreach ( $savejpegopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->SaveJPEGs() ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('VideoWriter') ?></td><td><select name="newMonitor[VideoWriter]"><?php foreach ( $videowriteropts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->VideoWriter() ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('VideoWriter') ?></td><td>
<?php
$videowriteropts = array(
0 => 'Disabled',
1 => 'X264 Encode',
);
if ($monitor->Type() == 'Ffmpeg' )
$videowriteropts[2]='H264 Camera Passthrough';
echo htmlselect( 'newMonitor[VideoWriter]', $videowriteropts, $monitor->VideoWriter() );
?>
</td></tr>
<tr><td><?php echo translate('OptionalEncoderParam') ?></td><td><textarea name="newMonitor[EncoderParameters]" rows="4" cols="36"><?php echo validHtmlStr($monitor->EncoderParameters()) ?></textarea></td></tr>
<tr><td><?php echo translate('RecordAudio') ?></td><td><input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ( $monitor->RecordAudio() ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php

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

@ -105,7 +105,7 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
} # end if has previous events
if ( ! $Event->file_exists() ) {
$EventsByMonitor[$event['MonitorId']]['FileMissing'][] = $Event;
} else if ( ! filesize( $Event->Path().'/'.$Event->DefaultVideo() ) ) {
} else if ( ! $Event->file_size() ) {
$EventsByMonitor[$event['MonitorId']]['ZeroSize'][] = $Event;
}
$EventsByMonitor[$event['MonitorId']]['Events'][] = $Event;

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

@ -18,7 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canView( 'Events' ) ) {
if ( !canView('Events') ) {
$view = 'error';
return;
}
@ -43,11 +43,15 @@ if ( $archivetype ) {
if ( $mimetype ) {
$filename = "zmExport.$file_ext";
$filename_path = ZM_DIR_EXPORTS.'/'.$filename;
Logger::Debug("downloading archive from $filename_path");
if ( is_readable($filename_path) ) {
header( "Content-type: application/$mimetype" );
header( "Content-Disposition: attachment; filename=$filename");
header("Content-type: application/$mimetype" );
header("Content-Disposition: inline; filename=$filename");
header('Content-Length: ' . filesize($filename_path) );
set_time_limit(0);
readfile( $filename_path );
if ( ! @readfile( $filename_path ) ) {
Error("Error sending $filename_path");
}
} else {
Error("$filename_path does not exist or is not readable.");
}

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;
}
@ -60,80 +60,96 @@ $path = null;
if ( empty($_REQUEST['path']) ) {
if ( ! empty($_REQUEST['fid']) ) {
if ( $_REQUEST['fid'] == 'snapshot' ) {
$Event = new Event( $_REQUEST['eid'] );
$Frame = new Frame();
$Frame->FrameId('snapshot');
$path = $Event->Path().'/snapshot.jpg';
} else {
$show = empty($_REQUEST['show']) ? 'capture' : $_REQUEST['show'];
$show = empty($_REQUEST['show']) ? 'capture' : $_REQUEST['show'];
if ( ! empty($_REQUEST['eid'] ) ) {
$Event = Event::find_one(array('Id'=> $_REQUEST['eid']));
if ( ! $Event ) {
header('HTTP/1.0 404 Not Found');
Fatal('Event ' . $_REQUEST['eid'].' Not found');
return;
}
$Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'FrameId'=>$_REQUEST['fid']));
if ( ! $Frame ) {
$previousBulkFrame = dbFetchOne('SELECT * FROM Frames WHERE EventId=? AND FrameId < ? ORDER BY FrameID DESC LIMIT 1', NULL, array($_REQUEST['eid'], $_REQUEST['fid'] ) );
$nextBulkFrame = dbFetchOne( "SELECT * FROM Frames WHERE EventId=? AND FrameId > ? ORDER BY FrameID ASC LIMIT 1", NULL, array($_REQUEST['eid'], $_REQUEST['fid'] ) );
if ( $previousBulkFrame and $nextBulkFrame ) {
$Frame = new Frame( $previousBulkFrame );
$Frame->FrameId( $_REQUEST['fid'] );
$percentage = ($Frame->FrameId() - $previousBulkFrame['FrameId']) / ($nextBulkFrame['FrameId'] - $previousBulkFrame['FrameId']);
$Frame->Delta( $previousBulkFrame['Delta'] + floor( 100* ( $nextBulkFrame['Delta'] - $previousBulkFrame['Delta'] ) * $percentage )/100 );
Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousBulkFrame['Delta'] . " + nextdelta:" . $nextBulkFrame['Delta'] . ' - ' . $previousBulkFrame['Delta'] . ' * ' . $percentage );
} else {
Fatal("No Frame found for event(".$_REQUEST['eid'].") and frame id(".$_REQUEST['fid'].")");
}
}
// Frame can be non-existent. We have Bulk frames. So now we should try to load the bulk frame
} else {
# If we are only specifying fid, then the fid must be the primary key into the frames table. But when the event is specified, then it is the frame #
$Frame = Frame::find_one(array('Id'=>$_REQUEST['fid']));
if ( ! $Frame ) {
header('HTTP/1.0 404 Not Found');
Fatal('Frame ' . $_REQUEST['fid'] . ' Not Found');
return;
}
$Event = Event::find_one(array('Id'=>$Frame->EventId()));
if ( ! $Event ) {
header('HTTP/1.0 404 Not Found');
Fatal('Event ' . $Frame->EventId() . ' Not Found');
return;
}
}
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
}
} else {
if ( empty($_REQUEST['fid']) ) {
header('HTTP/1.0 404 Not Found');
Fatal('No Frame ID specified');
return;
}
if ( ! file_exists( $path ) ) {
Logger::Debug( "$path does not exist");
# Generate the frame JPG
if ( !empty($_REQUEST['eid']) ) {
$Event = Event::find_one(array('Id'=>$_REQUEST['eid']));
if ( ! $Event ) {
header('HTTP/1.0 404 Not Found');
Fatal('Event ' . $_REQUEST['eid'].' Not found');
return;
}
if ( $_REQUEST['fid'] == 'snapshot' ) {
$Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Score'=>$Event->MaxScore()));
if ( ! $Frame )
$Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid']));
if ( ! $Frame ) {
$Frame = new Frame();
$Frame->Delta(1);
$Frame->FrameId('snapshot');
}
$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']));
if ( ! $Frame ) {
$previousBulkFrame = dbFetchOne(
'SELECT * FROM Frames WHERE EventId=? AND FrameId < ? ORDER BY FrameID DESC LIMIT 1',
NULL, array($_REQUEST['eid'], $_REQUEST['fid'])
);
$nextBulkFrame = dbFetchOne(
'SELECT * FROM Frames WHERE EventId=? AND FrameId > ? ORDER BY FrameID ASC LIMIT 1',
NULL, array($_REQUEST['eid'], $_REQUEST['fid'])
);
if ( $previousBulkFrame and $nextBulkFrame ) {
$Frame = new Frame($previousBulkFrame);
$Frame->FrameId($_REQUEST['fid']);
$percentage = ($Frame->FrameId() - $previousBulkFrame['FrameId']) / ($nextBulkFrame['FrameId'] - $previousBulkFrame['FrameId']);
$Frame->Delta($previousBulkFrame['Delta'] + floor( 100* ( $nextBulkFrame['Delta'] - $previousBulkFrame['Delta'] ) * $percentage )/100);
Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousBulkFrame['Delta'] . " + nextdelta:" . $nextBulkFrame['Delta'] . ' - ' . $previousBulkFrame['Delta'] . ' * ' . $percentage );
} else {
Fatal('No Frame found for event('.$_REQUEST['eid'].') and frame id('.$_REQUEST['fid'].')');
}
}
// Frame can be non-existent. We have Bulk frames. So now we should try to load the bulk frame
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
}
} else {
# If we are only specifying fid, then the fid must be the primary key into the frames table. But when the event is specified, then it is the frame #
$Frame = Frame::find_one(array('Id'=>$_REQUEST['fid']));
if ( ! $Frame ) {
header('HTTP/1.0 404 Not Found');
Fatal('Frame ' . $_REQUEST['fid'] . ' Not Found');
return;
}
$Event = Event::find_one(array('Id'=>$Frame->EventId()));
if ( ! $Event ) {
header('HTTP/1.0 404 Not Found');
Fatal('Event ' . $Frame->EventId() . ' Not Found');
return;
}
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
} # end if have eid
if ( ! file_exists($path) ) {
Logger::Debug("$path does not exist");
# Generate the frame JPG
if ( $show == 'capture' and $Event->DefaultVideo() ) {
if ( ! file_exists($Event->Path().'/'.$Event->DefaultVideo()) ) {
header('HTTP/1.0 404 Not Found');
Fatal("Can't create frame images from video becuase there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() );
Fatal("Can't create frame images from video because there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() );
}
$command ='ffmpeg -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -frames:v 1 '.$path;
#$command ='ffmpeg -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path;
#$command ='ffmpeg -v 0 -i '.$Storage->Path().'/'.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path;
Logger::Debug( "Running $command" );
Logger::Debug("Running $command");
$output = array();
$retval = 0;
exec( $command, $output, $retval );
@ -142,13 +158,15 @@ Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousB
header('HTTP/1.0 404 Not Found');
Fatal("Can't create frame images from video for this event (".$Event->DefaultVideo() );
}
$Event->DiskSpace( null );
# Generating an image file will use up more disk space, so update the Event record.
$Event->DiskSpace(null);
$Event->save();
} else {
header('HTTP/1.0 404 Not Found');
Fatal("Can't create frame images from video becuase there is no video file for this event (".$Event->DefaultVideo() );
Fatal("Can't create frame $show images from video because there is no video file for this event at ".
$Event->Path().'/'.$Event->DefaultVideo() );
}
}
} # end if ! file_exists($path)
} else {
Warning('Loading images by path is deprecated');
@ -157,10 +175,10 @@ Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousB
$pos = strpos($path, $dir_events);
if ( $pos == 0 && $pos !== false ) {
if ( ! empty( $user['MonitorIds'] ) ) {
if ( ! empty($user['MonitorIds']) ) {
$imageOk = false;
$pathMonId = substr( $path, 0, strspn( $path, '1234567890' ) );
foreach ( preg_split( '/["\'\s]*,["\'\s]*/', $user['MonitorIds'] ) as $monId ) {
$pathMonId = substr($path, 0, strspn($path, '1234567890'));
foreach ( preg_split('/["\'\s]*,["\'\s]*/', $user['MonitorIds']) as $monId ) {
if ( $pathMonId == $monId ) {
$imageOk = true;
break;
@ -172,39 +190,39 @@ Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousB
} else {
$errorText = 'Invalid image path';
}
if ( ! file_exists( $path ) ) {
if ( ! file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
Fatal("Image not found at $path");
}
}
$scale=0;
if( !empty($_REQUEST['scale']) ) {
if (is_numeric($_REQUEST['scale'])) {
if ( !empty($_REQUEST['scale']) ) {
if ( is_numeric($_REQUEST['scale']) ) {
$x = $_REQUEST['scale'];
if($x >= 1 and $x <= 400)
if ( $x >= 1 and $x <= 400 )
$scale=$x;
}
}
$width=0;
if ( !empty($_REQUEST['width']) ) {
if (is_numeric($_REQUEST['width'])) {
if ( is_numeric($_REQUEST['width']) ) {
$x = $_REQUEST['width'];
if($x >= 10 and $x <= 8000)
if ( $x >= 10 and $x <= 8000 )
$width=$x;
}
}
$height=0;
if( !empty($_REQUEST['height']) ) {
if (is_numeric($_REQUEST['height'])) {
if ( !empty($_REQUEST['height']) ) {
if ( is_numeric($_REQUEST['height']) ) {
$x = $_REQUEST['height'];
if($x >= 10 and $x <= 8000)
if ( $x >= 10 and $x <= 8000 )
$height=$x;
}
}
header( 'Content-type: image/jpeg' );
header('Content-type: image/jpeg');
# This is so that Save Image As give a useful filename
if ( $Event ) {
@ -215,19 +233,19 @@ ob_clean();
flush();
if ( $errorText ) {
Error( $errorText );
Error($errorText);
} else {
if ( ( $scale==0 || $scale==100 ) && $width==0 && $height==0 ) {
if ( ! readfile( $path ) ) {
Error("No bytes read from ". $path );
if ( !readfile($path) ) {
Error('No bytes read from '. $path);
}
} else {
Logger::Debug("Doing a scaled image: scale($scale) width($width) height($height)");
$i = 0;
if ( ! ( $width && $height ) ) {
$i = imagecreatefromjpeg( $path );
$oldWidth = imagesx( $i );
$oldHeight = imagesy( $i );
$i = imagecreatefromjpeg($path);
$oldWidth = imagesx($i);
$oldHeight = imagesy($i);
if ( $width == 0 && $height == 0 ) { // scale has to be set to get here with both zero
$width = $oldWidth * $scale / 100.0;
$height= $oldHeight * $scale / 100.0;
@ -237,23 +255,23 @@ if ( $errorText ) {
$height = ($width * $oldHeight) / $oldWidth;
}
if ( $width == $oldWidth && $height == $oldHeight) {
Warning( 'No change to width despite scaling.' );
Warning('No change to width despite scaling.');
}
}
# Slight optimisation, thumbnails always specify width and height, so we can cache them.
$scaled_path = preg_replace('/\.jpg$/', "-${width}x${height}.jpg", $path );
if ( ! file_exists( $scaled_path ) or ! readfile( $scaled_path ) ) {
Logger::Debug( "Cached scaled image does not exist at $scaled_path or is no good.. Creating it");
if ( ! file_exists($scaled_path) or ! readfile($scaled_path) ) {
Logger::Debug("Cached scaled image does not exist at $scaled_path or is no good.. Creating it");
ob_start();
if ( ! $i )
$i = imagecreatefromjpeg( $path );
$iScale = imagescale( $i, $width, $height );
imagejpeg( $iScale );
imagedestroy( $i );
imagedestroy( $iScale );
$i = imagecreatefromjpeg($path);
$iScale = imagescale($i, $width, $height);
imagejpeg($iScale);
imagedestroy($i);
imagedestroy($iScale);
$scaled_jpeg_data = ob_get_contents();
file_put_contents( $scaled_path, $scaled_jpeg_data );
file_put_contents($scaled_path, $scaled_jpeg_data);
ob_end_clean();
echo $scaled_jpeg_data;
}