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

pull/2077/head
Isaac Connor 2017-07-06 11:58:57 -04:00
commit f9be7f0fa0
36 changed files with 1597 additions and 1572 deletions

View File

@ -28,7 +28,7 @@ New installs
1. Unless you are already using MariaDB server, you need to ensure that the
server is configured to start during boot and properly secured by running:
sudo dnf install mariadb-server
sudo yum install mariadb-server
sudo systemctl enable mariadb
sudo systemctl start mariadb.service
mysql_secure_installation

View File

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

View File

@ -4,3 +4,5 @@ var/cache/zoneminder/events
var/cache/zoneminder/images
var/cache/zoneminder/temp
usr/share/zoneminder/db
etc/zm
etc/zm/conf.d

View File

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

View File

@ -13,11 +13,11 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa
,libavutil-dev (>= 6:10~)
,libswscale-dev (>= 6:10~)
,libbz2-dev
,libgcrypt-dev
,libgcrypt-dev | libgcrypt11-dev
,libcurl4-gnutls-dev
,libgnutls-openssl-dev
,libjpeg8-dev | libjpeg9-dev | libjpeg62-turbo-dev
,libmysqlclient-dev
,libmysqlclient-dev | libmariadbclient-dev
,libpcre3-dev
,libpolkit-gobject-1-dev
,libv4l-dev (>= 0.8.3) [!hurd-any]

View File

@ -21,6 +21,8 @@ if [ "$1" = "configure" ]; then
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/etc/init.d/mysql" ]; then
@ -46,10 +48,10 @@ if [ "$1" = "configure" ]; then
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo 'mysql not found, assuming remote server.'
echo 'mysql not found, assuming remote server.'
fi
else

View File

@ -297,24 +297,28 @@ sub terminate {
sub reinitialise {
my $this = shift;
# So if the logger is initialized, we just return. Since the logger is NORMALLY initialized... the rest of this function never executes.
return unless ( $this->{initialised} );
# Bit of a nasty hack to reopen connections to log files and the DB
my $syslogLevel = $this->syslogLevel();
$this->syslogLevel( NOLOG );
$this->syslogLevel( $syslogLevel ) if ( $syslogLevel > NOLOG );
my $logfileLevel = $this->fileLevel();
$this->fileLevel( NOLOG );
$this->fileLevel( $logfileLevel ) if ( $logfileLevel > NOLOG );
my $databaseLevel = $this->databaseLevel();
$this->databaseLevel( NOLOG );
$this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG );
my $screenLevel = $this->termLevel();
$this->termLevel( NOLOG );
$this->syslogLevel( $syslogLevel ) if ( $syslogLevel > NOLOG );
$this->fileLevel( $logfileLevel ) if ( $logfileLevel > NOLOG );
$this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG );
$this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG );
$this->termLevel( $screenLevel ) if ( $screenLevel > NOLOG );
}
# Prevents undefined logging levels
sub limit {
my $this = shift;
my $level = shift;
@ -375,12 +379,16 @@ sub level {
my $level = shift;
if ( defined($level) ) {
$this->{level} = $this->limit( $level );
# effectiveLevel is the highest logging level used by any of the outputs.
$this->{effectiveLevel} = NOLOG;
$this->{effectiveLevel} = $this->{termLevel} if ( $this->{termLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{databaseLevel} if ( $this->{databaseLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{fileLevel} if ( $this->{fileLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{effectiveLevel} );
# 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} );
}
return( $this->{level} );
}
@ -400,6 +408,7 @@ sub termLevel {
my $this = shift;
my $termLevel = shift;
if ( defined($termLevel) ) {
# What is the point of this next lint if we are just going to overwrite it with the next line? I propose we move it down one line or remove it altogether
$termLevel = NOLOG if ( !$this->{hasTerm} );
$termLevel = $this->limit( $termLevel );
if ( $this->{termLevel} != $termLevel ) {

View File

@ -174,7 +174,7 @@ if ( ! $server_up ) {
$attempts++;
Error("Waiting for zmdc.pl server process, attempt $attempts" );
Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY);
usleep(20000);
usleep(200000);
} # end while
} elsif ( defined($cpid) ) {
ZMServer::run();

View File

@ -20,6 +20,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# ==========================================================================
use strict;
use bytes;
@ -62,57 +63,56 @@ if ( ! defined $interval ) {
$interval = eval($Config{ZM_TELEMETRY_INTERVAL});
}
if ( $Config{ZM_TELEMETRY_DATA} or $force )
{
print "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n";
if ( $Config{ZM_TELEMETRY_DATA} or $force ) {
print "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n";
my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD};
my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD};
while( 1 ) {
my $now = time();
my $since_last_check = $now-$lastCheck;
Debug(" Last Check time (now($now) - lastCheck($lastCheck)) = $since_last_check > interval($interval) or force($force)");
if ( $since_last_check < 0 ) {
Warning( "Seconds since last check is negative! Which means that lastCheck is in the future!" );
next;
}
if ( ( ($now-$lastCheck) > $interval ) or $force ) {
print "Collecting data to send to ZoneMinder Telemetry server.\n";
my $dbh = zmDbConnect();
# Build the telemetry hash
# We should keep *BSD systems in mind when calling system commands
my %telemetry;
$telemetry{uuid} = getUUID($dbh);
$telemetry{ip} = getIP();
$telemetry{timestamp} = strftime( "%Y-%m-%dT%H:%M:%S%z", localtime() );
$telemetry{monitor_count} = countQuery($dbh,"Monitors");
$telemetry{event_count} = countQuery($dbh,"Events");
$telemetry{architecture} = runSysCmd("uname -p");
($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro();
$telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION;
$telemetry{system_memory} = totalmem();
$telemetry{processor_count} = cpu_count();
$telemetry{monitors} = getMonitorRef($dbh);
Info( "Sending data to ZoneMinder Telemetry server." );
my $result = jsonEncode( \%telemetry );
if ( sendData($result) ) {
my $sql = q`UPDATE Config SET Value = ? WHERE Name = 'ZM_TELEMETRY_LAST_UPLOAD'`;
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $now ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
$Config{ZM_TELEMETRY_LAST_UPLOAD} = $now;
}
zmDbDisconnect();
} elsif ( -t STDIN ) {
print "Update agent sleeping for 1 hour because ($now-$lastCheck=$since_last_check > $interval\n";
}
sleep( 3600 );
while( 1 ) {
my $now = time();
my $since_last_check = $now-$lastCheck;
Debug(" Last Check time (now($now) - lastCheck($lastCheck)) = $since_last_check > interval($interval) or force($force)");
if ( $since_last_check < 0 ) {
Warning( "Seconds since last check is negative! Which means that lastCheck is in the future!" );
next;
}
print "Update agent exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n";
if ( ( ($now-$lastCheck) > $interval ) or $force ) {
print "Collecting data to send to ZoneMinder Telemetry server.\n";
my $dbh = zmDbConnect();
# Build the telemetry hash
# We should keep *BSD systems in mind when calling system commands
my %telemetry;
$telemetry{uuid} = getUUID($dbh);
$telemetry{ip} = getIP();
$telemetry{timestamp} = strftime( '%Y-%m-%dT%H:%M:%S%z', localtime() );
$telemetry{monitor_count} = countQuery($dbh,'Monitors');
$telemetry{event_count} = countQuery($dbh,'Events');
$telemetry{architecture} = runSysCmd('uname -p');
($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro();
$telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION;
$telemetry{system_memory} = totalmem();
$telemetry{processor_count} = cpu_count();
$telemetry{monitors} = getMonitorRef($dbh);
Info( 'Sending data to ZoneMinder Telemetry server.' );
my $result = jsonEncode( \%telemetry );
if ( sendData($result) ) {
my $sql = q`UPDATE Config SET Value = ? WHERE Name = 'ZM_TELEMETRY_LAST_UPLOAD'`;
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $now ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
$Config{ZM_TELEMETRY_LAST_UPLOAD} = $now;
}
zmDbDisconnect();
} elsif ( -t STDIN ) {
print "Update agent sleeping for 1 hour because ($now-$lastCheck=$since_last_check > $interval\n";
}
sleep( 3600 );
}
print 'Update agent exiting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n";
}
###############
@ -121,227 +121,227 @@ if ( $Config{ZM_TELEMETRY_DATA} or $force )
# Find, verify, then run the supplied system command
sub runSysCmd {
my $msg = shift;
my @arguments = split(/ /,$msg);
chomp($arguments[0]);
my $path = qx( which $arguments[0] );
my $msg = shift;
my @arguments = split(/ /,$msg);
chomp($arguments[0]);
my $path = qx( which $arguments[0] );
my $status = $? >> 8;
my $result = "";
if ( !$path || $status ) {
Warning( "Cannot find the $arguments[0] executable." );
} else {
chomp($path);
$arguments[0] = $path;
my $cmd = join(" ",@arguments);
$result = qx( $cmd );
chomp($result);
}
my $status = $? >> 8;
my $result = '';
if ( !$path || $status ) {
Warning( "Cannot find the $arguments[0] executable." );
} else {
chomp($path);
$arguments[0] = $path;
my $cmd = join(' ',@arguments);
$result = qx( $cmd );
chomp($result);
}
return $result;
return $result;
}
# Upload message data to ZoneMinder telemetry server
sub sendData {
my $msg = shift;
my $msg = shift;
my $ua = LWP::UserAgent->new;
my $server_endpoint = $Config{ZM_TELEMETRY_SERVER_ENDPOINT};
my $ua = LWP::UserAgent->new;
my $server_endpoint = $Config{ZM_TELEMETRY_SERVER_ENDPOINT};
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
$ua->proxy( "https", $Config{ZM_UPDATE_CHECK_PROXY} );
}
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
$ua->proxy( 'https', $Config{ZM_UPDATE_CHECK_PROXY} );
}
Debug("Posting telemetry data to: $server_endpoint");
Debug("Posting telemetry data to: $server_endpoint");
# set custom HTTP request header fields
my $req = HTTP::Request->new(POST => $server_endpoint);
$req->header('content-type' => 'application/x-www-form-urlencoded');
$req->header('content-length' => length($msg));
$req->header('connection' => 'Close');
$req->content($msg);
my $resp = $ua->request($req);
my $resp_msg = $resp->decoded_content;
my $resp_code = $resp->code;
if ($resp->is_success) {
Info("Telemetry data uploaded successfully.");
Debug("Telemetry server upload success response message: $resp_msg");
} else {
Warning("Telemetry server returned HTTP POST error code: $resp_code");
Debug("Telemetry server upload failure response message: $resp_msg");
}
return $resp->is_success;
# set custom HTTP request header fields
my $req = HTTP::Request->new(POST => $server_endpoint);
$req->header('content-type' => 'application/x-www-form-urlencoded');
$req->header('content-length' => length($msg));
$req->header('connection' => 'Close');
$req->content($msg);
my $resp = $ua->request($req);
my $resp_msg = $resp->decoded_content;
my $resp_code = $resp->code;
if ($resp->is_success) {
Info('Telemetry data uploaded successfully.');
Debug("Telemetry server upload success response message: $resp_msg");
} else {
Warning("Telemetry server returned HTTP POST error code: $resp_code");
Debug("Telemetry server upload failure response message: $resp_msg");
}
return $resp->is_success;
}
# Retrieves the UUID from the database. Creates a new UUID if one does not exist.
sub getUUID {
my $dbh = shift;
my $uuid= "";
my $dbh = shift;
my $uuid= "";
# Verify the current UUID is valid and not nil
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne "00000000-0000-0000-0000-000000000000" )) {
$uuid = $Config{ZM_TELEMETRY_UUID};
} else {
my $sql = "SELECT uuid()";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
$sth->finish();
# Verify the current UUID is valid and not nil
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne '00000000-0000-0000-0000-000000000000' )) {
$uuid = $Config{ZM_TELEMETRY_UUID};
} else {
my $sql = 'SELECT uuid()';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
$sth->finish();
$sql = "UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'";
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
Debug("Using UUID of: $uuid");
$sql = q`UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`;
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
Debug("Using UUID of: $uuid");
return $uuid;
return $uuid;
}
# Retrieves the local server's external IP address
sub getIP {
my $ipaddr = "0.0.0.0";
my $ua = LWP::UserAgent->new;
my $server_endpoint = "https://wiki.zoneminder.com/ip.php";
my $ipaddr = '0.0.0.0';
my $ua = LWP::UserAgent->new;
my $server_endpoint = 'https://wiki.zoneminder.com/ip.php';
my $req = HTTP::Request->new(GET => $server_endpoint);
my $resp = $ua->request($req);
my $req = HTTP::Request->new(GET => $server_endpoint);
my $resp = $ua->request($req);
if ($resp->is_success) {
$ipaddr = $resp->decoded_content;
}
if ($resp->is_success) {
$ipaddr = $resp->decoded_content;
}
Debug("Found external ip address of: $ipaddr");
Debug("Found external ip address of: $ipaddr");
return $ipaddr;
return $ipaddr;
}
# As the name implies, just your average mysql count query
sub countQuery {
my $dbh = shift;
my $table = shift;
my $dbh = shift;
my $table = shift;
my $sql = "SELECT count(*) FROM $table";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $count = $sth->fetchrow_array();
$sth->finish();
my $sql = "SELECT count(*) FROM $table";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $count = $sth->fetchrow_array();
$sth->finish();
return $count
return $count
}
# Returns a reference to an array of hashes containing data from all monitors
sub getMonitorRef {
my $dbh = shift;
my $dbh = shift;
my $sql = "SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({});
my $sql = 'SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({});
return $arrayref;
return $arrayref;
}
sub getDistro {
my $kernel = "";
my $distro = "";
my $version = "";
my @uname = uname();
my $kernel = '';
my $distro = '';
my $version = '';
my @uname = uname();
if ( $uname[0] =~ /Linux/ ) {
Debug("Linux distro detected.");
($kernel, $distro, $version) = linuxDistro();
} elsif ( $uname[0] =~ /.*BSD/ ) {
Debug("BSD distro detected.");
$kernel = $uname[3];
$distro = $uname[0];
$version = $uname[2];
} elsif ( $uname[0] =~ /Darwin/ ) {
Debug("Mac OS distro detected.");
$kernel = $uname[3];
$distro = runSysCmd("sw_vers -productName");
$version = runSysCmd("sw_vers -productVersion");
} elsif ( $uname[0] =~ /SunOS|Solaris/ ) {
Debug("Sun Solaris detected.");
$kernel = $uname[3];
$distro = $uname[1];
$version = $uname[2];
} else {
Warning("ZoneMinder was unable to determine the host system. Please report.");
$kernel = "Unknown";
$distro = "Unknown";
$version = "Unknown";
}
if ( $uname[0] =~ /Linux/ ) {
Debug('Linux distro detected.');
($kernel, $distro, $version) = linuxDistro();
} elsif ( $uname[0] =~ /.*BSD/ ) {
Debug('BSD distro detected.');
$kernel = $uname[3];
$distro = $uname[0];
$version = $uname[2];
} elsif ( $uname[0] =~ /Darwin/ ) {
Debug('Mac OS distro detected.');
$kernel = $uname[3];
$distro = runSysCmd('sw_vers -productName');
$version = runSysCmd('sw_vers -productVersion');
} elsif ( $uname[0] =~ /SunOS|Solaris/ ) {
Debug('Sun Solaris detected.');
$kernel = $uname[3];
$distro = $uname[1];
$version = $uname[2];
} else {
Warning('ZoneMinder was unable to determine the host system. Please report.');
$kernel = 'Unknown';
$distro = 'Unknown';
$version = 'Unknown';
}
return ($kernel, $distro, $version);
return ($kernel, $distro, $version);
}
sub linuxDistro {
my @uname = uname();
my $kernel = $uname[2];
my $distro = "Unknown Linux Distro";
my $version = "Unknown Linux Version";
my $found = 0;
my @uname = uname();
my $kernel = $uname[2];
my $distro = 'Unknown Linux Distro';
my $version = 'Unknown Linux Version';
my $found = 0;
# os-release is the standard for many new distros based on systemd
if ( -f "/etc/os-release" ) {
open(my $RELFILE,"<","/etc/os-release") or die( "Can't Open file: $!\n" );
# os-release is the standard for many new distros based on systemd
if ( -f '/etc/os-release' ) {
open(my $RELFILE,'<','/etc/os-release') or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^NAME=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^VERSION_ID=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
# exists on many distros but does not always contain useful information, such as redhat
} elsif ( -f '/etc/lsb-release' ) {
open(my $RELFILE,'<','/etc/lsb-release') or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^DISTRIB_DESCRIPTION=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^DISTRIB_RELEASE=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
}
# If all else fails, search through a list of known release files until we find one
if ( !$found ) {
my @releasefile = ('/etc/SuSE-release', '/etc/redhat-release', '/etc/redhat_version',
'/etc/fedora-release', '/etc/slackware-release', '/etc/slackware-version',
'/etc/debian_release', '/etc/debian_version', '/etc/mandrake-release',
'/etc/yellowdog-release', '/etc/gentoo-release');
foreach (@releasefile) {
if ( -f $_ ) {
open(my $RELFILE,'<',$_) or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^NAME=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^VERSION_ID=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
if ( /(.*).* (\d+\.?\d*) .*/ ) {
$distro = $1;
$version = $2;
$found = 1;
}
}
close $RELFILE;
# exists on many distros but does not always contain useful information, such as redhat
} elsif ( -f "/etc/lsb-release" ) {
open(my $RELFILE,"<","/etc/lsb-release") or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^DISTRIB_DESCRIPTION=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^DISTRIB_RELEASE=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
close $RELFILE;
last;
}
}
}
# If all else fails, search through a list of known release files until we find one
if ( !$found ) {
my @releasefile = ("/etc/SuSE-release", "/etc/redhat-release", "/etc/redhat_version",
"/etc/fedora-release", "/etc/slackware-release", "/etc/slackware-version",
"/etc/debian_release", "/etc/debian_version", "/etc/mandrake-release",
"/etc/yellowdog-release", "/etc/gentoo-release");
foreach (@releasefile) {
if ( -f $_ ) {
open(my $RELFILE,"<",$_) or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /(.*).* (\d+\.?\d*) .*/ ) {
$distro = $1;
$version = $2;
$found = 1;
}
}
close $RELFILE;
last;
}
}
}
if ( !$found ) {
Warning('ZoneMinder was unable to determine Linux distro. Please report.');
}
if ( !$found ) {
Warning("ZoneMinder was unable to determine Linux distro. Please report.");
}
return ($kernel, $distro, $version);
return ($kernel, $distro, $version);
}
1;

View File

@ -39,24 +39,24 @@ void zmLoadConfig() {
// update the Config hash with those values
DIR* configSubFolder = opendir(ZM_CONFIG_SUBDIR);
if ( configSubFolder ) { // subfolder exists and is readable
char glob_pattern[PATH_MAX] = "";
snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.conf", ZM_CONFIG_SUBDIR );
char glob_pattern[PATH_MAX] = "";
snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.conf", ZM_CONFIG_SUBDIR );
glob_t pglob;
int glob_status = glob( glob_pattern, 0, 0, &pglob );
if ( glob_status != 0 ) {
if ( glob_status < 0 ) {
Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) );
} else {
Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status );
}
glob_t pglob;
int glob_status = glob( glob_pattern, 0, 0, &pglob );
if ( glob_status != 0 ) {
if ( glob_status < 0 ) {
Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) );
} else {
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) {
process_configfile(pglob.gl_pathv[i]);
}
closedir(configSubFolder);
Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status );
}
globfree( &pglob );
} else {
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) {
process_configfile(pglob.gl_pathv[i]);
}
closedir(configSubFolder);
}
globfree( &pglob );
}
zmDbConnect();

View File

@ -195,7 +195,7 @@ void Logger::initialise( const std::string &id, const Options &options ) {
level( tempLevel );
mFlush = false;
if (envPtr = getenv( "LOG_FLUSH")) {
if ( (envPtr = getenv("LOG_FLUSH")) ) {
mFlush = atoi( envPtr );
} else if ( config.log_debug ) {
mFlush = true;

View File

@ -30,8 +30,7 @@ class Monitor;
#define TV_2_FLOAT( tv ) ( double((tv).tv_sec) + (double((tv).tv_usec) / 1000000.0) )
class StreamBase
{
class StreamBase {
public:
typedef enum { STREAM_JPEG, STREAM_RAW, STREAM_ZIP, STREAM_SINGLE, STREAM_MPEG } StreamType;
@ -110,8 +109,7 @@ protected:
virtual void processCommand( const CmdMsg *msg )=0;
public:
StreamBase()
{
StreamBase() {
monitor = 0;
type = DEFAULT_TYPE;
@ -145,32 +143,27 @@ public:
}
virtual ~StreamBase();
void setStreamType( StreamType p_type )
{
void setStreamType( StreamType p_type ) {
type = p_type;
}
void setStreamFormat( const char *p_format )
{
void setStreamFormat( const char *p_format ) {
format = p_format;
}
void setStreamScale( int p_scale )
{
void setStreamScale( int p_scale ) {
scale = p_scale;
if ( ! scale )
scale = DEFAULT_SCALE;
}
void setStreamReplayRate( int p_rate )
{
void setStreamReplayRate( int p_rate ) {
replay_rate = p_rate;
}
void setStreamMaxFPS( double p_maxfps )
{
void setStreamMaxFPS( double p_maxfps ) {
maxfps = p_maxfps;
}
void setStreamBitrate( int p_bitrate )
{
void setStreamBitrate( int p_bitrate ) {
bitrate = p_bitrate;
}
void setStreamQueue( int p_connkey )
{
void setStreamQueue( int p_connkey ) {
connkey = p_connkey;
}
virtual void openComms();

View File

@ -155,7 +155,7 @@ int X264MP4Writer::Open() {
}
/* Search SPS NAL for AVC information */
for ( unsigned int i = 0; i < i_nals; i++ ) {
for ( int i = 0; i < i_nals; i++ ) {
if ( nals[i].i_type == NAL_SPS ) {
x264_profleindication = nals[i].p_payload[5];
x264_profilecompat = nals[i].p_payload[6];
@ -467,7 +467,7 @@ void X264MP4Writer::x264encodeloop(bool bFlush) {
/* Got a frame. Copy this new frame into the previous frame */
if ( frame_size > 0 ) {
/* Copy the NALs and the payloads */
for ( unsigned int i = 0; i < i_nals; i++ ) {
for ( int i = 0; i < i_nals; i++ ) {
prevnals.push_back(nals[i]);
prevpayload.append(nals[i].p_payload, nals[i].i_payload);
}

View File

@ -618,7 +618,7 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) {
int duration;
//Scale the PTS of the outgoing packet to be the correct time base
if (ipkt->pts != AV_NOPTS_VALUE) {
if ( ipkt->pts != AV_NOPTS_VALUE ) {
if ( ! video_last_pts ) {
// This is the first packet.
@ -696,9 +696,9 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) {
}
AVPacket safepkt;
memcpy(&safepkt, &opkt, sizeof(AVPacket));
memcpy( &safepkt, &opkt, sizeof(AVPacket) );
Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts, opkt.duration );
Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts, opkt.duration );
if ((opkt.data == NULL)||(opkt.size < 1)) {
Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__ );
dumpPacket( ipkt);
@ -714,10 +714,14 @@ Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts
video_previous_dts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance
video_previous_pts = opkt.pts;
ret = av_interleaved_write_frame(oc, &opkt);
if(ret<0){
if ( ret < 0 ) {
// There's nothing we can really do if the frame is rejected, just drop it and get on with the next
Warning("%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) ", __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret));
dumpPacket(&safepkt);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
zm_dump_codecpar( video_input_stream->codecpar );
zm_dump_codecpar( video_output_stream->codecpar );
#endif
}
}

View File

@ -28,44 +28,41 @@
#include "zm_monitorstream.h"
bool ValidateAccess( User *user, int mon_id ) {
bool allowed = true;
bool allowed = true;
if ( mon_id > 0 ) {
if ( user->getStream() < User::PERM_VIEW )
allowed = false;
if ( !user->canAccess( mon_id ) )
allowed = false;
} else {
if ( user->getEvents() < User::PERM_VIEW )
allowed = false;
}
if ( !allowed ) {
Error( "Error, insufficient privileges for requested action" );
exit( -1 );
if ( mon_id > 0 ) {
if ( user->getStream() < User::PERM_VIEW )
allowed = false;
if ( !user->canAccess( mon_id ) )
allowed = false;
} else {
Debug( 1, "User allowed.");
}
return( allowed );
if ( user->getEvents() < User::PERM_VIEW )
allowed = false;
}
if ( !allowed ) {
Error( "Error, insufficient privileges for requested action" );
exit( -1 );
}
return( allowed );
}
int main( int argc, const char *argv[] )
{
self = argv[0];
int main( int argc, const char *argv[] ) {
self = argv[0];
srand( getpid() * time( 0 ) );
srand( getpid() * time( 0 ) );
enum { ZMS_MONITOR, ZMS_EVENT } source = ZMS_MONITOR;
enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_ZIP, ZMS_SINGLE } mode = ZMS_JPEG;
char format[32] = "";
int monitor_id = 0;
time_t event_time = 0;
int event_id = 0;
unsigned int frame_id = 1;
unsigned int scale = 100;
unsigned int rate = 100;
double maxfps = 10.0;
unsigned int bitrate = 100000;
unsigned int ttl = 0;
enum { ZMS_MONITOR, ZMS_EVENT } source = ZMS_MONITOR;
enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_ZIP, ZMS_SINGLE } mode = ZMS_JPEG;
char format[32] = "";
int monitor_id = 0;
time_t event_time = 0;
int event_id = 0;
unsigned int frame_id = 1;
unsigned int scale = 100;
unsigned int rate = 100;
double maxfps = 10.0;
unsigned int bitrate = 100000;
unsigned int ttl = 0;
EventStream::StreamMode replay = EventStream::MODE_SINGLE;
std::string username;
std::string password;
@ -73,163 +70,158 @@ int main( int argc, const char *argv[] )
unsigned int connkey = 0;
unsigned int playback_buffer = 0;
bool nph = false;
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) ) ) {
nph = true;
}
zmLoadConfig();
logInit( "zms" );
bool nph = false;
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) ) ) {
nph = true;
}
hwcaps_detect();
zmLoadConfig();
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();
logInit( "zms" );
hwcaps_detect();
const char *query = getenv( "QUERY_STRING" );
if ( query ) {
Debug( 1, "Query: %s", query );
char temp_query[1024];
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, "&" )) ) {
parm_no++;
q_ptr = NULL;
}
for ( int p = 0; p < parm_no; p++ ) {
char *name = strtok( parms[p], "=" );
char *value = strtok( NULL, "=" );
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();
const char *query = getenv( "QUERY_STRING" );
if ( query ) {
Debug( 1, "Query: %s", query );
char temp_query[1024];
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, "&" )) ) {
parm_no++;
q_ptr = NULL;
}
for ( int p = 0; p < parm_no; p++ ) {
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;
} else if ( !strcmp( name, "format" ) )
strncpy( format, value, sizeof(format) );
else if ( !strcmp( name, "monitor" ) )
monitor_id = atoi( value );
else if ( !strcmp( name, "time" ) )
event_time = atoi( value );
else if ( !strcmp( name, "event" ) )
event_id = strtoull( value, (char **)NULL, 10 );
else if ( !strcmp( name, "frame" ) )
frame_id = strtoull( value, (char **)NULL, 10 );
else if ( !strcmp( name, "scale" ) )
scale = atoi( value );
else if ( !strcmp( name, "rate" ) )
rate = atoi( value );
else if ( !strcmp( name, "maxfps" ) )
maxfps = atof( value );
else if ( !strcmp( name, "bitrate" ) )
bitrate = atoi( value );
else if ( !strcmp( name, "ttl" ) )
ttl = atoi(value);
else if ( !strcmp( name, "replay" ) ) {
replay = !strcmp( value, "gapless" )?EventStream::MODE_ALL_GAPLESS:EventStream::MODE_SINGLE;
replay = !strcmp( value, "all" )?EventStream::MODE_ALL:replay;
} else if ( !strcmp( name, "connkey" ) )
connkey = atoi(value);
else if ( !strcmp( name, "buffer" ) )
playback_buffer = atoi(value);
else if ( config.opt_use_auth ) {
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
if ( !strcmp( name, "user" ) ) {
username = UriDecode( value );
}
} else {
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( !strcmp( name, "auth" ) ) {
strncpy( auth, value, sizeof(auth) );
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
if ( !strcmp( name, "user" ) ) {
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" ) ) {
monitor_id = atoi( value );
} else if ( !strcmp( name, "time" ) ) {
event_time = atoi( value );
} else if ( !strcmp( name, "event" ) ) {
event_id = strtoull( value, (char **)NULL, 10 );
} else if ( !strcmp( name, "frame" ) ) {
frame_id = strtoull( value, (char **)NULL, 10 );
} else if ( !strcmp( name, "scale" ) ) {
scale = atoi( value );
} else if ( !strcmp( name, "rate" ) ) {
rate = atoi( value );
} else if ( !strcmp( name, "maxfps" ) ) {
maxfps = atof( value );
} else if ( !strcmp( name, "bitrate" ) ) {
bitrate = atoi( value );
} else if ( !strcmp( name, "ttl" ) ) {
ttl = atoi(value);
} else if ( !strcmp( name, "replay" ) ) {
replay = !strcmp( value, "gapless" )?EventStream::MODE_ALL_GAPLESS:EventStream::MODE_SINGLE;
replay = !strcmp( value, "all" )?EventStream::MODE_ALL:replay;
} else if ( !strcmp( name, "connkey" ) ) {
connkey = atoi(value);
} else if ( !strcmp( name, "buffer" ) ) {
playback_buffer = atoi(value);
} else if ( config.opt_use_auth ) {
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
if ( !strcmp( name, "user" ) ) {
username = value;
}
} else {
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( !strcmp( name, "auth" ) ) {
strncpy( auth, value, sizeof(auth) );
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
if ( !strcmp( name, "user" ) ) {
username = UriDecode( value );
Debug( 1, "Have %s for username", username.c_str() );
}
if ( !strcmp( name, "pass" ) ) {
}
if ( !strcmp( name, "pass" ) ) {
password = UriDecode( value );
Debug( 1, "Have %s for password", password.c_str() );
}
}
}
}
} // end foreach parm
} // end if query
}
}
}
}
} // end foreach parm
} // end if query
if ( config.opt_use_auth ) {
User *user = 0;
if ( config.opt_use_auth ) {
User *user = 0;
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
if ( username.length() ) {
user = zmLoadUser( username.c_str() );
}
} else {
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( *auth ) {
user = zmLoadAuthUser( auth, config.auth_hash_ips );
} else {
Debug( 1, "Need both username and password" );
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
if ( username.length() && password.length() ) {
user = zmLoadUser( username.c_str(), password.c_str() );
} else {
Debug( 1, "Need both username and password" );
}
}
} // auth is none or something else
if ( !user ) {
Error( "Unable to authenticate user" );
logTerm();
zmDbClose();
return( -1 );
}
ValidateAccess( user, monitor_id );
} // end if use_auth
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
if ( username.length() ) {
user = zmLoadUser( username.c_str() );
}
} else {
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( *auth ) {
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() );
}
}
}
if ( !user ) {
Error( "Unable to authenticate user" );
logTerm();
zmDbClose();
return( -1 );
}
ValidateAccess( user, monitor_id );
}
setbuf( stdout, 0 );
if ( nph ) {
fprintf( stdout, "HTTP/1.0 200 OK\r\n" );
}
fprintf( stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION );
time_t now = time( 0 );
char date_string[64];
strftime( date_string, sizeof(date_string)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime( &now ) );
setbuf( stdout, 0 );
if ( nph ) {
fprintf( stdout, "HTTP/1.0 200 OK\r\n" );
}
fprintf( stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION );
time_t now = time( 0 );
char date_string[64];
strftime( date_string, sizeof(date_string)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime( &now ) );
fprintf( stdout, "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" );
fprintf( stdout, "Last-Modified: %s\r\n", date_string );
fprintf( stdout, "Cache-Control: no-store, no-cache, must-revalidate\r\n" );
fprintf( stdout, "Cache-Control: post-check=0, pre-check=0\r\n" );
fprintf( stdout, "Pragma: no-cache\r\n");
// Removed as causing more problems than it fixed.
//if ( !nph )
//{
//fprintf( stdout, "Content-Length: 0\r\n");
//}
fprintf( stdout, "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" );
fprintf( stdout, "Last-Modified: %s\r\n", date_string );
fprintf( stdout, "Cache-Control: no-store, no-cache, must-revalidate\r\n" );
fprintf( stdout, "Cache-Control: post-check=0, pre-check=0\r\n" );
fprintf( stdout, "Pragma: no-cache\r\n");
// Removed as causing more problems than it fixed.
//if ( !nph )
//{
//fprintf( stdout, "Content-Length: 0\r\n");
//}
if ( source == ZMS_MONITOR ) {
if ( source == ZMS_MONITOR ) {
MonitorStream stream;
stream.setStreamScale( scale );
stream.setStreamReplayRate( rate );
@ -249,9 +241,9 @@ int main( int argc, const char *argv[] )
stream.setStreamType( MonitorStream::STREAM_JPEG );
} else if ( mode == ZMS_RAW ) {
stream.setStreamType( MonitorStream::STREAM_RAW );
} else if ( mode == ZMS_ZIP ) {
} else if ( mode == ZMS_ZIP ) {
stream.setStreamType( MonitorStream::STREAM_ZIP );
} else if ( mode == ZMS_SINGLE ) {
} else if ( mode == ZMS_SINGLE ) {
stream.setStreamType( MonitorStream::STREAM_SINGLE );
} else {
#if HAVE_LIBAVCODEC

View File

@ -263,16 +263,15 @@ if [ $TYPE == "binary" ]; then
if [[ $REPLY == [yY] ]]; then
sudo dpkg -i $DIRECTORY*.deb
fi;
read -p "Do you want to upload this binary to zmrepo? (y/N)"
if [[ $REPLY == [yY] ]]; then
if [ "$RELEASE" != "" ]; then
scp "zoneminder_${VERSION}-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/"
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/"
else
if [ "$BRANCH" == "" ]; then
scp "zoneminder_${VERSION}-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/"
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/"
else
scp "$DIRECTORY-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/"
scp "$DIRECTORY-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/"
fi;
fi;
fi;

View File

@ -42,26 +42,27 @@ switch ( $_REQUEST['task'] )
$servers_by_Id[$server->Id()] = $server;
}
$minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL;
$maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL;
$minTime = isset($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL;
$maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL;
$limit = 100;
if ( isset($_POST['limit']) ) {
if ( ( !is_integer( $_POST['limit'] ) and !ctype_digit($_POST['limit']) ) ) {
Error("Invalid value for limit " . $_POST['limit'] );
if ( isset($_REQUEST['limit']) ) {
if ( ( !is_integer( $_REQUEST['limit'] ) and !ctype_digit($_REQUEST['limit']) ) ) {
Error("Invalid value for limit " . $_REQUEST['limit'] );
} else {
$limit = $_POST['limit'];
$limit = $_REQUEST['limit'];
}
}
$sortField = 'TimeKey';
if ( isset($_POST['sortField']) ) {
if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) {
Error("Invalid sort field " . $_POST['sortField'] );
if ( isset($_REQUEST['sortField']) ) {
if ( ! in_array( $_REQUEST['sortField'], $filterFields ) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) {
Error("Invalid sort field " . $_REQUEST['sortField'] );
} else {
$sortField = $_POST['sortField'];
$sortField = $_REQUEST['sortField'];
}
}
$sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc';
$filter = isset($_POST['filter'])?$_POST['filter']:array();
$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';
@ -95,6 +96,8 @@ switch ( $_REQUEST['task'] )
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]/u', '', $log['Message'] );
$log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message'] );
$logs[] = $log;
}
$options = array();

View File

@ -171,14 +171,13 @@ Warning("Addterm");
} else if ( $action == 'eventdetail' ) {
if ( !empty($_REQUEST['eid']) ) {
dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['eid'] ) );
$refreshParent = true;
} else {
foreach( getAffectedIds( 'markEid' ) as $markEid ) {
dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $markEid ) );
$refreshParent = true;
}
$refreshParent = '/index.php?view=filter&Id='.$_REQUEST['Id'];
}
$refreshParent = true;
$closePopup = true;
} elseif ( $action == 'archive' || $action == 'unarchive' ) {
$archiveVal = ($action == 'archive')?1:0;
if ( !empty($_REQUEST['eid']) ) {
@ -186,14 +185,14 @@ Warning("Addterm");
} else {
foreach( getAffectedIds( 'markEid' ) as $markEid ) {
dbQuery( 'UPDATE Events SET Archived=? WHERE Id=?', array( $archiveVal, $markEid ) );
$refreshParent = true;
}
$refreshParent = true;
}
} elseif ( $action == 'delete' ) {
foreach( getAffectedIds( 'markEid' ) as $markEid ) {
deleteEvent( $markEid );
$refreshParent = true;
}
$refreshParent = true;
}
} // end if canEdit(Events)
} // end if filter or something else

View File

@ -1146,24 +1146,26 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
$StorageArea = NULL;
if ( isset($filter['terms']) && count($filter['terms']) ) {
for ( $i = 0; $i < count($filter['terms']); $i++ ) {
if ( isset($filter['terms'][$i]['cnj']) ) {
$filter['query'] .= $querySep.urlencode("filter[terms][$i][cnj]").'='.urlencode($filter['terms'][$i]['cnj']);
$filter['sql'] .= ' '.$filter['terms'][$i]['cnj'].' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cnj]\" value=\"".htmlspecialchars($filter['terms'][$i]['cnj'])."\"/>\n";
$terms = $filter['Query']['terms'];
if ( isset($terms) && count($terms) ) {
for ( $i = 0; $i < count($terms); $i++ ) {
if ( isset($terms[$i]['cnj']) ) {
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][cnj]").'='.urlencode($terms[$i]['cnj']);
$filter['sql'] .= ' '.$terms[$i]['cnj'].' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][cnj]\" value=\"".htmlspecialchars($terms[$i]['cnj'])."\"/>\n";
}
if ( isset($filter['terms'][$i]['obr']) ) {
$filter['query'] .= $querySep.urlencode("filter[terms][$i][obr]").'='.urlencode($filter['terms'][$i]['obr']);
$filter['sql'] .= ' '.str_repeat( '(', $filter['terms'][$i]['obr'] ).' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][obr]\" value=\"".htmlspecialchars($filter['terms'][$i]['obr'])."\"/>\n";
if ( isset($terms[$i]['obr']) ) {
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][obr]").'='.urlencode($terms[$i]['obr']);
$filter['sql'] .= ' '.str_repeat( '(', $terms[$i]['obr'] ).' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][obr]\" value=\"".htmlspecialchars($terms[$i]['obr'])."\"/>\n";
}
if ( isset($filter['terms'][$i]['attr']) ) {
$filter['query'] .= $querySep.urlencode("filter[terms][$i][attr]").'='.urlencode($filter['terms'][$i]['attr']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][attr]\" value=\"".htmlspecialchars($filter['terms'][$i]['attr'])."\"/>\n";
switch ( $filter['terms'][$i]['attr'] ) {
if ( isset($terms[$i]['attr']) ) {
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][attr]").'='.urlencode($terms[$i]['attr']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][attr]\" value=\"".htmlspecialchars($terms[$i]['attr'])."\"/>\n";
switch ( $terms[$i]['attr'] ) {
case 'MonitorName':
$filter['sql'] .= 'M.'.preg_replace( '/^Monitor/', '', $filter['terms'][$i]['attr'] );
$filter['sql'] .= 'M.'.preg_replace( '/^Monitor/', '', $terms[$i]['attr'] );
break;
case 'ServerId':
$filter['sql'] .= 'M.ServerId';
@ -1194,14 +1196,14 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
case 'Notes':
case 'StateId':
case 'Archived':
$filter['sql'] .= 'E.'.$filter['terms'][$i]['attr'];
$filter['sql'] .= 'E.'.$terms[$i]['attr'];
break;
case 'DiskPercent':
// Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH
if ( ! $StorageArea ) {
for ( $j = 0; $j < count($filter['terms']); $j++ ) {
if ( isset($filter['terms'][$j]['attr']) and $filter['terms'][$j]['attr'] == 'StorageId' ) {
$StorageArea = new Storage( $filter['terms'][$j]['val'] );
for ( $j = 0; $j < count($terms); $j++ ) {
if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' ) {
$StorageArea = new Storage( $terms[$j]['val'] );
}
} // end foreach remaining term
if ( ! $StorageArea ) $StorageArea = new Storage();
@ -1212,9 +1214,9 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
case 'DiskBlocks':
// Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH
if ( ! $StorageArea ) {
for ( $j = $i; $j < count($filter['terms']); $j++ ) {
if ( isset($filter['terms'][$i]['attr']) and $filter['terms'][$i]['attr'] == 'StorageId' ) {
$StorageArea = new Storage( $filter['terms'][$i]['val'] );
for ( $j = $i; $j < count($terms); $j++ ) {
if ( isset($terms[$i]['attr']) and $terms[$i]['attr'] == 'StorageId' ) {
$StorageArea = new Storage( $terms[$i]['val'] );
}
} // end foreach remaining term
} // end no StorageArea found yet
@ -1225,8 +1227,8 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
break;
}
$valueList = array();
foreach ( preg_split( '/["\'\s]*?,["\'\s]*?/', preg_replace( '/^["\']+?(.+)["\']+?$/', '$1', $filter['terms'][$i]['val'] ) ) as $value ) {
switch ( $filter['terms'][$i]['attr'] ) {
foreach ( preg_split( '/["\'\s]*?,["\'\s]*?/', preg_replace( '/^["\']+?(.+)["\']+?$/', '$1', $terms[$i]['val'] ) ) as $value ) {
switch ( $terms[$i]['attr'] ) {
case 'MonitorName':
case 'Name':
case 'Cause':
@ -1260,14 +1262,14 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
$valueList[] = $value;
}
switch ( $filter['terms'][$i]['op'] ) {
switch ( $terms[$i]['op'] ) {
case '=' :
case '!=' :
case '>=' :
case '>' :
case '<' :
case '<=' :
$filter['sql'] .= ' '.$filter['terms'][$i]['op'].' '. $value;
$filter['sql'] .= ' '.$terms[$i]['op'].' '. $value;
break;
case '=~' :
$filter['sql'] .= ' regexp '.$value;
@ -1283,15 +1285,15 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
break;
}
$filter['query'] .= $querySep.urlencode("filter[terms][$i][op]").'='.urlencode($filter['terms'][$i]['op']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][op]\" value=\"".htmlspecialchars($filter['terms'][$i]['op'])."\"/>\n";
$filter['query'] .= $querySep.urlencode("filter[terms][$i][val]").'='.urlencode($filter['terms'][$i]['val']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][val]\" value=\"".htmlspecialchars($filter['terms'][$i]['val'])."\"/>\n";
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][op]\" value=\"".htmlspecialchars($terms[$i]['op'])."\"/>\n";
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][val]").'='.urlencode($terms[$i]['val']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][val]\" value=\"".htmlspecialchars($terms[$i]['val'])."\"/>\n";
}
if ( isset($filter['terms'][$i]['cbr']) ) {
$filter['query'] .= $querySep.urlencode("filter[terms][$i][cbr]").'='.urlencode($filter['terms'][$i]['cbr']);
$filter['sql'] .= ' '.str_repeat( ')', $filter['terms'][$i]['cbr'] ).' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cbr]\" value=\"".htmlspecialchars($filter['terms'][$i]['cbr'])."\"/>\n";
if ( isset($terms[$i]['cbr']) ) {
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][cbr]").'='.urlencode($terms[$i]['cbr']);
$filter['sql'] .= ' '.str_repeat( ')', $terms[$i]['cbr'] ).' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][cbr]\" value=\"".htmlspecialchars($terms[$i]['cbr'])."\"/>\n";
}
}
if ( $filter['sql'] )

View File

@ -28,7 +28,7 @@ if ( $debug ) {
}
// Use new style autoglobals where possible
if ( version_compare( phpversion(), "4.1.0", "<") ) {
if ( version_compare( phpversion(), '4.1.0', '<') ) {
$_SESSION = &$HTTP_SESSION_VARS;
$_SERVER = &$HTTP_SERVER_VARS;
}
@ -37,7 +37,7 @@ if ( version_compare( phpversion(), "4.1.0", "<") ) {
if ( false ) {
ob_start();
phpinfo( INFO_VARIABLES );
$fp = fopen( "/tmp/env.html", "w" );
$fp = fopen( '/tmp/env.html', 'w' );
fwrite( $fp, ob_get_contents() );
fclose( $fp );
ob_end_clean();
@ -114,10 +114,10 @@ $skinBase[] = $skin;
$currentCookieParams = session_get_cookie_params();
Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
session_set_cookie_params(
$currentCookieParams["lifetime"],
$currentCookieParams["path"],
$currentCookieParams["domain"],
$currentCookieParams["secure"],
$currentCookieParams['lifetime'],
$currentCookieParams['path'],
$currentCookieParams['domain'],
$currentCookieParams['secure'],
true
);
@ -205,7 +205,7 @@ require_once( 'includes/actions.php' );
# If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in.
if ( ZM_OPT_USE_AUTH && ! isset($user) ) {
Logger::Debug("Redirecting to login" );
Logger::Debug("Redirecting to login" );
$view = 'login';
$request = null;
}

View File

@ -38,8 +38,8 @@ var popupSizes = {
'events': { 'width': 960, 'height': 780 },
'export': { 'width': 400, 'height': 340 },
'filter': { 'width': 820, 'height': 700 },
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 100 },
'frames': { 'width': 600, 'height': 600 },
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 },
'frames': { 'width': 600, 'height': 700 },
'function': { 'width': 300, 'height': 92 },
'group': { 'width': 360, 'height': 180 },
'groups': { 'width': 440, 'height': 220 },

View File

@ -38,8 +38,8 @@ var popupSizes = {
'events': { 'width': 960, 'height': 780 },
'export': { 'width': 400, 'height': 340 },
'filter': { 'width': 900, 'height': 700 },
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 100 },
'frames': { 'width': 600, 'height': 600 },
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 },
'frames': { 'width': 600, 'height': 700 },
'function': { 'width': 300, 'height': 160 },
'group': { 'width': 360, 'height': 300 },
'groups': { 'width': 540, 'height': 420 },

View File

@ -38,7 +38,7 @@ var popupSizes = {
'events': { 'width': 1220, 'height': 780 },
'export': { 'width': 400, 'height': 340 },
'filter': { 'width': 900, 'height': 700 },
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 100 },
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 },
'frames': { 'width': 600, 'height': 600 },
'function': { 'width': 300, 'height': 160 },
'group': { 'width': 360, 'height': 300 },

View File

@ -253,8 +253,11 @@ if ( refreshParent ) {
if ( focusWindow ) {
windowToFront();
}
if ( closePopup ) {
closeWindow();
}
window.addEvent( 'domready', checkSize);
window.addEvent( 'domready', checkSize );
function convertLabelFormat(LabelFormat, monitorName){
//convert label format from strftime to moment's format (modified from

View File

@ -49,6 +49,13 @@ if ( ! empty($refreshParent) ) {
echo 'false';
}
?>;
var closePopup = <?php
if ( ( ! empty($closePopup) ) and ( $closePopup == true ) ) {
echo 'true';
} else {
echo 'false';
}
?>;
var focusWindow = <?php echo !empty($focusWindow)?'true':'false' ?>;

View File

@ -29,7 +29,8 @@ $eventCounts = array(
array(
'title' => translate('Events'),
'filter' => array(
'terms' => array(
'Query' => array (
'terms' => array()
)
),
'total' => 0,
@ -37,48 +38,58 @@ $eventCounts = array(
array(
'title' => translate('Hour'),
'filter' => array(
'Query' => array(
'terms' => array(
array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-1 hour' ),
array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-1 hour' ),
)
)
),
),
'total' => 0,
),
array(
'title' => translate('Day'),
'filter' => array(
'Query' => array(
'terms' => array(
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 day' ),
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 day' ),
)
)
),
),
'total' => 0,
),
array(
'title' => translate('Week'),
'filter' => array(
'Query' => array(
'terms' => array(
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-7 day' ),
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-7 day' ),
)
)
),
),
'total' => 0,
),
array(
'title' => translate('Month'),
'filter' => array(
'Query' => array(
'terms' => array(
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 month' ),
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 month' ),
)
)
),
),
'total' => 0,
),
array(
'title' => translate('Archived'),
'filter' => array(
'Query' => array(
'terms' => array(
array( 'attr' => "Archived", 'op' => '=', 'val' => '1' ),
array( 'attr' => "Archived", 'op' => '=', 'val' => '1' ),
)
)
),
),
'total' => 0,
),
),
);
$displayMonitors = NULL;
@ -94,7 +105,7 @@ for( $i = 0; $i < count($displayMonitors); $i += 1 ) {
$monitor['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitor['Id']) );
$counts = array();
for ( $j = 0; $j < count($eventCounts); $j += 1 ) {
$filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) );
$filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) );
parseFilter( $filter );
$counts[] = "count(if(1".$filter['sql'].",1,NULL)) as EventCount$j";
$monitor['eventCounts'][$j]['filter'] = $filter;

View File

@ -155,7 +155,7 @@ if ( $Event->DefaultVideo() ) {
?>
<div id="videoFeed">
<video id="videoobj" class="video-js vjs-default-skin" width="<?php echo reScale( $Event->Width(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $scale ) ?>" data-setup='{ "controls": true, "playbackRates": [0.5, 1, 1.5, 2, 4, 8, 16, 32, 64, 128, 256], "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'>
<source src="<?php echo $Event->getStreamSrc( array( "mode=mpeg&format=h264" ) ); ?>" type="video/mp4">
<source src="<?php echo $Event->getStreamSrc( array( 'mode'=>'mpeg','format'=>'h264' ) ); ?>" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
@ -170,7 +170,8 @@ if ( $Event->DefaultVideo() ) {
<?php
} // end if DefaultVideo
?>
<div id="imageFeed" <?php if ( $Event->DefaultVideo() ) { ?>class="hidden"<?php } ?> >
</div><!--eventVideo-->
<div id="imageFeed"<?php if ( $Event->DefaultVideo() ) { ?> class="hidden"<?php } ?>>
<?php
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
$streamSrc = $Event->getStreamSrc( array( 'mode'=>'mpeg', 'scale'=>$scale, 'rate'=>$rate, 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format'=>ZM_MPEG_REPLAY_FORMAT, 'replay'=>$replayMode ) );
@ -184,7 +185,6 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
}
} // end if stream method
?>
</div>
<p id="dvrControls">
<input type="button" value="&lt;+" id="prevBtn" title="<?php echo translate('Prev') ?>" class="inactive" onclick="streamPrev( true );"/>
<input type="button" value="&lt;&lt;" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="inactive" disabled="disabled" onclick="streamFastRev( true );"/>
@ -206,8 +206,8 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
<?php for ( $i = 0; $i < $panelSections; $i++ ) { ?>
<div class="progressBox" id="progressBox<?php echo $i ?>" title=""></div>
<?php } ?>
</div>
</div>
</div><!--progressBar-->
</div><!--imageFeed-->
</div>
<?php
if ( $Event->SaveJPEGs() & 3 ) { // frames or analysis

View File

@ -18,50 +18,43 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit( 'Events' ) )
{
$view = "error";
return;
if ( !canEdit( 'Events' ) ) {
$view = 'error';
return;
}
if ( isset($_REQUEST['eid']) ) {
$mode = 'single';
$eid = validInt($_REQUEST['eid']);
$newEvent = dbFetchOne( 'SELECT E.* FROM Events AS E WHERE E.Id = ?', NULL, array($eid) );
$mode = 'single';
$eid = validInt($_REQUEST['eid']);
$newEvent = dbFetchOne( 'SELECT E.* FROM Events AS E WHERE E.Id = ?', NULL, array($eid) );
} elseif ( isset($_REQUEST['eids']) ) {
$mode = 'multi';
$sql = 'SELECT E.* FROM Events AS E WHERE ';
$sqlWhere = array();
$sqlValues = array();
foreach ( $_REQUEST['eids'] as $eid ) {
$sqlWhere[] = 'E.Id = ?';
$sqlValues[] = $eid;
$mode = 'multi';
$sql = 'SELECT E.* FROM Events AS E WHERE ';
$sqlWhere = array();
$sqlValues = array();
foreach ( $_REQUEST['eids'] as $eid ) {
$sqlWhere[] = 'E.Id = ?';
$sqlValues[] = $eid;
}
unset( $eid );
$sql .= join( " or ", $sqlWhere );
foreach( dbFetchAll( $sql, NULL, $sqlValues ) as $row ) {
if ( !isset($newEvent) ) {
$newEvent = $row;
} else {
if ( $newEvent['Cause'] && $newEvent['Cause'] != $row['Cause'] )
$newEvent['Cause'] = '';
if ( $newEvent['Notes'] && $newEvent['Notes'] != $row['Notes'] )
$newEvent['Notes'] = '';
}
unset( $eid );
$sql .= join( " or ", $sqlWhere );
foreach( dbFetchAll( $sql, NULL, $sqlValues ) as $row )
{
if ( !isset($newEvent) )
{
$newEvent = $row;
}
else
{
if ( $newEvent['Cause'] && $newEvent['Cause'] != $row['Cause'] )
$newEvent['Cause'] = "";
if ( $newEvent['Notes'] && $newEvent['Notes'] != $row['Notes'] )
$newEvent['Notes'] = "";
}
}
}
else
{
$mode = '';
}
} else {
$mode = '';
}
$focusWindow = true;
if ( $mode == 'single' )
xhtmlHeaders(__FILE__, translate('Event')." - ".$eid );
xhtmlHeaders(__FILE__, translate('Event').' - '.$eid );
else
xhtmlHeaders(__FILE__, translate('Events') );
?>
@ -69,14 +62,11 @@ else
<div id="page">
<div id="header">
<?php
if ( $mode == 'single' )
{
if ( $mode == 'single' ) {
?>
<h2><?php echo translate('Event') ?> <?php echo $eid ?></h2>
<?php
}
else
{
} else {
?>
<h2><?php echo translate('Events') ?></h2>
<?php
@ -87,22 +77,18 @@ else
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<input type="hidden" name="view" value="none"/>
<?php
if ( $mode == 'single' )
{
if ( $mode == 'single' ) {
?>
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="action" value="eventdetail"/>
<input type="hidden" name="eid" value="<?php echo $eid ?>"/>
<?php
}
elseif ( $mode = 'multi' )
{
} elseif ( $mode = 'multi' ) {
?>
<input type="hidden" name="view" value="none"/>
<input type="hidden" name="action" value="eventdetail"/>
<?php
foreach ( $_REQUEST['eids'] as $eid )
{
foreach ( $_REQUEST['eids'] as $eid ) {
?>
<input type="hidden" name="markEids[]" value="<?php echo validHtmlStr($eid) ?>"/>
<?php
@ -122,7 +108,8 @@ elseif ( $mode = 'multi' )
</tbody>
</table>
<div id="contentButtons">
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/>
<input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
</div>
</form>
</div>

View File

@ -214,7 +214,7 @@ foreach ( $events as $event ) {
<td class="colThumbnail">
<?php
$imgSrc = '?view=image&amp;eid='.$event->Id().'&amp;fid='.$thumbData['FrameId'].'&amp;width='.$thumbData['Width'].'&amp;height='.$thumbData['Height'];
$streamSrc = getStreamSrc( array( "source=event", "mode=jpeg", "event=".$event->Id(), "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "replay=single") );
$streamSrc = $event->getStreamSrc( array( 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single') );
$imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($thumbData['Width']) .'px;height:'. validInt( $thumbData['Height'] ).'px;" onmouseover="this.src=\''.$streamSrc.'\';" onmouseout="this.src=\''.$imgSrc.'\';"/>';

View File

@ -19,8 +19,8 @@
//
if ( !canView( 'Events' ) ) {
$view = 'error';
return;
$view = 'error';
return;
}
require_once( 'includes/Frame.php' );
$Event = new Event( $_REQUEST['eid'] );
@ -61,10 +61,10 @@ xhtmlHeaders(__FILE__, translate('Frames')." - ".$Event->Id() );
<tbody>
<?php
if ( count($frames) ) {
foreach ( $frames as $frame ) {
$Frame = new Frame( $frame );
foreach ( $frames as $frame ) {
$Frame = new Frame( $frame );
$class = strtolower($frame['Type']);
$class = strtolower($frame['Type']);
?>
<tr class="<?php echo $class ?>">
<td class="colId"><?php echo makePopupLink( '?view=frame&amp;eid='.$Event->Id().'&amp;fid='.$frame['FrameId'], 'zmImage', array( 'frame', $Event->Width(), $Event->Height() ), $frame['FrameId'] ) ?></td>
@ -72,16 +72,16 @@ if ( count($frames) ) {
<td class="colTimeStamp"><?php echo strftime( STRF_FMT_TIME, $frame['UnixTimeStamp'] ) ?></td>
<td class="colTimeDelta"><?php echo number_format( $frame['Delta'], 2 ) ?></td>
<?php
if ( ZM_RECORD_EVENT_STATS && ($frame['Type'] == 'Alarm') ) {
if ( ZM_RECORD_EVENT_STATS && ($frame['Type'] == 'Alarm') ) {
?>
<td class="colScore"><?php echo makePopupLink( '?view=stats&amp;eid='.$Event->Id().'&amp;fid='.$frame['FrameId'], 'zmStats', 'stats', $frame['Score'] ) ?></td>
<?php
} else {
} else {
?>
<td class="colScore"><?php echo $frame['Score'] ?></td>
<?php
}
if ( ZM_WEB_LIST_THUMBS ) {
}
if ( ZM_WEB_LIST_THUMBS ) {
?>
<td class="colThumbnail"><?php echo makePopupLink( '?view=frame&amp;eid='.$Event->Id().'&amp;fid='.$frame['FrameId'], 'zmImage', array( 'image', $Event->Width(), $Event->Height() ), '<img src="?view=image&amp;fid='.$Frame->Id().'&amp;'.
(ZM_WEB_LIST_THUMB_WIDTH?'width='.ZM_WEB_LIST_THUMB_WIDTH.'&amp;':'').
@ -89,11 +89,11 @@ if ( count($frames) ) {
(ZM_WEB_LIST_THUMB_WIDTH?'width="'.ZM_WEB_LIST_THUMB_WIDTH.'" ':'').
(ZM_WEB_LIST_THUMB_HEIGHT?'height="'.ZM_WEB_LIST_THUMB_HEIGHT.'" ':'').' alt="'.$frame['FrameId'].'"/>' ) ?></td>
<?php
}
}
?>
</tr>
<?php
} // end foreach frame
} // end foreach frame
} else {
?>
<tr>

View File

@ -11,7 +11,7 @@ var logCodes = new Object({
'-4': 'PNC',
});
var minSampleTime = 1000;
var minSampleTime = 2000;
var maxSampleTime = 16000;
var minLogTime = 0;
var maxLogTime = 0;
@ -56,11 +56,12 @@ function logResponse( respObj ) {
try {
respObj.logs.each(
function( log ) {
if ( !maxLogTime || log.TimeKey > maxLogTime )
if ( ( !maxLogTime ) || ( log.TimeKey > maxLogTime ) )
maxLogTime = log.TimeKey;
if ( !minLogTime || log.TimeKey < minLogTime )
if ( ( !minLogTime ) || ( log.TimeKey < minLogTime ) )
minLogTime = log.TimeKey;
var row = logTable.push( [{ content: log.DateTime, properties: { style: 'white-space: nowrap' }}, log.Component, log.Server, log.Pid, log.Code, log.Message, log.File, log.Line] );
delete log.Message;
row.tr.store( 'log', log );
if ( log.Level <= -3 )
@ -106,8 +107,8 @@ function logResponse( respObj ) {
logTimeout *= 2;
if ( logTimeout > maxSampleTime )
logTimeout = maxSampleTime;
}
}
} // end logs.length > 0
} // end if result == Ok
logTimer = fetchNextLogs.delay( logTimeout );
}

View File

@ -0,0 +1,720 @@
function evaluateLoadTimes() {
// Only consider it a completed event if we load ALL monitors, then zero all and start again
var start=0;
var end=0;
if ( liveMode != 1 && currentSpeed == 0 ) return; // don't evaluate when we are not moving as we can do nothing really fast.
for ( var i = 0; i < monitorIndex.length; i++ ) {
if ( monitorName[i] > "" ) {
if ( monitorLoadEndTimems[i] ==0 ) return; // if we have a monitor with no time yet just wait
if ( start == 0 || start > monitorLoadStartTimems[i] ) start = monitorLoadStartTimems[i];
if ( end == 0 || end < monitorLoadEndTimems[i] ) end = monitorLoadEndTimems[i];
}
}
if ( start == 0 || end == 0 ) return; // we really should not get here
for ( var i=0; i < numMonitors; i++ ) {
var monId = monitorPtr[i];
monitorLoadStartTimems[monId] = 0;
monitorLoadEndTimems[monId] = 0;
}
freeTimeLastIntervals[imageLoadTimesEvaluated++] = 1 - ((end - start)/currentDisplayInterval);
if( imageLoadTimesEvaluated < imageLoadTimesNeeded ) return;
var avgFrac=0;
for ( var i=0; i < imageLoadTimesEvaluated; i++ )
avgFrac += freeTimeLastIntervals[i];
avgFrac = avgFrac / imageLoadTimesEvaluated;
// The larger this is(positive) the faster we can go
if (avgFrac >= 0.9) currentDisplayInterval = (currentDisplayInterval * 0.50).toFixed(1); // we can go much faster
else if (avgFrac >= 0.8) currentDisplayInterval = (currentDisplayInterval * 0.55).toFixed(1);
else if (avgFrac >= 0.7) currentDisplayInterval = (currentDisplayInterval * 0.60).toFixed(1);
else if (avgFrac >= 0.6) currentDisplayInterval = (currentDisplayInterval * 0.65).toFixed(1);
else if (avgFrac >= 0.5) currentDisplayInterval = (currentDisplayInterval * 0.70).toFixed(1);
else if (avgFrac >= 0.4) currentDisplayInterval = (currentDisplayInterval * 0.80).toFixed(1);
else if (avgFrac >= 0.35) currentDisplayInterval = (currentDisplayInterval * 0.90).toFixed(1);
else if (avgFrac >= 0.3) currentDisplayInterval = (currentDisplayInterval * 1.00).toFixed(1);
else if (avgFrac >= 0.25) currentDisplayInterval = (currentDisplayInterval * 1.20).toFixed(1);
else if (avgFrac >= 0.2) currentDisplayInterval = (currentDisplayInterval * 1.50).toFixed(1);
else if (avgFrac >= 0.1) currentDisplayInterval = (currentDisplayInterval * 2.00).toFixed(1);
else currentDisplayInterval = (currentDisplayInterval * 2.50).toFixed(1);
currentDisplayInterval=Math.min(Math.max(currentDisplayInterval, 30),10000); // limit this from about 30fps to .1 fps
imageLoadTimesEvaluated=0;
setSpeed(speedIndex);
$('fps').innerHTML="Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + ".";
}
function SetImageSource( monId, val ) {
if ( liveMode == 1 ) {
return monitorImageObject[monId].src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
} else {
for ( var i=0, eIdlength = eId.length; i < eIdlength; i++ ) {
// Search for a match
if ( eMonId[i] == monId && val >= eStartSecs[i] && val <= eEndSecs[i] ) {
var frame = parseInt((val - eStartSecs[i])/(eEndSecs[i]-eStartSecs[i])*eventFrames[i])+1;
return "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height;
}
} // end for
return "no data";
}
}
// callback when loading an image. Will load itself to the canvas, or draw no data
function imagedone( obj, monId, success ) {
if ( success ) {
var canvasCtx = monitorCanvasCtx[monId];
var canvasObj = monitorCanvasObj[monId];
canvasCtx.drawImage( monitorImageObject[monId], 0, 0, canvasObj.width, canvasObj.height );
var iconSize=(Math.max(canvasObj.width, canvasObj.height) * 0.10);
canvasCtx.font = "600 " + iconSize.toString() + "px Arial";
canvasCtx.fillStyle = "white";
canvasCtx.globalCompositeOperation = "difference";
canvasCtx.fillText( "+", iconSize*0.2, iconSize*1.2 );
canvasCtx.fillText( "-", canvasObj.width - iconSize*1.2, iconSize*1.2 );
canvasCtx.globalCompositeOperation = "source-over";
monitorLoadEndTimems[monId] = new Date().getTime(); // elapsed time to load
evaluateLoadTimes();
}
monitorLoading[monId] = false;
if ( ! success ) {
// if we had a failrue queue up the no-data image
//loadImage2Monitor(monId,"no data"); // leave the staged URL if there is one, just ignore it here.
loadNoData( monId );
} else {
if ( monitorLoadingStageURL[monId] == "" ) {
console.log("Not showing image for " + monId );
// This means that there wasn't a loading image placeholder.
// So we weren't actually loading an image... which seems weird.
return;
}
//loadImage2Monitor(monId,monitorLoadingStageURL[monId] );
//monitorLoadingStageURL[monId]="";
}
return;
}
function loadNoData( monId ) {
if ( monId ) {
var canvasCtx = monitorCanvasCtx[monId];
var canvasObj = monitorCanvasObj[monId];
canvasCtx.fillStyle="white";
canvasCtx.fillRect(0, 0, canvasObj.width, canvasObj.height);
var textSize=canvasObj.width * 0.15;
var text="No Data";
canvasCtx.font = "600 " + textSize.toString() + "px Arial";
canvasCtx.fillStyle="black";
var textWidth = canvasCtx.measureText(text).width;
canvasCtx.fillText(text,canvasObj.width/2 - textWidth/2,canvasObj.height/2);
} else {
console.log("No monId in loadNoData");
}
}
// Either draws the
function loadImage2Monitor( monId, url ) {
if ( monitorLoading[monId] && monitorImageObject[monId].src != url ) {
// never queue the same image twice (if it's loading it has to be defined, right?
monitorLoadingStageURL[monId] = url; // we don't care if we are overriting, it means it didn't change fast enough
} else {
if ( monitorImageObject[monId].src == url ) return; // do nothing if it's the same
if ( url == 'no data' ) {
loadNoData( monId );
} else {
monitorLoading[monId] = true;
monitorLoadStartTimems[monId] = new Date().getTime();
monitorImageObject[monId].src = url; // starts a load but doesn't refresh yet, wait until ready
}
}
}
function timerFire() {
// See if we need to reschedule
if(currentDisplayInterval != timerInterval || currentSpeed == 0) {
// zero just turn off interrupts
clearInterval(timerObj);
timerInterval=currentDisplayInterval;
if(currentSpeed>0 || liveMode!=0) timerObj=setInterval(timerFire,timerInterval); // don't fire out of live mode if speed is zero
}
if (liveMode) outputUpdate(currentTimeSecs); // In live mode we basically do nothing but redisplay
else if (currentTimeSecs + playSecsperInterval >= maxTimeSecs) // beyond the end just stop
{
setSpeed(0);
outputUpdate(currentTimeSecs);
}
else outputUpdate(currentTimeSecs + playSecsperInterval);
return;
}
function drawSliderOnGraph(val) {
var sliderWidth=10;
var sliderLineWidth=1;
var sliderHeight=cHeight;
if(liveMode==1) {
val=Math.floor( Date.now() / 1000);
}
// Set some sizes
var labelpx = Math.max( 6, Math.min( 20, parseInt(cHeight * timeLabelsFractOfRow / (numMonitors+1)) ) );
var labbottom=parseInt(cHeight * 0.2 / (numMonitors+1)).toString() + "px"; // This is positioning same as row labels below, but from bottom so 1-position
var labfont=labelpx + "px Georgia"; // set this like below row labels
if(numMonitors>0) {
// if we have no data to display don't do the slider itself
var sliderX=parseInt( (val - minTimeSecs) / rangeTimeSecs * cWidth - sliderWidth/2); // position left side of slider
if(sliderX < 0) sliderX=0;
if(sliderX+sliderWidth > cWidth) sliderX=cWidth-sliderWidth-1;
// If we have data already saved first restore it from LAST time
if(typeof underSlider !== 'undefined')
{
ctx.putImageData(underSlider,underSliderX, 0, 0, 0, sliderWidth, sliderHeight);
underSlider=undefined;
}
if(liveMode==0) // we get rid of the slider if we switch to live (since it may not be in the "right" place)
{
// Now save where we are putting it THIS time
underSlider=ctx.getImageData(sliderX, 0, sliderWidth, sliderHeight);
// And add in the slider'
ctx.lineWidth=sliderLineWidth;
ctx.strokeStyle='black';
// looks like strokes are on the outside (or could be) so shrink it by the line width so we replace all the pixels
ctx.strokeRect(sliderX+sliderLineWidth,sliderLineWidth,sliderWidth - 2*sliderLineWidth, sliderHeight - 2*sliderLineWidth);
underSliderX=sliderX;
}
var o = $('scruboutput');
if(liveMode==1)
{
o.innerHTML="Live Feed @ " + (1000 / currentDisplayInterval).toFixed(1) + " fps";
o.style.color="red";
}
else
{
o.innerHTML=secs2dbstr(val);
o.style.color="blue";
}
o.style.position="absolute";
o.style.bottom=labbottom;
o.style.font=labfont;
// try to get length and then when we get too close to the right switch to the left
var len = o.offsetWidth;
var x;
if(sliderX > cWidth/2)
x=sliderX - len - 10;
else
x=sliderX + 10;
o.style.left=x.toString() + "px";
}
// This displays (or not) the left/right limits depending on how close the slider is.
// Because these change widths if the slider is too close, use the slider width as an estimate for the left/right label length (i.e. don't recalculate len from above)
// If this starts to collide increase some of the extra space
var o = $('scrubleft');
o.innerHTML=secs2dbstr(minTimeSecs);
o.style.position="absolute";
o.style.bottom=labbottom;
o.style.font=labfont;
o.style.left="5px";
if(numMonitors==0) // we need a len calculation if we skipped the slider
len = o.offsetWidth;
// If the slider will overlay part of this suppress (this is the left side)
if(len + 10 > sliderX || cWidth < len * 4 ) // that last check is for very narrow browsers
o.style.display="none";
else
{
o.style.display="inline";
o.style.display="inline-flex"; // safari won't take this but will just ignore
}
var o = $('scrubright');
o.innerHTML=secs2dbstr(maxTimeSecs);
o.style.position="absolute";
o.style.bottom=labbottom;
o.style.font=labfont;
// If the slider will overlay part of this suppress (this is the right side)
o.style.left=(cWidth - len - 15).toString() + "px";
if(sliderX > cWidth - len - 20 || cWidth < len * 4 )
o.style.display="none";
else
{
o.style.display="inline";
o.style.display="inline-flex";
}
}
function drawGraph()
{
var divWidth=$('timelinediv').clientWidth
canvas.width = cWidth = divWidth; // Let it float and determine width (it should be sized a bit smaller percentage of window)
canvas.height=cHeight = parseInt(window.innerHeight * 0.10);
if(eId.length==0)
{
ctx.font="40px Georgia";
ctx.fillStyle="Black";
ctx.globalAlpha=1;
var t="No data found in range - choose differently";
var l=ctx.measureText(t).width;
ctx.fillText(t,(cWidth - l)/2, cHeight-10);
underSlider=undefined;
return;
}
var rowHeight=parseInt(cHeight / (numMonitors + 1) ); // Leave room for a scale of some sort
// first fill in the bars for the events (not alarms)
for(var i=0; i<eId.length; i++) // Display all we loaded
{
var x1=parseInt( (eStartSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth) ; // round low end down
var x2=parseInt( (eEndSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 ) ; // round high end up to be sure consecutive ones connect
ctx.fillStyle=monitorColour[eMonId[i]];
ctx.globalAlpha = 0.2; // light color for background
ctx.clearRect(x1,monitorIndex[eMonId[i]]*rowHeight,x2-x1,rowHeight); // Erase any overlap so it doesn't look artificially darker
ctx.fillRect (x1,monitorIndex[eMonId[i]]*rowHeight,x2-x1,rowHeight);
}
for(var i=0; (i<fScore.length) && (maxScore>0); i++) // Now put in scored frames (if any)
{
var x1=parseInt( (fTimeFromSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth) ; // round low end down
var x2=parseInt( (fTimeToSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 ) ; // round up
if(x2-x1 < 2) x2=x1+2; // So it is visible make them all at least this number of seconds wide
ctx.fillStyle=monitorColour[fMonId[i]];
ctx.globalAlpha = 0.4 + 0.6 * (1 - fScore[i]/maxScore); // Background is scaled but even lowest is twice as dark as the background
ctx.fillRect(x1,monitorIndex[fMonId[i]]*rowHeight,x2-x1,rowHeight);
}
for(var i=0; i<numMonitors; i++) // Note that this may be a sparse array
{
ctx.font= parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia";
ctx.fillStyle="Black";
ctx.globalAlpha=1;
ctx.fillText(monitorName[monitorPtr[i]], 0, (i + 1 - (1 - timeLabelsFractOfRow)/2 ) * rowHeight ); // This should roughly center font in row
}
underSlider=undefined; // flag we don't have a slider cached
drawSliderOnGraph(currentTimeSecs);
return;
}
function redrawScreen()
{
if(fitMode==0) // if we fit, then monitors were absolutely positioned already (or will be) otherwise release them to float
{
for(var i=0; i<numMonitors; i++)
monitorCanvasObj[monitorPtr[i]].style.position="";
$('monitors').setStyle('height',"auto");
}
if(liveMode==1) // if we are not in live view switch to history -- this has to come before fit in case we re-establish the timeline
{
$('SpeedDiv').style.display="none";
$('timelinediv').style.display="none";
$('live').innerHTML="History";
$('zoomin').style.display="none";
$('zoomout').style.display="none";
$('panleft').style.display="none";
$('panright').style.display="none";
}
else // switch out of liveview mode
{
$('SpeedDiv').style.display="inline";
$('SpeedDiv').style.display="inline-flex";
$('timelinediv').style.display=null;
$('live').innerHTML="Live";
$('zoomin').style.display="inline";
$('zoomin').style.display="inline-flex";
$('zoomout').style.display="inline";
$('zoomout').style.display="inline-flex";
$('panleft').style.display="inline";
$('panleft').style.display="inline-flex";
$('panright').style.display="inline";
$('panright').style.display="inline-flex";
}
if(fitMode==1)
{
$('ScaleDiv').style.display="none";
$('fit').innerHTML="Scale";
var vh=window.innerHeight;
var vw=window.innerWidth;
var pos=$('monitors').getPosition();
var mh=(vh - pos.y - $('fps').getSize().y);
$('monitors').setStyle('height',mh.toString() + "px"); // leave a small gap at bottom
if(maxfit2($('monitors').getSize().x,$('monitors').getSize().y) == 0) /// if we fail to fix we back out of fit mode -- ??? This may need some better handling
fitMode=1-fitMode;
}
else // switch out of fit mode
{
$('ScaleDiv').style.display="inline";
$('ScaleDiv').style.display="inline-flex";
$('fit').innerHTML="Fit";
setScale(currentScale);
}
drawGraph();
outputUpdate(currentTimeSecs);
timerFire(); // force a fire in case it's not timing
}
function outputUpdate(val)
{
drawSliderOnGraph(val);
for(var i=0; i<numMonitors; i++)
{
loadImage2Monitor(monitorPtr[i],SetImageSource(monitorPtr[i],val));
}
var currentTimeMS = new Date(val*1000);
currentTimeSecs=val;
}
/// Found this here: http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-element
function relMouseCoords(event){
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = this;
do{
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
}
while(currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
// These are the functions for mouse movement in the timeline. Note that touch is treated as a mouse move with mouse down
var mouseisdown=false;
function mdown(event) {mouseisdown=true; mmove(event);}
function mup(event) {mouseisdown=false;}
function mout(event) {mouseisdown=false;} // if we go outside treat it as release
function tmove(event) {mouseisdown=true; mmove(event);}
function mmove(event) {
if(mouseisdown) {
// only do anything if the mouse is depressed while on the sheet
var sec = minTimeSecs + rangeTimeSecs / event.target.width * event.target.relMouseCoords(event).x;
outputUpdate(sec);
}
}
function secs2dbstr (s)
{
var st = (new Date(s * 1000)).format("%Y-%m-%d %H:%M:%S");
return st;
}
function setFit(value)
{
fitMode=value;
redrawScreen();
}
function showScale(newscale) // updates slider only
{
$('scaleslideroutput').innerHTML = parseFloat(newscale).toFixed(2).toString() + " x";
return;
}
function setScale(newscale) // makes actual change
{
showScale(newscale);
for(var i=0; i<numMonitors; i++)
{
monitorCanvasObj[monitorPtr[i]].width=monitorWidth[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
monitorCanvasObj[monitorPtr[i]].height=monitorHeight[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
}
currentScale=newscale;
}
function showSpeed(val) // updates slider only
{
$('speedslideroutput').innerHTML = parseFloat(speeds[val]).toFixed(2).toString() + " x";
}
function setSpeed(val) // Note parameter is the index not the speed
{
var t;
if(liveMode==1) return; // we shouldn't actually get here but just in case
currentSpeed=parseFloat(speeds[val]);
speedIndex=val;
playSecsperInterval = currentSpeed * currentDisplayInterval / 1000;
showSpeed(val);
if( timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
}
function setLive(value)
{
liveMode=value;
redrawScreen();
}
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// The section below are to reload this program with new parameters
function clicknav(minSecs,maxSecs,arch,live) {// we use the current time if we can
var now = new Date() / 1000;
var minStr="";
var maxStr="";
var currentStr="";
if ( minSecs > 0 ) {
if(maxSecs > now)
maxSecs = parseInt(now);
maxStr="&maxTime=" + secs2dbstr(maxSecs);
}
if ( maxSecs > 0 )
minStr="&minTime=" + secs2dbstr(minSecs);
if ( maxSecs == 0 && minSecs == 0 ) {
minStr="&minTime=01/01/1950 12:00:00";
maxStr="&maxTime=12/31/2035 12:00:00";
}
var intervalStr="&displayinterval=" + currentDisplayInterval.toString();
if ( minSecs && maxSecs ) {
if ( currentTimeSecs > minSecs && currentTimeSecs < maxSecs ) // make sure time is in the new range
currentStr="&current=" + secs2dbstr(currentTimeSecs);
}
var liveStr="&live=0";
if ( live == 1 )
liveStr="&live=1";
var fitStr="&fit=0";
if ( fitMode == 1 )
fitStr="&fit=1";
var zoomStr="";
for ( var i=0; i < numMonitors; i++ )
if ( monitorZoomScale[monitorPtr[i]] < 0.99 || monitorZoomScale[monitorPtr[i]] > 1.01 ) // allow for some up/down changes and just treat as 1 of almost 1
zoomStr += "&z" + monitorPtr[i].toString() + "=" + monitorZoomScale[monitorPtr[i]].toFixed(2);
var uri = "?view=" + currentView + fitStr + groupStr + minStr + maxStr + currentStr + intervalStr + liveStr + zoomStr + "&scale=" + document.getElementById("scaleslider").value + "&speed=" + speeds[$j("#speedslider").value];
window.location = uri;
}
function lastHour() {
var now = new Date() / 1000;
clicknav(now - 3600 + 1, now,1,0);
}
function lastEight() {
var now = new Date() / 1000;
clicknav(now - 3600*8 + 1, now,1,0);
}
function zoomin() {
rangeTimeSecs = parseInt(rangeTimeSecs / 2);
minTimeSecs = parseInt(currentTimeSecs - rangeTimeSecs/2); // this is the slider current time, we center on that
maxTimeSecs = parseInt(currentTimeSecs + rangeTimeSecs/2);
clicknav(minTimeSecs,maxTimeSecs,1,0);
}
function zoomout() {
rangeTimeSecs = parseInt(rangeTimeSecs * 2);
minTimeSecs = parseInt(currentTimeSecs - rangeTimeSecs/2); // this is the slider current time, we center on that
maxTimeSecs = parseInt(currentTimeSecs + rangeTimeSecs/2);
clicknav(minTimeSecs,maxTimeSecs,1,0);
}
function panleft() {
minTimeSecs = parseInt(minTimeSecs - rangeTimeSecs/2);
maxTimeSecs = minTimeSecs + rangeTimeSecs - 1;
clicknav(minTimeSecs,maxTimeSecs,1,0);
}
function panright() {
minTimeSecs = parseInt(minTimeSecs + rangeTimeSecs/2);
maxTimeSecs = minTimeSecs + rangeTimeSecs - 1;
clicknav(minTimeSecs,maxTimeSecs,1,0);
}
function allof() {
clicknav(0,0,1,0);
}
function allnon() {
clicknav(0,0,0,0);
}
/// >>>>>>>>>>>>>>>>> handles packing different size/aspect monitors on screen <<<<<<<<<<<<<<<<<<<<<<<<
function compSize(a, b) { // sort array by some size parameter - height seems to work best. A semi-greedy algorithm
var a_value = monitorHeight[a] * monitorWidth[a] * monitorNormalizeScale[a] * monitorZoomScale[a] * monitorNormalizeScale[a] * monitorZoomScale[a];
var b_value = monitorHeight[b] * monitorWidth[b] * monitorNormalizeScale[b] * monitorZoomScale[b] * monitorNormalizeScale[b] * monitorZoomScale[b];
if ( a_value > b_value ) return -1;
else if ( a_value == b_value ) return 0;
else return 1;
}
function maxfit2(divW, divH) {
var bestFitX=[]; // how we arranged the so-far best match
var bestFitX2=[];
var bestFitY=[];
var bestFitY2=[];
var bestFitScale;
var minScale=0.05;
var maxScale=5.00;
var bestFitArea=0;
var borders=-1;
monitorPtr.sort(compSize);
while(1) {
if( maxScale - minScale < 0.01 ) break;
var thisScale = (maxScale + minScale) / 2;
var allFit=1;
var thisArea=0;
var thisX=[]; // top left
var thisY=[];
var thisX2=[]; // bottom right
var thisY2=[];
for ( var m = 0; m < numMonitors; m++ ) {
// this loop places each monitor (if it can)
var monId = monitorPtr[m];
function doesItFit(x,y,w,h,d) { // does block (w,h) fit at position (x,y) relative to edge and other nodes already done (0..d)
if(x+w>=divW) return 0;
if(y+h>=divH) return 0;
for(var i=0; i<=d; i++)
if( !( thisX[i]>x+w-1 || thisX2[i] < x || thisY[i] > y+h-1 || thisY2[i] < y ) ) return 0;
return 1; // it's OK
}
if ( borders <= 0 )
borders=$("Monitor"+monId).getStyle("border").toInt() * 2; // assume fixed size border, and added to both sides and top/bottom
// try fitting over first, then down. Each new one must land at either upper right or lower left corner of last (try in that order)
// Pick the one with the smallest Y, then smallest X if Y equal
var fitX = 999999999;
var fitY = 999999999;
for ( adjacent = 0; adjacent < m; adjacent ++ ) {
// try top right of adjacent
if ( doesItFit(thisX2[adjacent]+1, thisY[adjacent], monitorWidth[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, monitorHeight[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, m-1) == 1 ) {
if ( thisY[adjacent]<fitY || ( thisY[adjacent] == fitY && thisX2[adjacent]+1 < fitX ) ) {
fitX = thisX2[adjacent] + 1;
fitY = thisY[adjacent];
}
}
// try bottom left
if ( doesItFit(thisX[adjacent], thisY2[adjacent]+1, monitorWidth[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, monitorHeight[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, m-1) == 1 ) {
if ( thisY2[adjacent]+1 < fitY || ( thisY2[adjacent]+1 == fitY && thisX[adjacent] < fitX ) ) {
fitX = thisX[adjacent];
fitY = thisY2[adjacent] + 1;
}
}
}
if ( m == 0 ) { // note for the very first one there were no adjacents so the above loop didn't run
if ( doesItFit(0,0,monitorWidth[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, monitorHeight[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, -1) == 1 ) {
fitX = 0;
fitY = 0;
}
}
if ( fitX == 999999999 ) {
allFit = 0;
break; // break out of monitor loop flagging we didn't fit
}
thisX[m] =fitX;
thisX2[m]=fitX + monitorWidth[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders;
thisY[m] =fitY;
thisY2[m]=fitY + monitorHeight[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders;
thisArea += (thisX2[m] - thisX[m])*(thisY2[m] - thisY[m]);
}
if ( allFit == 1 ) {
minScale=thisScale;
if(bestFitArea<thisArea) {
bestFitArea=thisArea;
bestFitX=thisX;
bestFitY=thisY;
bestFitX2=thisX2;
bestFitY2=thisY2;
bestFitScale=thisScale;
}
} else {
// didn't fit
maxScale=thisScale;
}
}
if ( bestFitArea > 0 ) { // only rearrange if we could fit -- otherwise just do nothing, let them start coming out, whatever
for ( m = 0; m < numMonitors; m++ ) {
c = $("Monitor" + monitorPtr[m]);
c.style.position="absolute";
c.style.left=bestFitX[m].toString() + "px";
c.style.top=bestFitY[m].toString() + "px";
c.width = bestFitX2[m] - bestFitX[m] + 1 - borders;
c.height= bestFitY2[m] - bestFitY[m] + 1 - borders;
}
return 1;
} else {
return 0;
}
}
// >>>>>>>>>>>>>>>> Handles individual monitor clicks and navigation to the standard event/watch display
function showOneMonitor(monId) {
// link out to the normal view of one event's data
// We know the monitor, need to determine the event based on current time
var url;
if ( liveMode != 0 )
url="?view=watch&mid=" + monId.toString();
else
for ( var i=0, len=eId.length; i<len; i++ ) {
if ( eMonId[i] == monId && currentTimeSecs >= eStartSecs[i] && currentTimeSecs <= eEndSecs[i] )
url="?view=event&eid=" + eId[i] + '&fid=' + parseInt(Math.max(1, Math.min(eventFrames[i], eventFrames[i] * (currentTimeSecs - eStartSecs[i]) / (eEndSecs[i] - eStartSecs[i] + 1) ) ));
break;
}
createPopup(url, 'zmEvent', 'event', monitorWidth[eMonId[i]], monitorHeight[eMonId[i]]);
}
function zoom(monId,scale) {
var lastZoomMonPriorScale = monitorZoomScale[monId];
monitorZoomScale[monId] *= scale;
if ( redrawScreen() == 0 ) {// failure here is probably because we zoomed too far
monitorZoomScale[monId] = lastZoomMonPriorScale;
alert("You can't zoom that far -- rolling back");
redrawScreen(); // put things back and hope it works
}
}
function clickMonitor(event,monId) {
var monitor_element = $("Monitor"+monId.toString());
var pos_x = event.offsetX ? (event.offsetX) : event.pageX - monitor_element.offsetLeft;
var pos_y = event.offsetY ? (event.offsetY) : event.pageY - monitor_element.offsetTop;
if ( pos_x < monitor_element.width/4 && pos_y < monitor_element.height/4 )
zoom(monId,1.15);
else if ( pos_x > monitor_element.width * 3/4 && pos_y < monitor_element.height/4 )
zoom(monId,1/1.15);
else
showOneMonitor(monId);
return;
}
// >>>>>>>>> Initialization that runs on window load by being at the bottom
function initPage() {
canvas = $("timeline");
ctx = canvas.getContext('2d');
for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) {
var monId = monitorPtr[i];
if ( ! monId ) continue;
monitorCanvasObj[monId] = $('Monitor'+monId );
if ( ! monitorCanvasObj[monId] ) {
alert("Couldn't find DOM element for Monitor"+monId + "monitorPtr.length="+len);
} else {
monitorCanvasCtx[monId] = monitorCanvasObj[monId].getContext('2d');
var imageObject = monitorImageObject[monId] = new Image();
imageObject.monId = monId;
imageObject.onload = function() {imagedone(this, this.monId, true )};
imageObject.onerror = function() {imagedone(this, this.monId, false )};
loadImage2Monitor( monId, monitorImageURL[monId] );
}
}
drawGraph();
setSpeed(speedIndex);
setFit(fitMode); // will redraw
setLive(liveMode); // will redraw
}
window.addEventListener("resize",redrawScreen);
// Kick everything off
window.addEvent( 'domready', initPage );

View File

@ -0,0 +1,194 @@
var currentScale=<?php echo $defaultScale?>;
var liveMode=<?php echo $initialModeIsLive?>;
console.log("Live mode?"+liveMode);
var fitMode=<?php echo $fitMode?>;
var currentSpeed=<?php echo $speeds[$speedIndex]?>; // slider scale, which is only for replay and relative to real time
var speedIndex=<?php echo $speedIndex?>;
var currentDisplayInterval=<?php echo $initialDisplayInterval?>; // will be set based on performance, this is the display interval in milliseconds for history, and fps for live, and dynamically determined (in ms)
var playSecsperInterval=1; // How many seconds of recorded image we play per refresh determined by speed (replay rate) and display interval; (default=1 if coming from live)
var timerInterval; // milliseconds between interrupts
var timerObj; // object to hold timer interval;
var freeTimeLastIntervals=[]; // Percentage of current interval used in loading most recent image
var imageLoadTimesEvaluated=0; // running count
var imageLoadTimesNeeded=15; // and how many we need
var timeLabelsFractOfRow = 0.9;
var eMonId = [];
var eId = [];
var eStartSecs = [];
var eEndSecs = [];
var eventFrames = []; // this is going to presume all frames equal durationlength
var groupStr=<?php if($group=="") echo '""'; else echo "\"&group=$group\""; ?>;
<?php
// Because we might not have time as the criteria, figure out the min/max time when we run the query
$minTimeSecs = strtotime('2036-01-01 01:01:01');
$maxTimeSecs = strtotime('1950-01-01 01:01:01');
// This builds the list of events that are eligible from this range
$index=0;
$anyAlarms=false;
foreach( dbFetchAll( $eventsSql ) as $event ) {
if ( $minTimeSecs > $event['StartTimeSecs'] ) $minTimeSecs = $event['StartTimeSecs'];
if ( $maxTimeSecs < $event['CalcEndTimeSecs'] ) $maxTimeSecs = $event['CalcEndTimeSecs'];
echo "
eMonId[$index]=" . $event['MonitorId'] . ";
eId[$index]=" . $event['Id'] . ";
eStartSecs[$index]=" . $event['StartTimeSecs'] . ";
eEndSecs[$index]=" . $event['CalcEndTimeSecs'] . ";
eventFrames[$index]=" . $event['Frames'] . ";
";
$index = $index + 1;
if ( $event['MaxScore'] > 0 )
$anyAlarms = true;
}
// if there is no data set the min/max to the passed in values
if ( $index == 0 ) {
if ( isset($minTime) && isset($maxTime) ) {
$minTimeSecs = strtotime($minTime);
$maxTimeSecs = strtotime($maxTime);
} else {
// this is the case of no passed in times AND no data -- just set something arbitrary
$minTimeSecs = strtotime('1950-06-01 01:01:01'); // random time so there's something to display
$maxTimeSecs = time() + 86400;
}
}
// We only reset the calling time if there was no calling time
if ( !isset($minTime) || !isset($maxTime) ) {
$maxTime = strftime($maxTimeSecs);
$minTime = strftime($minTimeSecs);
} else {
$minTimeSecs = strtotime($minTime);
$maxTimeSecs = strtotime($maxTime);
}
// If we had any alarms in those events, this builds the list of all alarm frames, but consolidated down to (nearly) contiguous segments
// comparison in else governs how aggressively it consolidates
echo "var fMonId = [];\n";
echo "var fTimeFromSecs = [];\n";
echo "var fTimeToSecs = [];\n";
echo "var fScore = [];\n";
$maxScore=0;
$index=0;
$mId=-1;
$fromSecs=-1;
$toSecs=-1;
$maxScore=-1;
if ( $anyAlarms ) {
foreach( dbFetchAll ($frameSql) as $frame ) {
if ( $mId < 0 ) {
$mId = $frame['MonitorId'];
$fromSecs = $frame['TimeStampSecs'];
$toSecs = $frame['TimeStampSecs'];
$maxScore = $frame['Score'];
} else if ( $mId != $frame['MonitorId'] || $frame['TimeStampSecs'] - $toSecs > 10 ) {
// dump this one start a new
$index++;
echo "
fMonId[$index]= $mId;
fTimeFromSecs[$index]= $fromSecs;
fTimeToSecs[$index]= $toSecs;
fScore[$index]= $maxScore;
";
$mId = $frame['MonitorId'];
$fromSecs = $frame['TimeStampSecs'];
$toSecs = $frame['TimeStampSecs'];
$maxScore = $frame['Score'];
} else {
// just add this one on
$toSecs = $frame['TimeStampSecs'];
if ( $maxScore < $frame['Score'] ) $maxScore = $frame['Score'];
}
}
}
if ( $mId > 0 ) {
echo "
fMonId[$index]= $mId;
fTimeFromSecs[$index]= $fromSecs;
fTimeToSecs[$index]= $toSecs;
fScore[$index]= $maxScore;
";
}
echo "var maxScore=$maxScore;\n"; // used to skip frame load if we find no alarms.
echo "var monitorName = [];\n";
echo "var monitorLoading = [];\n";
echo "var monitorImageObject = [];\n";
echo "var monitorImageURL = [];\n";
echo "var monitorLoadingStageURL = [];\n";
echo "var monitorLoadStartTimems = [];\n";
echo "var monitorLoadEndTimems = [];\n";
echo "var monitorColour = [];\n";
echo "var monitorWidth = [];\n";
echo "var monitorHeight = [];\n";
echo "var monitorIndex = [];\n";
echo "var monitorNormalizeScale = [];\n";
echo "var monitorZoomScale = [];\n";
echo "var monitorCanvasObj = [];\n"; // stash location of these here so we don't have to search
echo "var monitorCanvasCtx = [];\n";
echo "var monitorPtr = []; // monitorName[monitorPtr[0]] is first monitor\n";
$numMonitors=0; // this array is indexed by the monitor ID for faster access later, so it may be sparse
$avgArea=floatval(0); // Calculations the normalizing scale
foreach ( $monitors as $m ) {
$avgArea = $avgArea + floatval($m->Width() * $m->Height());
$numMonitors++;
}
if ( $numMonitors > 0 ) $avgArea = $avgArea / $numMonitors;
$numMonitors = 0;
foreach ( $monitors as $m ) {
echo " monitorLoading[" . $m->Id() . "]=false;\n";
echo " monitorImageURL[" . $m->Id() . "]='".$m->getStreamSrc( array('mode'=>'single','scale'=>$defaultScale*100), '&' )."';\n";
echo " monitorLoadingStageURL[" . $m->Id() . "] = '';\n";
echo " monitorColour[" . $m->Id() . "]=\"" . $m->WebColour() . "\";\n";
echo " monitorWidth[" . $m->Id() . "]=" . $m->Width() . ";\n";
echo " monitorHeight[" . $m->Id() . "]=" . $m->Height() . ";\n";
echo " monitorIndex[" . $m->Id() . "]=" . $numMonitors . ";\n";
echo " monitorName[" . $m->Id() . "]=\"" . $m->Name() . "\";\n";
echo " monitorLoadStartTimems[" . $m->Id() . "]=0;\n";
echo " monitorLoadEndTimems[" . $m->Id() . "]=0;\n";
echo " monitorNormalizeScale[" . $m->Id() . "]=" . sqrt($avgArea / ($m->Width() * $m->Height() )) . ";\n";
$zoomScale=1.0;
if(isset($_REQUEST[ 'z' . $m->Id() ]) )
$zoomScale = floatval( validHtmlStr($_REQUEST[ 'z' . $m->Id() ]) );
echo " monitorZoomScale[" . $m->Id() . "]=" . $zoomScale . ";\n";
echo " monitorPtr[" . $numMonitors . "]=" . $m->Id() . ";\n";
$numMonitors += 1;
}
echo "var numMonitors = $numMonitors;\n";
echo "var minTimeSecs=" . $minTimeSecs . ";\n";
echo "var maxTimeSecs=" . $maxTimeSecs . ";\n";
echo "var rangeTimeSecs=" . ( $maxTimeSecs - $minTimeSecs + 1) . ";\n";
if(isset($defaultCurrentTime))
echo "var currentTimeSecs=" . strtotime($defaultCurrentTime) . ";\n";
else
echo "var currentTimeSecs=" . ($minTimeSecs + $maxTimeSecs)/2 . ";\n";
echo 'var speeds=[';
for ($i=0; $i<count($speeds); $i++)
echo (($i>0)?', ':'') . $speeds[$i];
echo "];\n";
?>
var scrubAsObject=$('scrub');
var cWidth; // save canvas width
var cHeight; // save canvas height
var canvas; // global canvas definition so we don't have to keep looking it up
var ctx;
var underSlider; // use this to hold what is hidden by the slider
var underSliderX; // Where the above was taken from (left side, Y is zero)

View File

@ -31,7 +31,7 @@ function changeScale() {
Cookie.write( 'zmWatchScale'+monitorId, scale, { duration: 10*365 } );
/*Stream could be an applet so can't use moo tools*/
var streamImg = document.getElementById('liveStream'+monitorId);
var streamImg = $('#liveStream'+monitorId);
if ( streamImg ) {
streamImg.style.width = newWidth + "px";
streamImg.style.height = newHeight + "px";
@ -187,14 +187,14 @@ function getStreamCmdResponse( respObj, respText ) {
if ( streamStatus.auth ) {
console.log("Haev a new auth hash" + streamStatus.auth);
// Try to reload the image stream.
var streamImg = document.getElementById('liveStream');
var streamImg = $('liveStream');
if ( streamImg )
streamImg.src = streamImg.src.replace( /auth=\w+/i, 'auth='+streamStatus.auth );
} // end if haev a new auth hash
} else {
checkStreamForErrors("getStreamCmdResponse",respObj);//log them
// Try to reload the image stream.
var streamImg = document.getElementById('liveStream'+monitorId);
var streamImg = $('liveStream'+monitorId);
if ( streamImg ) {
streamImg.src = streamImg.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
console.log("Changing lviestream src to " + streamImg.src);

View File

@ -41,6 +41,7 @@ if ( isset( $_REQUEST['showZones'] ) ) {
}
}
$monitors = array();
<<<<<<< HEAD
$widths = array(
'' => 'auto',
160 => 160,
@ -63,8 +64,10 @@ if ( isset( $_REQUEST['scale'] ) ) {
} else if ( isset( $_COOKIE['zmMontageScale'] ) ) {
$scale = $_COOKIE['zmMontageScale'];
Logger::Debug("Setting scale from cookie to $scale");
} else {
Logger::Debug("scale is $scale");
}
if ( ! $scale )
$scale = 100;
}
foreach( dbFetchAll( $sql ) as $row ) {

File diff suppressed because it is too large Load Diff