Merge branch 'master' into fix_token_auth_sessions
This commit is contained in:
commit
4922861d1d
|
@ -186,6 +186,7 @@ CREATE TABLE `Events` (
|
||||||
`Id` bigint unsigned NOT NULL auto_increment,
|
`Id` bigint unsigned NOT NULL auto_increment,
|
||||||
`MonitorId` int(10) unsigned NOT NULL default '0',
|
`MonitorId` int(10) unsigned NOT NULL default '0',
|
||||||
`StorageId` smallint(5) unsigned default 0,
|
`StorageId` smallint(5) unsigned default 0,
|
||||||
|
`SecondaryStorageId` smallint(5) unsigned default 0,
|
||||||
`Name` varchar(64) NOT NULL default '',
|
`Name` varchar(64) NOT NULL default '',
|
||||||
`Cause` varchar(32) NOT NULL default '',
|
`Cause` varchar(32) NOT NULL default '',
|
||||||
`StartTime` datetime default NULL,
|
`StartTime` datetime default NULL,
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
--
|
||||||
|
-- Add CopyTo action to Filters
|
||||||
|
--
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Filters'
|
||||||
|
AND column_name = 'AutoCopy'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column AutoCopy already exists in Filters'",
|
||||||
|
"ALTER TABLE Filters ADD `AutoCopy` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoMove`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Filters'
|
||||||
|
AND column_name = 'AutoCopyTo'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column AutoCopyTo already exists in Filters'",
|
||||||
|
"ALTER TABLE Filters ADD `AutoCopyTo` smallint(5) unsigned NOT NULL default '0' AFTER `AutoCopy`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Filters'
|
||||||
|
AND column_name = 'Query_json'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column Query_json already exists in Filters'",
|
||||||
|
"ALTER TABLE `Filters` Change `Query` `Query_json` text NOT NULL"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Events'
|
||||||
|
AND column_name = 'SecondaryStorageId'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column SecondaryStorageId already exists in Events'",
|
||||||
|
"ALTER TABLE `Events` ADD `SecondaryStorageId` smallint(5) unsigned default 0 AFTER `StorageId`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -23,7 +23,7 @@
|
||||||
%global _hardened_build 1
|
%global _hardened_build 1
|
||||||
|
|
||||||
Name: zoneminder
|
Name: zoneminder
|
||||||
Version: 1.33.12
|
Version: 1.33.14
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: A camera monitoring and analysis tool
|
Summary: A camera monitoring and analysis tool
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
@ -411,6 +411,9 @@ EOF
|
||||||
%dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload
|
%dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sun Aug 11 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.14-1
|
||||||
|
- Bump to 1.33.13 Development
|
||||||
|
|
||||||
* Sun Jul 07 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.12-1
|
* Sun Jul 07 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.12-1
|
||||||
- Bump to 1.33.12 Development
|
- Bump to 1.33.12 Development
|
||||||
|
|
||||||
|
|
19
docs/faq.rst
19
docs/faq.rst
|
@ -646,6 +646,23 @@ Why am I getting broken images when trying to view events?
|
||||||
Zoneminder and the Apache web server need to have the right permissions. Check this forum topic and similar ones:
|
Zoneminder and the Apache web server need to have the right permissions. Check this forum topic and similar ones:
|
||||||
http://www.zoneminder.com/forums/viewtopic.php?p=48754#48754
|
http://www.zoneminder.com/forums/viewtopic.php?p=48754#48754
|
||||||
|
|
||||||
|
|
||||||
|
I can review events for the current day, but ones from yesterday and beyond error out
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
If you've checked that the `www-data` user has permissions to the storage folders, perhaps your php.ini's timezone setting is incorrect. They _must_ match for certain playback functions.
|
||||||
|
|
||||||
|
If you're using Linux, this can be found using the following command: ::
|
||||||
|
|
||||||
|
timedatectl | grep "Time zone"
|
||||||
|
|
||||||
|
If using FreeBSD, you can use this one-liner: ::
|
||||||
|
|
||||||
|
cd /usr/share/zoneinfo/ && find * -type f -exec cmp -s {} /etc/localtime \; -print;
|
||||||
|
|
||||||
|
Once you know what timezone your system is set to, open `/etc/php.ini` and adjust ``date.timezone`` to the appropriate value. the PHP daemon may need to be restarted for changes to take effect.
|
||||||
|
|
||||||
|
|
||||||
Why is the image from my color camera appearing in black and white?
|
Why is the image from my color camera appearing in black and white?
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
If you recently upgraded to zoneminder 1.26, there is a per camera option that defaults to black and white and can be mis-set if your upgrade didn't happen right. See this thread: http://www.zoneminder.com/forums/viewtopic.php?f=30&t=21344
|
If you recently upgraded to zoneminder 1.26, there is a per camera option that defaults to black and white and can be mis-set if your upgrade didn't happen right. See this thread: http://www.zoneminder.com/forums/viewtopic.php?f=30&t=21344
|
||||||
|
@ -728,6 +745,8 @@ What causes "Invalid JPEG file structure: two SOI markers" from zmc (1.24.x)
|
||||||
|
|
||||||
Some settings that used to be global only are now per camera. On the Monitor Source tab, if you are using Remote Protocol "HTTP" and Remote Method "Simple", try changing Remote Method to "Regexp".
|
Some settings that used to be global only are now per camera. On the Monitor Source tab, if you are using Remote Protocol "HTTP" and Remote Method "Simple", try changing Remote Method to "Regexp".
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
-------------------
|
-------------------
|
||||||
I see ZoneMinder is licensed under the GPL. What does that allow or restrict me in doing with ZoneMinder?
|
I see ZoneMinder is licensed under the GPL. What does that allow or restrict me in doing with ZoneMinder?
|
||||||
|
|
|
@ -189,11 +189,17 @@ Add the following to the bottom of the file
|
||||||
::
|
::
|
||||||
|
|
||||||
# Backports repository
|
# Backports repository
|
||||||
deb http://httpredir.debian.org/debian jessie-backports main contrib non-free
|
deb http://archive.debian.org/debian/ jessie-backports main contrib non-free
|
||||||
|
|
||||||
CTRL+o and <Enter> to save
|
CTRL+o and <Enter> to save
|
||||||
CTRL+x to exit
|
CTRL+x to exit
|
||||||
|
|
||||||
|
Run the following
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
echo 'Acquire::Check-Valid-Until no;' > /etc/apt/apt.conf.d/99no-check-valid-until
|
||||||
|
|
||||||
**Step 5:** Install ZoneMinder
|
**Step 5:** Install ZoneMinder
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
|
@ -41,6 +41,7 @@ require Number::Bytes::Human;
|
||||||
require Date::Parse;
|
require Date::Parse;
|
||||||
require POSIX;
|
require POSIX;
|
||||||
use Date::Format qw(time2str);
|
use Date::Format qw(time2str);
|
||||||
|
use Time::HiRes qw(gettimeofday tv_interval);
|
||||||
|
|
||||||
#our @ISA = qw(ZoneMinder::Object);
|
#our @ISA = qw(ZoneMinder::Object);
|
||||||
use parent qw(ZoneMinder::Object);
|
use parent qw(ZoneMinder::Object);
|
||||||
|
@ -63,6 +64,7 @@ $serial = $primary_key = 'Id';
|
||||||
Id
|
Id
|
||||||
MonitorId
|
MonitorId
|
||||||
StorageId
|
StorageId
|
||||||
|
SecondaryStorageId
|
||||||
Name
|
Name
|
||||||
Cause
|
Cause
|
||||||
StartTime
|
StartTime
|
||||||
|
@ -116,7 +118,7 @@ sub Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getPath {
|
sub getPath {
|
||||||
return Path( @_ );
|
return Path(@_);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Path {
|
sub Path {
|
||||||
|
@ -131,7 +133,7 @@ sub Path {
|
||||||
|
|
||||||
if ( ! $$event{Path} ) {
|
if ( ! $$event{Path} ) {
|
||||||
my $Storage = $event->Storage();
|
my $Storage = $event->Storage();
|
||||||
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath() );
|
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
|
||||||
}
|
}
|
||||||
return $$event{Path};
|
return $$event{Path};
|
||||||
}
|
}
|
||||||
|
@ -163,7 +165,8 @@ sub RelativePath {
|
||||||
if ( $event->Time() ) {
|
if ( $event->Time() ) {
|
||||||
$$event{RelativePath} = join('/',
|
$$event{RelativePath} = join('/',
|
||||||
$event->{MonitorId},
|
$event->{MonitorId},
|
||||||
POSIX::strftime( '%y/%m/%d/%H/%M/%S',
|
POSIX::strftime(
|
||||||
|
'%y/%m/%d/%H/%M/%S',
|
||||||
localtime($event->Time())
|
localtime($event->Time())
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -203,7 +206,8 @@ sub LinkPath {
|
||||||
if ( $event->Time() ) {
|
if ( $event->Time() ) {
|
||||||
$$event{LinkPath} = join('/',
|
$$event{LinkPath} = join('/',
|
||||||
$event->{MonitorId},
|
$event->{MonitorId},
|
||||||
POSIX::strftime( '%y/%m/%d',
|
POSIX::strftime(
|
||||||
|
'%y/%m/%d',
|
||||||
localtime($event->Time())
|
localtime($event->Time())
|
||||||
),
|
),
|
||||||
'.'.$$event{Id}
|
'.'.$$event{Id}
|
||||||
|
@ -255,8 +259,8 @@ sub createIdFile {
|
||||||
sub GenerateVideo {
|
sub GenerateVideo {
|
||||||
my ( $self, $rate, $fps, $scale, $size, $overwrite, $format ) = @_;
|
my ( $self, $rate, $fps, $scale, $size, $overwrite, $format ) = @_;
|
||||||
|
|
||||||
my $event_path = $self->Path( );
|
my $event_path = $self->Path();
|
||||||
chdir( $event_path );
|
chdir($event_path);
|
||||||
( my $video_name = $self->{Name} ) =~ s/\s/_/g;
|
( my $video_name = $self->{Name} ) =~ s/\s/_/g;
|
||||||
|
|
||||||
my @file_parts;
|
my @file_parts;
|
||||||
|
@ -282,10 +286,10 @@ sub GenerateVideo {
|
||||||
$file_scale =~ s/_00//;
|
$file_scale =~ s/_00//;
|
||||||
$file_scale =~ s/(_\d+)0+$/$1/;
|
$file_scale =~ s/(_\d+)0+$/$1/;
|
||||||
$file_scale = 's'.$file_scale;
|
$file_scale = 's'.$file_scale;
|
||||||
push( @file_parts, $file_scale );
|
push @file_parts, $file_scale;
|
||||||
} elsif ( $size ) {
|
} elsif ( $size ) {
|
||||||
my $file_size = 'S'.$size;
|
my $file_size = 'S'.$size;
|
||||||
push( @file_parts, $file_size );
|
push @file_parts, $file_size;
|
||||||
}
|
}
|
||||||
my $video_file = join('-', $video_name, $file_parts[0], $file_parts[1] ).'.'.$format;
|
my $video_file = join('-', $video_name, $file_parts[0], $file_parts[1] ).'.'.$format;
|
||||||
if ( $overwrite || !-s $video_file ) {
|
if ( $overwrite || !-s $video_file ) {
|
||||||
|
@ -393,61 +397,66 @@ sub delete {
|
||||||
sub delete_files {
|
sub delete_files {
|
||||||
my $event = shift;
|
my $event = shift;
|
||||||
|
|
||||||
my $Storage = @_ ? $_[0] : new ZoneMinder::Storage($$event{StorageId});
|
foreach my $Storage (
|
||||||
my $storage_path = $Storage->Path();
|
@_ ? ($_[0]) : (
|
||||||
|
new ZoneMinder::Storage($$event{StorageId}),
|
||||||
|
( $$event{SecondaryStorageId} ? new ZoneMinder::Storage($$event{SecondaryStorageId}) : () ),
|
||||||
|
) ) {
|
||||||
|
my $storage_path = $Storage->Path();
|
||||||
|
|
||||||
if ( ! $storage_path ) {
|
if ( ! $storage_path ) {
|
||||||
Error("Empty storage path when deleting files for event $$event{Id} with storage id $$event{StorageId}");
|
Error("Empty storage path when deleting files for event $$event{Id} with storage id $$event{StorageId}");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! $$event{MonitorId} ) {
|
|
||||||
Error("No monitor id assigned to event $$event{Id}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
my $event_path = $event->RelativePath();
|
|
||||||
Debug("Deleting files for Event $$event{Id} from $storage_path/$event_path, scheme is $$event{Scheme}.");
|
|
||||||
if ( $event_path ) {
|
|
||||||
( $storage_path ) = ( $storage_path =~ /^(.*)$/ ); # De-taint
|
|
||||||
( $event_path ) = ( $event_path =~ /^(.*)$/ ); # De-taint
|
|
||||||
|
|
||||||
my $deleted = 0;
|
|
||||||
if ( $$Storage{Type} and ( $$Storage{Type} eq 's3fs' ) ) {
|
|
||||||
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$Storage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
|
|
||||||
eval {
|
|
||||||
require Net::Amazon::S3;
|
|
||||||
my $s3 = Net::Amazon::S3->new( {
|
|
||||||
aws_access_key_id => $aws_id,
|
|
||||||
aws_secret_access_key => $aws_secret,
|
|
||||||
( $aws_host ? ( host => $aws_host ) : () ),
|
|
||||||
});
|
|
||||||
my $bucket = $s3->bucket($aws_bucket);
|
|
||||||
if ( ! $bucket ) {
|
|
||||||
Error("S3 bucket $bucket not found.");
|
|
||||||
die;
|
|
||||||
}
|
|
||||||
if ( $bucket->delete_key($event_path) ) {
|
|
||||||
$deleted = 1;
|
|
||||||
} else {
|
|
||||||
Error('Failed to delete from S3:'.$s3->err . ': ' . $s3->errstr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Error($@) if $@;
|
|
||||||
}
|
}
|
||||||
if ( !$deleted ) {
|
|
||||||
my $command = "/bin/rm -rf $storage_path/$event_path";
|
|
||||||
ZoneMinder::General::executeShellCommand($command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $event->Scheme() eq 'Deep' ) {
|
if ( ! $$event{MonitorId} ) {
|
||||||
my $link_path = $event->LinkPath();
|
Error("No monitor id assigned to event $$event{Id}");
|
||||||
Debug("Deleting link for Event $$event{Id} from $storage_path/$link_path.");
|
return;
|
||||||
if ( $link_path ) {
|
}
|
||||||
( $link_path ) = ( $link_path =~ /^(.*)$/ ); # De-taint
|
my $event_path = $event->RelativePath();
|
||||||
|
Debug("Deleting files for Event $$event{Id} from $storage_path/$event_path, scheme is $$event{Scheme}.");
|
||||||
|
if ( $event_path ) {
|
||||||
|
( $storage_path ) = ( $storage_path =~ /^(.*)$/ ); # De-taint
|
||||||
|
( $event_path ) = ( $event_path =~ /^(.*)$/ ); # De-taint
|
||||||
|
|
||||||
|
my $deleted = 0;
|
||||||
|
if ( $$Storage{Type} and ( $$Storage{Type} eq 's3fs' ) ) {
|
||||||
|
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$Storage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
|
||||||
|
eval {
|
||||||
|
require Net::Amazon::S3;
|
||||||
|
my $s3 = Net::Amazon::S3->new( {
|
||||||
|
aws_access_key_id => $aws_id,
|
||||||
|
aws_secret_access_key => $aws_secret,
|
||||||
|
( $aws_host ? ( host => $aws_host ) : () ),
|
||||||
|
});
|
||||||
|
my $bucket = $s3->bucket($aws_bucket);
|
||||||
|
if ( ! $bucket ) {
|
||||||
|
Error("S3 bucket $bucket not found.");
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
if ( $bucket->delete_key($event_path) ) {
|
||||||
|
$deleted = 1;
|
||||||
|
} else {
|
||||||
|
Error('Failed to delete from S3:'.$s3->err . ': ' . $s3->errstr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Error($@) if $@;
|
||||||
|
}
|
||||||
|
if ( !$deleted ) {
|
||||||
|
my $command = "/bin/rm -rf $storage_path/$event_path";
|
||||||
|
ZoneMinder::General::executeShellCommand($command);
|
||||||
|
}
|
||||||
|
} # end if event_path
|
||||||
|
|
||||||
|
if ( $event->Scheme() eq 'Deep' ) {
|
||||||
|
my $link_path = $event->LinkPath();
|
||||||
|
Debug("Deleting link for Event $$event{Id} from $storage_path/$link_path.");
|
||||||
|
if ( $link_path ) {
|
||||||
|
( $link_path ) = ( $link_path =~ /^(.*)$/ ); # De-taint
|
||||||
unlink($storage_path.'/'.$link_path) or Error("Unable to unlink '$storage_path/$link_path': $!");
|
unlink($storage_path.'/'.$link_path) or Error("Unable to unlink '$storage_path/$link_path': $!");
|
||||||
}
|
}
|
||||||
}
|
} # end if Scheme eq Deep
|
||||||
|
} # end foreach Storage
|
||||||
} # end sub delete_files
|
} # end sub delete_files
|
||||||
|
|
||||||
sub StorageId {
|
sub StorageId {
|
||||||
|
@ -519,7 +528,7 @@ sub DiskSpace {
|
||||||
return $_[0]{DiskSpace};
|
return $_[0]{DiskSpace};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub MoveTo {
|
sub CopyTo {
|
||||||
my ( $self, $NewStorage ) = @_;
|
my ( $self, $NewStorage ) = @_;
|
||||||
|
|
||||||
my $OldStorage = $self->Storage(undef);
|
my $OldStorage = $self->Storage(undef);
|
||||||
|
@ -531,9 +540,9 @@ sub MoveTo {
|
||||||
# We do this before bothering to lock the event
|
# We do this before bothering to lock the event
|
||||||
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
|
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
|
||||||
if ( ! $$NewStorage{Id} ) {
|
if ( ! $$NewStorage{Id} ) {
|
||||||
return "New storage does not have an id. Moving will not happen.";
|
return 'New storage does not have an id. Moving will not happen.';
|
||||||
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
|
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
|
||||||
return "Event is already located at " . $NewPath;
|
return 'Event is already located at ' . $NewPath;
|
||||||
} elsif ( !$NewPath ) {
|
} elsif ( !$NewPath ) {
|
||||||
return "New path ($NewPath) is empty.";
|
return "New path ($NewPath) is empty.";
|
||||||
} elsif ( ! -e $NewPath ) {
|
} elsif ( ! -e $NewPath ) {
|
||||||
|
@ -545,7 +554,7 @@ sub MoveTo {
|
||||||
# data is reloaded, so need to check that the move hasn't already happened.
|
# data is reloaded, so need to check that the move hasn't already happened.
|
||||||
if ( $$self{StorageId} == $$NewStorage{Id} ) {
|
if ( $$self{StorageId} == $$NewStorage{Id} ) {
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
return "Event has already been moved by someone else.";
|
return 'Event has already been moved by someone else.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $$OldStorage{Id} != $$self{StorageId} ) {
|
if ( $$OldStorage{Id} != $$self{StorageId} ) {
|
||||||
|
@ -559,70 +568,76 @@ sub MoveTo {
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
return "New path and old path are the same! $NewPath";
|
return "New path and old path are the same! $NewPath";
|
||||||
}
|
}
|
||||||
Debug("Moving event $$self{Id} from $OldPath to $NewPath");
|
Debug("Copying event $$self{Id} from $OldPath to $NewPath");
|
||||||
|
|
||||||
my $moved = 0;
|
my $moved = 0;
|
||||||
|
|
||||||
if ( $$NewStorage{Type} eq 's3fs' ) {
|
if ( $$NewStorage{Type} eq 's3fs' ) {
|
||||||
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$NewStorage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
|
if ( $$NewStorage{Url} ) {
|
||||||
eval {
|
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$NewStorage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
|
||||||
require Net::Amazon::S3;
|
if ( $aws_id and $aws_secret and $aws_host and $aws_bucket ) {
|
||||||
require File::Slurp;
|
eval {
|
||||||
my $s3 = Net::Amazon::S3->new( {
|
require Net::Amazon::S3;
|
||||||
aws_access_key_id => $aws_id,
|
require File::Slurp;
|
||||||
aws_secret_access_key => $aws_secret,
|
my $s3 = Net::Amazon::S3->new( {
|
||||||
( $aws_host ? ( host => $aws_host ) : () ),
|
aws_access_key_id => $aws_id,
|
||||||
});
|
aws_secret_access_key => $aws_secret,
|
||||||
my $bucket = $s3->bucket($aws_bucket);
|
( $aws_host ? ( host => $aws_host ) : () ),
|
||||||
if ( ! $bucket ) {
|
});
|
||||||
Error("S3 bucket $bucket not found.");
|
my $bucket = $s3->bucket($aws_bucket);
|
||||||
die;
|
if ( !$bucket ) {
|
||||||
|
Error("S3 bucket $bucket not found.");
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $event_path = $self->RelativePath();
|
||||||
|
Debug("Making directory $event_path/");
|
||||||
|
if ( ! $bucket->add_key($event_path.'/', '') ) {
|
||||||
|
die "Unable to add key for $event_path/";
|
||||||
|
}
|
||||||
|
|
||||||
|
my @files = glob("$OldPath/*");
|
||||||
|
Debug("Files to move @files");
|
||||||
|
foreach my $file ( @files ) {
|
||||||
|
next if $file =~ /^\./;
|
||||||
|
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
|
||||||
|
my $starttime = [gettimeofday];
|
||||||
|
Debug("Moving file $file to $NewPath");
|
||||||
|
my $size = -s $file;
|
||||||
|
if ( ! $size ) {
|
||||||
|
Info('Not moving file with 0 size');
|
||||||
|
}
|
||||||
|
my $file_contents = File::Slurp::read_file($file);
|
||||||
|
if ( ! $file_contents ) {
|
||||||
|
die 'Loaded empty file, but it had a size. Giving up';
|
||||||
|
}
|
||||||
|
|
||||||
|
my $filename = $event_path.'/'.File::Basename::basename($file);
|
||||||
|
if ( ! $bucket->add_key($filename, $file_contents) ) {
|
||||||
|
die "Unable to add key for $filename";
|
||||||
|
}
|
||||||
|
my $duration = tv_interval($starttime);
|
||||||
|
Debug('PUT to S3 ' . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($duration?$size/$duration:$size) . '/sec');
|
||||||
|
} # end foreach file.
|
||||||
|
|
||||||
|
$moved = 1;
|
||||||
|
};
|
||||||
|
Error($@) if $@;
|
||||||
|
} else {
|
||||||
|
Error("Unable to parse S3 Url into it's component parts.");
|
||||||
}
|
}
|
||||||
|
#die $@ if $@;
|
||||||
my $event_path = 'events/'.$self->RelativePath();
|
} # end if Url
|
||||||
Info("Making dir ectory $event_path/");
|
|
||||||
if ( ! $bucket->add_key( $event_path.'/','' ) ) {
|
|
||||||
die "Unable to add key for $event_path/";
|
|
||||||
}
|
|
||||||
|
|
||||||
my @files = glob("$OldPath/*");
|
|
||||||
Debug("Files to move @files");
|
|
||||||
for my $file (@files) {
|
|
||||||
next if $file =~ /^\./;
|
|
||||||
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
|
|
||||||
my $starttime = time;
|
|
||||||
Debug("Moving file $file to $NewPath");
|
|
||||||
my $size = -s $file;
|
|
||||||
if ( ! $size ) {
|
|
||||||
Info('Not moving file with 0 size');
|
|
||||||
}
|
|
||||||
my $file_contents = File::Slurp::read_file($file);
|
|
||||||
if ( ! $file_contents ) {
|
|
||||||
die 'Loaded empty file, but it had a size. Giving up';
|
|
||||||
}
|
|
||||||
|
|
||||||
my $filename = $event_path.'/'.File::Basename::basename($file);
|
|
||||||
if ( ! $bucket->add_key( $filename, $file_contents ) ) {
|
|
||||||
die "Unable to add key for $filename";
|
|
||||||
}
|
|
||||||
my $duration = time - $starttime;
|
|
||||||
Debug('PUT to S3 ' . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($duration?$size/$duration:$size) . '/sec');
|
|
||||||
} # end foreach file.
|
|
||||||
|
|
||||||
$moved = 1;
|
|
||||||
};
|
|
||||||
Error($@) if $@;
|
|
||||||
die $@ if $@;
|
|
||||||
} # end if s3
|
} # end if s3
|
||||||
|
|
||||||
my $error = '';
|
my $error = '';
|
||||||
if ( ! $moved ) {
|
if ( !$moved ) {
|
||||||
File::Path::make_path( $NewPath, {error => \my $err} );
|
File::Path::make_path($NewPath, {error => \my $err});
|
||||||
if ( @$err ) {
|
if ( @$err ) {
|
||||||
for my $diag (@$err) {
|
for my $diag (@$err) {
|
||||||
my ($file, $message) = %$diag;
|
my ($file, $message) = %$diag;
|
||||||
next if $message eq 'File exists';
|
next if $message eq 'File exists';
|
||||||
if ($file eq '') {
|
if ( $file eq '' ) {
|
||||||
$error .= "general error: $message\n";
|
$error .= "general error: $message\n";
|
||||||
} else {
|
} else {
|
||||||
$error .= "problem making $file: $message\n";
|
$error .= "problem making $file: $message\n";
|
||||||
|
@ -636,21 +651,21 @@ Debug("Files to move @files");
|
||||||
my @files = glob("$OldPath/*");
|
my @files = glob("$OldPath/*");
|
||||||
if ( ! @files ) {
|
if ( ! @files ) {
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
return "No files to move.";
|
return 'No files to move.';
|
||||||
}
|
}
|
||||||
|
|
||||||
for my $file (@files) {
|
for my $file (@files) {
|
||||||
next if $file =~ /^\./;
|
next if $file =~ /^\./;
|
||||||
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
|
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
|
||||||
my $starttime = time;
|
my $starttime = [gettimeofday];
|
||||||
Debug("Moving file $file to $NewPath");
|
Debug("Moving file $file to $NewPath");
|
||||||
my $size = -s $file;
|
my $size = -s $file;
|
||||||
if ( ! File::Copy::copy( $file, $NewPath ) ) {
|
if ( ! File::Copy::copy( $file, $NewPath ) ) {
|
||||||
$error .= "Copy failed: for $file to $NewPath: $!";
|
$error .= "Copy failed: for $file to $NewPath: $!";
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
my $duration = time - $starttime;
|
my $duration = tv_interval($starttime);
|
||||||
Debug("Copied " . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . ($duration?Number::Bytes::Human::format_bytes($size/$duration):'inf') . "/sec");
|
Debug('Copied ' . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . ($duration?Number::Bytes::Human::format_bytes($size/$duration):'inf') . '/sec');
|
||||||
} # end foreach file.
|
} # end foreach file.
|
||||||
} # end if ! moved
|
} # end if ! moved
|
||||||
|
|
||||||
|
@ -658,6 +673,15 @@ Debug("Files to move @files");
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
return $error;
|
return $error;
|
||||||
}
|
}
|
||||||
|
} # end sub CopyTo
|
||||||
|
|
||||||
|
sub MoveTo {
|
||||||
|
|
||||||
|
my ( $self, $NewStorage ) = @_;
|
||||||
|
my $OldStorage = $self->Storage(undef);
|
||||||
|
|
||||||
|
my $error = $self->CopyTo($NewStorage);
|
||||||
|
return $error if $error;
|
||||||
|
|
||||||
# Succeeded in copying all files, so we may now update the Event.
|
# Succeeded in copying all files, so we may now update the Event.
|
||||||
$$self{StorageId} = $$NewStorage{Id};
|
$$self{StorageId} = $$NewStorage{Id};
|
||||||
|
@ -667,10 +691,8 @@ Debug("Files to move @files");
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
return $error;
|
return $error;
|
||||||
}
|
}
|
||||||
Debug("Committing");
|
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
$self->delete_files( $OldStorage );
|
$self->delete_files($OldStorage);
|
||||||
Debug("Done deleting files, returning");
|
|
||||||
return $error;
|
return $error;
|
||||||
} # end sub MoveTo
|
} # end sub MoveTo
|
||||||
|
|
||||||
|
|
|
@ -132,11 +132,13 @@ sub Sql {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$$self{Sql} = shift if @_;
|
$$self{Sql} = shift if @_;
|
||||||
if ( ! $$self{Sql} ) {
|
if ( ! $$self{Sql} ) {
|
||||||
if ( !$self->{Query} ) {
|
$self->{Sql} = '';
|
||||||
Warning('No Query in filter.');
|
if ( ! $self->{Query_json} ) {
|
||||||
|
Warning("No query in Filter!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
my $filter_expr = ZoneMinder::General::jsonDecode($self->{Query});
|
|
||||||
|
my $filter_expr = ZoneMinder::General::jsonDecode($self->{Query_json});
|
||||||
my $sql = 'SELECT E.*,
|
my $sql = 'SELECT E.*,
|
||||||
unix_timestamp(E.StartTime) as Time,
|
unix_timestamp(E.StartTime) as Time,
|
||||||
M.Name as MonitorName,
|
M.Name as MonitorName,
|
||||||
|
@ -146,7 +148,6 @@ sub Sql {
|
||||||
INNER JOIN Monitors as M on M.Id = E.MonitorId
|
INNER JOIN Monitors as M on M.Id = E.MonitorId
|
||||||
LEFT JOIN Storage as S on S.Id = E.StorageId
|
LEFT JOIN Storage as S on S.Id = E.StorageId
|
||||||
';
|
';
|
||||||
$self->{Sql} = '';
|
|
||||||
|
|
||||||
if ( $filter_expr->{terms} ) {
|
if ( $filter_expr->{terms} ) {
|
||||||
foreach my $term ( @{$filter_expr->{terms}} ) {
|
foreach my $term ( @{$filter_expr->{terms}} ) {
|
||||||
|
|
|
@ -46,56 +46,13 @@ use ZoneMinder::Database qw(:all);
|
||||||
|
|
||||||
use POSIX;
|
use POSIX;
|
||||||
|
|
||||||
use vars qw/ $table $primary_key /;
|
use vars qw/ $table $primary_key %fields/;
|
||||||
$table = 'Storage';
|
$table = 'Storage';
|
||||||
$primary_key = 'Id';
|
$primary_key = 'Id';
|
||||||
#__PACKAGE__->table('Storage');
|
#__PACKAGE__->table('Storage');
|
||||||
#__PACKAGE__->primary_key('Id');
|
#__PACKAGE__->primary_key('Id');
|
||||||
|
%fields = map { $_ => $_ } qw( Id Name Path DoDelete ServerId Type Url DiskSpace Scheme );
|
||||||
|
|
||||||
sub find {
|
|
||||||
shift if $_[0] eq 'ZoneMinder::Storage';
|
|
||||||
my %sql_filters = @_;
|
|
||||||
|
|
||||||
my $sql = 'SELECT * FROM Storage';
|
|
||||||
my @sql_filters;
|
|
||||||
my @sql_values;
|
|
||||||
|
|
||||||
if ( exists $sql_filters{Id} ) {
|
|
||||||
push @sql_filters , ' Id=? ';
|
|
||||||
push @sql_values, $sql_filters{Id};
|
|
||||||
}
|
|
||||||
if ( exists $sql_filters{Name} ) {
|
|
||||||
push @sql_filters , ' Name = ? ';
|
|
||||||
push @sql_values, $sql_filters{Name};
|
|
||||||
}
|
|
||||||
if ( exists $sql_filters{ServerId} ) {
|
|
||||||
push @sql_filters, ' ServerId = ?';
|
|
||||||
push @sql_values, $sql_filters{ServerId};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$sql .= ' WHERE ' . join(' AND ', @sql_filters) if @sql_filters;
|
|
||||||
$sql .= ' LIMIT ' . $sql_filters{limit} if $sql_filters{limit};
|
|
||||||
|
|
||||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
|
|
||||||
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
|
|
||||||
my $res = $sth->execute( @sql_values )
|
|
||||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
|
||||||
|
|
||||||
my @results;
|
|
||||||
|
|
||||||
while( my $db_filter = $sth->fetchrow_hashref() ) {
|
|
||||||
my $filter = new ZoneMinder::Storage( $$db_filter{Id}, $db_filter );
|
|
||||||
push @results, $filter;
|
|
||||||
} # end while
|
|
||||||
Debug("SQL: $sql returned " . @results . ' results');
|
|
||||||
return @results;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub find_one {
|
|
||||||
my @results = find(@_);
|
|
||||||
return $results[0] if @results;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub Path {
|
sub Path {
|
||||||
if ( @_ > 1 ) {
|
if ( @_ > 1 ) {
|
||||||
|
|
|
@ -240,6 +240,7 @@ sub getFilters {
|
||||||
or AutoDelete = 1
|
or AutoDelete = 1
|
||||||
or UpdateDiskSpace = 1
|
or UpdateDiskSpace = 1
|
||||||
or AutoMove = 1
|
or AutoMove = 1
|
||||||
|
or AutoCopy = 1
|
||||||
) ORDER BY Name';
|
) ORDER BY Name';
|
||||||
my $sth = $dbh->prepare_cached($sql)
|
my $sth = $dbh->prepare_cached($sql)
|
||||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||||
|
@ -283,6 +284,7 @@ sub checkFilter {
|
||||||
($filter->{AutoMessage}?'message':()),
|
($filter->{AutoMessage}?'message':()),
|
||||||
($filter->{AutoExecute}?'execute':()),
|
($filter->{AutoExecute}?'execute':()),
|
||||||
($filter->{AutoMove}?'move':()),
|
($filter->{AutoMove}?'move':()),
|
||||||
|
($filter->{AutoCopy}?'copy':()),
|
||||||
($filter->{UpdateDiskSpace}?'update disk space':()),
|
($filter->{UpdateDiskSpace}?'update disk space':()),
|
||||||
),
|
),
|
||||||
'returned' , scalar @Events , 'events',
|
'returned' , scalar @Events , 'events',
|
||||||
|
@ -300,9 +302,9 @@ sub checkFilter {
|
||||||
Info("Archiving event $Event->{Id}");
|
Info("Archiving event $Event->{Id}");
|
||||||
# Do it individually to avoid locking up the table for new events
|
# Do it individually to avoid locking up the table for new events
|
||||||
my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
|
my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
|
||||||
my $sth = $dbh->prepare_cached( $sql )
|
my $sth = $dbh->prepare_cached($sql)
|
||||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||||
my $res = $sth->execute( $Event->{Id} )
|
my $res = $sth->execute($Event->{Id})
|
||||||
or Error("Unable to execute '$sql': ".$dbh->errstr());
|
or Error("Unable to execute '$sql': ".$dbh->errstr());
|
||||||
}
|
}
|
||||||
if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) {
|
if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) {
|
||||||
|
@ -343,6 +345,23 @@ sub checkFilter {
|
||||||
$_ = $Event->MoveTo($NewStorage);
|
$_ = $Event->MoveTo($NewStorage);
|
||||||
Error($_) if $_;
|
Error($_) if $_;
|
||||||
}
|
}
|
||||||
|
if ( $filter->{AutoCopy} ) {
|
||||||
|
# Copy To is different from MoveTo in that it JUST copies the files
|
||||||
|
# So we still need to update the Event object with the new SecondaryStorageId
|
||||||
|
my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoCopyTo});
|
||||||
|
if ( $NewStorage ) {
|
||||||
|
$_ = $Event->CopyTo($NewStorage);
|
||||||
|
if ( $_ ) {
|
||||||
|
$ZoneMinder::Database::dbh->commit();
|
||||||
|
Error($_);
|
||||||
|
} else {
|
||||||
|
$Event->save({SecondaryStorageId=>$$NewStorage{Id}});
|
||||||
|
$ZoneMinder::Database::dbh->commit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("No storage area found for copy to operation. AutoCopyTo was $$filter{AutoCopyTo}");
|
||||||
|
}
|
||||||
|
} # end if AutoCopy
|
||||||
|
|
||||||
if ( $filter->{UpdateDiskSpace} ) {
|
if ( $filter->{UpdateDiskSpace} ) {
|
||||||
$ZoneMinder::Database::dbh->begin_work();
|
$ZoneMinder::Database::dbh->begin_work();
|
||||||
|
@ -361,7 +380,7 @@ sub checkFilter {
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
} # end if UpdateDiskSpace
|
} # end if UpdateDiskSpace
|
||||||
} # end foreach event
|
} # end foreach event
|
||||||
}
|
} # end sub checkFilter
|
||||||
|
|
||||||
sub generateVideo {
|
sub generateVideo {
|
||||||
my $filter = shift;
|
my $filter = shift;
|
||||||
|
@ -623,7 +642,7 @@ sub substituteTags {
|
||||||
my $Monitor = $Event->Monitor() if $need_monitor;
|
my $Monitor = $Event->Monitor() if $need_monitor;
|
||||||
|
|
||||||
# Do we need the image information too?
|
# Do we need the image information too?
|
||||||
my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA)%/;
|
my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA|EIMOD)%/;
|
||||||
my $first_alarm_frame;
|
my $first_alarm_frame;
|
||||||
my $max_alarm_frame;
|
my $max_alarm_frame;
|
||||||
my $max_alarm_score = 0;
|
my $max_alarm_score = 0;
|
||||||
|
|
|
@ -88,13 +88,13 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||||
logInit();
|
logInit();
|
||||||
logSetSignal();
|
logSetSignal();
|
||||||
|
|
||||||
Info( "Trigger daemon starting" );
|
Info('Trigger daemon starting');
|
||||||
|
|
||||||
my $dbh = zmDbConnect();
|
my $dbh = zmDbConnect();
|
||||||
|
|
||||||
my $base_rin = '';
|
my $base_rin = '';
|
||||||
foreach my $connection ( @connections ) {
|
foreach my $connection ( @connections ) {
|
||||||
Info( "Opening connection '$connection->{name}'" );
|
Info("Opening connection '$connection->{name}'");
|
||||||
$connection->open();
|
$connection->open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,32 +118,32 @@ my $win = $rin;
|
||||||
my $ein = $win;
|
my $ein = $win;
|
||||||
my $timeout = SELECT_TIMEOUT;
|
my $timeout = SELECT_TIMEOUT;
|
||||||
my %actions;
|
my %actions;
|
||||||
while( 1 ) {
|
while (1) {
|
||||||
$rin = $base_rin;
|
$rin = $base_rin;
|
||||||
# Add the file descriptors of any spawned connections
|
# Add the file descriptors of any spawned connections
|
||||||
foreach my $fileno ( keys(%spawned_connections) ) {
|
foreach my $fileno ( keys %spawned_connections ) {
|
||||||
vec( $rin, $fileno, 1 ) = 1;
|
vec($rin, $fileno, 1) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout );
|
my $nfound = select(my $rout = $rin, undef, my $eout = $ein, $timeout);
|
||||||
if ( $nfound > 0 ) {
|
if ( $nfound > 0 ) {
|
||||||
Debug( "Got input from $nfound connections" );
|
Debug("Got input from $nfound connections");
|
||||||
foreach my $connection ( @in_select_connections ) {
|
foreach my $connection ( @in_select_connections ) {
|
||||||
if ( vec( $rout, $connection->fileno(), 1 ) ) {
|
if ( vec($rout, $connection->fileno(), 1) ) {
|
||||||
Debug( 'Got input from connection '
|
Debug('Got input from connection '
|
||||||
.$connection->name()
|
.$connection->name()
|
||||||
.' ('
|
.' ('
|
||||||
.$connection->fileno()
|
.$connection->fileno()
|
||||||
.")"
|
.')'
|
||||||
);
|
);
|
||||||
if ( $connection->spawns() ) {
|
if ( $connection->spawns() ) {
|
||||||
my $new_connection = $connection->accept();
|
my $new_connection = $connection->accept();
|
||||||
$spawned_connections{$new_connection->fileno()} = $new_connection;
|
$spawned_connections{$new_connection->fileno()} = $new_connection;
|
||||||
Debug( 'Added new spawned connection ('
|
Debug('Added new spawned connection ('
|
||||||
.$new_connection->fileno()
|
.$new_connection->fileno()
|
||||||
.'), '
|
.'), '
|
||||||
.int(keys(%spawned_connections))
|
.int(keys(%spawned_connections))
|
||||||
." spawned connections"
|
.' spawned connections'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
my $messages = $connection->getMessages();
|
my $messages = $connection->getMessages();
|
||||||
|
@ -152,30 +152,30 @@ while( 1 ) {
|
||||||
handleMessage( $connection, $message );
|
handleMessage( $connection, $message );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} # end if connection->spawns
|
||||||
}
|
} # end if vec
|
||||||
} # end foreach connection
|
} # end foreach connection
|
||||||
|
|
||||||
foreach my $connection ( values(%spawned_connections) ) {
|
foreach my $connection ( values(%spawned_connections) ) {
|
||||||
if ( vec( $rout, $connection->fileno(), 1 ) ) {
|
if ( vec($rout, $connection->fileno(), 1) ) {
|
||||||
Debug( 'Got input from spawned connection '
|
Debug('Got input from spawned connection '
|
||||||
.$connection->name()
|
.$connection->name()
|
||||||
.' ('
|
.' ('
|
||||||
.$connection->fileno()
|
.$connection->fileno()
|
||||||
.")"
|
.')'
|
||||||
);
|
);
|
||||||
my $messages = $connection->getMessages();
|
my $messages = $connection->getMessages();
|
||||||
if ( defined($messages) ) {
|
if ( defined($messages) ) {
|
||||||
foreach my $message ( @$messages ) {
|
foreach my $message ( @$messages ) {
|
||||||
handleMessage( $connection, $message );
|
handleMessage($connection, $message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
delete( $spawned_connections{$connection->fileno()} );
|
delete $spawned_connections{$connection->fileno()};
|
||||||
Debug( 'Removed spawned connection ('
|
Debug('Removed spawned connection ('
|
||||||
.$connection->fileno()
|
.$connection->fileno()
|
||||||
.'), '
|
.'), '
|
||||||
.int(keys(%spawned_connections))
|
.int(keys(%spawned_connections))
|
||||||
." spawned connections"
|
.' spawned connections'
|
||||||
);
|
);
|
||||||
$connection->close();
|
$connection->close();
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ while( 1 ) {
|
||||||
if ( $! == EINTR ) {
|
if ( $! == EINTR ) {
|
||||||
# Do nothing
|
# Do nothing
|
||||||
} else {
|
} else {
|
||||||
Fatal( "Can't select: $!" );
|
Fatal("Can't select: $!");
|
||||||
}
|
}
|
||||||
} # end if select returned activitiy
|
} # end if select returned activitiy
|
||||||
|
|
||||||
|
@ -194,14 +194,14 @@ while( 1 ) {
|
||||||
my $messages = $connection->getMessages();
|
my $messages = $connection->getMessages();
|
||||||
if ( defined($messages) ) {
|
if ( defined($messages) ) {
|
||||||
foreach my $message ( @$messages ) {
|
foreach my $message ( @$messages ) {
|
||||||
handleMessage( $connection, $message );
|
handleMessage($connection, $message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check for alarms that might have happened
|
# Check for alarms that might have happened
|
||||||
my @out_messages;
|
my @out_messages;
|
||||||
foreach my $monitor ( values(%monitors) ) {
|
foreach my $monitor ( values %monitors ) {
|
||||||
|
|
||||||
if ( ! zmMemVerify($monitor) ) {
|
if ( ! zmMemVerify($monitor) ) {
|
||||||
# Our attempt to verify the memory handle failed. We should reload the monitors.
|
# Our attempt to verify the memory handle failed. We should reload the monitors.
|
||||||
|
@ -225,7 +225,7 @@ while( 1 ) {
|
||||||
|| ($last_event != $monitor->{LastEvent})
|
|| ($last_event != $monitor->{LastEvent})
|
||||||
) {
|
) {
|
||||||
# A new event
|
# A new event
|
||||||
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
push @out_messages, $monitor->{Id}.'|on|'.time().'|'.$last_event;
|
||||||
} else {
|
} else {
|
||||||
# The same one as last time, so ignore it
|
# The same one as last time, so ignore it
|
||||||
# Do nothing
|
# Do nothing
|
||||||
|
@ -236,42 +236,43 @@ while( 1 ) {
|
||||||
($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE)
|
($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE)
|
||||||
) {
|
) {
|
||||||
# Out of alarm state
|
# Out of alarm state
|
||||||
push( @out_messages, $monitor->{Id}.'|off|'.time().'|'.$last_event );
|
push @out_messages, $monitor->{Id}.'|off|'.time().'|'.$last_event;
|
||||||
} elsif (
|
} elsif (
|
||||||
defined($monitor->{LastEvent})
|
defined($monitor->{LastEvent})
|
||||||
&&
|
&&
|
||||||
($last_event != $monitor->{LastEvent})
|
($last_event != $monitor->{LastEvent})
|
||||||
) {
|
) {
|
||||||
# We've missed a whole event
|
# We've missed a whole event
|
||||||
push( @out_messages, $monitor->{Id}.'|on|'.time().'|'.$last_event );
|
push @out_messages, $monitor->{Id}.'|on|'.time().'|'.$last_event;
|
||||||
push( @out_messages, $monitor->{Id}.'|off|'.time().'|'.$last_event );
|
push @out_messages, $monitor->{Id}.'|off|'.time().'|'.$last_event;
|
||||||
}
|
}
|
||||||
$monitor->{LastState} = $state;
|
$monitor->{LastState} = $state;
|
||||||
$monitor->{LastEvent} = $last_event;
|
$monitor->{LastEvent} = $last_event;
|
||||||
} # end foreach monitor
|
} # end foreach monitor
|
||||||
|
|
||||||
foreach my $connection ( @out_connections ) {
|
foreach my $connection ( @out_connections ) {
|
||||||
if ( $connection->canWrite() ) {
|
if ( $connection->canWrite() ) {
|
||||||
$connection->putMessages( \@out_messages );
|
$connection->putMessages(\@out_messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach my $connection ( values(%spawned_connections) ) {
|
|
||||||
|
foreach my $connection ( values %spawned_connections ) {
|
||||||
if ( $connection->canWrite() ) {
|
if ( $connection->canWrite() ) {
|
||||||
$connection->putMessages( \@out_messages );
|
$connection->putMessages(\@out_messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( my @action_times = keys(%actions) ) {
|
if ( my @action_times = keys(%actions) ) {
|
||||||
Debug( "Checking for timed actions" );
|
Debug('Checking for timed actions');
|
||||||
my $now = time();
|
my $now = time();
|
||||||
foreach my $action_time ( sort( grep { $_ < $now } @action_times ) ) {
|
foreach my $action_time ( sort( grep { $_ < $now } @action_times ) ) {
|
||||||
Info( "Found actions expiring at $action_time" );
|
Info("Found " . scalar @{$actions{$action_time}} . "actions expiring at $action_time");
|
||||||
foreach my $action ( @{$actions{$action_time}} ) {
|
foreach my $action ( @{$actions{$action_time}} ) {
|
||||||
my $connection = $action->{connection};
|
my $connection = $action->{connection};
|
||||||
my $message = $action->{message};
|
Info("Found action '$$action{message}'");
|
||||||
Info( "Found action '$message'" );
|
handleMessage($connection, $$action{message});
|
||||||
handleMessage( $connection, $message );
|
|
||||||
}
|
}
|
||||||
delete( $actions{$action_time} );
|
delete $actions{$action_time};
|
||||||
}
|
}
|
||||||
} # end if have timed actions
|
} # end if have timed actions
|
||||||
|
|
||||||
|
@ -280,15 +281,16 @@ while( 1 ) {
|
||||||
my $messages = $connection->timedActions();
|
my $messages = $connection->timedActions();
|
||||||
if ( defined($messages) ) {
|
if ( defined($messages) ) {
|
||||||
foreach my $message ( @$messages ) {
|
foreach my $message ( @$messages ) {
|
||||||
handleMessage( $connection, $message );
|
handleMessage($connection, $message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach my $connection ( values(%spawned_connections) ) {
|
|
||||||
|
foreach my $connection ( values %spawned_connections ) {
|
||||||
my $messages = $connection->timedActions();
|
my $messages = $connection->timedActions();
|
||||||
if ( defined($messages) ) {
|
if ( defined($messages) ) {
|
||||||
foreach my $message ( @$messages ) {
|
foreach my $message ( @$messages ) {
|
||||||
handleMessage( $connection, $message );
|
handleMessage($connection, $message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,14 +319,14 @@ exit;
|
||||||
sub loadMonitor {
|
sub loadMonitor {
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
|
|
||||||
Debug( "Loading monitor $monitor" );
|
Debug("Loading monitor $monitor");
|
||||||
zmMemInvalidate( $monitor );
|
zmMemInvalidate($monitor);
|
||||||
|
|
||||||
if ( zmMemVerify( $monitor ) ) { # This will re-init shared memory
|
if ( zmMemVerify($monitor) ) { # This will re-init shared memory
|
||||||
$monitor->{LastState} = zmGetMonitorState( $monitor );
|
$monitor->{LastState} = zmGetMonitorState($monitor);
|
||||||
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
|
$monitor->{LastEvent} = zmGetLastEvent($monitor);
|
||||||
}
|
}
|
||||||
}
|
} # end sub loadMonitor
|
||||||
|
|
||||||
sub loadMonitors {
|
sub loadMonitors {
|
||||||
Debug('Loading monitors');
|
Debug('Loading monitors');
|
||||||
|
@ -332,18 +334,19 @@ sub loadMonitors {
|
||||||
|
|
||||||
my %new_monitors = ();
|
my %new_monitors = ();
|
||||||
|
|
||||||
my $sql = "SELECT * FROM Monitors
|
my $sql = q`SELECT * FROM Monitors
|
||||||
WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )".
|
WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )`.
|
||||||
( $Config{ZM_SERVER_ID} ? 'AND ServerId=?' : '' )
|
( $Config{ZM_SERVER_ID} ? ' AND ServerId=?' : '' )
|
||||||
;
|
;
|
||||||
my $sth = $dbh->prepare_cached( $sql )
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
|
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
|
||||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
|
||||||
if ( zmMemVerify( $monitor ) ) { # This will re-init shared memory
|
while ( my $monitor = $sth->fetchrow_hashref() ) {
|
||||||
$monitor->{LastState} = zmGetMonitorState( $monitor );
|
if ( zmMemVerify($monitor) ) { # This will re-init shared memory
|
||||||
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
|
$monitor->{LastState} = zmGetMonitorState($monitor);
|
||||||
|
$monitor->{LastEvent} = zmGetLastEvent($monitor);
|
||||||
}
|
}
|
||||||
$new_monitors{$monitor->{Id}} = $monitor;
|
$new_monitors{$monitor->{Id}} = $monitor;
|
||||||
} # end while fetchrow
|
} # end while fetchrow
|
||||||
|
@ -367,7 +370,7 @@ sub handleMessage {
|
||||||
}
|
}
|
||||||
Debug("Found monitor for id '$id'");
|
Debug("Found monitor for id '$id'");
|
||||||
|
|
||||||
next if ( !zmMemVerify($monitor) );
|
next if !zmMemVerify($monitor);
|
||||||
|
|
||||||
Debug("Handling action '$action'");
|
Debug("Handling action '$action'");
|
||||||
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) {
|
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) {
|
||||||
|
@ -412,20 +415,20 @@ sub handleMessage {
|
||||||
zmTriggerShowtext($monitor, $showtext) if defined($showtext);
|
zmTriggerShowtext($monitor, $showtext) if defined($showtext);
|
||||||
Info("Trigger '$trigger'");
|
Info("Trigger '$trigger'");
|
||||||
# Wait til it's finished
|
# Wait til it's finished
|
||||||
while( zmInAlarm($monitor)
|
while ( zmInAlarm($monitor)
|
||||||
&& ($last_event == zmGetLastEvent($monitor))
|
&& ($last_event == zmGetLastEvent($monitor))
|
||||||
) {
|
) {
|
||||||
# Tenth of a second
|
# Tenth of a second
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
}
|
}
|
||||||
zmTriggerEventCancel($monitor);
|
zmTriggerEventCancel($monitor);
|
||||||
}
|
} # end if delay or not
|
||||||
} # end if trigger is on or off
|
} # end if trigger is on or off
|
||||||
} elsif( $action eq 'cancel' ) {
|
} elsif ( $action eq 'cancel' ) {
|
||||||
zmTriggerEventCancel($monitor);
|
zmTriggerEventCancel($monitor);
|
||||||
zmTriggerShowtext($monitor, $showtext) if defined($showtext);
|
zmTriggerShowtext($monitor, $showtext) if defined($showtext);
|
||||||
Info('Cancelled event');
|
Info('Cancelled event');
|
||||||
} elsif( $action eq 'show' ) {
|
} elsif ( $action eq 'show' ) {
|
||||||
zmTriggerShowtext( $monitor, $showtext );
|
zmTriggerShowtext( $monitor, $showtext );
|
||||||
Info("Updated show text to '$showtext'");
|
Info("Updated show text to '$showtext'");
|
||||||
} else {
|
} else {
|
||||||
|
@ -439,11 +442,26 @@ sub handleDelay {
|
||||||
my $action_text = shift;
|
my $action_text = shift;
|
||||||
|
|
||||||
my $action_time = time()+$delay;
|
my $action_time = time()+$delay;
|
||||||
|
|
||||||
|
# Need to check and cancel previous actions. See issue #2619
|
||||||
|
foreach my $a_time ( keys %actions ) {
|
||||||
|
if ( $a_time <= $action_time ) {
|
||||||
|
for ( my $i = 0; $i < @{$actions{$a_time}}; $i ++ ) {
|
||||||
|
my $action = $actions{$a_time}[$i];
|
||||||
|
if ( $$action{message} eq $action_text ) {
|
||||||
|
Info("Found duplicate action '$$action{message}' at $a_time, cancelling it");
|
||||||
|
splice @{$actions{$a_time}}, $i, 1;
|
||||||
|
}
|
||||||
|
} # end foreach action
|
||||||
|
delete $actions{$a_time} if !@{$actions{$a_time}};
|
||||||
|
} # end if
|
||||||
|
} # end foreach action_time
|
||||||
|
|
||||||
my $action_array = $actions{$action_time};
|
my $action_array = $actions{$action_time};
|
||||||
if ( !$action_array ) {
|
if ( !$action_array ) {
|
||||||
$action_array = $actions{$action_time} = [];
|
$action_array = $actions{$action_time} = [];
|
||||||
}
|
}
|
||||||
push( @$action_array, { connection=>$connection, message=>$action_text } );
|
push @$action_array, { connection=>$connection, message=>$action_text };
|
||||||
Debug("Added timed event '$action_text', expires at $action_time (+$delay secs)");
|
Debug("Added timed event '$action_text', expires at $action_time (+$delay secs)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ protected:
|
||||||
unsigned int colours;
|
unsigned int colours;
|
||||||
unsigned int subpixelorder;
|
unsigned int subpixelorder;
|
||||||
unsigned int pixels;
|
unsigned int pixels;
|
||||||
unsigned int imagesize;
|
unsigned long long imagesize;
|
||||||
int brightness;
|
int brightness;
|
||||||
int hue;
|
int hue;
|
||||||
int colour;
|
int colour;
|
||||||
|
@ -73,7 +73,7 @@ public:
|
||||||
unsigned int Colours() const { return colours; }
|
unsigned int Colours() const { return colours; }
|
||||||
unsigned int SubpixelOrder() const { return subpixelorder; }
|
unsigned int SubpixelOrder() const { return subpixelorder; }
|
||||||
unsigned int Pixels() const { return pixels; }
|
unsigned int Pixels() const { return pixels; }
|
||||||
unsigned int ImageSize() const { return imagesize; }
|
unsigned long long ImageSize() const { return imagesize; }
|
||||||
unsigned int Bytes() const { return bytes; };
|
unsigned int Bytes() const { return bytes; };
|
||||||
|
|
||||||
virtual int Brightness( int/*p_brightness*/=-1 ) { return -1; }
|
virtual int Brightness( int/*p_brightness*/=-1 ) { return -1; }
|
||||||
|
|
|
@ -287,18 +287,6 @@ static void zm_log_fps(double d, const char *postfix) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void zm_dump_video_frame(const AVFrame *frame, const char *text) {
|
|
||||||
Debug(1, "%s: format %d %s %dx%d linesize:%d pts: %" PRId64,
|
|
||||||
text,
|
|
||||||
frame->format,
|
|
||||||
av_get_pix_fmt_name((AVPixelFormat)frame->format),
|
|
||||||
frame->width,
|
|
||||||
frame->height,
|
|
||||||
frame->linesize,
|
|
||||||
frame->pts
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
void zm_dump_codecpar ( const AVCodecParameters *par ) {
|
void zm_dump_codecpar ( const AVCodecParameters *par ) {
|
||||||
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d) bit_rate(%d) format(%d = %s)",
|
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d) bit_rate(%d) format(%d = %s)",
|
||||||
|
|
|
@ -329,7 +329,15 @@ void zm_dump_codecpar(const AVCodecParameters *par);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void zm_dump_video_frame(const AVFrame *frame, const char *text="Frame");
|
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
|
||||||
|
text, \
|
||||||
|
frame->format, \
|
||||||
|
av_get_pix_fmt_name((AVPixelFormat)frame->format), \
|
||||||
|
frame->width, \
|
||||||
|
frame->height, \
|
||||||
|
frame->linesize[0], frame->linesize[1], \
|
||||||
|
frame->pts \
|
||||||
|
);
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||||
#define zm_av_packet_unref( packet ) av_packet_unref( packet )
|
#define zm_av_packet_unref( packet ) av_packet_unref( packet )
|
||||||
|
|
|
@ -44,6 +44,7 @@ extern "C" {
|
||||||
|
|
||||||
|
|
||||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||||
static enum AVPixelFormat hw_pix_fmt;
|
static enum AVPixelFormat hw_pix_fmt;
|
||||||
static enum AVPixelFormat get_hw_format(
|
static enum AVPixelFormat get_hw_format(
|
||||||
AVCodecContext *ctx,
|
AVCodecContext *ctx,
|
||||||
|
@ -94,6 +95,7 @@ static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
FfmpegCamera::FfmpegCamera(
|
FfmpegCamera::FfmpegCamera(
|
||||||
int p_id,
|
int p_id,
|
||||||
|
@ -155,8 +157,10 @@ FfmpegCamera::FfmpegCamera(
|
||||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||||
hwFrame = NULL;
|
hwFrame = NULL;
|
||||||
hw_device_ctx = NULL;
|
hw_device_ctx = NULL;
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||||
hw_pix_fmt = AV_PIX_FMT_NONE;
|
hw_pix_fmt = AV_PIX_FMT_NONE;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
mConvertContext = NULL;
|
mConvertContext = NULL;
|
||||||
|
@ -437,6 +441,8 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
|
|
||||||
if ( hwaccel_name != "" ) {
|
if ( hwaccel_name != "" ) {
|
||||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||||
|
// 3.2 doesn't seem to have all the bits in place, so let's require 3.3 and up
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||||
// Print out available types
|
// Print out available types
|
||||||
enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
|
enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
|
||||||
while ( (type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE )
|
while ( (type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE )
|
||||||
|
@ -497,6 +503,9 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "Failed to setup hwaccel.");
|
Debug(1, "Failed to setup hwaccel.");
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
Debug(1, "AVCodec not new enough for hwaccel");
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
Warning("HWAccel support not compiled in.");
|
Warning("HWAccel support not compiled in.");
|
||||||
#endif
|
#endif
|
||||||
|
@ -944,8 +953,10 @@ int FfmpegCamera::CaptureAndRecord(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( error_count > 0 ) error_count--;
|
if ( error_count > 0 ) error_count--;
|
||||||
zm_dump_video_frame(mRawFrame);
|
Debug(3, "Decoded video packet at frame %d", frameCount);
|
||||||
|
zm_dump_video_frame(mRawFrame, "raw frame from decoder");
|
||||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||||
if (
|
if (
|
||||||
(hw_pix_fmt != AV_PIX_FMT_NONE)
|
(hw_pix_fmt != AV_PIX_FMT_NONE)
|
||||||
&&
|
&&
|
||||||
|
@ -964,14 +975,18 @@ int FfmpegCamera::CaptureAndRecord(
|
||||||
hwFrame->pts = mRawFrame->pts;
|
hwFrame->pts = mRawFrame->pts;
|
||||||
input_frame = hwFrame;
|
input_frame = hwFrame;
|
||||||
} else {
|
} else {
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
input_frame = mRawFrame;
|
input_frame = mRawFrame;
|
||||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Debug(4, "Got frame %d", frameCount);
|
Debug(4, "Got frame %d", frameCount);
|
||||||
if ( transfer_to_image(image, mFrame, input_frame) < 0 ) {
|
if ( transfer_to_image(image, mFrame, input_frame) < 0 ) {
|
||||||
|
Error("Failed to transfer from frame to image");
|
||||||
zm_av_packet_unref(&packet);
|
zm_av_packet_unref(&packet);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1038,8 +1053,13 @@ int FfmpegCamera::transfer_to_image(
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
av_image_fill_arrays(output_frame->data, output_frame->linesize,
|
int size = av_image_fill_arrays(
|
||||||
directbuffer, imagePixFormat, width, height, 1);
|
output_frame->data, output_frame->linesize,
|
||||||
|
directbuffer, imagePixFormat, width, height, 32);
|
||||||
|
if ( size < 0 ) {
|
||||||
|
Error("Problem setting up data pointers into image %s",
|
||||||
|
av_make_error_string(size).c_str());
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
avpicture_fill((AVPicture *)output_frame, directbuffer,
|
avpicture_fill((AVPicture *)output_frame, directbuffer,
|
||||||
imagePixFormat, width, height);
|
imagePixFormat, width, height);
|
||||||
|
@ -1061,6 +1081,12 @@ int FfmpegCamera::transfer_to_image(
|
||||||
);
|
);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
Debug(1, "Setup conversion context for %dx%d %s to %dx%d %s",
|
||||||
|
input_frame->width, input_frame->height,
|
||||||
|
av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
|
||||||
|
width, height,
|
||||||
|
av_get_pix_fmt_name(imagePixFormat)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sws_scale(
|
if ( sws_scale(
|
||||||
|
|
|
@ -497,8 +497,8 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !p_height || !p_width ) {
|
if ( ! ( p_height > 0 && p_width > 0 ) ) {
|
||||||
Error("WriteBuffer called with invalid width or height: %d %d",p_width,p_height);
|
Error("WriteBuffer called with invalid width or height: %d %d", p_width, p_height);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,11 +525,10 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
|
||||||
colours = p_colours;
|
colours = p_colours;
|
||||||
subpixelorder = p_subpixelorder;
|
subpixelorder = p_subpixelorder;
|
||||||
pixels = height*width;
|
pixels = height*width;
|
||||||
size = newsize;
|
size = newsize;
|
||||||
}
|
} // end if need to re-alloc buffer
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assign an existing buffer to the image instead of copying from a source buffer. The goal is to reduce the amount of memory copying and increase efficiency and buffer reusing. */
|
/* Assign an existing buffer to the image instead of copying from a source buffer. The goal is to reduce the amount of memory copying and increase efficiency and buffer reusing. */
|
||||||
|
|
|
@ -56,9 +56,9 @@ extern imgbufcpy_fptr_t fptr_imgbufcpy;
|
||||||
|
|
||||||
/* Should be called from Image class functions */
|
/* Should be called from Image class functions */
|
||||||
inline static uint8_t* AllocBuffer(size_t p_bufsize) {
|
inline static uint8_t* AllocBuffer(size_t p_bufsize) {
|
||||||
uint8_t* buffer = (uint8_t*)zm_mallocaligned(64,p_bufsize);
|
uint8_t* buffer = (uint8_t*)zm_mallocaligned(64, p_bufsize);
|
||||||
if ( buffer == NULL )
|
if ( buffer == NULL )
|
||||||
Fatal("Memory allocation failed: %s",strerror(errno));
|
Fatal("Memory allocation failed: %s", strerror(errno));
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ inline static void DumpBuffer(uint8_t* buffer, int buffertype) {
|
||||||
av_free(buffer);
|
av_free(buffer);
|
||||||
*/
|
*/
|
||||||
} else {
|
} else {
|
||||||
Error( "Unknown buffer type in DumpBuffer(%d)", buffertype );
|
Error("Unknown buffer type in DumpBuffer(%d)", buffertype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,8 +422,12 @@ Monitor::Monitor(
|
||||||
+ (image_buffer_count*camera->ImageSize())
|
+ (image_buffer_count*camera->ImageSize())
|
||||||
+ 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */
|
+ 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */
|
||||||
|
|
||||||
Debug(1, "mem.size SharedData=%d TriggerData=%d VideoStoreData=%d total=%" PRId64,
|
Debug(1, "mem.size(%d) SharedData=%d TriggerData=%d VideoStoreData=%d timestamps=%d images=%dx%d = %" PRId64 " total=%" PRId64,
|
||||||
sizeof(SharedData), sizeof(TriggerData), sizeof(VideoStoreData), mem_size);
|
sizeof(mem_size),
|
||||||
|
sizeof(SharedData), sizeof(TriggerData), sizeof(VideoStoreData),
|
||||||
|
(image_buffer_count*sizeof(struct timeval)),
|
||||||
|
image_buffer_count, camera->ImageSize(), (image_buffer_count*camera->ImageSize()),
|
||||||
|
mem_size);
|
||||||
mem_ptr = NULL;
|
mem_ptr = NULL;
|
||||||
|
|
||||||
storage = new Storage(storage_id);
|
storage = new Storage(storage_id);
|
||||||
|
@ -599,7 +603,7 @@ bool Monitor::connect() {
|
||||||
if ( shm_id < 0 ) {
|
if ( shm_id < 0 ) {
|
||||||
Fatal("Can't shmget, probably not enough shared memory space free: %s", strerror(errno));
|
Fatal("Can't shmget, probably not enough shared memory space free: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 );
|
mem_ptr = (unsigned char *)shmat(shm_id, 0, 0);
|
||||||
if ( mem_ptr < (void *)0 ) {
|
if ( mem_ptr < (void *)0 ) {
|
||||||
Fatal("Can't shmat: %s", strerror(errno));
|
Fatal("Can't shmat: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1010,7 +1010,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
||||||
|
|
||||||
# if 1
|
# if 1
|
||||||
if ( opkt.dts < video_out_stream->cur_dts ) {
|
if ( opkt.dts < video_out_stream->cur_dts ) {
|
||||||
Warning("Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
Debug(1, "Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
||||||
opkt.dts, opkt.pts, video_out_stream->cur_dts);
|
opkt.dts, opkt.pts, video_out_stream->cur_dts);
|
||||||
opkt.dts = video_out_stream->cur_dts;
|
opkt.dts = video_out_stream->cur_dts;
|
||||||
if ( opkt.dts > opkt.pts ) {
|
if ( opkt.dts > opkt.pts ) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ class Event {
|
||||||
'Name',
|
'Name',
|
||||||
'MonitorId',
|
'MonitorId',
|
||||||
'StorageId',
|
'StorageId',
|
||||||
|
'SecondaryStorageId',
|
||||||
'Name',
|
'Name',
|
||||||
'Cause',
|
'Cause',
|
||||||
'StartTime',
|
'StartTime',
|
||||||
|
@ -85,6 +86,19 @@ class Event {
|
||||||
return $this->{'Storage'};
|
return $this->{'Storage'};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function SecondaryStorage( $new = null ) {
|
||||||
|
if ( $new ) {
|
||||||
|
$this->{'SecondaryStorage'} = $new;
|
||||||
|
}
|
||||||
|
if ( ! ( array_key_exists('SecondaryStorage', $this) and $this->{'SecondaryStorage'} ) ) {
|
||||||
|
if ( isset($this->{'SecondaryStorageId'}) and $this->{'SecondaryStorageId'} )
|
||||||
|
$this->{'SecondaryStorage'} = Storage::find_one(array('Id'=>$this->{'SecondaryStorageId'}));
|
||||||
|
if ( ! ( array_key_exists('SecondaryStorage', $this) and $this->{'SecondaryStorage'} ) )
|
||||||
|
$this->{'SecondaryStorage'} = new Storage(NULL);
|
||||||
|
}
|
||||||
|
return $this->{'SecondaryStorage'};
|
||||||
|
}
|
||||||
|
|
||||||
public function Monitor() {
|
public function Monitor() {
|
||||||
if ( isset($this->{'MonitorId'}) ) {
|
if ( isset($this->{'MonitorId'}) ) {
|
||||||
$Monitor = Monitor::find_one(array('Id'=>$this->{'MonitorId'}));
|
$Monitor = Monitor::find_one(array('Id'=>$this->{'MonitorId'}));
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
namespace ZM;
|
namespace ZM;
|
||||||
|
require_once('Object.php');
|
||||||
|
|
||||||
class Filter {
|
class Filter extends ZM_Object {
|
||||||
|
protected static $table = 'Filters';
|
||||||
|
|
||||||
public $defaults = array(
|
protected $defaults = array(
|
||||||
'Id' => null,
|
'Id' => null,
|
||||||
'Name' => '',
|
'Name' => '',
|
||||||
'AutoExecute' => 0,
|
'AutoExecute' => 0,
|
||||||
|
@ -16,68 +18,55 @@ public $defaults = array(
|
||||||
'AutoMessage' => 0,
|
'AutoMessage' => 0,
|
||||||
'AutoMove' => 0,
|
'AutoMove' => 0,
|
||||||
'AutoMoveTo' => 0,
|
'AutoMoveTo' => 0,
|
||||||
|
'AutoCopy' => 0,
|
||||||
|
'AutoCopyTo' => 0,
|
||||||
'UpdateDiskSpace' => 0,
|
'UpdateDiskSpace' => 0,
|
||||||
'Background' => 0,
|
'Background' => 0,
|
||||||
'Concurrent' => 0,
|
'Concurrent' => 0,
|
||||||
'limit' => 100,
|
'Query_json' => '',
|
||||||
'Query' => array(),
|
);
|
||||||
'sort_field' => ZM_WEB_EVENT_SORT_FIELD,
|
|
||||||
'sort_asc' => ZM_WEB_EVENT_SORT_ORDER,
|
|
||||||
);
|
|
||||||
|
|
||||||
public function __construct( $IdOrRow=NULL ) {
|
public function Query_json() {
|
||||||
$row = NULL;
|
if ( func_num_args( ) ) {
|
||||||
if ( $IdOrRow ) {
|
$this->{'Query_json'} = func_get_arg(0);;
|
||||||
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
|
$this->{'Query'} = jsonDecode($this->{'Query_json'});
|
||||||
$row = dbFetchOne('SELECT * FROM Filters WHERE Id=?', NULL, array($IdOrRow));
|
}
|
||||||
if ( ! $row ) {
|
return $this->{'Query_json'};
|
||||||
Error('Unable to load Filter record for Id=' . $IdOrRow);
|
}
|
||||||
}
|
|
||||||
} elseif ( is_array($IdOrRow) ) {
|
|
||||||
$row = $IdOrRow;
|
|
||||||
} else {
|
|
||||||
$backTrace = debug_backtrace();
|
|
||||||
$file = $backTrace[1]['file'];
|
|
||||||
$line = $backTrace[1]['line'];
|
|
||||||
Error("Unknown argument passed to Filter Constructor from $file:$line)");
|
|
||||||
Error("Unknown argument passed to Filter Constructor ($IdOrRow)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} # end if isset($IdOrRow)
|
|
||||||
|
|
||||||
if ( $row ) {
|
public function Query() {
|
||||||
foreach ($row as $k => $v) {
|
if ( func_num_args( ) ) {
|
||||||
$this->{$k} = $v;
|
$this->{'Query'} = func_get_arg(0);;
|
||||||
}
|
$this->{'Query_json'} = jsonEncode($this->{'Query'});
|
||||||
if ( array_key_exists('Query', $this) and $this->{'Query'} ) {
|
}
|
||||||
$this->{'Query'} = jsonDecode($this->{'Query'});
|
if ( !array_key_exists('Query', $this) ) {
|
||||||
|
if ( array_key_exists('Query_json', $this) and $this->{'Query_json'} ) {
|
||||||
|
$this->{'Query'} = jsonDecode($this->{'Query_json'});
|
||||||
} else {
|
} else {
|
||||||
$this->{'Query'} = array();
|
$this->{'Query'} = array();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // end function __construct
|
|
||||||
|
|
||||||
public function __call( $fn, array $args ) {
|
|
||||||
if ( count( $args ) ) {
|
|
||||||
$this->{$fn} = $args[0];
|
|
||||||
}
|
|
||||||
if ( array_key_exists( $fn, $this ) ) {
|
|
||||||
return $this->{$fn};
|
|
||||||
} else if ( array_key_exists( $fn, $this->defaults ) ) {
|
|
||||||
$this->{$fn} = $this->defaults{$fn};
|
|
||||||
return $this->{$fn};
|
|
||||||
} else {
|
} else {
|
||||||
|
if ( !is_array($this->{'Query'}) ) {
|
||||||
$backTrace = debug_backtrace();
|
# Handle existence of both Query_json and Query in the row
|
||||||
$file = $backTrace[1]['file'];
|
$this->{'Query'} = jsonDecode($this->{'Query_json'});
|
||||||
$line = $backTrace[1]['line'];
|
}
|
||||||
Warning( "Unknown function call Filter->$fn from $file:$line" );
|
|
||||||
}
|
}
|
||||||
|
return $this->{'Query'};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function find( $parameters = array(), $options = array() ) {
|
||||||
|
return ZM_Object::_find(get_class(), $parameters, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function find_one( $parameters = array(), $options = array() ) {
|
||||||
|
return ZM_Object::_find_one(get_class(), $parameters, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function terms( ) {
|
public function terms( ) {
|
||||||
if ( func_num_args( ) ) {
|
if ( func_num_args() ) {
|
||||||
$this->Query()['terms'] = func_get_arg(0);
|
$Query = $this->Query();
|
||||||
|
$Query['terms'] = func_get_arg(0);
|
||||||
|
$this->Query($Query);
|
||||||
}
|
}
|
||||||
if ( isset( $this->Query()['terms'] ) ) {
|
if ( isset( $this->Query()['terms'] ) ) {
|
||||||
return $this->Query()['terms'];
|
return $this->Query()['terms'];
|
||||||
|
@ -88,108 +77,44 @@ public $defaults = array(
|
||||||
// The following three fields are actually stored in the Query
|
// The following three fields are actually stored in the Query
|
||||||
public function sort_field( ) {
|
public function sort_field( ) {
|
||||||
if ( func_num_args( ) ) {
|
if ( func_num_args( ) ) {
|
||||||
$this->Query()['sort_field'] = func_get_arg(0);
|
$Query = $this->Query();
|
||||||
|
$Query['sort_field'] = func_get_arg(0);
|
||||||
|
$this->Query($Query);
|
||||||
}
|
}
|
||||||
if ( isset( $this->Query()['sort_field'] ) ) {
|
if ( isset( $this->Query()['sort_field'] ) ) {
|
||||||
return $this->{'Query'}['sort_field'];
|
return $this->{'Query'}['sort_field'];
|
||||||
}
|
}
|
||||||
return $this->defaults{'sort_field'};
|
return ZM_WEB_EVENT_SORT_FIELD;
|
||||||
|
#return $this->defaults{'sort_field'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sort_asc( ) {
|
public function sort_asc( ) {
|
||||||
if ( func_num_args( ) ) {
|
if ( func_num_args( ) ) {
|
||||||
$this->{'Query'}['sort_asc'] = func_get_arg(0);
|
$Query = $this->Query();
|
||||||
|
$Query['sort_asc'] = func_get_arg(0);
|
||||||
|
$this->Query($Query);
|
||||||
}
|
}
|
||||||
if ( isset( $this->Query()['sort_asc'] ) ) {
|
if ( isset( $this->Query()['sort_asc'] ) ) {
|
||||||
return $this->{'Query'}['sort_asc'];
|
return $this->{'Query'}['sort_asc'];
|
||||||
}
|
}
|
||||||
return $this->defaults{'sort_asc'};
|
return ZM_WEB_EVENT_SORT_ORDER;
|
||||||
|
#return $this->defaults{'sort_asc'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function limit( ) {
|
public function limit( ) {
|
||||||
if ( func_num_args( ) ) {
|
if ( func_num_args( ) ) {
|
||||||
$this->{'Query'}['limit'] = func_get_arg(0);
|
$Query = $this->Query();
|
||||||
|
$Query['limit'] = func_get_arg(0);
|
||||||
|
$this->Query($Query);
|
||||||
}
|
}
|
||||||
if ( isset( $this->Query()['limit'] ) )
|
if ( isset( $this->Query()['limit'] ) )
|
||||||
return $this->{'Query'}['limit'];
|
return $this->{'Query'}['limit'];
|
||||||
return $this->defaults{'limit'};
|
return 100;
|
||||||
|
#return $this->defaults{'limit'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function find( $parameters = null, $options = null ) {
|
|
||||||
$filters = array();
|
|
||||||
$sql = 'SELECT * FROM Filters ';
|
|
||||||
$values = array();
|
|
||||||
|
|
||||||
if ( $parameters ) {
|
|
||||||
$fields = array();
|
|
||||||
$sql .= 'WHERE ';
|
|
||||||
foreach ( $parameters as $field => $value ) {
|
|
||||||
if ( $value == null ) {
|
|
||||||
$fields[] = $field.' IS NULL';
|
|
||||||
} else if ( is_array( $value ) ) {
|
|
||||||
$func = function(){return '?';};
|
|
||||||
$fields[] = $field.' IN ('.implode(',', array_map($func, $value)). ')';
|
|
||||||
$values += $value;
|
|
||||||
} else {
|
|
||||||
$fields[] = $field.'=?';
|
|
||||||
$values[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sql .= implode(' AND ', $fields);
|
|
||||||
}
|
|
||||||
if ( $options ) {
|
|
||||||
if ( isset($options['order']) ) {
|
|
||||||
$sql .= ' ORDER BY ' . $options['order'];
|
|
||||||
}
|
|
||||||
if ( isset($options['limit']) ) {
|
|
||||||
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
|
|
||||||
$sql .= ' LIMIT ' . $options['limit'];
|
|
||||||
} else {
|
|
||||||
$backTrace = debug_backtrace();
|
|
||||||
$file = $backTrace[1]['file'];
|
|
||||||
$line = $backTrace[1]['line'];
|
|
||||||
Error("Invalid value for limit(".$options['limit'].") passed to Filter::find from $file:$line");
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$result = dbQuery($sql, $values);
|
|
||||||
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Filter');
|
|
||||||
foreach ( $results as $row => $obj ) {
|
|
||||||
$filters[] = $obj;
|
|
||||||
}
|
|
||||||
return $filters;
|
|
||||||
} # end find()
|
|
||||||
|
|
||||||
public static function find_one( $parameters = array() ) {
|
|
||||||
$results = Filter::find($parameters, array('limit'=>1));
|
|
||||||
if ( ! sizeof($results) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return $results[0];
|
|
||||||
} # end find_one()
|
|
||||||
|
|
||||||
public function delete() {
|
|
||||||
dbQuery('DELETE FROM Filters WHERE Id=?', array($this->{'Id'}));
|
|
||||||
} # end function delete()
|
|
||||||
|
|
||||||
public function set( $data ) {
|
|
||||||
foreach ($data as $k => $v) {
|
|
||||||
if ( is_array( $v ) ) {
|
|
||||||
$this->{$k} = $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 function set
|
|
||||||
|
|
||||||
public function control($command, $server_id=null) {
|
public function control($command, $server_id=null) {
|
||||||
$Servers = $server_id ? Server::find(array('Id'=>$server_id)) : Server::find();
|
$Servers = $server_id ? Server::find(array('Id'=>$server_id)) : Server::find(array('Status'=>'Running'));
|
||||||
if ( !count($Servers) and !$server_id ) {
|
if ( !count($Servers) and !$server_id ) {
|
||||||
# This will be the non-multi-server case
|
# This will be the non-multi-server case
|
||||||
$Servers = array(new Server());
|
$Servers = array(new Server());
|
||||||
|
@ -199,7 +124,7 @@ public $defaults = array(
|
||||||
if ( !defined('ZM_SERVER_ID') or !$Server->Id() or ZM_SERVER_ID==$Server->Id() ) {
|
if ( !defined('ZM_SERVER_ID') or !$Server->Id() or ZM_SERVER_ID==$Server->Id() ) {
|
||||||
# Local
|
# Local
|
||||||
Logger::Debug("Controlling filter locally $command for server ".$Server->Id());
|
Logger::Debug("Controlling filter locally $command for server ".$Server->Id());
|
||||||
daemonControl($command, 'zmfilter.pl', '--filter_id='.$this->{'Id'});
|
daemonControl($command, 'zmfilter.pl', '--filter_id='.$this->{'Id'}.' --daemon');
|
||||||
} else {
|
} else {
|
||||||
# Remote case
|
# Remote case
|
||||||
|
|
||||||
|
|
|
@ -1,127 +1,21 @@
|
||||||
<?php
|
<?php
|
||||||
namespace ZM;
|
namespace ZM;
|
||||||
|
|
||||||
$group_cache = array();
|
class Group extends ZM_Object {
|
||||||
|
protected static $table = 'Groups';
|
||||||
class Group {
|
protected $defaults = array(
|
||||||
|
|
||||||
public $defaults = array(
|
|
||||||
'Id' => null,
|
'Id' => null,
|
||||||
'Name' => '',
|
'Name' => '',
|
||||||
'ParentId' => null,
|
'ParentId' => null,
|
||||||
);
|
);
|
||||||
|
|
||||||
public function __construct( $IdOrRow=NULL ) {
|
public static function find( $parameters = array(), $options = array() ) {
|
||||||
global $group_cache;
|
return ZM_Object::_find(get_class(), $parameters, $options);
|
||||||
|
|
||||||
$row = NULL;
|
|
||||||
if ( $IdOrRow ) {
|
|
||||||
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
|
|
||||||
$row = dbFetchOne('SELECT * FROM Groups WHERE Id=?', NULL, array($IdOrRow));
|
|
||||||
if ( ! $row ) {
|
|
||||||
Error('Unable to load Group record for Id=' . $IdOrRow);
|
|
||||||
}
|
|
||||||
} elseif ( is_array($IdOrRow) ) {
|
|
||||||
$row = $IdOrRow;
|
|
||||||
} else {
|
|
||||||
$backTrace = debug_backtrace();
|
|
||||||
$file = $backTrace[1]['file'];
|
|
||||||
$line = $backTrace[1]['line'];
|
|
||||||
Error("Unknown argument passed to Group Constructor from $file:$line)");
|
|
||||||
Error("Unknown argument passed to Group Constructor ($IdOrRow)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} # end if isset($IdOrRow)
|
|
||||||
|
|
||||||
if ( $row ) {
|
|
||||||
foreach ($row as $k => $v) {
|
|
||||||
$this->{$k} = $v;
|
|
||||||
}
|
|
||||||
$group_cache[$row['Id']] = $this;
|
|
||||||
}
|
|
||||||
} // end function __construct
|
|
||||||
|
|
||||||
public function __call($fn, array $args) {
|
|
||||||
if ( count($args) ) {
|
|
||||||
$this->{$fn} = $args[0];
|
|
||||||
}
|
|
||||||
if ( array_key_exists($fn, $this) ) {
|
|
||||||
return $this->{$fn};
|
|
||||||
} else if ( array_key_exists( $fn, $this->defaults ) ) {
|
|
||||||
$this->{$fn} = $this->defaults{$fn};
|
|
||||||
return $this->{$fn};
|
|
||||||
} else {
|
|
||||||
|
|
||||||
$backTrace = debug_backtrace();
|
|
||||||
$file = $backTrace[1]['file'];
|
|
||||||
$line = $backTrace[1]['line'];
|
|
||||||
Warning( "Unknown function call Group->$fn from $file:$line" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function find( $parameters = null, $options = null ) {
|
public static function find_one( $parameters = array(), $options = array() ) {
|
||||||
$sql = 'SELECT * FROM Groups ';
|
return ZM_Object::_find_one(get_class(), $parameters, $options);
|
||||||
$values = array();
|
}
|
||||||
|
|
||||||
if ( $parameters ) {
|
|
||||||
$fields = array();
|
|
||||||
$sql .= 'WHERE ';
|
|
||||||
foreach ( $parameters as $field => $value ) {
|
|
||||||
if ( $value == null ) {
|
|
||||||
$fields[] = $field.' IS NULL';
|
|
||||||
} else if ( is_array( $value ) ) {
|
|
||||||
$func = function(){return '?';};
|
|
||||||
$fields[] = $field.' IN ('.implode(',', array_map($func, $value)). ')';
|
|
||||||
$values += $value;
|
|
||||||
} else {
|
|
||||||
$fields[] = $field.'=?';
|
|
||||||
$values[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sql .= implode(' AND ', $fields);
|
|
||||||
} # end if parameters
|
|
||||||
if ( $options ) {
|
|
||||||
if ( isset($options['order']) ) {
|
|
||||||
$sql .= ' ORDER BY ' . $options['order'];
|
|
||||||
}
|
|
||||||
if ( isset($options['limit']) ) {
|
|
||||||
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
|
|
||||||
$sql .= ' LIMIT ' . $options['limit'];
|
|
||||||
} else {
|
|
||||||
$backTrace = debug_backtrace();
|
|
||||||
$file = $backTrace[1]['file'];
|
|
||||||
$line = $backTrace[1]['line'];
|
|
||||||
Error("Invalid value for limit(".$options['limit'].") passed to Group::find from $file:$line");
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} # end if options
|
|
||||||
|
|
||||||
$results = dbFetchAll($sql, NULL, $values);
|
|
||||||
if ( $results ) {
|
|
||||||
return array_map( function($row){ return new Group($row); }, $results );
|
|
||||||
}
|
|
||||||
return array();
|
|
||||||
} # end find()
|
|
||||||
|
|
||||||
public static function find_one($parameters = null, $options = null) {
|
|
||||||
global $group_cache;
|
|
||||||
if (
|
|
||||||
( count($parameters) == 1 ) and
|
|
||||||
isset($parameters['Id']) and
|
|
||||||
isset($group_cache[$parameters['Id']]) ) {
|
|
||||||
return $group_cache[$parameters['Id']];
|
|
||||||
}
|
|
||||||
$results = Group::find($parameters, $options);
|
|
||||||
if ( count($results) > 1 ) {
|
|
||||||
Error("Group::find_one Returned more than 1");
|
|
||||||
return $results[0];
|
|
||||||
} else if ( count($results) ) {
|
|
||||||
return $results[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} # end function find_one
|
|
||||||
|
|
||||||
public function delete() {
|
public function delete() {
|
||||||
if ( array_key_exists('Id', $this) ) {
|
if ( array_key_exists('Id', $this) ) {
|
||||||
|
@ -137,23 +31,6 @@ class Group {
|
||||||
}
|
}
|
||||||
} # end function delete()
|
} # end function delete()
|
||||||
|
|
||||||
public function set( $data ) {
|
|
||||||
foreach ($data as $k => $v) {
|
|
||||||
if ( is_array($v) ) {
|
|
||||||
$this->{$k} = $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 function set
|
|
||||||
|
|
||||||
public function depth( $new = null ) {
|
public function depth( $new = null ) {
|
||||||
if ( isset($new) ) {
|
if ( isset($new) ) {
|
||||||
$this->{'depth'} = $new;
|
$this->{'depth'} = $new;
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
<?php
|
||||||
|
namespace ZM;
|
||||||
|
require_once('database.php');
|
||||||
|
|
||||||
|
$object_cache = array();
|
||||||
|
|
||||||
|
class ZM_Object {
|
||||||
|
|
||||||
|
public function __construct($IdOrRow = NULL) {
|
||||||
|
$class = get_class($this);
|
||||||
|
global $object_cache;
|
||||||
|
if ( ! isset($object_cache[$class]) )
|
||||||
|
$object_cache[$class] = array();
|
||||||
|
$cache = $object_cache[$class];
|
||||||
|
|
||||||
|
$table = $class::$table;
|
||||||
|
|
||||||
|
$row = NULL;
|
||||||
|
if ( $IdOrRow ) {
|
||||||
|
if ( is_integer($IdOrRow) or ctype_digit($IdOrRow) ) {
|
||||||
|
$row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($IdOrRow));
|
||||||
|
if ( !$row ) {
|
||||||
|
Error("Unable to load $class record for Id=$IdOrRow");
|
||||||
|
}
|
||||||
|
} elseif ( is_array($IdOrRow) ) {
|
||||||
|
$row = $IdOrRow;
|
||||||
|
}
|
||||||
|
} # end if isset($IdOrRow)
|
||||||
|
if ( $row ) {
|
||||||
|
foreach ($row as $k => $v) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
}
|
||||||
|
$cache[$row['Id']] = $this;
|
||||||
|
} else {
|
||||||
|
# Set defaults
|
||||||
|
foreach ( $this->defaults as $k => $v ) $this->{$k} = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call($fn, array $args){
|
||||||
|
if ( count($args) ) {
|
||||||
|
$this->{$fn} = $args[0];
|
||||||
|
}
|
||||||
|
if ( array_key_exists($fn, $this) ) {
|
||||||
|
return $this->{$fn};
|
||||||
|
} else {
|
||||||
|
if ( array_key_exists($fn, $this->defaults) ) {
|
||||||
|
return $this->defaults{$fn};
|
||||||
|
} else {
|
||||||
|
$backTrace = debug_backtrace();
|
||||||
|
Warning("Unknown function call Sensor->$fn from ".print_r($backTrace,true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function _find($class, $parameters = null, $options = null ) {
|
||||||
|
$table = $class::$table;
|
||||||
|
$filters = array();
|
||||||
|
$sql = "SELECT * FROM `$table` ";
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
if ( $parameters ) {
|
||||||
|
$fields = array();
|
||||||
|
$sql .= 'WHERE ';
|
||||||
|
foreach ( $parameters as $field => $value ) {
|
||||||
|
if ( $value == null ) {
|
||||||
|
$fields[] = '`'.$field.'` IS NULL';
|
||||||
|
} else if ( is_array($value) ) {
|
||||||
|
$func = function(){return '?';};
|
||||||
|
$fields[] = '`'.$field.'` IN ('.implode(',', array_map($func, $value)). ')';
|
||||||
|
$values += $value;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$fields[] = '`'.$field.'`=?';
|
||||||
|
$values[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sql .= implode(' AND ', $fields );
|
||||||
|
}
|
||||||
|
if ( $options ) {
|
||||||
|
if ( isset($options['order']) ) {
|
||||||
|
$sql .= ' ORDER BY ' . $options['order'];
|
||||||
|
}
|
||||||
|
if ( isset($options['limit']) ) {
|
||||||
|
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
|
||||||
|
$sql .= ' LIMIT ' . $options['limit'];
|
||||||
|
} else {
|
||||||
|
Error('Invalid value for limit('.$options['limit'].') passed to '.get_class()."::find from ".print_r($backTrace,true));
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rows = dbFetchAll($sql, NULL, $values);
|
||||||
|
$results = array();
|
||||||
|
if ( $rows ) {
|
||||||
|
foreach ( $rows as $row ) {
|
||||||
|
array_push($results , new $class($row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $results;
|
||||||
|
} # end public function find()
|
||||||
|
|
||||||
|
public static function _find_one($class, $parameters = array(), $options = array() ) {
|
||||||
|
global $object_cache;
|
||||||
|
if ( ! isset($object_cache[$class]) )
|
||||||
|
$object_cache[$class] = array();
|
||||||
|
$cache = $object_cache[$class];
|
||||||
|
if (
|
||||||
|
( count($parameters) == 1 ) and
|
||||||
|
isset($parameters['Id']) and
|
||||||
|
isset($cache[$parameters['Id']]) ) {
|
||||||
|
return $cache[$parameters['Id']];
|
||||||
|
}
|
||||||
|
$options['limit'] = 1;
|
||||||
|
$results = ZM_Object::_find($class, $parameters, $options);
|
||||||
|
if ( ! sizeof($results) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return $results[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function Objects_Indexed_By_Id($class) {
|
||||||
|
$results = array();
|
||||||
|
foreach ( ZM_Object::_find($class, null, array('order'=>'lower(Name)')) as $Object ) {
|
||||||
|
$results[$Object->Id()] = $Object;
|
||||||
|
}
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function to_json() {
|
||||||
|
$json = array();
|
||||||
|
foreach ($this->defaults as $key => $value) {
|
||||||
|
if ( is_callable(array($this, $key)) ) {
|
||||||
|
$json[$key] = $this->$key();
|
||||||
|
} else if ( array_key_exists($key, $this) ) {
|
||||||
|
$json[$key] = $this->{$key};
|
||||||
|
} else {
|
||||||
|
$json[$key] = $this->defaults{$key};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json_encode($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set($data) {
|
||||||
|
foreach ( $data as $k => $v ) {
|
||||||
|
if ( method_exists($this, $k) ) {
|
||||||
|
$this->{$k}($v);
|
||||||
|
} else {
|
||||||
|
if ( is_array($v) ) {
|
||||||
|
# perhaps should turn into a comma-separated string
|
||||||
|
$this->{$k} = implode(',', $v);
|
||||||
|
} else if ( is_string($v) ) {
|
||||||
|
if ( $v == '' and array_key_exists($k, $this->defaults) ) {
|
||||||
|
$this->{$k} = $this->defaults[$k];
|
||||||
|
} else {
|
||||||
|
$this->{$k} = trim($v);
|
||||||
|
}
|
||||||
|
} else if ( is_integer($v) ) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
} else if ( is_bool($v) ) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
} else if ( is_null($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 function changes( $new_values ) {
|
||||||
|
$changes = array();
|
||||||
|
foreach ( $new_values as $field => $value ) {
|
||||||
|
|
||||||
|
if ( method_exists($this, $field) ) {
|
||||||
|
$old_value = $this->$field();
|
||||||
|
Logger::Debug("Checking method $field () ".print_r($old_value,true)." => " . print_r($value,true));
|
||||||
|
if ( is_array($old_value) ) {
|
||||||
|
$diff = array_recursive_diff($old_value, $value);
|
||||||
|
Logger::Debug("Checking method $field () diff is".print_r($diff,true));
|
||||||
|
if ( count($diff) ) {
|
||||||
|
$changes[$field] = $value;
|
||||||
|
}
|
||||||
|
} else if ( $this->$field() != $value ) {
|
||||||
|
$changes[$field] = $value;
|
||||||
|
}
|
||||||
|
} else if ( array_key_exists($field, $this) ) {
|
||||||
|
Logger::Debug("Checking field $field => ".$this->{$field} . " ?= " .$value);
|
||||||
|
if ( $this->{$field} != $value ) {
|
||||||
|
$changes[$field] = $value;
|
||||||
|
}
|
||||||
|
} else if ( array_key_exists($field, $this->defaults) ) {
|
||||||
|
|
||||||
|
Logger::Debug("Checking default $field => ".$this->defaults[$field] . " " .$value);
|
||||||
|
if ( $this->defaults[$field] != $value ) {
|
||||||
|
$changes[$field] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ( (!array_key_exists($field, $this)) or ( $this->{$field} != $new_values[$field] ) ) {
|
||||||
|
#Logger::Debug("Checking default $field => $default_value changes becaause" . $new_values[$field].' != '.$new_values[$field]);
|
||||||
|
#$changes[$field] = $new_values[$field];
|
||||||
|
##} else if {
|
||||||
|
#Logger::Debug("Checking default $field => $default_value changes becaause " . $new_values[$field].' != '.$new_values[$field]);
|
||||||
|
##array_push( $changes, [$field=>$defaults[$field]] );
|
||||||
|
#}
|
||||||
|
#} else {
|
||||||
|
#Logger::Debug("Checking default $field => $default_value not in new_values");
|
||||||
|
#}
|
||||||
|
} # end foreach default
|
||||||
|
return $changes;
|
||||||
|
} # end public function changes
|
||||||
|
|
||||||
|
public function save($new_values = null) {
|
||||||
|
$class = get_class($this);
|
||||||
|
$table = $class::$table;
|
||||||
|
|
||||||
|
if ( $new_values ) {
|
||||||
|
Logger::Debug("New values" . print_r($new_values,true));
|
||||||
|
$this->set($new_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this->Id() ) {
|
||||||
|
$fields = array_keys($this->defaults);
|
||||||
|
$sql = 'UPDATE '.$table.' SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields )) . ' WHERE Id=?';
|
||||||
|
$values = array_map(function($field){return $this->{$field};}, $fields);
|
||||||
|
$values[] = $this->{'Id'};
|
||||||
|
if ( dbQuery($sql, $values) )
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$fields = $this->defaults;
|
||||||
|
unset($fields['Id']);
|
||||||
|
|
||||||
|
$sql = 'INSERT INTO '.$table.' ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, array_keys($fields))).') VALUES ('.implode(', ', array_map(function($field){return '?';}, array_values($fields))).')';
|
||||||
|
$values = array_map(function($field){return $this->{$field};}, array_keys($fields));
|
||||||
|
if ( dbQuery($sql, $values) ) {
|
||||||
|
$this->{'Id'} = dbInsertId();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // end function save
|
||||||
|
|
||||||
|
public function delete() {
|
||||||
|
$class = get_class($this);
|
||||||
|
$table = $class::$table;
|
||||||
|
dbQuery("DELETE FROM $table WHERE Id=?", array($this->{'Id'}));
|
||||||
|
if ( isset($object_cache[$class]) and isset($object_cache[$class][$this->{'Id'}]) )
|
||||||
|
unset($object_cache[$class][$this->{'Id'}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} # end class Sensor Action
|
||||||
|
?>
|
|
@ -2,10 +2,11 @@
|
||||||
namespace ZM;
|
namespace ZM;
|
||||||
require_once('database.php');
|
require_once('database.php');
|
||||||
require_once('Event.php');
|
require_once('Event.php');
|
||||||
|
require_once('Object.php');
|
||||||
|
|
||||||
$storage_cache = array();
|
class Storage extends ZM_Object {
|
||||||
class Storage {
|
protected static $table = 'Storage';
|
||||||
private $defaults = array(
|
protected $defaults = array(
|
||||||
'Id' => null,
|
'Id' => null,
|
||||||
'Path' => '',
|
'Path' => '',
|
||||||
'Name' => '',
|
'Name' => '',
|
||||||
|
@ -16,31 +17,12 @@ class Storage {
|
||||||
'ServerId' => 0,
|
'ServerId' => 0,
|
||||||
'DoDelete' => 1,
|
'DoDelete' => 1,
|
||||||
);
|
);
|
||||||
|
public static function find($parameters = array(), $options = array() ) {
|
||||||
|
return ZM_Object::_find(get_class(), $parameters, $options);
|
||||||
|
}
|
||||||
|
|
||||||
public function __construct( $IdOrRow = NULL ) {
|
public static function find_one( $parameters = array(), $options = array() ) {
|
||||||
global $storage_cache;
|
return ZM_Object::_find_one(get_class(), $parameters, $options);
|
||||||
|
|
||||||
$row = NULL;
|
|
||||||
if ( $IdOrRow ) {
|
|
||||||
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
|
|
||||||
$row = dbFetchOne('SELECT * FROM Storage WHERE Id=?', NULL, array($IdOrRow));
|
|
||||||
if ( ! $row ) {
|
|
||||||
Error('Unable to load Storage record for Id=' . $IdOrRow);
|
|
||||||
}
|
|
||||||
} else if ( is_array($IdOrRow) ) {
|
|
||||||
$row = $IdOrRow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( $row ) {
|
|
||||||
foreach ($row as $k => $v) {
|
|
||||||
$this->{$k} = $v;
|
|
||||||
}
|
|
||||||
$storage_cache[$row['Id']] = $this;
|
|
||||||
} else {
|
|
||||||
$this->{'Name'} = '';
|
|
||||||
$this->{'Path'} = '';
|
|
||||||
$this->{'Type'} = 'local';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Path() {
|
public function Path() {
|
||||||
|
@ -66,93 +48,6 @@ class Storage {
|
||||||
return $this->{'Name'};
|
return $this->{'Name'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __call( $fn, array $args= NULL ) {
|
|
||||||
if ( count($args) ) {
|
|
||||||
$this->{$fn} = $args[0];
|
|
||||||
}
|
|
||||||
if ( array_key_exists($fn, $this) )
|
|
||||||
return $this->{$fn};
|
|
||||||
|
|
||||||
if ( array_key_exists($fn, $this->defaults) )
|
|
||||||
return $this->defaults{$fn};
|
|
||||||
|
|
||||||
$backTrace = debug_backtrace();
|
|
||||||
$file = $backTrace[0]['file'];
|
|
||||||
$line = $backTrace[0]['line'];
|
|
||||||
Warning("Unknown function call Storage->$fn from $file:$line");
|
|
||||||
$file = $backTrace[1]['file'];
|
|
||||||
$line = $backTrace[1]['line'];
|
|
||||||
Warning("Unknown function call Storage->$fn from $file:$line");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function find_one( $parameters = null, $options = null ) {
|
|
||||||
global $storage_cache;
|
|
||||||
if (
|
|
||||||
( count($parameters) == 1 ) and
|
|
||||||
isset($parameters['Id']) and
|
|
||||||
isset($storage_cache[$parameters['Id']]) ) {
|
|
||||||
return $storage_cache[$parameters['Id']];
|
|
||||||
}
|
|
||||||
|
|
||||||
$results = Storage::find($parameters, $options);
|
|
||||||
if ( count($results) > 1 ) {
|
|
||||||
Error('Storage Returned more than 1');
|
|
||||||
return $results[0];
|
|
||||||
} else if ( count($results) ) {
|
|
||||||
return $results[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static function find( $parameters = null, $options = null ) {
|
|
||||||
$sql = 'SELECT * FROM Storage ';
|
|
||||||
$values = array();
|
|
||||||
|
|
||||||
if ( $parameters ) {
|
|
||||||
$fields = array();
|
|
||||||
$sql .= 'WHERE ';
|
|
||||||
foreach ( $parameters as $field => $value ) {
|
|
||||||
if ( $value == null ) {
|
|
||||||
$fields[] = $field.' IS NULL';
|
|
||||||
} else if ( is_array($value) ) {
|
|
||||||
$func = function(){return '?';};
|
|
||||||
$fields[] = $field.' IN ('.implode(',', array_map($func, $value)).')';
|
|
||||||
$values += $value;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$fields[] = $field.'=?';
|
|
||||||
$values[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sql .= implode(' AND ', $fields);
|
|
||||||
} # end if parameters
|
|
||||||
if ( $options ) {
|
|
||||||
if ( isset($options['order']) ) {
|
|
||||||
$sql .= ' ORDER BY ' . $options['order'];
|
|
||||||
} # end if options
|
|
||||||
if ( isset($options['limit']) ) {
|
|
||||||
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
|
|
||||||
$sql .= ' LIMIT ' . $option['limit'];
|
|
||||||
} else {
|
|
||||||
$backTrace = debug_backtrace();
|
|
||||||
$file = $backTrace[1]['file'];
|
|
||||||
$line = $backTrace[1]['line'];
|
|
||||||
Error("Invalid value for limit(".$options['limit'].") passed to Control::find from $file:$line");
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
} # end if limit
|
|
||||||
} # end if options
|
|
||||||
$storage_areas = array();
|
|
||||||
$result = dbQuery($sql, $values);
|
|
||||||
if ( $result ) {
|
|
||||||
$results = $result->fetchALL();
|
|
||||||
foreach ( $results as $row ) {
|
|
||||||
$storage_areas[] = new Storage($row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $storage_areas;
|
|
||||||
} # end find()
|
|
||||||
|
|
||||||
public function disk_usage_percent() {
|
public function disk_usage_percent() {
|
||||||
$path = $this->Path();
|
$path = $this->Path();
|
||||||
if ( ! $path ) {
|
if ( ! $path ) {
|
||||||
|
@ -226,18 +121,5 @@ class Storage {
|
||||||
return $this->{'Server'};
|
return $this->{'Server'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function to_json() {
|
|
||||||
$json = array();
|
|
||||||
foreach ($this->defaults as $key => $value) {
|
|
||||||
if ( is_callable(array($this, $key)) ) {
|
|
||||||
$json[$key] = $this->$key();
|
|
||||||
} else if ( array_key_exists($key, $this) ) {
|
|
||||||
$json[$key] = $this->{$key};
|
|
||||||
} else {
|
|
||||||
$json[$key] = $this->defaults{$key};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return json_encode($json);
|
|
||||||
}
|
|
||||||
} // end class Storage
|
} // end class Storage
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -42,7 +42,7 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
|
||||||
$filter->delete();
|
$filter->delete();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ZM\Error("No filter id passed when deleting");
|
ZM\Error('No filter id passed when deleting');
|
||||||
}
|
}
|
||||||
} else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) {
|
} else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) {
|
||||||
|
|
||||||
|
@ -51,11 +51,30 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
|
||||||
$_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
|
$_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
|
||||||
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
|
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
|
||||||
if ( $action == 'execute' ) {
|
if ( $action == 'execute' ) {
|
||||||
$tempFilterName = '_TempFilter'.time();
|
$_REQUEST['filter']['Name'] = '_TempFilter'.time();
|
||||||
$sql .= ' Name = \''.$tempFilterName.'\'';
|
unset($_REQUEST['Id']);
|
||||||
} else {
|
#$tempFilterName = '_TempFilter'.time();
|
||||||
$sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
|
#$sql .= ' Name = \''.$tempFilterName.'\'';
|
||||||
|
#} else {
|
||||||
|
#$sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$_REQUEST['filter']['AutoCopy'] = empty($_REQUEST['filter']['AutoCopy']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoMove'] = empty($_REQUEST['filter']['AutoMove']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoArchive'] = empty($_REQUEST['filter']['AutoArchive']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoVideo'] = empty($_REQUEST['filter']['AutoVideo']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoUpload'] = empty($_REQUEST['filter']['AutoUpload']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoEmail'] = empty($_REQUEST['filter']['AutoEmail']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoMessage'] = empty($_REQUEST['filter']['AutoMessage']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoExecute'] = empty($_REQUEST['filter']['AutoExecute']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['AutoDelete'] = empty($_REQUEST['filter']['AutoDelete']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['UpdateDiskSpace'] = empty($_REQUEST['filter']['UpdateDiskSpace']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['Background'] = empty($_REQUEST['filter']['Background']) ? 0 : 1;
|
||||||
|
$_REQUEST['filter']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1;
|
||||||
|
$changes = $filter->changes($_REQUEST['filter']);
|
||||||
|
ZM\Logger::Debug("Changes: " . print_r($changes,true));
|
||||||
|
|
||||||
|
if ( 0 ) {
|
||||||
$sql .= ', Query = '.dbEscape(jsonEncode($_REQUEST['filter']['Query']));
|
$sql .= ', Query = '.dbEscape(jsonEncode($_REQUEST['filter']['Query']));
|
||||||
$sql .= ', AutoArchive = '.(!empty($_REQUEST['filter']['AutoArchive']) ? 1 : 0);
|
$sql .= ', AutoArchive = '.(!empty($_REQUEST['filter']['AutoArchive']) ? 1 : 0);
|
||||||
$sql .= ', AutoVideo = '. ( !empty($_REQUEST['filter']['AutoVideo']) ? 1 : 0);
|
$sql .= ', AutoVideo = '. ( !empty($_REQUEST['filter']['AutoVideo']) ? 1 : 0);
|
||||||
|
@ -73,17 +92,25 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
|
||||||
$sql .= ', UpdateDiskSpace = '. ( !empty($_REQUEST['filter']['UpdateDiskSpace']) ? 1 : 0);
|
$sql .= ', UpdateDiskSpace = '. ( !empty($_REQUEST['filter']['UpdateDiskSpace']) ? 1 : 0);
|
||||||
$sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
|
$sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
|
||||||
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
|
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
|
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
|
||||||
|
if ( 0 ) {
|
||||||
dbQuery('UPDATE Filters SET '.$sql.' WHERE Id=?', array($_REQUEST['Id']));
|
dbQuery('UPDATE Filters SET '.$sql.' WHERE Id=?', array($_REQUEST['Id']));
|
||||||
|
}
|
||||||
|
$filter->save($changes);
|
||||||
if ( $filter->Background() )
|
if ( $filter->Background() )
|
||||||
$filter->control('stop');
|
$filter->control('stop');
|
||||||
} else {
|
} else {
|
||||||
|
# COuld be execute
|
||||||
|
if ( 0 ) {
|
||||||
dbQuery('INSERT INTO Filters SET'.$sql);
|
dbQuery('INSERT INTO Filters SET'.$sql);
|
||||||
$_REQUEST['Id'] = dbInsertId();
|
$_REQUEST['Id'] = dbInsertId();
|
||||||
$filter = new ZM\Filter($_REQUEST['Id']);
|
$filter = new ZM\Filter($_REQUEST['Id']);
|
||||||
|
}
|
||||||
|
$filter->save($changes);
|
||||||
}
|
}
|
||||||
if ( !empty($_REQUEST['filter']['Background']) )
|
if ( $filter->Background() )
|
||||||
$filter->control('start');
|
$filter->control('start');
|
||||||
|
|
||||||
if ( $action == 'execute' ) {
|
if ( $action == 'execute' ) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ if ( !empty($_REQUEST['mid']) && canEdit('Monitors', $_REQUEST['mid']) ) {
|
||||||
$_REQUEST['newZone']['MaxBlobPixels'] = intval(($_REQUEST['newZone']['MaxBlobPixels']*$_REQUEST['newZone']['Area'])/100);
|
$_REQUEST['newZone']['MaxBlobPixels'] = intval(($_REQUEST['newZone']['MaxBlobPixels']*$_REQUEST['newZone']['Area'])/100);
|
||||||
}
|
}
|
||||||
|
|
||||||
unset( $_REQUEST['newZone']['Points'] );
|
unset($_REQUEST['newZone']['Points']);
|
||||||
|
|
||||||
# convert these fields to integer e.g. NULL -> 0
|
# convert these fields to integer e.g. NULL -> 0
|
||||||
$types = array(
|
$types = array(
|
||||||
|
|
|
@ -1341,7 +1341,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') {
|
||||||
$filter['sql'] .= " IS NOT $value";
|
$filter['sql'] .= " IS NOT $value";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ZM\Warning("Invalid operator in filter: " . $term['op'] );
|
ZM\Warning('Invalid operator in filter: ' . print_r($term['op'], true));
|
||||||
} // end switch op
|
} // end switch op
|
||||||
|
|
||||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($term['op']);
|
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($term['op']);
|
||||||
|
@ -1472,7 +1472,14 @@ function getPagination( $pages, $page, $maxShortcuts, $query, $querySep='&'
|
||||||
|
|
||||||
function sortHeader( $field, $querySep='&' ) {
|
function sortHeader( $field, $querySep='&' ) {
|
||||||
global $view;
|
global $view;
|
||||||
return '?view='.$view.$querySep.'page=1'.$_REQUEST['filter']['query'].$querySep.'sort_field='.$field.$querySep.'sort_asc='.($_REQUEST['sort_field'] == $field?!$_REQUEST['sort_asc']:0).$querySep.'limit='.validInt($_REQUEST['limit']);
|
return implode($querySep, array(
|
||||||
|
'?view='.$view,
|
||||||
|
'page=1'.$_REQUEST['filter']['query'],
|
||||||
|
'sort_field='.$field,
|
||||||
|
'sort_asc='.($_REQUEST['sort_field'] == $field ? !$_REQUEST['sort_asc'] : 0),
|
||||||
|
'limit='.validInt($_REQUEST['limit']),
|
||||||
|
($_REQUEST['eid'] ? 'eid='.$_REQUEST['eid'] : '' ),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortTag( $field ) {
|
function sortTag( $field ) {
|
||||||
|
@ -2518,4 +2525,45 @@ function format_duration($time, $separator=':') {
|
||||||
return sprintf('%02d%s%02d%s%02d', floor($time/3600), $separator, ($time/60)%60, $separator, $time%60);
|
return sprintf('%02d%s%02d%s%02d', floor($time/3600), $separator, ($time/60)%60, $separator, $time%60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function array_recursive_diff($aArray1, $aArray2) {
|
||||||
|
$aReturn = array();
|
||||||
|
|
||||||
|
foreach ($aArray1 as $mKey => $mValue) {
|
||||||
|
if ( array_key_exists($mKey, $aArray2) ) {
|
||||||
|
if ( is_array($mValue) ) {
|
||||||
|
$aRecursiveDiff = array_recursive_diff($mValue, $aArray2[$mKey]);
|
||||||
|
if ( count($aRecursiveDiff) ) {
|
||||||
|
$aReturn[$mKey] = $aRecursiveDiff;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ( $mValue != $aArray2[$mKey] ) {
|
||||||
|
$aReturn[$mKey] = $mValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aReturn[$mKey] = $mValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Now check for keys in array2 that are not in array1
|
||||||
|
foreach ($aArray2 as $mKey => $mValue) {
|
||||||
|
if ( array_key_exists($mKey, $aArray1) ) {
|
||||||
|
# Already checked it... I think.
|
||||||
|
#if ( is_array($mValue) ) {
|
||||||
|
#$aRecursiveDiff = array_recursive_diff($mValue, $aArray2[$mKey]);
|
||||||
|
#if ( count($aRecursiveDiff) ) {
|
||||||
|
#$aReturn[$mKey] = $aRecursiveDiff;
|
||||||
|
#}
|
||||||
|
#} else {
|
||||||
|
#if ( $mValue != $aArray2[$mKey] ) {
|
||||||
|
#$aReturn[$mKey] = $mValue;
|
||||||
|
#}
|
||||||
|
#}
|
||||||
|
} else {
|
||||||
|
$aReturn[$mKey] = $mValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $aReturn;
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -132,6 +132,7 @@ $SLANG = array(
|
||||||
'AttrMaxScore' => 'Max. Score',
|
'AttrMaxScore' => 'Max. Score',
|
||||||
'AttrMonitorId' => 'Monitor Id',
|
'AttrMonitorId' => 'Monitor Id',
|
||||||
'AttrMonitorName' => 'Monitor Name',
|
'AttrMonitorName' => 'Monitor Name',
|
||||||
|
'AttrSecondaryStorageArea' => 'Secondary Storage Area',
|
||||||
'AttrStorageArea' => 'Storage Area',
|
'AttrStorageArea' => 'Storage Area',
|
||||||
'AttrFilterServer' => 'Server Filter is Running On',
|
'AttrFilterServer' => 'Server Filter is Running On',
|
||||||
'AttrMonitorServer' => 'Server Monitor is Running On',
|
'AttrMonitorServer' => 'Server Monitor is Running On',
|
||||||
|
@ -356,6 +357,7 @@ $SLANG = array(
|
||||||
'FilterArchiveEvents' => 'Archive all matches',
|
'FilterArchiveEvents' => 'Archive all matches',
|
||||||
'FilterUpdateDiskSpace' => 'Update used disk space',
|
'FilterUpdateDiskSpace' => 'Update used disk space',
|
||||||
'FilterDeleteEvents' => 'Delete all matches',
|
'FilterDeleteEvents' => 'Delete all matches',
|
||||||
|
'FilterCopyEvents' => 'Copy all matches',
|
||||||
'FilterMoveEvents' => 'Move all matches',
|
'FilterMoveEvents' => 'Move all matches',
|
||||||
'FilterEmailEvents' => 'Email details of all matches',
|
'FilterEmailEvents' => 'Email details of all matches',
|
||||||
'FilterExecuteEvents' => 'Execute command on all matches',
|
'FilterExecuteEvents' => 'Execute command on all matches',
|
||||||
|
|
|
@ -286,7 +286,7 @@ function getNavBarHTML($reload = null) {
|
||||||
ZM\Error('Potentially invalid value for ZM_LOG_DATABASE_LIMIT: ' . ZM_LOG_DATABASE_LIMIT);
|
ZM\Error('Potentially invalid value for ZM_LOG_DATABASE_LIMIT: ' . ZM_LOG_DATABASE_LIMIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo makePopupLink( '?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>' );
|
echo makePopupLink('?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>');
|
||||||
}
|
}
|
||||||
?></li>
|
?></li>
|
||||||
<?php
|
<?php
|
||||||
|
@ -386,9 +386,6 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) {
|
||||||
foreach ( $storage_areas as $area ) {
|
foreach ( $storage_areas as $area ) {
|
||||||
$storage_paths[$area->Path()] = $area;
|
$storage_paths[$area->Path()] = $area;
|
||||||
}
|
}
|
||||||
if ( ! isset($storage_paths[ZM_DIR_EVENTS]) ) {
|
|
||||||
array_push( $storage_areas, new ZM\Storage() );
|
|
||||||
}
|
|
||||||
$func = function($S){
|
$func = function($S){
|
||||||
$class = '';
|
$class = '';
|
||||||
if ( $S->disk_usage_percent() > 98 ) {
|
if ( $S->disk_usage_percent() > 98 ) {
|
||||||
|
|
|
@ -134,7 +134,11 @@ if ( ! $Event->Id() ) {
|
||||||
<span id="dataDuration" title="<?php echo translate('Duration') ?>"><?php echo $Event->Length().'s' ?></span>
|
<span id="dataDuration" title="<?php echo translate('Duration') ?>"><?php echo $Event->Length().'s' ?></span>
|
||||||
<span id="dataFrames" title="<?php echo translate('AttrFrames').'/'.translate('AttrAlarmFrames') ?>"><?php echo $Event->Frames() ?>/<?php echo $Event->AlarmFrames() ?></span>
|
<span id="dataFrames" title="<?php echo translate('AttrFrames').'/'.translate('AttrAlarmFrames') ?>"><?php echo $Event->Frames() ?>/<?php echo $Event->AlarmFrames() ?></span>
|
||||||
<span id="dataScore" title="<?php echo translate('AttrTotalScore').'/'.translate('AttrAvgScore').'/'.translate('AttrMaxScore') ?>"><?php echo $Event->TotScore() ?>/<?php echo $Event->AvgScore() ?>/<?php echo $Event->MaxScore() ?></span>
|
<span id="dataScore" title="<?php echo translate('AttrTotalScore').'/'.translate('AttrAvgScore').'/'.translate('AttrMaxScore') ?>"><?php echo $Event->TotScore() ?>/<?php echo $Event->AvgScore() ?>/<?php echo $Event->MaxScore() ?></span>
|
||||||
<span id="Storage"> <?php echo human_filesize($Event->DiskSpace(null)) . ' on ' . $Event->Storage()->Name() ?></span>
|
<span id="Storage">
|
||||||
|
<?php echo
|
||||||
|
human_filesize($Event->DiskSpace(null)) . ' on ' . $Event->Storage()->Name().
|
||||||
|
( $Event->SecondaryStorageId() ? ', ' . $Event->SecondaryStorage()->Name() :'' )
|
||||||
|
?></span>
|
||||||
<div id="closeWindow"><a href="#" onclick="<?php echo $popup ? 'window.close()' : 'window.history.back();return false;' ?>"><?php echo $popup ? translate('Close') : translate('Back') ?></a></div>
|
<div id="closeWindow"><a href="#" onclick="<?php echo $popup ? 'window.close()' : 'window.history.back();return false;' ?>"><?php echo $popup ? translate('Close') : translate('Back') ?></a></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="menuBar1">
|
<div id="menuBar1">
|
||||||
|
|
|
@ -22,36 +22,32 @@ if ( !canView('Events') ) {
|
||||||
$view = 'error';
|
$view = 'error';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
require_once 'includes/Filter.php';
|
require_once('includes/Object.php');
|
||||||
|
require_once('includes/Storage.php');
|
||||||
|
require_once('includes/Filter.php');
|
||||||
parseSort();
|
parseSort();
|
||||||
|
|
||||||
$filterNames = array( ''=>translate('ChooseFilter') );
|
$filterNames = array(''=>translate('ChooseFilter'));
|
||||||
$filter = NULL;
|
$filter = NULL;
|
||||||
|
|
||||||
foreach ( dbFetchAll('SELECT * FROM Filters ORDER BY Name') as $row ) {
|
foreach ( ZM\Filter::find(null,array('order'=>'lower(Name)')) as $Filter ) {
|
||||||
$filterNames[$row['Id']] = $row['Id'] . ' ' . $row['Name'];
|
$filterNames[$Filter->Id()] = $Filter->Id() . ' ' . $Filter->Name();
|
||||||
if ( $row['Background'] )
|
if ( $Filter->Background() )
|
||||||
$filterNames[$row['Id']] .= '*';
|
$filterNames[$Filter->Id()] .= '*';
|
||||||
if ( $row['Concurrent'] )
|
if ( $Filter->Concurrent() )
|
||||||
$filterNames[$row['Id']] .= '&';
|
$filterNames[$Filter->Id()] .= '&';
|
||||||
|
|
||||||
if ( isset($_REQUEST['Id']) && $_REQUEST['Id'] == $row['Id'] ) {
|
if ( isset($_REQUEST['Id']) && ($_REQUEST['Id'] == $Filter->Id()) ) {
|
||||||
$filter = new ZM\Filter($row);
|
$filter = $Filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ! $filter ) {
|
if ( !$filter ) {
|
||||||
$filter = new ZM\Filter();
|
$filter = new ZM\Filter();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($_REQUEST['sort_field']) && isset($_REQUEST['filter']) ) {
|
|
||||||
$_REQUEST['filter']['Query']['sort_field'] = $_REQUEST['sort_field'];
|
|
||||||
$_REQUEST['filter']['Query']['sort_asc'] = $_REQUEST['sort_asc'];
|
|
||||||
$_REQUEST['filter']['Query']['limit'] = $_REQUEST['limit'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isset($_REQUEST['filter']) ) {
|
if ( isset($_REQUEST['filter']) ) {
|
||||||
$filter->set($_REQUEST['filter']);
|
|
||||||
# Update our filter object with whatever changes we have made before saving
|
# Update our filter object with whatever changes we have made before saving
|
||||||
|
#$filter->set($_REQUEST['filter']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$conjunctionTypes = getFilterQueryConjunctionTypes();
|
$conjunctionTypes = getFilterQueryConjunctionTypes();
|
||||||
|
@ -97,12 +93,13 @@ $attrTypes = array(
|
||||||
'DiskPercent' => translate('AttrDiskPercent'),
|
'DiskPercent' => translate('AttrDiskPercent'),
|
||||||
'DiskSpace' => translate('AttrDiskSpace'),
|
'DiskSpace' => translate('AttrDiskSpace'),
|
||||||
'SystemLoad' => translate('AttrSystemLoad'),
|
'SystemLoad' => translate('AttrSystemLoad'),
|
||||||
'StorageId' => translate('AttrStorageArea'),
|
'StorageId' => translate('AttrStorageArea'),
|
||||||
'ServerId' => translate('AttrMonitorServer'),
|
'SecondaryStorageId' => translate('AttrSecondaryStorageArea'),
|
||||||
|
'ServerId' => translate('AttrMonitorServer'),
|
||||||
'FilterServerId' => translate('AttrFilterServer'),
|
'FilterServerId' => translate('AttrFilterServer'),
|
||||||
'MonitorServerId' => translate('AttrMonitorServer'),
|
'MonitorServerId' => translate('AttrMonitorServer'),
|
||||||
'StorageServerId' => translate('AttrStorageServer'),
|
'StorageServerId' => translate('AttrStorageServer'),
|
||||||
'StateId' => translate('AttrStateId'),
|
'StateId' => translate('AttrStateId'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$opTypes = array(
|
$opTypes = array(
|
||||||
|
@ -127,27 +124,24 @@ $archiveTypes = array(
|
||||||
|
|
||||||
$focusWindow = true;
|
$focusWindow = true;
|
||||||
|
|
||||||
$storageareas = array('' => 'All');
|
$storageareas = array('' => 'All') + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage');
|
||||||
//$storageareas[0] = 'Default ' . ZM_DIR_EVENTS;
|
|
||||||
foreach ( dbFetchAll('SELECT Id,Name FROM Storage ORDER BY lower(Name) ASC') as $storage ) {
|
|
||||||
$storageareas[$storage['Id']] = $storage['Name'];
|
|
||||||
}
|
|
||||||
$weekdays = array();
|
$weekdays = array();
|
||||||
for ( $i = 0; $i < 7; $i++ ) {
|
for ( $i = 0; $i < 7; $i++ ) {
|
||||||
$weekdays[$i] = strftime('%A', mktime(12, 0, 0, 1, $i+1, 2001));
|
$weekdays[$i] = strftime('%A', mktime(12, 0, 0, 1, $i+1, 2001));
|
||||||
}
|
}
|
||||||
$states = array();
|
$states = array();
|
||||||
foreach ( dbFetchAll('SELECT Id, Name FROM States ORDER BY lower(Name) ASC') as $state_row ) {
|
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `States` ORDER BY lower(`Name`) ASC') as $state_row ) {
|
||||||
$states[$state_row['Id']] = validHtmlStr($state_row['Name']);
|
$states[$state_row['Id']] = validHtmlStr($state_row['Name']);
|
||||||
}
|
}
|
||||||
$servers = array();
|
$servers = array();
|
||||||
$servers['ZM_SERVER_ID'] = 'Current Server';
|
$servers['ZM_SERVER_ID'] = 'Current Server';
|
||||||
$servers['NULL'] = 'No Server';
|
$servers['NULL'] = 'No Server';
|
||||||
foreach ( dbFetchAll('SELECT Id, Name FROM Servers ORDER BY lower(Name) ASC') as $server ) {
|
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Servers` ORDER BY lower(`Name`) ASC') as $server ) {
|
||||||
$servers[$server['Id']] = validHtmlStr($server['Name']);
|
$servers[$server['Id']] = validHtmlStr($server['Name']);
|
||||||
}
|
}
|
||||||
$monitors = array();
|
$monitors = array();
|
||||||
foreach ( dbFetchAll('SELECT Id, Name FROM Monitors ORDER BY Name ASC') as $monitor ) {
|
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Monitors` ORDER BY lower(`Name`) ASC') as $monitor ) {
|
||||||
if ( visibleMonitor($monitor['Id']) ) {
|
if ( visibleMonitor($monitor['Id']) ) {
|
||||||
$monitors[$monitor['Name']] = validHtmlStr($monitor['Name']);
|
$monitors[$monitor['Name']] = validHtmlStr($monitor['Name']);
|
||||||
}
|
}
|
||||||
|
@ -273,7 +267,7 @@ for ( $i=0; $i < count($terms); $i++ ) {
|
||||||
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
|
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
|
||||||
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", $servers, $term['val']); ?></td>
|
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", $servers, $term['val']); ?></td>
|
||||||
<?php
|
<?php
|
||||||
} elseif ( $term['attr'] == 'StorageId' ) {
|
} elseif ( ($term['attr'] == 'StorageId') || ($term['attr'] == 'SecondaryStorageId') ) {
|
||||||
?>
|
?>
|
||||||
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
|
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
|
||||||
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", $storageareas, $term['val']); ?></td>
|
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", $storageareas, $term['val']); ?></td>
|
||||||
|
@ -391,7 +385,13 @@ if ( ZM_OPT_MESSAGE ) {
|
||||||
<label><?php echo translate('FilterDeleteEvents') ?></label>
|
<label><?php echo translate('FilterDeleteEvents') ?></label>
|
||||||
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( $filter->AutoDelete() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/>
|
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( $filter->AutoDelete() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/>
|
||||||
</p>
|
</p>
|
||||||
<p><label><?php echo translate('FilterMoveEvents') ?></label>
|
<p>
|
||||||
|
<label><?php echo translate('FilterCopyEvents') ?></label>
|
||||||
|
<input type="checkbox" name="filter[AutoCopy]" value="1"<?php if ( $filter->AutoCopy() ) { ?> checked="checked"<?php } ?> data-on-click-this="click_autocopy"/>
|
||||||
|
<?php echo htmlSelect('filter[AutoCopyTo]', $storageareas, $filter->AutoCopyTo(), $filter->AutoCopy() ? null : array('style'=>'display:none;')); ?>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label><?php echo translate('FilterMoveEvents') ?></label>
|
||||||
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( $filter->AutoMove() ) { ?> checked="checked"<?php } ?> data-on-click-this="click_automove"/>
|
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( $filter->AutoMove() ) { ?> checked="checked"<?php } ?> data-on-click-this="click_automove"/>
|
||||||
<?php echo htmlSelect('filter[AutoMoveTo]', $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;')); ?>
|
<?php echo htmlSelect('filter[AutoMoveTo]', $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;')); ?>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -39,7 +39,7 @@ if ( empty($_REQUEST['sort_field']) )
|
||||||
if ( !isset($_REQUEST['sort_asc']) )
|
if ( !isset($_REQUEST['sort_asc']) )
|
||||||
$_REQUEST['sort_asc'] = true;
|
$_REQUEST['sort_asc'] = true;
|
||||||
|
|
||||||
if( ! isset($_REQUEST['filter'])){
|
if ( ! isset($_REQUEST['filter'])){
|
||||||
// generate a dummy filter from the eid for pagination
|
// generate a dummy filter from the eid for pagination
|
||||||
$_REQUEST['filter'] = array('Query' => array( 'terms' => array( ) ) );
|
$_REQUEST['filter'] = array('Query' => array( 'terms' => array( ) ) );
|
||||||
$_REQUEST['filter'] = addFilterTerm(
|
$_REQUEST['filter'] = addFilterTerm(
|
||||||
|
@ -53,7 +53,6 @@ parseSort();
|
||||||
parseFilter($_REQUEST['filter']);
|
parseFilter($_REQUEST['filter']);
|
||||||
$filterQuery = $_REQUEST['filter']['query'];
|
$filterQuery = $_REQUEST['filter']['query'];
|
||||||
|
|
||||||
|
|
||||||
if ( $_REQUEST['filter']['sql'] ) {
|
if ( $_REQUEST['filter']['sql'] ) {
|
||||||
$countSql .= $_REQUEST['filter']['sql'];
|
$countSql .= $_REQUEST['filter']['sql'];
|
||||||
$frameSql .= $_REQUEST['filter']['sql'];
|
$frameSql .= $_REQUEST['filter']['sql'];
|
||||||
|
@ -61,7 +60,6 @@ if ( $_REQUEST['filter']['sql'] ) {
|
||||||
|
|
||||||
$frameSql .= " ORDER BY $sortColumn $sortOrder,Id $sortOrder";
|
$frameSql .= " ORDER BY $sortColumn $sortOrder,Id $sortOrder";
|
||||||
|
|
||||||
|
|
||||||
if ( isset( $_REQUEST['scale'] ) ) {
|
if ( isset( $_REQUEST['scale'] ) ) {
|
||||||
$scale = validNum($_REQUEST['scale']);
|
$scale = validNum($_REQUEST['scale']);
|
||||||
} else if ( isset( $_COOKIE['zmWatchScale'.$Monitor->Id()] ) ) {
|
} else if ( isset( $_COOKIE['zmWatchScale'.$Monitor->Id()] ) ) {
|
||||||
|
@ -75,7 +73,7 @@ if ( isset( $_REQUEST['scale'] ) ) {
|
||||||
$page = isset($_REQUEST['page']) ? validInt($_REQUEST['page']) : 1;
|
$page = isset($_REQUEST['page']) ? validInt($_REQUEST['page']) : 1;
|
||||||
$limit = isset($_REQUEST['limit']) ? validInt($_REQUEST['limit']) : 0;
|
$limit = isset($_REQUEST['limit']) ? validInt($_REQUEST['limit']) : 0;
|
||||||
|
|
||||||
$nFrames = dbFetchOne($countSql, 'FrameCount' );
|
$nFrames = dbFetchOne($countSql, 'FrameCount');
|
||||||
|
|
||||||
if ( !empty($limit) && ($nFrames > $limit) ) {
|
if ( !empty($limit) && ($nFrames > $limit) ) {
|
||||||
$nFrames = $limit;
|
$nFrames = $limit;
|
||||||
|
|
|
@ -72,6 +72,15 @@ function click_automove(element) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function click_autocopy(element) {
|
||||||
|
updateButtons(this);
|
||||||
|
if ( this.checked ) {
|
||||||
|
$j(this.form.elements['filter[AutoCopyTo]']).css('display', 'inline');
|
||||||
|
} else {
|
||||||
|
this.form.elements['filter[AutoCopyTo]'].hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkValue( element ) {
|
function checkValue( element ) {
|
||||||
var rows = $j(element).closest('tbody').children();
|
var rows = $j(element).closest('tbody').children();
|
||||||
parseRows(rows);
|
parseRows(rows);
|
||||||
|
@ -200,10 +209,10 @@ function parseRows(rows) {
|
||||||
}
|
}
|
||||||
var serverVal = inputTds.eq(4).children().val();
|
var serverVal = inputTds.eq(4).children().val();
|
||||||
inputTds.eq(4).html(serverSelect).children().val(serverVal).chosen({width: "101%"});
|
inputTds.eq(4).html(serverSelect).children().val(serverVal).chosen({width: "101%"});
|
||||||
} else if ( attr == 'StorageId' ) { //Choose by storagearea
|
} else if ( (attr == 'StorageId') || (attr == 'SecondaryStorageId') ) { //Choose by storagearea
|
||||||
var storageSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
|
var storageSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
|
||||||
for ( key in storageareas ) {
|
for ( key in storageareas ) {
|
||||||
storageSelect.append('<option value="' + key + '">' + storageareas[key] + '</option>');
|
storageSelect.append('<option value="' + key + '">' + storageareas[key].Name + '</option>');
|
||||||
}
|
}
|
||||||
var storageVal = inputTds.eq(4).children().val();
|
var storageVal = inputTds.eq(4).children().val();
|
||||||
inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"});
|
inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"});
|
||||||
|
|
|
@ -371,8 +371,8 @@ function updateY( index ) {
|
||||||
|
|
||||||
function saveChanges( element ) {
|
function saveChanges( element ) {
|
||||||
var form = element.form;
|
var form = element.form;
|
||||||
if ( validateForm( form ) ) {
|
if ( validateForm(form) ) {
|
||||||
submitForm( form );
|
submitForm(form);
|
||||||
if ( form.elements['newZone[Type]'].value == 'Privacy' ) {
|
if ( form.elements['newZone[Type]'].value == 'Privacy' ) {
|
||||||
alert( 'Capture process for this monitor will be restarted for the Privacy zone changes to take effect.' );
|
alert( 'Capture process for this monitor will be restarted for the Privacy zone changes to take effect.' );
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ $maxY = $monitor->Height()-1;
|
||||||
|
|
||||||
if ( !isset($newZone) ) {
|
if ( !isset($newZone) ) {
|
||||||
if ( $zid > 0 ) {
|
if ( $zid > 0 ) {
|
||||||
$zone = dbFetchOne( 'SELECT * FROM Zones WHERE MonitorId = ? AND Id=?', NULL, array( $monitor->Id(), $zid ) );
|
$zone = dbFetchOne('SELECT * FROM Zones WHERE MonitorId = ? AND Id=?', NULL, array($monitor->Id(), $zid));
|
||||||
} else {
|
} else {
|
||||||
$zone = array(
|
$zone = array(
|
||||||
'Id' => 0,
|
'Id' => 0,
|
||||||
|
@ -98,23 +98,23 @@ if ( !isset($newZone) ) {
|
||||||
} # end if new Zone
|
} # end if new Zone
|
||||||
|
|
||||||
# Ensure Zone fits within the limits of the Monitor
|
# Ensure Zone fits within the limits of the Monitor
|
||||||
limitPoints( $newZone['Points'], $minX, $minY, $maxX, $maxY );
|
limitPoints($newZone['Points'], $minX, $minY, $maxX, $maxY);
|
||||||
|
|
||||||
ksort( $newZone['Points'], SORT_NUMERIC );
|
ksort($newZone['Points'], SORT_NUMERIC);
|
||||||
|
|
||||||
$newZone['Coords'] = pointsToCoords( $newZone['Points'] );
|
$newZone['Coords'] = pointsToCoords($newZone['Points']);
|
||||||
$newZone['Area'] = getPolyArea( $newZone['Points'] );
|
$newZone['Area'] = getPolyArea($newZone['Points']);
|
||||||
$newZone['AreaCoords'] = preg_replace( '/\s+/', ',', $newZone['Coords'] );
|
$newZone['AreaCoords'] = preg_replace('/\s+/', ',', $newZone['Coords']);
|
||||||
$selfIntersecting = isSelfIntersecting( $newZone['Points'] );
|
$selfIntersecting = isSelfIntersecting($newZone['Points']);
|
||||||
|
|
||||||
$focusWindow = true;
|
$focusWindow = true;
|
||||||
$connkey = generateConnKey();
|
$connkey = generateConnKey();
|
||||||
$streamSrc = '';
|
$streamSrc = '';
|
||||||
$streamMode = '';
|
$streamMode = '';
|
||||||
# Have to do this here, because the .js.php references somethings figured out when generating the streamHTML
|
# Have to do this here, because the .js.php references somethings figured out when generating the streamHTML
|
||||||
$StreamHTML = getStreamHTML( $monitor, array('scale'=>$scale) );
|
$StreamHTML = getStreamHTML($monitor, array('scale'=>$scale));
|
||||||
|
|
||||||
xhtmlHeaders(__FILE__, translate('Zone') );
|
xhtmlHeaders(__FILE__, translate('Zone'));
|
||||||
?>
|
?>
|
||||||
<body>
|
<body>
|
||||||
<div id="page">
|
<div id="page">
|
||||||
|
@ -132,7 +132,7 @@ xhtmlHeaders(__FILE__, translate('Zone') );
|
||||||
<input type="hidden" name="newZone[Area]" value="<?php echo $newZone['Area'] ?>"/>
|
<input type="hidden" name="newZone[Area]" value="<?php echo $newZone['Area'] ?>"/>
|
||||||
<input type="hidden" name="newZone[AlarmRGB]" value=""/>
|
<input type="hidden" name="newZone[AlarmRGB]" value=""/>
|
||||||
<div id="settingsPanel">
|
<div id="settingsPanel">
|
||||||
<table id="zoneSettings" cellspacing="0">
|
<table id="zoneSettings">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row"><?php echo translate('Name') ?></th>
|
<th scope="row"><?php echo translate('Name') ?></th>
|
||||||
|
@ -162,7 +162,7 @@ xhtmlHeaders(__FILE__, translate('Zone') );
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row"><?php echo translate('CheckMethod') ?></th>
|
<th scope="row"><?php echo translate('CheckMethod') ?></th>
|
||||||
<td colspan="2"><?php echo buildSelect( "newZone[CheckMethod]", $optCheckMethods, 'applyCheckMethod()' ) ?></td>
|
<td colspan="2"><?php echo buildSelect('newZone[CheckMethod]', $optCheckMethods, 'applyCheckMethod()' ) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row"><?php echo translate('ZoneMinMaxPixelThres') ?></th>
|
<th scope="row"><?php echo translate('ZoneMinMaxPixelThres') ?></th>
|
||||||
|
@ -216,14 +216,14 @@ xhtmlHeaders(__FILE__, translate('Zone') );
|
||||||
<svg id="zoneSVG" class="zones" style="position: absolute; top: 0; left: 0; width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px; background: none;">
|
<svg id="zoneSVG" class="zones" style="position: absolute; top: 0; left: 0; width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px; background: none;">
|
||||||
<?php
|
<?php
|
||||||
if ( $zone['Id'] ) {
|
if ( $zone['Id'] ) {
|
||||||
$other_zones = dbFetchAll( 'SELECT * FROM Zones WHERE MonitorId = ? AND Id != ?', NULL, array( $monitor->Id(), $zone['Id'] ) );
|
$other_zones = dbFetchAll('SELECT * FROM Zones WHERE MonitorId = ? AND Id != ?', NULL, array($monitor->Id(), $zone['Id']));
|
||||||
} else {
|
} else {
|
||||||
$other_zones = dbFetchAll( 'SELECT * FROM Zones WHERE MonitorId = ?', NULL, array( $monitor->Id() ) );
|
$other_zones = dbFetchAll('SELECT * FROM Zones WHERE MonitorId = ?', NULL, array($monitor->Id()));
|
||||||
}
|
}
|
||||||
if ( count( $other_zones ) ) {
|
if ( count($other_zones) ) {
|
||||||
$html = '';
|
$html = '';
|
||||||
foreach( $other_zones as $other_zone ) {
|
foreach ( $other_zones as $other_zone ) {
|
||||||
$other_zone['AreaCoords'] = preg_replace( '/\s+/', ',', $other_zone['Coords'] );
|
$other_zone['AreaCoords'] = preg_replace('/\s+/', ',', $other_zone['Coords']);
|
||||||
$html .= '<polygon id="zonePoly'.$other_zone['Id'].'" points="'. $other_zone['AreaCoords'] .'" class="'. $other_zone['Type'] .'"/>';
|
$html .= '<polygon id="zonePoly'.$other_zone['Id'].'" points="'. $other_zone['AreaCoords'] .'" class="'. $other_zone['Type'] .'"/>';
|
||||||
}
|
}
|
||||||
echo $html;
|
echo $html;
|
||||||
|
@ -267,9 +267,11 @@ for ( $i = 0; $i < $pointCols; $i++ ) {
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<input id="pauseBtn" type="button" value="<?php echo translate('Pause') ?>" data-on-click="streamCmdPauseToggle"/>
|
<button id="pauseBtn" type="button" data-on-click="streamCmdPauseToggle"><?php echo translate('Pause') ?></button>
|
||||||
<input type="submit" id="submitBtn" name="submitBtn" value="<?php echo translate('Save') ?>" onclick="return saveChanges( this )"<?php if (!canEdit( 'Monitors' ) || (false && $selfIntersecting)) { ?> disabled="disabled"<?php } ?>/>
|
<button type="button" id="submitBtn" name="submitBtn" value="Save" data-on-click-this="saveChanges"<?php if (!canEdit('Monitors') || (false && $selfIntersecting)) { ?> disabled="disabled"<?php } ?>>
|
||||||
<input type="button" value="<?php echo translate('Cancel') ?>" onclick="refreshParentWindow(); closeWindow();"/>
|
<?php echo translate('Save') ?>
|
||||||
|
</button>
|
||||||
|
<button type="button" value="Cancel" onclick="refreshParentWindow(); closeWindow();"><?php echo translate('Cancel') ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue