Merge branch 'master' of github.com:ZoneMinder/ZoneMinder

This commit is contained in:
Isaac Connor 2018-09-20 13:37:46 -04:00
commit 999e4c6c43
12 changed files with 480 additions and 45 deletions

View File

@ -781,6 +781,8 @@ INSERT INTO `Controls` VALUES (NULL,'D-LINK DCS-3415','Remote','DCS3415',0,0,0,1
INSERT INTO `Controls` VALUES (NULL,'IOS Camera','Ffmpeg','IPCAMIOS',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
INSERT INTO `Controls` VALUES (NULL,'Dericam P2','Ffmpeg','DericamP2',0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,10,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,45,0,0,1,0,0,0,0,1,1,45,0,0,0,0);
INSERT INTO `Controls` VALUES (NULL,'Trendnet','Remote','Trendnet',1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
INSERT INTO `Controls` VALUES (NULL,'Dahua','Remote','Dahua',0,0,0,1,0,0,1,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,8,0,0,1,0,0,0,0,1,1,8,0,0,0,0);
--
-- Add some monitor preset values
--

View File

@ -15,7 +15,7 @@ AUTH_HASH_SECRET - When ZoneMinder is running in hashed authenticated mode it is
AUTH_HASH_IPS - When ZoneMinder is running in hashed authenticated mode it can optionally include the requesting IP address in the resultant hash. This adds an extra level of security as only requests from that address may use that authentication key. However in some circumstances, such as access over mobile networks, the requesting address can change for each request which will cause most requests to fail. This option allows you to control whether IP addresses are included in the authentication hash on your system. If you experience intermitent problems with authentication, switching this option off may help.
AUTH_HASH_LOGINS - The normal process for logging into ZoneMinder is via the login screen with username and password. In some circumstances it may be desirable to allow access directly to one or more pages, for instance from a third party application. If this option is enabled then adding an 'auth' parameter to any request will include a shortcut login bypassing the login screen, if not already logged in. As authentication hashes are time and, optionally, IP limited this can allow short-term access to ZoneMinder screens from other web pages etc. In order to use this the calling application will hae to generate the authentication hash itself and ensure it is valid. If you use this option you should ensure that you have modified the ZM_AUTH_HASH_SECRET to somethign unique to your system.
AUTH_HASH_LOGINS - The normal process for logging into ZoneMinder is via the login screen with username and password. In some circumstances it may be desirable to allow access directly to one or more pages, for instance from a third party application. If this option is enabled then adding an 'auth' parameter to any request will include a shortcut login bypassing the login screen, if not already logged in. As authentication hashes are time and, optionally, IP limited, this can allow short-term access to ZoneMinder screens from other web pages etc. In order to use this, the calling application will have to generate the authentication hash itself and ensure it is valid. If you use this option you should ensure that you have modified the ZM_AUTH_HASH_SECRET to something unique to your system.
OPT_FAST_DELETE - Normally an event created as the result of an alarm consists of entries in one or more database tables plus the various files associated with it. When deleting events in the browser it can take a long time to remove all of this if your are trying to do a lot of events at once. It is recommended that you set this option which means that the browser client only deletes the key entries in the events table, which means the events will no longer appear in the listing, and leaves the zmaudit daemon to clear up the rest later.
@ -38,6 +38,7 @@ OPT_CONTROL - ZoneMinder includes limited support for controllable cameras. A nu
OPT_TRIGGERS - ZoneMinder can interact with external systems which prompt or cancel alarms. This is done via the zmtrigger.pl script. This option indicates whether you want to use these external triggers. Most people will say no here.
CHECK_FOR_UPDATES - From ZoneMinder version 1.17.0 onwards new versions are expected to be more frequent. To save checking manually for each new version ZoneMinder can check with the zoneminder.com website to determine the most recent release. These checks are infrequent, about once per week, and no personal or system information is transmitted other than your current version number. If you do not wish these checks to take place or your ZoneMinder system has no internet access you can switch these check off with this configuration variable
UPDATE_CHECK_PROXY - If you use a proxy to access the internet then ZoneMinder needs to know so it can access zoneminder.com to check for updates. If you do use a proxy enter the full proxy url here in the form of http://<proxy host>:<proxy port>/
SHM_KEY - ZoneMinder uses shared memory to speed up communication between modules. To identify the right area to use shared memory keys are used. This option controls what the base key is, each monitor will have it's Id or'ed with this to get the actual key used. You will not normally need to change this value unless it clashes with another instance of ZoneMinder on the same machine. Only the first four hex digits are used, the lower four will be masked out and ignored.

View File

@ -0,0 +1,362 @@
package ZoneMinder::Control::Dahua;
use 5.8.0;
use strict;
use warnings;
require ZoneMinder::Base;
require ZoneMinder::Control;
our @ISA = qw(ZoneMinder::Control);
our $REALM = '';
our $USERNAME = '';
our $PASSWORD = '';
our $ADDRESS = '';
our $PROTOCOL = 'http://';
use Time::HiRes qw(usleep);
use ZoneMinder::Logger qw(:all);
use ZoneMinder::Config qw(:all);
use ZoneMinder::Database qw(zmDbConnect);
sub new
{
my $class = shift;
my $id = shift;
my $self = ZoneMinder::Control->new( $id );
bless( $self, $class );
srand( time() );
return $self;
}
our $AUTOLOAD;
sub AUTOLOAD
{
my $self = shift;
my $class = ref($self) || croak( "$self not object" );
my $name = $AUTOLOAD;
$name =~ s/.*://;
if ( exists($self->{$name}) )
{
return( $self->{$name} );
}
Fatal( "Can't access $name member of object of class $class" );
}
sub open
{
my $self = shift;
$self->loadMonitor();
# The Dahua camera firmware API supports the concept of having multiple
# channels on a single IP controller.
# As most cameras only have a single channel, and there is no similar
# information model in Zoneminder, I'm hardcoding the first and default
# channel "0", here.
$self->{dahua_channel_number} = "0";
if ( ( $self->{Monitor}->{ControlAddress} =~ /^(?<PROTOCOL>https?:\/\/)?(?<USERNAME>[^:@]+)?:?(?<PASSWORD>[^\/@]+)?@?(?<ADDRESS>.*)$/ ) ) {
$PROTOCOL = $+{PROTOCOL} if $+{PROTOCOL};
$USERNAME = $+{USERNAME} if $+{USERNAME};
$PASSWORD = $+{PASSWORD} if $+{PASSWORD};
$ADDRESS = $+{ADDRESS} if $+{ADDRESS};
} else {
Error('Failed to parse auth from address ' . $self->{Monitor}->{ControlAddress});
$ADDRESS = $self->{Monitor}->{ControlAddress};
}
if ( !($ADDRESS =~ /:/) ) {
Error('You generally need to also specify the port. I will append :80');
$ADDRESS .= ':80';
}
use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new;
$self->{ua}->agent("ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION);
$self->{state} = 'closed';
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
Debug("sendCmd credentials control address:'".$ADDRESS
."' realm:'" . $REALM
. "' username:'" . $USERNAME
. "' password:'".$PASSWORD
."'"
);
$self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD);
# Detect REALM
my $get_config_url = $PROTOCOL . $ADDRESS . "/cgi-bin/configManager.cgi?action=getConfig&name=Ptz";
my $req = HTTP::Request->new(GET=>$get_config_url);
my $res = $self->{ua}->request($req);
if ($res->is_success) {
$self->{state} = 'open';
return;
}
if ( $res->status_line() eq '401 Unauthorized' ) {
my $headers = $res->headers();
foreach my $k (keys %$headers) {
Debug("Initial Header $k => $$headers{$k}");
}
if ($$headers{'www-authenticate'}) {
my ($auth, $tokens) = $$headers{'www-authenticate'} =~ /^(\w+)\s+(.*)$/;
if ($tokens =~ /\w+="([^"]+)"/i) {
if ($REALM ne $1) {
$REALM = $1;
Debug("Changing REALM to '" . $REALM . "'");
$self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD);
my $req = HTTP::Request->new(GET=>$get_config_url);
$res = $self->{ua}->request($req);
if ($res->is_success()) {
$self->{state} = 'open';
return;
}
Debug('Authentication still failed after updating REALM' . $res->status_line);
$headers = $res->headers();
foreach my $k ( keys %$headers ) {
Debug("Initial Header $k => $$headers{$k}");
} # end foreach
} else {
Error('Authentication failed, not a REALM problem');
}
} else {
Error('Failed to match realm in tokens');
} # end if
} else {
Error('No WWW-Authenticate Header');
} # end if headers
} # end if $res->status_line() eq '401 Unauthorized'
}
sub close
{
my $self = shift;
$self->{state} = 'closed';
}
sub printMsg
{
my $self = shift;
my $msg = shift;
my $msg_len = length($msg);
Debug( $msg."[".$msg_len."]" );
}
sub sendGetRequest {
my $self = shift;
my $url_path = shift;
my $result = undef;
my $url = $PROTOCOL . $ADDRESS . $url_path;
my $req = HTTP::Request->new(GET=>$url);
my $res = $self->{ua}->request($req);
if ($res->is_success) {
$result = !undef;
} else {
if ($res->status_line() eq '401 Unauthorized') {
Debug("Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD);
Debug("Content was " . $res->content() );
my $res = $self->{ua}->request($req);
if ($res->is_success) {
$result = !undef;
} else {
Error("Content was " . $res->content() );
}
}
if ( ! $result ) {
Error("Error check failed: '".$res->status_line());
}
}
return($result);
}
sub sendPtzCommand
{
my $self = shift;
my $action = shift;
my $command_code = shift;
my $arg1 = shift;
my $arg2 = shift;
my $arg3 = shift;
my $channel = $self->{dahua_channel_number};
my $url_path = "/cgi-bin/ptz.cgi?";
$url_path .= "action=" . $action . "&";
$url_path .= "channel=" . $channel . "&";
$url_path .= "code=" . $command_code . "&";
$url_path .= "arg1=" . $arg1 . "&";
$url_path .= "arg2=" . $arg2 . "&";
$url_path .= "arg3=" . $arg3;
$self->sendGetRequest($url_path);
}
sub sendMomentaryPtzCommand
{
my $self = shift;
my $command_code = shift;
my $arg1 = shift;
my $arg2 = shift;
my $arg3 = shift;
my $duration_ms = shift;
$self->sendPtzCommand("start", $command_code, $arg1, $arg2, $arg3);
my $duration_ns = $duration_ms * 1000;
usleep($duration_ns);
$self->sendPtzCommand("stop", $command_code, $arg1, $arg2, $arg3);
}
sub moveRelUpLeft
{
my $self = shift;
Debug("Move Up Left");
$self->sendMomentaryPtzCommand("LeftUp", 4, 4, 0, 500);
}
sub moveRelUp
{
my $self = shift;
Debug("Move Up");
$self->sendMomentaryPtzCommand("Up", 0, 4, 0, 500);
}
sub moveRelUpRight
{
my $self = shift;
Debug("Move Up Right");
$self->sendMomentaryPtzCommand("RightUp", 0, 4, 0, 500);
}
sub moveRelLeft
{
my $self = shift;
Debug("Move Left");
$self->sendMomentaryPtzCommand("Left", 0, 4, 0, 500);
}
sub moveRelRight
{
my $self = shift;
Debug("Move Right");
$self->sendMomentaryPtzCommand("Right", 0, 4, 0, 500);
}
sub moveRelDownLeft
{
my $self = shift;
Debug("Move Down Left");
$self->sendMomentaryPtzCommand("LeftDown", 4, 4, 0, 500);
}
sub moveRelDown
{
my $self = shift;
Debug("Move Down");
$self->sendMomentaryPtzCommand("Down", 0, 4, 0, 500);
}
sub moveRelDownRight
{
my $self = shift;
Debug("Move Down Right");
$self->sendMomentaryPtzCommand("RightDown", 4, 4, 0, 500);
}
sub zoomRelTele
{
my $self = shift;
Debug("Zoom Relative Tele");
$self->sendMomentaryPtzCommand("ZoomTele", 0, 0, 0, 500);
}
sub zoomRelWide
{
my $self = shift;
Debug("Zoom Relative Wide");
$self->sendMomentaryPtzCommand("ZoomWide", 0, 0, 0, 500);
}
sub presetClear
{
my $self = shift;
my $params = shift;
my $preset_id = $self->getParam($params, 'preset');
$self->sendPtzCommand("start", "ClearPreset", 0, $preset_id, 0);
}
sub presetSet
{
my $self = shift;
my $params = shift;
my $preset_id = $self->getParam($params, 'preset');
my $dbh = zmDbConnect(1);
my $sql = 'SELECT * FROM ControlPresets WHERE MonitorId = ? AND Preset = ?';
my $sth = $dbh->prepare($sql)
or Fatal("Can't prepare sql '$sql': " . $dbh->errstr());
my $res = $sth->execute($self->{Monitor}->{Id}, $preset_id)
or Fatal("Can't execute sql '$sql': " . $sth->errstr());
my $control_preset_row = $sth->fetchrow_hashref();
my $new_label_name = $control_preset_row->{'Label'};
$self->sendPtzCommand("start", "SetPreset", 0, $preset_id, 0);
$self->sendPtzCommand("start", "SetPresetName", $preset_id, $new_label_name, 0);
}
sub presetGoto
{
my $self = shift;
my $params = shift;
my $preset_id = $self->getParam($params, 'preset');
$self->sendPtzCommand("start", "GotoPreset", 0, $preset_id, 0);
}
1;
__END__
=head1 NAME
ZoneMinder::Control::Dahua - Perl module for Dahua cameras
=head1 SYNOPSIS
use ZoneMinder::Control::Dahua;
place this in /usr/share/perl5/ZoneMinder/Control
=head1 DESCRIPTION
This module is an implementation of the Dahua IP camera HTTP control API.
=head2 EXPORT
None by default.
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2018 ZoneMinder LLC
This library 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 library 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.
=cut

View File

@ -30,10 +30,10 @@ sub open {
$self->loadMonitor();
if ( ( $self->{Monitor}->{ControlAddress} =~ /^(?<PROTOCOL>https?:\/\/)?(?<USERNAME>[^:@]+)?:?(?<PASSWORD>[^\/@]+)?@?(?<ADDRESS>.*)$/ ) ) {
$PROTOCOL = $+{PROTOCOL} if $+{PROTOCOL};
$USERNAME = $+{USERNAME} if $+{USERNAME};
$PASSWORD = $+{PASSWORD} if $+{PASSWORD};
$ADDRESS = $+{ADDRESS} if $+{ADDRESS};
$PROTOCOL = $+{PROTOCOL} if $+{PROTOCOL};
$USERNAME = $+{USERNAME} if $+{USERNAME};
$PASSWORD = $+{PASSWORD} if $+{PASSWORD};
$ADDRESS = $+{ADDRESS} if $+{ADDRESS};
} else {
Error('Failed to parse auth from address ' . $self->{Monitor}->{ControlAddress});
$ADDRESS = $self->{Monitor}->{ControlAddress};

View File

@ -264,17 +264,20 @@ MAIN: while( $loop ) {
Error("Can't open directory '$$Storage{Path}/$day_dir': $!");
next;
}
my %event_ids_by_path;
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR );
Debug("Have " . @event_links . ' event links');
closedir(DIR);
my $count = 0;
foreach my $event_link ( @event_links ) {
if ( $event_link =~ /[^\d\.]/ ) {
# Event links start with a period and consist of the digits of the event id. Anything else is not an event link
my ($event_id) = $event_link =~ /^(\.\d)$/;
if ( !$event_id ) {
Warning("Non-event link found $event_link in $day_dir, skipping");
next;
}
Debug("Checking link $event_link");
( my $event = $event_link ) =~ s/^.*\.//;
#Event path is hour/minute/sec
my $event_path = readlink($event_link);
@ -286,11 +289,13 @@ MAIN: while( $loop ) {
$cleaned = 1;
}
} else {
$event_ids_by_path{$event_path} = $event_id;
Debug("Checking link $event_link points to $event_path ");
my $Event = $fs_events->{$event} = new ZoneMinder::Event();
$$Event{Id} = $event;
$$Event{Path} = join('/', $Storage->Path(), $day_dir,$event_path);
$$Event{RelativePath} = join('/', $day_dir,$event_path);
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
$$Event{Id} = $event_id;
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_path);
$$Event{RelativePath} = join('/', $day_dir, $event_path);
$$Event{Scheme} = 'Deep';
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
@ -307,14 +312,33 @@ MAIN: while( $loop ) {
my $event_id = undef;
my @mp4_files = glob("$event_dir/[0-9]+\-video.mp4");
if ( ! opendir(DIR, $event_dir) ) {
Error("Can't open directory '$$Storage{Path}/$day_dir': $!");
next;
}
my @contents = readdir( DIR );
Debug("Have " . @contents . " files in $day_dir/$event_dir");
closedir(DIR);
my @mp4_files = grep( /^\d+\-video.mp4$/, @contents);
foreach my $mp4_file ( @mp4_files ) {
my ( $id ) = $mp4_file =~ /^([0-9]+)\-video\.mp4$/;
if ( $id ) {
$event_id = $id;
Debug("Got event id from mp4 file $mp4_file => $event_id");
last;
}
}
if ( ! $event_id ) {
# Look for .id file
my @hidden_files = grep( /^\.\d+$/, @contents);
Debug("Have " . @hidden_files . ' hidden files');
if ( @hidden_files ) {
( $event_id ) = $hidden_files[0] =~ /^.(\d+)$/;
}
}
if ( $event_id ) {
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
$$Event{Id} = $event_id;
@ -324,12 +348,17 @@ MAIN: while( $loop ) {
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
$Event->DiskSpace( undef );
if ( ! $event_ids_by_path{$event_dir} ) {
Warning("No event link found at ".$Event->LinkPath() ." for " . $Event->to_string());
}
} else {
aud_print("Deleting event directories with no event id information at $day_dir/$event_dir");
if ( confirm() ) {
my $command = "rm -rf $event_dir";
executeShellCommand( $command );
$cleaned = 1;
if ( ! $event_ids_by_path{$event_dir} ) {
aud_print("Deleting event directories with no event id information at $day_dir/$event_dir");
if ( confirm() ) {
my $command = "rm -rf $event_dir";
executeShellCommand( $command );
$cleaned = 1;
}
}
} # end if able to find id
} # end foreach event_dir without link
@ -386,7 +415,7 @@ MAIN: while( $loop ) {
} # if USE_DEEP_STORAGE
Debug( 'Got '.int(keys(%$fs_events))." filesystem events for monitor $monitor_dir\n" );
delete_empty_directories($$Storage{Path}.'/'.$monitor_dir);
delete_empty_subdirs($$Storage{Path}.'/'.$monitor_dir);
} # end foreach monitor
if ( $cleaned ) {
@ -885,6 +914,24 @@ sub deleteSwapImage {
}
}
# Deletes empty sub directories of the given path.
# Does not delete the path if empty. Is not meant to be recursive.
sub delete_empty_subdirs {
my $DIR;
if ( !opendir($DIR, $_[0]) ) {
Error("delete_empty_directories: Can't open directory '".getcwd()."/$_[0]': $!" );
return;
}
my @contents = map { ( $_ eq '.' or $_ eq '..' ) ? () : $_ } readdir( $DIR );
Debug("delete_empty_subdirectories $_[0] has " . @contents .' entries:' . ( @contents < 2 ? join(',',@contents) : '' ));
my @dirs = map { -d $_[0].'/'.$_ ? $_ : () } @contents;
Debug("Have " . @dirs . " dirs");
foreach ( @dirs ) {
delete_empty_directories( $_[0].'/'.$_ );
}
closedir($DIR);
}
sub delete_empty_directories {
my $DIR;
if ( !opendir($DIR, $_[0]) ) {
@ -892,7 +939,7 @@ sub delete_empty_directories {
return;
}
my @contents = map { ( $_ eq '.' or $_ eq '..' ) ? () : $_ } readdir( $DIR );
Debug("delete_empty_directories $_[0] has " . @contents .' entries:' . ( @contents < 2 ? join(',',@contents) : '' ));
Debug("delete_empty_directories $_[0] has " . @contents .' entries:' . ( @contents <= 2 ? join(',',@contents) : '' ));
my @dirs = map { -d $_[0].'/'.$_ ? $_ : () } @contents;
if ( @dirs ) {
Debug("Have " . @dirs . " dirs");

View File

@ -120,9 +120,15 @@ Event::Event(
char id_file[PATH_MAX];
char *path_ptr = path;
path_ptr += snprintf(path_ptr, sizeof(path), "%s/%d", storage->Path(), monitor->Id());
// Try to make the Monitor Dir. Normally this would exist, but in odd cases might not.
if ( mkdir(path, 0755) ) {
if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path, strerror(errno));
}
if ( storage->Scheme() == Storage::DEEP ) {
char *path_ptr = path;
path_ptr += snprintf(path_ptr, sizeof(path), "%s/%d", storage->Path(), monitor->Id());
int dt_parts[6];
dt_parts[0] = stime->tm_year-100;
@ -155,28 +161,24 @@ Event::Event(
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 ) {
char *path_ptr = path;
path_ptr += snprintf(
path_ptr, sizeof(path), "%s/%d/%04d-%02d-%02d",
storage->Path(), monitor->Id(), stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday
path_ptr, sizeof(path), "/%04d-%02d-%02d",
stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday
);
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));
}
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/%" PRIu64, storage->Path(), monitor->Id(), id);
path_ptr += snprintf(path, sizeof(path), "/%" PRIu64, id);
if ( mkdir(path, 0755) ) {
if ( errno != EEXIST ) {
if ( errno != EEXIST )
Error("Can't mkdir %s: %s", path, strerror(errno));
}
}
// Create empty id tag file

View File

@ -14,9 +14,17 @@ $| = 1;
my @monitors;
my $dbh = zmDbConnect();
my $sql = "SELECT * FROM Monitors";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute '$sql': ".$sth->errstr() );
my $sql = "SELECT * FROM Monitors
WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )".
( $Config{ZM_SERVER_ID} ? 'AND ServerId=?' : '' )
;
my $sth = $dbh->prepare_cached( $sql )
or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute()
or die( "Can't execute '$sql': ".$sth->errstr() );
while ( my $monitor = $sth->fetchrow_hashref() ) {
push( @monitors, $monitor );
@ -24,6 +32,12 @@ while ( my $monitor = $sth->fetchrow_hashref() ) {
while (1) {
foreach my $monitor (@monitors) {
# Check shared memory ok
if ( !zmMemVerify( $monitor ) ) {
zmMemInvalidate( $monitor );
next;
}
my $monitorState = zmGetMonitorState($monitor);
printState($monitor->{Id}, $monitor->{Name}, $monitorState);
}

View File

@ -85,7 +85,9 @@ class Event {
public function Monitor() {
if ( isset($this->{'MonitorId'}) ) {
return Monitor::find_one(array('Id'=>$this->{MonitorId}));
$Monitor = Monitor::find_one(array('Id'=>$this->{'MonitorId'}));
if ( $Monitor )
return $Monitor;
}
return new Monitor();
}

View File

@ -140,12 +140,12 @@ public $defaults = array(
}
if ( isset($options['limit']) ) {
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
$sql .= ' LIMIT ' . $limit;
$sql .= ' LIMIT ' . $options['limit'];
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Invalid value for limit($limit) passed to Filter::find from $file:$line");
Error("Invalid value for limit(".$options['limit'].") passed to Filter::find from $file:$line");
return array();
}
}
@ -185,7 +185,7 @@ public $defaults = array(
$this->{$k} = $v;
}
}
}
} # end class
} # end function set
} # end class Filter
?>

View File

@ -168,7 +168,7 @@ private $control_fields = array(
}
}
global $monitor_cache;
$monitor_cache[$row['Id']] = $row;
$monitor_cache[$row['Id']] = $this;
} else {
Error('No row for Monitor ' . $IdOrRow);

View File

@ -239,7 +239,7 @@ function getCmdResponse( respObj, respText ) {
if ( streamStatus.auth ) {
// Try to reload the image stream.
var streamImg = document.getElementById('evtStream');
var streamImg = $j('#evtStream');
if ( streamImg )
streamImg.src = streamImg.src.replace( /auth=\w+/i, 'auth='+streamStatus.auth );
} // end if haev a new auth hash
@ -992,10 +992,15 @@ function initPage() {
progressBarNav ();
streamCmdTimer = streamQuery.delay( 250 );
if ( canStreamNative ) {
var streamImg = $('imageFeed').getElement('img');
if ( !streamImg )
streamImg = $('imageFeed').getElement('object');
$(streamImg).addEvent( 'click', function( event ) { handleClick( event ); } );
var imageFeed = $('imageFeed');
if ( !imageFeed ) {
console.log('No element with id tag imageFeed found.');
} else {
var streamImg = imageFeed.getElement('img');
if ( !streamImg )
streamImg = imageFeed.getElement('object');
$(streamImg).addEvent( 'click', function( event ) { handleClick( event ); } );
}
}
}
nearEventsQuery(eventData.Id);

View File

@ -173,11 +173,11 @@ if ( !empty($_REQUEST['preset']) ) {
}
}
if ( !empty($_REQUEST['probe']) ) {
$probe = unserialize($_REQUEST['probe']);
$probe = unserialize(base64_decode($_REQUEST['probe']));
foreach ( $probe as $name=>$value ) {
if ( isset($value) ) {
# Does isset handle NULL's? I don't think this code is correct.
$monitor->$name = $value;
$monitor->$name = urldecode($value);
}
}
if ( ZM_HAS_V4L && $monitor->Type() == 'Local' ) {