From a231f500eca74df1d1ffc4f98926d669095c9b35 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 23 Feb 2018 19:01:42 -0500 Subject: [PATCH 001/154] better debug, whitespace --- src/zm_monitor.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index dc097d1ab..99cafd150 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -570,19 +570,19 @@ bool Monitor::connect() { Debug(3,"Aligning shared memory images to the next 64 byte boundary"); shared_images = (uint8_t*)((unsigned long)shared_images + (64 - ((unsigned long)shared_images % 64))); } - Debug(3, "Allocating %d image buffers", image_buffer_count ); - image_buffer = new Snapshot[image_buffer_count]; - for ( int i = 0; i < image_buffer_count; i++ ) { - image_buffer[i].timestamp = &(shared_timestamps[i]); - image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); - image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ - } - if ( (deinterlacing & 0xff) == 4) { - /* Four field motion adaptive deinterlacing in use */ - /* Allocate a buffer for the next image */ - next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); - next_buffer.timestamp = new struct timeval; - } + Debug(3, "Allocating %d image buffers", image_buffer_count ); + image_buffer = new Snapshot[image_buffer_count]; + for ( int i = 0; i < image_buffer_count; i++ ) { + image_buffer[i].timestamp = &(shared_timestamps[i]); + image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); + image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ + } + if ( (deinterlacing & 0xff) == 4) { + /* Four field motion adaptive deinterlacing in use */ + /* Allocate a buffer for the next image */ + next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + next_buffer.timestamp = new struct timeval; + } if ( ( purpose == ANALYSIS ) && analysis_fps ) { // Size of pre event buffer must be greater than pre_event_count // if alarm_frame_count > 1, because in this case the buffer contains @@ -802,7 +802,7 @@ double Monitor::GetFPS() const { Snapshot *snap1 = &image_buffer[index1]; if ( !snap1->timestamp || !snap1->timestamp->tv_sec ) { // This should be impossible - Warning("Impossible situation. No timestamp on captured image"); + Warning("Impossible situation. No timestamp on captured image index was %d, image-buffer_count was (%d)", index1, image_buffer_count); return 0.0; } struct timeval time1 = *snap1->timestamp; From ce5e484f2a6a35605cca50ddf8be04fb7ec2648d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 21:50:27 -0400 Subject: [PATCH 002/154] Work harder to ensure we return a Storage object --- web/includes/Event.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 440619390..66929687e 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -48,10 +48,13 @@ class Event { if ( $new ) { $this->{'Storage'} = $new; } - if ( ! ( array_key_exists( 'Storage', $this ) and $this->{'Storage'} ) ) { - $this->{'Storage'} = isset($this->{'StorageId'}) ? - Storage::find_one(array('Id'=>$this->{'StorageId'})) : - new Storage(NULL); + if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) ) { + if ( isset($this->{'StorageId'}) and $this->{'StorageId'} ) + $this->{'Storage'} = Storage::find_one(array('Id'=>$this->{'StorageId'})); + if ( ! $this->{'Storage'} ) + $this->{'Storage'} = new Storage(NULL); + } else { + $this->{'Storage'} = new Storage(NULL); } return $this->{'Storage'}; } From dcfd9a60bc7367a12088768c03e219e04cb7600a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 22:26:47 -0400 Subject: [PATCH 003/154] close the session earlier --- web/index.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/index.php b/web/index.php index f3fa91449..44c751352 100644 --- a/web/index.php +++ b/web/index.php @@ -145,6 +145,9 @@ if ( ZM_OPT_USE_AUTH ) { } else { $user = $defaultUser; } +# Only one request can open the session file at a time, so let's close the session here to improve concurrency. +# Any file/page that sets session variables must re-open it. +session_write_close(); require_once( 'includes/lang.php' ); require_once( 'includes/functions.php' ); @@ -158,7 +161,7 @@ CORSHeaders(); // Check for valid content dirs if ( !is_writable(ZM_DIR_EVENTS) || !is_writable(ZM_DIR_IMAGES) ) { - Error( "Cannot write to content dirs('".ZM_DIR_EVENTS."','".ZM_DIR_IMAGES."'). Check that these exist and are owned by the web account user"); + Warning("Cannot write to content dirs('".ZM_DIR_EVENTS."','".ZM_DIR_IMAGES."'). Check that these exist and are owned by the web account user"); } # Globals @@ -187,9 +190,6 @@ if ( ZM_OPT_USE_AUTH ) { generateAuthHash( ZM_AUTH_HASH_IPS ); } } -# Only one request can open the session file at a time, so let's close the session here to improve concurrency. -# Any file/page that sets session variables must re-open it. -session_write_close(); if ( isset($_REQUEST['action']) ) { $action = detaintPath($_REQUEST['action']); From 998d60a4b2de5a6771850152cb705fc335f6f7a7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 22:26:57 -0400 Subject: [PATCH 004/154] whitespace --- web/includes/actions.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 3eb76c945..cc264d29f 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -145,7 +145,7 @@ if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 're } // Event scope actions, view permissions only required -if ( canView( 'Events' ) ) { +if ( canView('Events') ) { if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) { if ( $action == 'addterm' ) { @@ -155,7 +155,7 @@ if ( canView( 'Events' ) ) { } else if ( canEdit( 'Events' ) ) { if ( $action == 'delete' ) { if ( ! empty($_REQUEST['Id']) ) { - dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['Id'] ) ); + dbQuery('DELETE FROM Filters WHERE Id=?', array($_REQUEST['Id'])); } } else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) { # or ( $action == 'submit' ) ) { @@ -189,9 +189,9 @@ if ( canView( 'Events' ) ) { $sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0); if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) { - dbQuery( 'UPDATE Filters SET ' . $sql. ' WHERE Id=?', array($_REQUEST['Id']) ); + dbQuery('UPDATE Filters SET ' . $sql. ' WHERE Id=?', array($_REQUEST['Id'])); } else { - dbQuery( 'INSERT INTO Filters SET' . $sql ); + dbQuery('INSERT INTO Filters SET' . $sql); $_REQUEST['Id'] = dbInsertId(); } if ( $action == 'execute' ) { @@ -207,7 +207,7 @@ if ( canView( 'Events' ) ) { // Event scope actions, edit permissions required if ( canEdit('Events') ) { if ( ($action == 'rename') && isset($_REQUEST['eventName']) && !empty($_REQUEST['eid']) ) { - dbQuery( 'UPDATE Events SET Name=? WHERE Id=?', array( $_REQUEST['eventName'], $_REQUEST['eid'] ) ); + dbQuery('UPDATE Events SET Name=? WHERE Id=?', array($_REQUEST['eventName'], $_REQUEST['eid'])); } 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'] ) ); From 279e437545dd84c2f51f7a21e2c4cab189703470 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 23:07:33 -0400 Subject: [PATCH 005/154] Put back zmupdate and do more output --- distros/ubuntu1604/zoneminder.postinst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index 27d31953c..b9307bddd 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -35,6 +35,7 @@ if [ "$1" = "configure" ]; then else DBSERVICE="mysql.service" fi + echo "Detected db service is $DBSERVICE" if systemctl is-failed --quiet $DBSERVICE; then echo "$DBSERVICE is in a failed state; it will not be started." echo "If you have already resolved the problem preventing $DBSERVICE from running," @@ -53,13 +54,20 @@ if [ "$1" = "configure" ]; 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 + echo "Creating zm db" cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf # This creates the user. echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql else + echo "Updating permissions" echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute 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 + + # Add any new PTZ control configurations to the database (will not overwrite) + zmcamtool.pl --import >/dev/null 2>&1 else echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.' fi From bef7098cb4b8fb8143df1e25f40e1c9ccd7f6c05 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 15 Apr 2018 10:26:38 -0400 Subject: [PATCH 006/154] Fix Event->Storage() --- web/includes/Event.php | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 66929687e..eca85cd97 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -15,12 +15,12 @@ class Event { public function __construct( $IdOrRow = null ) { $row = NULL; if ( $IdOrRow ) { - if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) { - $row = dbFetchOne( 'SELECT *,unix_timestamp(StartTime) as Time FROM Events WHERE Id=?', NULL, array( $IdOrRow ) ); + if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) { + $row = dbFetchOne('SELECT *,unix_timestamp(StartTime) as Time FROM Events WHERE Id=?', NULL, array($IdOrRow)); if ( ! $row ) { Error('Unable to load Event record for Id=' . $IdOrRow ); } - } elseif ( is_array( $IdOrRow ) ) { + } elseif ( is_array($IdOrRow) ) { $row = $IdOrRow; } else { $backTrace = debug_backtrace(); @@ -31,16 +31,16 @@ class Event { return; } - if ( $row ) { - foreach ($row as $k => $v) { - $this->{$k} = $v; - } - } else { + if ( $row ) { + foreach ($row as $k => $v) { + $this->{$k} = $v; + } + } else { $backTrace = debug_backtrace(); $file = $backTrace[1]['file']; $line = $backTrace[1]['line']; - Error('No row for Event ' . $IdOrRow . " from $file:$line"); - } + Error('No row for Event ' . $IdOrRow . " from $file:$line"); + } } # end if isset($IdOrRow) } // end function __construct @@ -51,10 +51,8 @@ class Event { if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) ) { if ( isset($this->{'StorageId'}) and $this->{'StorageId'} ) $this->{'Storage'} = Storage::find_one(array('Id'=>$this->{'StorageId'})); - if ( ! $this->{'Storage'} ) + if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) ) $this->{'Storage'} = new Storage(NULL); - } else { - $this->{'Storage'} = new Storage(NULL); } return $this->{'Storage'}; } @@ -73,12 +71,12 @@ class Event { $backTrace = debug_backtrace(); $file = $backTrace[1]['file']; $line = $backTrace[1]['line']; - Warning( "Unknown function call Event->$fn from $file:$line" ); + Warning("Unknown function call Event->$fn from $file:$line"); } } public function Time() { - if ( ! isset( $this->{'Time'} ) ) { + if ( ! isset($this->{'Time'}) ) { $this->{'Time'} = strtotime($this->{'StartTime'}); } return $this->{'Time'}; @@ -100,7 +98,7 @@ class Event { $event_path = $this->{'MonitorId'} .'/'.$this->{'Id'}; } - return( $event_path ); + return $event_path; } // end function Relative_Path() public function Link_Path() { @@ -210,8 +208,8 @@ class Event { $this->{'DiskSpace'} = $new; } if ( null === $this->{'DiskSpace'} ) { - $this->{'DiskSpace'} = folder_size( $this->Path() ); - dbQuery( 'UPDATE Events SET DiskSpace=? WHERE Id=?', array( $this->{'DiskSpace'}, $this->{'Id'} ) ); + $this->{'DiskSpace'} = folder_size($this->Path()); + dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'})); } return $this->{'DiskSpace'}; } From 2860e067bc9acfd57cc4e0d1f817bd57a986ac55 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 15 Apr 2018 10:26:57 -0400 Subject: [PATCH 007/154] Fix caching when an array is passed to new --- web/includes/Storage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 7497ab0f5..ef00348d8 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -21,7 +21,7 @@ class Storage { foreach ($row as $k => $v) { $this->{$k} = $v; } - $storage_cache[$IdOrRow] = $this; + $storage_cache[$row['Id']] = $this; } else { $this->{'Name'} = ''; $this->{'Path'} = ''; From 98b54f87f25880c78db98523423b1622441caa04 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 15 Apr 2018 10:27:08 -0400 Subject: [PATCH 008/154] make thumbnail code more readable --- web/skins/classic/views/events.php | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 02946c6a4..f4b84b065 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -218,22 +218,16 @@ while ( $event_row = dbFetchNext($results) ) { if ( ZM_WEB_LIST_THUMBS ) { if ( $thumbData = $event->createListThumbnail() ) { #Logger::Debug(print_r($thumbData,true)); -?> - -'; $imgSrc = $thumbData['url']; - $streamSrc = $event->getStreamSrc( array( 'mode'=>'jpeg', '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()) .''; echo ''.$imgHtml.''; -?> - -'; } else { Logger::Debug("No thumbnail data"); -?> -   - '; } } // end if ZM_WEB_LIST_THUMBS ?> @@ -256,7 +250,7 @@ while ( $event_row = dbFetchNext($results) ) { - + From dc098b5299aafd759f09d26d310e82aaab7e9eaa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 16 Apr 2018 14:51:10 -0400 Subject: [PATCH 009/154] put the status into the function column --- web/skins/classic/views/console.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 36de894bf..57be8aabf 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -247,7 +247,6 @@ if ( $fclass != 'infoText' ) $dot_class=$fclass; ?> ' : '>') . $monitor['Name'] ?>
-
', array_map(function($group_id){ $Group = new Group($group_id); @@ -258,7 +257,9 @@ if ( $fclass != 'infoText' ) $dot_class=$fclass; ?>
- '.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?>
+ '.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?>
+
+
Date: Mon, 16 Apr 2018 19:52:05 +0100 Subject: [PATCH 010/154] Fix travis build status (#2077) * Fix travis build status * Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b9a90f9c..3bdf1ffd1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ZoneMinder ========== -[![Build Status](https://travis-ci.org/ZoneMinder/ZoneMinder.png)](https://travis-ci.org/ZoneMinder/ZoneMinder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received) +[![Build Status](https://travis-ci.org/ZoneMinder/zoneminder.png)](https://travis-ci.org/ZoneMinder/zoneminder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received) All documentation for ZoneMinder is now online at https://zoneminder.readthedocs.org From 34111251d9d7c276e45daa7b88c95fc6c67cff2b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 07:02:52 -0700 Subject: [PATCH 011/154] Introduce Close() to camera and monitor api. Use it to close a camera when there is an error with capturing. Remove the sleep10 on error. --- src/zm_camera.h | 1 + src/zm_curl_camera.h | 1 + src/zm_ffmpeg_camera.cpp | 6 +++--- src/zm_ffmpeg_camera.h | 2 +- src/zm_file_camera.h | 1 + src/zm_libvlc_camera.h | 1 + src/zm_local_camera.h | 1 + src/zm_monitor.cpp | 1 + src/zm_monitor.h | 1 + src/zm_remote_camera_http.h | 3 ++- src/zm_remote_camera_nvsocket.h | 1 + src/zm_remote_camera_rtsp.h | 1 + src/zmc.cpp | 4 +++- web/api/app/Plugin/Crud | 2 +- 14 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/zm_camera.h b/src/zm_camera.h index 4d991d495..9833e098f 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -89,6 +89,7 @@ public: virtual int Capture( Image &image )=0; virtual int PostCapture()=0; virtual int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) = 0; + virtual int Close()=0; }; #endif // ZM_CAMERA_H diff --git a/src/zm_curl_camera.h b/src/zm_curl_camera.h index 263040649..816937a65 100644 --- a/src/zm_curl_camera.h +++ b/src/zm_curl_camera.h @@ -73,6 +73,7 @@ public: void Initialise(); void Terminate(); + int Close() { return 0; }; int PrimeCapture(); int PreCapture(); diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 5bda70c96..07d7dd657 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -137,7 +137,7 @@ FfmpegCamera::~FfmpegCamera() { delete videoStore; videoStore = NULL; } - CloseFfmpeg(); + Close(); if ( capture ) { Terminate(); @@ -161,7 +161,7 @@ void FfmpegCamera::Terminate() { int FfmpegCamera::PrimeCapture() { if ( mCanCapture ) { Info( "Priming capture from %s, CLosing", mPath.c_str() ); - CloseFfmpeg(); + Close(); } mVideoStreamId = -1; mAudioStreamId = -1; @@ -631,7 +631,7 @@ int FfmpegCamera::OpenFfmpeg() { return 0; } // int FfmpegCamera::OpenFfmpeg() -int FfmpegCamera::CloseFfmpeg() { +int FfmpegCamera::Close() { Debug(2, "CloseFfmpeg called."); diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 65193623c..db7ff8684 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -74,7 +74,7 @@ class FfmpegCamera : public Camera { AVPacket packet; int OpenFfmpeg(); - int CloseFfmpeg(); + int Close(); bool mCanCapture; #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_file_camera.h b/src/zm_file_camera.h index 39a13dae2..84201b872 100644 --- a/src/zm_file_camera.h +++ b/src/zm_file_camera.h @@ -47,6 +47,7 @@ public: int Capture( Image &image ); int PostCapture(); int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; +int Close() { return 0; }; }; #endif // ZM_FILE_CAMERA_H diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h index 4221bd0b7..1a061780b 100644 --- a/src/zm_libvlc_camera.h +++ b/src/zm_libvlc_camera.h @@ -72,6 +72,7 @@ public: int Capture( Image &image ); int CaptureAndRecord( Image &image, timeval recording, char* event_directory ); int PostCapture(); + int Close() { return 0; }; }; #endif // HAVE_LIBVLC diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index dae5f830e..d06631c23 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -163,6 +163,7 @@ public: int Capture( Image &image ); int PostCapture(); int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; + int Close() { return 0; }; static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose ); }; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 68ffdd106..5789fe6f5 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2768,6 +2768,7 @@ unsigned int Monitor::SubpixelOrder() const { return camera->SubpixelOrder(); } int Monitor::PrimeCapture() const { return camera->PrimeCapture(); } int Monitor::PreCapture() const { return camera->PreCapture(); } int Monitor::PostCapture() const { return camera->PostCapture() ; } +int Monitor::Close() { return camera->Close(); }; Monitor::Orientation Monitor::getOrientation() const { return orientation; } Monitor::Snapshot *Monitor::getSnapshot() const { diff --git a/src/zm_monitor.h b/src/zm_monitor.h index ace799312..91fa9bdcb 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -485,6 +485,7 @@ public: int PreCapture() const; int Capture(); int PostCapture() const; + int Close(); unsigned int DetectMotion( const Image &comp_image, Event::StringSet &zoneSet ); // DetectBlack seems to be unused. Check it on zm_monitor.cpp for more info. diff --git a/src/zm_remote_camera_http.h b/src/zm_remote_camera_http.h index fe5823397..a1ed4a267 100644 --- a/src/zm_remote_camera_http.h +++ b/src/zm_remote_camera_http.h @@ -57,7 +57,8 @@ public: int PreCapture(); int Capture( Image &image ); int PostCapture(); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; + int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return 0;}; + int Close() { return 0; }; }; #endif // ZM_REMOTE_CAMERA_HTTP_H diff --git a/src/zm_remote_camera_nvsocket.h b/src/zm_remote_camera_nvsocket.h index 2d9c2905f..fbd7fcd86 100644 --- a/src/zm_remote_camera_nvsocket.h +++ b/src/zm_remote_camera_nvsocket.h @@ -67,6 +67,7 @@ public: int Capture( Image &image ); int PostCapture(); int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; + int Close() { return 0; }; }; #endif // ZM_REMOTE_CAMERA_NVSOCKET_H diff --git a/src/zm_remote_camera_rtsp.h b/src/zm_remote_camera_rtsp.h index 8ed8b713c..b3e392a77 100644 --- a/src/zm_remote_camera_rtsp.h +++ b/src/zm_remote_camera_rtsp.h @@ -87,6 +87,7 @@ public: int Capture( Image &image ); int PostCapture(); int CaptureAndRecord( Image &image, timeval recording, char* event_directory ); + int Close() { return 0; }; }; #endif // ZM_REMOTE_CAMERA_RTSP_H diff --git a/src/zmc.cpp b/src/zmc.cpp index 871c380f6..93b12c716 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -295,16 +295,19 @@ int main(int argc, char *argv[]) { if ( next_delays[i] <= min_delay || next_delays[i] <= 0 ) { if ( monitors[i]->PreCapture() < 0 ) { Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + monitors[i]->Close(); result = -1; break; } if ( monitors[i]->Capture() < 0 ) { Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + monitors[i]->Close(); result = -1; break; } if ( monitors[i]->PostCapture() < 0 ) { Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + monitors[i]->Close(); result = -1; break; } @@ -339,7 +342,6 @@ int main(int argc, char *argv[]) { delete [] capture_delays; delete [] next_delays; delete [] last_capture_times; - sleep(10); } // end while ! zm_terminate outer connection loop for ( int i = 0; i < n_monitors; i++ ) { diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 1351dde6b..c3976f147 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 +Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5 From ef70ff86e97279e7da564733e40fa05c1a402c3b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 11:36:14 -0400 Subject: [PATCH 012/154] cleanup zmaControl --- web/includes/functions.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 10cdda31d..648ce20c3 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -716,18 +716,14 @@ Logger::Debug("daemonControl $string"); exec( $string ); } -function zmcControl( $monitor, $mode=false ) { +function zmcControl($monitor, $mode=false) { $Monitor = new Monitor( $monitor ); return $Monitor->zmcControl($mode); } -function zmaControl( $monitor, $mode=false ) { - if ( !is_array( $monitor ) ) { - $monitor = - $monitor = dbFetchOne( 'select C.*, M.* from Monitors as M left join Controls as C on (M.ControlId = C.Id ) where M.Id=?', NULL, array($monitor) ); - } - $Monitor = new Monitor( $monitor ); - $Monitor->zmaControl($mode); +function zmaControl($monitor, $mode=false) { + $Monitor = new Monitor($monitor); + return $Monitor->zmaControl($mode); } function initDaemonStatus() { From 7e7e353a8c1712850420b7e5e1ab89587c4745e5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 08:47:11 -0700 Subject: [PATCH 013/154] Use a more efficient SQL when finding Orphaned Frames --- scripts/zmaudit.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 0ab4e4e9d..f672a86b3 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -537,7 +537,7 @@ MAIN: while( $loop ) { $cleaned = 0; Debug("Checking for Orphaned Frames"); my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames - WHERE EventId NOT IN (SELECT Id FROM Events)'; + WHERE (SELECT COUNT(*) FROM Events WHERE Events.Id=EventId)=0'; my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() ); $res = $selectOrphanedFramesSth->execute() From 92cb7dabd56acf9da44b00f20c88fcce51e207a5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 08:48:59 -0700 Subject: [PATCH 014/154] merge some fixes from other branches --- web/skins/classic/includes/functions.php | 2 +- web/skins/classic/views/filter.php | 6 +++--- web/skins/classic/views/monitors.php | 6 +++--- web/skins/classic/views/report_event_audit.php | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 24a3e0532..f53b21d54 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -266,7 +266,6 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?> } // if canview_reports ?> -
  • >
  • +
  • >
  • diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 79485c535..5c639cecc 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -188,7 +188,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )

    - +

    @@ -398,11 +398,11 @@ if ( ZM_OPT_MESSAGE ) {

    - Background()) ) { ?> checked="checked"/> + Background()) ) { ?> checked="checked" onclick="updateButtons(this);"/>

    - Concurrent()) ) { ?> checked="checked"/> + Concurrent()) ) { ?> checked="checked" onclick="updateButtons(this);"/>


    diff --git a/web/skins/classic/views/monitors.php b/web/skins/classic/views/monitors.php index 7ee0a097a..4c35a0f8f 100644 --- a/web/skins/classic/views/monitors.php +++ b/web/skins/classic/views/monitors.php @@ -49,7 +49,7 @@ xhtmlHeaders(__FILE__, translate('Function'));
    The following monitors will have these settings update when you click Save:

    ', array_map( function($m){return $m->Id().' ' .$m->Name();}, $monitors ) ); ?> -
    + @@ -88,8 +88,8 @@ echo htmlSelect( 'newMonitor[Function]', $options, $monitor->Function() ); Enabled()) ) { ?> checked="checked"/>

    - - + +
    diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index 0fb878e88..39f5178f0 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -61,8 +61,8 @@ if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($display if ( !isset($_REQUEST['minTime']) && !isset($_REQUEST['maxTime']) ) { $time = time(); - $maxTime = strftime('%FT%T',$time) - 3600; - $minTime = strftime('%FT%T',$time - 2*3600); + $maxTime = strftime('%FT%T',$time - 3600); + $minTime = strftime('%FT%T',$time - (2*3600) ); } if ( isset($_REQUEST['minTime']) ) $minTime = validHtmlStr($_REQUEST['minTime']); From 0198ac832d96451beab0084a151054eac2d97fb2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 12:30:58 -0400 Subject: [PATCH 015/154] improve logging around loss of signal and lock around static sql --- src/zm_monitor.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 68ffdd106..35360d75c 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2366,14 +2366,16 @@ int Monitor::Capture() { captureResult = camera->Capture(*capture_image); } } -Debug(4, "Return from Capture (%d)", captureResult); + if ( captureResult < 0 ) { + Warning("Return from Capture (%d), signal loss", captureResult); // Unable to capture image for temporary reason // Fake a signal loss image Rgb signalcolor; signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */ capture_image->Fill(signalcolor); } else if ( captureResult > 0 ) { + Debug(4, "Return from Capture (%d)", captureResult); /* Deinterlacing */ if ( deinterlacing_value == 1 ) { @@ -2406,7 +2408,7 @@ Debug(4, "Return from Capture (%d)", captureResult); break; } } - } + } // end if have rotation if ( capture_image->Size() > camera->ImageSize() ) { Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); @@ -2451,17 +2453,17 @@ Debug(4, "Return from Capture (%d)", captureResult); last_fps_time = now; if ( new_fps != fps ) { fps = new_fps; - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, fps, fps ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, fps, fps); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); } db_mutex.unlock(); } // end if new_fps != fps } // end if time has changed since last update - } // end if captureResult - } + } // end if it might be time to report the fps + } // end if captureResult // Icon: I'm not sure these should be here. They have nothing to do with capturing if ( shared_data->action & GET_SETTINGS ) { From 196b8c52dc6535d222185633febb5a445d89ae91 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 12:35:59 -0400 Subject: [PATCH 016/154] Apply multiport to event viewing as well --- web/includes/Event.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index eca85cd97..f001deddb 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -162,6 +162,8 @@ class Event { } # end Event->delete public function getStreamSrc( $args=array(), $querySep='&' ) { + + if ( $this->{'DefaultVideo'} and $args['mode'] != 'jpeg' ) { $streamSrc = ZM_BASE_PROTOCOL.'://'; $Monitor = $this->Monitor(); @@ -175,7 +177,19 @@ class Event { $args['eid'] = $this->{'Id'}; $args['view'] = 'view_video'; } else { - $streamSrc = ZM_BASE_URL.ZM_PATH_ZMS; + $streamSrc = ZM_BASE_PROTOCOL.'://'; + if ( $this->Storage()->ServerId() ) { + $Server = $this->Storage()->Server(); + $streamSrc .= $Server->Hostname(); + if ( ZM_MIN_STREAMING_PORT ) { + $streamSrc .= ':'.(ZM_MIN_STREAMING_PORT+$this->{'MonitorId'}); + } + } else if ( ZM_MIN_STREAMING_PORT ) { + $streamSrc .= $_SERVER['SERVER_NAME'].':'.(ZM_MIN_STREAMING_PORT+$this->{'MonitorId'}); + } else { + $streamSrc .= $_SERVER['HTTP_HOST']; + } + $streamSrc .= ZM_PATH_ZMS; $args['source'] = 'event'; $args['event'] = $this->{'Id'}; @@ -256,7 +270,7 @@ class Event { // frame is an array representing the db row for a frame. function getImageSrc($frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false) { - $Storage = new Storage(isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL); + $Storage = $this->Storage(); $Event = $this; $eventPath = $Event->Path(); From 92c8b9038c4f858c1b4dbe0abef270b59cb1f3be Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 12:36:35 -0400 Subject: [PATCH 017/154] fix to group caching and group deleting --- web/includes/Group.php | 111 ++++++++++++----------------------------- 1 file changed, 31 insertions(+), 80 deletions(-) diff --git a/web/includes/Group.php b/web/includes/Group.php index be2a90f54..02314cc99 100644 --- a/web/includes/Group.php +++ b/web/includes/Group.php @@ -20,7 +20,7 @@ class Group { if ( ! $row ) { Error('Unable to load Group record for Id=' . $IdOrRow); } - } elseif ( is_array( $IdOrRow ) ) { + } elseif ( is_array($IdOrRow) ) { $row = $IdOrRow; } else { $backTrace = debug_backtrace(); @@ -36,8 +36,8 @@ class Group { foreach ($row as $k => $v) { $this->{$k} = $v; } + $group_cache[$row['Id']] = $this; } - $group_cache[$row['Id']] = $this; } // end function __construct public function __call($fn, array $args) { @@ -58,7 +58,7 @@ class Group { } } - public static function find_one( $parameters = null, $options = null ) { + public static function find_one($parameters = null, $options = null) { global $group_cache; if ( ( count($parameters) == 1 ) and @@ -109,13 +109,13 @@ class Group { } public function delete() { - if ( array_key_exists( 'Id', $this ) ) { - dbQuery( 'DELETE FROM Groups WHERE Id=?', array($this->{'Id'}) ); + if ( array_key_exists('Id', $this) ) { dbQuery( 'DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}) ); + dbQuery( 'DELETE FROM Groups WHERE Id=?', array($this->{'Id'}) ); if ( isset($_COOKIE['zmGroup']) ) { if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) { - unset( $_COOKIE['zmGroup'] ); - setcookie( 'zmGroup', '', time()-3600*24*2 ); + unset($_COOKIE['zmGroup']); + setcookie('zmGroup', '', time()-3600*24*2); } } } @@ -123,16 +123,16 @@ class Group { public function set( $data ) { foreach ($data as $k => $v) { - if ( is_array( $v ) ) { + if ( is_array($v) ) { $this->{$k} = $v; - } else if ( is_string( $v ) ) { + } else if ( is_string($v) ) { $this->{$k} = trim( $v ); - } else if ( is_integer( $v ) ) { + } else if ( is_integer($v) ) { $this->{$k} = $v; - } else if ( is_bool( $v ) ) { + } else if ( is_bool($v) ) { $this->{$k} = $v; } else { - Error( "Unknown type $k => $v of var " . gettype( $v ) ); + Error("Unknown type $k => $v of var " . gettype($v)); $this->{$k} = $v; } } @@ -141,10 +141,10 @@ class Group { if ( isset($new) ) { $this->{'depth'} = $new; } - if ( ! array_key_exists( 'depth', $this ) or ( $this->{'depth'} == null ) ) { + if ( ! array_key_exists('depth', $this) or ($this->{'depth'} == null) ) { $this->{'depth'} = 1; if ( $this->{'ParentId'} != null ) { - $Parent = new Group( $this->{'ParentId'} ); + $Parent = Group::find_one(array('Id'=>$this->{'ParentId'})); $this->{'depth'} += $Parent->depth(); } } @@ -152,8 +152,8 @@ class Group { } // end public function depth public function MonitorIds( ) { - if ( ! array_key_exists( 'MonitorIds', $this ) ) { - $this->{'MonitorIds'} = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}) ); + if ( ! array_key_exists('MonitorIds', $this) ) { + $this->{'MonitorIds'} = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'})); } return $this->{'MonitorIds'}; } @@ -198,12 +198,12 @@ class Group { } } - function get_options( $Group ) { + function get_options($Group) { global $children; - $options = array( $Group->Id() => str_repeat('   ', $Group->depth() ) . $Group->Name() ); + $options = array($Group->Id() => str_repeat('   ', $Group->depth()) . $Group->Name()); if ( isset($children[$Group->Id()]) ) { foreach ( $children[$Group->Id()] as $child ) { - $options += get_options( $child ); + $options += get_options($child); } } return $options; @@ -217,77 +217,28 @@ class Group { return $group_options; } - public static function get_group_dropdowns( $selected = null ) { - # This will end up with the group_id of the deepest selection - $group_id = 0; - $depth = 0; - $groups = array(); - $parent_group_ids = null; - session_start(); - - $group_options = array(0=>'All'); - while(1) { - $Groups = Group::find_all( array('ParentId'=>$parent_group_ids) ); - if ( ! count( $Groups ) ) - break; - - $parent_group_ids = array(); -if ( ! $selected ) { - $selected_group_id = 0; - if ( isset($_REQUEST['group'.$depth]) ) { - $selected_group_id = $group_id = $_SESSION['group'.$depth] = $_REQUEST['group'.$depth]; - } else if ( isset( $_SESSION['group'.$depth] ) ) { - $selected_group_id = $group_id = $_SESSION['group'.$depth]; - } else if ( isset($_REQUEST['filtering']) ) { - unset($_SESSION['group'.$depth]); - } -} else { - $selected_group_id = $selected; -} - - foreach ( $Groups as $Group ) { - if ( ! isset( $groups[$depth] ) ) { - $groups[$depth] = array(0=>'All'); - } -$group_options[$Group->Id()] = str_repeat( ' ', $depth ) . $Group->Name(); - $groups[$depth][$Group->Id()] = $Group->Name(); - if ( $selected_group_id and ( $selected_group_id == $Group->Id() ) ) - $parent_group_ids[] = $Group->Id(); - } - - //echo htmlSelect( 'group'.$depth, $groups[$depth], $selected_group_id, "this.form.submit();" ); - if ( ! count($parent_group_ids) ) break; - $depth += 1; - } - echo htmlSelect( 'groups', $group_options, $selected_group_id, 'this.form.submit();' ); - session_write_close(); - - return $group_id; - } # end public static function get_group_dropdowns() - - - public static function get_group_sql( $group_id ) { + public static function get_group_sql($group_id) { $groupSql = ''; if ( $group_id ) { - if ( is_array( $group_id ) ) { + if ( is_array($group_id) ) { $group_id_sql_part = ' IN ('.implode(',', array_map(function(){return '?';}, $group_id ) ).')'; - $MonitorIds = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId'.$group_id_sql_part, 'MonitorId', $group_id ); + $MonitorIds = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId'.$group_id_sql_part, 'MonitorId', $group_id); - $MonitorIds = array_merge( $MonitorIds, dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId'.$group_id_sql_part.')', 'MonitorId', $group_id ) ); + $MonitorIds = array_merge($MonitorIds, dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId'.$group_id_sql_part.')', 'MonitorId', $group_id)); } else { - $MonitorIds = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($group_id) ); + $MonitorIds = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($group_id)); - $MonitorIds = array_merge( $MonitorIds, dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId = ?)', 'MonitorId', array($group_id) ) ); + $MonitorIds = array_merge($MonitorIds, dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId = ?)', 'MonitorId', array($group_id))); } - $groupSql = " find_in_set( M.Id, '".implode( ',', $MonitorIds )."' )"; + $groupSql = " find_in_set( M.Id, '".implode(',', $MonitorIds)."' )"; } return $groupSql; } # end public static function get_group_sql( $group_id ) - public static function get_monitors_dropdown( $options = null ) { + public static function get_monitors_dropdown($options = null) { $monitor_id = 0; - if ( isset( $_REQUEST['monitor_id'] ) ) { + if ( isset($_REQUEST['monitor_id']) ) { $monitor_id = $_REQUEST['monitor_id']; } else if ( isset($_COOKIE['zmMonitorId']) ) { $monitor_id = $_COOKIE['zmMonitorId']; @@ -300,14 +251,14 @@ $group_options[$Group->Id()] = str_repeat( ' ', $depth ) . $Group->Name(); } $monitors_dropdown = array(''=>'All'); - foreach ( dbFetchAll( $sql ) as $monitor ) { - if ( !visibleMonitor( $monitor['Id'] ) ) { + foreach ( dbFetchAll($sql) as $monitor ) { + if ( !visibleMonitor($monitor['Id']) ) { continue; } $monitors_dropdown[$monitor['Id']] = $monitor['Name']; } - echo htmlSelect( 'monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') ); + echo htmlSelect('monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);')); return $monitor_id; } From c043a157ad1e6ce76caa57f1644c189c63d71b35 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 12:37:30 -0400 Subject: [PATCH 018/154] spacing and add Server function --- web/includes/Storage.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index ef00348d8..ab6f533f8 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -97,7 +97,7 @@ class Storage { $fields[] = $field.' IS NULL'; } else if ( is_array( $value ) ) { $func = function(){return '?';}; - $fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')'; + $fields[] = $field.' IN ('.implode(',', array_map($func, $value)). ')'; $values += $value; } else { @@ -105,10 +105,10 @@ class Storage { $values[] = $value; } } - $sql .= implode(' AND ', $fields ); + $sql .= implode(' AND ', $fields); } if ( $options and isset($options['order']) ) { - $sql .= ' ORDER BY ' . $options['order']; + $sql .= ' ORDER BY ' . $options['order']; } $result = dbQuery($sql, $values); if ( $result ) { @@ -165,5 +165,11 @@ class Storage { return $this->{'DiskSpace'}; } + public function Server() { + if ( ! array_key_exists('Server',$this) ) { + $this->{'Server'}= new Server( $this->{'ServerId'} ); + } + return $this->{'Server'}; + } } ?> From fd1c69d48a06b2be3c9411a64af2210bad3cae42 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 13:51:20 -0400 Subject: [PATCH 019/154] switch to uint64_t for event_id because long long can actually be 128 bit --- src/zm_event.h | 4 ++-- src/zm_eventstream.cpp | 34 +++++++++++++++++----------------- src/zm_eventstream.h | 8 ++++---- src/zm_monitor.cpp | 22 +++++++++++----------- src/zm_monitor.h | 4 ++-- src/zmu.cpp | 6 +++--- web/api/app/Plugin/Crud | 2 +- web/includes/Monitor.php | 1 + 8 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/zm_event.h b/src/zm_event.h index 69d4dc46b..1e55ae593 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -73,7 +73,7 @@ class Event { static int pre_alarm_count; static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES]; - unsigned long long int id; + uint64_t id; Monitor *monitor; struct timeval start_time; struct timeval end_time; @@ -103,7 +103,7 @@ class Event { Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false ); ~Event(); - unsigned long long int Id() const { return id; } + uint64_t Id() const { return id; } const std::string &Cause() { return cause; } int Frames() const { return frames; } int AlarmFrames() const { return alarm_frames; } diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 9f91336aa..989d2b14d 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -62,7 +62,7 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) { exit( mysql_errno(&dbconn)); } - unsigned long long init_event_id = atoll(dbrow[0]); + uint64_t init_event_id = atoll(dbrow[0]); mysql_free_result(result); @@ -87,7 +87,7 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) { return true; } -bool EventStream::loadInitialEventData( unsigned long long init_event_id, unsigned int init_frame_id ) { +bool EventStream::loadInitialEventData( uint64_t init_event_id, unsigned int init_frame_id ) { loadEventData(init_event_id); if ( init_frame_id ) { @@ -105,10 +105,10 @@ bool EventStream::loadInitialEventData( unsigned long long init_event_id, unsign return true; } -bool EventStream::loadEventData(unsigned long long event_id) { +bool EventStream::loadEventData(uint64_t event_id) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %llu", event_id); + snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %" PRIu64, event_id); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); @@ -167,26 +167,26 @@ bool EventStream::loadEventData(unsigned long long event_id) { } else if ( event_data->scheme == Storage::MEDIUM ) { struct tm *event_time = localtime( &event_data->start_time ); if ( storage_path[0] == '/' ) - snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%llu", + snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%" PRIu64, storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id ); else - snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%llu", + snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%" PRIu64, staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id ); } else { if ( storage_path[0] == '/' ) - snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%llu", + snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%" PRIu64, storage_path, event_data->monitor_id, event_data->event_id ); else - snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%llu", + snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%" PRIu64, staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id ); } delete storage; storage = NULL; updateFrameRate( (double)event_data->frame_count/event_data->duration ); - snprintf(sql, sizeof(sql), "SELECT FrameId, unix_timestamp( `TimeStamp` ), Delta FROM Frames where EventId = %llu ORDER BY FrameId ASC", event_id); + snprintf(sql, sizeof(sql), "SELECT FrameId, unix_timestamp( `TimeStamp` ), Delta FROM Frames where EventId = %" PRIu64 " ORDER BY FrameId ASC", event_id); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); exit(mysql_errno(&dbconn)); @@ -254,7 +254,7 @@ bool EventStream::loadEventData(unsigned long long event_id) { else curr_stream_time = event_data->frames[event_data->frame_count-1].timestamp; } - Debug(2, "Event:%llu, Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration); + Debug(2, "Event:%" PRIu64 ", Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration); return true; } // bool EventStream::loadEventData( int event_id ) @@ -450,7 +450,7 @@ void EventStream::processCommand(const CmdMsg *msg) { break; } struct { - unsigned long long event_id; + uint64_t event_id; int progress; int rate; int zoom; @@ -462,7 +462,7 @@ void EventStream::processCommand(const CmdMsg *msg) { status_data.rate = replay_rate; status_data.zoom = zoom; status_data.paused = paused; - Debug( 2, "Event:%llu, Paused:%d, progress:%d Rate:%d, Zoom:%d", + Debug( 2, "Event:%" PRIu64 ", Paused:%d, progress:%d Rate:%d, Zoom:%d", status_data.event_id, status_data.paused, status_data.progress, @@ -492,10 +492,10 @@ void EventStream::checkEventLoaded() { static char sql[ZM_SQL_SML_BUFSIZ]; if ( curr_frame_id <= 0 ) { - snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id < %llu ORDER BY Id DESC LIMIT 1", event_data->monitor_id, event_data->event_id ); + snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id < %" PRIu64 " ORDER BY Id DESC LIMIT 1", event_data->monitor_id, event_data->event_id ); reload_event = true; } else if ( (unsigned int)curr_frame_id > event_data->frame_count ) { - snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id > %llu ORDER BY Id ASC LIMIT 1", event_data->monitor_id, event_data->event_id ); + snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id > %" PRIu64 " ORDER BY Id ASC LIMIT 1", event_data->monitor_id, event_data->event_id ); reload_event = true; } @@ -520,8 +520,8 @@ void EventStream::checkEventLoaded() { } if ( dbrow ) { - unsigned long long event_id = atoll(dbrow[0]); - Debug( 1, "Loading new event %llu", event_id ); + uint64_t event_id = atoll(dbrow[0]); + Debug( 1, "Loading new event %" PRIu64, event_id ); loadEventData(event_id); @@ -846,7 +846,7 @@ void EventStream::runStream() { closeComms(); } -void EventStream::setStreamStart( unsigned long long init_event_id, unsigned int init_frame_id=0 ) { +void EventStream::setStreamStart( uint64_t init_event_id, unsigned int init_frame_id=0 ) { loadInitialEventData( init_event_id, init_frame_id ); if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) { Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id ); diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index 37feafafe..067661937 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -54,7 +54,7 @@ class EventStream : public StreamBase { }; struct EventData { - unsigned long long event_id; + uint64_t event_id; unsigned long monitor_id; unsigned long storage_id; unsigned long frame_count; @@ -83,8 +83,8 @@ class EventStream : public StreamBase { FFmpeg_Input *ffmpeg_input; protected: - bool loadEventData( unsigned long long event_id ); - bool loadInitialEventData( unsigned long long init_event_id, unsigned int init_frame_id ); + bool loadEventData( uint64_t event_id ); + bool loadInitialEventData( uint64_t init_event_id, unsigned int init_frame_id ); bool loadInitialEventData( int monitor_id, time_t event_time ); void checkEventLoaded(); @@ -110,7 +110,7 @@ class EventStream : public StreamBase { ffmpeg_input = NULL; } - void setStreamStart( unsigned long long init_event_id, unsigned int init_frame_id ); + void setStreamStart( uint64_t init_event_id, unsigned int init_frame_id ); void setStreamStart( int monitor_id, time_t event_time ); void setStreamMode( StreamMode p_mode ) { mode = p_mode; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 54d5477f8..d410b1399 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -634,7 +634,7 @@ Monitor::~Monitor() { } if ( mem_ptr ) { if ( event ) { - Info( "%s: image_count:%d - Closing event %llu, shutting down", name, image_count, event->Id() ); + Info( "%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name, image_count, event->Id() ); closeEvent(); // closeEvent may start another thread to close the event, so wait for it to finish @@ -809,7 +809,7 @@ unsigned int Monitor::GetLastWriteIndex() const { } uint64_t Monitor::GetLastEventId() const { - Debug(2, "mem_ptr(%x), State(%d) last_read_index(%d) last_read_time(%d) last_event(%llu)", + Debug(2, "mem_ptr(%x), State(%d) last_read_index(%d) last_read_time(%d) last_event(%" PRIu64 ")", mem_ptr, shared_data->state, shared_data->last_read_index, @@ -1092,7 +1092,7 @@ void Monitor::DumpZoneImage( const char *zone_string ) { if ( eventid_row.fetch(sql.c_str()) ) { uint64_t event_id = atoll(eventid_row[0]); - Debug(3, "Got event %llu", event_id); + Debug(3, "Got event %" PRIu64, event_id); EventStream *stream = new EventStream(); stream->setStreamStart(event_id, (unsigned int)1); zone_image = stream->getImage(); @@ -1369,7 +1369,7 @@ bool Monitor::Analyse() { } Warning( "%s: %s", SIGNAL_CAUSE, signalText ); if ( event && !signal ) { - Info( "%s: %03d - Closing event %llu, signal loss", name, image_count, event->Id() ); + Info( "%s: %03d - Closing event %" PRIu64 ", signal loss", name, image_count, event->Id() ); closeEvent(); last_section_mod = 0; } @@ -1454,7 +1454,7 @@ bool Monitor::Analyse() { //shared_data->state = state = IDLE; //Info( "%s: %03d - Closing event %d, section end", name, image_count, event->Id() ) //} else { - Info( "%s: %03d - Closing event %llu, section end forced ", name, image_count, event->Id() ); + Info( "%s: %03d - Closing event %" PRIu64 ", section end forced ", name, image_count, event->Id() ); //} closeEvent(); last_section_mod = 0; @@ -1476,7 +1476,7 @@ bool Monitor::Analyse() { snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); video_store_data->recording = event->StartTime(); - Info( "%s: %03d - Opening new event %llu, section start", name, image_count, event->Id() ); + Info( "%s: %03d - Opening new event %" PRIu64 ", section start", name, image_count, event->Id() ); /* To prevent cancelling out an existing alert\prealarm\alarm state */ if ( state == IDLE ) { @@ -1592,7 +1592,7 @@ bool Monitor::Analyse() { snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); video_store_data->recording = event->StartTime(); - Info( "%s: %03d - Opening new event %llu, alarm start", name, image_count, event->Id() ); + Info( "%s: %03d - Opening new event %" PRIu64 ", alarm start", name, image_count, event->Id() ); if ( pre_event_images ) { if ( analysis_fps ) { @@ -1630,11 +1630,11 @@ bool Monitor::Analyse() { shared_data->state = state = ALERT; } else if ( state == ALERT ) { if ( image_count-last_alarm_count > post_event_count ) { - Info( "%s: %03d - Left alarm state (%llu) - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); + Info( "%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) { shared_data->state = state = IDLE; - Info( "%s: %03d - Closing event %llu, alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); + Info( "%s: %03d - Closing event %" PRIu64 ", alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); closeEvent(); } else { shared_data->state = state = TAPE; @@ -1716,7 +1716,7 @@ bool Monitor::Analyse() { } } else { if ( event ) { - Info( "%s: %03d - Closing event %llu, trigger off", name, image_count, event->Id() ); + Info( "%s: %03d - Closing event %" PRIu64 ", trigger off", name, image_count, event->Id() ); closeEvent(); } shared_data->state = state = IDLE; @@ -1753,7 +1753,7 @@ void Monitor::Reload() { Debug( 1, "Reloading monitor %s", name ); if ( event ) { - Info( "%s: %03d - Closing event %llu, reloading", name, image_count, event->Id() ); + Info( "%s: %03d - Closing event %" PRIu64 ", reloading", name, image_count, event->Id() ); closeEvent(); } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 91fa9bdcb..c91622f41 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -174,7 +174,7 @@ protected: //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit typedef struct { uint32_t size; - uint64_t current_event; + unsigned long long current_event; char event_file[4096]; timeval recording; // used as both bool and a pointer to the timestamp when recording should begin //uint32_t frameNumber; @@ -447,7 +447,7 @@ public: VideoWriter GetOptVideoWriter() const { return videowriter; } const std::vector* GetOptEncoderParams() const { return &encoderparamsvec; } uint64_t GetVideoWriterEventId() const { return video_store_data->current_event; } - void SetVideoWriterEventId( uint64_t p_event_id ) { video_store_data->current_event = p_event_id; } + void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; } unsigned int GetPreEventCount() const { return pre_event_count; }; State GetState() const; diff --git a/src/zmu.cpp b/src/zmu.cpp index 4c94d0b51..640b9a342 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -514,10 +514,10 @@ int main( int argc, char *argv[] ) { } if ( function & ZMU_EVENT ) { if ( verbose ) - printf( "Last event id: %d\n", monitor->GetLastEventId() ); + printf( "Last event id: %" PRIu64 "\n", monitor->GetLastEventId() ); else { if ( have_output ) printf( "%c", separator ); - printf( "%d", monitor->GetLastEventId() ); + printf( "%" PRIu64, monitor->GetLastEventId() ); have_output = true; } } @@ -704,7 +704,7 @@ int main( int argc, char *argv[] ) { Monitor *monitor = Monitor::Load( mon_id, false, Monitor::QUERY ); if ( monitor && monitor->connect() ) { struct timeval tv = monitor->GetTimestamp(); - printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8d%8.2f\n", + printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8" PRIu64 "%8.2f\n", monitor->Id(), function, monitor->GetState(), diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index c3976f147..1351dde6b 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5 +Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 5631c845f..74cb3f528 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -168,6 +168,7 @@ private $control_fields = array( } } # end if isset($IdOrRow) } // end function __construct + public function Server() { return new Server( $this->{'ServerId'} ); } From e56cf0b31c0b4c863d930a8605356b5a78e18640 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 13:57:19 -0400 Subject: [PATCH 020/154] switch to uint64_t for event_id because long long can actually be 128 bit --- src/zm_event.cpp | 22 +++++++++++----------- src/zms.cpp | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index e23c37382..927399670 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -147,7 +147,7 @@ Event::Event( time_path_ptr += snprintf( time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i] ); } // Create event id symlink - snprintf( id_file, sizeof(id_file), "%s/.%llu", date_path, id ); + snprintf( id_file, sizeof(id_file), "%s/.%" PRIu64, date_path, id ); if ( symlink( time_path, id_file ) < 0 ) Error( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno)); } else if ( storage->Scheme() == Storage::MEDIUM ) { @@ -160,14 +160,14 @@ Event::Event( if ( errno != EEXIST ) Error( "Can't mkdir %s: %s", path, strerror(errno)); } - path_ptr += snprintf( path_ptr, sizeof(path), "/%llu", id ); + path_ptr += snprintf( path_ptr, sizeof(path), "/%" PRIu64, id ); if ( mkdir( path, 0755 ) ) { // FIXME This should not be fatal. Should probably move to a different storage area. if ( errno != EEXIST ) Error( "Can't mkdir %s: %s", path, strerror(errno)); } } else { - snprintf( path, sizeof(path), "%s/%d/%llu", storage->Path(), monitor->Id(), id ); + snprintf( path, sizeof(path), "%s/%d/%" PRIu64, storage->Path(), monitor->Id(), id ); if ( mkdir( path, 0755 ) ) { if ( errno != EEXIST ) { Error( "Can't mkdir %s: %s", path, strerror(errno)); @@ -175,7 +175,7 @@ Event::Event( } // Create empty id tag file - snprintf( id_file, sizeof(id_file), "%s/.%llu", path, id ); + snprintf( id_file, sizeof(id_file), "%s/.%" PRIu64, path, id ); if ( FILE *id_fp = fopen( id_file, "w" ) ) fclose( id_fp ); else @@ -189,7 +189,7 @@ Event::Event( /* Save as video */ if ( monitor->GetOptVideoWriter() != 0 ) { - snprintf( video_name, sizeof(video_name), "%llu-%s", id, "video.mp4" ); + snprintf( video_name, sizeof(video_name), "%" PRIu64 "-%s", id, "video.mp4" ); snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name ); Debug(1,"Writing video file to %s", video_file ); @@ -241,7 +241,7 @@ Event::~Event() { if ( frames > last_db_frame ) { Debug(1, "Adding closing frame %d to DB", frames); snprintf(sql, sizeof(sql), - "INSERT INTO Frames ( EventId, FrameId, TimeStamp, Delta ) VALUES ( %llu, %d, from_unixtime( %ld ), %s%ld.%02ld )", + "INSERT INTO Frames ( EventId, FrameId, TimeStamp, Delta ) VALUES ( %" PRIu64 ", %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec); db_mutex.lock(); if ( mysql_query(&dbconn, sql) ) { @@ -253,7 +253,7 @@ Event::~Event() { } snprintf(sql, sizeof(sql), - "UPDATE Events SET Name='%s %llu', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %llu", + "UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64, monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); db_mutex.lock(); while ( mysql_query(&dbconn, sql) ) { @@ -423,7 +423,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) { mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() ); - snprintf( sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %llu", escapedNotes, id ); + snprintf( sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %" PRIu64, escapedNotes, id ); db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't insert event: %s", mysql_error( &dbconn ) ); @@ -481,7 +481,7 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st } int sql_len = strlen(sql); - snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %llu, %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); + snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); frameCount++; } @@ -542,7 +542,7 @@ Debug(3, "Writing video"); Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type] ); static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf(sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %llu, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score); + snprintf(sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score); db_mutex.lock(); if ( mysql_query(&dbconn, sql) ) { Error("Can't insert frame: %s", mysql_error(&dbconn)); @@ -556,7 +556,7 @@ Debug(3, "Writing video"); // We are writing a Bulk frame if ( frame_type == BULK ) { snprintf( sql, sizeof(sql), - "UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %llu", + "UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %" PRIu64, ( delta_time.positive?"":"-" ), delta_time.sec, delta_time.fsec, frames, diff --git a/src/zms.cpp b/src/zms.cpp index aee752e25..63cbfff5f 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -58,7 +58,7 @@ int main( int argc, const char *argv[] ) { char format[32] = ""; int monitor_id = 0; time_t event_time = 0; - unsigned long long event_id = 0; + uint64_t event_id = 0; unsigned int frame_id = 1; unsigned int scale = 100; unsigned int rate = 100; @@ -174,7 +174,7 @@ int main( int argc, const char *argv[] ) { if ( monitor_id ) { snprintf(log_id_string, sizeof(log_id_string), "zms_m%d", monitor_id); } else { - snprintf(log_id_string, sizeof(log_id_string), "zms_e%llu", event_id); + snprintf(log_id_string, sizeof(log_id_string), "zms_e%" PRIu64, event_id); } logInit( log_id_string ); From 08447de7ca4c94f2a15d09340f7fe4cc27e32bae Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 17 Apr 2018 14:53:55 -0500 Subject: [PATCH 021/154] bump rpm specfile version --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 0226d777f..b3e1e89e8 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -33,7 +33,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.31.1 +Version: 1.31.41 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons From 3a80c60d2e8283c09be147ec6aed66314e366f9a Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Tue, 17 Apr 2018 15:13:38 -0500 Subject: [PATCH 022/154] rpm spefile changes - account for new files --- distros/redhat/zoneminder.spec | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index b3e1e89e8..15d586846 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -82,6 +82,7 @@ BuildRequires: vlc-devel BuildRequires: libcurl-devel BuildRequires: libv4l-devel BuildRequires: ffmpeg-devel +BuildRequires: desktop-file-utils # Required for mp4 container support BuildRequires: libmp4v2-devel @@ -167,6 +168,12 @@ too much degradation of performance. %install %make_install +desktop-file-install \ + --dir %{buildroot}%{_datadir}/applications \ + --delete-original \ + --mode 644 \ + %{buildroot}%{_datadir}/applications/zoneminder.desktop + # Remove unwanted files and folders find %{buildroot} \( -name .htaccess -or -name .editorconfig -or -name .packlist -or -name .git -or -name .gitignore -or -name .gitattributes -or -name .travis.yml \) -type f -delete > /dev/null 2>&1 || : @@ -341,6 +348,7 @@ rm -rf %{_docdir}/%{name}-%{version} %{_bindir}/zmtelemetry.pl %{_bindir}/zmx10.pl %{_bindir}/zmonvif-probe.pl +%{_bindir}/zmstats.pl %{perl_vendorlib}/ZoneMinder* %{perl_vendorlib}/ONVIF* @@ -351,6 +359,7 @@ rm -rf %{_docdir}/%{name}-%{version} %{_libexecdir}/zoneminder/ %{_datadir}/zoneminder/ +%{_datadir}/applications/*%{name}.desktop %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/events From 17fbb4902580fd6b079400ab7edc11c63ff89f4e Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 17 Apr 2018 15:50:30 -0500 Subject: [PATCH 023/154] cannot assign categories when type=link RPM packaging calls the freedesktop tool "desktop-file-install", which fails with: ``` error: key "Categories" is present in group "Desktop Entry", but the type is "Link" while this key is only valid for type "Application" ``` @connortechnology This fails the build so I'm removing the categories. Let me know if you've got any other ideas. --- misc/zoneminder.desktop.in | 1 - 1 file changed, 1 deletion(-) diff --git a/misc/zoneminder.desktop.in b/misc/zoneminder.desktop.in index fd7f247d8..675dc62c5 100755 --- a/misc/zoneminder.desktop.in +++ b/misc/zoneminder.desktop.in @@ -5,4 +5,3 @@ Name=ZoneMinder Comment= Icon=@PKGDATADIR@/icons/16x16/icon.xpm URL=http://localhost/zm/\r -Categories=GNOME;AudioVideo;Video;Recorder; From 10a191ae5bdedd98b98c2e098abab024b256e55e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 14:14:40 -0700 Subject: [PATCH 024/154] add event_disk_space to storage to differentiate between real used space versus event used disk space. Use this in the navbar to show actual disk use and also event disk use --- web/includes/Storage.php | 33 +++++++++++-------- web/skins/classic/css/base/skin.css | 4 +-- web/skins/classic/includes/functions.php | 12 ++++++- .../classic/views/report_event_audit.php | 6 ++-- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index ef00348d8..e524a9084 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -140,30 +140,37 @@ class Storage { return $usage; } public function disk_total_space() { - if ( ! array_key_exists( 'disk_total_space', $this ) ) { - $this->{'disk_total_space'} = disk_total_space( $this->Path() ); + if ( ! array_key_exists('disk_total_space', $this) ) { + $this->{'disk_total_space'} = disk_total_space($this->Path()); } return $this->{'disk_total_space'}; } + public function disk_used_space() { # This isn't a function like this in php, so we have to add up the space used in each event. - if ( (! array_key_exists( 'DiskSpace', $this )) or (!$this->{'DiskSpace'}) ) { - $used = 0; + if ( (! array_key_exists('disk_used_space', $this)) or (!$this->{'disk_used_space'}) ) { if ( $this->{'Type'} == 's3fs' ) { - $used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) ); - - foreach ( Event::find_all( array( 'StorageId'=>$this->Id(), 'DiskSpace'=>null ) ) as $Event ) { - $Event->Storage( $this ); // Prevent further db hit - $used += $Event->DiskSpace(); - } + $this->{'disk_used_space'} = $this->disk_event_space(); } else { $path = $this->Path(); - $used = disk_total_space( $path ) - disk_free_space( $path );; + $this->{'disk_used_space'} = disk_total_space($path) - disk_free_space($path); + } + } + return $this->{'disk_used_space'}; + } // end function disk_used_space + + public function event_disk_space() { + # This isn't a function like this in php, so we have to add up the space used in each event. + if ( (! array_key_exists('DiskSpace', $this)) or (!$this->{'DiskSpace'}) ) { + $used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) ); + + foreach ( Event::find_all( array('StorageId'=>$this->Id(), 'DiskSpace'=>null) ) as $Event ) { + $Event->Storage( $this ); // Prevent further db hit + $used += $Event->DiskSpace(); } $this->{'DiskSpace'} = $used; } - return $this->{'DiskSpace'}; - } + } // end function event_disk_space } ?> diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index 0fda49d10..3fdd5a12f 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -341,11 +341,11 @@ fieldset > legend { /* * Behavior classes */ -.alarm, .errorText { +.alarm, .errorText, .error { color: #ff3f34; } -.alert, .warnText { +.alert, .warnText, .warning { color: #ffa801; } diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index f53b21d54..b814e9a13 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -340,7 +340,17 @@ if ($reload == 'reload') ob_start(); if ( ! isset($storage_paths[ZM_DIR_EVENTS]) ) { array_push( $storage_areas, new Storage() ); } - $func = function($S){ return ''.$S->Name() . ': ' . $S->disk_usage_percent().'%' . ''; }; + $func = function($S){ + $class = ''; + if ( $S->disk_usage_percent() > 98 ) { + $class = "error"; + } else if ( $S->disk_usage_percent() > 90 ) { + $class = "warning"; + } + $title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()). + ( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' ); + + return ''.$S->Name() . ': ' . $S->disk_usage_percent().'%' . ''; }; #$func = function($S){ return ''.$S->Name() . ': ' . $S->disk_usage_percent().'%' . ''; }; if ( count($storage_areas) >= 4 ) $storage_areas = Storage::find_all( array('ServerId'=>null) ); diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index 39f5178f0..e779d3bdf 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -149,11 +149,13 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) { for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $monitor = $displayMonitors[$monitor_i]; $Monitor = new Monitor($monitor); + + $montagereview_link = "?view=montagereview&live=0&MonitorId=". $monitor['Id'] . '&minTime='.$minTime.'&maxTime='.$maxTime; ?> - + + @@ -169,6 +172,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { + Date: Wed, 18 Apr 2018 14:17:41 -0700 Subject: [PATCH 046/154] fix array_key_exists --- web/includes/database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/database.php b/web/includes/database.php index b22f5b1b0..9ec113ff1 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -166,7 +166,7 @@ function dbFetchOne( $sql, $col=false, $params=NULL ) { if ( $result && $dbRow = $result->fetch(PDO::FETCH_ASSOC) ) { if ( $col ) { - if ( ! array_key_exists($col, $dbRow[$col]) ) { + if ( ! array_key_exists($col, $dbRow) ) { Warning("$col does not exist in the returned row " . print_r($dbRow, true)); } return $dbRow[$col]; From a5cbc8abd16b88cf1ef1f534ebb749b50eb01c87 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 18 Apr 2018 19:21:14 -0500 Subject: [PATCH 047/154] buildsystem - update git submodules --- utils/packpack/startpackpack.sh | 28 ++++++++++++++++++++++++---- web/api/app/Plugin/Crud | 2 +- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 3eb2ef20d..95f887320 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -123,14 +123,26 @@ commonprep () { patch -p1 < utils/packpack/setarch.patch fi - # The rpm specfile requires we download the tarball and manually move it into place + # The rpm specfile requires we download each submodule as a tarball then manually move it into place # Might as well do this for Debian as well, rather than git submodule init - CRUDVER="3.0.10" + CRUDVER="3.1.0-zm" if [ -e "build/crud-${CRUDVER}.tar.gz" ]; then echo "Found existing Crud ${CRUDVER} tarball..." else echo "Retrieving Crud ${CRUDVER} submodule..." - curl -L https://github.com/FriendsOfCake/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz + curl -L https://github.com/ZoneMinder/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz + if [ $? -ne 0 ]; then + echo "ERROR: Crud tarball retreival failed..." + exit 1 + fi + fi + + CEBVER="1.0-zm" + if [ -e "build/crud-${CEBVER}.tar.gz" ]; then + echo "Found existing CakePHP-Enum-Behavior ${CEBVER} tarball..." + else + echo "Retrieving CakePHP-Enum-Behavior ${CEBVER} submodule..." + curl -L https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/v${CEBVER}.tar.gz > build/crud-${CEBVER}.tar.gz if [ $? -ne 0 ]; then echo "ERROR: Crud tarball retreival failed..." exit 1 @@ -138,7 +150,7 @@ commonprep () { fi } -# Uncompress the Crud tarball and move it into place +# Uncompress the submodule tarballs and move them into place movecrud () { if [ -e "web/api/app/Plugin/Crud/LICENSE.txt" ]; then echo "Crud plugin already installed..." @@ -148,6 +160,14 @@ movecrud () { rmdir web/api/app/Plugin/Crud mv -f crud-${CRUDVER} web/api/app/Plugin/Crud fi + if [ -e "web/api/app/Plugin/CakePHP-Enum-Behavior/readme.md" ]; then + echo "CakePHP-Enum-Behavior plugin already installed..." + else + echo "Unpacking CakePHP-Enum-Behavior plugin..." + tar -xzf build/cakephp-enum-behavior-${CEBVER}.tar.gz + rmdir web/api/app/Plugin/CakePHP-Enum-Behavior + mv -f crud-${CEBVER} web/api/app/Plugin/CakePHP-Enum-Behavior + fi } # previsouly part of installzm.sh diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 0bd63fb46..1351dde6b 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef +Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 From cb7107ec4dd83742e16f2c51a74ea0a501db54c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 21:04:54 -0400 Subject: [PATCH 048/154] Fix insert for default Storage Group --- db/zm_create.sql.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 745420107..10f765232 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -713,7 +713,7 @@ CREATE TABLE `Storage` ( -- -- Create a default storage location -- -insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL, 'Medium', 0 ); +insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL, NULL, 'Medium', 0, true ); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; From b965eca683a0f06d48e337dc8a70324c3837c50c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 21:06:13 -0400 Subject: [PATCH 049/154] Use a build substr for the default path to events --- db/zm_create.sql.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 10f765232..06bdf0f85 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -713,7 +713,7 @@ CREATE TABLE `Storage` ( -- -- Create a default storage location -- -insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL, NULL, 'Medium', 0, true ); +insert into Storage VALUES (NULL, '@ZM_DIR_EVENTS@', 'Default', 'local', NULL, NULL, 'Medium', 0, true ); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; From 6dae6d894984d8c42965616ada6100f60345e40e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 21:29:35 -0400 Subject: [PATCH 050/154] fix doubled use --- scripts/zmdc.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index d229efe57..74208f4c6 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -155,8 +155,8 @@ my $server_up = connect( CLIENT, $saddr ); if ( ! $server_up ) { if ( $Config{ZM_SERVER_ID} ) { -use Sys::MemInfo qw(totalmem freemem totalswap freeswap); -use use ZoneMinder::Server qw(CpuLoad); + use Sys::MemInfo qw(totalmem freemem totalswap freeswap); + use ZoneMinder::Server qw(CpuLoad); if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, 'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr()); From c27aa5efea3f6f5fd781649b331b140e8811c675 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 21:44:37 -0400 Subject: [PATCH 051/154] Need to actually export CpuLoad --- scripts/ZoneMinder/lib/ZoneMinder/Server.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Server.pm b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm index eae64f96a..1d822f9af 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Server.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm @@ -42,6 +42,7 @@ our @ISA = qw(Exporter ZoneMinder::Base); # will save memory. our %EXPORT_TAGS = ( 'functions' => [ qw( + CpuLoad ) ] ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; From d01682f3adf220481f35444ec6801910da9badc3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 21:46:55 -0400 Subject: [PATCH 052/154] remove second use --- scripts/zmdc.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 74208f4c6..c358d3c4a 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -237,7 +237,7 @@ use Socket; use IO::Handle; use Time::HiRes qw(usleep); use Sys::MemInfo qw(totalmem freemem totalswap freeswap); -use use ZoneMinder::Server qw(CpuLoad); +use ZoneMinder::Server qw(CpuLoad); #use Data::Dumper; # We count 10 of these, so total timeout is this value *10. From edd4b1ec7ff129f702394a3bb61f8332260a9960 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 19 Apr 2018 07:24:05 -0500 Subject: [PATCH 053/154] fix a second case of perl double use --- scripts/zmdc.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 74208f4c6..c358d3c4a 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -237,7 +237,7 @@ use Socket; use IO::Handle; use Time::HiRes qw(usleep); use Sys::MemInfo qw(totalmem freemem totalswap freeswap); -use use ZoneMinder::Server qw(CpuLoad); +use ZoneMinder::Server qw(CpuLoad); #use Data::Dumper; # We count 10 of these, so total timeout is this value *10. From 98eb6570dd40afb1c6f07fe209d1d6b0da69b50d Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Thu, 19 Apr 2018 07:43:43 -0500 Subject: [PATCH 054/154] use make macros in zm_update-1.31.30.sql.in --- db/CMakeLists.txt | 5 +++++ db/{zm_update-1.31.30.sql => zm_update-1.31.30.sql.in} | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) rename db/{zm_update-1.31.30.sql => zm_update-1.31.30.sql.in} (86%) diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt index c68285e5b..c8aa7cad6 100644 --- a/db/CMakeLists.txt +++ b/db/CMakeLists.txt @@ -2,6 +2,7 @@ # Create files from the .in files configure_file(zm_create.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" @ONLY) +configure_file(zm_update-1.31.30.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" @ONLY) # Glob all database upgrade scripts file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql") @@ -9,8 +10,12 @@ file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql") # Install the database upgrade scripts install(FILES ${dbfileslist} DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") +# install zm_update-1.31.30.sql +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") + # install zm_create.sql install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") # install triggers.sql install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") + diff --git a/db/zm_update-1.31.30.sql b/db/zm_update-1.31.30.sql.in similarity index 86% rename from db/zm_update-1.31.30.sql rename to db/zm_update-1.31.30.sql.in index c87b4409a..b6746b55a 100644 --- a/db/zm_update-1.31.30.sql +++ b/db/zm_update-1.31.30.sql.in @@ -10,10 +10,10 @@ CREATE TABLE `Monitor_Status` ( SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO'; SET @s = (SELECT IF( - (SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='/var/cache/zoneminder/events' + (SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='@ZM_DIR_EVENTS@' ) > 0, "SELECT 'Default Storage Area already exists.'", - "INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','/var/cache/zoneminder/events','Medium',NULL)" + "INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','@ZM_DIR_EVENTS@','Medium',NULL)" )); PREPARE stmt FROM @s; From a05a1f396c69b456302e9e43608600ed625d6481 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 19 Apr 2018 08:20:38 -0500 Subject: [PATCH 055/154] fix copy/paste typo --- db/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt index c8aa7cad6..ed215d35f 100644 --- a/db/CMakeLists.txt +++ b/db/CMakeLists.txt @@ -11,7 +11,7 @@ file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql") install(FILES ${dbfileslist} DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") # install zm_update-1.31.30.sql -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") # install zm_create.sql install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") From eb21a5113e5b53529c1d3f3cc47633ac5e4a63b9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 09:34:14 -0400 Subject: [PATCH 056/154] Add a debug line in SignaCheck function --- src/zm_monitor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index d410b1399..20313de73 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1184,6 +1184,7 @@ bool Monitor::CheckSignal( const Image *image ) { int index = 0; for ( int i = 0; i < config.signal_check_points; i++ ) { while( true ) { + // Why the casting to long long? also note that on a 64bit cpu, long long is 128bits index = (int)(((long long)rand()*(long long)(pixels-1))/RAND_MAX); if ( !config.timestamp_on_capture || !label_format[0] ) break; @@ -1219,6 +1220,7 @@ bool Monitor::CheckSignal( const Image *image ) { } } } // end for < signal_check_points + Debug(1,"SignalCheck: %d points, colour_val(%d)", config.signal_check_points, colour_val); return false; } // end if signal_check_points return true; From cd70ed3decce146f2869954052602054df570b01 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 09:45:28 -0400 Subject: [PATCH 057/154] always show SignalCheckColour and add a SignalCheckPoints option --- web/skins/classic/views/monitor.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 53c46c2f4..c0532aa78 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -980,19 +980,19 @@ if ( $monitor->Type() == 'Local' ) { -Type() == 'Local' ) { -?> + + + + -
    -
    +
    ', array_map(function($group_id){ $Group = new Group($group_id); From 04cb1f9300482c6703af0292ac26c6d96c14db04 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 17 Apr 2018 20:09:41 -0500 Subject: [PATCH 025/154] use ZoneMinder::Server::CpuLoad rather than Sys:CpuLoad (#2080) --- scripts/ZoneMinder/lib/ZoneMinder/Server.pm | 11 +++++++++++ scripts/zmdc.pl.in | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Server.pm b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm index 9c68f5a51..eae64f96a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Server.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm @@ -107,6 +107,17 @@ sub Hostname { return $_[0]{Hostname}; } # end sub Hostname +sub CpuLoad { + my $output = qx(uptime); + my @sysloads = split ', ', (split ': ', $output)[-1]; + + if (join(', ',@sysloads) =~ /(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*$/) { + return @sysloads; + } + + return (undef, undef, undef); +} # end sub CpuLoad + 1; __END__ # Below is stub documentation for your module. You'd better edit it! diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 18ae27844..d229efe57 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -156,7 +156,7 @@ my $server_up = connect( CLIENT, $saddr ); if ( ! $server_up ) { if ( $Config{ZM_SERVER_ID} ) { use Sys::MemInfo qw(totalmem freemem totalswap freeswap); -use Sys::CpuLoad; +use use ZoneMinder::Server qw(CpuLoad); if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, 'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr()); @@ -237,7 +237,7 @@ use Socket; use IO::Handle; use Time::HiRes qw(usleep); use Sys::MemInfo qw(totalmem freemem totalswap freeswap); -use Sys::CpuLoad; +use use ZoneMinder::Server qw(CpuLoad); #use Data::Dumper; # We count 10 of these, so total timeout is this value *10. @@ -302,7 +302,7 @@ sub run { if ( $Config{ZM_SERVER_ID} ) { if ( ! ( $secs_count % 60 ) ) { $dbh = zmDbConnect() if ! $dbh->ping(); - my @cpuload = Sys::CpuLoad::load(); + my @cpuload = CpuLoad(); dPrint( ZoneMinder::Logger::DEBUG, 'Updating Server record' ); if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, 'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { From 48d5fa00d4a8b9a2963ddfcd113ad14c7e935878 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Apr 2018 21:10:55 -0400 Subject: [PATCH 026/154] remove libsys-cpuload-perl as a dependency --- distros/ubuntu1604/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/ubuntu1604/control b/distros/ubuntu1604/control index 2c7549b16..0b934b7d2 100644 --- a/distros/ubuntu1604/control +++ b/distros/ubuntu1604/control @@ -59,7 +59,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,libsoap-wsdl-perl ,libio-socket-multicast-perl ,libdigest-sha-perl - ,libsys-cpu-perl, libsys-cpuload-perl, libsys-meminfo-perl + ,libsys-cpu-perl, libsys-meminfo-perl ,libdata-uuid-perl ,libnumber-bytes-human-perl ,libfile-slurp-perl From 8bf502ee4fe816d3c91559cfcc5c20636818cb2e Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 17 Apr 2018 20:24:14 -0500 Subject: [PATCH 027/154] upgrade to cakephp 2.10.8 (#2067) * upgrade lib folder to cakephp 2.10.8 * recreate bootstrap.php.in * Bump Crud module 3.0.10 -> 3.1.0 * fix CrudBaseObject.php --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6f989f01..9de584fd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,12 @@ message( SEND_ERROR "The git submodules are not available. Please run git submodule update --init --recursive") endif( NOT EXISTS "${CMAKE_SOURCE_DIR}/web/api/app/Plugin/Crud/Lib/CrudControllerTrait.php" ) +# This is a hack that should be removed after Crud PR 582 is merged +# See issue 581 for more details: https://github.com/FriendsOfCake/crud/issues/581 +file(READ "${CMAKE_SOURCE_DIR}/web/api/app/Plugin/Crud/Controller/Crud/CrudBaseObject.php" CRUDBASEOBJECT) +string(REPLACE "CrudBaseObject extends Object" "CrudBaseObject extends CakeObject" NEWCRUDBASEOBJECT "${CRUDBASEOBJECT}") +file(WRITE "${CMAKE_SOURCE_DIR}/web/api/app/Plugin/Crud/Controller/Crud/CrudBaseObject.php" ${NEWCRUDBASEOBJECT}) + # CMake does not allow out-of-source build if CMakeCache.exists # in the source folder. Abort and notify the user if( From 456b1b59dfd5af1218aab986d67f54c760323ef0 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 17 Apr 2018 20:27:28 -0500 Subject: [PATCH 028/154] rpm specfile - bump crud to 3.1.0 --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 15d586846..0956d0f6b 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -2,7 +2,7 @@ %global zmgid_final apache # Crud is configured as a git submodule -%global crud_version 3.0.10 +%global crud_version 3.1.0 %if "%{zmuid_final}" == "nginx" %global with_nginx 1 From bfe82e297a7357d9e4dad33f5bed549e421f6be5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 09:26:36 -0400 Subject: [PATCH 029/154] Default an empty Storage to doing Deletes --- scripts/ZoneMinder/lib/ZoneMinder/Storage.pm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm b/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm index 8fbe5ed80..ceac60a17 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm @@ -113,6 +113,15 @@ sub Name { return $_[0]{Name}; } # end sub Path +sub DoDelete { + $self = shift; + $$self{DoDelete} = shift if @_; + if ( ! defined $$self{DoDelete} ) { + $$self{DoDelete} = 1; + } + return $$self{DoDelete}; +} + sub Server { my $self = shift; if ( ! $$self{Server} ) { From 1040afbda460b9e7b870ebdb080a1560c9219775 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 09:27:11 -0400 Subject: [PATCH 030/154] change message about not deleting files for speed --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index b401054a3..06b7adaab 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -397,7 +397,7 @@ sub delete { if ( (! $Config{ZM_OPT_FAST_DELETE}) and $event->Storage()->DoDelete() ) { $event->delete_files( ); } else { - Debug('Not deleting frames, stats and files for speed.'); + Debug('Not deleting event files for speed.'); } } # end sub delete From 12d46e2377ad4e282535f0e8621c71a63c520ef2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 09:52:57 -0400 Subject: [PATCH 031/154] change event_id in status_msg to 64bit when unpacking --- web/ajax/stream.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/stream.php b/web/ajax/stream.php index 00ed7719d..1c2fb3d62 100644 --- a/web/ajax/stream.php +++ b/web/ajax/stream.php @@ -145,7 +145,7 @@ if ( sem_acquire($semaphore,1) !== false ) { } case MSG_DATA_EVENT : { - $data = unpack( "ltype/ievent/iprogress/irate/izoom/Cpaused", $msg ); + $data = unpack( "ltype/Pevent/iprogress/irate/izoom/Cpaused", $msg ); //$data['progress'] = sprintf( "%.2f", $data['progress'] ); $data['rate'] /= RATE_BASE; $data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 ); From 00b7ae9006bc20e56f4988f3cc0defa9ca199445 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 10:07:50 -0400 Subject: [PATCH 032/154] put in missing my --- scripts/ZoneMinder/lib/ZoneMinder/Storage.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm b/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm index ceac60a17..b6924c4e9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm @@ -114,7 +114,7 @@ sub Name { } # end sub Path sub DoDelete { - $self = shift; + my $self = shift; $$self{DoDelete} = shift if @_; if ( ! defined $$self{DoDelete} ) { $$self{DoDelete} = 1; From e3afa5e309acd82206a73e5e0ea052f6fbb07ae6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 11:28:19 -0400 Subject: [PATCH 033/154] handle scale not being defined when using mpeg streaming --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 648ce20c3..64d6ce29b 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2132,7 +2132,7 @@ function getStreamHTML( $monitor, $options = array() ) { if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { $streamSrc = $monitor->getStreamSrc( array( 'mode'=>'mpeg', - 'scale'=>$options['scale'], + 'scale'=>(isset($options['scale'])?$options['scale']:100), 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format' => ZM_MPEG_LIVE_FORMAT From 940c791d4fde04e493f7f68de1b0835a7bbdff5f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 12:14:49 -0400 Subject: [PATCH 034/154] GroupIds won't be set if no groups are selected --- web/includes/actions.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index cc264d29f..423f63bcb 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -564,7 +564,14 @@ if ( canEdit( 'Monitors' ) ) { Error("Users with Monitors restrictions cannot create new monitors."); return; } - if ( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) or array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds() ) ) { + + if ( + ( !isset($_POST['newMonitor']['GroupIds']) ) + or + ( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) ) + or + array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds()) + ) { if ( $Monitor->Id() ) dbQuery('DELETE FROM Groups_Monitors WHERE MonitorId=?', array($mid)); From 36b8cfb1159765de65b1469345abeedda460afe8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 12:29:59 -0400 Subject: [PATCH 035/154] test element so that processing will continue if buton doesn't exist --- web/skins/classic/views/js/watch.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 430a9bdb3..d5860214a 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -1,6 +1,8 @@ -function setButtonState( element, butClass ) { - element.className = butClass; - element.disabled = (butClass != 'inactive'); +function setButtonState(element, butClass) { + if ( element ) { + element.className = butClass; + element.disabled = (butClass != 'inactive'); + } } function showEvents() { From 61249ccf2ae147b791af8b34df29241bad61f9e9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Apr 2018 12:30:18 -0400 Subject: [PATCH 036/154] Show pause/play/stop when no stream buffer --- web/skins/classic/views/watch.php | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index c7d8eb36b..92eec1cb6 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -54,7 +54,6 @@ if ( isset( $_REQUEST['scale'] ) ) { $connkey = generateConnKey(); $streamMode = getStreamMode(); -$showDvrControls = ( $streamMode == 'jpeg' && $monitor->StreamReplayBuffer() != 0 ); noCacheHeaders(); @@ -97,15 +96,31 @@ if ( canEdit( 'Monitors' ) ) { ?>
     -  fps
    -
    Id()])?$EventsByMonitor[$Monitor->Id()]['MinGap']:0 ?> Id()])?$EventsByMonitor[$Monitor->Id()]['MaxGap']:0 ?> Id()])?$EventsByMonitor[$Monitor->Id()]['FileMissing']:0 ?>Id()])?$EventsByMonitor[$Monitor->Id()]['ZeroSize']:0 ?>
    DefaultRate() ); ?>
    DefaultScale() ); ?>
    + +
    - +     
    From c7f672fabd33daa5b81bdc7ca1f7a8a58112d74e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 09:59:10 -0400 Subject: [PATCH 058/154] SIGNAL_CHECK_POINTS is now a per-monitor setting --- .../lib/ZoneMinder/ConfigData.pm.in | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index acd2464bf..addd6239b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -1723,26 +1723,6 @@ our @options = ( type => $types{abs_path}, category => 'config', }, - { - name => 'ZM_SIGNAL_CHECK_POINTS', - default => '10', - description => 'How many points in a captured image to check for signal loss', - help => q` - For locally attached video cameras ZoneMinder can check for - signal loss by looking at a number of random points on each - captured image. If all of these points are set to the same - fixed colour then the camera is assumed to have lost signal. - When this happens any open events are closed and a short one - frame signal loss event is generated, as is another when the - signal returns. This option defines how many points on each - image to check. Note that this is a maximum, any points found - to not have the check colour will abort any further checks so - in most cases on a couple of points will actually be checked. - Network and file based cameras are never checked. - `, - type => $types{integer}, - category => 'config', - }, { name => 'ZM_V4L_MULTI_BUFFER', default => 'yes', From 983cd8305487a355525882b55fbc6812ff0e07dd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 10:01:04 -0400 Subject: [PATCH 059/154] Add default for SignalCheckPoints and add it as a hidden field to the non-misc tabs --- web/skins/classic/views/monitor.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index c0532aa78..424748410 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -133,6 +133,7 @@ if ( ! $monitor ) { 'DefaultView' => 'Events', 'DefaultRate' => '100', 'DefaultScale' => '100', + 'SignalCheckPoints' => '10', 'SignalCheckColour' => '#0000c0', 'WebColour' => 'red', 'Exif' => '0', @@ -659,8 +660,9 @@ if ( $tab != 'misc' ) { Type()!= 'Local') ) { +if ( $tab != 'misc' ) { ?> + Date: Thu, 19 Apr 2018 10:09:32 -0400 Subject: [PATCH 060/154] Add SignalCheckPoints to Monitors --- db/zm_create.sql.in | 1 + db/zm_update-1.31.42.sql | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 db/zm_update-1.31.42.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 06bdf0f85..9c237b8a0 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -499,6 +499,7 @@ CREATE TABLE `Monitors` ( `DefaultView` enum('Events','Control') NOT NULL default 'Events', `DefaultRate` smallint(5) unsigned NOT NULL default '100', `DefaultScale` smallint(5) unsigned NOT NULL default '100', + `SignalCheckPoints` INT UNSIGNED NOT NULL default '0', `SignalCheckColour` varchar(32) NOT NULL default '#0000BE', `WebColour` varchar(32) NOT NULL default 'red', `Exif` tinyint(1) unsigned NOT NULL default '0', diff --git a/db/zm_update-1.31.42.sql b/db/zm_update-1.31.42.sql new file mode 100644 index 000000000..adb004baf --- /dev/null +++ b/db/zm_update-1.31.42.sql @@ -0,0 +1,12 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'SignalCheckPoints' + ) > 0, +"SELECT 'Column SignalCheckPoints already exists in Storage'", +"ALTER TABLE `Monitors` ADD `SignalCheckPoints` INT UNSIGNED NOT NULL default '0' AFTER `DefaultScale`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; From 56186a42ef88e6dc30d2dd81f04855be0c46c2e4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 10:10:14 -0400 Subject: [PATCH 061/154] change signal_check_points to a per-monitor variable instead of parts of config. Only call SignalCheck if signal_check_points is > 0 --- src/zm_monitor.cpp | 16 ++++++++++------ src/zm_monitor.h | 2 ++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 20313de73..601f9f424 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -77,7 +77,7 @@ std::string load_monitor_sql = "EventPrefix, LabelFormat, LabelX, LabelY, LabelSize," "ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, " "SectionLength, FrameSkip, MotionFrameSkip, " -"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckColour FROM Monitors"; +"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckPoints, SignalCheckColour FROM Monitors"; std::string CameraType_Strings[] = { "Local", @@ -304,6 +304,7 @@ Monitor::Monitor( int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, + int p_signal_check_points, Rgb p_signal_check_colour, bool p_embed_exif, Purpose p_purpose, @@ -341,6 +342,7 @@ Monitor::Monitor( ref_blend_perc( p_ref_blend_perc ), alarm_ref_blend_perc( p_alarm_ref_blend_perc ), track_motion( p_track_motion ), + signal_check_points(p_signal_check_points), signal_check_colour( p_signal_check_colour ), embed_exif( p_embed_exif ), delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ), @@ -1164,7 +1166,7 @@ bool Monitor::CheckSignal( const Image *image ) { static Rgb colour_val; /* RGB32 color */ static int usedsubpixorder; - if ( config.signal_check_points > 0 ) { + if ( signal_check_points > 0 ) { if ( static_undef ) { static_undef = false; usedsubpixorder = camera->SubpixelOrder(); @@ -1182,7 +1184,7 @@ bool Monitor::CheckSignal( const Image *image ) { int colours = image->Colours(); int index = 0; - for ( int i = 0; i < config.signal_check_points; i++ ) { + for ( int i = 0; i < signal_check_points; i++ ) { while( true ) { // Why the casting to long long? also note that on a 64bit cpu, long long is 128bits index = (int)(((long long)rand()*(long long)(pixels-1))/RAND_MAX); @@ -1220,7 +1222,7 @@ bool Monitor::CheckSignal( const Image *image ) { } } } // end for < signal_check_points - Debug(1,"SignalCheck: %d points, colour_val(%d)", config.signal_check_points, colour_val); + Debug(1,"SignalCheck: %d points, colour_val(%d)", signal_check_points, colour_val); return false; } // end if signal_check_points return true; @@ -1803,6 +1805,7 @@ void Monitor::Reload() { alarm_ref_blend_perc = atoi(dbrow[index++]); track_motion = atoi(dbrow[index++]); + signal_check_points = dbrow[index]?atoi(dbrow[index]):0;index++; if ( dbrow[index][0] == '#' ) signal_check_colour = strtol(dbrow[index]+1,0,16); @@ -2090,7 +2093,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { int ref_blend_perc = atoi(dbrow[col]); col++; int alarm_ref_blend_perc = atoi(dbrow[col]); col++; int track_motion = atoi(dbrow[col]); col++; - + int signal_check_points = dbrow[col] ? atoi(dbrow[col]) : 0;col++; int signal_check_color = strtol(dbrow[col][0] == '#' ? dbrow[col]+1 : dbrow[col], 0, 16); col++; bool embed_exif = (*dbrow[col] != '0'); col++; @@ -2290,6 +2293,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { ref_blend_perc, alarm_ref_blend_perc, track_motion, + signal_check_points, signal_check_color, embed_exif, purpose, @@ -2437,7 +2441,7 @@ int Monitor::Capture() { TimestampImage( capture_image, image_buffer[index].timestamp ); } // Maybe we don't need to do this on all camera types - shared_data->signal = CheckSignal(capture_image); + shared_data->signal = signal_check_points ? CheckSignal(capture_image) : true; shared_data->last_write_index = index; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index c91622f41..0f78b55a4 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -284,6 +284,7 @@ protected: int ref_blend_perc; // Percentage of new image going into reference image. int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm. bool track_motion; // Whether this monitor tries to track detected motion + int signal_check_points; // Number of points in the image to check for signal Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected bool embed_exif; // Whether to embed Exif data into each image frame or not @@ -384,6 +385,7 @@ public: int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, + int p_signal_check_points, Rgb p_signal_check_colour, bool p_embed_exif, Purpose p_purpose, From bd5f4020cace1f221183495452c887bf2498aba5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 10:10:23 -0400 Subject: [PATCH 062/154] bump version --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 5ab7277d8..dd8165476 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.41 +1.31.42 From 696b17e92eb3ebe94c226fef72a8ac34d7d23c23 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 07:37:11 -0700 Subject: [PATCH 063/154] include path to where we are not deleting from in teh debug output --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index f9b139095..7e4c6b819 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -397,7 +397,7 @@ sub delete { if ( (! $Config{ZM_OPT_FAST_DELETE}) and $event->Storage()->DoDelete() ) { $event->delete_files( ); } else { - Debug('Not deleting event files for speed.'); + Debug('Not deleting event files from '.$event->Path().' for speed.'); } } # end sub delete From d9a035a45da1d9831a8b8e06afbf848b5fb10ecd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 07:38:39 -0700 Subject: [PATCH 064/154] Remove commit that is unneccesary --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 7e4c6b819..e1f554483 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -522,7 +522,6 @@ sub MoveTo { my $OldStorage = $self->Storage(undef); my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint if ( ! -e $OldPath ) { - $ZoneMinder::Database::dbh->commit(); return "Old path $OldPath does not exist."; } # First determine if we can move it to the dest. From 5fe7b3f55f12a16ae4b4bad0f8f2c5eea7892f8f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 08:17:37 -0700 Subject: [PATCH 065/154] increase process kill time to 100 secs. zma can sometimes take this long --- scripts/zmdc.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index c358d3c4a..f1b7171a1 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -241,7 +241,7 @@ use ZoneMinder::Server qw(CpuLoad); #use Data::Dumper; # We count 10 of these, so total timeout is this value *10. -use constant KILL_DELAY => 1; # seconds +use constant KILL_DELAY => 10; # seconds our %cmd_hash; our %pid_hash; From e6525ce59e543186e6c2a642b0892ebdb28b6cc5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 08:18:23 -0700 Subject: [PATCH 066/154] Introduce a level param, and use it to turn on checks that shouldn't need to be done anymore, due to foreign keys --- scripts/zmaudit.pl.in | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index f672a86b3..80d675f05 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -63,6 +63,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my $report = 0; my $interactive = 0; my $continuous = 0; +my $level = 1; my $monitor_id = 0; my $version; my $force = 0; @@ -74,6 +75,7 @@ GetOptions( continuous =>\$continuous, force =>\$force, interactive =>\$interactive, + level =>\$level, 'monitor_id=i' =>\$monitor_id, report =>\$report, 'storage_id=i' =>\$storage_id, @@ -485,7 +487,9 @@ MAIN: while( $loop ) { redo MAIN; } +if ( $level > 1 ) { # Remove orphaned events (with no monitor) +# Shouldn't be possible anymore with FOREIGN KEYS in place $cleaned = 0; Debug("Checking for Orphaned Events"); my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name @@ -507,6 +511,7 @@ MAIN: while( $loop ) { } } redo MAIN if $cleaned; +} # end if level > 1 # Remove empty events (with no frames) $cleaned = 0; @@ -552,6 +557,7 @@ MAIN: while( $loop ) { } redo MAIN if $cleaned; +if ( $level > 1 ) { # Remove orphaned stats records $cleaned = 0; Debug("Checking for Orphaned Stats"); @@ -570,6 +576,7 @@ MAIN: while( $loop ) { } } redo MAIN if ( $cleaned ); +} # New audit to close any events that were left open for longer than MIN_AGE seconds my $selectUnclosedEventsSql = From a3373e5e4002b858d55b402fa54a33d377f22237 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 08:22:28 -0700 Subject: [PATCH 067/154] Use correct dir to source cmake generated files from --- db/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt index c8aa7cad6..07ead2406 100644 --- a/db/CMakeLists.txt +++ b/db/CMakeLists.txt @@ -11,11 +11,11 @@ file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql") install(FILES ${dbfileslist} DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") # install zm_update-1.31.30.sql -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") # install zm_create.sql install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") # install triggers.sql -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") From 56d3c2824f9c0d2e831ffd5215ccb73757fb9d2f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 12:31:50 -0400 Subject: [PATCH 068/154] Fix path to triggers.sql --- db/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt index 07ead2406..ed215d35f 100644 --- a/db/CMakeLists.txt +++ b/db/CMakeLists.txt @@ -17,5 +17,5 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" DESTINATION "$ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") # install triggers.sql -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") From 5b5cd3f33063b4d1e130df6f326f6f3a34b2188f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 14:16:30 -0400 Subject: [PATCH 069/154] fix broken table when no monitors to display --- web/skins/classic/views/console.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 6d202d163..298e82246 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -177,16 +177,9 @@ xhtmlHeaders( __FILE__, translate('Console') );
    '; - } +ob_start(); ?> - +
    @@ -211,8 +204,19 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { - + '; + } + echo $table_head; } # monitor_i % 100 ?> From 2aa689a14a95dcf5e77b3a4cb07792a685c0de02 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 14:20:02 -0400 Subject: [PATCH 070/154] Use a class instead of an id for consoleTable --- web/api/app/Plugin/CakePHP-Enum-Behavior | 2 +- web/skins/classic/css/base/views/console.css | 20 ++-- .../classic/css/classic/views/console.css | 92 +----------------- web/skins/classic/css/dark/skin.css | 14 --- web/skins/classic/css/dark/views/console.css | 95 +------------------ 5 files changed, 14 insertions(+), 209 deletions(-) diff --git a/web/api/app/Plugin/CakePHP-Enum-Behavior b/web/api/app/Plugin/CakePHP-Enum-Behavior index ea90c0cd7..ca91b87fd 160000 --- a/web/api/app/Plugin/CakePHP-Enum-Behavior +++ b/web/api/app/Plugin/CakePHP-Enum-Behavior @@ -1 +1 @@ -Subproject commit ea90c0cd7f6e24333a90885e563b5d30b793db29 +Subproject commit ca91b87fda8e006e4fca2ed870f24f9a29c2905d diff --git a/web/skins/classic/css/base/views/console.css b/web/skins/classic/css/base/views/console.css index 21f85424a..4a5470b6b 100644 --- a/web/skins/classic/css/base/views/console.css +++ b/web/skins/classic/css/base/views/console.css @@ -51,46 +51,46 @@ width: 20%; } -#consoleTable { +.consoleTable { width: 100%; } -#consoleTable tr.highlight { +.consoleTable tr.highlight { background-color: #eeeeee; } -#consoleTable thead th { +.consoleTable thead th { padding-bottom: 4px; vertical-align: middle; } -#consoleTable tfoot td { +.consoleTable tfoot td { padding-top: 4px; vertical-align: middle; } -#consoleTable th,td { +.consoleTable th,td { text-align: left; } -#consoleTable .colMark { +.consoleTable .colMark { width: 52px; text-align: center; } -#consoleTable .colEvents { +.consoleTable .colEvents { text-align: right; } -#consoleTable .colZones { +.consoleTable .colZones { text-align: right; } -#consoleTable .colFunction { +.consoleTable .colFunction { width: 120px; text-align: center; } -#consoleTable .colLeftButtons { +.consoleTable .colLeftButtons { text-align: left; } .FunctionFilter select { diff --git a/web/skins/classic/css/classic/views/console.css b/web/skins/classic/css/classic/views/console.css index 8f90f9eb4..14d02ad4e 100644 --- a/web/skins/classic/css/classic/views/console.css +++ b/web/skins/classic/css/classic/views/console.css @@ -1,96 +1,8 @@ -#systemTime { - float: left; -} -#title { - margin: 0 auto; - text-align: center; - width: 50%; -} - -#systemStats { - float: right; -} - -#systemStats .warning { - color: orange; -} - -#systemStats .error { - color: red; -} - -#systemStats .critical { - color: red; - text-decoration: blink; -} - -#monitorSummary { - float: left; - text-align: left; - width: 20%; -} - -#devices { - float: left; -} - -#loginBandwidth { - margin: 0 auto; - text-align: center; - width: 40%; -} - -#cycleMontage { - float: right; -} - -#options { - float: right; - text-align: right; - width: 20%; -} - -#consoleTable { - width: 100%; -} - -#consoleTable tr.highlight { - background-color: #eeeeee; -} - -#consoleTable thead th { - padding-bottom: 4px; - vertical-align: middle; -} - -#consoleTable tfoot td { - padding-top: 4px; - vertical-align: middle; -} - -#consoleTable th,td { - height: 16px; - text-align: left; -} - -#consoleTable .colMark { +.consoleTable .colMark { width: 72px; - text-align: center; } -#consoleTable .colEvents { - text-align: right; -} - -#consoleTable .colZones { - text-align: right; -} - -#consoleTable .colLeftButtons { - text-align: left; -} - -#consoleTable .colLeftButtons input { +.consoleTable .colLeftButtons input { margin-right: 24px; } diff --git a/web/skins/classic/css/dark/skin.css b/web/skins/classic/css/dark/skin.css index 4ef70091d..13bfa125e 100644 --- a/web/skins/classic/css/dark/skin.css +++ b/web/skins/classic/css/dark/skin.css @@ -495,20 +495,6 @@ input[type=submit]:disabled, border-color: #666666; } -/* - * Console table for the main event table - */ - -#consoleTable td, #consoleTable th { - padding: 5px; - border-bottom: 1px solid #000000; -} - -#consoleTable input[type=button] { - margin-right: 3px !important; -} - - .navbar{ margin-bottom: 0 !important; border-radius: 0; diff --git a/web/skins/classic/css/dark/views/console.css b/web/skins/classic/css/dark/views/console.css index e28a15b79..48c0b6d86 100644 --- a/web/skins/classic/css/dark/views/console.css +++ b/web/skins/classic/css/dark/views/console.css @@ -1,96 +1,3 @@ -#systemTime { - float: left; -} - -#title { - margin: 0 auto; - text-align: center; - width: 50%; -} - -#systemStats { - float: right; -} - -#systemStats .warning { - color: orange; -} - -#systemStats .error { - color: red; -} - -#systemStats .critical { - color: red; - text-decoration: blink; -} - -#monitorSummary { - float: left; - text-align: left; - width: 20%; -} - -#devices { - float: left; -} - -#loginBandwidth { - margin: 0 auto; - text-align: center; - width: 40%; -} - -#cycleMontage { - float: right; -} - -#options { - float: right; - text-align: right; - width: 20%; -} - -#consoleTable { - width: 100%; -} - -#consoleTable tr.highlight { +.consoleTable tr.highlight { background-color: #111111; } - -#consoleTable thead th { - padding-bottom: 4px; - vertical-align: middle; -} - -#consoleTable tfoot td { - padding-top: 4px; - vertical-align: middle; -} - -#consoleTable th,td { - height: 16px; - text-align: left; -} - -#consoleTable .colMark { - width: 62px; - text-align: center; -} - -#consoleTable .colEvents { - text-align: right; -} - -#consoleTable .colZones { - text-align: right; -} - -#consoleTable .colLeftButtons { - text-align: left; -} - -#consoleTable .colLeftButtons input { - margin-right: 24px; -} From 251684617601374eaa640b3f3ef6f15003197aff Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 14:22:19 -0400 Subject: [PATCH 071/154] only update DiskSpace if new DiskSpace is defined --- scripts/zmfilter.pl.in | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 12dae98cf..20c8569d8 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -340,7 +340,13 @@ sub checkFilter { $Event->lock_and_load(); my $old_diskspace = $$Event{DiskSpace}; - if ( $old_diskspace != $Event->DiskSpace(undef) ) { + my $new_diskspace = $Event->DiskSpace(undef); + + if ( + ( (!defined $old_diskspace) and defined $new_diskspace) + or + ( (defined $old_diskspace) and (defined $new_diskspace) and ( $old_diskspace != $Event->DiskSpace(undef) ) ) + ) { $Event->save(); } $ZoneMinder::Database::dbh->commit(); From fb44619a667c1a62c807bf9995631dfaa0565131 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Apr 2018 14:33:05 -0400 Subject: [PATCH 072/154] output the initial table head --- web/api/app/Plugin/CakePHP-Enum-Behavior | 2 +- web/api/app/Plugin/Crud | 2 +- web/skins/classic/views/console.php | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/web/api/app/Plugin/CakePHP-Enum-Behavior b/web/api/app/Plugin/CakePHP-Enum-Behavior index ca91b87fd..7108489f2 160000 --- a/web/api/app/Plugin/CakePHP-Enum-Behavior +++ b/web/api/app/Plugin/CakePHP-Enum-Behavior @@ -1 +1 @@ -Subproject commit ca91b87fda8e006e4fca2ed870f24f9a29c2905d +Subproject commit 7108489f218c54d36d235d3af91d6da2f8311237 diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 1351dde6b..c3976f147 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 +Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5 diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 298e82246..1db519a18 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -208,6 +208,7 @@ ob_start(); Date: Thu, 19 Apr 2018 14:01:46 -0500 Subject: [PATCH 073/154] Migrate Webcache out of webroot (#2083) * migrate webcache folder out of webroot, migrate htaccess files * rpm specfile - add missing reference to cache folder * fix submodule mixup --- CMakeLists.txt | 2 + distros/redhat/CMakeLists.txt | 1 + distros/redhat/apache/zoneminder.conf.in | 17 ++++++++ distros/redhat/systemd/zoneminder.tmpfiles.in | 3 ++ distros/redhat/zoneminder.spec | 1 + .../ubuntu1204/conf/apache2/zoneminder.conf | 32 +++++++++++++- distros/ubuntu1204/rules | 1 + distros/ubuntu1204/zoneminder.dirs | 1 + .../ubuntu1604/conf/apache2/zoneminder.conf | 31 +++++++++++++- distros/ubuntu1604/rules | 1 + distros/ubuntu1604/zoneminder.dirs | 2 +- distros/ubuntu1604/zoneminder.postinst | 2 +- distros/ubuntu1604/zoneminder.tmpfile | 2 +- misc/apache.conf.in | 42 +++++++++++++++++++ web/.htaccess | 5 --- web/api/.htaccess | 6 --- web/api/app/.htaccess | 6 --- web/api/app/Plugin/Crud | 2 +- web/api/app/webroot/.htaccess | 7 ---- .../lib/Cake/Console/Templates/skel/.htaccess | 5 --- .../Templates/skel/tmp/cache/models/empty | 0 .../Templates/skel/tmp/cache/persistent/empty | 0 .../Templates/skel/tmp/cache/views/empty | 0 .../Console/Templates/skel/tmp/logs/empty | 0 .../Console/Templates/skel/tmp/sessions/empty | 0 .../Console/Templates/skel/tmp/tests/empty | 0 .../Console/Templates/skel/webroot/.htaccess | 6 --- web/includes/config.php.in | 1 + web/includes/functions.php | 6 +-- 29 files changed, 136 insertions(+), 46 deletions(-) delete mode 100644 web/.htaccess delete mode 100644 web/api/.htaccess delete mode 100644 web/api/app/.htaccess delete mode 100644 web/api/app/webroot/.htaccess delete mode 100644 web/api/lib/Cake/Console/Templates/skel/.htaccess create mode 100644 web/api/lib/Cake/Console/Templates/skel/tmp/cache/models/empty create mode 100644 web/api/lib/Cake/Console/Templates/skel/tmp/cache/persistent/empty create mode 100644 web/api/lib/Cake/Console/Templates/skel/tmp/cache/views/empty create mode 100644 web/api/lib/Cake/Console/Templates/skel/tmp/logs/empty create mode 100644 web/api/lib/Cake/Console/Templates/skel/tmp/sessions/empty create mode 100644 web/api/lib/Cake/Console/Templates/skel/tmp/tests/empty delete mode 100644 web/api/lib/Cake/Console/Templates/skel/webroot/.htaccess diff --git a/CMakeLists.txt b/CMakeLists.txt index d6f989f01..b24bc6fa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,8 @@ set(ZM_WEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/www" "Location of the web files, default: /${CMAKE_INSTALL_DATADIR}/zoneminder/www") set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH "Location of the cgi-bin files, default: /${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin") +set(ZM_CACHEDIR "/var/cache/zoneminder" CACHE PATH + "Location of the web server cache busting files, default: /var/cache/zoneminder") set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH "Location of dynamic content (events and images), default: /var/lib/zoneminder") set(ZM_DB_HOST "localhost" CACHE STRING diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index 73f88f968..edc0fd080 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -52,6 +52,7 @@ file(MAKE_DIRECTORY sock swap zoneminder zoneminder-upload events images temp) install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder DESTINATION /var/log DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder DESTINATION /var/run DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(DIRECTORY zoneminder DESTINATION /var/cache DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/distros/redhat/apache/zoneminder.conf.in b/distros/redhat/apache/zoneminder.conf.in index 0e546f9df..a52c1166a 100644 --- a/distros/redhat/apache/zoneminder.conf.in +++ b/distros/redhat/apache/zoneminder.conf.in @@ -9,6 +9,23 @@ RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^/?(zm)(.*) https://%{SERVER_NAME}/$1$2 [R,L] +# Order matters. This alias must come first. +Alias /zm/cache "@ZM_CACHEDIR@" + + SSLRequireSSL + Options -Indexes +MultiViews +FollowSymLinks + AllowOverride None + + # Apache 2.4 + Require all granted + + + # Apache 2.2 + Order deny,allow + Allow from all + + + Alias /zm "@ZM_WEBDIR@" # explicitly set index.php as the only directoryindex diff --git a/distros/redhat/systemd/zoneminder.tmpfiles.in b/distros/redhat/systemd/zoneminder.tmpfiles.in index f3acd0af7..de155b4cc 100644 --- a/distros/redhat/systemd/zoneminder.tmpfiles.in +++ b/distros/redhat/systemd/zoneminder.tmpfiles.in @@ -1,2 +1,5 @@ D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@ D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_CACHEDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_DIR_EVENTS@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_DIR_IMAGES@ 0755 @WEB_USER@ @WEB_GROUP@ diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 5d8f213b6..3d2febab9 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -377,6 +377,7 @@ rm -rf %{_docdir}/%{name}-%{version} %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/sock %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/swap %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/temp +%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/cache/zoneminder %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/log/zoneminder %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/spool/zoneminder-upload %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder diff --git a/distros/ubuntu1204/conf/apache2/zoneminder.conf b/distros/ubuntu1204/conf/apache2/zoneminder.conf index 0dc312769..81e9713db 100644 --- a/distros/ubuntu1204/conf/apache2/zoneminder.conf +++ b/distros/ubuntu1204/conf/apache2/zoneminder.conf @@ -6,6 +6,12 @@ ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin" Require all granted +# Order matters. This Alias must come first +Alias /zm/cache /var/cache/zoneminder/cache + + Options -Indexes +FollowSymLinks + + Alias /zm /usr/share/zoneminder/www php_flag register_globals off @@ -15,6 +21,28 @@ Alias /zm /usr/share/zoneminder/www - - AllowOverride All +# For better visibility, the following directives have been migrated from the +# default .htaccess files included with the CakePHP project. +# Parameters not set here are inherited from the parent directive above. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api + + diff --git a/distros/ubuntu1204/rules b/distros/ubuntu1204/rules index 0103d1c27..aed63c110 100755 --- a/distros/ubuntu1204/rules +++ b/distros/ubuntu1204/rules @@ -25,6 +25,7 @@ override_dh_auto_configure: -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ + -DZM_CACHEDIR="/var/cache/zoneminder/cache" \ -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \ diff --git a/distros/ubuntu1204/zoneminder.dirs b/distros/ubuntu1204/zoneminder.dirs index ff1ec7858..79b2c66af 100644 --- a/distros/ubuntu1204/zoneminder.dirs +++ b/distros/ubuntu1204/zoneminder.dirs @@ -3,6 +3,7 @@ var/lib/zm var/cache/zoneminder/events var/cache/zoneminder/images var/cache/zoneminder/temp +var/cache/zoneminder/cache usr/share/zoneminder/db etc/zm etc/zm/conf.d diff --git a/distros/ubuntu1604/conf/apache2/zoneminder.conf b/distros/ubuntu1604/conf/apache2/zoneminder.conf index 59efc6248..a51b153a9 100644 --- a/distros/ubuntu1604/conf/apache2/zoneminder.conf +++ b/distros/ubuntu1604/conf/apache2/zoneminder.conf @@ -6,6 +6,12 @@ ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin" Require all granted +# Order matters. This alias must come first. +Alias /zm/cache /var/cache/zoneminder/cache + + Options -Indexes +FollowSymLinks + + Alias /zm /usr/share/zoneminder/www Options -Indexes +FollowSymLinks @@ -14,6 +20,27 @@ Alias /zm /usr/share/zoneminder/www - - AllowOverride All +# For better visibility, the following directives have been migrated from the +# default .htaccess files included with the CakePHP project. +# Parameters not set here are inherited from the parent directive above. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules index 97c084e42..f0808a8e1 100755 --- a/distros/ubuntu1604/rules +++ b/distros/ubuntu1604/rules @@ -25,6 +25,7 @@ override_dh_auto_configure: -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ + -DZM_CACHEDIR="/var/cache/zoneminder/cache" \ -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" diff --git a/distros/ubuntu1604/zoneminder.dirs b/distros/ubuntu1604/zoneminder.dirs index 08840aef4..6db3d5a95 100644 --- a/distros/ubuntu1604/zoneminder.dirs +++ b/distros/ubuntu1604/zoneminder.dirs @@ -3,7 +3,7 @@ var/lib/zm var/cache/zoneminder/events var/cache/zoneminder/images var/cache/zoneminder/temp +var/cache/zoneminder/cache usr/share/zoneminder/db -usr/share/zoneminder/www/cache etc/zm/ etc/zm/conf.d diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index b9307bddd..17272c2df 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -13,7 +13,7 @@ if [ "$1" = "configure" ]; then 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/* /usr/share/zoneminder/www/cache + chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* fi if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ] && [ "$(command -v a2enmod)" != "" ]; then echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi." diff --git a/distros/ubuntu1604/zoneminder.tmpfile b/distros/ubuntu1604/zoneminder.tmpfile index f23ca55b3..9435be2a8 100644 --- a/distros/ubuntu1604/zoneminder.tmpfile +++ b/distros/ubuntu1604/zoneminder.tmpfile @@ -1,4 +1,4 @@ d /var/run/zm 0755 www-data www-data d /tmp/zm 0755 www-data www-data d /var/tmp/zm 0755 www-data www-data -d /usr/share/zoneminder/www/cache 0755 www-data www-data +d /var/cache/zoneminder/cache 0755 www-data www-data diff --git a/misc/apache.conf.in b/misc/apache.conf.in index 1344bb9b1..cb9c08667 100644 --- a/misc/apache.conf.in +++ b/misc/apache.conf.in @@ -8,6 +8,23 @@ ServerAdmin webmaster@localhost DocumentRoot "@WEB_PREFIX@" + + # Order matters. This alias must come first. + Alias /zm/cache "@ZM_CACHEDIR@" + + Options -Indexes +FollowSymLinks + AllowOverride None + + # Apache 2.4 + Require all granted + + + # Apache 2.2 + Order deny,allow + Allow from all + + + Alias /zm "@WEB_PREFIX@" Options -Indexes +FollowSymLinks @@ -38,6 +55,31 @@ + # For better visibility, the following directives have been migrated from the + # default .htaccess files included with the CakePHP project. + # Parameters not set here are inherited from the parent directive above. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api + + # Use the first option to have Apache logs written to the general log # directory, or the second to have them written to the regular Apache # directory (you may have to change the path to that used on your system) diff --git a/web/.htaccess b/web/.htaccess deleted file mode 100644 index f23dbaf66..000000000 --- a/web/.htaccess +++ /dev/null @@ -1,5 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ app/webroot/ [L] - RewriteRule (.*) app/webroot/$1 [L] - \ No newline at end of file diff --git a/web/api/.htaccess b/web/api/.htaccess deleted file mode 100644 index 7139a2766..000000000 --- a/web/api/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ app/webroot/ [L] - RewriteRule (.*) app/webroot/$1 [L] - RewriteBase /zm/api - diff --git a/web/api/app/.htaccess b/web/api/app/.htaccess deleted file mode 100644 index 1af74d971..000000000 --- a/web/api/app/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ webroot/ [L] - RewriteRule (.*) webroot/$1 [L] - RewriteBase /zm/api - diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 1351dde6b..0bd63fb46 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 +Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef diff --git a/web/api/app/webroot/.htaccess b/web/api/app/webroot/.htaccess deleted file mode 100644 index f08afa8b2..000000000 --- a/web/api/app/webroot/.htaccess +++ /dev/null @@ -1,7 +0,0 @@ - - RewriteEngine On - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [L] - RewriteBase /zm/api - diff --git a/web/api/lib/Cake/Console/Templates/skel/.htaccess b/web/api/lib/Cake/Console/Templates/skel/.htaccess deleted file mode 100644 index 128e7871b..000000000 --- a/web/api/lib/Cake/Console/Templates/skel/.htaccess +++ /dev/null @@ -1,5 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ webroot/ [L] - RewriteRule (.*) webroot/$1 [L] - \ No newline at end of file diff --git a/web/api/lib/Cake/Console/Templates/skel/tmp/cache/models/empty b/web/api/lib/Cake/Console/Templates/skel/tmp/cache/models/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/tmp/cache/persistent/empty b/web/api/lib/Cake/Console/Templates/skel/tmp/cache/persistent/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/tmp/cache/views/empty b/web/api/lib/Cake/Console/Templates/skel/tmp/cache/views/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/tmp/logs/empty b/web/api/lib/Cake/Console/Templates/skel/tmp/logs/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/tmp/sessions/empty b/web/api/lib/Cake/Console/Templates/skel/tmp/sessions/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/tmp/tests/empty b/web/api/lib/Cake/Console/Templates/skel/tmp/tests/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/webroot/.htaccess b/web/api/lib/Cake/Console/Templates/skel/webroot/.htaccess deleted file mode 100644 index 1d499ba73..000000000 --- a/web/api/lib/Cake/Console/Templates/skel/webroot/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ - - RewriteEngine On - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [L] - diff --git a/web/includes/config.php.in b/web/includes/config.php.in index c9bd55dd7..c6aa93c63 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -26,6 +26,7 @@ define( 'ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@' ); // Path to config subfolder // Define, and override any given in config file define( 'ZM_VERSION', '@VERSION@' ); // Version define( 'ZM_DIR_TEMP', '@ZM_TMPDIR@' ); +define( 'ZM_DIR_CACHE', '@ZM_CACHEDIR@' ); global $configvals; $configFile = ZM_CONFIG; diff --git a/web/includes/functions.php b/web/includes/functions.php index 64d6ce29b..69d655d8a 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2031,9 +2031,9 @@ function cache_bust( $file ) { $parts = pathinfo($file); global $css; $dirname = preg_replace( '/\//', '_', $parts['dirname'] ); - $cacheFile = 'cache/'.$dirname.'_'.$parts['filename'].'-'.$css.'-'.filemtime($file).'.'.$parts['extension']; - if ( file_exists( ZM_PATH_WEB.'/'.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_PATH_WEB.'/'.$cacheFile ) ) { - return $cacheFile; + $cacheFile = $dirname.'_'.$parts['filename'].'-'.$css.'-'.filemtime($file).'.'.$parts['extension']; + if ( file_exists( ZM_DIR_CACHE.'/'.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_DIR_CACHE.'/'.$cacheFile ) ) { + return 'cache/'.$cacheFile; } else { Warning("Failed linking $file to $cacheFile"); } From ed140426abae562f83577d1e714916720a0fa18b Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Thu, 19 Apr 2018 15:36:43 -0500 Subject: [PATCH 074/154] rpm packaging changes and documentation --- distros/redhat/CMakeLists.txt | 7 ++-- distros/redhat/readme/README.Fedora | 56 ++++++++++++---------------- distros/redhat/readme/README.Redhat6 | 52 +++++++++++--------------- distros/redhat/readme/README.Redhat7 | 54 +++++++++++---------------- distros/redhat/readme/README.https | 29 +++++++------- distros/redhat/zoneminder.spec | 5 +-- web/api/app/Plugin/Crud | 2 +- 7 files changed, 84 insertions(+), 121 deletions(-) diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index edc0fd080..ba8aba9c0 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -62,17 +62,16 @@ install(CODE "execute_process(COMMAND ln -sf ../../../../../../var/lib/zoneminde # Link to Cambozola install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/cambozola.jar\")") -# Install auxiliary files required to run zoneminder on CentOS +# Install auxiliary files install(FILES misc/redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY jscalendar-1.0/ DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/tools/jscalendar) +# Install zoneminder service files install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) +install(FILES zoneminder.conf DESTINATION /etc/zm/www PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) if(ZM_WEB_USER STREQUAL "nginx") - install(FILES zoneminder.conf DESTINATION /etc/nginx/default.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.php-fpm.conf DESTINATION /etc/php-fpm.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ RENAME zoneminder.conf) -else(ZM_WEB_USER STREQUAL "nginx") - install(FILES zoneminder.conf DESTINATION /etc/httpd/conf.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) endif(ZM_WEB_USER STREQUAL "nginx") if(ZM_TARGET_DISTRO STREQUAL "el6") diff --git a/distros/redhat/readme/README.Fedora b/distros/redhat/readme/README.Fedora index e3cca1f8c..bd80b02a8 100644 --- a/distros/redhat/readme/README.Fedora +++ b/distros/redhat/readme/README.Fedora @@ -1,37 +1,19 @@ What's New ========== -1. ZoneMinder now uses a conf.d subfolder to process custom changes to - variables found in zm.conf. Changes to zm.conf will be overwritten - during an upgrade. Instead, create a file with a ".conf" extension under - the conf.d folder and make your changes there. - -2. ZoneMinder now supports recording directly to video container! This feature - is new and should be treated as experimental. Refer to the documentation - regarding how to use this feature. - -3. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to - "/cgi-bin-zm/zms". This has been to done to avoid this bug: - https://bugzilla.redhat.com/show_bug.cgi?id=973067 - - IMPORTANT: You must manually inspect the value for PATH_ZMS under Options - and verify it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result - in a broken system. You have been warned. - -4. This package uses the HTTPS protocol by default to access the web portal. - Requests using HTTP will auto-redirect to HTTPS. See README.https for - more information. - +1. See the ZoneMinder release notes for a list of new features: + https://github.com/ZoneMinder/zoneminder/releases + 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 systemctl enable mariadb - sudo systemctl start mariadb.service - mysql_secure_installation + sudo dnf install mariadb-server + sudo systemctl enable mariadb + sudo systemctl start mariadb.service + mysql_secure_installation 2. Assuming the database is local and using the password for the root account set during the previous step, you will need to create the ZoneMinder @@ -82,16 +64,24 @@ New installs SELINUX line from "enforcing" to "disabled". This change will take effect after a reboot. -6. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your - needs. This package comes preconfigured for HTTPS using the default self - signed certificate on your system. The recommended way to complete this step - is to simply install mod_ssl: +6. Configure the web server + This package uses the HTTPS protocol by default to access the web portal, + using rhe default self signed certificate on your system. Requests using + HTTP will auto-redirect to HTTPS. + + Inspect the web server configuration file and verify it meets your needs: + + /etc/zm/www/zoneminder.conf + + If you are running other web enabled services then you may need to edit + this file to suite. See README.https to learn about other alternatives. + + When in doubt, proceed with the default: + + sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ sudo dnf install mod_ssl - If this does not meet your needs, then read README.https to - learn about alternatives. When in doubt, install mod_ssl. - 7. Now start the web server: sudo systemctl enable httpd @@ -131,7 +121,7 @@ Upgrades See step 2 of the Installation section to add missing permissions. 3. Verify the ZoneMinder Apache configuration file in the folder - /etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there + /etc/zm/www. You will have a file called "zoneminder.conf" and there may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file exists, inspect it and merge anything new in that file with zoneminder.conf. Verify the SSL REquirements meet your needs. Read README.https if necessary. diff --git a/distros/redhat/readme/README.Redhat6 b/distros/redhat/readme/README.Redhat6 index 939300d96..e7e4a4d49 100644 --- a/distros/redhat/readme/README.Redhat6 +++ b/distros/redhat/readme/README.Redhat6 @@ -1,7 +1,10 @@ What's New ========== -1. ***EOL NOTICE*** +1. See the ZoneMinder release notes for a list of new features: + https://github.com/ZoneMinder/zoneminder/releases + +2. ***EOL NOTICE*** It has become increasingly difficult to maintain the ZoneMinder project such that it remains compatible with EL6 distros. The version of php shipped with EL6 distros and the version of ffmpeg which will build against EL6 are too @@ -11,28 +14,7 @@ What's New replacing core packages, such as php, will not be supported by us. You are on your own should you choose to go down that path. -2. ZoneMinder now uses a conf.d subfolder to process custom changes to - variables found in zm.conf. Changes to zm.conf will be overwritten - during an upgrade. Instead, create a file with a ".conf" extension under - th2 conf.d folder and make your changes there. - -3. ZoneMinder now supports recording directly to video container! This feature - is new and should be treated as experimental. Refer to the documentation - regarding how to use this feature. - -4. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to - "/cgi-bin-zm/zms". This has been to done match the configuration of - CentOS7/Fedora and simplify the build process. - - IMPORTANT: You must manually verify the value of PATH_ZMS under Options. - Make sure it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result - in a broken system. You have been warned. - -5. This package uses the HTTPS protocol by default to access the web portal. - Requests using HTTP will auto-redirect to HTTPS. See README.https for - more information. - -6. The php package that ships with CentOS 6 does not support the new ZoneMinder +3. The php package that ships with CentOS 6 does not support the new ZoneMinder API. If you require API functionality (such as using a mobile app) then you should consider an upgrade to CentOS 7 or use Fedora. @@ -81,15 +63,23 @@ New installs If you are not sure of the proper timezone specification to use, look at http://php.net/date.timezone -5. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your - needs. This package comes preconfigured for HTTPS using the default self - signed certificate on your system. The recommended way to complete this step - is to simply install mod_ssl: +5. Configure the web server - sudo yum install mod_ssl + This package uses the HTTPS protocol by default to access the web portal, + using rhe default self signed certificate on your system. Requests using + HTTP will auto-redirect to HTTPS. - If this does not meet your needs, then read README.https to - learn about alternatives. When in doubt, install mod_ssl. + Inspect the web server configuration file and verify it meets your needs: + + /etc/zm/www/zoneminder.conf + + If you are running other web enabled services then you may need to edit + this file to suite. See README.https to learn about other alternatives. + + When in doubt, proceed with the default: + + sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ + sudo dnf install mod_ssl 6. Configure the web server to start automatically: @@ -137,7 +127,7 @@ Upgrades See step 2 of the Installation section to add missing permissions. 3. Verify the ZoneMinder Apache configuration file in the folder - /etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there + /etc/zm/www. You will have a file called "zoneminder.conf" and there may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file exists, inspect it and merge anything new in that file with zoneminder.conf. Verify the SSL REquirements meet your needs. Read README.https if necessary. diff --git a/distros/redhat/readme/README.Redhat7 b/distros/redhat/readme/README.Redhat7 index d74973a72..3e226fbbf 100644 --- a/distros/redhat/readme/README.Redhat7 +++ b/distros/redhat/readme/README.Redhat7 @@ -1,26 +1,8 @@ What's New ========== -1. ZoneMinder now uses a conf.d subfolder to process custom changes to - variables found in zm.conf. Changes to zm.conf will be overwritten - during an upgrade. Instead, create a file with a ".conf" extension under - the conf.d folder and make your changes there. - -2. ZoneMinder now supports recording directly to video container! This feature - is new and should be treated as experimental. Refer to the documentation - regarding how to use this feature. - -3. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to - "/cgi-bin-zm/zms". This has been to done to avoid this bug: - https://bugzilla.redhat.com/show_bug.cgi?id=973067 - - IMPORTANT: You must manually inspect the value for PATH_ZMS under Options - and verify it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result - in a broken system. You have been warned. - -4. This package uses the HTTPS protocol by default to access the web portal. - Requests using HTTP will auto-redirect to HTTPS. See README.https for - more information. +1. See the ZoneMinder release notes for a list of new features: + https://github.com/ZoneMinder/zoneminder/releases New installs ============ @@ -28,10 +10,10 @@ 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 yum install mariadb-server - sudo systemctl enable mariadb - sudo systemctl start mariadb.service - mysql_secure_installation + sudo yum install mariadb-server + sudo systemctl enable mariadb + sudo systemctl start mariadb.service + mysql_secure_installation 2. Using the password for the root account set during the previous step, you will need to create the ZoneMinder database and configure a database @@ -82,15 +64,23 @@ New installs SELINUX line from "enforcing" to "disabled". This change will take effect after a reboot. -6. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your - needs. This package comes preconfigured for HTTPS using the default self - signed certificate on your system. The recommended way to complete this step - is to simply install mod_ssl: +6. Configure the web server - sudo yum install mod_ssl + This package uses the HTTPS protocol by default to access the web portal, + using rhe default self signed certificate on your system. Requests using + HTTP will auto-redirect to HTTPS. - If this does not meet your needs, then read README.https to - learn about alternatives. When in doubt, install mod_ssl. + Inspect the web server configuration file and verify it meets your needs: + + /etc/zm/www/zoneminder.conf + + If you are running other web enabled services then you may need to edit + this file to suite. See README.https to learn about other alternatives. + + When in doubt, proceed with the default: + + sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ + sudo dnf install mod_ssl 7. Now start the web server: @@ -122,7 +112,7 @@ Upgrades See step 2 of the Installation section to add missing permissions. 3. Verify the ZoneMinder Apache configuration file in the folder - /etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there + /etc/zm/www. You will have a file called "zoneminder.conf" and there may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file exists, inspect it and merge anything new in that file with zoneminder.conf. Verify the SSL REquirements meet your needs. Read README.https if necessary. diff --git a/distros/redhat/readme/README.https b/distros/redhat/readme/README.https index 7e4132a4a..4b02aaa0d 100644 --- a/distros/redhat/readme/README.https +++ b/distros/redhat/readme/README.https @@ -1,29 +1,26 @@ -HTTPS is now a requirement -========================== +HTTPS is now the default +======================== -This package now depends on Apache's mod_ssl package. This will automatically -be installed along with ZoneMinder. Upon installation, the mod_ssl package -will create a default, self-signed certificate. This is the certificate that -ZoneMinder will use out of the box. +By default, ZoneMinder will use the certifciate created when the mod_ssl +pacakge was installed on your system. Since the certificate is self-signed, you will get a warning from your browser the first time you access the web portal. This is normal. This is not intended to be an all encompasing solution for everyone. ZoneMinder will work just fine over HTTPS the way it is currently configured. However, -here are a couple of considerations you may want to take. +here are a couple of considerations you may want to take to improve your +experience. -1. Create your own certificate. The CentOS wiki has a guide that describes how +1. Install a fully signed certificate from letsencrypt, using certbot. See the + certbot site for more information. This free service is very easy to set up. + https://certbot.eff.org/all-instructions/ + +2. Create your own certificate. The CentOS wiki has a guide that describes how to do this: https://wiki.centos.org/HowTos/Https . Additionally, Googling - "centos certificate" reveals many articles on the subject. Note that some - third party applications, such as zmNinja, will require you to create a - certificate different than the default certificate on your machine. + "centos certificate" reveals many articles on the subject. -2. You can turn off HTTPS entirely by simply commenting out the SSLRequireSSL +3. You can turn off HTTPS entirely by simply commenting out the SSLRequireSSL directives found in /etc/httpd/conf.d/zoneminder.conf. You should also comment out the HTTP -> HTTPS Rewrite rule. -3. Install a fully signed certificate from letsencrypt. See the Letsencrypt - site for more information. https://letsencrypt.org/ - This service is totally free! - diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 3d2febab9..75d97ebeb 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -9,9 +9,6 @@ %if "%{zmuid_final}" == "nginx" %global with_nginx 1 -%global wwwconfdir %{_sysconfdir}/nginx/default.d -%else -%global wwwconfdir %{_sysconfdir}/httpd/conf.d %endif %global sslcert %{_sysconfdir}/pki/tls/certs/localhost.crt @@ -321,7 +318,7 @@ rm -rf %{_docdir}/%{name}-%{version} %config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/*.conf %ghost %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/zmcustom.conf -%config(noreplace) %attr(644,root,root) %{wwwconfdir}/zoneminder.conf +%config(noreplace) %attr(644,root,root) /etc/zm/www/zoneminder.conf %config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder %if 0%{?with_nginx} 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 From 2d2c0df8f18689cf09707fbdecefe41c4e6f381f Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 19 Apr 2018 15:39:08 -0500 Subject: [PATCH 075/154] rpm specfile - bump version --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 75d97ebeb..e3d019a4b 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -33,7 +33,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.31.41 +Version: 1.31.42 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons From 411a83133805b9bc89f1f1b0e05b869bbc1188e3 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Thu, 19 Apr 2018 18:40:05 -0500 Subject: [PATCH 076/154] rpm packaging - mention the firewall in the README's --- distros/redhat/readme/README.Fedora | 58 +++++++++++++++++++--------- distros/redhat/readme/README.Redhat6 | 29 ++++++++++++++ distros/redhat/readme/README.Redhat7 | 51 ++++++++++++++++++------ 3 files changed, 108 insertions(+), 30 deletions(-) diff --git a/distros/redhat/readme/README.Fedora b/distros/redhat/readme/README.Fedora index bd80b02a8..d0ccf8c4e 100644 --- a/distros/redhat/readme/README.Fedora +++ b/distros/redhat/readme/README.Fedora @@ -32,13 +32,13 @@ New installs /etc/zm/conf.d and set your credentials there. For example, create the file /etc/zm/conf.d/zm-db-user.conf and add the following content to it: - ZM_DB_USER = {username of the sql account you want to use} - ZM_DB_PASS = {password of the sql account you want to use} + ZM_DB_USER = {username of the sql account you want to use} + ZM_DB_PASS = {password of the sql account you want to use} Once the file has been saved, set proper file & ownership permissions on it: - sudo chown root:apache *.conf - sudo chmod 640 *.conf + sudo chown root:apache *.conf + sudo chmod 640 *.conf 4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local timezone. PHP will complain loudly if this is not set, or if it is set @@ -72,34 +72,54 @@ New installs Inspect the web server configuration file and verify it meets your needs: - /etc/zm/www/zoneminder.conf + /etc/zm/www/zoneminder.conf If you are running other web enabled services then you may need to edit this file to suite. See README.https to learn about other alternatives. When in doubt, proceed with the default: - sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ - sudo dnf install mod_ssl + sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ + sudo dnf install mod_ssl 7. Now start the web server: - sudo systemctl enable httpd - sudo systemctl start httpd + sudo systemctl enable httpd + sudo systemctl start httpd 8. Now start zoneminder: - sudo systemctl enable zoneminder - sudo systemctl start zoneminder + sudo systemctl enable zoneminder + sudo systemctl start zoneminder -9. The Fedora repos have a ZoneMinder package available, but it does not - support ffmpeg or libvlc, which many modern IP cameras require. Most users - will want to prevent the ZoneMinder package in the Fedora repos from - overwriting the ZoneMinder package in zmrepo, during a future dnf update. To - prevent that from happening you must edit /etc/yum.repos.d/fedora.repo - and /etc/yum.repos.d/fedora-updates.repo. Add the line "exclude=zoneminder*" - without the quotes under the [fedora] and [fedora-updates] blocks, - respectively. +9. Optionally configure the firewall + + All Redhat distros ship with the firewall enabled. That means you will not + be able to access the ZoneMinder web console from a remote machine until + changes are made to the firewall. + + What follows are a set of minimal commands to allow remote access to the + ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to + work. The following commands do not put any restrictions on which remote + machine(s) have access to the listed ports or services. + + sudo firewall-cmd --permanent --zone=public --add-service=http + sudo firewall-cmd --permanent --zone=public --add-service=https + sudo firewall-cmd --permanent --zone=public --add-port=3702/udp + sudo firewall-cmd --reload + + Additional changes to the firewall may be required, depending on your + security requirements and how you use the system. It is up to you to verify + these commands are sufficient. + +10. Access the ZoneMinder web console + + You may now access the ZoneMinder web console from your web browser using + an appropriate url. Here are some examples: + + http://localhost/zm (works from the local machine only) + http://{machine name}/zm (works only if dns is configured for your network) + http://{ip address}/zm Upgrades ======== diff --git a/distros/redhat/readme/README.Redhat6 b/distros/redhat/readme/README.Redhat6 index e7e4a4d49..95c063b10 100644 --- a/distros/redhat/readme/README.Redhat6 +++ b/distros/redhat/readme/README.Redhat6 @@ -107,6 +107,35 @@ New installs Then point your web browser to http:///zm +9. Optionally configure the firewall + + All Redhat distros ship with the firewall enabled. That means you will not + be able to access the ZoneMinder web console from a remote machine until + changes are made to the firewall. + + What follows are a set of minimal commands to allow remote access to the + ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to + work. The following commands do not put any restrictions on which remote + machine(s) have access to the listed ports or services. + + sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT + sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT + sudo iptables -A INPUT -p udp --dport 3702 -j ACCEPT + iptables-save | sudo tee /etc/sysconfig/iptables + + Additional changes to the firewall may be required, depending on your + security requirements and how you use the system. It is up to you to verify + these commands are sufficient. + +10. Access the ZoneMinder web console + + You may now access the ZoneMinder web console from your web browser using + an appropriate url. Here are some examples: + + http://localhost/zm (works from the local machine only) + http://{machine name}/zm (works only if dns is configured for your network) + http://{ip address}/zm + Upgrades ======== diff --git a/distros/redhat/readme/README.Redhat7 b/distros/redhat/readme/README.Redhat7 index 3e226fbbf..b70e7768d 100644 --- a/distros/redhat/readme/README.Redhat7 +++ b/distros/redhat/readme/README.Redhat7 @@ -32,13 +32,13 @@ New installs /etc/zm/conf.d and set your credentials there. For example, create the file /etc/zm/conf.d/zm-db-user.conf and add the following content to it: - ZM_DB_USER = {username of the sql account you want to use} - ZM_DB_PASS = {password of the sql account you want to use} + ZM_DB_USER = {username of the sql account you want to use} + ZM_DB_PASS = {password of the sql account you want to use} Once the file has been saved, set proper file & ownership permissions on it: - sudo chown root:apache *.conf - sudo chmod 640 *.conf + sudo chown root:apache *.conf + sudo chmod 640 *.conf 4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local timezone. PHP will complain loudly if this is not set, or if it is set @@ -72,25 +72,54 @@ New installs Inspect the web server configuration file and verify it meets your needs: - /etc/zm/www/zoneminder.conf + /etc/zm/www/zoneminder.conf If you are running other web enabled services then you may need to edit this file to suite. See README.https to learn about other alternatives. When in doubt, proceed with the default: - sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ - sudo dnf install mod_ssl + sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ + sudo dnf install mod_ssl 7. Now start the web server: - sudo systemctl enable httpd - sudo systemctl start httpd + sudo systemctl enable httpd + sudo systemctl start httpd 8. Now start zoneminder: - sudo systemctl enable zoneminder - sudo systemctl start zoneminder + sudo systemctl enable zoneminder + sudo systemctl start zoneminder + +9. Optionally configure the firewall + + All Redhat distros ship with the firewall enabled. That means you will not + be able to access the ZoneMinder web console from a remote machine until + changes are made to the firewall. + + What follows are a set of minimal commands to allow remote access to the + ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to + work. The following commands do not put any restrictions on which remote + machine(s) have access to the listed ports or services. + + sudo firewall-cmd --permanent --zone=public --add-service=http + sudo firewall-cmd --permanent --zone=public --add-service=https + sudo firewall-cmd --permanent --zone=public --add-port=3702/udp + sudo firewall-cmd --reload + + Additional changes to the firewall may be required, depending on your + security requirements and how you use the system. It is up to you to verify + these commands are sufficient. + +10. Access the ZoneMinder web console + + You may now access the ZoneMinder web console from your web browser using + an appropriate url. Here are some examples: + + http://localhost/zm (works from the local machine only) + http://{machine name}/zm (works only if dns is configured for your network) + http://{ip address}/zm Upgrades ======== From 39244ac6ec6402b4e9ee21e1b646714a3375f989 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 19 Apr 2018 20:01:31 -0500 Subject: [PATCH 077/154] buildsystem update --- utils/packpack/startpackpack.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 95f887320..46f6f2356 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -138,11 +138,11 @@ commonprep () { fi CEBVER="1.0-zm" - if [ -e "build/crud-${CEBVER}.tar.gz" ]; then + if [ -e "build/cakephp-enum-behavior-${CEBVER}.tar.gz" ]; then echo "Found existing CakePHP-Enum-Behavior ${CEBVER} tarball..." else echo "Retrieving CakePHP-Enum-Behavior ${CEBVER} submodule..." - curl -L https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/v${CEBVER}.tar.gz > build/crud-${CEBVER}.tar.gz + curl -L https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/v${CEBVER}.tar.gz > build/cakephp-enum-behavior-${CEBVER}.tar.gz if [ $? -ne 0 ]; then echo "ERROR: Crud tarball retreival failed..." exit 1 From 087fcc6c784a3aeab872dc91a51880e9f3aa0b54 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 19 Apr 2018 20:23:17 -0500 Subject: [PATCH 078/154] update buildsystem --- utils/packpack/startpackpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 46f6f2356..e8fa9c862 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -142,7 +142,7 @@ commonprep () { echo "Found existing CakePHP-Enum-Behavior ${CEBVER} tarball..." else echo "Retrieving CakePHP-Enum-Behavior ${CEBVER} submodule..." - curl -L https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/v${CEBVER}.tar.gz > build/cakephp-enum-behavior-${CEBVER}.tar.gz + curl -L https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/${CEBVER}.tar.gz > build/cakephp-enum-behavior-${CEBVER}.tar.gz if [ $? -ne 0 ]; then echo "ERROR: Crud tarball retreival failed..." exit 1 From 85ba5254963ce20857694765ccf7947d548bca5e Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 19 Apr 2018 20:41:11 -0500 Subject: [PATCH 079/154] rpm spec file - use %{_sourcedir} macro --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index e3d019a4b..d69469cd0 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -151,7 +151,7 @@ too much degradation of performance. %{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud # The all powerful autosetup macro does not work after the second source tarball -%{__gzip} -dc %{_topdir}/SOURCES/cakephp-enum-behavior-%{ceb_version}.tar.gz | tar -xvvf - +%{__gzip} -dc %{_sourcedir}/cakephp-enum-behavior-%{ceb_version}.tar.gz | tar -xvvf - %{__rm} -rf ./web/api/app/Plugin/CakePHP-Enum-Behavior %{__mv} -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Behavior From 914c608dbc2defaf91f28a60f34a4ac193b96b62 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Apr 2018 08:54:25 -0400 Subject: [PATCH 080/154] get rid of stored procedure. Do everything in the Trigger --- db/triggers.sql | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/db/triggers.sql b/db/triggers.sql index c7a6eb38b..2f13be435 100644 --- a/db/triggers.sql +++ b/db/triggers.sql @@ -60,7 +60,6 @@ FOR EACH ROW // -delimiter // DROP TRIGGER IF EXISTS Events_Week_delete_trigger// CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week FOR EACH ROW BEGIN @@ -89,9 +88,6 @@ FOR EACH ROW END; // -DELIMITER ; - -delimiter // DROP TRIGGER IF EXISTS Events_Month_delete_trigger// CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month FOR EACH ROW BEGIN @@ -120,39 +116,26 @@ FOR EACH ROW END; // -drop procedure if exists update_storage_stats; -create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT) - -sql security invoker - -deterministic - -begin - - update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; - -end; - -// +drop procedure if exists update_storage_stats// drop trigger if exists event_update_trigger// CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events FOR EACH ROW BEGIN - declare diff BIGINT default 0; + declare diff BIGINT default 0; - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( NEW.StorageId = OLD.StorageID ) THEN IF ( diff ) THEN - call update_storage_stats(OLD.StorageId, diff); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + diff WHERE Id = OLD.StorageId; END IF; ELSE IF ( NEW.DiskSpace ) THEN - call update_storage_stats(NEW.StorageId, NEW.DiskSpace); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + NEW.DiskSpace WHERE Id = NEW.StorageId; END IF; IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) - OLD.DiskSpace WHERE Id = OLD.StorageId; END IF; END IF; @@ -220,7 +203,7 @@ CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events FOR EACH ROW BEGIN IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) - CAST(OLD.DiskSpace AS SIGNED) WHERE Id = OLD.StorageId; END IF; DELETE FROM Events_Hour WHERE EventId=OLD.Id; DELETE FROM Events_Day WHERE EventId=OLD.Id; From 970830aee388ee01c18088dc7021127ed13a59a5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Apr 2018 13:10:38 -0400 Subject: [PATCH 081/154] tidy up --- .../classic/includes/timeline_functions.php | 898 +++++++++--------- web/skins/classic/views/timeline.php | 137 ++- 2 files changed, 539 insertions(+), 496 deletions(-) diff --git a/web/skins/classic/includes/timeline_functions.php b/web/skins/classic/includes/timeline_functions.php index ee3b64808..b5cc3909c 100644 --- a/web/skins/classic/includes/timeline_functions.php +++ b/web/skins/classic/includes/timeline_functions.php @@ -1,494 +1,538 @@ "; - if ( $scaleRange >= $minLines ) { - $scale['range'] = $scaleRange; - break; - } - } - if ( !isset($scale['range']) ) { - $scale['range'] = (int)($range/($scale['factor']*$align)); - } - $scale['divisor'] = 1; - while ( ($scale['range']/$scale['divisor']) > $maxLines ) { - $scale['divisor']++; - } - $scale['lines'] = (int)($scale['range']/$scale['divisor']); - return( $scale ); + foreach ( $scales as $scale ) { + $align = isset($scale['align'])?$scale['align']:1; + $scaleRange = (int)($range/($scale['factor']*$align)); + //echo "S:".$scale['name'].", A:$align, SR:$scaleRange
    "; + if ( $scaleRange >= $minLines ) { + $scale['range'] = $scaleRange; + break; + } + } + if ( !isset($scale['range']) ) { + $scale['range'] = (int)($range/($scale['factor']*$align)); + } + $scale['divisor'] = 1; + while ( ($scale['range']/$scale['divisor']) > $maxLines ) { + $scale['divisor']++; + } + $scale['lines'] = (int)($scale['range']/$scale['divisor']); + return( $scale ); } function getYScale( $range, $minLines, $maxLines ) { - $scale['range'] = $range; - $scale['divisor'] = 1; - while ( $scale['range']/$scale['divisor'] > $maxLines ) { - $scale['divisor']++; - } - $scale['lines'] = (int)(($scale['range']-1)/$scale['divisor'])+1; + $scale['range'] = $range; + $scale['divisor'] = 1; + while ( $scale['range']/$scale['divisor'] > $maxLines ) { + $scale['divisor']++; + } + $scale['lines'] = (int)(($scale['range']-1)/$scale['divisor'])+1; - return( $scale ); + return( $scale ); } function getSlotFrame( $slot ) { - $slotFrame = isset($slot['frame'])?$slot['frame']['FrameId']:1; - if ( false && $slotFrame ) { - $slotFrame -= $monitor['PreEventCount']; - if ( $slotFrame < 1 ) - $slotFrame = 1; - } - return( $slotFrame ); + $slotFrame = isset($slot['frame'])?$slot['frame']['FrameId']:1; + if ( false && $slotFrame ) { + $slotFrame -= $monitor['PreEventCount']; + if ( $slotFrame < 1 ) + $slotFrame = 1; + } + return( $slotFrame ); } function parseFilterToTree( $filter ) { - if ( count($filter['terms']) > 0 ) { - $postfixExpr = array(); - $postfixStack = array(); + if ( count($filter['terms']) <= 0 ) { + return false; + } + $terms = $filter['terms']; - $priorities = array( - '<' => 1, - '<=' => 1, - '>' => 1, - '>=' => 1, - '=' => 2, - '!=' => 2, - '=~' => 2, - '!~' => 2, - '=[]' => 2, - '![]' => 2, - 'and' => 3, - 'or' => 4, - ); + $StorageArea = NULL; - for ( $i = 0; $i <= count($filter['terms']); $i++ ) { - if ( !empty($filter['terms'][$i]['cnj']) ) { - while( true ) { - if ( !count($postfixStack) ) { - $postfixStack[] = array( 'type'=>"cnj", 'value'=>$filter['terms'][$i]['cnj'], 'sqlValue'=>$filter['terms'][$i]['cnj']); - break; - } elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) { - $postfixStack[] = array( 'type'=>"cnj", 'value'=>$filter['terms'][$i]['cnj'], 'sqlValue'=>$filter['terms'][$i]['cnj']); - break; - } elseif ( $priorities[$filter['terms'][$i]['cnj']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) { - $postfixStack[] = array( 'type'=>"cnj", 'value'=>$filter['terms'][$i]['cnj'], 'sqlValue'=>$filter['terms'][$i]['cnj']); - break; - } else { - $postfixExpr[] = array_pop( $postfixStack ); - } - } - } - if ( !empty($filter['terms'][$i]['obr']) ) - { - for ( $j = 0; $j < $filter['terms'][$i]['obr']; $j++ ) - { - $postfixStack[] = array( 'type'=>"obr", 'value'=>$filter['terms'][$i]['obr']); - } - } - if ( !empty($filter['terms'][$i]['attr']) ) - { - $dtAttr = false; - switch ( $filter['terms'][$i]['attr']) - { - case 'MonitorName': - $sqlValue = 'M.'.preg_replace( '/^Monitor/', '', $filter['terms'][$i]['attr']); - break; - case 'Name': - $sqlValue = "E.Name"; - break; - case 'Cause': - $sqlValue = "E.Cause"; - break; - case 'DateTime': - $sqlValue = "E.StartTime"; - $dtAttr = true; - break; - case 'StartDateTime': - $sqlValue = "E.StartTime"; - $dtAttr = true; - break; - case 'Date': - $sqlValue = "to_days( E.StartTime )"; - $dtAttr = true; - break; - case 'Time': - $sqlValue = "extract( hour_second from E.StartTime )"; - break; - case 'Weekday': - $sqlValue = "weekday( E.StartTime )"; - break; - case 'Id': - case 'Name': - case 'MonitorId': - case 'Length': - case 'Frames': - case 'AlarmFrames': - case 'TotScore': - case 'AvgScore': - case 'MaxScore': - case 'Archived': - $sqlValue = "E.".$filter['terms'][$i]['attr']; - break; - case 'DiskPercent': - $sqlValue = getDiskPercent(); - break; - case 'DiskBlocks': - $sqlValue = getDiskBlocks(); - break; - default : - $sqlValue = $filter['terms'][$i]['attr']; - break; - } - if ( $dtAttr ) { - $postfixExpr[] = array( 'type'=>"attr", 'value'=>$filter['terms'][$i]['attr'], 'sqlValue'=>$sqlValue, 'dtAttr'=>true ); - } else { - $postfixExpr[] = array( 'type'=>"attr", 'value'=>$filter['terms'][$i]['attr'], 'sqlValue'=>$sqlValue ); - } - } - if ( isset($filter['terms'][$i]['op']) ) { - if ( empty($filter['terms'][$i]['op']) ) { - $filter['terms'][$i]['op' ]= '='; - } - switch ( $filter['terms'][$i]['op' ]) { - case '=' : - case '!=' : - case '>=' : - case '>' : - case '<' : - case '<=' : - $sqlValue = $filter['terms'][$i]['op']; - break; - case '=~' : - $sqlValue = "regexp"; - break; - case '!~' : - $sqlValue = "not regexp"; - break; - case '=[]' : - $sqlValue = 'in ('; - break; - case '![]' : - $sqlValue = 'not in ('; - break; - } - while( true ) { - if ( !count($postfixStack) ) { - $postfixStack[] = array( 'type'=>"op", 'value'=>$filter['terms'][$i]['op'], 'sqlValue'=>$sqlValue ); - break; - } elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) { - $postfixStack[] = array( 'type'=>"op", 'value'=>$filter['terms'][$i]['op'], 'sqlValue'=>$sqlValue ); - break; - } elseif ( $priorities[$filter['terms'][$i]['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) { - $postfixStack[] = array( 'type'=>"op", 'value'=>$filter['terms'][$i]['op'], 'sqlValue'=>$sqlValue ); - break; - } else { - $postfixExpr[] = array_pop( $postfixStack ); - } - } - } - if ( isset($filter['terms'][$i]['val']) ) { - $valueList = array(); - foreach ( preg_split( '/["\'\s]*?,["\'\s]*?/', preg_replace( '/^["\']+?(.+)["\']+?$/', '$1', $filter['terms'][$i]['val' ]) ) as $value ) { - switch ( $filter['terms'][$i]['attr']) { - case 'MonitorName': - case 'Name': - case 'Cause': - case 'Notes': - $value = "'$value'"; - break; - case 'DateTime': - $value = "'".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."'"; - break; - case 'StartDateTime': - $value = "'".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."'"; - break; - case 'Date': - $value = "to_days( '".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."' )"; - break; - case 'Time': - $value = "extract( hour_second from '".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."' )"; - break; - case 'Weekday': - $value = "weekday( '".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."' )"; - break; - } - $valueList[] = $value; - } - $postfixExpr[] = array( 'type'=>"val", 'value'=>$filter['terms'][$i]['val'], 'sqlValue'=>join( ',', $valueList ) ); - } - if ( !empty($filter['terms'][$i]['cbr']) ) - { - for ( $j = 0; $j < $filter['terms'][$i]['cbr']; $j++ ) - { - while ( count($postfixStack) ) - { - $element = array_pop( $postfixStack ); - if ( $element['type'] == "obr" ) - { - $postfixExpr[count($postfixExpr)-1]['bracket'] = true; - break; - } - $postfixExpr[] = $element; - } - } - } - } - while ( count($postfixStack) ) - { - $postfixExpr[] = array_pop( $postfixStack ); - } + $postfixExpr = array(); + $postfixStack = array(); - $exprStack = array(); - //foreach ( $postfixExpr as $element ) - //{ - //echo $element['value']." "; - //} - //echo "
    "; - foreach ( $postfixExpr as $element ) - { - if ( $element['type'] == 'attr' || $element['type'] == 'val' ) - { - $node = array( 'data'=>$element, 'count'=>0 ); - $exprStack[] = $node; - } - elseif ( $element['type'] == 'op' || $element['type'] == 'cnj' ) - { - $right = array_pop( $exprStack ); - $left = array_pop( $exprStack ); - $node = array( 'data'=>$element, 'count'=>2+$left['count']+$right['count'], 'right'=>$right, 'left'=>$left ); - $exprStack[] = $node; - } - else - { - Fatal( "Unexpected element type '".$element['type']."', value '".$element['value']."'" ); - } - } - if ( count($exprStack) != 1 ) - { - Fatal( "Expression stack has ".count($exprStack)." elements" ); - } - $exprTree = array_pop( $exprStack ); - return( $exprTree ); - } - return( false ); + $priorities = array( + '<' => 1, + '<=' => 1, + '>' => 1, + '>=' => 1, + '=' => 2, + '!=' => 2, + '=~' => 2, + '!~' => 2, + '=[]' => 2, + '![]' => 2, + 'and' => 3, + 'or' => 4, + ); + + for ( $i = 0; $i <= count($terms); $i++ ) { + if ( !empty($terms[$i]['cnj']) ) { + while( true ) { + if ( !count($postfixStack) ) { + $postfixStack[] = array('type'=>'cnj', 'value'=>$terms[$i]['cnj'], 'sqlValue'=>$terms[$i]['cnj']); + break; + } elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) { + $postfixStack[] = array('type'=>'cnj', 'value'=>$terms[$i]['cnj'], 'sqlValue'=>$terms[$i]['cnj']); + break; + } elseif ( $priorities[$terms[$i]['cnj']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) { + $postfixStack[] = array('type'=>'cnj', 'value'=>$terms[$i]['cnj'], 'sqlValue'=>$terms[$i]['cnj']); + break; + } else { + $postfixExpr[] = array_pop($postfixStack); + } + } + } + if ( !empty($terms[$i]['obr']) ) { + for ( $j = 0; $j < $terms[$i]['obr']; $j++ ) { + $postfixStack[] = array('type'=>'obr', 'value'=>$terms[$i]['obr']); + } + } + if ( !empty($terms[$i]['attr']) ) { + $dtAttr = false; + switch ( $terms[$i]['attr']) { + case 'MonitorName': + $sqlValue = 'M.'.preg_replace( '/^Monitor/', '', $terms[$i]['attr']); + break; + case 'ServerId': + $sqlValue .= 'M.ServerId'; + break; + case 'DateTime': + case 'StartDateTime': + $sqlValue = "E.StartTime"; + $dtAttr = true; + break; + case 'Date': + case 'StartDate': + $sqlValue = "to_days( E.StartTime )"; + $dtAttr = true; + break; + case 'Time': + case 'StartTime': + $sqlValue = "extract( hour_second from E.StartTime )"; + break; + case 'Weekday': + case 'StartWeekday': + $sqlValue = "weekday( E.StartTime )"; + break; + case 'EndDateTime': + $sqlValue = "E.EndTime"; + $dtAttr = true; + break; + case 'EndDate': + $sqlValue = "to_days( E.EndTime )"; + $dtAttr = true; + break; + case 'EndTime': + $sqlValue = "extract( hour_second from E.EndTime )"; + break; + case 'EndWeekday': + $sqlValue = "weekday( E.EndTime )"; + break; + case 'Id': + case 'Name': + case 'MonitorId': + case 'StorageId': + case 'Length': + case 'Frames': + case 'AlarmFrames': + case 'TotScore': + case 'AvgScore': + case 'MaxScore': + case 'Cause': + case 'Notes': + case 'StateId': + case 'Archived': + $sqlValue = "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($terms); $j++ ) { + if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) { + $StorageArea = new Storage($terms[$j]['val']); + break; + } + } // end foreach remaining term + if ( ! $StorageArea ) $StorageArea = new Storage(); + } // end no StorageArea found yet + $sqlValue = getDiskPercent($StorageArea); + break; + 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 = 0; $j < count($terms); $j++ ) { + if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' and isset($terms[$j]['val']) ) { + $StorageArea = new Storage($terms[$j]['val']); + break; + } + } // end foreach remaining term + if ( ! $StorageArea ) $StorageArea = new Storage(); + } // end no StorageArea found yet + $sqlValue = getDiskBlocks($StorageArea); + break; + default : + $sqlValue = $terms[$i]['attr']; + break; + } + if ( $dtAttr ) { + $postfixExpr[] = array('type'=>'attr', 'value'=>$terms[$i]['attr'], 'sqlValue'=>$sqlValue, 'dtAttr'=>true); + } else { + $postfixExpr[] = array('type'=>'attr', 'value'=>$terms[$i]['attr'], 'sqlValue'=>$sqlValue); + } + } # end if attr + + if ( isset($terms[$i]['op']) ) { + if ( empty($terms[$i]['op']) ) { + $terms[$i]['op'] = '='; + } + switch ( $terms[$i]['op']) { + case '=' : + case '!=' : + case '>=' : + case '>' : + case '<' : + case '<=' : + $sqlValue = $terms[$i]['op']; + break; + case '=~' : + $sqlValue = 'regexp'; + break; + case '!~' : + $sqlValue = 'not regexp'; + break; + case '=[]' : + $sqlValue = 'in ('; + break; + case '![]' : + $sqlValue = 'not in ('; + break; + default : + Error('Unknown operator in filter '. $terms[$i]['op']); + } + while( true ) { + if ( !count($postfixStack) ) { + $postfixStack[] = array('type'=>'op', 'value'=>$terms[$i]['op'], 'sqlValue'=>$sqlValue); + break; + } elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) { + $postfixStack[] = array('type'=>'op', 'value'=>$terms[$i]['op'], 'sqlValue'=>$sqlValue); + break; + } elseif ( $priorities[$terms[$i]['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) { + $postfixStack[] = array('type'=>'op', 'value'=>$terms[$i]['op'], 'sqlValue'=>$sqlValue ); + break; + } else { + $postfixExpr[] = array_pop($postfixStack); + } + } // end while + } // end if operator + + if ( isset($terms[$i]['val']) ) { + $valueList = array(); + foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $terms[$i]['val'])) as $value ) { + switch ( $terms[$i]['attr'] ) { + case 'MonitorName': + case 'Name': + case 'Cause': + case 'Notes': + $value = "'$value'"; + break; + case 'ServerId': + if ( $value == 'ZM_SERVER_ID' ) { + $value = ZM_SERVER_ID; + } else if ( $value == 'NULL' ) { + + } else { + $value = dbEscape($value); + } + break; + case 'StorageId': + $StorageArea = new Storage($value); + if ( $value != 'NULL' ) + $value = dbEscape($value); + break; + case 'DateTime': + case 'EndDateTime': + case 'StartDateTime': + $value = "'".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."'"; + break; + case 'Date': + case 'EndDate': + case 'StartDate': + $value = "to_days('".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."' )"; + break; + case 'Time': + case 'EndTime': + case 'StartTime': + $value = "extract( hour_second from '".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."' )"; + break; + case 'Weekday': + case 'EndWeekday': + case 'StartWeekday': + $value = "weekday( '".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."' )"; + break; + default : + if ( $value != 'NULL' ) + $value = dbEscape($value); + } // end switch attribute + $valueList[] = $value; + } // end foreach value + $postfixExpr[] = array('type'=>'val', 'value'=>$terms[$i]['val'], 'sqlValue'=>join(',', $valueList)); + } // end if has val + + if ( !empty($terms[$i]['cbr']) ) { + for ( $j = 0; $j < $terms[$i]['cbr']; $j++ ) { + while ( count($postfixStack) ) { + $element = array_pop($postfixStack); + if ( $element['type'] == 'obr' ) { + $postfixExpr[count($postfixExpr)-1]['bracket'] = true; + break; + } + $postfixExpr[] = $element; + } + } + } + } + while ( count($postfixStack) ) { + $postfixExpr[] = array_pop($postfixStack); + } + + $exprStack = array(); + //foreach ( $postfixExpr as $element ) + //{ + //echo $element['value'].' '; + //} + //echo "
    "; + foreach ( $postfixExpr as $element ) { + if ( $element['type'] == 'attr' || $element['type'] == 'val' ) { + $node = array('data'=>$element, 'count'=>0); + $exprStack[] = $node; + } elseif ( $element['type'] == 'op' || $element['type'] == 'cnj' ) { + $right = array_pop($exprStack); + $left = array_pop($exprStack); + $node = array('data'=>$element, 'count'=>2+$left['count']+$right['count'], 'right'=>$right, 'left'=>$left); + $exprStack[] = $node; + } else { + Fatal("Unexpected element type '".$element['type']."', value '".$element['value']."'"); + } + } + if ( count($exprStack) != 1 ) { + Fatal('Expression stack has '.count($exprStack).' elements'); + } + return array_pop($exprStack); } -function _parseTreeToInfix( $node ) -{ - $expression = ''; - if ( isset($node) ) - { - if ( isset($node['left']) ) - { - if ( !empty($node['data']['bracket']) ) - $expression .= '( '; - $expression .= _parseTreeToInfix( $node['left'] ); - } - $expression .= $node['data']['value']." "; - if ( isset($node['right']) ) - { - $expression .= _parseTreeToInfix( $node['right'] ); - if ( !empty($node['data']['bracket']) ) - $expression .= ') '; - } - } - return( $expression ); +function _parseTreeToInfix($node) { + $expression = ''; + if ( isset($node) ) { + if ( isset($node['left']) ) { + if ( !empty($node['data']['bracket']) ) + $expression .= '( '; + $expression .= _parseTreeToInfix($node['left']); + } + $expression .= $node['data']['value'].' '; + if ( isset($node['right']) ) { + $expression .= _parseTreeToInfix($node['right']); + if ( !empty($node['data']['bracket']) ) + $expression .= ') '; + } + } + return $expression; } -function parseTreeToInfix( $tree ) -{ - return( _parseTreeToInfix( $tree ) ); +function parseTreeToInfix($tree) { + return _parseTreeToInfix($tree); } function _parseTreeToSQL( $node, $cbr=false ) { - $expression = ''; - if ( $node ) - { - if ( isset($node['left']) ) - { - if ( !empty($node['data']['bracket']) ) - $expression .= '( '; - $expression .= _parseTreeToSQL( $node['left'] ); - } - $inExpr = $node['data']['type'] == 'op' && ($node['data']['value'] == '=[]' || $node['data']['value'] == '![]'); - $expression .= $node['data']['sqlValue']; - if ( !$inExpr ) - $expression .= ' '; - if ( $cbr ) - $expression .= ') '; - if ( isset($node['right']) ) - { - $expression .= _parseTreeToSQL( $node['right'], $inExpr ); - if ( !empty($node['data']['bracket']) ) - $expression .= ') '; - } - } - return( $expression ); + $expression = ''; + if ( $node ) + { + if ( isset($node['left']) ) + { + if ( !empty($node['data']['bracket']) ) + $expression .= '( '; + $expression .= _parseTreeToSQL( $node['left'] ); + } + $inExpr = $node['data']['type'] == 'op' && ($node['data']['value'] == '=[]' || $node['data']['value'] == '![]'); + $expression .= $node['data']['sqlValue']; + if ( !$inExpr ) + $expression .= ' '; + if ( $cbr ) + $expression .= ') '; + if ( isset($node['right']) ) + { + $expression .= _parseTreeToSQL( $node['right'], $inExpr ); + if ( !empty($node['data']['bracket']) ) + $expression .= ') '; + } + } + return( $expression ); } function parseTreeToSQL( $tree ) { - return( _parseTreeToSQL( $tree ) ); + return( _parseTreeToSQL( $tree ) ); } function _parseTreeToFilter( $node, &$terms, &$level ) { - $elements = array(); - if ( $node ) - { - if ( isset($node['left']) ) - { - if ( !empty($node['data']['bracket']) ) - $terms[$level]['obr'] = 1; - _parseTreeToFilter( $node['left'], $terms, $level ); - } - if ( $node['data']['type'] == 'cnj' ) - { - $level++; - } - $terms[$level][$node['data']['type']] = $node['data']['value']; - if ( isset($node['right']) ) - { - _parseTreeToFilter( $node['right'], $terms, $level ); - if ( !empty($node['data']['bracket']) ) - $terms[$level]['cbr'] = 1; - } - } + $elements = array(); + if ( $node ) + { + if ( isset($node['left']) ) + { + if ( !empty($node['data']['bracket']) ) + $terms[$level]['obr'] = 1; + _parseTreeToFilter( $node['left'], $terms, $level ); + } + if ( $node['data']['type'] == 'cnj' ) + { + $level++; + } + $terms[$level][$node['data']['type']] = $node['data']['value']; + if ( isset($node['right']) ) + { + _parseTreeToFilter( $node['right'], $terms, $level ); + if ( !empty($node['data']['bracket']) ) + $terms[$level]['cbr'] = 1; + } + } } function parseTreeToFilter( $tree ) { - $terms = array(); - if ( isset($tree) ) - { - $level = 0; - _parseTreeToFilter( $tree, $terms, $level ); - } - return( array( 'Query' => array( 'terms' => $terms ) ) ); + $terms = array(); + if ( isset($tree) ) + { + $level = 0; + _parseTreeToFilter( $tree, $terms, $level ); + } + return( array( 'Query' => array( 'terms' => $terms ) ) ); } function parseTreeToQuery( $tree ) { - $filter = parseTreeToFilter( $tree ); - parseFilter( $filter, false, '&' ); - return( $filter['query'] ); + $filter = parseTreeToFilter( $tree ); + parseFilter( $filter, false, '&' ); + return( $filter['query'] ); } function _drawTree( $node, $level ) { - if ( isset($node['left']) ) - { - _drawTree( $node['left'], $level+1 ); - } - echo str_repeat( ".", $level*2 ).$node['data']['value']."
    "; - if ( isset($node['right']) ) - { - _drawTree( $node['right'], $level+1 ); - } + if ( isset($node['left']) ) + { + _drawTree( $node['left'], $level+1 ); + } + echo str_repeat( ".", $level*2 ).$node['data']['value']."
    "; + if ( isset($node['right']) ) + { + _drawTree( $node['right'], $level+1 ); + } } function drawTree( $tree ) { - _drawTree( $tree, 0 ); + _drawTree( $tree, 0 ); } function _extractDatetimeRange( &$node, &$minTime, &$maxTime, &$expandable, $subOr ) { - $pruned = $leftPruned = $rightPruned = false; - if ( $node ) - { - if ( isset($node['left']) && isset($node['right']) ) - { - if ( $node['data']['type'] == 'cnj' && $node['data']['value'] == 'or' ) - { - $subOr = true; - } - elseif ( !empty($node['left']['data']['dtAttr']) ) - { - if ( $subOr ) - { - $expandable = false; - } - elseif ( $node['data']['type'] == 'op' ) - { - if ( $node['data']['value'] == '>' || $node['data']['value'] == '>=' ) - { - if ( !$minTime || $minTime > $node['right']['data']['sqlValue'] ) - { - $minTime = $node['right']['data']['value']; - return( true ); - } - } - if ( $node['data']['value'] == '<' || $node['data']['value'] == '<=' ) - { - if ( !$maxTime || $maxTime < $node['right']['data']['sqlValue'] ) - { - $maxTime = $node['right']['data']['value']; - return( true ); - } - } - } - else - { - Fatal( "Unexpected node type '".$node['data']['type']."'" ); - } - return( false ); - } + $pruned = $leftPruned = $rightPruned = false; + if ( $node ) + { + if ( isset($node['left']) && isset($node['right']) ) + { + if ( $node['data']['type'] == 'cnj' && $node['data']['value'] == 'or' ) + { + $subOr = true; + } + elseif ( !empty($node['left']['data']['dtAttr']) ) + { + if ( $subOr ) + { + $expandable = false; + } + elseif ( $node['data']['type'] == 'op' ) + { + if ( $node['data']['value'] == '>' || $node['data']['value'] == '>=' ) + { + if ( !$minTime || $minTime > $node['right']['data']['sqlValue'] ) + { + $minTime = $node['right']['data']['value']; + return( true ); + } + } + if ( $node['data']['value'] == '<' || $node['data']['value'] == '<=' ) + { + if ( !$maxTime || $maxTime < $node['right']['data']['sqlValue'] ) + { + $maxTime = $node['right']['data']['value']; + return( true ); + } + } + } + else + { + Fatal( "Unexpected node type '".$node['data']['type']."'" ); + } + return( false ); + } - $leftPruned = _extractDatetimeRange( $node['left'], $minTime, $maxTime, $expandable, $subOr ); - $rightPruned = _extractDatetimeRange( $node['right'], $minTime, $maxTime, $expandable, $subOr ); + $leftPruned = _extractDatetimeRange( $node['left'], $minTime, $maxTime, $expandable, $subOr ); + $rightPruned = _extractDatetimeRange( $node['right'], $minTime, $maxTime, $expandable, $subOr ); - if ( $leftPruned && $rightPruned ) - { - $pruned = true; - } - elseif ( $leftPruned ) - { - $node = $node['right']; - } - elseif ( $rightPruned ) - { - $node = $node['left']; - } - } - } - return( $pruned ); + if ( $leftPruned && $rightPruned ) + { + $pruned = true; + } + elseif ( $leftPruned ) + { + $node = $node['right']; + } + elseif ( $rightPruned ) + { + $node = $node['left']; + } + } + } + return( $pruned ); } function extractDatetimeRange( &$tree, &$minTime, &$maxTime, &$expandable ) { - $minTime = ""; - $maxTime = ""; - $expandable = true; + $minTime = ""; + $maxTime = ""; + $expandable = true; - _extractDateTimeRange( $tree, $minTime, $maxTime, $expandable, false ); + _extractDateTimeRange( $tree, $minTime, $maxTime, $expandable, false ); } function appendDatetimeRange( &$tree, $minTime, $maxTime=false ) { - $attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 ); - $valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$minTime, 'sqlValue'=>$minTime ), 'count'=>0 ); - $opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'>=', 'sqlValue'=>'>=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode ); - if ( isset($tree) ) - { - $cnjNode = array( 'data'=>array( 'type'=>'cnj', 'value'=>'and', 'sqlValue'=>'and' ), 'count'=>2+$tree['count']+$opNode['count'], 'left'=>$tree, 'right'=>$opNode ); - $tree = $cnjNode; - } - else - { - $tree = $opNode; - } + $attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 ); + $valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$minTime, 'sqlValue'=>$minTime ), 'count'=>0 ); + $opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'>=', 'sqlValue'=>'>=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode ); + if ( isset($tree) ) + { + $cnjNode = array( 'data'=>array( 'type'=>'cnj', 'value'=>'and', 'sqlValue'=>'and' ), 'count'=>2+$tree['count']+$opNode['count'], 'left'=>$tree, 'right'=>$opNode ); + $tree = $cnjNode; + } + else + { + $tree = $opNode; + } - if ( $maxTime ) - { - $attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 ); - $valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$maxTime, 'sqlValue'=>$maxTime ), 'count'=>0 ); - $opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'<=', 'sqlValue'=>'<=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode ); - $cnjNode = array( 'data'=>array( 'type'=>'cnj', 'value'=>'and', 'sqlValue'=>'and' ), 'count'=>2+$tree['count']+$opNode['count'], 'left'=>$tree, 'right'=>$opNode ); - $tree = $cnjNode; - } + if ( $maxTime ) + { + $attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 ); + $valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$maxTime, 'sqlValue'=>$maxTime ), 'count'=>0 ); + $opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'<=', 'sqlValue'=>'<=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode ); + $cnjNode = array( 'data'=>array( 'type'=>'cnj', 'value'=>'and', 'sqlValue'=>'and' ), 'count'=>2+$tree['count']+$opNode['count'], 'left'=>$tree, 'right'=>$opNode ); + $tree = $cnjNode; + } } ?> diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index 61c7170b5..7cb07f026 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -142,7 +142,8 @@ foreach( dbFetchAll( $monitorsSql ) as $row ) { # The as E, and joining with Monitors is required for the filterSQL filters. $rangeSql = 'SELECT min(E.StartTime) AS MinTime, max(E.EndTime) AS MaxTime FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(E.StartTime) AND NOT isnull(E.EndTime)'; -$eventsSql = 'SELECT * FROM Events AS E WHERE NOT isnull(StartTime)'; +$eventsSql = 'SELECT * FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(StartTime)'; +$eventsValues = array(); if ( !empty($user['MonitorIds']) ) { $monFilterSql = ' AND MonitorId IN ('.$user['MonitorIds'].')'; @@ -152,7 +153,7 @@ if ( !empty($user['MonitorIds']) ) { } if ( isset($_REQUEST['filter']) ) - $tree = parseFilterToTree( $_REQUEST['filter']['Query'] ); + $tree = parseFilterToTree($_REQUEST['filter']['Query']); else $tree = false; @@ -200,27 +201,27 @@ if ( isset($range) ) { if ( isset($minTime) && isset($maxTime) ) { $tempMinTime = $tempMaxTime = $tempExpandable = false; - extractDatetimeRange( $tree, $tempMinTime, $tempMaxTime, $tempExpandable ); - $filterSql = parseTreeToSQL( $tree ); + extractDatetimeRange($tree, $tempMinTime, $tempMaxTime, $tempExpandable); + $filterSql = parseTreeToSQL($tree); if ( $filterSql ) { - $filterSql = " and $filterSql"; + $filterSql = " AND $filterSql"; $eventsSql .= $filterSql; } } else { - $filterSql = parseTreeToSQL( $tree ); + $filterSql = parseTreeToSQL($tree); $tempMinTime = $tempMaxTime = $tempExpandable = false; - extractDatetimeRange( $tree, $tempMinTime, $tempMaxTime, $tempExpandable ); + extractDatetimeRange($tree, $tempMinTime, $tempMaxTime, $tempExpandable); if ( $filterSql ) { - $filterSql = " and $filterSql"; + $filterSql = " AND $filterSql"; $rangeSql .= $filterSql; $eventsSql .= $filterSql; } if ( !isset($minTime) || !isset($maxTime) ) { // Dynamically determine range - $row = dbFetchOne( $rangeSql ); + $row = dbFetchOne($rangeSql); if ( !isset($minTime) ) $minTime = $row['MinTime']; @@ -233,7 +234,7 @@ if ( isset($minTime) && isset($maxTime) ) { if ( empty($maxTime) ) $maxTime = $tempMaxTime; if ( empty($maxTime) ) - $maxTime = "now"; + $maxTime = 'now'; $minTimeT = strtotime($minTime); $maxTimeT = strtotime($maxTime); @@ -253,16 +254,16 @@ if ( $tree ) { } $scales = array( - array( 'name'=>"year", 'factor'=>60*60*24*365, 'align'=>1, 'zoomout'=>2, 'label'=>STRF_TL_AXIS_LABEL_YEAR ), - array( 'name'=>"month", 'factor'=>60*60*24*30, 'align'=>1, 'zoomout'=>12, 'label'=>STRF_TL_AXIS_LABEL_MONTH ), - array( 'name'=>"week", 'factor'=>60*60*24*7, 'align'=>1, 'zoomout'=>4.25, 'label'=>STRF_TL_AXIS_LABEL_WEEK, 'labelCheck'=>"%W" ), - array( 'name'=>"day", 'factor'=>60*60*24, 'align'=>1, 'zoomout'=>7, 'label'=>STRF_TL_AXIS_LABEL_DAY ), + array( 'name'=>'year', 'factor'=>60*60*24*365, 'align'=>1, 'zoomout'=>2, 'label'=>STRF_TL_AXIS_LABEL_YEAR ), + array( 'name'=>'month', 'factor'=>60*60*24*30, 'align'=>1, 'zoomout'=>12, 'label'=>STRF_TL_AXIS_LABEL_MONTH ), + array( 'name'=>'week', 'factor'=>60*60*24*7, 'align'=>1, 'zoomout'=>4.25, 'label'=>STRF_TL_AXIS_LABEL_WEEK, 'labelCheck'=>"%W" ), + array( 'name'=>'day', 'factor'=>60*60*24, 'align'=>1, 'zoomout'=>7, 'label'=>STRF_TL_AXIS_LABEL_DAY ), array( 'name'=>"hour4", 'factor'=>60*60, 'align'=>4, 'zoomout'=>6, 'label'=>STRF_TL_AXIS_LABEL_4HOUR, 'labelCheck'=>"%H" ), - array( 'name'=>"hour", 'factor'=>60*60, 'align'=>1, 'zoomout'=>4, 'label'=>STRF_TL_AXIS_LABEL_HOUR, 'labelCheck'=>"%H" ), + array( 'name'=>'hour', 'factor'=>60*60, 'align'=>1, 'zoomout'=>4, 'label'=>STRF_TL_AXIS_LABEL_HOUR, 'labelCheck'=>"%H" ), array( 'name'=>"minute10", 'factor'=>60, 'align'=>10, 'zoomout'=>6, 'label'=>STRF_TL_AXIS_LABEL_10MINUTE, 'labelCheck'=>"%M" ), - array( 'name'=>"minute", 'factor'=>60, 'align'=>1, 'zoomout'=>10, 'label'=>STRF_TL_AXIS_LABEL_MINUTE, 'labelCheck'=>"%M" ), + array( 'name'=>'minute', 'factor'=>60, 'align'=>1, 'zoomout'=>10, 'label'=>STRF_TL_AXIS_LABEL_MINUTE, 'labelCheck'=>"%M" ), array( 'name'=>"second10", 'factor'=>1, 'align'=>10, 'zoomout'=>6, 'label'=>STRF_TL_AXIS_LABEL_10SECOND ), - array( 'name'=>"second", 'factor'=>1, 'align'=>1, 'zoomout'=>10, 'label'=>STRF_TL_AXIS_LABEL_SECOND ), + array( 'name'=>'second', 'factor'=>1, 'align'=>1, 'zoomout'=>10, 'label'=>STRF_TL_AXIS_LABEL_SECOND ), ); $majXScale = getDateScale( $scales, $range, $chart['grid']['x']['major']['min'], $chart['grid']['x']['major']['max'] ); @@ -288,10 +289,10 @@ $midTime = strftime( STRF_FMT_DATETIME_DB, $midTimeT ); //echo "MxTt:$maxTimeT
    "; if ( isset($minTime) && isset($maxTime) ) { - $eventsSql .= " and EndTime >= '$minTime' and StartTime <= '$maxTime'"; + $eventsSql .= " AND EndTime >= '$minTime' AND StartTime <= '$maxTime'"; } -$eventsSql .= ' order by Id asc'; +$eventsSql .= ' ORDER BY E.Id ASC'; //echo "ESQL: $eventsSql
    "; $chart['data'] = array( @@ -361,14 +362,13 @@ if ( $event ) { } if ( $event['MaxScore'] > 0 ) { - Warning("Has max Scoer"); if ( $startIndex == $endIndex ) { $framesSql = 'SELECT FrameId,Score FROM Frames WHERE EventId = ? AND Score > 0 ORDER BY Score DESC LIMIT 1'; - $frame = dbFetchOne( $framesSql, NULL, array($event['Id']) ); + $frame = dbFetchOne($framesSql, NULL, array($event['Id'])); $i = $startIndex; if ( !isset($currFrameSlots[$i]) ) { - $currFrameSlots[$i] = array( 'count'=>1, 'value'=>$event['MaxScore'], 'event'=>$event, 'frame'=>$frame ); + $currFrameSlots[$i] = array('count'=>1, 'value'=>$event['MaxScore'], 'event'=>$event, 'frame'=>$frame); } else { $currFrameSlots[$i]['count']++; if ( $event['MaxScore'] > $currFrameSlots[$i]['value'] ) { @@ -382,8 +382,8 @@ if ( $event ) { } } else { $framesSql = 'SELECT FrameId,Delta,unix_timestamp(TimeStamp) AS TimeT,Score FROM Frames WHERE EventId = ? AND Score > 0'; - $result = dbQuery( $framesSql, array( $event['Id'] ) ); - while( $frame = dbFetchNext( $result ) ) { + $result = dbQuery($framesSql, array($event['Id'])); + while( $frame = dbFetchNext($result) ) { if ( $frame['Score'] == 0 ) continue; $frameTimeT = $frame['TimeT']; @@ -395,7 +395,7 @@ if ( $event ) { continue; if ( !isset($currFrameSlots[$frameIndex]) ) { - $currFrameSlots[$frameIndex] = array( 'count'=>1, 'value'=>$frame['Score'], 'event'=>$event, 'frame'=>$frame ); + $currFrameSlots[$frameIndex] = array('count'=>1, 'value'=>$frame['Score'], 'event'=>$event, 'frame'=>$frame); } else { $currFrameSlots[$frameIndex]['count']++; if ( $frame['Score'] > $currFrameSlots[$frameIndex]['value'] ) { @@ -426,7 +426,7 @@ if ( false ) { for ( $i = 0; $i < $chart['graph']['width']; $i++ ) { if ( isset($currFrameSlots[$i]) ) { if ( !isset($currFrameSlots[$i]['frame']) ) { - $framesSql = "select FrameId,Score from Frames where EventId = ? and Score > 0 order by FrameId limit 1"; + $framesSql = "SELECT FrameId,Score FROM Frames WHERE EventId = ? AND Score > 0 ORDER BY FrameId LIMIT 1"; $currFrameSlots[$i]['frame'] = dbFetchOne( $framesSql, NULL, array( $currFrameSlots[$i]['event']['Id'] ) ); } } @@ -488,7 +488,7 @@ $frameSlots = array(); $frameMonitorIds = array_keys($monFrameSlots); for ( $i = 0; $i < $chart['graph']['width']; $i++ ) { foreach ( $frameMonitorIds as $frameMonitorId ) { - unset( $currFrameSlots ); + unset($currFrameSlots); $currFrameSlots = &$monFrameSlots[$frameMonitorId]; if ( isset($currFrameSlots[$i]) ) { if ( !isset($frameSlots[$i]) ) { @@ -595,7 +595,7 @@ function drawXGrid( $chart, $scale, $labelClass, $tickClass, $gridClass, $zoomCl unset( $lastLabel ); $labelCheck = isset($scale['labelCheck'])?$scale['labelCheck']:$scale['label']; ?> -
    +
    -
    +
    -
    +
    -
    '; - } + if ( $monitor_i and ( $monitor_i % 100 == 0 ) ) { + echo '
    '; echo $table_head; -} # monitor_i % 100 + } # monitor_i % 100 ?> Date: Sat, 21 Apr 2018 18:49:35 -0500 Subject: [PATCH 100/154] Update startpackpack.sh --- utils/packpack/startpackpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index a58cc084f..a5f8c2787 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -341,7 +341,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then baseurl="https://${DEPLOYHOST}/el/${DIST}/x86_64/" reporpm="zmrepo" # Let repoquery determine the full url and filename to the latest zmrepo package - dlurl=`repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2> /dev/null` + dlurl=$(repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2>&1) else reporpm="rpmfusion-free-release" dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm" From 4f7e0fedad103361839963deba207685acff1ec4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 21 Apr 2018 18:50:46 -0500 Subject: [PATCH 101/154] Update startpackpack.sh --- utils/packpack/startpackpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index a5f8c2787..7f576077c 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -341,7 +341,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then baseurl="https://${DEPLOYHOST}/el/${DIST}/x86_64/" reporpm="zmrepo" # Let repoquery determine the full url and filename to the latest zmrepo package - dlurl=$(repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2>&1) + dlurl="$(repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2>&1)" else reporpm="rpmfusion-free-release" dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm" From 35dcedb2ad180d859acff77aab90c6921a62d0b2 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 21 Apr 2018 20:55:21 -0500 Subject: [PATCH 102/154] fix ftbs on el7 adds compiler support for PRIu64 --- src/zm_event.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 927399670..2008132ef 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "zm.h" #include "zm_db.h" From f13d174ea5e313ae6770200ad6790354c8f16605 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Sat, 21 Apr 2018 21:49:04 -0500 Subject: [PATCH 103/154] remove support for el6 from the buildsystem --- .travis.yml | 2 -- utils/packpack/startpackpack.sh | 27 +++------------------------ 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index 74f686caf..78167f860 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,6 @@ env: global: - SMPFLAGS=-j4 matrix: - - OS=el DIST=6 - - OS=el DIST=6 ARCH=i386 DOCKER_REPO=knnniggett/packpack - OS=el DIST=7 - OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack - OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 7f576077c..91e671f2e 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -19,20 +19,7 @@ checksanity () { exit 1 fi done - - if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then - type repoquery 2>&1 > /dev/null - - if [ $? -ne 0 ]; then - echo - echo "ERROR: The script cannot find the required command \"reqoquery\"." - echo "This command is required in order to build ZoneMinder on el6." - echo "Please install the \"yum-utils\" package then try again." - echo - exit 1 - fi - fi - + # Verify OS & DIST environment variables have been set before calling this script if [ -z "${OS}" ] || [ -z "${DIST}" ]; then echo "ERROR: both OS and DIST environment variables must be set" @@ -336,16 +323,8 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then rm -rf web/api/app/Plugin/Crud mkdir web/api/app/Plugin/Crud - # We use zmrepo to build el6 only. All other redhat distros use rpm fusion - if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then - baseurl="https://${DEPLOYHOST}/el/${DIST}/x86_64/" - reporpm="zmrepo" - # Let repoquery determine the full url and filename to the latest zmrepo package - dlurl="$(repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2>&1)" - else - reporpm="rpmfusion-free-release" - dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm" - fi + reporpm="rpmfusion-free-release" + dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm" # Give our downloaded repo rpm a common name so redhat_package.mk can find it if [ -n "$dlurl" ] && [ $? -eq 0 ]; then From 02f8493b394ec4f3c2e0f9fe5d931c634387ff16 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Sun, 22 Apr 2018 07:25:06 -0500 Subject: [PATCH 104/154] rpm packaging - remove support for sysvinit aka el6 --- CMakeLists.txt | 2 +- distros/redhat/CMakeLists.txt | 36 ++-- distros/redhat/readme/README.Redhat6 | 180 ------------------ distros/redhat/sysvinit/zoneminder.in | 121 ------------ .../redhat/sysvinit/zoneminder.logrotate.in | 7 - distros/redhat/zoneminder.spec | 85 ++------- 6 files changed, 28 insertions(+), 403 deletions(-) delete mode 100644 distros/redhat/readme/README.Redhat6 delete mode 100644 distros/redhat/sysvinit/zoneminder.in delete mode 100644 distros/redhat/sysvinit/zoneminder.logrotate.in diff --git a/CMakeLists.txt b/CMakeLists.txt index b24bc6fa8..c847e06a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,7 +207,7 @@ set(ZM_PERL_SEARCH_PATH "" CACHE PATH where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path.") set(ZM_TARGET_DISTRO "" CACHE STRING - "Build ZoneMinder for a specific distribution. Currently, valid names are: fc24, fc25, el6, el7, OS13, FreeBSD") + "Build ZoneMinder for a specific distribution. Currently, valid names are: fc27, fc26, el7, OS13, FreeBSD") set(ZM_SYSTEMD "OFF" CACHE BOOL "Set to ON to force building ZM with systemd support. default: OFF") diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index ba8aba9c0..e42c5db61 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -14,24 +14,18 @@ if((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx")) endif((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx")) # Configure the zoneminder service files -if(ZM_TARGET_DISTRO STREQUAL "el6") - configure_file(sysvinit/zoneminder.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.sysvinit @ONLY) - configure_file(sysvinit/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) +configure_file(systemd/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) +if(ZM_WEB_USER STREQUAL "nginx") + configure_file(nginx/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) + configure_file(nginx/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) + configure_file(nginx/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) + configure_file(nginx/zoneminder.php-fpm.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.php-fpm.conf @ONLY) + configure_file(nginx/README.Fedora ${CMAKE_CURRENT_SOURCE_DIR}/readme/README.Fedora COPYONLY) +else(ZM_WEB_USER STREQUAL "nginx") + configure_file(systemd/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) -else(ZM_TARGET_DISTRO STREQUAL "el6") - configure_file(systemd/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) - if(ZM_WEB_USER STREQUAL "nginx") - configure_file(nginx/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) - configure_file(nginx/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) - configure_file(nginx/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) - configure_file(nginx/zoneminder.php-fpm.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.php-fpm.conf @ONLY) - configure_file(nginx/README.Fedora ${CMAKE_CURRENT_SOURCE_DIR}/readme/README.Fedora COPYONLY) - else(ZM_WEB_USER STREQUAL "nginx") - configure_file(systemd/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) - configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) - configure_file(systemd/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) - endif(ZM_WEB_USER STREQUAL "nginx") -endif(ZM_TARGET_DISTRO STREQUAL "el6") + configure_file(systemd/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) +endif(ZM_WEB_USER STREQUAL "nginx") # Unpack jscalendar & move files into position message(STATUS "Unpacking and Installing jscalendar...") @@ -74,10 +68,6 @@ if(ZM_WEB_USER STREQUAL "nginx") install(FILES zoneminder.php-fpm.conf DESTINATION /etc/php-fpm.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ RENAME zoneminder.conf) endif(ZM_WEB_USER STREQUAL "nginx") -if(ZM_TARGET_DISTRO STREQUAL "el6") - install(FILES zoneminder.sysvinit DESTINATION /etc/rc.d/init.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -else(ZM_TARGET_DISTRO STREQUAL "el6") - install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) - install(FILES zoneminder.tmpfiles DESTINATION /usr/lib/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -endif(ZM_TARGET_DISTRO STREQUAL "el6") +install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) +install(FILES zoneminder.tmpfiles DESTINATION /usr/lib/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/distros/redhat/readme/README.Redhat6 b/distros/redhat/readme/README.Redhat6 deleted file mode 100644 index 95c063b10..000000000 --- a/distros/redhat/readme/README.Redhat6 +++ /dev/null @@ -1,180 +0,0 @@ -What's New -========== - -1. See the ZoneMinder release notes for a list of new features: - https://github.com/ZoneMinder/zoneminder/releases - -2. ***EOL NOTICE*** - It has become increasingly difficult to maintain the ZoneMinder project such - that it remains compatible with EL6 distros. The version of php shipped with - EL6 distros and the version of ffmpeg which will build against EL6 are too - old. It is with regret that I must announce our plans to stop supporting - ZoneMinder on EL6 distros soon. Your best option is to upgrade to an EL7 - distro or another distro with newer php & ffmpeg packages. Please note that - replacing core packages, such as php, will not be supported by us. You are - on your own should you choose to go down that path. - -3. The php package that ships with CentOS 6 does not support the new ZoneMinder - API. If you require API functionality (such as using a mobile app) then you - should consider an upgrade to CentOS 7 or use Fedora. - -New installs -============ - -1. Unless you are already using MySQL server, you need to ensure that - the server is confired to start during boot and properly secured - by running: - - sudo yum install mysql-server - sudo service mysqld start - /usr/bin/mysql_secure_installation - sudo chkconfig mysqld on - -2. Using the password for the root account set during the previous step, you - will need to create the ZoneMinder database and configure a database - account for ZoneMinder to use: - - mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql - mysql -uroot -p -e "grant all on zm.* to \ - 'zmuser'@localhost identified by 'zmpass';" - mysqladmin -uroot -p reload - - The database account credentials, zmuser/zmpass, are arbitrary. Set them to - anything that suits your environment. - -3. If you have chosen to change the zoneminder database account credentials to - something other than zmuser/zmpass, you must now create a config file under - /etc/zm/conf.d and set your credentials there. For example, create the file - /etc/zm/conf.d/zm-db-user.conf and add the following content to it: - - ZM_DB_USER = {username of the sql account you want to use} - ZM_DB_PASS = {password of the sql account you want to use} - - Once the file has been saved, set proper file & ownership permissions on it: - - sudo chown root:apache *.conf - sudo chmod 640 *.conf - -4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local - timezone. PHP will complain loudly if this is not set, or if it is set - incorrectly, and these complaints will show up in the zoneminder logging - system as errors - - If you are not sure of the proper timezone specification to use, look at - http://php.net/date.timezone - -5. Configure the web server - - This package uses the HTTPS protocol by default to access the web portal, - using rhe default self signed certificate on your system. Requests using - HTTP will auto-redirect to HTTPS. - - Inspect the web server configuration file and verify it meets your needs: - - /etc/zm/www/zoneminder.conf - - If you are running other web enabled services then you may need to edit - this file to suite. See README.https to learn about other alternatives. - - When in doubt, proceed with the default: - - sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ - sudo dnf install mod_ssl - -6. Configure the web server to start automatically: - - sudo chkconfig httpd on - sudo service httpd start - -7. This package will automatically configure and install an SELinux policy - called local_zoneminder. A copy of this policy is in the documentation - folder. - - It is still possible to run into SELinux issues, however. If this is case, - you can disable SELinux permanently by editing the following: - - /etc/selinux/conf - - Change SELINUX line from "enforcing" to "disabled". This change will not - take effect until a reboot, however. To avoid a reboot, execute the - following from the commandline: - - sudo setenforce 0 - -8. Finally, you may start the ZoneMinder service: - - sudo service zoneminder start - - Then point your web browser to http:///zm - -9. Optionally configure the firewall - - All Redhat distros ship with the firewall enabled. That means you will not - be able to access the ZoneMinder web console from a remote machine until - changes are made to the firewall. - - What follows are a set of minimal commands to allow remote access to the - ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to - work. The following commands do not put any restrictions on which remote - machine(s) have access to the listed ports or services. - - sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT - sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT - sudo iptables -A INPUT -p udp --dport 3702 -j ACCEPT - iptables-save | sudo tee /etc/sysconfig/iptables - - Additional changes to the firewall may be required, depending on your - security requirements and how you use the system. It is up to you to verify - these commands are sufficient. - -10. Access the ZoneMinder web console - - You may now access the ZoneMinder web console from your web browser using - an appropriate url. Here are some examples: - - http://localhost/zm (works from the local machine only) - http://{machine name}/zm (works only if dns is configured for your network) - http://{ip address}/zm - -Upgrades -======== - -1. Conf.d folder support has been added to ZoneMinder 1.31.0. Any custom - changes previously made to zm.conf must now be made in one or more custom - config files, created under the conf.d folder. Do this now. See - /etc/zm/conf.d/README for details. Once you recreate any custom config changes - under the conf.d folder, they will remain in place indefinitely. - -2. Verify permissions of the zmuser account. - - Over time, the database account permissions required for normal operation - have increased. Verify the zmuser database account has been granted all - permission to the ZoneMinder database: - - mysql -uroot -p -e "show grants for zmuser@localhost;" - - See step 2 of the Installation section to add missing permissions. - -3. Verify the ZoneMinder Apache configuration file in the folder - /etc/zm/www. You will have a file called "zoneminder.conf" and there - may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file - exists, inspect it and merge anything new in that file with zoneminder.conf. - Verify the SSL REquirements meet your needs. Read README.https if necessary. - -4. Upgrade the database before starting ZoneMinder. - - Most upgrades can be performed by executing the following command: - - sudo zmupdate.pl - - Recent versions of ZoneMinder don't require any parameters added to the - zmupdate command. However, if ZoneMinder complains, you may need to call - zmupdate in the following manner: - - sudo zmupdate.pl --user=root --pass= --version= - -5. Now restart the web server then start zoneminder: - - sudo service httpd restart - sudo service zoneminder start - diff --git a/distros/redhat/sysvinit/zoneminder.in b/distros/redhat/sysvinit/zoneminder.in deleted file mode 100644 index f1c6c47c6..000000000 --- a/distros/redhat/sysvinit/zoneminder.in +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/sh -# description: ZoneMinder is the top Linux video camera security and surveillance solution. ZoneMinder is intended for use in single or multi-camera video security applications.Copyright: Philip Coombes, Corey DeLasaux 2003-2008 -# chkconfig: - 99 00 -# processname: zmpkg.pl - -# Source function library. -. /etc/rc.d/init.d/functions - -prog=ZoneMinder -ZM_CONFIG="@ZM_CONFIG@" -pidfile="@ZM_RUNDIR@" -LOCKFILE=/var/lock/subsys/zm - -loadconf() -{ - if [ -f $ZM_CONFIG ]; then - . $ZM_CONFIG - else - echo "ERROR: $ZM_CONFIG not found." - return 1 - fi -} - -loadconf -command="$ZM_PATH_BIN/zmpkg.pl" - -start() -{ -# Commenting out as it is not needed. Leaving as a placeholder for future use. -# zmupdate || return $? - loadconf || return $? - #Make sure the directory for our PID folder exists or create one. - [ ! -d $pidfile ] \ - && mkdir -m 774 $pidfile \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile - #Make sure the folder for the socks file exists or create one - GetPath="select Value from Config where Name='ZM_PATH_SOCKS'" - dbHost=`echo $ZM_DB_HOST | cut -d: -f1` - dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2` - if [ "$dbPort" = "" ] - then - ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` - else - ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` - fi - [ ! -d $ZM_PATH_SOCK ] \ - && mkdir -m 774 $ZM_PATH_SOCK \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK - echo -n $"Starting $prog: " - $command start - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && touch $LOCKFILE - return $RETVAL -} - -stop() -{ - loadconf - echo -n $"Stopping $prog: " - $command stop - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && rm -f $LOCKFILE -} - -zmstatus() -{ - loadconf - result=`$command status` - if [ "$result" = "running" ]; then - echo "ZoneMinder is running" - $ZM_PATH_BIN/zmu -l - RETVAL=0 - else - echo "ZoneMinder is stopped" - RETVAL=1 - fi -} - -zmupdate() -{ - if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then - $ZM_PATH_BIN/zmupdate.pl -f - fi -} - - -case "$1" in - 'start') - start - ;; - 'stop') - stop - ;; - 'restart') - stop - start - ;; - 'condrestart') - loadconf - result=`$ZM_PATH_BIN/zmdc.pl check` - if [ "$result" = "running" ]; then - $ZM_PATH_BIN/zmdc.pl shutdown > /dev/null - rm -f $LOCKFILE - start - fi - ;; - 'status') - status httpd - status mysqld - zmstatus - ;; - *) - echo "Usage: $0 { start | stop | restart | condrestart | status }" - RETVAL=1 - ;; -esac -exit $RETVAL diff --git a/distros/redhat/sysvinit/zoneminder.logrotate.in b/distros/redhat/sysvinit/zoneminder.logrotate.in deleted file mode 100644 index daf0b908f..000000000 --- a/distros/redhat/sysvinit/zoneminder.logrotate.in +++ /dev/null @@ -1,7 +0,0 @@ -@ZM_LOGDIR@/*log -{ - weekly - notifempty - missingok - create 660 @WEB_USER@ @WEB_GROUP@ -} diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index d69469cd0..120a3a705 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -22,13 +22,6 @@ %global with_apcu_bc 1 %endif -# Include files for SysV init or systemd -%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7 -%global with_init_systemd 1 -%else -%global with_init_sysv 1 -%endif - %global readme_suffix %{?rhel:Redhat%{?rhel}}%{!?rhel:Fedora} %global _hardened_build 1 @@ -49,12 +42,10 @@ Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zon Source1: https://github.com/ZoneMinder/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz Source2: https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/%{ceb_version}.tar.gz#/cakephp-enum-behavior-%{ceb_version}.tar.gz -%{?with_init_systemd:BuildRequires: systemd-devel} -%{?with_init_systemd:BuildRequires: mariadb-devel} -%{?with_init_systemd:BuildRequires: perl-podlators} -%{?with_init_systemd:BuildRequires: polkit-devel} -%{?with_init_sysv:BuildRequires: mysql-devel} -%{?el6:BuildRequires: epel-rpm-macros} +BuildRequires: systemd-devel +BuildRequires: mariadb-devel +BuildRequires: perl-podlators +BuildRequires: polkit-devel BuildRequires: cmake >= 2.8.7 BuildRequires: gnutls-devel BuildRequires: bzip2-devel @@ -119,19 +110,10 @@ Requires: perl(LWP::Protocol::https) Requires: ca-certificates Requires: zip -%{?with_init_systemd:Requires(post): systemd} -%{?with_init_systemd:Requires(post): systemd-sysv} -%{?with_init_systemd:Requires(preun): systemd} -%{?with_init_systemd:Requires(postun): systemd} - -%{?with_init_sysv:Requires(post): /sbin/chkconfig} -%{?with_init_sysv:Requires(post): %{_bindir}/checkmodule} -%{?with_init_sysv:Requires(post): %{_bindir}/semodule_package} -%{?with_init_sysv:Requires(post): %{_sbindir}/semodule} -%{?with_init_sysv:Requires(preun): /sbin/chkconfig} -%{?with_init_sysv:Requires(preun): /sbin/service} -%{?with_init_sysv:Requires(preun): %{_sbindir}/semodule} -%{?with_init_sysv:Requires(postun): /sbin/service} +Requires(post): systemd +Requires(post): systemd-sysv +Requires(preun): systemd +Requires(postun): systemd Requires(post): %{_bindir}/gpasswd Requires(post): %{_bindir}/less @@ -192,24 +174,10 @@ find %{buildroot}%{_datadir}/zoneminder/www/api \( -name cake -or -name cake.php %{__ln_s} ../../../../../../../..%{_sysconfdir}/pki/tls/certs/ca-bundle.crt %{buildroot}%{_datadir}/zoneminder/www/api/lib/Cake/Config/cacert.pem %post -%if 0%{?with_init_sysv} -/sbin/chkconfig --add zoneminder -/sbin/chkconfig zoneminder on - -# Create and load zoneminder selinux policy module -echo -e "\nCreating and installing a ZoneMinder SELinux policy module. Please wait.\n" -%{_bindir}/checkmodule -M -m -o %{_docdir}/%{name}-%{version}/local_zoneminder.mod %{_docdir}/%{name}-%{version}/local_zoneminder.te > /dev/null 2>&1 || : -%{_bindir}/semodule_package -o %{_docdir}/%{name}-%{version}/local_zoneminder.pp -m %{_docdir}/%{name}-%{version}/local_zoneminder.mod > /dev/null 2>&1 || : -%{_sbindir}/semodule -i %{_docdir}/%{name}-%{version}/local_zoneminder.pp > /dev/null 2>&1 || : - -%endif - -%if 0%{?with_init_systemd} # Initial installation if [ $1 -eq 1 ] ; then %systemd_post %{name}.service fi -%endif # Upgrade from a previous version of zoneminder if [ $1 -eq 2 ] ; then @@ -263,34 +231,11 @@ EOF %endif %preun -%if 0%{?with_init_sysv} -if [ $1 -eq 0 ]; then - /sbin/service zoneminder stop > /dev/null 2>&1 || : - /sbin/chkconfig --del zoneminder - echo -e "\nRemoving ZoneMinder SELinux policy module. Please wait.\n" - %{_sbindir}/semodule -r local_zoneminder.pp -fi -%endif - -%if 0%{?with_init_systemd} %systemd_preun %{name}.service -%endif %postun -%if 0%{?with_init_sysv} -if [ $1 -ge 1 ]; then - /sbin/service zoneminder condrestart > /dev/null 2>&1 || : -fi - -# Remove the doc folder. -rm -rf %{_docdir}/%{name}-%{version} -%endif - -%if 0%{?with_init_systemd} %systemd_postun_with_restart %{name}.service -%endif -%if 0%{?with_init_systemd} %triggerun -- zoneminder < 1.25.0-4 # Save the current service runlevel info # User must manually run systemd-sysv-convert --apply zoneminder @@ -300,7 +245,6 @@ rm -rf %{_docdir}/%{name}-%{version} # Run these because the SysV package being removed won't do them /sbin/chkconfig --del zoneminder >/dev/null 2>&1 || : /bin/systemctl try-restart zoneminder.service >/dev/null 2>&1 || : -%endif %files %license COPYING @@ -325,18 +269,11 @@ rm -rf %{_docdir}/%{name}-%{version} %config(noreplace) %{_sysconfdir}/php-fpm.d/zoneminder.conf %endif -%if 0%{?with_init_systemd} %{_tmpfilesdir}/zoneminder.conf %{_unitdir}/zoneminder.service %{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy %{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules %{_bindir}/zmsystemctl.pl -%endif - -%if 0%{?with_init_sysv} -%doc distros/redhat/misc/local_zoneminder.te -%attr(755,root,root) %{_initrddir}/zoneminder -%endif %{_bindir}/zma %{_bindir}/zmaudit.pl @@ -380,6 +317,12 @@ rm -rf %{_docdir}/%{name}-%{version} %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder %changelog +* Sun Apr 22 2017 Andrew Bauer - 1.31.42-1 +- Remove support for sysvinit a.k.a. el6 +- use desktop-file-install for new zoneminder.desktop file +- add new web cache folder +- 1.31.42 development snapshot + * Tue May 09 2017 Andrew Bauer - 1.30.4-1 - modify autosetup macro parameters - modify requirements for php-pecl-acpu-bc package From 93263c40b463c18a2f546a21b174954314fdc3eb Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 22 Apr 2018 07:30:28 -0500 Subject: [PATCH 105/154] Remove mention of el6 from readthedocs --- docs/installationguide/redhat.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index fbbb7a5d8..327089380 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -45,8 +45,6 @@ The following notes are based on real problems which have occurred by those who How to Install ZoneMinder ------------------------- -These instructions apply to all redhat distros and compatible clones, except for RHEL/CentOS 6. - ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site `_ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site `_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline: :: @@ -57,13 +55,6 @@ Note that RHEL/CentOS 7 users should use yum instead of dnf. Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder. ZoneMinder will not run without completing the steps outlined in the README. -How to Install ZoneMinder on RHEL/CentOS 6 ------------------------------------------- - -We continue to encounter build problems, caused by the age of this distro. It is unforuntate, but we can see the writing on the wall. We do not have a date set, but the end of the line for this distros is near. - -Please be advised that we do not recommend any new ZoneMinder installations using CentOS 6. However, for the time being, ZoneMinder rpms will continue to be hosted at `zmrepo `_. - How to Install Nightly Development Builds ----------------------------------------- From 600b66e27c5ea600cc682a223b010e1cee37ee42 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 23 Apr 2018 07:41:36 -0500 Subject: [PATCH 106/154] Update zoneminder.spec --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 120a3a705..9ef5b2606 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -317,7 +317,7 @@ EOF %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder %changelog -* Sun Apr 22 2017 Andrew Bauer - 1.31.42-1 +* Sun Apr 22 2018 Andrew Bauer - 1.31.42-1 - Remove support for sysvinit a.k.a. el6 - use desktop-file-install for new zoneminder.desktop file - add new web cache folder From 0a24f8550affc3fd591e656303ea585dfcf58712 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 23 Apr 2018 08:59:31 -0500 Subject: [PATCH 107/154] Update path to zmtriggers.sql ZM_PATH_DATA is not configured as a make macro. Use @PKGDATADIR@ instead. --- db/zm_create.sql.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 9c237b8a0..0dad55059 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -891,7 +891,7 @@ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' ); -- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts. -source @ZM_PATH_DATA@/db/triggers.sql +source @PKGDATADIR@/db/triggers.sql -- -- Apply the initial configuration -- From 9c0600cace2b0181dedccb303ba3c6813c6ef69b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 10:29:42 -0400 Subject: [PATCH 108/154] Add a HUP Handler --- src/zmc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zmc.cpp b/src/zmc.cpp index 93b12c716..720c21075 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -221,6 +221,7 @@ int main(int argc, char *argv[]) { } Info("Starting Capture version %s", ZM_VERSION); + zmSetDefaultHupHandler(); zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); From 609244857d7d4557bb41ebc757afed2b33567b9f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 10:39:32 -0400 Subject: [PATCH 109/154] google styleguide updates --- src/zmc.cpp | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 720c21075..30be7b30c 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -1,21 +1,21 @@ // // ZoneMinder Capture Daemon, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// /* @@ -39,7 +39,7 @@ zmc - The ZoneMinder Capture daemon =head1 DESCRIPTION This binary's job is to sit on a video device and suck frames off it as fast as -possible, this should run at more or less constant speed. +possible, this should run at more or less constant speed. =head1 OPTIONS @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) { std::cout << ZM_VERSION << "\n"; exit(0); default: - //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); + // fprintf(stderr, "?? getopt returned character code 0%o ??\n", c); break; } } @@ -161,7 +161,7 @@ int main(int argc, char *argv[]) { Usage(); } - int modes = ( (device[0]?1:0) + (host[0]?1:0) + (file[0]?1:0) + (monitor_id > 0 ? 1 : 0)); + int modes = ( (device[0]?1:0) + (host[0]?1:0) + (file[0]?1:0) + (monitor_id > 0 ? 1 : 0) ); if ( modes > 1 ) { fprintf(stderr, "Only one of device, host/port/path, file or monitor id allowed\n"); Usage(); @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) { if ( device[0] ) { n_monitors = Monitor::LoadLocalMonitors(device, monitors, Monitor::CAPTURE); } else -#endif // ZM_HAS_V4L +#endif // ZM_HAS_V4L if ( host[0] ) { if ( !port ) port = "80"; @@ -233,16 +233,18 @@ int main(int argc, char *argv[]) { int result = 0; - while( ! zm_terminate ) { + while ( !zm_terminate ) { result = 0; static char sql[ZM_SQL_SML_BUFSIZ]; - for ( int i = 0; i < n_monitors; i ++ ) { + for ( int i = 0; i < n_monitors; i++ ) { time_t now = (time_t)time(NULL); monitors[i]->setStartupTime(now); - snprintf(sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", monitors[i]->Id()); + snprintf(sql, sizeof(sql), + "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", + monitors[i]->Id()); if ( mysql_query(&dbconn, sql) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + Error("Can't run query: %s", mysql_error(&dbconn)); } } // Outer primary loop, handles connection to camera @@ -251,8 +253,10 @@ int main(int argc, char *argv[]) { sleep(10); continue; } - for ( int i = 0; i < n_monitors; i ++ ) { - snprintf(sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", monitors[i]->Id()); + for ( int i = 0; i < n_monitors; i++ ) { + snprintf(sql, sizeof(sql), + "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", + monitors[i]->Id()); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } @@ -291,7 +295,7 @@ int main(int argc, char *argv[]) { if ( next_delays[j] <= min_delay ) { min_delay = next_delays[j]; } - } // end foreach monitor + } // end foreach monitor if ( next_delays[i] <= min_delay || next_delays[i] <= 0 ) { if ( monitors[i]->PreCapture() < 0 ) { @@ -331,7 +335,7 @@ int main(int argc, char *argv[]) { monitors[i]->Reload(); } logTerm(); - logInit( log_id_string ); + logInit(log_id_string); zm_reload = false; } if ( result < 0 ) { @@ -347,9 +351,11 @@ int main(int argc, char *argv[]) { for ( int i = 0; i < n_monitors; i++ ) { static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')", monitors[i]->Id() ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + snprintf(sql, sizeof(sql), + "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')", + monitors[i]->Id()); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); } delete monitors[i]; } From 3b9f7b38c5983cbf9198c3ee270b27e9779cd069 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 10:40:42 -0400 Subject: [PATCH 110/154] Use int instead of long. Monitor->GetCaptureDelay returns an int, so no reason to use long. --- src/zmc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 30be7b30c..6b277ebcc 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -262,9 +262,9 @@ int main(int argc, char *argv[]) { } } - long *capture_delays = new long[n_monitors]; - long *alarm_capture_delays = new long[n_monitors]; - long *next_delays = new long[n_monitors]; + int *capture_delays = new int[n_monitors]; + int *alarm_capture_delays = new int[n_monitors]; + int *next_delays = new int[n_monitors]; struct timeval * last_capture_times = new struct timeval[n_monitors]; for ( int i = 0; i < n_monitors; i++ ) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; From 11cacebb3bef80fcc7186da871e968936521e93e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 11:14:44 -0400 Subject: [PATCH 111/154] use a function called exit_zmu instead of exit() to properly close logs and db. The reason is just to reduce connection lost logs in mysql. --- src/zmu.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/zmu.cpp b/src/zmu.cpp index 640b9a342..3fc19ed51 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -422,7 +422,7 @@ int main( int argc, char *argv[] ) { if ( strcmp( config.auth_relay, "none" ) == 0 ) { if ( !username ) { fprintf( stderr, "Error, username must be supplied\n" ); - exit( -1 ); + exit_zmu( -1 ); } if ( username ) { @@ -431,7 +431,7 @@ int main( int argc, char *argv[] ) { } else { if ( !(username && password) && !auth ) { fprintf( stderr, "Error, username and password or auth string must be supplied\n" ); - exit( -1 ); + exit_zmu( -1 ); } //if ( strcmp( config.auth_relay, "hashed" ) == 0 ) @@ -449,7 +449,7 @@ int main( int argc, char *argv[] ) { } if ( !user ) { fprintf( stderr, "Error, unable to authenticate user\n" ); - exit( -1 ); + exit_zmu( -1 ); } ValidateAccess( user, mon_id, function ); } @@ -463,7 +463,7 @@ int main( int argc, char *argv[] ) { } if ( ! monitor->connect() ) { Error( "Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name() ); - exit( -1 ); + exit_zmu( -1 ); } char separator = ' '; @@ -661,7 +661,7 @@ int main( int argc, char *argv[] ) { delete monitor; } else { fprintf( stderr, "Error, invalid monitor id %d\n", mon_id ); - exit( -1 ); + exit_zmu( -1 ); } } else { if ( function & ZMU_QUERY ) { @@ -669,10 +669,10 @@ int main( int argc, char *argv[] ) { char vidString[0x10000] = ""; bool ok = LocalCamera::GetCurrentSettings( device, vidString, v4lVersion, verbose ); printf( "%s", vidString ); - exit( ok?0:-1 ); + exit_zmu( ok?0:-1 ); #else // ZM_HAS_V4L fprintf( stderr, "Error, video4linux is required for device querying\n" ); - exit( -1 ); + exit_zmu( -1 ); #endif // ZM_HAS_V4L } @@ -685,13 +685,13 @@ int main( int argc, char *argv[] ) { if ( mysql_query( &dbconn, sql.c_str() ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + exit_zmu( mysql_errno( &dbconn ) ); } MYSQL_RES *result = mysql_store_result( &dbconn ); if ( !result ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + exit_zmu( mysql_errno( &dbconn ) ); } Debug( 1, "Got %d monitors", mysql_num_rows( result ) ); @@ -738,8 +738,12 @@ int main( int argc, char *argv[] ) { } delete user; + return exit_zmu(0); +} +int exit_zmu(int exit_code) { logTerm(); zmDbClose(); - return( 0 ); + exit(exit_code); + return exit_code; } From 235fc640be17df163c36cf2b7e4800a3332a7278 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 11:15:33 -0400 Subject: [PATCH 112/154] exit_zmu must come before use --- src/zmu.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/zmu.cpp b/src/zmu.cpp index 3fc19ed51..b902e515e 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -196,6 +196,14 @@ bool ValidateAccess( User *user, int mon_id, int function ) { return( allowed ); } +int exit_zmu(int exit_code) { + logTerm(); + zmDbClose(); + + exit(exit_code); + return exit_code; +} + int main( int argc, char *argv[] ) { if ( access(ZM_CONFIG, R_OK) != 0 ) { fprintf( stderr, "Can't open %s: %s\n", ZM_CONFIG, strerror(errno) ); @@ -740,10 +748,3 @@ int main( int argc, char *argv[] ) { return exit_zmu(0); } -int exit_zmu(int exit_code) { - logTerm(); - zmDbClose(); - - exit(exit_code); - return exit_code; -} From f752b3077a3f3eb6f2d55462077a2c780304126e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 11:16:24 -0400 Subject: [PATCH 113/154] add the # of seconds before kill to the log line --- scripts/zmdc.pl.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index f1b7171a1..4b58e2b19 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -528,9 +528,10 @@ sub kill_until_dead { sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n"; while( $process and $$process{pid} and kill( 0, $$process{pid} ) ) { if ( $count++ > 10 ) { - dPrint( ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) - .". Sending KILL to pid $$process{pid}\n" + dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) + .' after ' . ( KILL_DELAY * $count ) . ' seconds.' + ." Sending KILL to pid $$process{pid}\n" ); kill( 'KILL', $$process{pid} ); last; From e3161687ba72fc5e19c9caedaa24ceb1b938c56c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 11:16:37 -0400 Subject: [PATCH 114/154] google code style --- scripts/zmwatch.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index 7d21ecfee..3b607306c 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -147,11 +147,11 @@ while( 1 ) { if ( !defined($image_time) ) { # Can't read from shared data $restart = 1; - Error( "Error reading shared data for $$monitor{Id} $$monitor{Name}\n"); + Error("Error reading shared data for $$monitor{Id} $$monitor{Name}\n"); } elsif ( !$image_time ) { # We can't get the last capture time so can't be sure it's died. $restart = 1; - Error( "Error getting last analyse time for $$monitor{Id} $$monitor{Name}\n"); + Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero.\n"); } else { my $max_image_delay = ( $monitor->{MaxFPS} From a68ed3a3051c826cc844cc07ab1e8e1078fff1ef Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 11:38:25 -0400 Subject: [PATCH 115/154] watchfeed => watch. Fixes #2086 --- scripts/zmfilter.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 3bde3e859..faa9814b9 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -646,8 +646,8 @@ sub substituteTags { $text =~ s/%MEM%/$Monitor->{MonthEvents}/g; $text =~ s/%MEA%/$Monitor->{ArchivedEvents}/g; $text =~ s/%MP%/$url?view=watch&mid=$Event->{MonitorId}/g; - $text =~ s/%MPS%/$url?view=watchfeed&mid=$Event->{MonitorId}&mode=stream/g; - $text =~ s/%MPI%/$url?view=watchfeed&mid=$Event->{MonitorId}&mode=still/g; + $text =~ s/%MPS%/$url?view=watch&mid=$Event->{MonitorId}&mode=stream/g; + $text =~ s/%MPI%/$url?view=watch&mid=$Event->{MonitorId}&mode=still/g; $text =~ s/%EP%/$url?view=event&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; $text =~ s/%EPS%/$url?view=event&mode=stream&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; $text =~ s/%EPI%/$url?view=event&mode=still&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; From a110ae71f5162e33f7366bc91f165efbd593b1a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 13:48:14 -0400 Subject: [PATCH 116/154] put lines back preventing double open of mysql --- src/zm_db.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 131306854..186551673 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -23,7 +23,6 @@ #include "zm.h" #include "zm_db.h" -// From what I read, we need one of these per thread MYSQL dbconn; Mutex db_mutex; @@ -31,8 +30,9 @@ bool zmDbConnected = false; bool zmDbConnect() { // For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu - //if ( zmDbConnected ) - //return; + // But they really need to be here in order to prevent a double open of mysql + if ( zmDbConnected ) + return true; if ( !mysql_init(&dbconn) ) { Error("Can't initialise database connection: %s", mysql_error(&dbconn)); From 3ab0755e031dce6234e20e116f4231423971cfd4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 13:50:10 -0400 Subject: [PATCH 117/154] google code style plus other cleanups --- src/zmu.cpp | 190 ++++++++++++++++++++++++++-------------------------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/src/zmu.cpp b/src/zmu.cpp index b902e515e..e508b16fb 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -95,49 +95,51 @@ Options for use with monitors: #include "zm_monitor.h" #include "zm_local_camera.h" -void Usage( int status=-1 ) { - fprintf( stderr, "zmu <-d device_path> [-v] [function] [-U -P]\n" ); - fprintf( stderr, "zmu <-m monitor_id> [-v] [function] [-U -P]\n" ); - fprintf( stderr, "General options:\n" ); - fprintf( stderr, " -h, --help : This screen\n" ); - fprintf( stderr, " -v, --verbose : Produce more verbose output\n" ); - fprintf( stderr, " -l, --list : List the current status of active (or all with -v) monitors\n" ); - fprintf( stderr, "Options for use with devices:\n" ); - fprintf( stderr, " -d, --device [device_path] : Get the current video device settings for [device_path] or all devices\n" ); - fprintf( stderr, " -V, --version : Set the Video 4 Linux API version to use for the query, use 1 or 2\n" ); - fprintf( stderr, " -q, --query : Query the current settings for the device\n" ); - fprintf( stderr, "Options for use with monitors:\n" ); - fprintf( stderr, " -m, --monitor : Specify which monitor to address, default 1 if absent\n" ); - fprintf( stderr, " -q, --query : Query the current settings for the monitor\n" ); - fprintf( stderr, " -s, --state : Output the current monitor state, 0 = idle, 1 = prealarm, 2 = alarm,\n" ); - fprintf( stderr, " 3 = alert, 4 = tape\n" ); - fprintf( stderr, " -B, --brightness [value] : Output the current brightness, set to value if given \n" ); - fprintf( stderr, " -C, --contrast [value] : Output the current contrast, set to value if given \n" ); - fprintf( stderr, " -H, --hue [value] : Output the current hue, set to value if given \n" ); - fprintf( stderr, " -O, --colour [value] : Output the current colour, set to value if given \n" ); - fprintf( stderr, " -i, --image [image_index] : Write captured image to disk as .jpg, last image captured\n" ); - fprintf( stderr, " or specified ring buffer index if given.\n" ); - fprintf( stderr, " -S, --scale : With --image specify any scaling (in %%) to be applied to the image\n" ); - fprintf( stderr, " -t, --timestamp [image_index] : Output captured image timestamp, last image captured or specified\n" ); - fprintf( stderr, " ring buffer index if given\n" ); - fprintf( stderr, " -R, --read_index : Output ring buffer read index\n" ); - fprintf( stderr, " -W, --write_index : Output ring buffer write index\n" ); - fprintf( stderr, " -e, --event : Output last event index\n" ); - fprintf( stderr, " -f, --fps : Output last Frames Per Second captured reading\n" ); - fprintf( stderr, " -z, --zones : Write last captured image overlaid with zones to -Zones.jpg\n" ); - fprintf( stderr, " -a, --alarm : Force alarm in monitor, this will trigger recording until cancelled with -c\n" ); - fprintf( stderr, " -n, --noalarm : Force no alarms in monitor, this will prevent alarms until cancelled with -c\n" ); - fprintf( stderr, " -c, --cancel : Cancel a forced alarm/noalarm in monitor, required after being enabled with -a or -n\n" ); - fprintf( stderr, " -L, --reload : Signal monitor to reload settings\n" ); - fprintf( stderr, " -E, --enable : Enable detection, wake monitor up\n" ); - fprintf( stderr, " -D, --disable : Disable detection, put monitor to sleep\n" ); - fprintf( stderr, " -u, --suspend : Suspend detection, useful to prevent bogus alarms when panning etc\n" ); - fprintf( stderr, " -r, --resume : Resume detection after a suspend\n" ); - fprintf( stderr, " -U, --username : When running in authenticated mode the username and\n" ); - fprintf( stderr, " -P, --password : password combination of the given user\n" ); - fprintf( stderr, " -A, --auth : Pass authentication hash string instead of user details\n" ); +void Usage(int status=-1) { + fputs( + "zmu <-d device_path> [-v] [function] [-U -P]\n" + "zmu <-m monitor_id> [-v] [function] [-U -P]\n" + "General options:\n" + " -h, --help : This screen\n" + " -v, --verbose : Produce more verbose output\n" + " -l, --list : List the current status of active (or all with -v) monitors\n" + "Options for use with devices:\n" + " -d, --device [device_path] : Get the current video device settings for [device_path] or all devices\n" + " -V, --version : Set the Video 4 Linux API version to use for the query, use 1 or 2\n" + " -q, --query : Query the current settings for the device\n" + "Options for use with monitors:\n" + " -m, --monitor : Specify which monitor to address, default 1 if absent\n" + " -q, --query : Query the current settings for the monitor\n" + " -s, --state : Output the current monitor state, 0 = idle, 1 = prealarm, 2 = alarm,\n" + " 3 = alert, 4 = tape\n" + " -B, --brightness [value] : Output the current brightness, set to value if given \n" + " -C, --contrast [value] : Output the current contrast, set to value if given \n" + " -H, --hue [value] : Output the current hue, set to value if given \n" + " -O, --colour [value] : Output the current colour, set to value if given \n" + " -i, --image [image_index] : Write captured image to disk as .jpg, last image captured\n" + " or specified ring buffer index if given.\n" + " -S, --scale : With --image specify any scaling (in %%) to be applied to the image\n" + " -t, --timestamp [image_index] : Output captured image timestamp, last image captured or specified\n" + " ring buffer index if given\n" + " -R, --read_index : Output ring buffer read index\n" + " -W, --write_index : Output ring buffer write index\n" + " -e, --event : Output last event index\n" + " -f, --fps : Output last Frames Per Second captured reading\n" + " -z, --zones : Write last captured image overlaid with zones to -Zones.jpg\n" + " -a, --alarm : Force alarm in monitor, this will trigger recording until cancelled with -c\n" + " -n, --noalarm : Force no alarms in monitor, this will prevent alarms until cancelled with -c\n" + " -c, --cancel : Cancel a forced alarm/noalarm in monitor, required after being enabled with -a or -n\n" + " -L, --reload : Signal monitor to reload settings\n" + " -E, --enable : Enable detection, wake monitor up\n" + " -D, --disable : Disable detection, put monitor to sleep\n" + " -u, --suspend : Suspend detection, useful to prevent bogus alarms when panning etc\n" + " -r, --resume : Resume detection after a suspend\n" + " -U, --username : When running in authenticated mode the username and\n" + " -P, --password : password combination of the given user\n" + " -A, --auth : Pass authentication hash string instead of user details\n" + "", stderr ); - exit( status ); + exit(status); } typedef enum { @@ -166,7 +168,7 @@ typedef enum { ZMU_LIST = 0x10000000, } Function; -bool ValidateAccess( User *user, int mon_id, int function ) { +bool ValidateAccess(User *user, int mon_id, int function) { bool allowed = true; if ( function & (ZMU_STATE|ZMU_IMAGE|ZMU_TIME|ZMU_READ_IDX|ZMU_WRITE_IDX|ZMU_FPS) ) { if ( user->getStream() < User::PERM_VIEW ) @@ -185,15 +187,11 @@ bool ValidateAccess( User *user, int mon_id, int function ) { allowed = false; } if ( mon_id > 0 ) { - if ( !user->canAccess( mon_id ) ) { + if ( !user->canAccess(mon_id) ) { allowed = false; } } - if ( !allowed ) { - fprintf( stderr, "Error, insufficient privileges for requested action\n" ); - exit( -1 ); - } - return( allowed ); + return allowed; } int exit_zmu(int exit_code) { @@ -204,15 +202,15 @@ int exit_zmu(int exit_code) { return exit_code; } -int main( int argc, char *argv[] ) { +int main(int argc, char *argv[]) { if ( access(ZM_CONFIG, R_OK) != 0 ) { - fprintf( stderr, "Can't open %s: %s\n", ZM_CONFIG, strerror(errno) ); - exit( -1 ); + fprintf(stderr, "Can't open %s: %s\n", ZM_CONFIG, strerror(errno)); + exit(-1); } self = argv[0]; - srand( getpid() * time( 0 ) ); + srand(getpid() * time(0)); static struct option long_options[] = { {"device", 2, 0, 'd'}, @@ -274,8 +272,8 @@ int main( int argc, char *argv[] ) { while (1) { int option_index = 0; - int c = getopt_long (argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::U:P:A:V:", long_options, &option_index); - if (c == -1) { + int c = getopt_long(argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::U:P:A:V:", long_options, &option_index); + if ( c == -1 ) { break; } @@ -296,7 +294,7 @@ int main( int argc, char *argv[] ) { case 'i': function |= ZMU_IMAGE; if ( optarg ) - image_idx = atoi( optarg ); + image_idx = atoi(optarg); break; case 'S': scale = atoi(optarg); @@ -304,7 +302,7 @@ int main( int argc, char *argv[] ) { case 't': function |= ZMU_TIME; if ( optarg ) - image_idx = atoi( optarg ); + image_idx = atoi(optarg); break; case 'R': function |= ZMU_READ_IDX; @@ -353,22 +351,22 @@ int main( int argc, char *argv[] ) { case 'B': function |= ZMU_BRIGHTNESS; if ( optarg ) - brightness = atoi( optarg ); + brightness = atoi(optarg); break; case 'C': function |= ZMU_CONTRAST; if ( optarg ) - contrast = atoi( optarg ); + contrast = atoi(optarg); break; case 'H': function |= ZMU_HUE; if ( optarg ) - hue = atoi( optarg ); + hue = atoi(optarg); break; case 'O': function |= ZMU_COLOUR; if ( optarg ) - colour = atoi( optarg ); + colour = atoi(optarg); break; case 'U': username = optarg; @@ -385,41 +383,39 @@ int main( int argc, char *argv[] ) { break; #endif // ZM_HAS_V4L case 'h': - Usage( 0 ); + case '?': + Usage(0); break; case 'l': function |= ZMU_LIST; break; - case '?': - Usage(); - break; default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); break; } } - if (optind < argc) { - fprintf( stderr, "Extraneous options, " ); + if ( optind < argc ) { + fprintf(stderr, "Extraneous options, "); while (optind < argc) - fprintf( stderr, "%s ", argv[optind++]); - fprintf( stderr, "\n"); + fprintf(stderr, "%s ", argv[optind++]); + fprintf(stderr, "\n"); Usage(); } if ( device && !(function&ZMU_QUERY) ) { - fprintf( stderr, "Error, -d option cannot be used with this option\n" ); + fprintf(stderr, "Error, -d option cannot be used with this option\n"); Usage(); } if ( scale != -1 && !(function&ZMU_IMAGE) ) { - fprintf( stderr, "Error, -S option cannot be used with this option\n" ); + fprintf(stderr, "Error, -S option cannot be used with this option\n"); Usage(); } //printf( "Monitor %d, Function %d\n", mon_id, function ); zmLoadConfig(); - logInit( "zmu" ); + logInit("zmu"); zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); @@ -427,62 +423,66 @@ int main( int argc, char *argv[] ) { User *user = 0; if ( config.opt_use_auth ) { - if ( strcmp( config.auth_relay, "none" ) == 0 ) { + if ( strcmp(config.auth_relay, "none") == 0 ) { if ( !username ) { - fprintf( stderr, "Error, username must be supplied\n" ); - exit_zmu( -1 ); + fprintf(stderr, "Error, username must be supplied\n"); + exit_zmu(-1); } if ( username ) { - user = zmLoadUser( username ); + user = zmLoadUser(username); } } else { if ( !(username && password) && !auth ) { - fprintf( stderr, "Error, username and password or auth string must be supplied\n" ); - exit_zmu( -1 ); + fprintf(stderr, "Error, username and password or auth string must be supplied\n"); + exit_zmu(-1); } //if ( strcmp( config.auth_relay, "hashed" ) == 0 ) { if ( auth ) { - user = zmLoadAuthUser( auth, false ); + user = zmLoadAuthUser(auth, false); } } //else if ( strcmp( config.auth_relay, "plain" ) == 0 ) { if ( username && password ) { - user = zmLoadUser( username, password ); + user = zmLoadUser(username, password); } } } if ( !user ) { - fprintf( stderr, "Error, unable to authenticate user\n" ); - exit_zmu( -1 ); + fprintf(stderr, "Error, unable to authenticate user\n"); + return exit_zmu(-1); } - ValidateAccess( user, mon_id, function ); - } - + if ( !ValidateAccess(user, mon_id, function) ) { + fprintf(stderr, "Error, insufficient privileges for requested action\n"); + exit_zmu(-1); + } + } // end if auth if ( mon_id > 0 ) { - Monitor *monitor = Monitor::Load( mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY ); + fprintf(stderr,"Monitor %d\n", mon_id); + Monitor *monitor = Monitor::Load(mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY); if ( monitor ) { + fprintf(stderr,"Monitor %d(%s)\n", monitor->Id(), monitor->Name()); if ( verbose ) { - printf( "Monitor %d(%s)\n", monitor->Id(), monitor->Name() ); + 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 ); - } + Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); + exit_zmu(-1); + } 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") ); + printf("Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle")); else { - if ( have_output ) printf( "%c", separator ); - printf( "%d", state ); + if ( have_output ) printf("%c", separator); + printf("%d", state); have_output = true; } } @@ -668,8 +668,8 @@ int main( int argc, char *argv[] ) { } delete monitor; } else { - fprintf( stderr, "Error, invalid monitor id %d\n", mon_id ); - exit_zmu( -1 ); + fprintf(stderr, "Error, invalid monitor id %d\n", mon_id); + exit_zmu(-1); } } else { if ( function & ZMU_QUERY ) { From 18b015903a85eb564f6fbc90a2dd8d3433fa7284 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 14:36:46 -0400 Subject: [PATCH 118/154] cleanup. Google Code Style. Move diag_path from a static to a class member so that multiple zones will create different diag files. --- src/zm_zone.cpp | 349 +++++++++++++++++++++++------------------------- 1 file changed, 170 insertions(+), 179 deletions(-) diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 29a24a47a..87b7ac902 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -108,14 +108,12 @@ void Zone::Setup( } } - // FIXME: Is this not a problem? If you had two zones for a monitor.. then these would conflict. You would only get 1 dump file if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( ! diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); - } - pg_image->WriteJpeg( diag_path ); - } + snprintf(diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); + pg_image->WriteJpeg(diag_path); + } else { + diag_path[0] = 0; + } } // end Zone::Setup Zone::~Zone() { @@ -127,21 +125,22 @@ Zone::~Zone() { void Zone::RecordStats( const Event *event ) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "insert into Stats set MonitorId=%d, ZoneId=%d, EventId=%d, FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't insert event stats: %s", mysql_error( &dbconn ) ); + snprintf(sql, sizeof(sql), + "INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", + monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score + ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't insert event stats: %s", mysql_error(&dbconn)); } db_mutex.unlock(); } // end void Zone::RecordStats( const Event *event ) bool Zone::CheckOverloadCount() { - Info("Overloaded count: %d, Overloaded frames: %d", overload_count, overload_frames); if ( overload_count ) { - Info( "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); - Debug( 4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); + Debug(4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames); overload_count--; - return( false ); + return false; } return true; } // end bool Zone::CheckOverloadCount() @@ -180,28 +179,27 @@ int Zone::GetExtendAlarmFrames() { } // end int Zone::GetExtendAlarmFrames() bool Zone::CheckExtendAlarmCount() { - Info( "ExtendAlarm count: %d, ExtendAlarm frames: %d", extend_alarm_count, extend_alarm_frames ); + Info("ExtendAlarm count: %d, ExtendAlarm frames: %d", extend_alarm_count, extend_alarm_frames); if ( extend_alarm_count ) { - Debug( 3, "In extend mode, %d frames of %d remaining", extend_alarm_count, extend_alarm_frames ); + Debug(3, "In extend mode, %d frames of %d remaining", extend_alarm_count, extend_alarm_frames); extend_alarm_count--; - return( true ); + return true; } return false; } // end bool Zone::CheckExtendAlarmCount -bool Zone::CheckAlarms( const Image *delta_image ) { +bool Zone::CheckAlarms(const Image *delta_image) { ResetStats(); if ( overload_count ) { - Info( "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); - Debug( 4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); + Info("In overload mode, %d frames of %d remaining", overload_count, overload_frames); overload_count--; - return( false ); + return false; } delete image; // Get the difference image - Image *diff_image = image = new Image( *delta_image ); + Image *diff_image = image = new Image(*delta_image); int diff_width = diff_image->Width(); uint8_t* diff_buff = (uint8_t*)diff_image->Buffer(); uint8_t* pdiff; @@ -221,7 +219,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { unsigned int hi_x = polygon.HiX(); unsigned int hi_y = polygon.HiY(); - Debug( 4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y ); + Debug(4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y); /* if(config.cpu_extensions && sseversion >= 20) { sse2_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count); @@ -230,36 +228,31 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } */ std_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count); - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( ! diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 1 ); - } - diff_image->WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); if ( pixel_diff_count && alarm_pixels ) pixel_diff = pixel_diff_count/alarm_pixels; - Debug( 5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff ); + Debug(5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff); - if( alarm_pixels ) { - if( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) { + if ( alarm_pixels ) { + if ( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) { /* Not enough pixels alarmed */ - return (false); - } else if( max_alarm_pixels && (alarm_pixels > (unsigned int)max_alarm_pixels) ) { + return false; + } else if ( max_alarm_pixels && (alarm_pixels > (unsigned int)max_alarm_pixels) ) { /* Too many pixels alarmed */ overload_count = overload_frames; - return (false); + return false; } } else { /* No alarmed pixels */ - return (false); + return false; } score = (100*alarm_pixels)/polygon.Area(); if ( score < 1 ) score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */ - Debug( 5, "Current score is %d", score ); + Debug(5, "Current score is %d", score); if ( check_method >= FILTERED_PIXELS ) { int bx = filter_box.X(); @@ -268,7 +261,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { int by1 = by-1; - Debug( 5, "Checking for filtered pixels" ); + Debug(5, "Checking for filtered pixels"); if ( bx > 1 || by > 1 ) { // Now remove any pixels smaller than our filter size unsigned char *cpdiff; @@ -306,47 +299,42 @@ bool Zone::CheckAlarms( const Image *delta_image ) { continue; } alarm_filter_pixels++; - } - } - } + } // end if white + } // end for x + } // end foreach y line } else { alarm_filter_pixels = alarm_pixels; } - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 2 ); - } - diff_image->WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); - Debug( 5, "Got %d filtered pixels, need %d -> %d", alarm_filter_pixels, min_filter_pixels, max_filter_pixels ); + Debug(5, "Got %d filtered pixels, need %d -> %d", alarm_filter_pixels, min_filter_pixels, max_filter_pixels); - if( alarm_filter_pixels ) { - if( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) { + if ( alarm_filter_pixels ) { + if ( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) { /* Not enough pixels alarmed */ - return (false); - } else if( max_filter_pixels && (alarm_filter_pixels > max_filter_pixels) ) { + return false; + } else if ( max_filter_pixels && (alarm_filter_pixels > max_filter_pixels) ) { /* Too many pixels alarmed */ overload_count = overload_frames; - return (false); + return false; } } else { /* No filtered pixels */ - return (false); + return false; } score = (100*alarm_filter_pixels)/(polygon.Area()); if ( score < 1 ) score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */ - Debug( 5, "Current score is %d", score ); + Debug(5, "Current score is %d", score); if ( check_method >= BLOBS ) { - Debug( 5, "Checking for blob pixels" ); + Debug(5, "Checking for blob pixels"); typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats; BlobStats blob_stats[256]; - memset( blob_stats, 0, sizeof(BlobStats)*256 ); + memset(blob_stats, 0, sizeof(BlobStats)*256); uint8_t *spdiff; uint8_t last_x, last_y; BlobStats *bsx, *bsy; @@ -358,32 +346,32 @@ bool Zone::CheckAlarms( const Image *delta_image ) { pdiff = (uint8_t*)diff_image->Buffer( lo_x, y ); for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) { if ( *pdiff == WHITE ) { - Debug( 9, "Got white pixel at %d,%d (%p)", x, y, pdiff ); + Debug(9, "Got white pixel at %d,%d (%p)", x, y, pdiff); //last_x = (x>lo_x)?*(pdiff-1):0; //last_y = (y>lo_y&&x>=last_lo_x&&x<=last_hi_x)?*(pdiff-diff_width):0; last_x = 0; - if(x > 0) { - if((x-1) >= lo_x) { + if ( x > 0 ) { + if ( (x-1) >= lo_x ) { last_x = *(pdiff-1); } } last_y = 0; - if(y > 0) { - if((y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x) { + if (y > 0 ) { + if ( (y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x ) { last_y = *(pdiff-diff_width); } } if ( last_x ) { - Debug( 9, "Left neighbour is %d", last_x ); + Debug(9, "Left neighbour is %d", last_x); bsx = &blob_stats[last_x]; if ( last_y ) { - Debug( 9, "Top neighbour is %d", last_y ); + Debug(9, "Top neighbour is %d", last_y); bsy = &blob_stats[last_y]; if ( last_x == last_y ) { - Debug( 9, "Matching neighbours, setting to %d", last_x ); + Debug(9, "Matching neighbours, setting to %d", last_x); // Add to the blob from the x side (either side really) *pdiff = last_x; alarm_blob_pixels++; @@ -395,22 +383,29 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bsm = bsx->count>=bsy->count?bsx:bsy; bss = bsm==bsx?bsy:bsx; - Debug( 9, "Different neighbours, setting pixels of %d to %d", bss->tag, bsm->tag ); - Debug( 9, "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y ); - Debug( 9, "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y ); + Debug(9, + "Different neighbours, setting pixels of %d to %d\n" + "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n" + "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n", + bss->tag, bsm->tag, + bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y, + bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y + ); // Now change all those pixels to the other setting int changed = 0; - for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++) { + for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++ ) { int lo_sx = bss->lo_x>=ranges[sy].lo_x?bss->lo_x:ranges[sy].lo_x; int hi_sx = bss->hi_x<=ranges[sy].hi_x?bss->hi_x:ranges[sy].hi_x; - Debug( 9, "Changing %d, %d->%d", sy, lo_sx, hi_sx ); - Debug( 9, "Range %d, %d->%d", sy, ranges[sy].lo_x, ranges[sy].hi_x ); + Debug(9, + "Changing %d, %d->%d Range %d->%d", + sy, lo_sx, hi_sx, ranges[sy].lo_x, ranges[sy].hi_x + ); spdiff = diff_buff + ((diff_width * sy) + lo_sx); for ( int sx = lo_sx; sx <= hi_sx; sx++, spdiff++ ) { - Debug( 9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff ); + Debug(9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff); if ( *spdiff == bss->tag ) { - Debug( 9, "Setting pixel" ); + Debug(9, "Setting pixel"); *spdiff = bsm->tag; changed++; } @@ -419,10 +414,14 @@ bool Zone::CheckAlarms( const Image *delta_image ) { *pdiff = bsm->tag; alarm_blob_pixels++; if ( !changed ) { - Info( "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y ); - Info( "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y ); - Error( "No pixels changed, exiting" ); - exit( -1 ); + Info( + "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n" + "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", + bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y, + bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y + ); + Error("No pixels changed, exiting"); + exit(-1); } // Merge the slave blob into the master @@ -436,7 +435,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { alarm_blobs--; - Debug( 6, "Merging blob %d with %d at %d,%d, %d current blobs", bss->tag, bsm->tag, x, y, alarm_blobs ); + Debug(6, "Merging blob %d with %d at %d,%d, %d current blobs", bss->tag, bsm->tag, x, y, alarm_blobs); // Clear out the old blob bss->tag = 0; @@ -447,7 +446,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bss->hi_y = 0; } } else { - Debug( 9, "Setting to left neighbour %d", last_x ); + Debug(9, "Setting to left neighbour %d", last_x); // Add to the blob from the x side *pdiff = last_x; alarm_blob_pixels++; @@ -457,8 +456,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } } else { if ( last_y ) { - Debug( 9, "Top neighbour is %d", last_y ); - Debug( 9, "Setting to top neighbour %d", last_y ); + Debug(9, "Top neighbour is %d", last_y); // Add to the blob from the y side BlobStats *bsy = &blob_stats[last_y]; @@ -489,7 +487,8 @@ bool Zone::CheckAlarms( const Image *delta_image ) { alarm_blobs--; alarm_blob_pixels -= bs->count; - Debug( 6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); + Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", + i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs); bs->tag = 0; bs->count = 0; @@ -500,7 +499,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } } if ( !bs->count ) { - Debug( 9, "Creating new blob %d", i ); + Debug(9, "Creating new blob %d", i); *pdiff = i; alarm_blob_pixels++; bs->tag = i; @@ -509,12 +508,12 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bs->lo_y = bs->hi_y = y; alarm_blobs++; - Debug( 6, "Created blob %d at %d,%d, %d current blobs", bs->tag, x, y, alarm_blobs ); + Debug(6, "Created blob %d at %d,%d, %d current blobs", bs->tag, x, y, alarm_blobs); break; } } if ( i == 0 ) { - Warning( "Max blob count reached. Unable to allocate new blobs so terminating. Zone settings may be too sensitive." ); + Warning("Max blob count reached. Unable to allocate new blobs so terminating. Zone settings may be too sensitive."); x = hi_x+1; y = hi_y+1; } @@ -523,19 +522,15 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } } } - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 3 ); - } - diff_image->WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); if ( !alarm_blobs ) { - return( false ); + return false; } - Debug( 5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs ); + Debug(5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d", + alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); // Now eliminate blobs under the threshold for ( int i = 1; i < WHITE; i++ ) { @@ -555,7 +550,8 @@ bool Zone::CheckAlarms( const Image *delta_image ) { alarm_blobs--; alarm_blob_pixels -= bs->count; - Debug( 6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); + Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", + i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); bs->tag = 0; bs->count = 0; @@ -564,39 +560,37 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bs->hi_x = 0; bs->hi_y = 0; } else { - Debug( 6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); + Debug(6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", + i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); if ( !min_blob_size || bs->count < min_blob_size ) min_blob_size = bs->count; if ( !max_blob_size || bs->count > max_blob_size ) max_blob_size = bs->count; } - } - } - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 4 ); - } - diff_image->WriteJpeg( diag_path ); - } - Debug( 5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs ); + } // end if bs_count + } // end for i < WHITE + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); - if( alarm_blobs ) { - if( min_blobs && (alarm_blobs < min_blobs) ) { + Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", + alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); + + if ( alarm_blobs ) { + if ( min_blobs && (alarm_blobs < min_blobs) ) { /* Not enough pixels alarmed */ - return (false); - } else if(max_blobs && (alarm_blobs > max_blobs) ) { + return false; + } else if ( max_blobs && (alarm_blobs > max_blobs) ) { /* Too many pixels alarmed */ overload_count = overload_frames; - return (false); + return false; } } else { /* No blobs */ - return (false); + return false; } score = (100*alarm_blob_pixels)/(polygon.Area()); if ( score < 1 ) score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */ - Debug( 5, "Current score is %d", score ); + Debug(5, "Current score is %d", score); alarm_lo_x = polygon.HiX()+1; alarm_hi_x = polygon.LoX()-1; @@ -648,15 +642,15 @@ bool Zone::CheckAlarms( const Image *delta_image ) { score *= 2; } - Debug( 5, "Adjusted score is %d", score ); + Debug(5, "Adjusted score is %d", score); // Now outline the changed region if ( score ) { - alarm_box = Box( Coord( alarm_lo_x, alarm_lo_y ), Coord( alarm_hi_x, alarm_hi_y ) ); + alarm_box = Box(Coord(alarm_lo_x, alarm_lo_y), Coord(alarm_hi_x, alarm_hi_y)); //if ( monitor->followMotion() ) if ( true ) { - alarm_centre = Coord( alarm_mid_x, alarm_mid_y ); + alarm_centre = Coord(alarm_mid_x, alarm_mid_y); } else { alarm_centre = alarm_box.Centre(); } @@ -698,9 +692,9 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } if ( monitor->Colours() == ZM_COLOUR_GRAY8 ) { - image = diff_image->HighlightEdges( alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent() ); + image = diff_image->HighlightEdges(alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent()); } else { - image = diff_image->HighlightEdges( alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent() ); + image = diff_image->HighlightEdges(alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent()); } // Only need to delete this when 'image' becomes detached and points somewhere else @@ -710,18 +704,18 @@ bool Zone::CheckAlarms( const Image *delta_image ) { image = 0; } - Debug( 1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d", - Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score ); + Debug(1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d", + Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score); } - return( true ); + return true; } -bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { - Debug( 3, "Parsing polygon string '%s'", poly_string ); +bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) { + Debug(3, "Parsing polygon string '%s'", poly_string); char *str_ptr = new char[strlen(poly_string)+1]; char *str = str_ptr; - strcpy( str, poly_string ); + strcpy(str, poly_string); char *ws; int n_coords = 0; @@ -731,16 +725,16 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { if ( *str == '\0' ) { break; } - ws = strchr( str, ' ' ); + ws = strchr(str, ' '); if ( ws ) { *ws = '\0'; } - char *cp = strchr( str, ',' ); + char *cp = strchr(str, ','); if ( !cp ) { - Error( "Bogus coordinate %s found in polygon string", str ); + Error("Bogus coordinate %s found in polygon string", str); delete[] coords; delete[] str_ptr; - return( false ); + return false; } else { *cp = '\0'; char *xp = str; @@ -749,7 +743,7 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { int x = atoi(xp); int y = atoi(yp); - Debug( 3, "Got coordinate %d,%d from polygon string", x, y ); + Debug(3, "Got coordinate %d,%d from polygon string", x, y); #if 0 if ( x < 0 ) x = 0; @@ -767,80 +761,80 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { else break; } - polygon = Polygon( n_coords, coords ); + polygon = Polygon(n_coords, coords); - Debug( 3, "Successfully parsed polygon string" ); + Debug(3, "Successfully parsed polygon string"); //printf( "Area: %d\n", pg.Area() ); //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); delete[] coords; delete[] str_ptr; - return( true ); + return true; } -bool Zone::ParseZoneString( const char *zone_string, int &zone_id, int &colour, Polygon &polygon ) { - Debug( 3, "Parsing zone string '%s'", zone_string ); +bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) { + Debug(3, "Parsing zone string '%s'", zone_string); char *str_ptr = new char[strlen(zone_string)+1]; char *str = str_ptr; - strcpy( str, zone_string ); + strcpy(str, zone_string); - char *ws = strchr( str, ' ' ); + char *ws = strchr(str, ' '); if ( !ws ) { - Debug( 3, "No initial whitespace found in zone string '%s', finishing", str ); + Debug(3, "No initial whitespace found in zone string '%s', finishing", str); } - zone_id = strtol( str, 0, 10 ); - Debug( 3, "Got zone %d from zone string", zone_id ); + zone_id = strtol(str, 0, 10); + Debug(3, "Got zone %d from zone string", zone_id); if ( !ws ) { delete[] str_ptr; - return( true ); + return true; } *ws = '\0'; str = ws+1; - ws = strchr( str, ' ' ); + ws = strchr(str, ' '); if ( !ws ) { - Debug( 3, "No secondary whitespace found in zone string '%s', finishing", zone_string ); + Debug(3, "No secondary whitespace found in zone string '%s', finishing", zone_string); } - colour = strtol( str, 0, 16 ); - Debug( 3, "Got colour %06x from zone string", colour ); + colour = strtol(str, 0, 16); + Debug(3, "Got colour %06x from zone string", colour); if ( !ws ) { delete[] str_ptr; - return( true ); + return true; } *ws = '\0'; str = ws+1; - bool result = ParsePolygonString( str, polygon ); + bool result = ParsePolygonString(str, polygon); //printf( "Area: %d\n", pg.Area() ); //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); delete[] str_ptr; - return( result ); + return result; } -int Zone::Load( Monitor *monitor, Zone **&zones ) { +int Zone::Load(Monitor *monitor, Zone **&zones) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id() ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + snprintf(sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id()); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + return 0; } MYSQL_RES *result = mysql_store_result( &dbconn ); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + return 0; } - int n_zones = mysql_num_rows( result ); - Debug( 1, "Got %d zones for monitor %s", n_zones, monitor->Name() ); + int n_zones = mysql_num_rows(result); + Debug(1, "Got %d zones for monitor %s", n_zones, monitor->Name()); delete[] zones; zones = new Zone *[n_zones]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { + for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { int col = 0; int Id = atoi(dbrow[col++]); @@ -868,17 +862,18 @@ int Zone::Load( Monitor *monitor, Zone **&zones ) { /* HTML colour code is actually BGR in memory, we want RGB */ AlarmRGB = rgb_convert(AlarmRGB, ZM_SUBPIX_ORDER_BGR); - Debug( 5, "Parsing polygon %s", Coords ); + Debug(5, "Parsing polygon %s", Coords); Polygon polygon; - if ( !ParsePolygonString( Coords, polygon ) ) { - Error( "Unable to parse polygon string '%s' for zone %d/%s for monitor %s, ignoring", Coords, Id, Name, monitor->Name() ); + if ( !ParsePolygonString(Coords, polygon) ) { + Error("Unable to parse polygon string '%s' for zone %d/%s for monitor %s, ignoring", Coords, Id, Name, monitor->Name()); n_zones -= 1; continue; } if ( polygon.LoX() < 0 || polygon.HiX() >= (int)monitor->Width() || polygon.LoY() < 0 || polygon.HiY() >= (int)monitor->Height() ) { - Error( "Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring", Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY() ); + Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring", + Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY()); n_zones -= 1; continue; } @@ -893,21 +888,17 @@ int Zone::Load( Monitor *monitor, Zone **&zones ) { } if ( atoi(dbrow[2]) == Zone::INACTIVE ) { - zones[i] = new Zone( monitor, Id, Name, polygon ); + zones[i] = new Zone(monitor, Id, Name, polygon); } else if ( atoi(dbrow[2]) == Zone::PRIVACY ) { - zones[i] = new Zone( monitor, Id, Name, (Zone::ZoneType)Type, polygon ); + zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon); } - zones[i] = new Zone( monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames ); - } - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - mysql_free_result( result ); - return( n_zones ); -} + zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames); + } // end foreach row + mysql_free_result(result); + return n_zones; +} // end int Zone::Load(Monitor *monitor, Zone **&zones) -bool Zone::DumpSettings( char *output, bool /*verbose*/ ) { +bool Zone::DumpSettings(char *output, bool /*verbose*/) { output[0] = 0; sprintf( output+strlen(output), " Id : %d\n", id ); @@ -951,7 +942,7 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig unsigned int lo_y; unsigned int hi_y; - if(max_pixel_threshold) + if ( max_pixel_threshold ) calc_max_pixel_threshold = max_pixel_threshold; lo_y = polygon.LoY(); @@ -960,9 +951,9 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig unsigned int lo_x = ranges[y].lo_x; unsigned int hi_x = ranges[y].hi_x; - Debug( 7, "Checking line %d from %d -> %d", y, lo_x, hi_x ); - uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer( lo_x, y ); - const uint8_t *ppoly = ppoly_image->Buffer( lo_x, y ); + Debug(7, "Checking line %d from %d -> %d", y, lo_x, hi_x); + uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer(lo_x, y); + const uint8_t *ppoly = ppoly_image->Buffer(lo_x, y); for ( unsigned int x = lo_x; x <= hi_x; x++, pdiff++, ppoly++ ) { if ( *ppoly && (*pdiff > min_pixel_threshold) && (*pdiff <= calc_max_pixel_threshold) ) { From c0d04521d49fc092322fb35f73c2c7ee7afab7f7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 14:36:54 -0400 Subject: [PATCH 119/154] cleanup. Google Code Style. Move diag_path from a static to a class member so that multiple zones will create different diag files. --- src/zm_zone.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_zone.h b/src/zm_zone.h index 9ac8371f0..0c7b26a57 100644 --- a/src/zm_zone.h +++ b/src/zm_zone.h @@ -94,6 +94,7 @@ protected: int overload_count; int extend_alarm_count; + char diag_path[PATH_MAX]; protected: void Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_type, const Polygon &p_polygon, const Rgb p_alarm_rgb, CheckMethod p_check_method, int p_min_pixel_threshold, int p_max_pixel_threshold, int p_min_alarm_pixels, int p_max_alarm_pixels, const Coord &p_filter_box, int p_min_filter_pixels, int p_max_filter_pixels, int p_min_blob_pixels, int p_max_blob_pixels, int p_min_blobs, int p_max_blobs, int p_overload_frames, int p_extend_alarm_frames ); From e8eaf5fc802e4c040a2c6f6d891d8ec65b2d911c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 14:43:16 -0400 Subject: [PATCH 120/154] quiten build error --- src/zm_remote_camera_nvsocket.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index 990b4f89d..9045b962a 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -187,13 +187,14 @@ int RemoteCameraNVSocket::Capture( Image &image ) { Warning( "Unable to capture image, retrying" ); return 0; } - if ( Read( sd, buffer, imagesize ) < imagesize ) { - Warning( "Unable to capture image, retrying" ); + int bytes_read = Read(sd, buffer, imagesize); + if ( (bytes_read < 0) || ( (unsigned int)bytes_read < imagesize ) ) { + Warning("Unable to capture image, retrying"); return 0; } uint32_t end; if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) { - Warning( "Unable to capture image, retrying" ); + Warning("Unable to capture image, retrying"); return 0; } if ( end != 0xFFFFFFFF) { @@ -201,7 +202,7 @@ int RemoteCameraNVSocket::Capture( Image &image ) { return 0; } - image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); + image.Assign(width, height, colours, subpixelorder, buffer, imagesize); return 1; } From 5f7d404a0c773b28da67094a59788ceae0db6951 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 16:24:15 -0400 Subject: [PATCH 121/154] spacing & style. Put locking around db accesses in RealoadLinkedMonitors --- src/zm_monitor.cpp | 53 ++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 601f9f424..d41291b79 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1819,7 +1819,7 @@ void Monitor::Reload() { shared_data->active = true; ready_count = image_count+warmup_count; - ReloadLinkedMonitors( p_linked_monitors ); + ReloadLinkedMonitors(p_linked_monitors); delete row; } // end if row @@ -1837,8 +1837,8 @@ void Monitor::ReloadZones() { //DumpZoneImage(); } -void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { - Debug( 1, "Reloading linked monitors for monitor %s, '%s'", name, p_linked_monitors ); +void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { + Debug(1, "Reloading linked monitors for monitor %s, '%s'", name, p_linked_monitors); if ( n_linked_monitors ) { for( int i = 0; i < n_linked_monitors; i++ ) { delete linked_monitors[i]; @@ -1868,8 +1868,8 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { if ( dest_ptr != link_id_str ) { *dest_ptr = '\0'; unsigned int link_id = atoi(link_id_str); - if ( link_id > 0 && link_id != id) { - Debug( 3, "Found linked monitor id %d", link_id ); + if ( link_id > 0 && link_id != id ) { + Debug(3, "Found linked monitor id %d", link_id); int j; for ( j = 0; j < n_link_ids; j++ ) { if ( link_ids[j] == link_id ) @@ -1889,39 +1889,42 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { break; } if ( n_link_ids > 0 ) { - Debug( 1, "Linking to %d monitors", n_link_ids ); + Debug(1, "Linking to %d monitors", n_link_ids); linked_monitors = new MonitorLink *[n_link_ids]; int count = 0; for ( int i = 0; i < n_link_ids; i++ ) { - Debug( 1, "Checking linked monitor %d", link_ids[i] ); + Debug(1, "Checking linked monitor %d", link_ids[i]); + db_mutex.lock(); static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id, Name from Monitors where Id = %d and Function != 'None' and Function != 'Monitor' and Enabled = 1", link_ids[i] ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + snprintf(sql, sizeof(sql), "select Id, Name from Monitors where Id = %d and Function != 'None' and Function != 'Monitor' and Enabled = 1", link_ids[i] ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + db_mutex.unlock(); + continue; } - MYSQL_RES *result = mysql_store_result( &dbconn ); + MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + db_mutex.unlock(); + continue; } - int n_monitors = mysql_num_rows( result ); + db_mutex.unlock(); + int n_monitors = mysql_num_rows(result); if ( n_monitors == 1 ) { - MYSQL_ROW dbrow = mysql_fetch_row( result ); - Debug( 1, "Linking to monitor %d", link_ids[i] ); - linked_monitors[count++] = new MonitorLink( link_ids[i], dbrow[1] ); + MYSQL_ROW dbrow = mysql_fetch_row(result); + Debug(1, "Linking to monitor %d", link_ids[i]); + linked_monitors[count++] = new MonitorLink(link_ids[i], dbrow[1]); } else { - Warning( "Can't link to monitor %d, invalid id, function or not enabled", link_ids[i] ); + Warning("Can't link to monitor %d, invalid id, function or not enabled", link_ids[i]); } - mysql_free_result( result ); - } + mysql_free_result(result); + } // end foreach link_id n_linked_monitors = count; - } - } -} - + } // end if has link_ids + } // end if p_linked_monitors +} // end void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) { From b5ff820c61ac8bdb8b2968493d4f0036cd7a8f16 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Apr 2018 16:24:44 -0400 Subject: [PATCH 122/154] Test that shm is always valid in zma so that zma dies if zmc does. --- src/zma.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zma.cpp b/src/zma.cpp index 4bb8e25b4..83035f011 100644 --- a/src/zma.cpp +++ b/src/zma.cpp @@ -146,7 +146,7 @@ int main( int argc, char *argv[] ) { monitor->UpdateAdaptiveSkip(); last_analysis_update_time = time( 0 ); - while( !zm_terminate ) { + while( (!zm_terminate) && monitor->ShmValid() ) { // Process the next image sigprocmask(SIG_BLOCK, &block_set, 0); From 9fd2c127650018b5b1c3b0f013a9690c95c91dbb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 08:42:52 -0400 Subject: [PATCH 123/154] DB Logging is a Debug level --- web/includes/database.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/web/includes/database.php b/web/includes/database.php index 9ec113ff1..872371089 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -133,10 +133,7 @@ function dbQuery( $sql, $params=NULL ) { } } else { if ( defined('ZM_DB_DEBUG') ) { - if ( $params ) - Warning("SQL: $sql" . implode(',',$params) ); - else - Warning("SQL: $sql:" ); + Logger::Debug("SQL: $sql values:" . $params?implode(',',$params):'' ); } $result = $dbConn->query($sql); } From cc7756182699d1193d7828b21a039b9b78cc9472 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 11:40:38 -0400 Subject: [PATCH 124/154] fix last_event being uint64 --- .../ZoneMinder/lib/ZoneMinder/Memory.pm.in | 3 +- src/zm_monitor.h | 49 +++++++++---------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in index 834e0747c..2529c8786 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in @@ -147,7 +147,7 @@ our $mem_data = { last_write_index => { type=>'uint32', seq=>$mem_seq++ }, last_read_index => { type=>'uint32', seq=>$mem_seq++ }, state => { type=>'uint32', seq=>$mem_seq++ }, - last_event => { type=>'uint32', seq=>$mem_seq++ }, + last_event => { type=>'uint64', seq=>$mem_seq++ }, action => { type=>'uint32', seq=>$mem_seq++ }, brightness => { type=>'int32', seq=>$mem_seq++ }, hue => { type=>'int32', seq=>$mem_seq++ }, @@ -167,7 +167,6 @@ our $mem_data = { last_read_time => { type=>'time_t64', seq=>$mem_seq++ }, control_state => { type=>'uint8[256]', seq=>$mem_seq++ }, alarm_cause => { type=>'int8[256]', seq=>$mem_seq++ }, - } }, trigger_data => { type=>'TriggerData', seq=>$mem_seq++, 'contents'=> { diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 0f78b55a4..800dab9db 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -106,44 +106,44 @@ protected: typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode; - /* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */ + /* sizeof(SharedData) expected to be 340 bytes on 32bit and 64bit */ typedef struct { uint32_t size; /* +0 */ uint32_t last_write_index; /* +4 */ uint32_t last_read_index; /* +8 */ uint32_t state; /* +12 */ - uint32_t last_event; /* +16 */ - uint32_t action; /* +20 */ - int32_t brightness; /* +24 */ - int32_t hue; /* +28 */ - int32_t colour; /* +32 */ - int32_t contrast; /* +36 */ - int32_t alarm_x; /* +40 */ - int32_t alarm_y; /* +44 */ - uint8_t valid; /* +48 */ - uint8_t active; /* +49 */ - uint8_t signal; /* +50 */ - uint8_t format; /* +51 */ - uint32_t imagesize; /* +52 */ - uint32_t epadding1; /* +56 */ - uint32_t epadding2; /* +60 */ + uint64_t last_event; /* +16 */ + uint32_t action; /* +24 */ + int32_t brightness; /* +28 */ + int32_t hue; /* +32 */ + int32_t colour; /* +36 */ + int32_t contrast; /* +40 */ + int32_t alarm_x; /* +44 */ + int32_t alarm_y; /* +48 */ + uint8_t valid; /* +52 */ + uint8_t active; /* +53 */ + uint8_t signal; /* +54 */ + uint8_t format; /* +55 */ + uint32_t imagesize; /* +56 */ + uint32_t epadding1; /* +60 */ + uint32_t epadding2; /* +64 */ /* ** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038. ** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16. */ - union { /* +64 */ + union { /* +68 */ time_t startup_time; /* When the zmc process started. zmwatch uses this to see how long the process has been running without getting any images */ uint64_t extrapad1; }; - union { /* +72 */ + union { /* +76 */ time_t last_write_time; uint64_t extrapad2; }; - union { /* +80 */ + union { /* +84 */ time_t last_read_time; uint64_t extrapad3; }; - uint8_t control_state[256]; /* +88 */ + uint8_t control_state[256]; /* +92 */ char alarm_cause[256]; @@ -174,7 +174,7 @@ protected: //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit typedef struct { uint32_t size; - unsigned long long current_event; + uint64_t current_event; char event_file[4096]; timeval recording; // used as both bool and a pointer to the timestamp when recording should begin //uint32_t frameNumber; @@ -206,7 +206,6 @@ protected: int last_state; uint64_t last_event; - public: MonitorLink( int p_id, const char *p_name ); ~MonitorLink(); @@ -318,8 +317,6 @@ protected: #endif // ZM_MEM_MAPPED off_t mem_size; unsigned char *mem_ptr; - Storage *storage; - SharedData *shared_data; TriggerData *trigger_data; VideoStoreData *video_store_data; @@ -329,8 +326,8 @@ protected: Snapshot *pre_event_buffer; Camera *camera; - - Event *event; + Event *event; + Storage *storage; int n_zones; Zone **zones; From 93ad25e12444b0149b054d0e7a2d3297f9c7d1c1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 11:41:04 -0400 Subject: [PATCH 125/154] rework zmdc.pl to better handle killing processes --- scripts/zmdc.pl.in | 171 ++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 96 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 4b58e2b19..c70fbe9b7 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -240,11 +240,11 @@ use Sys::MemInfo qw(totalmem freemem totalswap freeswap); use ZoneMinder::Server qw(CpuLoad); #use Data::Dumper; -# We count 10 of these, so total timeout is this value *10. -use constant KILL_DELAY => 10; # seconds +use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sending KILL our %cmd_hash; our %pid_hash; +our %terminating_processes; sub run { my $fd = 0; @@ -268,6 +268,7 @@ sub run { Error( "Can't open pid file at " . ZM_PID ); } + # Tell any existing processes to die, wait 1 second between TERM and KILL killAll( 1 ); dPrint( ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE ); @@ -303,7 +304,6 @@ sub run { if ( ! ( $secs_count % 60 ) ) { $dbh = zmDbConnect() if ! $dbh->ping(); my @cpuload = CpuLoad(); - dPrint( ZoneMinder::Logger::DEBUG, 'Updating Server record' ); if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, 'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); @@ -366,7 +366,10 @@ sub run { #print( "Select timed out\n" ); restartPending(); } - } + + check_for_processes_to_kill(); + + } # end while dPrint( ZoneMinder::Logger::INFO, 'Server exiting at ' .strftime( '%y/%m/%d %H:%M:%S', localtime() ) ."\n" @@ -515,44 +518,33 @@ sub send_stop { ."\n" ); $process->{keepalive} = !$final; + $process->{term_sent_at} = time; + $process->{pending} = 0; + $terminating_processes{$command} = $process; + + kill( 'TERM', $pid ); return $pid; } # end sub send_stop -sub kill_until_dead { - my ( $process ) = @_; -# Now check it has actually gone away, if not kill -9 it - my $count = 0; +sub check_for_processes_to_kill { + # Turn off SIGCHLD my $sigset = POSIX::SigSet->new; my $blockset = POSIX::SigSet->new(SIGCHLD); sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n"; - while( $process and $$process{pid} and kill( 0, $$process{pid} ) ) { - if ( $count++ > 10 ) { + foreach my $command ( %terminating_processes ) { + my $process = $cmd_hash{$command}; + if ( $$process{term_sent_at} - time > KILL_DELAY ) { dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " - .strftime('%y/%m/%d %H:%M:%S', localtime()) - .' after ' . ( KILL_DELAY * $count ) . ' seconds.' - ." Sending KILL to pid $$process{pid}\n" - ); - kill( 'KILL', $$process{pid} ); - last; + .strftime('%y/%m/%d %H:%M:%S', localtime()) + .' after ' . KILL_DELAY . ' seconds.' + ." Sending KILL to pid $$process{pid}\n" + ); + kill('KILL', $$process{pid}); } - - # THe purpose of the signal blocking is to simplify the concurrency - sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; - sleep( KILL_DELAY ); - sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n"; } sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; -} - -sub _stop { - my ($final, $process ) = @_; - - my $pid = send_stop( $final, $process ); - return if ! $pid; - delete( $cmd_hash{$$process{command}} ); - kill_until_dead( $process ); -} +} # end sub check_for_processess_to_kill sub stop { my ( $daemon, @args ) = @_; @@ -560,57 +552,49 @@ sub stop { my $process = $cmd_hash{$command}; if ( !$process ) { dPrint( ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n" ); - return(); + return; } - _stop( 1, $process ); + send_stop( 1, $process ); } +# restart is the same as stop, except that we flag the processes for restarting once it dies +# One difference is that if we don't know about the process, then we start it. sub restart { - my $daemon = shift; - my @args = @_; + my ( $daemon, @args ) = @_; - my $command = $daemon; - $command .= ' '.join( ' ', ( @args ) ) if @args; - dPrint ( ZoneMinder::Logger::DEBUG, "Restarting $command\n"); + my $command = join(' ', $daemon, @args ); + dPrint(ZoneMinder::Logger::DEBUG, "Restarting $command\n"); my $process = $cmd_hash{$command}; - if ( $process ) { - dPrint( ZoneMinder::Logger::DEBUG, "Have process" ); - if ( $process->{pid} ) { - dPrint( ZoneMinder::Logger::DEBUG, "Have process pid " .$process->{pid} ); - my $cpid = $process->{pid}; - if ( defined($pid_hash{$cpid}) ) { - dPrint( ZoneMinder::Logger::DEBUG, "Have process pid hash " .$process->{pid} ); - _stop( 0, $process ); - return; - } else { - dPrint( ZoneMinder::Logger::DEBUG, "Not sending stop" ); - } - } + if ( !$process ) { + dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n"); + start($daemon, @args); + return; } - start( $daemon, @args ); + # Start will be handled by the reaper + send_stop(0, $process); + return; } sub reload { my $daemon = shift; my @args = @_; - my $command = $daemon; - $command .= ' '.join( ' ', ( @args ) ) if ( @args ); + my $command = join(' ', $daemon, @args ) ; my $process = $cmd_hash{$command}; if ( $process ) { if ( $process->{pid} ) { - kill( 'HUP', $process->{pid} ); + kill('HUP', $process->{pid}); } } } sub logrot { logReinit(); - foreach my $process ( values( %pid_hash ) ) { + foreach my $process ( values(%pid_hash) ) { if ( $process->{pid} ) { # && $process->{command} =~ /^zm.*\.pl/ ) { - kill( 'HUP', $process->{pid} ); + kill('HUP', $process->{pid}); } } } @@ -621,16 +605,18 @@ sub reaper { my $status = $?; my $process = $pid_hash{$cpid}; - delete( $pid_hash{$cpid} ); + delete $pid_hash{$cpid}; if ( !$process ) { dPrint( ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n" ); next; } + delete $terminating_processes{$$process{command}}; + delete $$process{term_sent_at}; $process->{stopped} = time(); $process->{runtime} = ($process->{stopped}-$process->{started}); - delete( $process->{pid} ); + delete $process->{pid}; my $exit_status = $status>>8; my $exit_signal = $status&0xfe; @@ -677,6 +663,8 @@ sub reaper { $process->{delay} = $Config{ZM_MAX_RESTART_DELAY}; } } + } else { + delete $cmd_hash{$$process{command}}; } } $SIG{CHLD} = \&reaper; @@ -687,8 +675,8 @@ sub restartPending { # Restart any pending processes foreach my $process ( values( %cmd_hash ) ) { if ( $process->{pending} && $process->{pending} <= time() ) { - dPrint( ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n" ); - start( $process->{daemon}, @{$process->{args}} ); + dPrint(ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n"); + start($process->{daemon}, @{$process->{args}}); } } } @@ -699,21 +687,12 @@ sub shutdownAll { next if ! $pid_hash{$pid}; send_stop( 1, $pid_hash{$pid} ); } - foreach my $pid ( keys %pid_hash ) { -# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here. - next if ! $pid_hash{$pid}; - - my $process = $pid_hash{$pid}; - - kill_until_dead( $process ); - delete( $cmd_hash{$$process{command}} ); - delete( $pid_hash{$pid} ); + while ( %terminating_processes ) { + check_for_processes_to_kill(); + sleep(1) if %terminating_processes; } -if ( 0 ) { - killAll( 5 ); -} - dPrint( ZoneMinder::Logger::INFO, "Server shutdown at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + dPrint(ZoneMinder::Logger::INFO, "Server shutdown at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); unlink( main::SOCK_FILE ) or Error( "Unable to unlink " . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE ); @@ -748,53 +727,54 @@ sub status { my @args = @_; if ( defined($daemon) ) { - my $command = join( ' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( ! $process ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); - return(); + dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n"); + return; } if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) ) + dPrint(ZoneMinder::Logger::DEBUG, "'$command' pending at " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{pending})) ."\n" ); } else { - my $cpid = $process->{pid}; - if ( ! $pid_hash{$cpid} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); - return(); + my $pid = $process->{pid}; + if ( ! $pid_hash{$pid} ) { + dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n"); + return; } } - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started} ) ) + dPrint(ZoneMinder::Logger::DEBUG, "'$command' running since " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}" ); } else { - foreach my $process ( values(%pid_hash) ) { + foreach my $process ( values %pid_hash ) { my $out_str = "'$process->{command}' running since " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}" ; - $out_str .= ", valid" if ( kill( 0, $process->{pid} ) ); + $out_str .= ", valid" if ( kill(0, $process->{pid}) ); $out_str .= "\n"; - dPrint( ZoneMinder::Logger::DEBUG, $out_str ); + dPrint(ZoneMinder::Logger::DEBUG, $out_str); } - foreach my $process ( values( %cmd_hash ) ) { + foreach my $process ( values %cmd_hash ) { if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) ) + dPrint(ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " + .strftime( '%y/%m/%d %H:%M:%S', localtime($process->{pending})) ."\n" ); } } # end foreach process } -} +} # end sub status sub killAll { my $delay = shift; - sleep( $delay ); + # Why sleep before sending term? + #sleep( $delay ); my $killall; if ( '@HOST_OS@' eq 'BSD' ) { $killall = 'killall -q -'; @@ -815,6 +795,5 @@ sub killAll { qx( $cmd ); } } - 1; __END__ From 4d95498664b1a0541a146fe0ed233bf9dcd9a534 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 11:41:31 -0400 Subject: [PATCH 126/154] Prevent double init of Ffmpeg by using FFMPEGInit() --- src/zm_ffmpeg_camera.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index d77c1e788..29db3600d 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -146,13 +146,7 @@ FfmpegCamera::~FfmpegCamera() { } void FfmpegCamera::Initialise() { - if ( logDebugging() ) - av_log_set_level( AV_LOG_DEBUG ); - else - av_log_set_level( AV_LOG_QUIET ); - - av_register_all(); - avformat_network_init(); + FFMPEGInit(); } void FfmpegCamera::Terminate() { From cc525b23973fcb4899880a823c30989d1e6956e1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 11:41:54 -0400 Subject: [PATCH 127/154] Output more detailed shared mem size info --- src/zm_monitor.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index d41291b79..01a67581b 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -410,14 +410,15 @@ Monitor::Monitor( + (image_buffer_count*camera->ImageSize()) + 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */ - Debug( 1, "mem.size=%d", mem_size ); + Debug(1, "mem.size SharedData=%d TriggerData=%d VideoStoreData=%d total=%d", + sizeof(SharedData), sizeof(TriggerData), sizeof(VideoStoreData), mem_size); mem_ptr = NULL; - storage = new Storage( storage_id ); - Debug(1, "Storage path: %s", storage->Path() ); + storage = new Storage(storage_id); + Debug(1, "Storage path: %s", storage->Path()); // Should maybe store this for later use char monitor_dir[PATH_MAX] = ""; - snprintf( monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id ); + snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id); if ( purpose == CAPTURE ) { struct stat statbuf; @@ -916,9 +917,9 @@ void Monitor::actionReload() { void Monitor::actionEnable() { shared_data->action |= RELOAD; + db_mutex.lock(); static char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "UPDATE Monitors SET Enabled = 1 WHERE Id = %d", id); - db_mutex.lock(); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } From de149c1328c78cfee57d11e6754fc883aeaf8ae0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 08:48:35 -0700 Subject: [PATCH 128/154] spacing --- web/includes/Storage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 352a2249d..57f518a65 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -13,7 +13,7 @@ class Storage { if ( ! $row ) { Error("Unable to load Storage record for Id=" . $IdOrRow ); } - } elseif ( is_array( $IdOrRow ) ) { + } else if ( is_array($IdOrRow) ) { $row = $IdOrRow; } } From 21413c0fe67f87ce98acc2944c88b6c77bbbfe76 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 11:49:10 -0400 Subject: [PATCH 129/154] comment out corrupting code --- src/zm_db.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 186551673..3ab89386d 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -31,8 +31,10 @@ bool zmDbConnected = false; bool zmDbConnect() { // For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu // But they really need to be here in order to prevent a double open of mysql - if ( zmDbConnected ) - return true; + //if ( zmDbConnected ) { + //Warning("Calling zmDbConnect when already connected"); + //return true; + //} if ( !mysql_init(&dbconn) ) { Error("Can't initialise database connection: %s", mysql_error(&dbconn)); From bbb10fa4b4f497996eea7246164331b1385a8eb5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 12:40:15 -0400 Subject: [PATCH 130/154] Turn off ffmpeg debugging output, as it seems to conflict with the code at zm_db.cpp 34 --- src/zm_db.cpp | 8 ++++---- src/zm_ffmpeg.cpp | 6 +++--- web/api/app/Plugin/CakePHP-Enum-Behavior | 2 +- web/api/app/Plugin/Crud | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 3ab89386d..d4a927f3b 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -31,10 +31,10 @@ bool zmDbConnected = false; bool zmDbConnect() { // For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu // But they really need to be here in order to prevent a double open of mysql - //if ( zmDbConnected ) { - //Warning("Calling zmDbConnect when already connected"); - //return true; - //} + if ( zmDbConnected ) { + Warning("Calling zmDbConnect when already connected"); + return true; + } if ( !mysql_init(&dbconn) ) { Error("Can't initialise database connection: %s", mysql_error(&dbconn)); diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index b4d7e323a..4d78c45ab 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -27,9 +27,9 @@ void FFMPEGInit() { static bool bInit = false; if ( !bInit ) { - if ( logDebugging() ) - av_log_set_level( AV_LOG_DEBUG ); - else + //if ( logDebugging() ) + //av_log_set_level( AV_LOG_DEBUG ); + //else av_log_set_level( AV_LOG_QUIET ); av_register_all(); avformat_network_init(); diff --git a/web/api/app/Plugin/CakePHP-Enum-Behavior b/web/api/app/Plugin/CakePHP-Enum-Behavior index ea90c0cd7..ca91b87fd 160000 --- a/web/api/app/Plugin/CakePHP-Enum-Behavior +++ b/web/api/app/Plugin/CakePHP-Enum-Behavior @@ -1 +1 @@ -Subproject commit ea90c0cd7f6e24333a90885e563b5d30b793db29 +Subproject commit ca91b87fda8e006e4fca2ed870f24f9a29c2905d diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 0bd63fb46..1351dde6b 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef +Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 From e4465c0a617ad42839be31b07f7024a6b3ffc9e5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 12:44:11 -0400 Subject: [PATCH 131/154] add this to git... --- db/zm_update-1.31.30.sql | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 db/zm_update-1.31.30.sql diff --git a/db/zm_update-1.31.30.sql b/db/zm_update-1.31.30.sql new file mode 100644 index 000000000..c87b4409a --- /dev/null +++ b/db/zm_update-1.31.30.sql @@ -0,0 +1,20 @@ +DROP TABLE IF EXISTS `Monitor_Status`; +CREATE TABLE `Monitor_Status` ( + `MonitorId` int(10) unsigned NOT NULL, + `Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown', + `CaptureFPS` DECIMAL(10,2) NOT NULL default 0, + `AnalysisFPS` DECIMAL(5,2) NOT NULL default 0, + PRIMARY KEY (`MonitorId`) +) ENGINE=MEMORY; + +SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO'; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='/var/cache/zoneminder/events' + ) > 0, + "SELECT 'Default Storage Area already exists.'", + "INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','/var/cache/zoneminder/events','Medium',NULL)" + )); + +PREPARE stmt FROM @s; +EXECUTE stmt; From 678503b992d296552e255bdcbd081850e0dc2d73 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Tue, 24 Apr 2018 12:16:19 -0500 Subject: [PATCH 132/154] fix ftbs on el7 --- src/zm_eventstream.cpp | 1 + src/zm_ffmpeg.cpp | 1 + src/zm_monitor.cpp | 1 + src/zm_videostore.cpp | 2 +- src/zms.cpp | 1 + src/zmu.cpp | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 989d2b14d..2578d91d4 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "zm.h" #include "zm_db.h" diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index b4d7e323a..b0d11948a 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -16,6 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "zm_ffmpeg.h" #include "zm_image.h" diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 601f9f424..b49609d1e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "zm.h" #include "zm_db.h" diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 6ca8f3f96..3500d716a 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -20,7 +20,7 @@ #define __STDC_FORMAT_MACROS 1 -#include +#include #include #include diff --git a/src/zms.cpp b/src/zms.cpp index 63cbfff5f..e8d20f72f 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "zm.h" #include "zm_db.h" diff --git a/src/zmu.cpp b/src/zmu.cpp index 640b9a342..266f91704 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -87,6 +87,7 @@ Options for use with monitors: */ #include +#include #include "zm.h" #include "zm_db.h" From 426b3cf9d4fea7e65e2cc079524f86cde9984463 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 24 Apr 2018 12:43:45 -0500 Subject: [PATCH 133/154] Update startpackpack.sh --- utils/packpack/startpackpack.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 91e671f2e..3794e4645 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -105,10 +105,11 @@ commonprep () { fi # fix 32bit rpm builds - patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch - if [ $? -eq 0 ]; then - patch -p1 < utils/packpack/setarch.patch - fi + # FIXME: breaks arm rpm builds + #patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch + #if [ $? -eq 0 ]; then + # patch -p1 < utils/packpack/setarch.patch + #fi # The rpm specfile requires we download each submodule as a tarball then manually move it into place # Might as well do this for Debian as well, rather than git submodule init From 20f6985dff4e4ae34b33eb54e4f30c329a9f5851 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 14:11:27 -0400 Subject: [PATCH 134/154] implement capturing bandwidth --- db/zm_create.sql.in | 1 + db/zm_update-1.31.44.sql | 12 ++++++++++++ src/zm_camera.h | 3 +++ src/zm_ffmpeg_camera.cpp | 2 ++ src/zm_monitor.cpp | 11 +++++++++-- src/zm_monitor.h | 2 ++ web/includes/Monitor.php | 1 + web/skins/classic/views/_monitor_filters.php | 2 +- web/skins/classic/views/console.php | 1 + 9 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 db/zm_update-1.31.44.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 9c237b8a0..48d1a2fcd 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -528,6 +528,7 @@ CREATE TABLE `Monitor_Status` ( `Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown', `CaptureFPS` DECIMAL(10,2) NOT NULL default 0, `AnalysisFPS` DECIMAL(5,2) NOT NULL default 0, + `CaptureBandwidth` INT NOT NULL default 0, PRIMARY KEY (`MonitorId`) ) ENGINE=MEMORY; -- diff --git a/db/zm_update-1.31.44.sql b/db/zm_update-1.31.44.sql new file mode 100644 index 000000000..3c8a1525a --- /dev/null +++ b/db/zm_update-1.31.44.sql @@ -0,0 +1,12 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'CaptureBandwidth' + ) > 0, +"SELECT 'Column CaptureBandwidth already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `CaptureBandwidth` INT NOT NULL default 0 AFTER `AnalysisFPS`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/src/zm_camera.h b/src/zm_camera.h index 9833e098f..a524fc380 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -53,6 +53,8 @@ protected: int contrast; bool capture; bool record_audio; + unsigned int bytes; + public: Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_width, unsigned int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); @@ -74,6 +76,7 @@ public: unsigned int SubpixelOrder() const { return( subpixelorder ); } unsigned int Pixels() const { return( pixels ); } unsigned int ImageSize() const { return( imagesize ); } + unsigned int Bytes() const { return bytes; }; virtual int Brightness( int/*p_brightness*/=-1 ) { return( -1 ); } virtual int Hue( int/*p_hue*/=-1 ) { return( -1 ); } diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 29db3600d..2216d723b 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -292,6 +292,7 @@ int FfmpegCamera::Capture( Image &image ) { } else { Debug( 4, "Different stream_index %d", packet.stream_index ); } // end if packet.stream_index == mVideoStreamId + bytes += packet.size; zm_av_packet_unref( &packet ); } // end while ! frameComplete return 1; @@ -708,6 +709,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event } int keyframe = packet.flags & AV_PKT_FLAG_KEY; + bytes += packet.size; dumpPacket(&packet); //Video recording diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 01a67581b..b1ea7be22 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -380,6 +380,7 @@ Monitor::Monitor( ParseEncoderParameters(encoderparams.c_str(), &encoderparamsvec); fps = 0.0; + last_camera_bytes = 0; event_count = 0; image_count = 0; ready_count = warmup_count; @@ -2457,15 +2458,21 @@ int Monitor::Capture() { if ( now != last_fps_time ) { // # of images per interval / the amount of time it took double new_fps = double(fps_report_interval)/(now-last_fps_time); + unsigned int new_camera_bytes = camera->Bytes(); + unsigned int new_capture_bandwidth = (new_camera_bytes - last_camera_bytes)/(now-last_fps_time); + last_camera_bytes = new_camera_bytes; //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info("%s: images:%d - Capturing at %.2lf fps", name, image_count, new_fps); + Info("%s: images:%d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec", name, image_count, new_fps, new_capture_bandwidth); last_fps_time = now; if ( new_fps != fps ) { fps = new_fps; + db_mutex.lock(); static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, fps, fps); + snprintf(sql, sizeof(sql), + "INSERT INTO Monitor_Status (MonitorId,CaptureFPS,CaptureBandwidth) VALUES (%d, %.2lf,%u) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf, CaptureBandwidth=%u", + id, fps, new_capture_bandwidth, fps, new_capture_bandwidth); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 800dab9db..fd4988ca4 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -288,6 +288,8 @@ protected: bool embed_exif; // Whether to embed Exif data into each image frame or not double fps; + unsigned int last_camera_bytes; + Image delta_image; Image ref_image; Image alarm_image; // Used in creating analysis images, will be initialized in Analysis diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 74cb3f528..07e151a07 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -24,6 +24,7 @@ private $defaults = array( private $status_fields = array( 'AnalysisFPS' => null, 'CaptureFPS' => null, + 'CaptureBandwidth' => null, ); private $control_fields = array( 'Name' => '', diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index 2ee0e437d..70e1655ea 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -152,7 +152,7 @@ $html .= htmlSelect( 'Status[]', $status_options, ) ); $html .= ''; - $sql = 'SELECT *,S.Status AS Status, S.CaptureFPS AS CaptureFPS, S.AnalysisFPS AS AnalysisFPS + $sql = 'SELECT *,S.Status AS Status, S.CaptureFPS AS CaptureFPS, S.AnalysisFPS AS AnalysisFPS, S.CaptureBandwidth AS CaptureBandwidth FROM Monitors AS M LEFT JOIN Monitor_Status AS S ON MonitorId=Id ' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : '' ).' ORDER BY Sequence ASC'; $monitors = dbFetchAll($sql, null, $values); diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 7565335bb..d4749ab83 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -275,6 +275,7 @@ if ( $fclass != 'infoText' ) $dot_class=$fclass; $fps_string .= '/' . $monitor['AnalysisFPS']; } if ($fps_string) $fps_string .= ' fps'; + $fps_string .= ' ' . human_filesize($monitor['CaptureBandwidth']).'/s'; echo $fps_string; ?>
    From 5b4d16071071a837605d66f86acdf28ae248cd04 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Apr 2018 14:18:41 -0400 Subject: [PATCH 135/154] add total bandwidth at bottom and move buttons to top --- web/skins/classic/views/console.php | 49 ++++++++++++++++++----------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index d4749ab83..1d8cf3c9d 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -105,6 +105,7 @@ $show_storage_areas = count($storage_areas) > 1 and canEdit( 'System' ) ? 1 : 0; $maxWidth = 0; $maxHeight = 0; $zoneCount = 0; +$total_capturing_bandwidth=0; $status_counts = array(); for ( $i = 0; $i < count($displayMonitors); $i++ ) { @@ -176,6 +177,23 @@ xhtmlHeaders( __FILE__, translate('Console') );
    + + + + + @@ -276,6 +294,7 @@ if ( $fclass != 'infoText' ) $dot_class=$fclass; } if ($fps_string) $fps_string .= ' fps'; $fps_string .= ' ' . human_filesize($monitor['CaptureBandwidth']).'/s'; + $total_capturing_bandwidth += $monitor['CaptureBandwidth']; echo $fps_string; ?>
    @@ -340,27 +359,19 @@ if ( $fclass != 'infoText' ) $dot_class=$fclass; + - - - - - - - + + + + + + + + + From f04bccceb271262426d606239f0e19c2c4da948b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 04:59:08 -0400 Subject: [PATCH 136/154] handle out of order pts better --- src/zm_videostore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 6ca8f3f96..9c6d1ca21 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -711,8 +711,8 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { opkt.dts = video_next_dts; opkt.duration = 0; - int duration; - if (!video_last_pts) { + int64_t duration; + if ( !video_last_pts ) { duration = 0; } else { duration = @@ -723,7 +723,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { video_last_pts, duration); if (duration < 0) { - duration = ipkt->duration; + duration = ipkt->duration ? ipkt->duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base); } } From 80803a164c6b585a244bbe4407f5d2a7dbf398f5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:27:43 -0400 Subject: [PATCH 137/154] in set(), check to see if there is a method and if there is call it to set the value. Implement using GroupIds to set the GroupIds value. If the new value is a scalar, then turn it into an array. --- web/includes/Monitor.php | 48 ++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 07e151a07..3e574bf98 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -181,7 +181,7 @@ private $control_fields = array( return $this->{$fn}; #array_unshift($args, $this); #call_user_func_array( $this->{$fn}, $args); - } else { + } else { if ( array_key_exists($fn, $this->control_fields) ) { return $this->control_fields{$fn}; } else if ( array_key_exists( $fn, $this->defaults ) ) { @@ -254,22 +254,26 @@ private $control_fields = array( return $this->{'Height'}; } - public function set( $data ) { + public function set($data) { foreach ($data as $k => $v) { - if ( is_array( $v ) ) { - # perhaps should turn into a comma-separated string - $this->{$k} = implode(',',$v); - } else if ( is_string( $v ) ) { - $this->{$k} = trim( $v ); - } else if ( is_integer( $v ) ) { - $this->{$k} = $v; - } else if ( is_bool( $v ) ) { - $this->{$k} = $v; + if ( method_exists($this, $k) ) { + $this->{$k}($v); } else { - Error( "Unknown type $k => $v of var " . gettype( $v ) ); - $this->{$k} = $v; - } - } + if ( is_array( $v ) ) { +# perhaps should turn into a comma-separated string + $this->{$k} = implode(',',$v); + } else if ( is_string( $v ) ) { + $this->{$k} = trim( $v ); + } else if ( is_integer( $v ) ) { + $this->{$k} = $v; + } else if ( is_bool( $v ) ) { + $this->{$k} = $v; + } else { + Error( "Unknown type $k => $v of var " . gettype( $v ) ); + $this->{$k} = $v; + } + } # end if method_exists + } # end foreach $data as $k=>$v } public static function find_all( $parameters = null, $options = null ) { $filters = array(); @@ -400,10 +404,20 @@ private $control_fields = array( } } // end if we are on the recording server } - public function GroupIds( ) { + public function GroupIds( $new='') { + if ( $new != '' ) { + if(!is_array($new)) { + $this->{'GroupIds'} = array($new); + } else { + $this->{'GroupIds'} = $new; + } + } + if ( !array_key_exists('GroupIds', $this) ) { if ( array_key_exists('Id', $this) and $this->{'Id'} ) { - $this->{'GroupIds'} = dbFetchAll( 'SELECT GroupId FROM Groups_Monitors WHERE MonitorId=?', 'GroupId', array($this->{'Id'}) ); + $this->{'GroupIds'} = dbFetchAll('SELECT GroupId FROM Groups_Monitors WHERE MonitorId=?', 'GroupId', array($this->{'Id'}) ); + if ( ! $this->{'GroupIds'} ) + $this->{'GroupIds'} = array(); } else { $this->{'GroupIds'} = array(); } From 2a81877664618e1c24b048d2c95f98c9038a11bd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:31:40 -0400 Subject: [PATCH 138/154] spacing --- web/includes/Monitor.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 3e574bf98..823491aa4 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -309,7 +309,7 @@ private $control_fields = array( return $filters; } - public function save( $new_values = null ) { + public function save($new_values = null) { if ( $new_values ) { foreach ( $new_values as $k=>$v ) { @@ -317,12 +317,12 @@ private $control_fields = array( } } - $fields = array_keys( $this->defaults ); + $fields = array_keys($this->defaults); - $sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?'; - $values = array_map( function($field){return $this->{$field};}, $fields ); + $sql = 'UPDATE Monitors SET '.implode(', ', array_map(function($field) {return $field.'=?';}, $fields )) . ' WHERE Id=?'; + $values = array_map(function($field){return $this->{$field};}, $fields); $values[] = $this->{'Id'}; - dbQuery( $sql, $values ); + dbQuery($sql, $values); } // end function save function zmcControl( $mode=false ) { From 5f415873d461d1a1b872b2ff7d2a153206057a44 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:32:15 -0400 Subject: [PATCH 139/154] Update GroupIds regardless of changes returned from getFormChanges on Monitor save --- web/includes/actions.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 423f63bcb..b112bebb8 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -458,7 +458,7 @@ if ( canEdit( 'Monitors' ) ) { $x10Monitor = array(); } } - $Monitor = new Monitor( $monitor ); + $Monitor = new Monitor($monitor); // Define a field type for anything that's not simple text equivalent $types = array( @@ -475,7 +475,7 @@ if ( canEdit( 'Monitors' ) ) { if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) { Logger::Debug("Auto selecting server"); - $_REQUEST['newMonitor']['ServerId'] = dbFetchOne( 'SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id' ); + $_REQUEST['newMonitor']['ServerId'] = dbFetchOne('SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id'); Logger::Debug("Auto selecting server: Got " . $_REQUEST['newMonitor']['ServerId'] ); if ( ( ! $_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) { $_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID; @@ -485,8 +485,8 @@ if ( canEdit( 'Monitors' ) ) { Logger::Debug("NOT Auto selecting server" . $_REQUEST['newMonitor']['ServerId']); } - $columns = getTableColumns( 'Monitors' ); - $changes = getFormChanges( $monitor, $_REQUEST['newMonitor'], $types, $columns ); + $columns = getTableColumns('Monitors'); + $changes = getFormChanges($monitor, $_REQUEST['newMonitor'], $types, $columns); if ( count( $changes ) ) { if ( $mid ) { @@ -565,6 +565,8 @@ if ( canEdit( 'Monitors' ) ) { return; } + $restart = true; + } # end if count(changes) if ( ( !isset($_POST['newMonitor']['GroupIds']) ) or @@ -581,8 +583,6 @@ if ( canEdit( 'Monitors' ) ) { } } } // end if there has been a change of groups - $restart = true; - } # end if count(changes) if ( ZM_OPT_X10 ) { $x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] ); From dfae6661ab811e90865b610fb59aecb097e9a47a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:32:40 -0400 Subject: [PATCH 140/154] use isset when determining if a column exists, otherwise we throw warnings --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 0e396a02f..2ae484784 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -486,7 +486,7 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) { $types = array(); foreach( $newValues as $key=>$value ) { - if ( $columns && !$columns[$key] ) + if ( $columns && !isset($columns[$key]) ) continue; if ( !isset($types[$key]) ) From 80f73854c7304d3bdd0065d41ca70055a0148850 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:33:02 -0400 Subject: [PATCH 141/154] Include the groupIds hidden when not on general tab --- web/skins/classic/views/monitor.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 424748410..522b45c31 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -62,7 +62,7 @@ if ( ! $monitor ) { $nextId = getTableAutoInc( 'Monitors' ); if ( isset( $_REQUEST['dupId'] ) ) { $monitor = new Monitor( $_REQUEST['dupId'] ); - $monitor->GroupIds(); // have to lead before we change the Id + $monitor->GroupIds(); // have to load before we change the Id if ( ZM_OPT_X10 ) $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId']) ); $clonedName = $monitor->Name(); @@ -534,6 +534,11 @@ if ( $tab != 'general' ) { +GroupIds() as $group_id ) { +echo ''; +} +?> From 161fc94496e3e6abcffd7f75c5656ba71ccc101f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:33:12 -0400 Subject: [PATCH 142/154] remove useless () --- web/includes/database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/database.php b/web/includes/database.php index 9ec113ff1..ea834de98 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -186,7 +186,7 @@ function dbFetchAll( $sql, $col=false, $params=NULL ) { $dbRows = array(); while( $dbRow = $result->fetch( PDO::FETCH_ASSOC ) ) $dbRows[] = $col?$dbRow[$col]:$dbRow; - return( $dbRows ); + return $dbRows; } function dbFetchAssoc( $sql, $indexCol, $dataCol=false ) { From 61fe2a734b8e96f908c0d69a4a60c784c0340685 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:38:18 -0400 Subject: [PATCH 143/154] Add SIGHUP handler so that zmc reloads instead of dies --- src/zmc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zmc.cpp b/src/zmc.cpp index 6b277ebcc..df116eaea 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -228,6 +228,7 @@ int main(int argc, char *argv[]) { sigset_t block_set; sigemptyset(&block_set); + sigaddset(&block_set, SIGHUP); sigaddset(&block_set, SIGUSR1); sigaddset(&block_set, SIGUSR2); From 8d1ae6ac49bd44da7374d170155e3445656f40e8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 09:39:05 -0400 Subject: [PATCH 144/154] add back in zm_update-1.31.30.sql --- db/zm_update-1.31.30.sql | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 db/zm_update-1.31.30.sql diff --git a/db/zm_update-1.31.30.sql b/db/zm_update-1.31.30.sql new file mode 100644 index 000000000..c87b4409a --- /dev/null +++ b/db/zm_update-1.31.30.sql @@ -0,0 +1,20 @@ +DROP TABLE IF EXISTS `Monitor_Status`; +CREATE TABLE `Monitor_Status` ( + `MonitorId` int(10) unsigned NOT NULL, + `Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown', + `CaptureFPS` DECIMAL(10,2) NOT NULL default 0, + `AnalysisFPS` DECIMAL(5,2) NOT NULL default 0, + PRIMARY KEY (`MonitorId`) +) ENGINE=MEMORY; + +SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO'; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='/var/cache/zoneminder/events' + ) > 0, + "SELECT 'Default Storage Area already exists.'", + "INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','/var/cache/zoneminder/events','Medium',NULL)" + )); + +PREPARE stmt FROM @s; +EXECUTE stmt; From 27531750a4a7169478c18ed61ae5c22480cea5b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 10:48:50 -0400 Subject: [PATCH 145/154] Google code style --- scripts/zmdc.pl.in | 224 ++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 114 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index c70fbe9b7..00c796a53 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -104,23 +104,23 @@ my @daemons = ( 'zmtelemetry.pl' ); -if ($Config{ZM_OPT_USE_EVENTNOTIFICATION}) { - push @daemons,'zmeventnotification.pl'; +if ( $Config{ZM_OPT_USE_EVENTNOTIFICATION} ) { + push @daemons,'zmeventnotification.pl'; } my $command = shift @ARGV; -if( ! $command ) { - print( STDERR "No command given\n" ); +if ( !$command ) { + print(STDERR "No command given\n"); pod2usage(-exitstatus => -1); } if ( $command eq 'version' ) { print ZoneMinder::Base::ZM_VERSION."\n"; - exit( 0 ); + exit(0); } my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/; -my $daemon = shift( @ARGV ); +my $daemon = shift @ARGV; if ( $needs_daemon && ! $daemon ) { - print( STDERR "No daemon given\n" ); + print(STDERR "No daemon given\n"); pod2usage(-exitstatus => -1); } my @args; @@ -130,7 +130,7 @@ if ( $needs_daemon ) { if ( $daemon =~ /^${daemon_patt}$/ ) { $daemon = $1; } else { - print( STDERR "Invalid daemon '$daemon' specified" ); + print(STDERR "Invalid daemon '$daemon' specified"); pod2usage(-exitstatus => -1); } } @@ -141,19 +141,19 @@ foreach my $arg ( @ARGV ) { if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) { push( @args, $1 ); } else { - print( STDERR "Bogus argument '$arg' found" ); - exit( -1 ); + print(STDERR "Bogus argument '$arg' found"); + exit(-1); } } my $dbh = zmDbConnect(); -socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); +socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); -my $saddr = sockaddr_un( SOCK_FILE ); -my $server_up = connect( CLIENT, $saddr ); +my $saddr = sockaddr_un(SOCK_FILE); +my $server_up = connect(CLIENT, $saddr); -if ( ! $server_up ) { +if ( !$server_up ) { if ( $Config{ZM_SERVER_ID} ) { use Sys::MemInfo qw(totalmem freemem totalswap freeswap); use ZoneMinder::Server qw(CpuLoad); @@ -168,16 +168,16 @@ if ( ! $server_up ) { exit(); } if ( $command eq 'check' ) { - print( "stopped\n" ); + print("stopped\n"); exit(); } elsif ( $command ne 'startup' ) { - print( "Unable to connect to server using socket at " . SOCK_FILE . "\n" ); + print("Unable to connect to server using socket at " . SOCK_FILE . "\n"); exit( -1 ); } # The server isn't there - print( "Starting server\n" ); - close( CLIENT ); + print("Starting server\n"); + close(CLIENT); if ( my $cpid = fork() ) { # Parent process just sleep and fall through @@ -185,7 +185,7 @@ if ( ! $server_up ) { # I'm still not sure why we need to re-init the logs logInit(); - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); + socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); my $attempts = 0; while( !connect(CLIENT, $saddr) ) { $attempts++; @@ -209,7 +209,6 @@ if ( ($command eq 'check') && !$daemon ) { } # The server is there, connect to it -#print( "Writing commands\n" ); CLIENT->autoflush(); my $message = join(';', $command, ( $daemon ? $daemon : () ), @args ); print(CLIENT $message); @@ -218,9 +217,7 @@ while( my $line = ) { chomp($line); print("$line\n"); } -# And we're done! close(CLIENT); -#print( "Finished writing, bye\n" ); exit; @@ -248,35 +245,35 @@ our %terminating_processes; sub run { my $fd = 0; - while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) { - POSIX::close( $fd++ ); + while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) { + POSIX::close($fd++); } setpgrp(); logInit(); - dPrint( ZoneMinder::Logger::INFO, 'Server starting at ' - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + dPrint(ZoneMinder::Logger::INFO, 'Server starting at ' + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); - if ( open( my $PID, '>', ZM_PID ) ) { - print( $PID $$ ); - close( $PID ); + if ( open(my $PID, '>', ZM_PID) ) { + print($PID $$); + close($PID); } else { - Error( "Can't open pid file at " . ZM_PID ); + Error("Can't open pid file at " . ZM_PID); } # Tell any existing processes to die, wait 1 second between TERM and KILL - killAll( 1 ); + killAll(1); - dPrint( ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE ); + dPrint(ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE); my $dbh = zmDbConnect(1); - socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); - unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if -e main::SOCK_FILE; - bind( SERVER, $saddr ) or Fatal( "Can't bind to " . main::SOCK_FILE . ": $!" ); - listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); + socket(SERVER, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); + unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if -e main::SOCK_FILE; + bind(SERVER, $saddr) or Fatal("Can't bind to " . main::SOCK_FILE . ": $!"); + listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); $SIG{CHLD} = \&reaper; $SIG{INT} = \&shutdownAll; @@ -285,7 +282,7 @@ sub run { $SIG{HUP} = \&logrot; my $rin = ''; - vec( $rin, fileno(SERVER), 1 ) = 1; + vec($rin, fileno(SERVER), 1) = 1; my $win = $rin; my $ein = $win; my $timeout = 1; @@ -294,8 +291,8 @@ sub run { if ( $Config{ZM_SERVER_ID} ) { require ZoneMinder::Server; - $Server = new ZoneMinder::Server( $Config{ZM_SERVER_ID} ); - dPrint( ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name} ); + $Server = new ZoneMinder::Server($Config{ZM_SERVER_ID}); + dPrint(ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name}); } while( 1 ) { @@ -311,41 +308,41 @@ sub run { } $secs_count += 1; } - my $nfound = select( my $rout = $rin, undef, undef, $timeout ); + my $nfound = select(my $rout = $rin, undef, undef, $timeout); if ( $nfound > 0 ) { - if ( vec( $rout, fileno(SERVER), 1 ) ) { - my $paddr = accept( CLIENT, SERVER ); + if ( vec($rout, fileno(SERVER), 1) ) { + my $paddr = accept(CLIENT, SERVER); my $message = ; next if !$message; - my ( $command, $daemon, @args ) = split( /;/, $message ); + my ( $command, $daemon, @args ) = split(';', $message); if ( $command eq 'start' ) { - start( $daemon, @args ); + start($daemon, @args); } elsif ( $command eq 'stop' ) { - stop( $daemon, @args ); + stop($daemon, @args); } elsif ( $command eq 'restart' ) { - restart( $daemon, @args ); + restart($daemon, @args); } elsif ( $command eq 'reload' ) { - reload( $daemon, @args ); + reload($daemon, @args); } elsif ( $command eq 'startup' ) { # Do nothing, this is all we're here for - dPrint( ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n" ); + dPrint(ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n"); } elsif ( $command eq 'shutdown' ) { shutdownAll(); } elsif ( $command eq 'check' ) { - check( $daemon, @args ); + check($daemon, @args); } elsif ( $command eq 'status' ) { if ( $daemon ) { - status( $daemon, @args ); + status($daemon, @args); } else { status(); } } elsif ( $command eq 'logrot' ) { logrot(); } else { - dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); + dPrint(ZoneMinder::Logger::ERROR, "Invalid command '$command'\n"); } close(CLIENT); } else { @@ -370,18 +367,18 @@ sub run { check_for_processes_to_kill(); } # end while - dPrint( ZoneMinder::Logger::INFO, 'Server exiting at ' + dPrint(ZoneMinder::Logger::INFO, 'Server exiting at ' .strftime( '%y/%m/%d %H:%M:%S', localtime() ) ."\n" ); if ( $Config{ZM_SERVER_ID} ) { $dbh = zmDbConnect() if ! $dbh->ping(); - if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID} ) ) { + if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID}) ) { Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); } } - unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE ); - unlink( ZM_PID ) or Error( 'Unable to unlink ' . ZM_PID .". Error message was: $!" ) if ( -e ZM_PID ); + unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE ); + unlink(ZM_PID) or Error('Unable to unlink ' . ZM_PID .". Error message was: $!") if ( -e ZM_PID ); exit(); } @@ -398,15 +395,15 @@ sub dPrint { print CLIENT @_ } if ( $logLevel == ZoneMinder::Logger::DEBUG ) { - Debug( @_ ); + Debug(@_); } elsif ( $logLevel == ZoneMinder::Logger::INFO ) { - Info( @_ ); + Info(@_); } elsif ( $logLevel == ZoneMinder::Logger::WARNING ) { - Warning( @_ ); + Warning(@_); } elsif ( $logLevel == ZoneMinder::Logger::ERROR ) { - Error( @_ ); + Error(@_); } elsif ( $logLevel == ZoneMinder::Logger::FATAL ) { - Fatal( @_ ); + Fatal(@_); } } @@ -414,61 +411,60 @@ sub start { my $daemon = shift; my @args = @_; - my $command = join(' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( !$process ) { # It's not running, or at least it's not been started by us $process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef }; } elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) { - dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}\n" ); - return(); + return; } my $sigset = POSIX::SigSet->new; my $blockset = POSIX::SigSet->new( SIGCHLD ); - sigprocmask( SIG_BLOCK, $blockset, $sigset ) or Fatal( "Can't block SIGCHLD: $!" ); + sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!"); if ( my $cpid = fork() ) { logReinit(); $process->{pid} = $cpid; $process->{started} = time(); - delete( $process->{pending} ); + delete $process->{pending}; - dPrint( ZoneMinder::Logger::INFO, "'$command' starting at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + dPrint(ZoneMinder::Logger::INFO, "'$command' starting at " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}\n" ); $cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process; - sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" ); - } elsif ( defined($cpid ) ) { + sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!"); + } elsif ( defined($cpid) ) { # Force reconnection to the db. $dbh = zmDbConnect(1); logReinit(); - dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) ) - ."' started at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + dPrint(ZoneMinder::Logger::INFO, "'$command' started at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); if ( $daemon =~ /^${daemon_patt}$/ ) { $daemon = $Config{ZM_PATH_BIN}.'/'.$1; } else { - Fatal( "Invalid daemon '$daemon' specified" ); + Fatal("Invalid daemon '$daemon' specified"); } my @good_args; foreach my $arg ( @args ) { # Detaint arguments, if they look ok if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) { - push( @good_args, $1 ); + push @good_args, $1; } else { - Fatal( "Bogus argument '$arg' found" ); + Fatal("Bogus argument '$arg' found"); } } @@ -476,8 +472,8 @@ sub start { zmDbDisconnect(); my $fd = 0; - while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) { - POSIX::close( $fd++ ); + while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) { + POSIX::close($fd++); } # Child process @@ -486,11 +482,11 @@ sub start { $SIG{TERM} = 'DEFAULT'; $SIG{ABRT} = 'DEFAULT'; - exec( $daemon, @good_args ) or Fatal( "Can't exec: $!" ); + exec($daemon, @good_args) or Fatal("Can't exec: $!"); } else { - Fatal( "Can't fork: $!" ); + Fatal("Can't fork: $!"); } -} +} # end sub start # Sends the stop signal, without waiting around to see if the process died. sub send_stop { @@ -499,9 +495,9 @@ sub send_stop { my $command = $process->{command}; if ( $process->{pending} ) { - delete( $cmd_hash{$command} ); - dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + delete $cmd_hash{$command}; + dPrint(ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); return(); @@ -509,12 +505,12 @@ sub send_stop { my $pid = $process->{pid}; if ( !$pid_hash{$pid} ) { - dPrint( ZoneMinder::Logger::ERROR, "No process with command of '$command' pid $pid is running\n" ); + dPrint(ZoneMinder::Logger::ERROR, "No process with command of '$command' pid $pid is running\n"); return(); } - dPrint( ZoneMinder::Logger::INFO, "'$command' sending stop to pid $pid at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + dPrint(ZoneMinder::Logger::INFO, "'$command' sending stop to pid $pid at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); $process->{keepalive} = !$final; @@ -522,8 +518,7 @@ sub send_stop { $process->{pending} = 0; $terminating_processes{$command} = $process; - - kill( 'TERM', $pid ); + kill('TERM', $pid); return $pid; } # end sub send_stop @@ -531,9 +526,10 @@ sub check_for_processes_to_kill { # Turn off SIGCHLD my $sigset = POSIX::SigSet->new; my $blockset = POSIX::SigSet->new(SIGCHLD); - sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n"; + sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n"; foreach my $command ( %terminating_processes ) { my $process = $cmd_hash{$command}; +Debug("Have process $command at pid $$process{pid} $$process{term_sent_at}"); if ( $$process{term_sent_at} - time > KILL_DELAY ) { dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " .strftime('%y/%m/%d %H:%M:%S', localtime()) @@ -551,11 +547,11 @@ sub stop { my $command = join(' ', $daemon, @args ); my $process = $cmd_hash{$command}; if ( !$process ) { - dPrint( ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n" ); + dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n"); return; } - send_stop( 1, $process ); + send_stop(1, $process); } # restart is the same as stop, except that we flag the processes for restarting once it dies @@ -563,7 +559,7 @@ sub stop { sub restart { my ( $daemon, @args ) = @_; - my $command = join(' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); dPrint(ZoneMinder::Logger::DEBUG, "Restarting $command\n"); my $process = $cmd_hash{$command}; if ( !$process ) { @@ -580,7 +576,7 @@ sub reload { my $daemon = shift; my @args = @_; - my $command = join(' ', $daemon, @args ) ; + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( $process ) { if ( $process->{pid} ) { @@ -591,7 +587,7 @@ sub reload { sub logrot { logReinit(); - foreach my $process ( values(%pid_hash) ) { + foreach my $process ( values %pid_hash ) { if ( $process->{pid} ) { # && $process->{command} =~ /^zm.*\.pl/ ) { kill('HUP', $process->{pid}); @@ -601,14 +597,14 @@ sub logrot { sub reaper { my $saved_status = $!; - while ( (my $cpid = waitpid( -1, WNOHANG )) > 0 ) { + while ( (my $cpid = waitpid(-1, WNOHANG)) > 0 ) { my $status = $?; my $process = $pid_hash{$cpid}; delete $pid_hash{$cpid}; if ( !$process ) { - dPrint( ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n" ); + dPrint(ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n"); next; } delete $terminating_processes{$$process{command}}; @@ -643,9 +639,9 @@ sub reaper { $out_str .= "\n"; if ( $exit_status == 0 ) { - Info( $out_str ); + Info($out_str); } else { - Error( $out_str ); + Error($out_str); } if ( $process->{keepalive} ) { @@ -685,7 +681,7 @@ sub shutdownAll { foreach my $pid ( keys %pid_hash ) { # This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here. next if ! $pid_hash{$pid}; - send_stop( 1, $pid_hash{$pid} ); + send_stop(1, $pid_hash{$pid}); } while ( %terminating_processes ) { check_for_processes_to_kill(); @@ -695,10 +691,10 @@ sub shutdownAll { .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); - unlink( main::SOCK_FILE ) or Error( "Unable to unlink " . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE ); - unlink( ZM_PID ) or Error( "Unable to unlink " . ZM_PID .". Error message was: $!" ) if ( -e ZM_PID ); - close( CLIENT ); - close( SERVER ); + unlink(main::SOCK_FILE) or Error("Unable to unlink " . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE ); + unlink(ZM_PID) or Error("Unable to unlink " . ZM_PID .". Error message was: $!") if ( -e ZM_PID ); + close(CLIENT); + close(SERVER); exit(); } @@ -706,18 +702,18 @@ sub check { my $daemon = shift; my @args = @_; - my $command = join( ' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( !$process ) { - cPrint( "unknown\n" ); + cPrint("unknown\n"); } elsif ( $process->{pending} ) { - cPrint( "pending\n" ); + cPrint("pending\n"); } else { my $cpid = $process->{pid}; if ( ! $pid_hash{$cpid} ) { - cPrint( "stopped\n" ); + cPrint("stopped\n"); } else { - cPrint( "running\n" ); + cPrint("running\n"); } } } @@ -785,14 +781,14 @@ sub killAll { } foreach my $daemon ( @daemons ) { my $cmd = $killall ."TERM $daemon"; - Debug( $cmd ); - qx( $cmd ); + Debug($cmd); + qx($cmd); } - sleep( $delay ); + sleep($delay); foreach my $daemon ( @daemons ) { my $cmd = $killall."KILL $daemon"; - Debug( $cmd ); - qx( $cmd ); + Debug($cmd); + qx($cmd); } } 1; From 8bdc68dc65b4ac83497810c93b465ec35344e749 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 10:49:35 -0400 Subject: [PATCH 146/154] include zm_signal.h so that we have access to zm_terminate. Use zm_terminate to break out of endless loops. Add incoming bytes counts --- src/zm_remote_camera_http.cpp | 49 +++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index c22816747..9c91d235b 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -21,6 +21,7 @@ #include "zm_rtsp_auth.h" #include "zm_mem_utils.h" +#include "zm_signal.h" #include #include @@ -192,24 +193,24 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) { struct timeval temp_timeout = timeout; - int n_found = select( sd+1, &rfds, NULL, NULL, &temp_timeout ); + int n_found = select(sd+1, &rfds, NULL, NULL, &temp_timeout); if( n_found == 0 ) { - Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); + Debug( 1, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); int error = 0; socklen_t len = sizeof (error); int retval = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len); if(retval != 0 ) { Debug( 1, "error getting socket error code %s", strerror(retval) ); } - if (error != 0) { + if (error != 0 ) { return -1; } // Why are we disconnecting? It's just a timeout, meaning that data wasn't available. //Disconnect(); - return( 0 ); + return 0; } else if ( n_found < 0) { - Error( "Select error: %s", strerror(errno) ); - return( -1 ); + Error("Select error: %s", strerror(errno)); + return -1; } unsigned int total_bytes_to_read = 0; @@ -309,13 +310,14 @@ int RemoteCameraHttp::GetResponse() static RegExpr *content_length_expr = 0; static RegExpr *content_type_expr = 0; - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting for REGEXP HEADER"); } if ( buffer_len < 0 ) { Error( "Unable to read header data" ); return( -1 ); } + bytes += buffer_len; if ( !header_expr ) header_expr = new RegExpr( "^(.+?\r?\n\r?\n)", PCRE_DOTALL ); if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 ) @@ -483,13 +485,14 @@ int RemoteCameraHttp::GetResponse() else { Debug( 3, "Unable to extract subheader from stream, retrying" ); - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting to extract subheader"); } if ( buffer_len < 0 ) { Error( "Unable to extract subheader data" ); return( -1 ); } + bytes += buffer_len; } break; } @@ -522,13 +525,16 @@ int RemoteCameraHttp::GetResponse() if ( content_length ) { - while ( (long)buffer.size() < content_length ) + while ( ((long)buffer.size() < content_length ) && ! zm_terminate ) { Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_length ); - if ( ReadData( buffer ) < 0 ) { + int bytes_read = ReadData( buffer ); + + if ( bytes_read < 0 ) { Error( "Unable to read content" ); return( -1 ); } + bytes += bytes_read; } Debug( 3, "Got end of image by length, content-length = %d", content_length ); } @@ -536,13 +542,14 @@ int RemoteCameraHttp::GetResponse() { while ( !content_length ) { - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting for content"); } if ( buffer_len < 0 ) { Error( "Unable to read content" ); return( -1 ); } + bytes += buffer_len; static RegExpr *content_expr = 0; if ( mode == MULTI_IMAGE ) { @@ -656,13 +663,14 @@ int RemoteCameraHttp::GetResponse() } case HEADERCONT : { - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting for HEADERCONT"); } if ( buffer_len < 0 ) { Error( "Unable to read header" ); return( -1 ); } + bytes += buffer_len; char *crlf = 0; char *header_ptr = (char *)buffer; @@ -941,13 +949,14 @@ int RemoteCameraHttp::GetResponse() state = CONTENT; } else { Debug( 3, "Unable to extract subheader from stream, retrying" ); - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) &&!zm_terminate ) { Debug(1, "Timeout waiting to extra subheader non regexp"); } if ( buffer_len < 0 ) { Error( "Unable to read subheader" ); return( -1 ); } + bytes += buffer_len; state = SUBHEADERCONT; } break; @@ -980,18 +989,19 @@ int RemoteCameraHttp::GetResponse() } if ( content_length ) { - while ( (long)buffer.size() < content_length ) { - //int buffer_len = ReadData( buffer, content_length-buffer.size() ); + while ( ( (long)buffer.size() < content_length ) && ! zm_terminate ) { Debug(4, "getting more data"); - if ( ReadData( buffer ) < 0 ) { - Error( "Unable to read content" ); - return( -1 ); + int bytes_read = ReadData(buffer); + if ( bytes_read < 0 ) { + Error("Unable to read content"); + return -1; } + bytes += bytes_read; } Debug( 3, "Got end of image by length, content-length = %d", content_length ); } else { // Read until we find the end of image or the stream closes. - while ( !content_length ) { + while ( !content_length && !zm_terminate ) { Debug(4, "!content_length, ReadData"); buffer_len = ReadData( buffer ); if ( buffer_len < 0 ) @@ -999,6 +1009,7 @@ int RemoteCameraHttp::GetResponse() Error( "Unable to read content" ); return( -1 ); } + bytes += buffer_len; int buffer_size = buffer.size(); if ( buffer_len ) { // Got some data From 1907b18ac24c538ffa8d326fe3987dc941739781 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 12:36:18 -0400 Subject: [PATCH 147/154] fix libnumber-bytes-human => libnumber-bytes-human-perl --- distros/ubuntu1204/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/ubuntu1204/control b/distros/ubuntu1204/control index 8c9bf2e61..febcb9435 100644 --- a/distros/ubuntu1204/control +++ b/distros/ubuntu1204/control @@ -54,7 +54,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,liburi-encode-perl ,libwww-perl ,libdata-uuid-perl - ,libnumber-bytes-human + ,libnumber-bytes-human-perl ,libfile-slurp-perl ,mysql-client | virtual-mysql-client ,perl-modules From 636d0caf30a4d64d3fb800f5db7a8e4d8da76951 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 10:28:19 -0700 Subject: [PATCH 148/154] handle no swap --- web/skins/classic/views/options.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 697abd6e5..42da8ae70 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -234,7 +234,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI +"> From f2073c958f27716eeb266b2545b209848f6f6eac Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 10:33:42 -0700 Subject: [PATCH 149/154] more debug --- scripts/zmdc.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 00c796a53..ab6d4e4c6 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -530,7 +530,7 @@ sub check_for_processes_to_kill { foreach my $command ( %terminating_processes ) { my $process = $cmd_hash{$command}; Debug("Have process $command at pid $$process{pid} $$process{term_sent_at}"); - if ( $$process{term_sent_at} - time > KILL_DELAY ) { + if ( $$process{term_sent_at} and ( $$process{term_sent_at} - time > KILL_DELAY ) ) { dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " .strftime('%y/%m/%d %H:%M:%S', localtime()) .' after ' . KILL_DELAY . ' seconds.' From 00e82fb75108981eb8fa637222c17ca304ec0321 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Apr 2018 13:04:46 -0700 Subject: [PATCH 150/154] Implement MonitoServerId,StorageServerId,FilterServerID in Filters --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 11 +++++--- scripts/zmdc.pl.in | 6 ++--- web/includes/database.php | 2 +- web/includes/functions.php | 10 +++++++ web/lang/en_gb.php | 4 ++- web/skins/classic/views/filter.php | 7 +++-- web/skins/classic/views/js/filter.js | 29 +++++++++------------ 7 files changed, 41 insertions(+), 28 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 065a2339b..b78b801f1 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -160,9 +160,12 @@ sub Sql { if ( $term->{attr} =~ /^Monitor/ ) { my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/; $self->{Sql} .= 'M.'.$temp_attr_name; - } elsif ( $term->{attr} =~ /^Server/ ) { + } elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) { + $self->{Sql} .= 'M.'.$term->{attr}; + } elsif ( $term->{attr} eq 'StorageServerId' ) { $self->{Sql} .= 'S.'.$term->{attr}; - + } elsif ( $term->{attr} eq 'FilterServerId' ) { + $self->{Sql} .= $Config{ZM_SERVER_ID}; # StartTime options } elsif ( $term->{attr} eq 'DateTime' ) { $self->{Sql} .= 'E.StartTime'; @@ -208,7 +211,7 @@ sub Sql { foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) { if ( $term->{attr} =~ /^MonitorName/ ) { $value = "'$temp_value'"; - } elsif ( $term->{attr} eq 'ServerId' ) { + } elsif ( $term->{attr} =~ /ServerId/) { Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})"); if ( $temp_value eq 'ZM_SERVER_ID' ) { $value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'"; @@ -241,7 +244,7 @@ sub Sql { } $value = "'$value'"; } - } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) { + } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) { if ( $temp_value eq 'NULL' ) { $value = $temp_value; } else { diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index ab6d4e4c6..d7627ac42 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -346,14 +346,13 @@ sub run { } close(CLIENT); } else { - Fatal('Bogus descriptor'); + Error('Bogus descriptor'); } } elsif ( $nfound < 0 ) { if ( $! == EINTR ) { # Dead child, will be reaped #print( "Probable dead child\n" ); # See if it needs to start up again - restartPending(); } elsif ( $! == EPIPE ) { Error("Can't select: $!"); } else { @@ -361,12 +360,13 @@ sub run { } } else { #print( "Select timed out\n" ); - restartPending(); } + restartPending(); check_for_processes_to_kill(); } # end while + dPrint(ZoneMinder::Logger::INFO, 'Server exiting at ' .strftime( '%y/%m/%d %H:%M:%S', localtime() ) ."\n" diff --git a/web/includes/database.php b/web/includes/database.php index 82fc3c765..2c3a818c1 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -133,7 +133,7 @@ function dbQuery( $sql, $params=NULL ) { } } else { if ( defined('ZM_DB_DEBUG') ) { - Logger::Debug("SQL: $sql values:" . $params?implode(',',$params):'' ); + Logger::Debug("SQL: $sql values:" . ($params?implode(',',$params):'') ); } $result = $dbConn->query($sql); } diff --git a/web/includes/functions.php b/web/includes/functions.php index 2ae484784..1bca995b4 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1004,8 +1004,15 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { $filter['sql'] .= 'M.'.preg_replace('/^Monitor/', '', $terms[$i]['attr']); break; case 'ServerId': + case 'MonitorServerId': $filter['sql'] .= 'M.ServerId'; break; + case 'StorageServerId': + $filter['sql'] .= 'S.ServerId'; + break; + case 'FilterServerId': + $filter['sql'] .= ZM_SERVER_ID; + break; # Unspecified start or end, so assume start, this is to support legacy filters case 'DateTime': $filter['sql'] .= 'E.StartTime'; @@ -1100,6 +1107,9 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { case 'Notes': $value = dbEscape($value); break; + case 'MonitorServerId': + case 'FilterServerId': + case 'StorageServerId': case 'ServerId': if ( $value == 'ZM_SERVER_ID' ) { $value = ZM_SERVER_ID; diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 6e97eaab8..786d38dff 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -130,7 +130,9 @@ $SLANG = array( 'AttrMonitorId' => 'Monitor Id', 'AttrMonitorName' => 'Monitor Name', 'AttrStorageArea' => 'Storage Area', - 'AttrServer' => 'Server', + 'AttrFilterServer' => 'Server Filter is Running On', + 'AttrMonitorServer' => 'Server Monitor is Running On', + 'AttrStorageServer' => 'Server Hosting Storage', 'AttrStateId' => 'Run State', 'AttrName' => 'Name', 'AttrNotes' => 'Notes', diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 5c639cecc..2f82fcd49 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -101,7 +101,10 @@ $attrTypes = array( 'DiskSpace' => translate('AttrDiskSpace'), 'SystemLoad' => translate('AttrSystemLoad'), 'StorageId' => translate('AttrStorageArea'), - 'ServerId' => translate('AttrServer'), + 'ServerId' => translate('AttrMonitorServer'), + 'FilterServerId' => translate('AttrFilterServer'), + 'MonitorServerId' => translate('AttrMonitorServer'), + 'StorageServerId' => translate('AttrStorageServer'), 'StateId' => translate('AttrStateId'), ); @@ -268,7 +271,7 @@ for ( $i=0; $i < count($terms); $i++ ) { diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index 4df73997e..f752dbff7 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -142,7 +142,9 @@ function parseRows (rows) { inputTds.eq(6).find(':input[value="-"]').prop('disabled', false); } - if (inputTds.eq(2).children().val() == "Archived") { //Archived types + var attr = inputTds.eq(2).children().val(); + + if ( attr == "Archived") { //Archived types inputTds.eq(3).html('equal to'); let archiveSelect = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); for (let i = 0; i < archiveTypes.length; i++) { @@ -151,7 +153,7 @@ function parseRows (rows) { let archiveVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(archiveSelect).children().val(archiveVal).chosen({width: "101%"}); - } else if (inputTds.eq(2).children().val().indexOf('Weekday') >= 0) { //Weekday selection + } else if ( attr.indexOf('Weekday') >= 0 ) { //Weekday selection let weekdaySelect = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); for (let i = 0; i < weekdays.length; i++) { weekdaySelect.append(''); @@ -159,7 +161,7 @@ function parseRows (rows) { let weekdayVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(weekdaySelect).children().val(weekdayVal).chosen({width: "101%"}); - } else if (inputTds.eq(2).children().val() == 'StateId') { //Run state + } else if ( attr == 'StateId' ) { //Run state let stateSelect = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); for (let key in states) { stateSelect.append(''); @@ -167,8 +169,7 @@ function parseRows (rows) { let stateVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(stateSelect).children().val(stateVal).chosen({width: "101%"}); - - } else if (inputTds.eq(2).children().val() == 'ServerId') { //Select Server + } else if ( attr == 'ServerId' || attr == 'MonitorServerId' || attr == 'StorageServerId' || attr == 'FilterServerId' ) { //Select Server let serverSelect = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); for (let key in servers) { serverSelect.append(''); @@ -176,21 +177,15 @@ function parseRows (rows) { let serverVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(serverSelect).children().val(serverVal).chosen({width: "101%"}); - } else if (inputTds.eq(2).children().val() == 'StorageId') { //Choose by storagearea + } else if ( attr == 'StorageId' ) { //Choose by storagearea let storageSelect = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); for ( key in storageareas ) { -console.log(key + ' ' + storageareas[key]); storageSelect.append(''); -} -/* - for (let i=0; i < storageareas.length; i++) { - storageSelect.append(''); } -*/ let storageVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"}); - } else if (inputTds.eq(2).children().val() == 'MonitorName') { //Monitor names + } else if ( attr == 'MonitorName' ) { //Monitor names let monitorSelect = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); for (let key in monitors) { monitorSelect.append(''); @@ -208,15 +203,15 @@ console.log(key + ' ' + storageareas[key]); let textVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(textInput).children().val(textVal); } - if (inputTds.eq(2).children().val().endsWith('DateTime')) { //Start/End DateTime + if ( attr.endsWith('DateTime') ) { //Start/End DateTime inputTds.eq(4).children().datetimepicker({timeFormat: "HH:mm:ss", dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false}); - } else if (inputTds.eq(2).children().val().endsWith('Date')) { //Start/End Date + } else if ( attr.endsWith('Date') ) { //Start/End Date inputTds.eq(4).children().datepicker({dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false}); - } else if (inputTds.eq(2).children().val().endsWith('Time')) { //Start/End Time + } else if ( attr.endsWith('Time')) { //Start/End Time inputTds.eq(4).children().timepicker({timeFormat: "HH:mm:ss", constrainInput: false}); } - let attr = inputTds.find("[name$='attr\\]']") // Set attr list id and name + attr = inputTds.find("[name$='attr\\]']") // Set attr list id and name let term = attr.attr('name').split(/[[\]]{1,2}/); term.length--; term.shift(); From 86b2f6a12ed57a8e49b2427e9841c59bc6cd45f0 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 26 Apr 2018 16:18:36 -0500 Subject: [PATCH 151/154] New Monitor Type - Website (#2065) * implement website monitor * don't check certain fields when using website monitor * continue to fix javascript errors for website monitors * check $monitor, not $new_monitor here * add website monitor documentation was somehow left out of the initial commit * fix corruption of functions.php * add missing comma * remove errors by testing for existence of key. If it's a new monitor, then none of the keys will be valid * If the monitor type is WebSite, then default Status to Running. * put back start function that got lost in merge. Don't start StreamCmd's if it's a WebSite * Add midding comma * Hide unrelated tabs when type is WebSite. Put back input fields for Type=WebSite * Don't show control or any of the status fields for WebSite type monitors * add some parenthesis to ensure order of operations, seems to fix fps and status fields not being shown for regular monitors --- db/zm_create.sql.in | 2 +- db/zm_update-1.31.43.sql | 24 +++ distros/redhat/zoneminder.spec | 2 +- docs/userguide/definemonitor.rst | 17 +++ .../lib/ZoneMinder/ConfigData.pm.in | 17 +++ scripts/zmpkg.pl.in | 2 +- scripts/zmwatch.pl.in | 1 + version | 2 +- .../Console/Templates/skel/Console/cake.bat | 60 ++++---- web/api/lib/Cake/Console/cake.bat | 56 +++---- web/includes/actions.php | 28 ++-- web/includes/functions.php | 39 ++++- web/lang/en_gb.php | 3 + web/skins/classic/views/console.php | 9 +- web/skins/classic/views/js/monitor.js.php | 101 +++++++------ web/skins/classic/views/js/montage.js | 54 +++++-- web/skins/classic/views/js/montage.js.php | 4 +- web/skins/classic/views/js/watch.js | 142 ++++++++++-------- web/skins/classic/views/js/watch.js.php | 2 + web/skins/classic/views/monitor.php | 57 ++++--- web/skins/classic/views/montage.php | 8 +- web/skins/classic/views/montagereview.php | 2 +- web/skins/classic/views/watch.php | 8 +- 23 files changed, 406 insertions(+), 234 deletions(-) create mode 100644 db/zm_update-1.31.43.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 0dad55059..b7cfca3c5 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -63,7 +63,7 @@ DROP TABLE IF EXISTS `Controls`; CREATE TABLE `Controls` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', - `Type` enum('Local','Remote','Ffmpeg','Libvlc','cURL') NOT NULL default 'Local', + `Type` enum('Local','Remote','Ffmpeg','Libvlc','cURL','WebSite') NOT NULL default 'Local', `Protocol` varchar(64) default NULL, `CanWake` tinyint(3) unsigned NOT NULL default '0', `CanSleep` tinyint(3) unsigned NOT NULL default '0', diff --git a/db/zm_update-1.31.43.sql b/db/zm_update-1.31.43.sql new file mode 100644 index 000000000..d8d6eaefd --- /dev/null +++ b/db/zm_update-1.31.43.sql @@ -0,0 +1,24 @@ +-- +-- This updates a 1.31.42 database to 1.31.43 +-- +-- Add WebSite enum to Monitor.Type +-- Add Refresh column to Monitors table +-- + +ALTER TABLE `zm`.`Monitors` +CHANGE COLUMN `Type` `Type` ENUM('Local', 'Remote', 'File', 'Ffmpeg', 'Libvlc', 'cURL', 'WebSite') NOT NULL DEFAULT 'Local' ; + +SET @s = (SELECT IF( + (SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'Monitors' + AND table_schema = DATABASE() + AND column_name = 'Refresh' + ) > 0, +"SELECT 'Column Refresh exists in Monitors'", +"ALTER TABLE Monitors ADD `Refresh` int(10) unsigned default NULL" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 9ef5b2606..c52ccbad9 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -26,7 +26,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.31.42 +Version: 1.31.43 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/docs/userguide/definemonitor.rst b/docs/userguide/definemonitor.rst index 66e8928d3..8f85feb98 100644 --- a/docs/userguide/definemonitor.rst +++ b/docs/userguide/definemonitor.rst @@ -147,6 +147,23 @@ Keep aspect ratio Orientation As per local devices. +WebSite +^^^^^^^ + +This Source Type allows one to configure an arbitrary website as a non-reocrdable, fully interactive, monitor in ZoneMinder. Note that sites with self-signed certificates will not display until the end user first manually navigates to the site and accpets the unsigned certificate. Also note that some sites will set an X-Frame option in the header, which discourages their site from being displayed within a frame. ZoneMinder will detect this condition and present a warning in the log. When this occurs, the end user can choose to install a browser plugin or extension to workaround this issue. + +Website URL + Enter the full http or https url to the desired website. + +Width (pixels) + Chose a desired width in pixels that gives an acceptable appearance. This may take some expirimentation. + +Height (pixels) + Chose a desired height in pixels that gives an acceptable appearance. This may take some expirimentation. + +Web Site Refresh + If the website in question has static content, optionally enter a time period in seconds for ZoneMinder to refresh the content. + Timestamp Tab ------------- diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index addd6239b..6eb41e57e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -2946,6 +2946,23 @@ our @options = ( type => $types{boolean}, category => 'web', }, + { + name => 'ZM_WEB_XFRAME_WARN', + default => 'yes', + description => 'Warn when website X-Frame-Options is set to sameorigin', + help => q` + When creating a Web Site monitor, if the target web site has + X-Frame-Options set to sameorigin in the header, the site will + not display in ZoneMinder. This is a design feature in most modern + browsers. When this condiction has occured, ZoneMinder will write a + warning to the log file. To get around this, one can install a browser + plugin or extension to ignore X-Frame headers, and then the page will + display properly. Once the plugin or extenstion has ben installed, + the end user may choose to turn this warning off. + `, + type => $types{boolean}, + category => 'web', + }, { name => 'ZM_WEB_H_REFRESH_MAIN', default => '60', diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 6b6839bff..62771c7aa 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -211,7 +211,7 @@ if ( $command =~ /^(?:start|restart)$/ ) { my $res = $sth->execute( @values ) or Fatal( "Can't execute: ".$sth->errstr() ); while( my $monitor = $sth->fetchrow_hashref() ) { - if ( $monitor->{Function} ne 'None' ) { + if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) { if ( $monitor->{Type} eq 'Local' ) { runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); } else { diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index 7d21ecfee..28a8d4a9b 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -84,6 +84,7 @@ while( 1 ) { while( my $monitor = $sth->fetchrow_hashref() ) { my $now = time(); next if $monitor->{Function} eq 'None'; + next if $monitor->{Type} eq 'WebSite'; my $restart = 0; if ( zmMemVerify( $monitor ) ) { # Check we have got an image recently diff --git a/version b/version index dd8165476..92522fa6a 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.42 +1.31.43 diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat b/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat index 722febf10..31bde01b1 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat +++ b/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat @@ -1,30 +1,30 @@ -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:: -:: Bake is a shell script for running CakePHP bake script -:: -:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) -:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) -:: -:: Licensed under The MIT License -:: Redistributions of files must retain the above copyright notice. -:: -:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) -:: @link https://cakephp.org CakePHP(tm) Project -:: @package app.Console -:: @since CakePHP(tm) v 2.0 -:: -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -:: In order for this script to work as intended, the cake\console\ folder must be in your PATH - -@echo. -@echo off - -SET app=%0 -SET lib=%~dp0 - -php -q "%lib%cake.php" -working "%CD% " %* - -echo. - -exit /B %ERRORLEVEL% +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Bake is a shell script for running CakePHP bake script +:: +:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: +:: Licensed under The MIT License +:: Redistributions of files must retain the above copyright notice. +:: +:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: @link https://cakephp.org CakePHP(tm) Project +:: @package app.Console +:: @since CakePHP(tm) v 2.0 +:: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +:: In order for this script to work as intended, the cake\console\ folder must be in your PATH + +@echo. +@echo off + +SET app=%0 +SET lib=%~dp0 + +php -q "%lib%cake.php" -working "%CD% " %* + +echo. + +exit /B %ERRORLEVEL% diff --git a/web/api/lib/Cake/Console/cake.bat b/web/api/lib/Cake/Console/cake.bat index 7aa9ad78f..8792173ef 100644 --- a/web/api/lib/Cake/Console/cake.bat +++ b/web/api/lib/Cake/Console/cake.bat @@ -1,28 +1,28 @@ -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:: -:: Bake is a shell script for running CakePHP bake script -:: -:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) -:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) -:: -:: Licensed under The MIT License -:: Redistributions of files must retain the above copyright notice. -:: -:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) -:: @link https://cakephp.org CakePHP(tm) Project -:: @package Cake.Console -:: @since CakePHP(tm) v 1.2.0.5012 -:: @license https://opensource.org/licenses/mit-license.php MIT License -:: -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -@echo off - -SET app=%0 -SET lib=%~dp0 - -php -q "%lib%cake.php" -working "%CD% " %* - -echo. - -exit /B %ERRORLEVEL% +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Bake is a shell script for running CakePHP bake script +:: +:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: +:: Licensed under The MIT License +:: Redistributions of files must retain the above copyright notice. +:: +:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: @link https://cakephp.org CakePHP(tm) Project +:: @package Cake.Console +:: @since CakePHP(tm) v 1.2.0.5012 +:: @license https://opensource.org/licenses/mit-license.php MIT License +:: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +@echo off + +SET app=%0 +SET lib=%~dp0 + +php -q "%lib%cake.php" -working "%CD% " %* + +echo. + +exit /B %ERRORLEVEL% diff --git a/web/includes/actions.php b/web/includes/actions.php index 423f63bcb..d0540b8dc 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -299,10 +299,12 @@ if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) { continue; } $Monitor = new Monitor( $mid ); - $Monitor->zmaControl('stop'); - $Monitor->zmcControl('stop'); + if ( $Monitor->Type() != 'WebSite' ) { + $Monitor->zmaControl('stop'); + $Monitor->zmcControl('stop'); + } $Monitor->save( $_REQUEST['newMonitor'] ); - if ($Monitor->Function() != 'None' ) { + if ($Monitor->Function() != 'None' && $Monitor->Type() != 'WebSite' ) { $Monitor->zmcControl('start'); if ( $Monitor->Enabled() ) { $Monitor->zmaControl('start'); @@ -330,7 +332,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) { $monitor['Function'] = $newFunction; $monitor['Enabled'] = $newEnabled; - if ( daemonCheck() ) { + if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) { $restart = ($oldFunction == 'None') || ($newFunction == 'None') || ($newEnabled != $oldEnabled); zmaControl( $monitor, 'stop' ); zmcControl( $monitor, $restart?'restart':'' ); @@ -371,7 +373,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) { } else { dbQuery( 'INSERT INTO Zones SET MonitorId=?, '.implode( ', ', $changes ), array( $mid ) ); } - if ( daemonCheck() ) { + if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) { if ( $_REQUEST['newZone']['Type'] == 'Privacy' ) { zmaControl( $monitor, 'stop' ); zmcControl( $monitor, 'restart' ); @@ -399,7 +401,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) { } } if($changes>0) { - if ( daemonCheck() ) { + if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) { zmaControl( $mid, 'restart' ); } $refreshParent = true; @@ -424,7 +426,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) { $deletedZid = 1; } if ( $deletedZid ) { - if ( daemonCheck() ) { + if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) { if ( $zone['Type'] == 'Privacy' ) { zmaControl( $mid, 'stop' ); zmcControl( $mid, 'restart' ); @@ -492,8 +494,10 @@ if ( canEdit( 'Monitors' ) ) { if ( $mid ) { # If we change anything that changes the shared mem size, zma can complain. So let's stop first. - zmaControl( $monitor, 'stop' ); - zmcControl( $monitor, 'stop' ); + if ( $monitor['Type'] != 'WebSite' ) { + zmaControl( $monitor, 'stop' ); + zmcControl( $monitor, 'stop' ); + } dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) ); // Groups will be added below if ( isset($changes['Name']) or isset($changes['StorageId']) ) { @@ -606,8 +610,10 @@ if ( canEdit( 'Monitors' ) ) { $new_monitor = new Monitor($mid); //fixDevices(); - $new_monitor->zmcControl('start'); - $new_monitor->zmaControl('start'); + if ( $monitor['Type'] != 'WebSite' ) { + $new_monitor->zmcControl('start'); + $new_monitor->zmaControl('start'); + } if ( $new_monitor->Controllable() ) { require_once( 'control_functions.php' ); diff --git a/web/includes/functions.php b/web/includes/functions.php index 0e396a02f..27974b222 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -280,6 +280,27 @@ function getImageStill( $id, $src, $width, $height, $title='' ) { return ''.$title.''; } +function getWebSiteUrl( $id, $src, $width, $height, $title='' ) { + # Prevent unsightly warnings when php cannot verify the ssl certificate + stream_context_set_default( [ + 'ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ], + ]); + # The End User can turn off the following warning under Options -> Web + if ( ZM_WEB_XFRAME_WARN ) { + $header = get_headers($src, 1); + # If the target website has set X-Frame-Options, check it for "sameorigin" and warn the end user + if (array_key_exists('X-Frame-Options', $header)) { + $header = $header['X-Frame-Options']; + if ( stripos($header, 'sameorigin') === 0 ) + Warning("Web site $src has X-Frame-Options set to sameorigin. An X-Frame-Options browser plugin is required to display this site."); + } + } + return ''; +} + function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) { ?>
    @@ -486,7 +507,7 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) { $types = array(); foreach( $newValues as $key=>$value ) { - if ( $columns && !$columns[$key] ) + if ( $columns && !isset($columns[$key]) ) continue; if ( !isset($types[$key]) ) @@ -495,11 +516,11 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) { switch( $types[$key] ) { case 'set' : { - if ( is_array( $newValues[$key] ) ) { - if ( join(',',$newValues[$key]) != $values[$key] ) { + if ( is_array($newValues[$key]) ) { + if ( (!isset($values[$key])) or ( join(',',$newValues[$key]) != $values[$key] ) ) { $changes[$key] = "`$key` = ".dbEscape(join(',',$newValues[$key])); } - } elseif ( $values[$key] ) { + } else if ( (!isset($values[$key])) or $values[$key] ) { $changes[$key] = "`$key` = ''"; } break; @@ -548,7 +569,7 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) { } case 'raw' : { - if ( $values[$key] != $value ) { + if ( (!isset($values[$key])) or ($values[$key] != $value) ) { $changes[$key] = $key . ' = '.dbEscape($value); } break; @@ -2128,8 +2149,14 @@ function getStreamHTML( $monitor, $options = array() ) { $options['buffer'] = $monitor->StreamReplayBuffer(); //Warning("width: " . $options['width'] . ' height: ' . $options['height']. ' scale: ' . $options['scale'] ); + if ( $monitor->Type() == "WebSite" ) { + return getWebSiteUrl( 'liveStream'.$monitor->Id(), $monitor->Path(), + ( isset($options['width']) ? $options['width'] : NULL ), + ( isset($options['height']) ? $options['height'] : NULL ), + $monitor->Name() + ); //FIXME, the width and height of the image need to be scaled. - if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { + } else if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { $streamSrc = $monitor->getStreamSrc( array( 'mode'=>'mpeg', 'scale'=>(isset($options['scale'])?$options['scale']:100), diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 6e97eaab8..262870d82 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -174,8 +174,10 @@ $SLANG = array( 'BadSectionLength' => 'Section length must be an integer of 30 or more', 'BadSignalCheckColour' => 'Signal check colour must be a valid RGB colour string', 'BadStreamReplayBuffer' => 'Stream replay buffer must be an integer of zero or more', + 'BadSourceType' => 'Source Type \"Web Site\" requires the Function to be set to \"Monitor\"', 'BadWarmupCount' => 'Warmup frames must be an integer of zero or more', 'BadWebColour' => 'Web colour must be a valid web colour string', + 'BadWebSitePath' => 'Please enter a complete website url, including the http:// or https:// prefix.', 'BadWidth' => 'Width must be set to a valid value', 'Bandwidth' => 'Bandwidth', 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing @@ -768,6 +770,7 @@ $SLANG = array( 'Watch' => 'Watch', 'WebColour' => 'Web Colour', 'Web' => 'Web', + 'WebSiteUrl' => 'Website URL', 'Week' => 'Week', 'WhiteBalance' => 'White Balance', 'White' => 'White', diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 7565335bb..e21cf5311 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -110,6 +110,9 @@ $status_counts = array(); for ( $i = 0; $i < count($displayMonitors); $i++ ) { $monitor = &$displayMonitors[$i]; if ( ! $monitor['Status'] ) { + if ( $monitor['Type'] == 'WebSite' ) + $monitor['Status'] = 'Running'; + else $monitor['Status'] = 'NotRunning'; } if ( !isset($status_counts[$monitor['Status']]) ) @@ -220,7 +223,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { ?> "; - if ( form.elements['newMonitor[AnalysisFPSLimit]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPSLimit]'].value) > 0 ) ) - errors[errors.length] = ""; - if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) ) - errors[errors.length] = ""; - if ( form.elements['newMonitor[AlarmMaxFPS]'].value && !(parseFloat(form.elements['newMonitor[AlarmMaxFPS]'].value) > 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[RefBlendPerc]'].value || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) > 100 ) || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) < 0 ) ) - errors[errors.length] = ""; if ( form.elements['newMonitor[Type]'].value == 'Local' ) { if ( !form.elements['newMonitor[Palette]'].value || !form.elements['newMonitor[Palette]'].value.match( /^\d+$/ ) ) errors[errors.length] = ""; @@ -81,44 +73,63 @@ function validateForm( form ) { } else if ( form.elements['newMonitor[Type]'].value == 'File' ) { if ( !form.elements['newMonitor[Path]'].value ) errors[errors.length] = ""; + } else if ( form.elements['newMonitor[Type]'].value == 'WebSite' ) { + if ( form.elements['newMonitor[Function]'].value != 'Monitor' && form.elements['newMonitor[Function]'].value != 'None') + errors[errors.length] = ""; + if ( form.elements['newMonitor[Path]'].value.search(/^https?:\/\//i) ) + errors[errors.length] = ""; + } + + if ( form.elements['newMonitor[Type]'].value != 'WebSite' ) { + + if ( form.elements['newMonitor[AnalysisFPSLimit]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPSLimit]'].value) > 0 ) ) + errors[errors.length] = ""; + if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) ) + errors[errors.length] = ""; + if ( form.elements['newMonitor[AlarmMaxFPS]'].value && !(parseFloat(form.elements['newMonitor[AlarmMaxFPS]'].value) > 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[RefBlendPerc]'].value || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) > 100 ) || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) < 0 ) ) + errors[errors.length] = ""; + + if ( !form.elements['newMonitor[Colours]'].value || (parseInt(form.elements['newMonitor[Colours]'].value) != 1 && parseInt(form.elements['newMonitor[Colours]'].value) != 3 && parseInt(form.elements['newMonitor[Colours]'].value) != 4 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[Width]'].value || !(parseInt(form.elements['newMonitor[Width]'].value) > 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[Height]'].value || !(parseInt(form.elements['newMonitor[Height]'].value) > 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[LabelX]'].value || !(parseInt(form.elements['newMonitor[LabelX]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[LabelY]'].value || !(parseInt(form.elements['newMonitor[LabelY]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[ImageBufferCount]'].value || !(parseInt(form.elements['newMonitor[ImageBufferCount]'].value) >= 10 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[StreamReplayBuffer]'].value || !(parseInt(form.elements['newMonitor[StreamReplayBuffer]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[AlarmFrameCount]'].value || !(parseInt(form.elements['newMonitor[AlarmFrameCount]'].value) > 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[SectionLength]'].value || !(parseInt(form.elements['newMonitor[SectionLength]'].value) >= 30 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[AnalysisUpdateDelay]'].value || !(parseInt(form.elements['newMonitor[AnalysisUpdateDelay]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[FPSReportInterval]'].value || !(parseInt(form.elements['newMonitor[FPSReportInterval]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[FrameSkip]'].value || !(parseInt(form.elements['newMonitor[FrameSkip]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[MotionFrameSkip]'].value || !(parseInt(form.elements['newMonitor[MotionFrameSkip]'].value) >= 0 ) ) + errors[errors.length] = ""; + if ( form.elements['newMonitor[Type]'].value == 'Local' ) + if ( !form.elements['newMonitor[SignalCheckColour]'].value || !form.elements['newMonitor[SignalCheckColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) ) + errors[errors.length] = ""; + if ( !form.elements['newMonitor[WebColour]'].value || !form.elements['newMonitor[WebColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) ) + errors[errors.length] = ""; + } - if ( !form.elements['newMonitor[Colours]'].value || (parseInt(form.elements['newMonitor[Colours]'].value) != 1 && parseInt(form.elements['newMonitor[Colours]'].value) != 3 && parseInt(form.elements['newMonitor[Colours]'].value) != 4 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[Width]'].value || !(parseInt(form.elements['newMonitor[Width]'].value) > 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[Height]'].value || !(parseInt(form.elements['newMonitor[Height]'].value) > 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[LabelX]'].value || !(parseInt(form.elements['newMonitor[LabelX]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[LabelY]'].value || !(parseInt(form.elements['newMonitor[LabelY]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[ImageBufferCount]'].value || !(parseInt(form.elements['newMonitor[ImageBufferCount]'].value) >= 10 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[StreamReplayBuffer]'].value || !(parseInt(form.elements['newMonitor[StreamReplayBuffer]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[AlarmFrameCount]'].value || !(parseInt(form.elements['newMonitor[AlarmFrameCount]'].value) > 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[SectionLength]'].value || !(parseInt(form.elements['newMonitor[SectionLength]'].value) >= 30 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[AnalysisUpdateDelay]'].value || !(parseInt(form.elements['newMonitor[AnalysisUpdateDelay]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[FPSReportInterval]'].value || !(parseInt(form.elements['newMonitor[FPSReportInterval]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[FrameSkip]'].value || !(parseInt(form.elements['newMonitor[FrameSkip]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[MotionFrameSkip]'].value || !(parseInt(form.elements['newMonitor[MotionFrameSkip]'].value) >= 0 ) ) - errors[errors.length] = ""; - if ( form.elements['newMonitor[Type]'].value == 'Local' ) - if ( !form.elements['newMonitor[SignalCheckColour]'].value || !form.elements['newMonitor[SignalCheckColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) ) - errors[errors.length] = ""; - if ( !form.elements['newMonitor[WebColour]'].value || !form.elements['newMonitor[WebColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) ) - errors[errors.length] = ""; if ( errors.length ) { alert( errors.join( "\n" ) ); diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 152fdcd9b..b9dc84f00 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -12,6 +12,15 @@ function Monitor( monitorData ) { if ( auth_hash ) this.streamCmdParms += '&auth='+auth_hash; this.streamCmdTimer = null; + this.type = monitorData.type; + this.refresh = monitorData.refresh; + this.start = function( delay ) { + if ( this.streamCmdQuery ) + this.streamCmdTimer = this.streamCmdQuery.delay( delay, this ); + else + console.log("No streamCmdQuery"); + }; + this.setStateClass = function( element, stateClass ) { if ( !element.hasClass( stateClass ) ) { @@ -68,7 +77,7 @@ function Monitor( monitorData ) { else stateClass = "idle"; - if ( !COMPACT_MONTAGE ) { + if ( (!COMPACT_MONTAGE) && (this.type != 'WebSite') ) { $('fpsValue'+this.id).set( 'text', this.status.fps ); $('stateValue'+this.id).set( 'text', stateStrings[this.alarmState] ); this.setStateClass( $('monitorState'+this.id), stateClass ); @@ -137,22 +146,26 @@ function Monitor( monitorData ) { this.streamCmdReq.cancel(); } //console.log("Starting CmdQuery for " + this.connKey ); - this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); + if ( this.type != 'WebSite' ) { + this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); + } }; - this.streamCmdReq = new Request.JSON( { - url: this.server_url, - method: 'get', - timeout: 1000+AJAX_TIMEOUT, - onSuccess: this.getStreamCmdResponse.bind( this ), - onTimeout: this.streamCmdQuery.bind( this, true ), - onError: this.onError.bind(this), - onFailure: this.onFailure.bind(this), - link: 'cancel' - } ); + if ( this.type != 'WebSite' ) { + this.streamCmdReq = new Request.JSON( { + url: this.server_url, + method: 'get', + timeout: 1000+AJAX_TIMEOUT, + onSuccess: this.getStreamCmdResponse.bind( this ), + onTimeout: this.streamCmdQuery.bind( this, true ), + onError: this.onError.bind(this), + onFailure: this.onFailure.bind(this), + link: 'cancel' + } ); + console.log("queueing for " + this.id + " " + this.connKey ); + requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq ); + } - console.log("queueing for " + this.id + " " + this.connKey ); - requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq ); } function selectLayout( element ) { @@ -378,15 +391,26 @@ function cancel_layout(button) { selectLayout('#zmMontageLayout'); } +function reloadWebSite(ndx) { + document.getElementById('imageFeed'+ndx).innerHTML = document.getElementById('imageFeed'+ndx).innerHTML; +} + var monitors = new Array(); function initPage() { -console.log("initPage"); for ( var i = 0; i < monitorData.length; i++ ) { monitors[i] = new Monitor(monitorData[i]); + var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); + var interval = monitors[i].refresh; + monitors[i].start( delay ); + if ( monitors[i].type == 'WebSite' && interval > 0 ) { + setInterval(reloadWebSite, interval*1000, i); + } } selectLayout('#zmMontageLayout'); for ( var i = 0; i < monitorData.length; i++ ) { + if ( monitors[i].type == 'WebSite' ) + continue; var delay = Math.round( (Math.random()+0.75)*statusRefreshTimeout ); console.log("Delay for monitor " + monitorData[i].id + " is " + delay ); monitors[i].streamCmdQuery.delay( delay, monitors[i] ); diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index 7f749d47a..1b67d764b 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -36,7 +36,9 @@ monitorData[monitorData.length] = { 'width': Width() ?>, 'height':Height() ?>, 'server_url': 'Server()->Url().$_SERVER['PHP_SELF'] ?>', - 'onclick': function(){createPopup( '?view=watch&mid=Id() ?>', 'zmWatchId() ?>', 'watch', Width(), $monitor->PopupScale() ); ?>, Height(), $monitor->PopupScale() ); ?> );} + 'onclick': function(){createPopup( '?view=watch&mid=Id() ?>', 'zmWatchId() ?>', 'watch', Width(), $monitor->PopupScale() ); ?>, Height(), $monitor->PopupScale() ); ?> );}, + 'type': 'Type() ?>', + 'refresh': 'Refresh() ?>' }; 0 ) { + var myReload = setInterval(reloadWebSite, monitorRefresh*1000); } } diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index 79b48de94..c446703cf 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -49,6 +49,8 @@ var monitorId = Id() ?>; var monitorWidth = Width() ?>; var monitorHeight = Height() ?>; var monitorUrl = 'Server()->Url() . ( ZM_MIN_STREAMING_PORT ? ':'. (ZM_MIN_STREAMING_PORT+$monitor->Id()) : '' ) ) ?>'; +var monitorType = 'Type() ) ?>'; +var monitorRefresh = 'Refresh() ) ?>'; var scale = ''; diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 424748410..43998c174 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -26,23 +26,6 @@ if ( !canView( 'Monitors' ) ) { return; } -$tabs = array(); -$tabs['general'] = translate('General'); -$tabs['source'] = translate('Source'); -$tabs['storage'] = translate('Storage'); -$tabs['timestamp'] = translate('Timestamp'); -$tabs['buffers'] = translate('Buffers'); -if ( ZM_OPT_CONTROL && canView( 'Control' ) ) - $tabs['control'] = translate('Control'); -if ( ZM_OPT_X10 ) - $tabs['x10'] = translate('X10'); -$tabs['misc'] = translate('Misc'); - -if ( isset($_REQUEST['tab']) ) - $tab = validHtmlStr($_REQUEST['tab']); -else - $tab = 'general'; - $Server = null; if ( defined( 'ZM_SERVER_ID' ) ) { $Server = dbFetchOne( 'SELECT * FROM Servers WHERE Id=?', NULL, array( ZM_SERVER_ID ) ); @@ -142,6 +125,7 @@ if ( ! $monitor ) { 'V4LCapturesPerFrame' => 1, 'ServerId' => 'auto', 'StorageId' => '1', + 'Refresh' => '', ) ); } # end if $_REQUEST['dupID'] } # end if $_REQUEST['mid'] @@ -212,7 +196,8 @@ $sourceTypes = array( 'Ffmpeg' => translate('Ffmpeg'), 'Libvlc' => translate('Libvlc'), 'cURL' => 'cURL (HTTP(S) only)', - 'NVSocket' => translate('NVSocket') + 'WebSite'=> 'Web Site', + 'NVSocket' => translate('NVSocket') ); if ( !ZM_HAS_V4L ) unset($sourceTypes['Local']); @@ -507,6 +492,25 @@ if ( canEdit( 'Monitors' ) ) {
      Type() != 'WebSite' ) { + $tabs['storage'] = translate('Storage'); + $tabs['timestamp'] = translate('Timestamp'); + $tabs['buffers'] = translate('Buffers'); + if ( ZM_OPT_CONTROL && canView( 'Control' ) ) + $tabs['control'] = translate('Control'); + if ( ZM_OPT_X10 ) + $tabs['x10'] = translate('X10'); + $tabs['misc'] = translate('Misc'); +} + +if ( isset($_REQUEST['tab']) ) + $tab = validHtmlStr($_REQUEST['tab']); +else + $tab = 'general'; + foreach ( $tabs as $name=>$value ) { if ( $tab == $name ) { ?> @@ -578,7 +582,7 @@ if ( $tab != 'source' || ($monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Lib Type()!= 'Remote' && $monitor->Type()!= 'File' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' && $monitor->Type()!= 'cURL') ) { +if ( $tab != 'source' || ($monitor->Type()!= 'Remote' && $monitor->Type()!= 'File' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' && $monitor->Type()!= 'cURL' && $monitor->Type() != 'WebSite') ) { ?> @@ -708,6 +712,9 @@ switch ( $tab ) { ?> Enabled() ) { ?> checked="checked"/> +Type != 'WebSite' ) { +?> @@ -797,6 +804,7 @@ echo htmlOptions(Group::get_dropdown_options( ), $monitor->GroupIds() ); ?> +Type() == 'WebSite' ) { +?> + + () + () + Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { ?> @@ -871,7 +886,7 @@ include('_monitor_source_nvsocket.php');  (Type()), 'zmOptionHelp', 'optionhelp', '?' ) ?>) Type() != 'NVSocket' ) { +if ( $monitor->Type() != 'NVSocket' && $monitor->Type() != 'WebSite' ) { ?> Colours() ); ?> @@ -885,7 +900,7 @@ if ( $monitor->Type() == 'Local' ) { ?> Type() != 'WebSite' ) { ?> Type() == "WebSite" ) { + echo getWebSiteUrl( 'liveStream'.$monitor->Id(), $monitor->Path(), reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() ); + } else { + echo getStreamHTML( $monitor, $monitor_options ); + } if ( $showZones ) { $height = null; $width = null; @@ -255,7 +259,7 @@ foreach ( $monitors as $monitor ) {
    Type() != 'WebSite') ) { ?>
     -  fps
    Controllable() && canView( 'Control' ) ); +$showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' ); if ( isset( $_REQUEST['scale'] ) ) { $scale = validInt($_REQUEST['scale']); @@ -80,6 +80,7 @@ if ( canView( 'Control' ) && $monitor->Type() == 'Local' ) {
    $scale) ); ?>
    +Type() != 'WebSite' ) { ?>
    @@ -119,7 +120,7 @@ if ( $streamMode == 'jpeg' ) { ?>
    +Type() != 'WebSite' ?> Type() != 'WebSite' ) { ?>
    From 7e88d2885735bc665193c4648c5afcc965319698 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Apr 2018 21:58:19 -0400 Subject: [PATCH 152/154] bump version to .44 --- version | 2 +- web/api/app/Plugin/CakePHP-Enum-Behavior | 2 +- web/api/app/Plugin/Crud | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/version b/version index 92522fa6a..856307b22 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.43 +1.31.44 diff --git a/web/api/app/Plugin/CakePHP-Enum-Behavior b/web/api/app/Plugin/CakePHP-Enum-Behavior index ea90c0cd7..ca91b87fd 160000 --- a/web/api/app/Plugin/CakePHP-Enum-Behavior +++ b/web/api/app/Plugin/CakePHP-Enum-Behavior @@ -1 +1 @@ -Subproject commit ea90c0cd7f6e24333a90885e563b5d30b793db29 +Subproject commit ca91b87fda8e006e4fca2ed870f24f9a29c2905d diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 0bd63fb46..1351dde6b 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef +Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 From ecf8003aefe81253bfe15e5fd79335cdbc3b677d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 28 Apr 2018 12:32:21 -0400 Subject: [PATCH 153/154] remove extra spaces --- web/includes/Storage.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 38ba83bf9..5dc7016be 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -124,7 +124,7 @@ public static function find_all( $parameters = null, $options = null ) { return $usage; } public function disk_total_space() { - if ( ! array_key_exists( 'disk_total_space', $this ) ) { + if ( ! array_key_exists('disk_total_space', $this ) ) { $this->{'disk_total_space'} = disk_total_space( $this->Path() ); } return $this->{'disk_total_space'}; @@ -142,7 +142,7 @@ public static function find_all( $parameters = null, $options = null ) { } } else { $path = $this->Path(); - $used = disk_total_space( $path ) - disk_free_space( $path );; + $used = disk_total_space($path) - disk_free_space($path); } $this->{'DiskSpace'} = $used; } From abd52ebfb12d78f4a415fd661fa95f25668aec12 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 28 Apr 2018 12:38:10 -0400 Subject: [PATCH 154/154] Add DiskSpace column to storage listing --- web/skins/classic/views/options.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 697abd6e5..ef01003c5 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -265,21 +265,22 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI + - +'lower(Name)') ) as $Storage ) { ?> - - - - - + + + + + - + echo makePopupLink( '?view=storage&id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?> +
    Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Id()), $canEdit ) ?>Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?>Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Path()), $canEdit ) ?>Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Type()), $canEdit ) ?>Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Scheme()), $canEdit ) ?> Name()), $canEdit ) ?> disabled="disabled"/>disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?> + disabled="disabled"/>