From a6b804bb62b7b2327772d5733ab6ab6c503bcb99 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 07:58:53 -0400 Subject: [PATCH 01/45] As params are passed in command, they should not be fatal to the control process --- scripts/ZoneMinder/lib/ZoneMinder/Control.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm index 06c116626..acce8eb4a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm @@ -116,7 +116,7 @@ sub getParam { } elsif ( defined($default) ) { return $default; } - Fatal("Missing mandatory parameter '$name'"); + Error("Missing mandatory parameter '$name'"); } sub executeCommand { From 807efde5237cba83b803a10b0b2153b16c31ec90 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 08:01:04 -0400 Subject: [PATCH 02/45] xtell and ytell are data-xtell and data-ytell fixes #2932 --- web/skins/classic/views/js/watch.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 8a38afea4..19f74333b 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -695,12 +695,11 @@ function getControlResponse(respObj, respText) { function controlCmd(event) { button = event.target; control = button.getAttribute('value'); - xtell = button.getAttribute('xtell'); - ytell = button.getAttribute('ytell'); + xtell = button.getAttribute('data-xtell'); + ytell = button.getAttribute('data-ytell'); var locParms = ''; if ( event && (xtell || ytell) ) { - console.log(event); var target = event.target; var coords = $(target).getCoordinates(); From f72ad1023c56da9ff42df4830ef03119459f0e06 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 07:58:53 -0400 Subject: [PATCH 03/45] As params are passed in command, they should not be fatal to the control process --- scripts/ZoneMinder/lib/ZoneMinder/Control.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm index 896d10c07..98abab744 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm @@ -116,7 +116,7 @@ sub getParam { } elsif ( defined($default) ) { return $default; } - Fatal("Missing mandatory parameter '$name'"); + Error("Missing mandatory parameter '$name'"); } sub executeCommand { From edd718afd24ec447ffce16f3cbfc1eff33bb9b0e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 08:01:04 -0400 Subject: [PATCH 04/45] xtell and ytell are data-xtell and data-ytell fixes #2932 --- web/skins/classic/views/js/watch.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 633d507a5..0056f0a08 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -695,12 +695,11 @@ function getControlResponse(respObj, respText) { function controlCmd(event) { button = event.target; control = button.getAttribute('value'); - xtell = button.getAttribute('xtell'); - ytell = button.getAttribute('ytell'); + xtell = button.getAttribute('data-xtell'); + ytell = button.getAttribute('data-ytell'); var locParms = ''; if ( event && (xtell || ytell) ) { - console.log(event); var target = event.target; var coords = $(target).getCoordinates(); From bbf64de40eb50ed54d258a2260e38d23e6fc8501 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 May 2020 15:10:08 -0400 Subject: [PATCH 05/45] If there is a failure when decoding due to lack of support for the codec profile, re-init without hwaccel --- src/zm_ffmpeg_camera.cpp | 10 ++++++++-- src/zm_ffmpeg_camera.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index ea13f9382..109be4083 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -148,6 +148,7 @@ FfmpegCamera::FfmpegCamera( have_video_keyframe = false; packetqueue = NULL; error_count = 0; + use_hwaccel = true; #if HAVE_LIBAVUTIL_HWCONTEXT_H hwFrame = NULL; hw_device_ctx = NULL; @@ -471,7 +472,7 @@ int FfmpegCamera::OpenFfmpeg() { zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0); - if ( hwaccel_name != "" ) { + if ( use_hwaccel && (hwaccel_name != "") ) { #if HAVE_LIBAVUTIL_HWCONTEXT_H // 3.2 doesn't seem to have all the bits in place, so let's require 3.3 and up #if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0) @@ -503,8 +504,9 @@ int FfmpegCamera::OpenFfmpeg() { hw_pix_fmt = config->pix_fmt; break; } else { - Debug(1, "decoder %s hwConfig doesn't match our type: %s, pix_fmt %s.", + Debug(1, "decoder %s hwConfig doesn't match our type: %s != %s, pix_fmt %s.", mVideoCodec->name, + av_hwdevice_get_type_name(type), av_hwdevice_get_type_name(config->device_type), av_get_pix_fmt_name(config->pix_fmt) ); @@ -973,6 +975,10 @@ int FfmpegCamera::CaptureAndRecord( Error("Error count over 100, going to close and re-open stream"); return -1; } + if ( (ret == AVERROR_INVALIDDATA ) && (hw_pix_fmt != AV_PIX_FMT_NONE) ) { + use_hwaccel = false; + return -1; + } } zm_av_packet_unref(&packet); continue; diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 7a6439ee4..badf90834 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -60,6 +60,7 @@ class FfmpegCamera : public Camera { AVFrame *input_frame; // Use to point to mRawFrame or hwFrame; AVFrame *hwFrame; // Will also be used to indicate if hwaccel is in use + bool use_hwaccel; //will default to on if hwaccel specified, will get turned off if there is a failure #if HAVE_LIBAVUTIL_HWCONTEXT_H AVBufferRef *hw_device_ctx = NULL; #endif From e24b6214b18d97a93bfce40785ad8d961d6be895 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 May 2020 18:35:31 -0400 Subject: [PATCH 06/45] test logFile before doing regexps on it --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 5d05ae7c5..39c10a058 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -490,7 +490,7 @@ sub closeSyslog { sub logFile { my $this = shift; my $logFile = shift; - if ( $logFile =~ /^(.+)\+$/ ) { + if ( $logFile and ( $logFile =~ /^(.+)\+$/ ) ) { $this->{logFile} = $1.'.'.$$; } else { $this->{logFile} = $logFile; From 88a910793cf75e9486634527a5a056fcd8a25517 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 11 May 2020 09:19:33 -0400 Subject: [PATCH 07/45] Spacing --- web/includes/logger.php | 49 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/web/includes/logger.php b/web/includes/logger.php index 2b5463dfb..f4e16221e 100644 --- a/web/includes/logger.php +++ b/web/includes/logger.php @@ -1,7 +1,7 @@ terminate(); } - public function initialise( $options=array() ) { + public function initialise($options=array()) { if ( !empty($options['id']) ) $this->id = $options['id']; @@ -237,31 +237,31 @@ class Logger { $this->effectiveLevel = $this->level; if ( !$this->hasTerm ) { if ( $lastLevel < self::DEBUG && $this->level >= self::DEBUG ) { - $this->savedErrorReporting = error_reporting( E_ALL ); - $this->savedDisplayErrors = ini_set( 'display_errors', true ); + $this->savedErrorReporting = error_reporting(E_ALL); + $this->savedDisplayErrors = ini_set('display_errors', true); } elseif ( $lastLevel >= self::DEBUG && $this->level < self::DEBUG ) { - error_reporting( $this->savedErrorReporting ); - ini_set( 'display_errors', $this->savedDisplayErrors ); + error_reporting($this->savedErrorReporting); + ini_set('display_errors', $this->savedDisplayErrors); } } } - return( $this->level ); + return $this->level; } public function debugOn() { return( $this->effectiveLevel >= self::DEBUG ); } - public function termLevel( $termLevel ) { + public function termLevel($termLevel) { if ( isset($termLevel) ) { $termLevel = $this->limit($termLevel); if ( $this->termLevel != $termLevel ) $this->termLevel = $termLevel; } - return( $this->termLevel ); + return $this->termLevel; } - public function databaseLevel( $databaseLevel=NULL ) { + public function databaseLevel($databaseLevel=NULL) { if ( !is_null($databaseLevel) ) { $databaseLevel = $this->limit($databaseLevel); if ( $this->databaseLevel != $databaseLevel ) { @@ -269,7 +269,7 @@ class Logger { if ( $this->databaseLevel > self::NOLOG ) { if ( (include_once 'database.php') === FALSE ) { $this->databaseLevel = self::NOLOG; - Warning( 'Unable to write log entries to DB, database.php not found' ); + Warning('Unable to write log entries to DB, database.php not found'); } } } @@ -277,7 +277,7 @@ class Logger { return $this->databaseLevel; } - public function fileLevel( $fileLevel ) { + public function fileLevel($fileLevel) { if ( isset($fileLevel) ) { $fileLevel = $this->limit($fileLevel); if ( $this->fileLevel != $fileLevel ) { @@ -291,14 +291,14 @@ class Logger { return $this->fileLevel; } - public function weblogLevel( $weblogLevel ) { + public function weblogLevel($weblogLevel) { if ( isset($weblogLevel) ) { $weblogLevel = $this->limit($weblogLevel); if ( $this->weblogLevel != $weblogLevel ) { if ( $weblogLevel > self::NOLOG && $this->weblogLevel <= self::NOLOG ) { - $this->savedLogErrors = ini_set( 'log_errors', true ); + $this->savedLogErrors = ini_set('log_errors', true); } elseif ( $weblogLevel <= self::NOLOG && $this->weblogLevel > self::NOLOG ) { - ini_set( 'log_errors', $this->savedLogErrors ); + ini_set('log_errors', $this->savedLogErrors); } $this->weblogLevel = $weblogLevel; } @@ -306,7 +306,7 @@ class Logger { return $this->weblogLevel; } - public function syslogLevel( $syslogLevel ) { + public function syslogLevel($syslogLevel) { if ( isset($syslogLevel) ) { $syslogLevel = $this->limit($syslogLevel); if ( $this->syslogLevel != $syslogLevel ) { @@ -353,7 +353,7 @@ class Logger { fclose($this->logFd); } - public function logPrint( $level, $string, $file=NULL, $line=NULL ) { + public function logPrint($level, $string, $file=NULL, $line=NULL) { if ( $level > $this->effectiveLevel ) { return; } @@ -375,21 +375,21 @@ class Logger { $rootPath = getcwd(); else $rootPath = $_SERVER['DOCUMENT_ROOT']; - $file = preg_replace('/^'.addcslashes($rootPath,'/').'\/?/', '', $file); + $file = preg_replace('/^'.addcslashes($rootPath, '/').'\/?/', '', $file); } } if ( $this->useErrorLog ) { $message .= ' at '.$file.' line '.$line; - } else { - $message = $message; } if ( $level <= $this->termLevel ) { - if ( $this->hasTerm ) + if ( $this->hasTerm ) { print($message."\n"); - else - print(preg_replace("/\n/", '
', htmlspecialchars($message)).'
'); + } else { + // Didn't we already replace all newlines with spaces above? + print(preg_replace('/\n/', '
', htmlspecialchars($message)).'
'); + } } if ( $level <= $this->fileLevel ) { @@ -402,6 +402,9 @@ class Logger { } } else if ( $this->logFd ) { fprintf($this->logFd, $message."\n"); + } else { + $this->fileLevel = self::NOLOG; + Error('No logFd but have fileLevel logging!?'); } } From fc12b61750af8354699d86aba3c0056aa392419f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 15:09:31 -0400 Subject: [PATCH 08/45] Fix probing --- scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in index 86cb859c6..2341e1748 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in @@ -39,12 +39,10 @@ our %EXPORT_TAGS = ( ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; -our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); +our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } ); our @EXPORT = qw(); -our $VERSION = $ZoneMinder::Base::VERSION; - use Data::UUID; use vars qw( $verbose $soap_version ); @@ -60,6 +58,9 @@ require WSDiscovery::TransportUDP; sub deserialize_message { my ($wsdl_client, $response) = @_; + if ( ! $response ) { + return; + } # copied and adapted from SOAP::WSDL::Client @@ -74,20 +75,16 @@ sub deserialize_message { } # set class resolver if serializer supports it $deserializer->set_class_resolver( $wsdl_client->get_class_resolver() ) - if ( $deserializer->can('set_class_resolver') ); + if $deserializer->can('set_class_resolver'); # Try deserializing response - there may be some, -# even if transport did not succeed (got a 500 response) - if ( ! $response ) { - return; - } - +# even if transport did not succeed (got a 500 response) # as our faults are false, returning a success marker is the only # reliable way of determining whether the deserializer succeeded. # Custom deserializers may return an empty list, or undef, # and $@ is not guaranteed to be undefined. my ($success, $result_body, $result_header) = eval { - (1, $deserializer->deserialize( $response )); + (1, $deserializer->deserialize($response)); }; if ( defined $success ) { return wantarray @@ -110,10 +107,7 @@ sub interpret_messages { my @results; foreach my $response ( @responses ) { - - if ( $verbose ) { - print "Received message:\n" . $response . "\n"; - } + print "Received message:\n" . $response . "\n" if $verbose; my $result = deserialize_message($svc_discover, $response); if ( not $result ) { @@ -151,17 +145,16 @@ sub interpret_messages { foreach my $scope (split ' ', $scopes) { if ( $scope =~ m|onvif://www\.onvif\.org/(.+)/(.*)| ) { my ($attr, $value) = ($1,$2); - if ( 0 < $count ++) { - print ', '; - } + print ', ' if 0 < $count ++; print $attr . '=\'' . $value . '\''; $scopes{$attr} = $value; } } print ")\n"; - push @results, { xaddr=>$xaddr, + push @results, { + xaddr => $xaddr, soap_version => $svc_discover->get_soap_version(), - scopes => \%scopes, + scopes => \%scopes, }; } return @results; @@ -170,7 +163,7 @@ sub interpret_messages { # functions sub discover { - my ( $soap_version, $net_interface ) = @_; + my ($soap_version, $net_interface) = @_; my @results; ## collect all responses @@ -195,7 +188,7 @@ sub discover { $svc_discover->set_soap_version($version); if ( $net_interface ) { my $transport = $svc_discover->get_transport(); - print "Setting net interface for $transport to $net_interface\n"; + print "Setting net interface for $transport to $net_interface\n" if $verbose; $transport->set_net_interface($net_interface); } @@ -203,7 +196,15 @@ sub discover { my $result = $svc_discover->ProbeOp( { # WSDiscovery::Types::ProbeType - Types => 'http://www.onvif.org/ver10/network/wsdl:NetworkVideoTransmitter http://www.onvif.org/ver10/device/wsdl:Device', # QNameListType + ( + ($version eq '1.1') ? + ( + Types => 'http://www.onvif.org/ver10/network/wsdl:NetworkVideoTransmitter http://www.onvif.org/ver10/device/wsdl:Device', # QNameListType + ) : ( + xmlattr => { 'xmlns:dn' => 'http://www.onvif.org/ver10/network/wsdl', }, + Types => 'dn:NetworkVideoTransmitter', # QNameListType + ) + ), Scopes => { value => '' }, }, WSDiscovery10::Elements::Header->new({ @@ -215,22 +216,23 @@ sub discover { print $result."\n" if $verbose; push @results, interpret_messages($svc_discover, \%services, @responses); + @responses = (); } # end foreach version return @results; } # end sub discover sub profiles { - my ( $client ) = @_; + my ($client) = @_; my $media = $client->get_endpoint('media'); - if ( ! $media ) { + if ( !$media ) { print "No media endpoint for client.\n"; return; } my $result = $media->GetProfiles( { } ,, ); - if ( ! $result ) { + if ( !$result ) { print "No result from GetProfiles.\n"; return; } @@ -244,7 +246,7 @@ sub profiles { print "No profiles returned from get_Profiles\n"; return; } - print "Number of profiles found: " .(scalar @Profiles)."\n" if $verbose; + print 'Number of profiles found: ' .(scalar @Profiles)."\n" if $verbose; my @profiles; foreach my $profile ( @Profiles ) { @@ -339,12 +341,12 @@ sub move { } # end sub move sub metadata { - my ( $client ) = @_; + my ($client) = @_; my $media = $client->get_endpoint('media'); die 'No media endpoint.' if !$media; my $result = $media->GetMetadataConfigurations( { } ,, ); - if ( ! $result ) { + if ( !$result ) { print "No MetaDataConfigurations\n" if $verbose; } else { print $result . "\n"; @@ -363,8 +365,6 @@ sub metadata { } - - 1; __END__ From 437a96915fbae05dfe3df6c09e28530be500feb6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 15:24:58 -0400 Subject: [PATCH 09/45] sketchy fix for soap 1.1 --- scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in index 2341e1748..01536bf77 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in @@ -202,9 +202,9 @@ sub discover { Types => 'http://www.onvif.org/ver10/network/wsdl:NetworkVideoTransmitter http://www.onvif.org/ver10/device/wsdl:Device', # QNameListType ) : ( xmlattr => { 'xmlns:dn' => 'http://www.onvif.org/ver10/network/wsdl', }, - Types => 'dn:NetworkVideoTransmitter', # QNameListType ) ), + Types => 'dn:NetworkVideoTransmitter', # QNameListType Scopes => { value => '' }, }, WSDiscovery10::Elements::Header->new({ From 880b456d933e611c670e0a51095356640f607fcc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 15:30:56 -0400 Subject: [PATCH 10/45] Rrename MetaConfig to ONVIF --- web/skins/classic/views/monitor.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index be4df7b16..f137c58cd 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -169,12 +169,6 @@ if ( !ZM_PCRE ) // Currently unsupported unset($httpMethods['jpegTags']); -$configTypes = array( - 'None' => translate('None'), - 'ONVIF' => 'ONVIF', - 'PSIA' => 'PSIA', -); - if ( ZM_HAS_V4L1 ) { $v4l1DeviceFormats = array( 'PAL' => 0, @@ -419,7 +413,7 @@ if ( canEdit('Monitors') ) { $tabs = array(); $tabs['general'] = translate('General'); $tabs['source'] = translate('Source'); -$tabs["config"] = translate('MetaConfig'); +$tabs['onvif'] = translate('ONVIF'); if ( $monitor->Type() != 'WebSite' ) { $tabs['storage'] = translate('Storage'); $tabs['timestamp'] = translate('Timestamp'); From 992ac144a9a728a6b88c93290920d2c706ab21ed Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 13 May 2020 16:04:26 -0400 Subject: [PATCH 11/45] Fix ONVIF_User => ONVIF_Username --- web/skins/classic/views/monitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index f137c58cd..910adc539 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -492,7 +492,7 @@ if ( ZM_HAS_V4L && ($tab != 'source' || $monitor->Type() != 'Local') ) { if ( $tab != 'onvif' ) { ?> - + Date: Wed, 13 May 2020 16:06:26 -0400 Subject: [PATCH 12/45] Fix log file containing - or _ --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 39c10a058..0513f563e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -210,7 +210,7 @@ sub initialise( @ ) { if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) { $tempLogFile = $logFile; } - ($tempLogFile) = $tempLogFile =~ /^([\w\.\/]+)$/; + ($tempLogFile) = $tempLogFile =~ /^([_\-\w\.\/]+)$/; my $tempLevel = INFO; my $tempTermLevel = $this->{termLevel}; @@ -456,9 +456,9 @@ sub fileLevel { if ( defined($fileLevel) ) { $fileLevel = $this->limit($fileLevel); # The filename might have changed, so always close and re-open - $this->closeFile() if ( $this->{fileLevel} > NOLOG ); + $this->closeFile() if $this->{fileLevel} > NOLOG; $this->{fileLevel} = $fileLevel; - $this->openFile() if ( $this->{fileLevel} > NOLOG ); + $this->openFile() if $this->{fileLevel} > NOLOG; } return $this->{fileLevel}; } @@ -499,6 +499,7 @@ sub logFile { sub openFile { my $this = shift; + if ( open($LOGFILE, '>>', $this->{logFile}) ) { $LOGFILE->autoflush() if $this->{autoFlush}; @@ -519,7 +520,6 @@ sub openFile { } sub closeFile { - #my $this = shift; close($LOGFILE) if fileno($LOGFILE); } From efbab4e2bcc1ef06c8ea89c8a5af48a2035fbf61 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 May 2020 12:00:36 -0400 Subject: [PATCH 13/45] Dont' call mysql_library_end as it segfaults and hangs. --- src/zm_db.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 8e6258b0b..35982ce50 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -81,10 +81,11 @@ bool zmDbConnect() { void zmDbClose() { if ( zmDbConnected ) { db_mutex.lock(); - mysql_close( &dbconn ); + mysql_close(&dbconn); // mysql_init() call implicitly mysql_library_init() but // mysql_close() does not call mysql_library_end() - mysql_library_end(); + // We get segfaults and a hang when we call this. So just don't. + //mysql_library_end(); zmDbConnected = false; db_mutex.unlock(); } @@ -96,6 +97,12 @@ MYSQL_RES * zmDbFetch(const char * query) { return NULL; } db_mutex.lock(); + // Might have been disconnected while we waited for the lock + if ( !zmDbConnected ) { + db_mutex.unlock(); + Error("Not connected."); + return NULL; + } if ( mysql_query(&dbconn, query) ) { db_mutex.unlock(); From 402c0c6a1bb7ac28a57b448769a39660b8143346 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 May 2020 12:01:03 -0400 Subject: [PATCH 14/45] Fix build on older ffmpeg --- src/zm_ffmpeg_camera.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 109be4083..11c25addc 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -975,10 +975,12 @@ int FfmpegCamera::CaptureAndRecord( Error("Error count over 100, going to close and re-open stream"); return -1; } +#if HAVE_LIBAVUTIL_HWCONTEXT_H if ( (ret == AVERROR_INVALIDDATA ) && (hw_pix_fmt != AV_PIX_FMT_NONE) ) { use_hwaccel = false; return -1; } +#endif } zm_av_packet_unref(&packet); continue; From 16e7ca5a513bfbe6542b11855795ef6d2458a87e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 May 2020 12:01:24 -0400 Subject: [PATCH 15/45] failure opening a monitor should not be fatal. --- src/zm_monitor.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index b2a3b56c5..d06baf271 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -555,14 +555,18 @@ bool Monitor::connect() { snprintf(mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id); map_fd = open(mem_file, O_RDWR|O_CREAT, (mode_t)0600); if ( map_fd < 0 ) { - Fatal("Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno)); + Error("Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno)); + return false; } else { Debug(3, "Success opening mmap file at (%s)", mem_file); } struct stat map_stat; - if ( fstat(map_fd, &map_stat) < 0 ) - Fatal("Can't stat memory map file %s: %s, is the zmc process for this monitor running?", mem_file, strerror(errno)); + if ( fstat(map_fd, &map_stat) < 0 ) { + Error("Can't stat memory map file %s: %s, is the zmc process for this monitor running?", mem_file, strerror(errno)); + close(map_fd); + return false; + } if ( map_stat.st_size != mem_size ) { if ( purpose == CAPTURE ) { From 25a772c5eb85e7f5045405f926e3bf258d7446aa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 May 2020 12:02:02 -0400 Subject: [PATCH 16/45] reorder logic a bit to make it easier to read. Make exit_zmu not return a value. --- src/zmu.cpp | 459 ++++++++++++++++++++++++++-------------------------- 1 file changed, 233 insertions(+), 226 deletions(-) diff --git a/src/zmu.cpp b/src/zmu.cpp index 33eb730e5..b5e951100 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -196,12 +196,12 @@ bool ValidateAccess(User *user, int mon_id, int function) { return allowed; } -int exit_zmu(int exit_code) { +void exit_zmu(int exit_code) { logTerm(); + printf("closing db\n"); zmDbClose(); exit(exit_code); - return exit_code; } int main(int argc, char *argv[]) { @@ -477,228 +477,233 @@ int main(int argc, char *argv[]) { if ( mon_id > 0 ) { Monitor *monitor = Monitor::Load(mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY); - if ( monitor ) { - if ( verbose ) { - printf("Monitor %d(%s)\n", monitor->Id(), monitor->Name()); - } - if ( !monitor->connect() ) { - Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); - exit_zmu(-1); - } + if ( !monitor ) { + Error("Unable to load monitor %d", mon_id); + exit_zmu(-1); + } // end if ! MONITOR - char separator = ' '; - bool have_output = false; - if ( function & ZMU_STATE ) { - Monitor::State state = monitor->GetState(); - if ( verbose ) { - printf("Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle")); - } else { - if ( have_output ) fputc(separator, stdout); - printf("%d", state); - have_output = true; - } - } - if ( function & ZMU_TIME ) { - struct timeval timestamp = monitor->GetTimestamp(image_idx); - if ( verbose ) { - char timestamp_str[64] = "None"; - if ( timestamp.tv_sec ) - strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime(×tamp.tv_sec)); - if ( image_idx == -1 ) - printf("Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000); - else - printf("Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000); - } else { - if ( have_output ) fputc(separator, stdout); - printf("%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000); - have_output = true; - } - } - if ( function & ZMU_READ_IDX ) { - if ( verbose ) - printf("Last read index: %d\n", monitor->GetLastReadIndex()); - else { - if ( have_output ) fputc(separator, stdout); - printf("%d", monitor->GetLastReadIndex()); - have_output = true; - } - } - if ( function & ZMU_WRITE_IDX ) { - if ( verbose ) { - printf("Last write index: %d\n", monitor->GetLastWriteIndex()); - } else { - if ( have_output ) fputc(separator, stdout); - printf("%d", monitor->GetLastWriteIndex()); - have_output = true; - } - } - if ( function & ZMU_EVENT ) { - if ( verbose ) { - printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId()); - } else { - if ( have_output ) fputc(separator, stdout); - printf("%" PRIu64, monitor->GetLastEventId()); - have_output = true; - } - } - if ( function & ZMU_FPS ) { - if ( verbose ) { - printf("Current capture rate: %.2f frames per second\n", monitor->GetFPS()); - } else { - if ( have_output ) fputc(separator, stdout); - printf("%.2f", monitor->GetFPS()); - have_output = true; - } - } - if ( function & ZMU_IMAGE ) { - if ( verbose ) { - if ( image_idx == -1 ) - printf("Dumping last image captured to Monitor%d.jpg", monitor->Id()); - else - printf("Dumping buffer image %d to Monitor%d.jpg", image_idx, monitor->Id()); - if ( scale != -1 ) - printf(", scaling by %d%%", scale); - printf("\n"); - } - monitor->GetImage(image_idx, scale>0?scale:100); - } - if ( function & ZMU_ZONES ) { - if ( verbose ) - printf("Dumping zone image to Zones%d.jpg\n", monitor->Id()); - monitor->DumpZoneImage(zoneString); - } - if ( function & ZMU_ALARM ) { - if ( monitor->GetFunction() == Monitor::Function::MONITOR ) { - printf("A Monitor in monitor mode cannot handle alarms. Please use NoDect\n"); - } else { - Monitor::State state = monitor->GetState(); - - if ( verbose ) { - printf("Forcing alarm on current state: %s, event %" PRIu64 "\n", - state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle"), - monitor->GetLastEventId() - ); - } - monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web"); - while ( ((state = monitor->GetState()) != Monitor::ALARM) && !zm_terminate ) { - // Wait for monitor to notice. - usleep(1000); - } - printf("Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId()); - } // end if ! MONITOR - } - if ( function & ZMU_NOALARM ) { - if ( verbose ) - printf("Forcing alarm off\n"); - monitor->ForceAlarmOff(); - } - if ( function & ZMU_CANCEL ) { - if ( verbose ) - printf("Cancelling forced alarm on/off\n"); - monitor->CancelForced(); - } - if ( function & ZMU_RELOAD ) { - if ( verbose ) - printf("Reloading monitor settings\n"); - monitor->actionReload(); - } - if ( function & ZMU_ENABLE ) { - if ( verbose ) - printf("Enabling event generation\n"); - monitor->actionEnable(); - } - if ( function & ZMU_DISABLE ) { - if ( verbose ) - printf("Disabling event generation\n"); - monitor->actionDisable(); - } - if ( function & ZMU_SUSPEND ) { - if ( verbose ) - printf("Suspending event generation\n"); - monitor->actionSuspend(); - } - if ( function & ZMU_RESUME ) { - if ( verbose ) - printf("Resuming event generation\n"); - monitor->actionResume(); - } - if ( function & ZMU_QUERY ) { - char monString[16382] = ""; - monitor->DumpSettings(monString, verbose); - printf("%s\n", monString); - } - if ( function & ZMU_BRIGHTNESS ) { - if ( verbose ) { - if ( brightness >= 0 ) - printf("New brightness: %d\n", monitor->actionBrightness(brightness)); - else - printf("Current brightness: %d\n", monitor->actionBrightness()); - } else { - if ( have_output ) fputc(separator, stdout); - if ( brightness >= 0 ) - printf("%d", monitor->actionBrightness(brightness)); - else - printf("%d", monitor->actionBrightness()); - have_output = true; - } - } - if ( function & ZMU_CONTRAST ) { - if ( verbose ) { - if ( contrast >= 0 ) - printf("New brightness: %d\n", monitor->actionContrast(contrast)); - else - printf("Current contrast: %d\n", monitor->actionContrast()); - } else { - if ( have_output ) fputc(separator, stdout); - if ( contrast >= 0 ) - printf("%d", monitor->actionContrast(contrast)); - else - printf("%d", monitor->actionContrast()); - have_output = true; - } - } - if ( function & ZMU_HUE ) { - if ( verbose ) { - if ( hue >= 0 ) - printf("New hue: %d\n", monitor->actionHue(hue)); - else - printf("Current hue: %d\n", monitor->actionHue()); - } else { - if ( have_output ) fputc(separator, stdout); - if ( hue >= 0 ) - printf("%d", monitor->actionHue(hue)); - else - printf("%d", monitor->actionHue()); - have_output = true; - } - } - if ( function & ZMU_COLOUR ) { - if ( verbose ) { - if ( colour >= 0 ) - printf("New colour: %d\n", monitor->actionColour(colour)); - else - printf("Current colour: %d\n", monitor->actionColour()); - } else { - if ( have_output ) fputc(separator, stdout); - if ( colour >= 0 ) - printf("%d", monitor->actionColour(colour)); - else - printf("%d", monitor->actionColour()); - have_output = true; - } - } - if ( have_output ) { - printf("\n"); - } - if ( !function ) { - Usage(); - } + if ( verbose ) { + printf("Monitor %d(%s)\n", monitor->Id(), monitor->Name()); + } + if ( !monitor->connect() ) { + Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); delete monitor; - } else { - Error("Invalid monitor id %d", mon_id); + monitor = NULL; exit_zmu(-1); } - } else { + + char separator = ' '; + bool have_output = false; + if ( function & ZMU_STATE ) { + Monitor::State state = monitor->GetState(); + if ( verbose ) { + printf("Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle")); + } else { + if ( have_output ) fputc(separator, stdout); + printf("%d", state); + have_output = true; + } + } + if ( function & ZMU_TIME ) { + struct timeval timestamp = monitor->GetTimestamp(image_idx); + if ( verbose ) { + char timestamp_str[64] = "None"; + if ( timestamp.tv_sec ) + strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime(×tamp.tv_sec)); + if ( image_idx == -1 ) + printf("Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000); + else + printf("Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000); + } else { + if ( have_output ) fputc(separator, stdout); + printf("%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000); + have_output = true; + } + } + if ( function & ZMU_READ_IDX ) { + if ( verbose ) + printf("Last read index: %d\n", monitor->GetLastReadIndex()); + else { + if ( have_output ) fputc(separator, stdout); + printf("%d", monitor->GetLastReadIndex()); + have_output = true; + } + } + if ( function & ZMU_WRITE_IDX ) { + if ( verbose ) { + printf("Last write index: %d\n", monitor->GetLastWriteIndex()); + } else { + if ( have_output ) fputc(separator, stdout); + printf("%d", monitor->GetLastWriteIndex()); + have_output = true; + } + } + if ( function & ZMU_EVENT ) { + if ( verbose ) { + printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId()); + } else { + if ( have_output ) fputc(separator, stdout); + printf("%" PRIu64, monitor->GetLastEventId()); + have_output = true; + } + } + if ( function & ZMU_FPS ) { + if ( verbose ) { + printf("Current capture rate: %.2f frames per second\n", monitor->GetFPS()); + } else { + if ( have_output ) fputc(separator, stdout); + printf("%.2f", monitor->GetFPS()); + have_output = true; + } + } + if ( function & ZMU_IMAGE ) { + if ( verbose ) { + if ( image_idx == -1 ) + printf("Dumping last image captured to Monitor%d.jpg", monitor->Id()); + else + printf("Dumping buffer image %d to Monitor%d.jpg", image_idx, monitor->Id()); + if ( scale != -1 ) + printf(", scaling by %d%%", scale); + printf("\n"); + } + monitor->GetImage(image_idx, scale>0?scale:100); + } + if ( function & ZMU_ZONES ) { + if ( verbose ) + printf("Dumping zone image to Zones%d.jpg\n", monitor->Id()); + monitor->DumpZoneImage(zoneString); + } + if ( function & ZMU_ALARM ) { + if ( monitor->GetFunction() == Monitor::Function::MONITOR ) { + printf("A Monitor in monitor mode cannot handle alarms. Please use NoDect\n"); + } else { + Monitor::State state = monitor->GetState(); + + if ( verbose ) { + printf("Forcing alarm on current state: %s, event %" PRIu64 "\n", + state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle"), + monitor->GetLastEventId() + ); + } + monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web"); + while ( ((state = monitor->GetState()) != Monitor::ALARM) && !zm_terminate ) { + // Wait for monitor to notice. + usleep(1000); + } + printf("Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId()); + } + } // end if ZMU_ALARM + + if ( function & ZMU_NOALARM ) { + if ( verbose ) + printf("Forcing alarm off\n"); + monitor->ForceAlarmOff(); + } + if ( function & ZMU_CANCEL ) { + if ( verbose ) + printf("Cancelling forced alarm on/off\n"); + monitor->CancelForced(); + } + if ( function & ZMU_RELOAD ) { + if ( verbose ) + printf("Reloading monitor settings\n"); + monitor->actionReload(); + } + if ( function & ZMU_ENABLE ) { + if ( verbose ) + printf("Enabling event generation\n"); + monitor->actionEnable(); + } + if ( function & ZMU_DISABLE ) { + if ( verbose ) + printf("Disabling event generation\n"); + monitor->actionDisable(); + } + if ( function & ZMU_SUSPEND ) { + if ( verbose ) + printf("Suspending event generation\n"); + monitor->actionSuspend(); + } + if ( function & ZMU_RESUME ) { + if ( verbose ) + printf("Resuming event generation\n"); + monitor->actionResume(); + } + if ( function & ZMU_QUERY ) { + char monString[16382] = ""; + monitor->DumpSettings(monString, verbose); + printf("%s\n", monString); + } + if ( function & ZMU_BRIGHTNESS ) { + if ( verbose ) { + if ( brightness >= 0 ) + printf("New brightness: %d\n", monitor->actionBrightness(brightness)); + else + printf("Current brightness: %d\n", monitor->actionBrightness()); + } else { + if ( have_output ) fputc(separator, stdout); + if ( brightness >= 0 ) + printf("%d", monitor->actionBrightness(brightness)); + else + printf("%d", monitor->actionBrightness()); + have_output = true; + } + } + if ( function & ZMU_CONTRAST ) { + if ( verbose ) { + if ( contrast >= 0 ) + printf("New brightness: %d\n", monitor->actionContrast(contrast)); + else + printf("Current contrast: %d\n", monitor->actionContrast()); + } else { + if ( have_output ) fputc(separator, stdout); + if ( contrast >= 0 ) + printf("%d", monitor->actionContrast(contrast)); + else + printf("%d", monitor->actionContrast()); + have_output = true; + } + } + if ( function & ZMU_HUE ) { + if ( verbose ) { + if ( hue >= 0 ) + printf("New hue: %d\n", monitor->actionHue(hue)); + else + printf("Current hue: %d\n", monitor->actionHue()); + } else { + if ( have_output ) fputc(separator, stdout); + if ( hue >= 0 ) + printf("%d", monitor->actionHue(hue)); + else + printf("%d", monitor->actionHue()); + have_output = true; + } + } + if ( function & ZMU_COLOUR ) { + if ( verbose ) { + if ( colour >= 0 ) + printf("New colour: %d\n", monitor->actionColour(colour)); + else + printf("Current colour: %d\n", monitor->actionColour()); + } else { + if ( have_output ) fputc(separator, stdout); + if ( colour >= 0 ) + printf("%d", monitor->actionColour(colour)); + else + printf("%d", monitor->actionColour()); + have_output = true; + } + } + + if ( have_output ) { + printf("\n"); + } + if ( !function ) { + Usage(); + } + delete monitor; + monitor = NULL; + } else { // non monitor functions if ( function & ZMU_QUERY ) { #if ZM_HAS_V4L char vidString[0x10000] = ""; @@ -712,11 +717,11 @@ int main(int argc, char *argv[]) { } if ( function & ZMU_LIST ) { - std::string sql = "select Id, Function+0 from Monitors"; + std::string sql = "SELECT Id, `Function`+0 FROM Monitors"; if ( !verbose ) { - sql += "where Function != 'None'"; + sql += "WHERE `Function` != 'None'"; } - sql += " order by Id asc"; + sql += " ORDER BY Id ASC"; if ( mysql_query(&dbconn, sql.c_str()) ) { Error("Can't run query: %s", mysql_error(&dbconn)); @@ -770,8 +775,10 @@ int main(int argc, char *argv[]) { } // end foreach row mysql_free_result(result); } // end if function && ZMU_LIST - } + } // end if monitor id or not delete user; - return exit_zmu(0); -} + printf("Exiting"); + exit_zmu(0); + return 0; +} // end int main() From 4fed2d6d267ff849de73e9971cb1062334a663db Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 May 2020 12:20:14 -0400 Subject: [PATCH 17/45] bump version to 1.34.13 for release --- distros/redhat/zoneminder.spec | 2 +- version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 10fd82e4f..73f66e958 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.34.12 +Version: 1.34.13 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 7355e24bb..9c9f16d07 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.34.12 +1.34.13 From 7a85be59be946cf9605360deaddd8b4c7fe45f42 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 10:22:58 -0400 Subject: [PATCH 18/45] Remove errant closing db debug output --- src/zmu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zmu.cpp b/src/zmu.cpp index b5e951100..ef8a9276e 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -198,7 +198,6 @@ bool ValidateAccess(User *user, int mon_id, int function) { void exit_zmu(int exit_code) { logTerm(); - printf("closing db\n"); zmDbClose(); exit(exit_code); From 94b29c6c7a86ab51671ea9a3b0ad13a69f6b58db Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 10:44:48 -0400 Subject: [PATCH 19/45] replace inline javascript in timeline zoom --- web/api/app/Plugin/Crud | 2 +- web/skins/classic/views/js/timeline.js | 5 ++++- web/skins/classic/views/timeline.php | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 0bd63fb46..c3976f147 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef +Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5 diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js index 8d3f01d4c..cbebfc0d7 100644 --- a/web/skins/classic/views/js/timeline.js +++ b/web/skins/classic/views/js/timeline.js @@ -179,7 +179,10 @@ function loadEventImage( imagePath, eid, fid, width, height, fps, videoName, dur eventData.addEvent('click', showEvent.pass()); } -function tlZoomBounds( minTime, maxTime ) { +function tlZoomBounds(event) { + var target = event.target; + var minTime = target.getAttribute('data-zoom-min-time'); + var maxTime = target.getAttribute('data-zoom-max-time'); location.replace('?view='+currentView+filterQuery+'&minTime='+minTime+'&maxTime='+maxTime); } diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index 794b99c20..2f1218b3e 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -616,7 +616,7 @@ function drawXGrid( $chart, $scale, $labelClass, $tickClass, $gridClass, $zoomCl $zoomMinTime = strftime( STRF_FMT_DATETIME_DB, (int)($chart['data']['x']['lo'] + ($lastTick * $chart['data']['x']['density'])) ); $zoomMaxTime = strftime( STRF_FMT_DATETIME_DB, (int)($chart['data']['x']['lo'] + ($i * $chart['data']['x']['density'])) ); ?> -
+
-
+
From 0dd426d64ce207a97cb2b8b529283176b6dcc527 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 11:33:10 -0400 Subject: [PATCH 20/45] handle range being set to an empty value. Fixes zoom out on timeline. Fix on-click to data-on-click --- web/skins/classic/views/timeline.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index 2f1218b3e..cab313f52 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -154,7 +154,7 @@ if ( isset($_REQUEST['midTime']) ) if ( isset($_REQUEST['maxTime']) ) $maxTime = validHtmlStr($_REQUEST['maxTime']); -if ( isset($range) ) { +if ( isset($range) and validInt($range) ) { $halfRange = (int)($range/2); if ( isset($midTime) ) { $midTimeT = strtotime($midTime); @@ -616,7 +616,7 @@ function drawXGrid( $chart, $scale, $labelClass, $tickClass, $gridClass, $zoomCl $zoomMinTime = strftime( STRF_FMT_DATETIME_DB, (int)($chart['data']['x']['lo'] + ($lastTick * $chart['data']['x']['density'])) ); $zoomMaxTime = strftime( STRF_FMT_DATETIME_DB, (int)($chart['data']['x']['lo'] + ($i * $chart['data']['x']['density'])) ); ?> -
+
-
+
From 424a4ed0b12579f50fe92e3e69dd9b0e4b1db032 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 11:34:23 -0400 Subject: [PATCH 21/45] add onclick to div.zoom --- web/skins/classic/views/js/timeline.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js index cbebfc0d7..0b4d1d5fc 100644 --- a/web/skins/classic/views/js/timeline.js +++ b/web/skins/classic/views/js/timeline.js @@ -36,14 +36,14 @@ function createEventHtml(zm_event, frame) { return eventHtml; } -function showEventDetail( eventHtml ) { - $('instruction').addClass( 'hidden' ); +function showEventDetail(eventHtml) { + $('instruction').addClass('hidden'); $('eventData').empty(); - $('eventData').adopt( eventHtml ); - $('eventData').removeClass( 'hidden' ); + $('eventData').adopt(eventHtml); + $('eventData').removeClass('hidden'); } -function eventDataResponse( respObj, respText ) { +function eventDataResponse(respObj, respText) { var zm_event = respObj.event; if ( !zm_event ) { console.log('Null event'); @@ -197,14 +197,18 @@ function tlPanRight() { location.replace('?view='+currentView+filterQuery+'&midTime='+maxTime+'&range='+range); } -window.addEventListener("DOMContentLoaded", function() { - document.querySelectorAll("div.event").forEach(function(el) { +window.addEventListener('DOMContentLoaded', function() { + // These look like the code in skin.js, but that code doesn't select for divs. + document.querySelectorAll('div.event').forEach(function(el) { el.onclick = window[el.getAttribute('data-on-click-this')].bind(el, el); el.onmouseover = window[el.getAttribute('data-on-mouseover-this')].bind(el, el); }); - document.querySelectorAll("div.activity").forEach(function(el) { + document.querySelectorAll('div.activity').forEach(function(el) { el.onclick = window[el.getAttribute('data-on-click-this')].bind(el, el); el.onmouseover = window[el.getAttribute('data-on-mouseover-this')].bind(el, el); }); + document.querySelectorAll('div.zoom').forEach(function(el) { + el.onclick = function(ev) { window[el.getAttribute('data-on-click')](ev); }; + }); }); From c4c4c5bcbfa3aeb94f1f0947c0757f02750b2440 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 11:34:34 -0400 Subject: [PATCH 22/45] fix Crud submodule version --- web/api/app/Plugin/Crud | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index c3976f147..0bd63fb46 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5 +Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef From f79a17f3023169afee9adde5fc0d179aec14d928 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 11:35:59 -0400 Subject: [PATCH 23/45] Bump version to 1.34.14 for release --- distros/redhat/zoneminder.spec | 2 +- version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 73f66e958..c3458074c 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.34.13 +Version: 1.34.14 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 9c9f16d07..46a99f18d 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.34.13 +1.34.14 From 9ea1c637f96a5de2ac8f17778abf54e9fece0b7d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 11:48:41 -0400 Subject: [PATCH 24/45] Remove debug Exiting message --- src/zmu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zmu.cpp b/src/zmu.cpp index ef8a9276e..d3e9d96c5 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -777,7 +777,6 @@ int main(int argc, char *argv[]) { } // end if monitor id or not delete user; - printf("Exiting"); exit_zmu(0); return 0; } // end int main() From 4dc693022e4bd0f7afd3142b1210faa958a4892d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 May 2020 16:02:19 -0400 Subject: [PATCH 25/45] Failure to parse output shouldn't be fatal. Just skp to the next instead. Use json_encode instead of serialize --- web/skins/classic/views/monitorprobe.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/web/skins/classic/views/monitorprobe.php b/web/skins/classic/views/monitorprobe.php index 9cab32b3e..a76c67810 100644 --- a/web/skins/classic/views/monitorprobe.php +++ b/web/skins/classic/views/monitorprobe.php @@ -39,16 +39,18 @@ function probeV4L() { } $monitors = array(); - foreach ( dbFetchAll("SELECT Id, Name, Device,Channel FROM Monitors WHERE Type = 'Local' ORDER BY Device, Channel" ) as $monitor ) + foreach ( dbFetchAll("SELECT Id, Name, Device, Channel FROM Monitors WHERE Type = 'Local' ORDER BY Device, Channel" ) as $monitor ) $monitors[$monitor['Device'].':'.$monitor['Channel']] = $monitor; $devices = array(); $preferredStandards = array('PAL', 'NTSC'); $preferredFormats = array('BGR3', 'RGB3', 'YUYV', 'UYVY', 'JPEG', 'MJPG', '422P', 'YU12', 'GREY'); foreach ( $output as $line ) { - if ( !preg_match('/^d:([^|]+).*S:([^|]*).*F:([^|]+).*I:(\d+)\|(.+)$/', $line, $deviceMatches) ) - ZM\Fatal("Can't parse command output '$line'"); - $standards = explode('/',$deviceMatches[2]); + if ( !preg_match('/^d:([^|]+).*S:([^|]*).*F:([^|]+).*I:(\d+)\|(.+)$/', $line, $deviceMatches) ) { + ZM\Error("Can't parse command output '$line'"); + continue; + } + $standards = explode('/', $deviceMatches[2]); $preferredStandard = false; foreach ( $preferredStandards as $standard ) { if ( in_array( $standard, $standards ) ) { @@ -56,7 +58,7 @@ function probeV4L() { break; } } - $formats = explode('/',$deviceMatches[3]); + $formats = explode('/', $deviceMatches[3]); $preferredFormat = false; foreach ( $preferredFormats as $format ) { if ( in_array($format, $formats) ) { @@ -73,8 +75,10 @@ function probeV4L() { ); $inputs = array(); for ( $i = 0; $i < $deviceMatches[4]; $i++ ) { - if ( !preg_match('/i'.$i.':([^|]+)\|i'.$i.'T:([^|]+)\|/', $deviceMatches[5], $inputMatches) ) - ZM\Fatal("Can't parse input '".$deviceMatches[5]."'"); + if ( !preg_match('/i'.$i.':([^|]+)\|i'.$i.'T:([^|]+)\|/', $deviceMatches[5], $inputMatches) ) { + ZM\Error("Can't parse input '".$deviceMatches[5]."'"); + continue; + } if ( $inputMatches[2] == 'Camera' ) { $input = array( 'index' => $i, @@ -101,7 +105,7 @@ function probeV4L() { $inputMonitor['Colours'] = 1; $inputMonitor['SignalCheckColour'] = '#000023'; } - $inputDesc = base64_encode(serialize($inputMonitor)); + $inputDesc = base64_encode(json_encode($inputMonitor)); $inputString = $deviceMatches[1].', chan '.$i.($input['free']?(' - '.translate('Available')):(' ('.$monitors[$input['id']]['Name'].')')); $inputs[] = $input; $cameras[$inputDesc] = $inputString; @@ -288,7 +292,7 @@ function probeNetwork() { if ( isset($macBases[$macRoot]) ) { $macBase = $macBases[$macRoot]; $camera = call_user_func($macBase['probeFunc'], $ip); - $sourceDesc = base64_encode(serialize($camera['monitor'])); + $sourceDesc = base64_encode(json_encode($camera['monitor'])); $sourceString = $camera['model'].' @ '.$host; if ( isset($monitors[$ip]) ) { $monitor = $monitors[$ip]; @@ -330,7 +334,7 @@ xhtmlHeaders(__FILE__, translate('MonitorProbe') );

- + 'configureButtons(this)')); ?>

From 074e270e795d005c5e1c8c11d50c661d97f9081d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 May 2020 16:58:26 -0400 Subject: [PATCH 29/45] populate network interfaces list, rescan on change. --- web/skins/classic/views/onvifprobe.php | 68 +++++++++++++++++++++----- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/web/skins/classic/views/onvifprobe.php b/web/skins/classic/views/onvifprobe.php index ef4e3523d..6f1f2af80 100644 --- a/web/skins/classic/views/onvifprobe.php +++ b/web/skins/classic/views/onvifprobe.php @@ -29,14 +29,14 @@ $cameras[0] = translate('ChooseDetectedCamera'); $profiles = array(); $profiles[0] = translate('ChooseDetectedProfile'); -function execONVIF( $cmd ) { +function execONVIF($cmd) { $shell_command = escapeshellcmd(ZM_PATH_BIN . "/zmonvif-probe.pl $cmd"); - exec( $shell_command, $output, $status ); + exec($shell_command, $output, $status); if ( $status ) { - $html_output = implode( '
', $output ); - ZM\Fatal( "Unable to probe network cameras, status is '$status'. Output was:

+ $html_output = implode('
', $output); + ZM\Fatal("Unable to probe network cameras, status is '$status'. Output was:

$html_output

Please the following command from a command line for more information:

$shell_command" ); @@ -49,7 +49,7 @@ function execONVIF( $cmd ) { function probeCameras($localIp) { $cameras = array(); - if ( $lines = @execONVIF('probe') ) { + if ( $lines = @execONVIF('probe 1.1,1.2'.(isset($_REQUEST['interface']) ? isset($_REQUEST['interface'] : '' )) ) { foreach ( $lines as $line ) { $line = rtrim($line); if ( preg_match('|^(.+),(.+),\s\((.*)\)$|', $line, $matches) ) { @@ -62,20 +62,23 @@ function probeCameras($localIp) { 'Type' => 'Ffmpeg', 'Host' => $device_ep, 'SOAP' => $soapversion, - 'ConfigURL' => $device_ep, - 'ConfigOptions' => 'SOAP' . $soapversion, + 'ConfigURL' => $device_ep, + 'ConfigOptions' => 'SOAP' . $soapversion, + 'Notes' => '', ), ); foreach ( preg_split('|,\s*|', $matches[3]) as $attr_val ) { if ( preg_match('|(.+)=\'(.*)\'|', $attr_val, $tokens) ) { if ( $tokens[1] == 'hardware' ) { $camera['model'] = $tokens[2]; - } elseif ( $tokens[1] == 'name' ) { + } else if ( $tokens[1] == 'name' ) { $camera['monitor']['Name'] = $tokens[2]; - } elseif ( $tokens[1] == 'location' ) { - // $camera['location'] = $tokens[2]; + } else if ( $tokens[1] == 'type' ) { + } else if ( $tokens[1] == 'location' or $tokens[1] == 'location/city' or $tokens[1] == 'location/country' ) { + $camera['monitor']['Notes'] .= $tokens[1].'='.$tokens[2]."\n"; + // $camera['location'] = $tokens[2]; } else { - ZM\Logger::Debug('Unknown token ' . $tokens[1]); + ZM\Logger::Debug('Unknown token '.$tokens[1].' = '.$tokens[2]); } } } // end foreach token @@ -165,6 +168,48 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {

+

+ ', $output); + ZM\Error("Unable to list network interfaces, status is '$status'. Output was:

$html_output"); + } else { + foreach ( $output as $line ) { + if ( preg_match('/^\d+: ([[:alnum:]]+):/', $line, $matches ) ) { + if ( $matches[1] != 'lo' ) { + $interfaces[$matches[1]] = $matches[1]; + } else { + ZM\Logger::Debug("No match for $line"); + } + } + } + } + $routes = array(); + exec('ip route', $output, $status); + if ( $status ) { + $html_output = implode('
', $output); + ZM\Error("Unable to list network interfaces, status is '$status'. Output was:

$html_output"); + } else { + foreach ( $output as $line ) { + if ( preg_match('/^default via [.[:digit:]]+ dev ([[:alnum:]]+)/', $line, $matches) ) { + $default_interface = $matches[1]; + } else if ( preg_match('/^([.\/[:digit:]]+) dev ([[:alnum:]]+)/', $line, $matches) ) { + $interfaces[$matches[2]] .= ' ' . $matches[1]; + } + } # end foreach line of output + } + + echo htmlSelect('interface', $interfaces, + (isset($_REQUEST['interface']) ? $_REQUEST['interface'] : $default_interface), + array('data-on-change-this'=>'changeInterface') ); + +?> +

+

'configureButtons')); ?> @@ -180,6 +225,7 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {

+
From 3faf20516f2ed89995990b0a4cc86f1a1048c1dd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 May 2020 16:58:45 -0400 Subject: [PATCH 30/45] add changeInterface handler --- web/skins/classic/views/js/onvifprobe.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/skins/classic/views/js/onvifprobe.js b/web/skins/classic/views/js/onvifprobe.js index 71cb5e16f..4f10e5c29 100644 --- a/web/skins/classic/views/js/onvifprobe.js +++ b/web/skins/classic/views/js/onvifprobe.js @@ -33,3 +33,7 @@ function configureButtons(element) { form.saveBtn.disabled = (form.probe.selectedIndex==0); } } + +function changeInterface(element) { + gotoStep1(element); +} From 2b60b6b41976859e0f4859cb1047d2fc2720963d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 20 May 2020 09:50:17 -0400 Subject: [PATCH 31/45] Add new ONVIF columns present in zm_update-1.35.4.sql --- db/zm_create.sql.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index ce462ac4c..2c287d7a9 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -445,6 +445,10 @@ CREATE TABLE `Monitors` ( `Enabled` tinyint(3) unsigned NOT NULL default '1', `LinkedMonitors` varchar(255), `Triggers` set('X10') NOT NULL default '', + `ONVIF_URL` VARCHAR(255) NOT NULL DEFAULT '', + `ONVIF_Username` VARCHAR(64) NOT NULL DEFAULT '', + `ONVIF_Password` VARCHAR(64) NOT NULL DEFAULT '', + `ONVIF_Options` VARCHAR(64) NOT NULL DEFAULT '', `Device` tinytext NOT NULL default '', `Channel` tinyint(3) unsigned NOT NULL default '0', `Format` int(10) unsigned NOT NULL default '0', From 59c08410c18dad1e10cd6b3f6729321ce04a37e4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 21 May 2020 13:32:33 -0400 Subject: [PATCH 32/45] Put the size of SHM in the title of the shm space used element --- web/skins/classic/includes/functions.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 51a4a0820..f329f2e40 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -423,13 +423,16 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) { if ( count($storage_areas) <= 4 ) echo implode(', ', array_map($func, $storage_areas)); $shm_percent = getDiskPercent(ZM_PATH_MAP); + $shm_total_space = disk_total_space(ZM_PATH_MAP); + $shm_used = $dhm_total_space - $disk_free_space(ZM_PATH_MAP); + $class = ''; if ( $shm_percent > 98 ) { $class = 'error'; } else if ( $shm_percent > 90 ) { $class = 'warning'; } - echo ' '.ZM_PATH_MAP.': '.$shm_percent.'%'; + echo ' '.ZM_PATH_MAP.': '.$shm_percent.'%'; ?> From 23900cbf01a240f143eec0d31ef7ed65e75f4a73 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 21 May 2020 13:34:09 -0400 Subject: [PATCH 33/45] fix --- web/skins/classic/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index f329f2e40..3d60fde3e 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -424,7 +424,7 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) { echo implode(', ', array_map($func, $storage_areas)); $shm_percent = getDiskPercent(ZM_PATH_MAP); $shm_total_space = disk_total_space(ZM_PATH_MAP); - $shm_used = $dhm_total_space - $disk_free_space(ZM_PATH_MAP); + $shm_used = $shm_total_space - disk_free_space(ZM_PATH_MAP); $class = ''; if ( $shm_percent > 98 ) { From 46a13237b52f1835d2e985d4b3b2f19f28e258e8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 22 May 2020 09:28:15 -0400 Subject: [PATCH 34/45] fix eslint errors --- web/skins/classic/views/js/timeline.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js index 0b4d1d5fc..8742ac67b 100644 --- a/web/skins/classic/views/js/timeline.js +++ b/web/skins/classic/views/js/timeline.js @@ -208,7 +208,9 @@ window.addEventListener('DOMContentLoaded', function() { el.onmouseover = window[el.getAttribute('data-on-mouseover-this')].bind(el, el); }); document.querySelectorAll('div.zoom').forEach(function(el) { - el.onclick = function(ev) { window[el.getAttribute('data-on-click')](ev); }; + el.onclick = function(ev) { + window[el.getAttribute('data-on-click')](ev); + }; }); }); From d7680e1a4477d78e79a573e4b76a04e79562253d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 23 May 2020 10:15:48 -0400 Subject: [PATCH 35/45] Spacing --- web/ajax/event.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index fb9000cc6..1456bd192 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -1,5 +1,5 @@ $exportFile,'exportFormat'=>$exportFormat, 'connkey'=>(isset($_REQUEST['connkey'])?$_REQUEST['connkey']:''))); + ajaxResponse(array( + 'exportFile'=>$exportFile, + 'exportFormat'=>$exportFormat, + 'connkey'=>(isset($_REQUEST['connkey'])?$_REQUEST['connkey']:'') + )); } else { ajaxError('Export Failed'); } @@ -145,7 +149,7 @@ if ( canEdit('Events') ) { break; case 'delete' : $Event = new ZM\Event($_REQUEST['id']); - if ( ! $Event->Id() ) { + if ( !$Event->Id() ) { ajaxResponse(array('refreshEvent'=>false, 'refreshParent'=>true, 'message'=> 'Event not found.')); } else { $Event->delete(); From 662b9894bd4bf79bb5ac32ed7e548a735413d13d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 23 May 2020 16:12:55 -0400 Subject: [PATCH 36/45] Don't delete send_image because it is static. Fixes #2923 --- src/zm_eventstream.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index c65bf7445..3bcce223e 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -714,11 +714,9 @@ bool EventStream::sendFrame(int delta_us) { Image *image = NULL; if ( filepath[0] ) { -Debug(1, "Loading image"); image = new Image(filepath); } else if ( ffmpeg_input ) { // Get the frame from the mp4 input - Debug(1,"Getting frame from ffmpeg"); FrameData *frame_data = &event_data->frames[curr_frame_id-1]; AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id(), @@ -767,7 +765,11 @@ Debug(1, "Loading image"); switch ( type ) { case STREAM_JPEG : - send_image->EncodeJpeg(img_buffer, &img_buffer_size); + if ( send_image->EncodeJpeg(img_buffer, &img_buffer_size) ) { + Debug(1, "encoded JPEG"); + } else { + // Failed + } break; case STREAM_ZIP : #if HAVE_ZLIB_H @@ -787,10 +789,6 @@ Debug(1, "Loading image"); Fatal("Unexpected frame type %d", type); break; } - if ( send_image != image ) { - delete send_image; - send_image = NULL; - } delete image; image = NULL; } // end if send_raw or not @@ -815,7 +813,7 @@ Debug(1, "Loading image"); fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size); if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) { /* sendfile() failed, use standard way instead */ - img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); + img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj); if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) { fclose(fdj); /* Close the file handle */ Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); From a9cec3ebbdffb9dd61df886257505a0c983965bb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 23 May 2020 16:13:29 -0400 Subject: [PATCH 37/45] spacing --- web/skins/classic/views/js/event.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 8b51e0cec..ae14144f5 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -285,7 +285,7 @@ function getCmdResponse( respObj, respText ) { } } // end if haev a new auth hash - streamCmdTimer = streamQuery.delay( streamTimeout ); //Timeout is refresh rate for progressBox and time display + streamCmdTimer = streamQuery.delay(streamTimeout); //Timeout is refresh rate for progressBox and time display } var streamReq = new Request.JSON( { From e72c357fd0440bdd2e4d7b521a20a395dd37dd18 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 23 May 2020 16:13:48 -0400 Subject: [PATCH 38/45] Unable to probe should not be fatal --- web/skins/classic/views/onvifprobe.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/onvifprobe.php b/web/skins/classic/views/onvifprobe.php index 6f1f2af80..95e1abeba 100644 --- a/web/skins/classic/views/onvifprobe.php +++ b/web/skins/classic/views/onvifprobe.php @@ -36,9 +36,10 @@ function execONVIF($cmd) { if ( $status ) { $html_output = implode('
', $output); - ZM\Fatal("Unable to probe network cameras, status is '$status'. Output was:

- $html_output

- Please the following command from a command line for more information:

$shell_command" + ZM\Error("Unable to probe network cameras, status is '$status'. Output was: + $html_output + Please run the following command from a command line for more information: + $shell_command" ); } else { ZM\Logger::Debug('Results from probe: '.implode('
', $output)); @@ -49,7 +50,8 @@ function execONVIF($cmd) { function probeCameras($localIp) { $cameras = array(); - if ( $lines = @execONVIF('probe 1.1,1.2'.(isset($_REQUEST['interface']) ? isset($_REQUEST['interface'] : '' )) ) { + $lines = @execONVIF('probe 1.1,1.2'.(isset($_REQUEST['interface']) ? ' '.isset($_REQUEST['interface']) : '' )); + if ( $lines ) { foreach ( $lines as $line ) { $line = rtrim($line); if ( preg_match('|^(.+),(.+),\s\((.*)\)$|', $line, $matches) ) { From 85e1dcadf4d616666a9647dbeb94e688e687c774 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 24 May 2020 11:07:52 -0400 Subject: [PATCH 39/45] Fix the array for the de-interlacing options --- web/skins/classic/views/monitor.php | 62 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 910adc539..4e8c2da8d 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -321,31 +321,31 @@ $orientations = array( ); $deinterlaceopts = array( - 'Disabled' => 0x00000000, - 'Four field motion adaptive - Soft' => 0x00001E04, /* 30 change */ - 'Four field motion adaptive - Medium' => 0x00001404, /* 20 change */ - 'Four field motion adaptive - Hard' => 0x00000A04, /* 10 change */ - 'Discard' => 0x00000001, - 'Linear' => 0x00000002, - 'Blend' => 0x00000003, - 'Blend (25%)' => 0x00000205 - ); + 0x00000000 => 'Disabled', + 0x00001E04 => 'Four field motion adaptive - Soft', /* 30 change */ + 0x00001404 => 'Four field motion adaptive - Medium', /* 20 change */ + 0x00000A04 => 'Four field motion adaptive - Hard', /* 10 change */ + 0x00000001 => 'Discard', + 0x00000002 => 'Linear', + 0x00000003 => 'Blend', + 0x00000205 => 'Blend (25%)', +); $deinterlaceopts_v4l2 = array( - 'Disabled' => 0x00000000, - 'Four field motion adaptive - Soft' => 0x00001E04, /* 30 change */ - 'Four field motion adaptive - Medium' => 0x00001404, /* 20 change */ - 'Four field motion adaptive - Hard' => 0x00000A04, /* 10 change */ - 'Discard' => 0x00000001, - 'Linear' => 0x00000002, - 'Blend' => 0x00000003, - 'Blend (25%)' => 0x00000205, - 'V4L2: Capture top field only' => 0x02000000, - 'V4L2: Capture bottom field only' => 0x03000000, - 'V4L2: Alternate fields (Bob)' => 0x07000000, - 'V4L2: Progressive' => 0x01000000, - 'V4L2: Interlaced' => 0x04000000 - ); + 0x00000000 => 'Disabled', + 0x00001E04 => 'Four field motion adaptive - Soft', /* 30 change */ + 0x00001404 => 'Four field motion adaptive - Medium', /* 20 change */ + 0x00000A04 => 'Four field motion adaptive - Hard', /* 10 change */ + 0x00000001 => 'Discard', + 0x00000002 => 'Linear', + 0x00000003 => 'Blend', + 0x00000205 => 'Blend (25%)', + 0x02000000 => 'V4L2: Capture top field only', + 0x03000000 => 'V4L2: Capture bottom field only', + 0x07000000 => 'V4L2: Alternate fields (Bob)', + 0x01000000 => 'V4L2: Progressive', + 0x04000000 => 'V4L2: Interlaced', +); $fastblendopts = array( 'No blending' => 0, @@ -739,8 +739,8 @@ switch ( $tab ) { continue; if ( $optCount && ($optCount%$breakCount == 0) ) echo '
'; - echo 'Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"' : ''). '/> '. $optTrigger; + echo 'Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"' : ''). '/> '. $optTrigger; $optCount ++; } # end foreach trigger option if ( !$optCount ) { @@ -755,7 +755,7 @@ switch ( $tab ) { case 'onvif' : { ?> - + @@ -829,7 +829,7 @@ include('_monitor_source_nvsocket.php'); -Type() == 'Remote' ) { ?> Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?> @@ -838,7 +838,7 @@ include('_monitor_source_nvsocket.php'); -Protocol() || $monitor->Protocol() == 'http' ) { echo htmlSelect('newMonitor[Method]', $httpMethods, $monitor->Method() ); } else { @@ -1106,7 +1106,7 @@ include('_monitor_source_nvsocket.php'); - ControlId()); + ControlId()); if ( canEdit('Control') ) { echo ' '.makePopupLink('?view=controlcaps', 'zmControlCaps', 'controlcaps', translate('Edit')); } @@ -1134,7 +1134,7 @@ if ( canEdit('Control') ) { - translate('None'), '0' => translate('Home'), @@ -1236,7 +1236,7 @@ echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnL      - sync + sync From 8121787ee6b4059446c8d83651ce3844b49b1e70 Mon Sep 17 00:00:00 2001 From: Romain ODDONE Date: Wed, 27 May 2020 10:08:08 +0200 Subject: [PATCH 40/45] make monitors table (console view) responsive --- web/skins/classic/views/console.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 71c60b6f0..98420783b 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -205,6 +205,7 @@ getBodyTopHTML(); +
@@ -390,9 +391,10 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { - + -
+ +
From bd287d7c7c6caac34a73679f9469e4e513d1b12a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 29 May 2020 11:44:34 -0400 Subject: [PATCH 41/45] Fix segfault when timestamp contains an unimplemented character. Fixes #2943 --- src/zm_image.cpp | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 31c71037f..02cdd1ad8 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -1905,11 +1905,11 @@ void Image::MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour /* RGB32 compatible: complete */ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int size, const Rgb fg_colour, const Rgb bg_colour ) { - strncpy( text, p_text, sizeof(text)-1 ); + strncpy(text, p_text, sizeof(text)-1); unsigned int index = 0; unsigned int line_no = 0; - unsigned int text_len = strlen( text ); + unsigned int text_len = strlen(text); unsigned int line_len = 0; const char *line = text; @@ -1928,10 +1928,10 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int const bool bg_trans = (bg_colour == RGB_TRANSPARENT); int zm_text_bitmask = 0x80; - if (size == 2) + if ( size == 2 ) zm_text_bitmask = 0x8000; - while ( (index < text_len) && (line_len = strcspn( line, "\n" )) ) { + while ( (index < text_len) && (line_len = strcspn(line, "\n")) ) { unsigned int line_width = line_len * ZM_CHAR_WIDTH * size; @@ -1967,10 +1967,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int unsigned char *temp_ptr = ptr; for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) { int f; - if (size == 2) + if ( size == 2 ) { + if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) { + Warning("Unsupported character %c in %s", line[c], line); + continue; + } f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r]; - else + } else { + if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) { + Warning("Unsupported character %c in %s", line[c], line); + continue; + } f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r]; + } for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr++ ) { if ( f & (zm_text_bitmask >> i) ) { if ( !fg_trans ) @@ -1989,10 +1998,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int unsigned char *temp_ptr = ptr; for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) { int f; - if (size == 2) + if ( size == 2 ) { + if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) { + Warning("Unsupported character %c in %s", line[c], line); + continue; + } f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r]; - else + } else { + if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) { + Warning("Unsupported character %c in %s", line[c], line); + continue; + } f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r]; + } for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr += colours ) { if ( f & (zm_text_bitmask >> i) ) { if ( !fg_trans ) { @@ -2016,10 +2034,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int Rgb* temp_ptr = (Rgb*)ptr; for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) { int f; - if (size == 2) + if ( size == 2 ) { + if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) { + Warning("Unsupported character %c in %s", line[c], line); + continue; + } f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r]; - else + } else { + if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) { + Warning("Unsupported character %c in %s", line[c], line); + continue; + } f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r]; + } for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr++ ) { if ( f & (zm_text_bitmask >> i) ) { if ( !fg_trans ) { From 0e6ff1ad09abd9f4ffd0472880f8063de5ee882c Mon Sep 17 00:00:00 2001 From: Kevin Stolp Date: Mon, 1 Jun 2020 22:54:29 -0700 Subject: [PATCH 42/45] Detaint mysql commands in update script --- scripts/zmupdate.pl.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 3662b6655..adbfde8a3 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -399,6 +399,7 @@ if ( $version ) { $command .= " --add-drop-table --databases ".$Config{ZM_DB_NAME}." > ".$backup; print( "Creating backup to $backup. This may take several minutes.\n" ); print( "Executing '$command'\n" ) if ( logDebugging() ); + ($command) = $command =~ /(.*)/; # detaint my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { @@ -993,6 +994,7 @@ sub patchDB { $command .= '/zm_update-'.$version.'.sql'; print("Executing '$command'\n") if logDebugging(); + ($command) = $command =~ /(.*)/; # detaint my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { From a9c52a21ec6d5b421c96e8eacd3cc9c619e7a3d8 Mon Sep 17 00:00:00 2001 From: Romain ODDONE Date: Tue, 2 Jun 2020 17:25:07 +0200 Subject: [PATCH 43/45] call to changeScale() on page init when "scale to fit" is selected --- web/skins/classic/views/js/watch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 8a38afea4..bb6f535d8 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -849,7 +849,7 @@ function initPage() { if ( refreshApplet && appletRefreshTime ) { appletRefresh.delay(appletRefreshTime*1000); } - if ( scale == 'auto' ) changeScale(); + if ( scale == '0' || scale == 'auto' ) changeScale(); if ( window.history.length == 1 ) { $j('#closeControl').html(''); } From 6f42cb22d665b5cd4be785672fbf0b7fc5843ab8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Jun 2020 15:36:47 -0400 Subject: [PATCH 44/45] Use single quotes when escaping password so that $ has no effect. Also escape any single quotes in the password. --- scripts/zmupdate.pl.in | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 3662b6655..69e277a19 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -121,6 +121,8 @@ GetOptions( my $dbh = zmDbConnect(undef, { mysql_multi_statements=>1 } ); $Config{ZM_DB_USER} = $dbUser; $Config{ZM_DB_PASS} = $dbPass; +# we escape dbpass with single quotes so that $ in the password has no effect, but dbpass could have a ' in it. +$dbPass =~ s/'/\\'/g; if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version) ) { if ( $Config{ZM_DYN_DB_VERSION} ) { @@ -384,21 +386,21 @@ if ( $version ) { my $command = 'mysqldump'; if ( defined($portOrSocket) ) { if ( $portOrSocket =~ /^\// ) { - $command .= " -S".$portOrSocket; + $command .= ' -S'.$portOrSocket; } else { - $command .= " -h".$host." -P".$portOrSocket; + $command .= ' -h'.$host.' -P'.$portOrSocket; } } else { - $command .= " -h".$host; + $command .= ' -h'.$host; } if ( $dbUser ) { $command .= ' -u'.$dbUser; - $command .= ' -p"'.$dbPass.'"' if $dbPass; + $command .= ' -p\''.$dbPass.'\'' if $dbPass; } - my $backup = "@ZM_TMPDIR@/".$Config{ZM_DB_NAME}."-".$version.".dump"; - $command .= " --add-drop-table --databases ".$Config{ZM_DB_NAME}." > ".$backup; - print( "Creating backup to $backup. This may take several minutes.\n" ); - print( "Executing '$command'\n" ) if ( logDebugging() ); + my $backup = '@ZM_TMPDIR@/'.$Config{ZM_DB_NAME}.'-'.$version.'.dump'; + $command .= ' --add-drop-table --databases '.$Config{ZM_DB_NAME}.' > '.$backup; + print("Creating backup to $backup. This may take several minutes.\n"); + print("Executing '$command'\n") if logDebugging(); my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { @@ -982,7 +984,7 @@ sub patchDB { } if ( $dbUser ) { $command .= ' -u'.$dbUser; - $command .= ' -p"'.$dbPass.'"' if $dbPass; + $command .= ' -p\''.$dbPass.'\'' if $dbPass; } $command .= ' '.$Config{ZM_DB_NAME}.' < '; if ( $updateDir ) { From 0644358d0a7c0ac41c55e36eb7804cf2aa9c4bee Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Jun 2020 17:41:03 -0400 Subject: [PATCH 45/45] in getDiskPercent we have calls to Error without the ZM namespace. Fixes #2954 --- web/includes/functions.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index f640569c3..d5c98cb3f 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1499,15 +1499,15 @@ function getLoad() { function getDiskPercent($path = ZM_DIR_EVENTS) { $total = disk_total_space($path); if ( $total === false ) { - Error('disk_total_space returned false. Verify the web account user has access to ' . $path); + ZM\Error('disk_total_space returned false. Verify the web account user has access to ' . $path); return 0; } elseif ( $total == 0 ) { - Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path); + ZM\Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path); return 100; } $free = disk_free_space($path); if ( $free === false ) { - Error('disk_free_space returned false. Verify the web account user has access to ' . $path); + ZM\Error('disk_free_space returned false. Verify the web account user has access to ' . $path); } $space = round((($total - $free) / $total) * 100); return $space; @@ -2063,7 +2063,7 @@ function logState() { if ( $count['Level'] <= ZM\Logger::PANIC ) $count['Level'] = ZM\Logger::FATAL; if ( !($levelCount = $levelCounts[$count['Level']]) ) { - Error('Unexpected Log level '.$count['Level']); + ZM\Error('Unexpected Log level '.$count['Level']); next; } if ( $levelCount[1] && $count['LevelCount'] >= $levelCount[1] ) {