diff --git a/distros/redhat/readme/README.Redhat7 b/distros/redhat/readme/README.Redhat7 index 8817b925c..d74973a72 100644 --- a/distros/redhat/readme/README.Redhat7 +++ b/distros/redhat/readme/README.Redhat7 @@ -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 diff --git a/distros/redhat/sysvinit/zoneminder.conf.in b/distros/redhat/sysvinit/zoneminder.conf.in index 0fbee6a62..413910214 100644 --- a/distros/redhat/sysvinit/zoneminder.conf.in +++ b/distros/redhat/sysvinit/zoneminder.conf.in @@ -18,7 +18,7 @@ Alias /zm "@ZM_WEBDIR@" Allow from all -ScriptAlias /cgi-bin/zm "@ZM_CGIDIR@" +ScriptAlias /cgi-bin-zm "@ZM_CGIDIR@" SSLRequireSSL AllowOverride All diff --git a/distros/ubuntu1204/zoneminder.dirs b/distros/ubuntu1204/zoneminder.dirs index 4178482c1..ff1ec7858 100644 --- a/distros/ubuntu1204/zoneminder.dirs +++ b/distros/ubuntu1204/zoneminder.dirs @@ -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 diff --git a/distros/ubuntu1204/zoneminder.postinst b/distros/ubuntu1204/zoneminder.postinst index 9d786e27d..d01d27925 100644 --- a/distros/ubuntu1204/zoneminder.postinst +++ b/distros/ubuntu1204/zoneminder.postinst @@ -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# diff --git a/distros/ubuntu1604/control b/distros/ubuntu1604/control index 1adea5494..a28824866 100644 --- a/distros/ubuntu1604/control +++ b/distros/ubuntu1604/control @@ -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] diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index 9e3f117a4..e06cdd3b5 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -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 diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 3f30672ee..b803ef329 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -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 ) { diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index a952899c6..aaaee0ff8 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -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(); diff --git a/scripts/zmtelemetry.pl.in b/scripts/zmtelemetry.pl.in index 426d36b40..54521d335 100644 --- a/scripts/zmtelemetry.pl.in +++ b/scripts/zmtelemetry.pl.in @@ -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; diff --git a/src/zm_config.cpp b/src/zm_config.cpp index bf9d2dac6..03f7b587a 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -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(); diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 6cfe00163..ee3a5a8b5 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -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; diff --git a/src/zm_stream.h b/src/zm_stream.h index 98d96389f..aad9bbfaa 100644 --- a/src/zm_stream.h +++ b/src/zm_stream.h @@ -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(); diff --git a/src/zm_video.cpp b/src/zm_video.cpp index 7f88fa1ef..369819098 100644 --- a/src/zm_video.cpp +++ b/src/zm_video.cpp @@ -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); } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 0d6056e3e..9cfeb74a9 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -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 } } diff --git a/src/zms.cpp b/src/zms.cpp index f37b63ca1..f396e2b46 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -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 diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index 716719e3c..5034f0fb9 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -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; diff --git a/web/ajax/log.php b/web/ajax/log.php index c38a6d5d0..4e8c13a35 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -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(); diff --git a/web/includes/actions.php b/web/includes/actions.php index e41ef8fbb..0516f0a38 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -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 diff --git a/web/includes/functions.php b/web/includes/functions.php index 58fda1d13..b50a14917 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1146,24 +1146,26 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) { $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'] .= "\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'] .= "\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'] .= "\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'] .= "\n"; } - if ( isset($filter['terms'][$i]['attr']) ) { - $filter['query'] .= $querySep.urlencode("filter[terms][$i][attr]").'='.urlencode($filter['terms'][$i]['attr']); - $filter['fields'] .= "\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'] .= "\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='&' ) { 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='&' ) { 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='&' ) { 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='&' ) { $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='&' ) { break; } - $filter['query'] .= $querySep.urlencode("filter[terms][$i][op]").'='.urlencode($filter['terms'][$i]['op']); - $filter['fields'] .= "\n"; - $filter['query'] .= $querySep.urlencode("filter[terms][$i][val]").'='.urlencode($filter['terms'][$i]['val']); - $filter['fields'] .= "\n"; + $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']); + $filter['fields'] .= "\n"; + $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][val]").'='.urlencode($terms[$i]['val']); + $filter['fields'] .= "\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'] .= "\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'] .= "\n"; } } if ( $filter['sql'] ) diff --git a/web/index.php b/web/index.php index e691e1e1d..a8848118d 100644 --- a/web/index.php +++ b/web/index.php @@ -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; } diff --git a/web/skins/classic/js/classic.js b/web/skins/classic/js/classic.js index 95ee5dcb5..61ccc984e 100644 --- a/web/skins/classic/js/classic.js +++ b/web/skins/classic/js/classic.js @@ -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 }, diff --git a/web/skins/classic/js/dark.js b/web/skins/classic/js/dark.js index 32b43c732..e0142017f 100644 --- a/web/skins/classic/js/dark.js +++ b/web/skins/classic/js/dark.js @@ -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 }, diff --git a/web/skins/classic/js/flat.js b/web/skins/classic/js/flat.js index 672ba5a64..83fccaec5 100644 --- a/web/skins/classic/js/flat.js +++ b/web/skins/classic/js/flat.js @@ -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 }, diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index c6ac7dd57..ac58e9bdf 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -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 diff --git a/web/skins/classic/js/skin.js.php b/web/skins/classic/js/skin.js.php index c96969423..87a76b921 100644 --- a/web/skins/classic/js/skin.js.php +++ b/web/skins/classic/js/skin.js.php @@ -49,6 +49,13 @@ if ( ! empty($refreshParent) ) { echo 'false'; } ?>; +var closePopup = ; var focusWindow = ; diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 72d29b999..871f20830 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -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; diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 0849a827b..9352f6f2b 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -155,7 +155,7 @@ if ( $Event->DefaultVideo() ) { ?>
@@ -170,7 +170,8 @@ if ( $Event->DefaultVideo() ) { -
DefaultVideo() ) { ?>class="hidden" > +
+
DefaultVideo() ) { ?> class="hidden"> 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 ?> -

@@ -206,8 +206,8 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {

- - + + SaveJPEGs() & 3 ) { // frames or analysis diff --git a/web/skins/classic/views/eventdetail.php b/web/skins/classic/views/eventdetail.php index 491de763f..bad9a18bc 100644 --- a/web/skins/classic/views/eventdetail.php +++ b/web/skins/classic/views/eventdetail.php @@ -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
diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 19ad7caf7..7aad2b36e 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -214,7 +214,7 @@ foreach ( $events as $event ) { Id().'&fid='.$thumbData['FrameId'].'&width='.$thumbData['Width'].'&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 = ''. validHtmlStr('Event '.$event->Id()) .''; diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index 9b5e57e6e..c50da5e7e 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -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() ); Id().'&fid='.$frame['FrameId'], 'zmImage', array( 'frame', $Event->Width(), $Event->Height() ), $frame['FrameId'] ) ?> @@ -72,16 +72,16 @@ if ( count($frames) ) { Id().'&fid='.$frame['FrameId'], 'zmStats', 'stats', $frame['Score'] ) ?> Id().'&fid='.$frame['FrameId'], 'zmImage', array( 'image', $Event->Width(), $Event->Height() ), ''.$frame['FrameId'].'' ) ?> diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js index f78912681..b3b30fa86 100644 --- a/web/skins/classic/views/js/log.js +++ b/web/skins/classic/views/js/log.js @@ -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 ); } diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js new file mode 100644 index 000000000..5a7c73ede --- /dev/null +++ b/web/skins/classic/views/js/montagereview.js @@ -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; i0); 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 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="¤t=" + 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] 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= 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 ); diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php new file mode 100644 index 000000000..512c670d3 --- /dev/null +++ b/web/skins/classic/views/js/montagereview.js.php @@ -0,0 +1,194 @@ + +var currentScale=; +var liveMode=; +console.log("Live mode?"+liveMode); +var fitMode=; +var currentSpeed=; // slider scale, which is only for replay and relative to real time +var speedIndex=; +var currentDisplayInterval=; // 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=; + + $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; $i0)?', ':'') . $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) + diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 02cdcf22b..2909f0476 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -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); diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index 9ed88ed6e..175d1a98a 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -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 ) { diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 5a153dd9e..cbd91f5f1 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -95,20 +95,20 @@ // if ( !canView( 'Events' ) ) { - $view = 'error'; - return; + $view = 'error'; + return; } require_once( 'includes/Monitor.php' ); # FIXME THere is no way to select group at this time. if ( !empty($_REQUEST['group']) ) { - $group = $_REQUEST['group']; - $row = dbFetchOne( 'SELECT * FROM Groups WHERE Id = ?', NULL, array($_REQUEST['group']) ); - $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None' AND find_in_set( Id, '".$row['MonitorIds']."' ) "; + $group = $_REQUEST['group']; + $row = dbFetchOne( 'SELECT * FROM Groups WHERE Id = ?', NULL, array($_REQUEST['group']) ); + $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None' AND find_in_set( Id, '".$row['MonitorIds']."' ) "; } else { - $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None'"; - $group = ''; + $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None'"; + $group = ''; } // Note that this finds incomplete events as well, and any frame records written, but still cannot "see" to the end frame @@ -181,34 +181,34 @@ else $speeds=[0, 0.1, 0.25, 0.5, 0.75, 1.0, 1.5, 2, 3, 5, 10, 20, 50]; -if (isset($_REQUEST['speed']) ) +if ( isset($_REQUEST['speed']) ) $defaultSpeed = validHtmlStr($_REQUEST['speed']); else $defaultSpeed = 1; $speedIndex=5; // default to 1x -for ($i=0; $i
+
'; foreach ($monitors as $m) { - echo 'No Canvas Support!!'; + echo 'No Canvas Support!!'; } -echo "
\n"; -echo "

evaluating fps

\n"; -echo " + +

evaluating fps