diff --git a/distros/ubuntu1410/changelog b/distros/ubuntu1410/changelog index f155ab9ef..74129432f 100644 --- a/distros/ubuntu1410/changelog +++ b/distros/ubuntu1410/changelog @@ -1,3 +1,27 @@ +zoneminder (1.30.2-trusty-2016030702) trusty; urgency=medium + + * + + -- Isaac Connor Mon, 07 Mar 2016 22:14:03 -0500 + +zoneminder (1.30.2-trusty-2016030701) trusty; urgency=medium + + * merge master. with telemetry + + -- Isaac Connor Mon, 07 Mar 2016 21:47:53 -0500 + +zoneminder (1.30.2-trusty-2016022101) trusty; urgency=medium + + * merge zmtrigger fix + + -- Isaac Connor Mon, 22 Feb 2016 09:15:53 -0500 + +zoneminder (1.30.2-trusty-2016021901) trusty; urgency=medium + + * zmtrigger improvements + + -- Isaac Connor Fri, 19 Feb 2016 11:09:57 -0500 + zoneminder (1.30.2-trusty-2016021701) trusty; urgency=medium * printout id, and ip address when failing to connect diff --git a/distros/ubuntu1410/rules b/distros/ubuntu1410/rules index 37fe00538..49d3549f1 100755 --- a/distros/ubuntu1410/rules +++ b/distros/ubuntu1410/rules @@ -53,7 +53,7 @@ override_dh_auto_configure: --with-mariadb=/usr --with-webdir=/usr/share/zoneminder \ --with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin \ --with-webuser=www-data --with-webgroup=www-data \ - --enable-crashtrace=no --enable-mmap=yes $(DEBOPT) + --enable-mmap=yes $(DEBOPT) override_dh_clean: # Add here commands to clean up after the build process. diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 486e7689f..2657b8653 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -10,7 +10,6 @@ bin_SCRIPTS = \ zmdc.pl \ zmaudit.pl \ zmfilter.pl \ - zmtelemetry.pl \ zmtrigger.pl \ zmx10.pl \ zmwatch.pl \ @@ -20,7 +19,8 @@ bin_SCRIPTS = \ zmcontrol.pl \ zmtrack.pl \ zmcamtool.pl \ - zmsystemctl.pl + zmsystemctl.pl \ + zmtelemetry.pl SUBDIRS = \ . \ @@ -30,7 +30,6 @@ EXTRA_DIST = \ zmdc.pl.in \ zmaudit.pl.in \ zmfilter.pl.in \ - zmtelemetry.pl.in \ zmtrigger.pl.in \ zmx10.pl.in \ zmwatch.pl.in \ @@ -41,6 +40,7 @@ EXTRA_DIST = \ zmtrack.pl.in \ zmcamtool.pl.in \ zmsystemctl.pl.in \ + zmtelemtry.pl.in \ ZoneMinder/Makefile.PL \ ZoneMinder/README \ ZoneMinder/Changes \ diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index 2f180e090..095a9bf6d 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -198,6 +198,7 @@ my %spawned_connections; my %monitors; my $monitor_reload_time = 0; +my $needsReload = 0; $! = undef; my $rin = ''; @@ -218,8 +219,8 @@ while( 1 ) if ( $nfound > 0 ) { Debug( "Got input from $nfound connections\n" ); - foreach my $connection ( @in_select_connections ) - { + foreach my $connection ( @in_select_connections ) { + if ( vec( $rout, $connection->fileno(), 1 ) ) { Debug( "Got input from connection " @@ -311,52 +312,56 @@ while( 1 ) # Check for alarms that might have happened my @out_messages; - foreach my $monitor ( values(%monitors) ) - { - my ( $state, $last_event ) - = zmMemRead( $monitor, - [ "shared_data:state", - "shared_data:last_event" - ] - ); + foreach my $monitor ( values(%monitors) ) { - #print( "$monitor->{Id}: S:$state, LE:$last_event\n" ); - #print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" ); - if ( $state == STATE_ALARM - || $state == STATE_ALERT - ) # In alarm state - { - if ( !defined($monitor->{LastEvent}) - || ($last_event != $monitor->{LastEvent}) - ) # A new event - { + my $memVerified = 1; + if ( !zmMemRead($monitor, "shared_data:valid") ) { + zmMemInvalidate($monitor); + $memVerified = zmMemVerify($monitor); + } + + if ($memVerified) { + my ( $state, $last_event ) + = zmMemRead( $monitor, + [ "shared_data:state", + "shared_data:last_event" + ] + ); + + #print( "$monitor->{Id}: S:$state, LE:$last_event\n" ); + #print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" ); + if ( $state == STATE_ALARM + || $state == STATE_ALERT + ) { # In alarm state + if ( !defined($monitor->{LastEvent}) + || ($last_event != $monitor->{LastEvent}) + ) { # A new event + push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); + } else { # The same one as last time, so ignore it + # Do nothing + } + } elsif ( ($state == STATE_IDLE + && $monitor->{LastState} != STATE_IDLE + ) + || ($state == STATE_TAPE + && $monitor->{LastState} != STATE_TAPE + ) + ) { # Out of alarm state + push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); + } + elsif ( defined($monitor->{LastEvent}) + && ($last_event != $monitor->{LastEvent}) + ) { # We've missed a whole event push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); + push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); } - else # The same one as last time, so ignore it - { - # Do nothing - } + $monitor->{LastState} = $state; + $monitor->{LastEvent} = $last_event; + } else { # Our attempt to verify the memory handle failed. We should reload the monitors. + $needsReload = 1; } - elsif ( ($state == STATE_IDLE - && $monitor->{LastState} != STATE_IDLE - ) - || ($state == STATE_TAPE - && $monitor->{LastState} != STATE_TAPE - ) - ) # Out of alarm state - { - push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); - } - elsif ( defined($monitor->{LastEvent}) - && ($last_event != $monitor->{LastEvent}) - ) # We've missed a whole event - { - push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); - push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); - } - $monitor->{LastState} = $state; - $monitor->{LastEvent} = $last_event; } + foreach my $connection ( @out_connections ) { if ( $connection->canWrite() ) @@ -413,7 +418,7 @@ while( 1 ) } # If necessary reload monitors - if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ) + if ( $needsReload || ((time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )) { foreach my $monitor ( values(%monitors) ) { @@ -421,6 +426,7 @@ while( 1 ) zmMemInvalidate( $monitor ); } loadMonitors(); + $needsReload = 0; } } Info( "Trigger daemon exiting\n" ); diff --git a/src/zm_event.cpp b/src/zm_event.cpp index a5e0a03cd..1d8e87822 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -1221,6 +1221,17 @@ void EventStream::checkEventLoaded() } } +Image * EventStream::getImage( ) { + Event::Initialise(); + static char filepath[PATH_MAX]; + + Debug( 2, "EventStream::getImage path(%s) frame(%d)", event_data->path, curr_frame_id ); + snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id ); + Debug( 2, "EventStream::getImage path(%s) ", filepath, curr_frame_id ); + Image *image = new Image( filepath ); + return image; +} + bool EventStream::sendFrame( int delta_us ) { Debug( 2, "Sending frame %d", curr_frame_id ); diff --git a/src/zm_event.h b/src/zm_event.h index 80117cd2f..a99874394 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -253,18 +253,19 @@ public: void setStreamStart( int init_event_id, int init_frame_id=0 ) { loadInitialEventData( init_event_id, init_frame_id ); - loadMonitor( event_data->monitor_id ); + loadMonitor( event_data->monitor_id ); } void setStreamStart( int monitor_id, time_t event_time ) { loadInitialEventData( monitor_id, event_time ); - loadMonitor( monitor_id ); + loadMonitor( monitor_id ); } void setStreamMode( StreamMode p_mode ) { mode = p_mode; } void runStream(); + Image *getImage(); }; #endif // ZM_EVENT_H diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e44c52154..231852ca4 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1131,13 +1131,32 @@ void Monitor::DumpZoneImage( const char *zone_string ) } } - int index = shared_data->last_write_index; - Snapshot *snap = &image_buffer[index]; - Image *snap_image = snap->image; + Image *zone_image = NULL; + if ( ( (!staticConfig.SERVER_ID) || ( staticConfig.SERVER_ID == server_id ) ) && mem_ptr ) { + Debug(3, "Trying to load from local zmc"); + int index = shared_data->last_write_index; + Snapshot *snap = &image_buffer[index]; + zone_image = new Image( *snap->image ); + } else { + Debug(3, "Trying to load from event"); + // Grab the most revent event image + std::string sql = stringtf( "SELECT MAX(Id) FROM Events WHERE MonitorId=%d AND Frames > 0", id ); + MYSQL_ROW eventid_row = zmDbFetchOne(sql.c_str() ); + if ( eventid_row ) { + int event_id = atoi( eventid_row[0] ); - Image zone_image( *snap_image ); - if(zone_image.Colours() == ZM_COLOUR_GRAY8) { - zone_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); + Debug( 3, "Got event %d", event_id ); + EventStream *stream = new EventStream(); + stream->setStreamStart( event_id, 1 ); + zone_image = stream->getImage(); + } else { + Error("Unable to load an event for monitor %d", id ); + return; + } + } + + if(zone_image->Colours() == ZM_COLOUR_GRAY8) { + zone_image->Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); } for( int i = 0; i < n_zones; i++ ) @@ -1173,19 +1192,20 @@ void Monitor::DumpZoneImage( const char *zone_string ) colour = RGB_WHITE; } } - zone_image.Fill( colour, 2, zones[i]->GetPolygon() ); - zone_image.Outline( colour, zones[i]->GetPolygon() ); + zone_image->Fill( colour, 2, zones[i]->GetPolygon() ); + zone_image->Outline( colour, zones[i]->GetPolygon() ); } if ( extra_zone.getNumCoords() ) { - zone_image.Fill( extra_colour, 2, extra_zone ); - zone_image.Outline( extra_colour, extra_zone ); + zone_image->Fill( extra_colour, 2, extra_zone ); + zone_image->Outline( extra_colour, extra_zone ); } static char filename[PATH_MAX]; snprintf( filename, sizeof(filename), "Zones%d.jpg", id ); - zone_image.WriteJpeg( filename ); + zone_image->WriteJpeg( filename ); + delete zone_image; } void Monitor::DumpImage( Image *dump_image ) const diff --git a/src/zm_remote_camera.h b/src/zm_remote_camera.h index 7e3ae79a8..38c0903b6 100644 --- a/src/zm_remote_camera.h +++ b/src/zm_remote_camera.h @@ -27,6 +27,7 @@ #include #include #include +#include // // Class representing 'remote' cameras, i.e. those which are diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 006f80faf..cb26413e0 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -108,7 +108,12 @@ int RemoteCameraHttp::Connect() { close(sd); sd = -1; - Warning("Can't connect to remote camera: %s", strerror(errno) ); + char buf[sizeof(struct in6_addr)]; + struct sockaddr_in *addr; + addr = (struct sockaddr_in *)p->ai_addr; + inet_ntop( AF_INET, &(addr->sin_addr), buf, INET6_ADDRSTRLEN ); + + Warning("Can't connect to remote camera mid: %d at %s: %s", id, buf, strerror(errno) ); continue; } diff --git a/src/zmu.cpp b/src/zmu.cpp index a1e8887bd..188362446 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -493,7 +493,6 @@ int main( int argc, char *argv[] ) } if ( ! monitor->connect() ) { Error( "Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name() ); - exit( -1 ); } char separator = ' '; diff --git a/web/includes/Event.php b/web/includes/Event.php index cd4f831d8..170cf8cf0 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -66,7 +66,49 @@ class Event { } -} + public function LinkPath() { + if ( ZM_USE_DEEP_STORAGE ) { + return $this->{'MonitorId'} .'/'.strftime( "%y/%m/%d/.", $this->{'Time'}).$this->{'Id'}; + } + Error("Calling Link_Path when not using deep storage"); + return ''; + } + public function delete() { + dbQuery( 'DELETE FROM Events WHERE Id = ?', array($this->{'Id'}) ); + if ( !ZM_OPT_FAST_DELETE ) { + dbQuery( 'DELETE FROM Stats WHERE EventId = ?', array($this->{'Id'}) ); + dbQuery( 'DELETE FROM Frames WHERE EventId = ?', array($this->{'Id'}) ); + if ( ZM_USE_DEEP_STORAGE ) { + # Assumption: All events haev a start time + $start_date = date_parse( $this->{'StartTime'} ); + $start_date['year'] = $start_date['year'] % 100; + + $Storage = $this->Storage(); + # So this is because ZM creates a link under teh day pointing to the time that the event happened. + $eventlink_path = $Storage->Path().'/'.$this->Link_Path(); + + if ( $id_files = glob( $eventlink_path ) ) { + # I know we are using arrays here, but really there can only ever be 1 in the array + $eventPath = preg_replace( '/\.'.$event['Id'].'$/', readlink($id_files[0]), $id_files[0] ); + deletePath( $eventPath ); + deletePath( $id_files[0] ); + $pathParts = explode( '/', $eventPath ); + for ( $i = count($pathParts)-1; $i >= 2; $i-- ) { + $deletePath = join( '/', array_slice( $pathParts, 0, $i ) ); + if ( !glob( $deletePath."/*" ) ) { + deletePath( $deletePath ); + } + } + } else { + Warning( "Found no event files under $eventlink_path" ); + } # end if found files + } else { + $eventPath = $this->Path(); + deletePath( $eventPath ); + } # USE_DEEP_STORAGE OR NOT + } # ! ZM_OPT_FAST_DELETE + } # end Event->delete +} # end class ?> diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 1820b977d..4143d0585 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -26,6 +26,8 @@ class Storage { public function Path() { if ( isset( $this->{'Path'} ) and ( $this->{'Path'} != '' ) ) { return $this->{'Path'}; + } else if ( ! $this->{'Id'} ) { + return ZM_DIR_EVENTS; } return $this->{'Name'}; } diff --git a/web/includes/functions.php b/web/includes/functions.php index 6cbc24704..499e8fd2c 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -537,7 +537,7 @@ function deletePath( $path ) } } -function deleteEvent( $event, $mid=false ) { +function deleteEvent( $event ) { if ( empty($event) ) { Error( "Empty event passed to deleteEvent."); @@ -546,49 +546,13 @@ function deleteEvent( $event, $mid=false ) { if ( gettype($event) != 'array' ) { # $event could be an eid, so turn it into an event hash - $event = dbFetchOne( 'SELECT Id, MonitorId, StartTime FROM Events WHERE Id=?', NULL, array( $event ) ); + $event = new Event( $event ); } global $user; - if ( !$mid ) - $mid = $event['MonitorId']; - if ( $user['Events'] == 'Edit' ) { - - dbQuery( 'DELETE FROM Events WHERE Id = ?', array($event['Id']) ); - if ( !ZM_OPT_FAST_DELETE ) { - dbQuery( 'DELETE FROM Stats WHERE EventId = ?', array($event['Id']) ); - dbQuery( 'DELETE FROM Frames WHERE EventId = ?', array($event['Id']) ); - if ( ZM_USE_DEEP_STORAGE ) { - - # Assumption: All events haev a start time - $start_date = date_parse( $event['StartTime'] ); - $start_date['year'] = $start_date['year'] % 100; - - # So this is because ZM creates a link under teh day pointing to the time that the event happened. - $eventlink_path = sprintf('%s/%d/%02d/%02d/%02d/.%d', ZM_DIR_EVENTS, $mid, $start_date['year'], $start_date['month'], $start_date['day'], $event['Id'] ); - - if ( $id_files = glob( $eventlink_path ) ) { - # I know we are using arrays here, but really there can only ever be 1 in the array - $eventPath = preg_replace( '/\.'.$event['Id'].'$/', readlink($id_files[0]), $id_files[0] ); - deletePath( $eventPath ); - deletePath( $id_files[0] ); - $pathParts = explode( '/', $eventPath ); - for ( $i = count($pathParts)-1; $i >= 2; $i-- ) { - $deletePath = join( '/', array_slice( $pathParts, 0, $i ) ); - if ( !glob( $deletePath."/*" ) ) { - deletePath( $deletePath ); - } - } - } else { - Warning( "Found no event files under $eventlink_path" ); - } # end if found files - } else { - $eventPath = implode( '/', array( ZM_DIR_EVENTS, $mid, $event['Id'] ) ); - deletePath( $eventPath ); - } # USE_DEEP_STORAGE OR NOT - } # ! ZM_OPT_FAST_DELETE + $event->delete(); } # CAN EDIT } @@ -1433,6 +1397,9 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) case 'MonitorName': $filter['sql'] .= 'M.'.preg_replace( '/^Monitor/', '', $filter['terms'][$i]['attr'] ); break; + case 'ServerId': + $filter['sql'] .= 'M.ServerId'; + break; case 'DateTime': $filter['sql'] .= "E.StartTime"; break; @@ -1448,6 +1415,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) case 'Id': case 'Name': case 'MonitorId': + case 'StorageId': case 'Length': case 'Frames': case 'AlarmFrames': @@ -1480,6 +1448,12 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) case 'Notes': $value = dbEscape($value); break; + case 'ServerId': + if ( $value == 'ZM_SERVER_ID' ) { + $value = ZM_SERVER_ID; + } else { + $value = dbEscape($value); + } case 'DateTime': $value = "'".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."'"; break; diff --git a/web/index.php b/web/index.php index 72e6dc8c0..2d3e8e73a 100644 --- a/web/index.php +++ b/web/index.php @@ -49,6 +49,8 @@ if ( false ) require_once( 'includes/config.php' ); require_once( 'includes/logger.php' ); require_once( 'includes/Server.php' ); +require_once( 'includes/Event.php' ); +require_once( 'includes/Monitor.php' ); if ( isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' ) { diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index b9b5765fc..a6a8a73c0 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -100,6 +100,8 @@ if ( !canView( 'Events' ) ) return; } +require_once( 'includes/Monitor.php' ); + if ( !empty($_REQUEST['group']) ) { $group = $_REQUEST['group']; @@ -117,7 +119,7 @@ else // Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly. $eventsSql = " - select E.Id,E.Name,UNIX_TIMESTAMP(E.StartTime) as StartTimeSecs, + select E.Id,E.Name,E.StorageId,UNIX_TIMESTAMP(E.StartTime) as StartTimeSecs, case when E.EndTime is null then (Select UNIX_TIMESTAMP(DATE_ADD(E.StartTime, Interval max(Delta)+0.5 Second)) from Frames F where F.EventId=E.Id) else UNIX_TIMESTAMP(E.EndTime) end as CalcEndTimeSecs, E.Length, @@ -553,13 +555,12 @@ function SetImageSource(monId,val) else { var zeropad = ; - for(var i=0; i= eStartSecs[i] && val <= eEndSecs[i]) { var frame=parseInt((val - eStartSecs[i])/(eEndSecs[i]-eStartSecs[i])*eventFrames[i])+1; -// img = ePath[i] + zeropad.substr(frame.toString().length) + frame.toString() + "-capture.jpg"; - img = "index.php?view=image&path=" + ePath[i].substring(6) + zeropad.substr(frame.toString().length) + frame.toString() + "-capture.jpg" + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height; + img = "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height; return img; } } diff --git a/web/skins/classic/views/zones.php b/web/skins/classic/views/zones.php index 9182dc98f..f5e237369 100644 --- a/web/skins/classic/views/zones.php +++ b/web/skins/classic/views/zones.php @@ -25,13 +25,12 @@ if ( !canView( 'Monitors' ) ) } $mid = validInt($_REQUEST['mid']); +$Monitor = new Monitor( $mid ); $wd = getcwd(); chdir( ZM_DIR_IMAGES ); $status = exec( escapeshellcmd( getZmuCommand( " -m ".$mid." -z" ) ) ); chdir( $wd ); - -$monitor = dbFetchMonitor( $mid ); - +$image = ZM_DIR_IMAGES.'/'.'Zones'.$Monitor->Id().'.jpg'; $zones = array(); foreach( dbFetchAll( 'select * from Zones where MonitorId = ? order by Area desc', NULL, array($mid) ) as $row ) { @@ -42,7 +41,6 @@ foreach( dbFetchAll( 'select * from Zones where MonitorId = ? order by Area desc } } -$image = 'Zones'.$monitor['Id'].'.jpg'; xhtmlHeaders(__FILE__, translate('Zones') ); ?> @@ -58,13 +56,13 @@ xhtmlHeaders(__FILE__, translate('Zones') ); foreach( array_reverse($zones) as $zone ) { ?> - <?php echo htmlspecialchars($zone['Name']) ?> + <?php echo htmlspecialchars($zone['Name']) ?> - zones + zones
@@ -84,9 +82,9 @@ foreach( $zones as $zone ) { ?> - + -  /  +  / Width*$Monitor->Height) ) ?> disabled="disabled"/>
- disabled="disabled"/> + disabled="disabled"/>