Merge branch 'master' into fix_use_of_sprintf

This commit is contained in:
Isaac Connor 2020-04-06 11:21:43 -04:00
commit c6e0b9be39
96 changed files with 2503 additions and 1756 deletions

View File

@ -188,6 +188,8 @@ set(ZM_NO_MMAP "OFF" CACHE BOOL
experience problems with the shared memory. default: OFF") experience problems with the shared memory. default: OFF")
set(ZM_NO_LIBVLC "OFF" CACHE BOOL set(ZM_NO_LIBVLC "OFF" CACHE BOOL
"Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF") "Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF")
set(ZM_NO_LIBVNC "OFF" CACHE BOOL
"Set to ON to skip libvnc checks and force building ZM without libvnc. default: OFF")
set(ZM_NO_CURL "OFF" CACHE BOOL set(ZM_NO_CURL "OFF" CACHE BOOL
"Set to ON to skip cURL checks and force building ZM without cURL. default: OFF") "Set to ON to skip cURL checks and force building ZM without cURL. default: OFF")
set(ZM_NO_X10 "OFF" CACHE BOOL set(ZM_NO_X10 "OFF" CACHE BOOL
@ -553,6 +555,7 @@ if(AVCODEC_LIBRARIES)
check_include_file("libavcodec/avcodec.h" HAVE_LIBAVCODEC_AVCODEC_H) check_include_file("libavcodec/avcodec.h" HAVE_LIBAVCODEC_AVCODEC_H)
set(optlibsfound "${optlibsfound} AVCodec") set(optlibsfound "${optlibsfound} AVCodec")
else(AVCODEC_LIBRARIES) else(AVCODEC_LIBRARIES)
message(WARNING "\nWhile it should be possible to build ZM without AVCODEC the result will pretty useless.")
set(optlibsnotfound "${optlibsnotfound} AVCodec") set(optlibsnotfound "${optlibsnotfound} AVCodec")
endif(AVCODEC_LIBRARIES) endif(AVCODEC_LIBRARIES)
@ -674,6 +677,25 @@ if(NOT ZM_NO_LIBVLC)
endif(LIBVLC_LIBRARIES) endif(LIBVLC_LIBRARIES)
endif(NOT ZM_NO_LIBVLC) endif(NOT ZM_NO_LIBVLC)
if(NOT ZM_NO_LIBVNC)
# libvncclient (using find_library and find_path)
find_library(LIBVNC_LIBRARIES vncclient)
if(LIBVNC_LIBRARIES)
set(HAVE_LIBVNC 1)
list(APPEND ZM_BIN_LIBS "${LIBVNC_LIBRARIES}")
find_path(LIBVNC_INCLUDE_DIR "rfb/rfb.h")
if(LIBVNC_INCLUDE_DIR)
include_directories("${LIBVNC_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${LIBVNC_INCLUDE_DIR}")
endif(LIBVNC_INCLUDE_DIR)
mark_as_advanced(FORCE LIBVNC_LIBRARIES LIBVNC_INCLUDE_DIR)
check_include_file("rfb/rfb.h" HAVE_RFB_RFB_H)
set(optlibsfound "${optlibsfound} libVNC")
else(LIBVNC_LIBRARIES)
set(optlibsnotfound "${optlibsnotfound} libVNC")
endif(LIBVNC_LIBRARIES)
endif(NOT ZM_NO_LIBVNC)
#find_package(Boost 1.36.0) #find_package(Boost 1.36.0)
#if(Boost_FOUND) #if(Boost_FOUND)
#include_directories(${Boost_INCLUDE_DIRS}) #include_directories(${Boost_INCLUDE_DIRS})
@ -908,7 +930,7 @@ message(STATUS "Optional libraries not found:${optlibsnotfound}")
# Run ZM configuration generator # Run ZM configuration generator
message(STATUS "Running ZoneMinder configuration generator") message(STATUS "Running ZoneMinder configuration generator")
execute_process(COMMAND perl ./zmconfgen.pl RESULT_VARIABLE zmconfgen_result) execute_process(COMMAND perl ${CMAKE_CURRENT_BINARY_DIR}/zmconfgen.pl RESULT_VARIABLE zmconfgen_result)
if(zmconfgen_result EQUAL 0) if(zmconfgen_result EQUAL 0)
message(STATUS message(STATUS
"ZoneMinder configuration generator completed successfully") "ZoneMinder configuration generator completed successfully")

View File

@ -63,7 +63,7 @@ DROP TABLE IF EXISTS `Controls`;
CREATE TABLE `Controls` ( CREATE TABLE `Controls` (
`Id` int(10) unsigned NOT NULL auto_increment, `Id` int(10) unsigned NOT NULL auto_increment,
`Name` varchar(64) NOT NULL default '', `Name` varchar(64) NOT NULL default '',
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket') NOT NULL default 'Local', `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket','VNC') NOT NULL default 'Local',
`Protocol` varchar(64) default NULL, `Protocol` varchar(64) default NULL,
`CanWake` tinyint(3) unsigned NOT NULL default '0', `CanWake` tinyint(3) unsigned NOT NULL default '0',
`CanSleep` tinyint(3) unsigned NOT NULL default '0', `CanSleep` tinyint(3) unsigned NOT NULL default '0',
@ -287,6 +287,9 @@ CREATE TABLE `Filters` (
`AutoVideo` tinyint(3) unsigned NOT NULL default '0', `AutoVideo` tinyint(3) unsigned NOT NULL default '0',
`AutoUpload` tinyint(3) unsigned NOT NULL default '0', `AutoUpload` tinyint(3) unsigned NOT NULL default '0',
`AutoEmail` tinyint(3) unsigned NOT NULL default '0', `AutoEmail` tinyint(3) unsigned NOT NULL default '0',
`EmailTo` TEXT,
`EmailSubject` TEXT,
`EmailBody` TEXT,
`AutoMessage` tinyint(3) unsigned NOT NULL default '0', `AutoMessage` tinyint(3) unsigned NOT NULL default '0',
`AutoExecute` tinyint(3) unsigned NOT NULL default '0', `AutoExecute` tinyint(3) unsigned NOT NULL default '0',
`AutoExecuteCmd` tinytext, `AutoExecuteCmd` tinytext,
@ -403,7 +406,7 @@ DROP TABLE IF EXISTS `MonitorPresets`;
CREATE TABLE `MonitorPresets` ( CREATE TABLE `MonitorPresets` (
`Id` int(10) unsigned NOT NULL auto_increment, `Id` int(10) unsigned NOT NULL auto_increment,
`Name` varchar(64) NOT NULL default '', `Name` varchar(64) NOT NULL default '',
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket') NOT NULL default 'Local', `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket','VNC') NOT NULL default 'Local',
`Device` tinytext, `Device` tinytext,
`Channel` tinyint(3) unsigned default NULL, `Channel` tinyint(3) unsigned default NULL,
`Format` int(10) unsigned default NULL, `Format` int(10) unsigned default NULL,
@ -437,7 +440,7 @@ CREATE TABLE `Monitors` (
`Notes` TEXT, `Notes` TEXT,
`ServerId` int(10) unsigned, `ServerId` int(10) unsigned,
`StorageId` smallint(5) unsigned default 0, `StorageId` smallint(5) unsigned default 0,
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket') NOT NULL default 'Local', `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite','NVSocket','VNC') NOT NULL default 'Local',
`Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor', `Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor',
`Enabled` tinyint(3) unsigned NOT NULL default '1', `Enabled` tinyint(3) unsigned NOT NULL default '1',
`LinkedMonitors` varchar(255), `LinkedMonitors` varchar(255),
@ -730,13 +733,14 @@ CREATE TABLE `Storage` (
`Scheme` enum('Deep','Medium','Shallow') NOT NULL default 'Medium', `Scheme` enum('Deep','Medium','Shallow') NOT NULL default 'Medium',
`ServerId` int(10) unsigned, `ServerId` int(10) unsigned,
`DoDelete` BOOLEAN NOT NULL DEFAULT true, `DoDelete` BOOLEAN NOT NULL DEFAULT true,
`Enabled` BOOLEAN NOT NULL DEFAULT true,
PRIMARY KEY (`Id`) PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@; ) ENGINE=@ZM_MYSQL_ENGINE@;
-- --
-- Create a default storage location -- Create a default storage location
-- --
insert into Storage VALUES (NULL, '@ZM_DIR_EVENTS@', 'Default', 'local', NULL, NULL, 'Medium', 0, true ); insert into Storage VALUES (NULL, '@ZM_DIR_EVENTS@', 'Default', 'local', NULL, NULL, 'Medium', 0, true, true );
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
@ -759,18 +763,91 @@ insert into Users VALUES (NULL,'admin','$2b$12$NHZsm6AM2f2LQVROriz79ul3D6DnmFiZC
-- Add a sample filter to purge the oldest 100 events when the disk is 95% full -- Add a sample filter to purge the oldest 100 events when the disk is 95% full
-- --
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}', INSERT INTO `Filters`
(
`Name`,
`Query_json`,
`AutoArchive`,
`AutoVideo`,
`AutoUpload`,
`AutoEmail`,
`EmailTo`,
`EmailSubject`,
`EmailBody`,
`AutoMessage`,
`AutoExecute`,
`AutoExecuteCmd`,
`AutoDelete`,
`AutoMove`,
`AutoMoveTo`,
`AutoCopy`,
`AutoCopyTo`,
`UpdateDiskSpace`,
`Background`,
`Concurrent`
)
VALUES
(
'PurgeWhenFull',
'{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',
0/*AutoArchive*/, 0/*AutoArchive*/,
0/*AutoVideo*/, 0/*AutoVideo*/,
0/*AutoUpload*/, 0/*AutoUpload*/,
0/*AutoEmail*/, 0/*AutoEmail*/,
''/*EmailTo*/,
''/*EmailSubject*/,
''/*EmailBody*/,
0/*AutoMessage*/, 0/*AutoMessage*/,
0/*AutoExecute*/,'', 0/*AutoExecute*/,'',
1/*AutoDelete*/, 1/*AutoDelete*/,
0/*AutoMove*/,0/*MoveTo*/, 0/*AutoMove*/,0/*MoveTo*/,
0/*AutoCopy*/,0/*CopyTo*/, 0/*AutoCopy*/,0/*CopyTo*/,
0/*UpdateDiskSpace*/,1/*Background*/,0/*Concurrent*/); 0/*UpdateDiskSpace*/,
insert into Filters values (NULL,'Update DiskSpace','{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',0,0,0,0,0,0,'',0,0,0,0,0,1,1,0); 1/*Background*/,
0/*Concurrent*/
);
INSERT INTO `Filters`
(
`Name`,
`Query_json`,
`AutoArchive`,
`AutoVideo`,
`AutoUpload`,
`AutoEmail`,
`EmailTo`,
`EmailSubject`,
`EmailBody`,
`AutoMessage`,
`AutoExecute`,
`AutoExecuteCmd`,
`AutoDelete`,
`AutoMove`,
`AutoMoveTo`,
`AutoCopy`,
`AutoCopyTo`,
`UpdateDiskSpace`,
`Background`,
`Concurrent`
)
VALUES (
'Update DiskSpace',
'{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',
0/*AutoArchive*/,
0/*AutoVideo*/,
0/*AutoUpload*/,
0/*AutoEmail*/,
''/*EmailTo*/,
''/*EmailSubject*/,
''/*EmailBody*/,
0/*AutoMessage*/,
0/*AutoExecute*/,'',
0/*AutoDelete*/,
0/*AutoMove*/,0/*MoveTo*/,
0/*AutoCopy*/,0/*CopyTo*/,
1/*UpdateDiskSpace*/,
1/*Background*/,
0/*Concurrent*/
);
-- --
-- Add in some sample control protocol definitions -- Add in some sample control protocol definitions
@ -820,6 +897,9 @@ INSERT INTO `Controls` VALUES (NULL,'Amcrest HTTP API','Ffmpeg','Amcrest_HTTP',0
-- --
-- Add some monitor preset values -- Add some monitor preset values
-- --
INSERT into MonitorPresets VALUES (NULL,'Amcrest, IP8M-T2499EW 640x480, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp','NULL',554,'rtsp://<username>:<password>@<ip-address>/cam/realmonitor?channel=1&subtype=1',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'Amcrest, IP8M-T2499EW 3840x2160, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp','NULL',554,'rtsp://<username>:<password>@<ip-address>/cam/realmonitor?channel=1&subtype=0',NULL,3840,2160,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100); INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100); INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100); INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);

41
db/zm_update-1.35.0.sql Normal file
View File

@ -0,0 +1,41 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'EmailTo'
) > 0,
"SELECT 'Column EmailTo already exists in Filters'",
"ALTER TABLE `Filters` ADD `EmailTo` TEXT AFTER `AutoEmail`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
UPDATE Filters SET EmailTo=(SELECT Value FROM Config WHERE Name='ZM_EMAIL_ADDRESS') WHERE AutoEmail=1;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'EmailSubject'
) > 0,
"SELECT 'Column EmailSubject already exists in Filters'",
"ALTER TABLE `Filters` ADD `EmailSubject` TEXT AFTER `EmailTo`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
UPDATE Filters SET EmailSubject=(SELECT Value FROM Config WHERE Name='ZM_EMAIL_SUBJECT') WHERE AutoEmail=1;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'EmailBody'
) > 0,
"SELECT 'Column EmailBody already exists in Filters'",
"ALTER TABLE `Filters` ADD `EmailBody` TEXT AFTER `EmailSubject`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
UPDATE Filters SET EmailBody=(SELECT Value FROM Config WHERE Name='ZM_EMAIL_BODY') WHERE AutoEmail=1;

12
db/zm_update-1.35.1.sql Normal file
View File

@ -0,0 +1,12 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Storage'
AND column_name = 'Enabled'
) > 0,
"SELECT 'Column Enabled already exists in Storage'",
"ALTER TABLE `Storage` ADD `Enabled` BOOLEAN NOT NULL default true AFTER `DoDelete`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

1
db/zm_update-1.35.2.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE Monitors MODIFY `Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL','NVSocket','VNC') NOT NULL default 'Local';

View File

@ -28,7 +28,7 @@
%global _hardened_build 1 %global _hardened_build 1
Name: zoneminder Name: zoneminder
Version: 1.34.9 Version: 1.35.2
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

View File

@ -33,6 +33,7 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa
,libssl-dev ,libssl-dev
,libcrypt-eksblowfish-perl ,libcrypt-eksblowfish-perl
,libdata-entropy-perl ,libdata-entropy-perl
,libvncserver-dev
# Unbundled (dh_linktree): # Unbundled (dh_linktree):
,libjs-jquery ,libjs-jquery
,libjs-mootools ,libjs-mootools
@ -82,6 +83,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,libssl | libssl1.0.0 | libssl1.1 ,libssl | libssl1.0.0 | libssl1.1
,libcrypt-eksblowfish-perl ,libcrypt-eksblowfish-perl
,libdata-entropy-perl ,libdata-entropy-perl
,libvncclient1
Recommends: ${misc:Recommends} Recommends: ${misc:Recommends}
,libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm ,libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm
,mysql-server | mariadb-server | virtual-mysql-server ,mysql-server | mariadb-server | virtual-mysql-server

View File

@ -482,6 +482,7 @@ Create a Zone
&Zone[Units]=Percent\ &Zone[Units]=Percent\
&Zone[NumCoords]=4\ &Zone[NumCoords]=4\
&Zone[Coords]=0,0 639,0 639,479 0,479\ &Zone[Coords]=0,0 639,0 639,479 0,479\
&Zone[Area]=307200\
&Zone[AlarmRGB]=16711680\ &Zone[AlarmRGB]=16711680\
&Zone[CheckMethod]=Blobs\ &Zone[CheckMethod]=Blobs\
&Zone[MinPixelThreshold]=25\ &Zone[MinPixelThreshold]=25\

View File

@ -68,9 +68,13 @@ Here is what the filter window looks like
* %ESM% Maximum score of the event * %ESM% Maximum score of the event
* %EP% Path to the event * %EP% Path to the event
* %EPS% Path to the event stream * %EPS% Path to the event stream
* %EPF1% Path to the frame view for the first alarmed event image
* %EPFM% Path to the frame view for the (first) event image with the highest score
* %EFMOD% Path to image containing object detection, in frame view
* %EPI% Path to the event images * %EPI% Path to the event images
* %EPI1% Path to the first alarmed event image * %EPI1% Path to the first alarmed event image, suitable for use in img tags
* %EPIM% Path to the (first) event image with the highest score * %EPIM% Path to the (first) event image with the highest score, suitable for use in img tags
* %EIMOD% Path to image containing object detection, suitable for use in img tags
* %EI1% Attach first alarmed event image * %EI1% Attach first alarmed event image
* %EIM% Attach (first) event image with the highest score * %EIM% Attach (first) event image with the highest score
* %EV% Attach event mpeg video * %EV% Attach event mpeg video
@ -81,7 +85,6 @@ Here is what the filter window looks like
* %MEW% Number of events for the monitor in the last week * %MEW% Number of events for the monitor in the last week
* %MEM% Number of events for the monitor in the last month * %MEM% Number of events for the monitor in the last month
* %MEA% Number of archived events for the monitor * %MEA% Number of archived events for the monitor
* %MOD% Path to image containing object detection
* %MP% Path to the monitor window * %MP% Path to the monitor window
* %MPS% Path to the monitor stream * %MPS% Path to the monitor stream
* %MPI% Path to the monitor recent image * %MPI% Path to the monitor recent image

View File

@ -43,7 +43,7 @@ my %message_of :ATTR(:name<message> :default<()>);
my %is_success_of :ATTR(:name<is_success> :default<()>); my %is_success_of :ATTR(:name<is_success> :default<()>);
my %local_addr_of :ATTR(:name<local_addr> :init_arg<local_addr> :default<()>); my %local_addr_of :ATTR(:name<local_addr> :init_arg<local_addr> :default<()>);
my $net_interface;
# create methods normally inherited from SOAP::Client # create methods normally inherited from SOAP::Client
SUBFACTORY: { SUBFACTORY: {
@ -60,14 +60,22 @@ sub _notify_response
} }
sub set_net_interface {
my $self = shift;
$net_interface = shift;
}
sub send_multi() { sub send_multi() {
my ($self, $address, $port, $utf8_string) = @_; my ($self, $address, $port, $utf8_string) = @_;
my $destination = $address . ':' . $port; my $destination = $address . ':' . $port;
my $socket = IO::Socket::Multicast->new(PROTO => 'udp', my $socket = IO::Socket::Multicast->new(
LocalPort=>$port, PeerAddr=>$destination, ReuseAddr=>1) PROTO => 'udp',
LocalPort=>$port,
or die 'Cannot open multicast socket to ' . ${address} . ':' . ${port}; PeerAddr=>$destination,
ReuseAddr=>1
) or die 'Cannot open multicast socket to ' . ${address} . ':' . ${port};
$_ = $socket->mcast_if($net_interface) if $net_interface;
my $bytes = $utf8_string; my $bytes = $utf8_string;
utf8::encode($bytes); utf8::encode($bytes);
@ -80,14 +88,16 @@ sub receive_multi() {
my ($self, $address, $port) = @_; my ($self, $address, $port) = @_;
my $data = undef; my $data = undef;
my $socket = IO::Socket::Multicast->new(PROTO => 'udp', my $socket = IO::Socket::Multicast->new(
LocalPort=>$port, ReuseAddr=>1); PROTO => 'udp',
$socket->mcast_add($address); LocalPort=>$port,
ReuseAddr=>1);
$socket->mcast_add($address, $net_interface);
my $readbits = ''; my $readbits = '';
vec($readbits, $socket->fileno, 1) = 1; vec($readbits, $socket->fileno, 1) = 1;
if(select($readbits, undef, undef, WAIT_TIME/1000)) { if ( select($readbits, undef, undef, WAIT_TIME/1000) ) {
$socket->recv($data, 9999); $socket->recv($data, 9999);
return $data; return $data;
} }
@ -98,15 +108,19 @@ sub receive_uni() {
my ($self, $address, $port, $localaddr) = @_; my ($self, $address, $port, $localaddr) = @_;
my $data = undef; my $data = undef;
my $socket = IO::Socket::Multicast->new(PROTO => 'udp', my $socket = IO::Socket::Multicast->new(
LocalAddr => $localaddr, LocalPort=>$port, ReuseAddr=>1); PROTO => 'udp',
LocalAddr => $localaddr,
LocalPort=>$port,
ReuseAddr=>1
);
$socket->mcast_add($address); $socket->mcast_add($address, $net_interface);
my $readbits = ''; my $readbits = '';
vec($readbits, $socket->fileno, 1) = 1; vec($readbits, $socket->fileno, 1) = 1;
if(select($readbits, undef, undef, WAIT_TIME/1000)) { if ( select($readbits, undef, undef, WAIT_TIME/1000) ) {
$socket->recv($data, 9999); $socket->recv($data, 9999);
return $data; return $data;
} }
@ -120,39 +134,39 @@ sub send_receive {
my ($address,$port) = ($endpoint =~ /([^:\/]+):([0-9]+)/); my ($address,$port) = ($endpoint =~ /([^:\/]+):([0-9]+)/);
#warn "address = ${address}"; #warn "address = ${address}";
#warn "port = ${port}"; #warn "port = ${port}";
$self->send_multi($address, $port, $envelope); $self->send_multi($address, $port, $envelope);
my $localaddr = $self->get_local_addr(); my $localaddr = $self->get_local_addr();
#warn "localddr $localaddr";
my ($response, $last_response); my ($response, $last_response);
my $wait = WAIT_COUNT; my $wait = WAIT_COUNT;
while ( $wait >= 0 ) { while ( $wait >= 0 ) {
if($localaddr) { if ( $localaddr ) {
if($response = $self->receive_uni($address, $port, $localaddr)) { if ( $response = $self->receive_uni($address, $port, $localaddr) ) {
$last_response = $response; $last_response = $response;
$self->_notify_response($response); $self->_notify_response($response);
} }
$wait --; $wait --;
} }
if($response = $self->receive_multi($address, $port)) { if ( $response = $self->receive_multi($address, $port) ) {
$last_response = $response; $last_response = $response;
$self->_notify_response($response); $self->_notify_response($response);
} }
$wait --; $wait --;
} }
if($last_response) { if ( $last_response ) {
$self->set_code(); $self->set_code();
$self->set_message(""); $self->set_message('');
$self->set_is_success(1); $self->set_is_success(1);
$self->set_status('OK'); $self->set_status('OK');
} } else {
else{
$self->set_code(); $self->set_code();
$self->set_message("Timed out waiting for response"); $self->set_message('Timed out waiting for response');
$self->set_is_success(0); $self->set_is_success(0);
$self->set_status('TIMEOUT'); $self->set_status('TIMEOUT');
} }
@ -161,3 +175,4 @@ sub send_receive {
} }
1; 1;
__END__

View File

@ -2213,7 +2213,7 @@ our @options = (
that match the appropriate filters will be sent to. that match the appropriate filters will be sent to.
`, `,
type => $types{email}, type => $types{email},
category => 'mail', category => 'hidden',
}, },
{ {
name => 'ZM_EMAIL_TEXT', name => 'ZM_EMAIL_TEXT',
@ -2253,7 +2253,7 @@ our @options = (
sent for any events that match the appropriate filters. sent for any events that match the appropriate filters.
`, `,
type => $types{string}, type => $types{string},
category => 'mail', category => 'hidden',
}, },
{ {
name => 'ZM_EMAIL_BODY', name => 'ZM_EMAIL_BODY',
@ -2280,7 +2280,7 @@ our @options = (
sent for any events that match the appropriate filters. sent for any events that match the appropriate filters.
`, `,
type => $types{text}, type => $types{text},
category => 'mail', category => 'hidden',
}, },
{ {
name => 'ZM_OPT_MESSAGE', name => 'ZM_OPT_MESSAGE',

View File

@ -1,6 +1,6 @@
# ========================================================================== # ==========================================================================
# #
# ZoneMinder Base Control Module, $Date$, $Revision$ # ZoneMinder Base Control Module
# Copyright (C) 2001-2008 Philip Coombes # Copyright (C) 2001-2008 Philip Coombes
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
@ -46,13 +46,13 @@ our $AUTOLOAD;
sub new { sub new {
my $class = shift; my $class = shift;
my $id = shift; my $id = shift;
if ( !defined($id) ) {
Fatal('No monitor defined when invoking protocol '.$class);
}
my $self = {}; my $self = {};
$self->{name} = $class; $self->{name} = $class;
if ( !defined($id) ) {
Fatal('No monitor defined when invoking protocol '.$self->{name});
}
$self->{id} = $id; $self->{id} = $id;
bless( $self, $class ); bless($self, $class);
return $self; return $self;
} }
@ -78,7 +78,7 @@ sub AUTOLOAD {
sub getKey { sub getKey {
my $self = shift; my $self = shift;
return( $self->{id} ); return $self->{id};
} }
sub open { sub open {

View File

@ -46,96 +46,54 @@ use ZoneMinder::Config qw(:all);
use Time::HiRes qw( usleep ); use Time::HiRes qw( usleep );
sub new sub open {
{
my $class = shift;
my $id = shift;
my $self = ZoneMinder::Control->new( $id );
bless( $self, $class );
srand( time() );
return $self;
}
our $AUTOLOAD;
sub AUTOLOAD
{
my $self = shift;
my $class = ref($self) || croak( "$self not object" );
my $name = $AUTOLOAD;
$name =~ s/.*://;
if ( exists($self->{$name}) )
{
return( $self->{$name} );
}
Fatal( "Can't access $name member of object of class $class" );
}
sub open
{
my $self = shift; my $self = shift;
$self->loadMonitor(); $self->loadMonitor();
use LWP::UserAgent; use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new; $self->{ua} = LWP::UserAgent->new;
$self->{ua}->agent( "ZoneMinder Control Agent/" . ZoneMinder::Base::ZM_VERSION ); $self->{ua}->agent('ZoneMinder Control Agent/' . ZoneMinder::Base::ZM_VERSION);
$self->{state} = 'open'; $self->{state} = 'open';
} }
sub close sub close {
{
my $self = shift; my $self = shift;
$self->{state} = 'closed'; $self->{state} = 'closed';
} }
sub printMsg sub sendCmd {
{
my $self = shift;
my $msg = shift;
my $msg_len = length($msg);
Debug( $msg."[".$msg_len."]" );
}
sub sendCmd
{
my $self = shift; my $self = shift;
my $cmd = shift; my $cmd = shift;
my $cgi = shift; my $cgi = shift;
my $result = undef; my $result = undef;
printMsg( $cmd, "Tx" ); printMsg($cmd, 'Tx');
my $req = HTTP::Request->new( POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi" ); my $req = HTTP::Request->new( POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi" );
$req->content($cmd); $req->content($cmd);
my $res = $self->{ua}->request($req); my $res = $self->{ua}->request($req);
if ( $res->is_success ) if ( $res->is_success ) {
{
$result = !undef; $result = !undef;
} } else {
else Error("Error check failed: '".$res->status_line()."'");
{
Error( "Error check failed: '".$res->status_line()."'" );
} }
return( $result ); return $result;
} }
sub move sub move {
{
my $self = shift; my $self = shift;
my $dir = shift; my $dir = shift;
my $panStep = shift; my $panStep = shift;
my $tiltStep = shift; my $tiltStep = shift;
my $cmd = "PanSingleMoveDegree=$panStep&TiltSingleMoveDegree=$tiltStep&PanTiltSingleMove=$dir"; my $cmd = "PanSingleMoveDegree=$panStep&TiltSingleMoveDegree=$tiltStep&PanTiltSingleMove=$dir";
$self->sendCmd( $cmd, 'pantiltcontrol' ); $self->sendCmd($cmd, 'pantiltcontrol');
} }
sub moveRel sub moveRel {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
my $panStep = $self->getParam($params, 'panstep', 0); my $panStep = $self->getParam($params, 'panstep', 0);
@ -144,66 +102,57 @@ sub moveRel
$self->move( $dir, $panStep, $tiltStep ); $self->move( $dir, $panStep, $tiltStep );
} }
sub moveRelUpLeft sub moveRelUpLeft {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 0 ); $self->moveRel($params, 0);
} }
sub moveRelUp sub moveRelUp {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 1 ); $self->moveRel($params, 1);
} }
sub moveRelUpRight sub moveRelUpRight {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 2 ); $self->moveRel($params, 2);
} }
sub moveRelLeft sub moveRelLeft {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 3 ); $self->moveRel($params, 3);
} }
sub moveRelRight sub moveRelRight {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 5 ); $self->moveRel($params, 5);
} }
sub moveRelDownLeft sub moveRelDownLeft {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 6 ); $self->moveRel($params, 6);
} }
sub moveRelDown sub moveRelDown {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 7 ); $self->moveRel($params, 7);
} }
sub moveRelDownRight sub moveRelDownRight {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
$self->moveRel( $params, 8 ); $self->moveRel($params, 8);
} }
# moves the camera to center on the point that the user clicked on in the video image. # moves the camera to center on the point that the user clicked on in the video image.
# This isn't extremely accurate but good enough for most purposes # This isn't extremely accurate but good enough for most purposes
sub moveMap sub moveMap {
{
# if the camera moves too much or too little, try increasing or decreasing this value # if the camera moves too much or too little, try increasing or decreasing this value
my $f = 11; my $f = 11;
@ -241,12 +190,11 @@ sub moveMap
} }
my $v = int($verSteps + .5); my $v = int($verSteps + .5);
my $h = int($horSteps + .5); my $h = int($horSteps + .5);
Debug( "Move Map to $xcoord,$ycoord, hor=$h, ver=$v with direction $direction" ); Debug("Move Map to $xcoord,$ycoord, hor=$h, ver=$v with direction $direction");
$self->move( $direction, $h, $v ); $self->move($direction, $h, $v);
} }
sub presetClear sub presetClear {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
my $preset = $self->getParam( $params, 'preset' ); my $preset = $self->getParam( $params, 'preset' );
@ -255,8 +203,7 @@ sub presetClear
$self->sendCmd( $cmd, 'pantiltcontrol' ); $self->sendCmd( $cmd, 'pantiltcontrol' );
} }
sub presetSet sub presetSet {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
my $preset = $self->getParam( $params, 'preset' ); my $preset = $self->getParam( $params, 'preset' );
@ -265,8 +212,7 @@ sub presetSet
$self->sendCmd( $cmd, 'pantiltcontrol' ); $self->sendCmd( $cmd, 'pantiltcontrol' );
} }
sub presetGoto sub presetGoto {
{
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
my $preset = $self->getParam( $params, 'preset' ); my $preset = $self->getParam( $params, 'preset' );
@ -275,14 +221,12 @@ sub presetGoto
$self->sendCmd( $cmd, 'pantiltcontrol' ); $self->sendCmd( $cmd, 'pantiltcontrol' );
} }
sub presetHome sub presetHome {
{
my $self = shift; my $self = shift;
Debug( "Home Preset" ); Debug( "Home Preset" );
$self->move( 4, 0, 0 ); $self->move( 4, 0, 0 );
} }
# IR Controls # IR Controls
# #
# wake = IR on # wake = IR on
@ -293,37 +237,33 @@ sub setDayNightMode {
my $self = shift; my $self = shift;
my $mode = shift; my $mode = shift;
my $cmd = "DayNightMode=$mode&ConfigReboot=No"; my $cmd = "DayNightMode=$mode&ConfigReboot=No";
$self->sendCmd( $cmd, 'daynight' ); $self->sendCmd($cmd, 'daynight');
} }
sub wake sub wake {
{
my $self = shift; my $self = shift;
Debug( "Wake - IR on" ); Debug('Wake - IR on');
$self->setDayNightMode(2); $self->setDayNightMode(2);
} }
sub sleep sub sleep {
{
my $self = shift; my $self = shift;
Debug( "Sleep - IR off" ); Debug('Sleep - IR off');
$self->setDayNightMode(3); $self->setDayNightMode(3);
} }
sub reset sub reset {
{
my $self = shift; my $self = shift;
Debug( "Reset - IR auto" ); Debug('Reset - IR auto');
$self->setDayNightMode(0); $self->setDayNightMode(0);
} }
1; 1;
__END__ __END__
# Below is stub documentation for your module. You'd better edit it!
=head1 NAME =head1 NAME
ZoneMinder::Database - Perl extension for DCS-5020L ZoneMinder::Control::DCS5020L - Perl extension for DCS-5020L
=head1 SYNOPSIS =head1 SYNOPSIS
@ -351,6 +291,20 @@ Art Scheel <lt>ascheel (at) gmail<gt>
=head1 COPYRIGHT AND LICENSE =head1 COPYRIGHT AND LICENSE
LGPLv3 Copyright (C) 2018 ZoneMinder LLC
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
=cut =cut

View File

@ -1,6 +1,6 @@
# ========================================================================== # ==========================================================================
# #
# ZoneMinder Filter Module, $Date$, $Revision$ # ZoneMinder Filter Module
# Copyright (C) 2001-2008 Philip Coombes # Copyright (C) 2001-2008 Philip Coombes
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
@ -162,7 +162,9 @@ sub Sql {
my $value = $term->{val}; my $value = $term->{val};
my @value_list; my @value_list;
if ( $term->{attr} ) { if ( $term->{attr} ) {
if ( $term->{attr} =~ /^Monitor/ ) { if ( $term->{attr} eq 'AlarmedZoneId' ) {
$term->{op} = 'EXISTS';
} elsif ( $term->{attr} =~ /^Monitor/ ) {
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/; my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
$self->{Sql} .= 'M.'.$temp_attr_name; $self->{Sql} .= 'M.'.$temp_attr_name;
} elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) { } elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) {
@ -214,7 +216,10 @@ sub Sql {
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/; ( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) { foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
if ( $term->{attr} =~ /^MonitorName/ ) {
if ( $term->{attr} eq 'AlarmedZoneId' ) {
$value = '(SELECT * FROM Stats WHERE EventId=E.Id AND ZoneId='.$value.')';
} elsif ( $term->{attr} =~ /^MonitorName/ ) {
$value = "'$temp_value'"; $value = "'$temp_value'";
} elsif ( $term->{attr} =~ /ServerId/) { } elsif ( $term->{attr} =~ /ServerId/) {
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})"); Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
@ -256,6 +261,8 @@ sub Sql {
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) { } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
if ( $temp_value eq 'NULL' ) { if ( $temp_value eq 'NULL' ) {
$value = $temp_value; $value = $temp_value;
} elsif ( $temp_value eq 'CURDATE()' or $temp_value eq 'NOW()' ) {
$value = 'to_days('.$temp_value.')';
} else { } else {
$value = DateTimeToSQL($temp_value); $value = DateTimeToSQL($temp_value);
if ( !$value ) { if ( !$value ) {
@ -294,6 +301,8 @@ sub Sql {
} else { } else {
$self->{Sql} .= " IS $value"; $self->{Sql} .= " IS $value";
} }
} elsif ( $term->{op} eq 'EXISTS' ) {
$self->{Sql} .= " EXISTS $value";
} elsif ( $term->{op} eq 'IS NOT' ) { } elsif ( $term->{op} eq 'IS NOT' ) {
$self->{Sql} .= " IS NOT $value"; $self->{Sql} .= " IS NOT $value";
} elsif ( $term->{op} eq '=[]' ) { } elsif ( $term->{op} eq '=[]' ) {

View File

@ -172,7 +172,7 @@ sub interpret_messages {
# functions # functions
sub discover { sub discover {
my ( $soap_version ) = @_; my ( $soap_version, $net_interface ) = @_;
my @results; my @results;
## collect all responses ## collect all responses
@ -192,13 +192,18 @@ sub discover {
if ( ( ! $soap_version ) or ( $soap_version eq '1.1' ) ) { if ( ( ! $soap_version ) or ( $soap_version eq '1.1' ) ) {
my %services; my %services;
if($verbose) { if ( $verbose ) {
print "Probing for SOAP 1.1\n" print "Probing for SOAP 1.1\n";
} }
my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({ my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({
# no_dispatch => '1', # no_dispatch => '1',
}); });
$svc_discover->set_soap_version('1.1'); $svc_discover->set_soap_version('1.1');
if ( $net_interface ) {
my $transport = $svc_discover->get_transport();
print "Setting net interface for $transport to $net_interface\n";
$transport->set_net_interface($net_interface);
}
my $uuid = $uuid_gen->create_str(); my $uuid = $uuid_gen->create_str();
@ -221,13 +226,18 @@ sub discover {
if ( ( ! $soap_version ) or ( $soap_version eq '1.2' ) ) { if ( ( ! $soap_version ) or ( $soap_version eq '1.2' ) ) {
my %services; my %services;
if($verbose) { if ( $verbose ) {
print "Probing for SOAP 1.2\n" print "Probing for SOAP 1.2\n";
} }
my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({ my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({
# no_dispatch => '1', # no_dispatch => '1',
}); });
$svc_discover->set_soap_version('1.2'); $svc_discover->set_soap_version('1.2');
if ( $net_interface ) {
my $transport = $svc_discover->get_transport();
print "Setting net interface for $transport to $net_interface\n";
$transport->set_net_interface($net_interface);
}
# copies of the same Probe message must have the same MessageID. # copies of the same Probe message must have the same MessageID.
# This is not a copy. So we generate a new uuid. # This is not a copy. So we generate a new uuid.
@ -250,7 +260,7 @@ sub discover {
push @results, interpret_messages($svc_discover, \%services, @responses); push @results, interpret_messages($svc_discover, \%services, @responses);
} # end if doing soap 1.2 } # end if doing soap 1.2
return @results; return @results;
} } # end sub discover
sub profiles { sub profiles {
my ( $client ) = @_; my ( $client ) = @_;

View File

@ -352,9 +352,13 @@ sub exportsql {
} }
my $name = $ARGV[0]; my $name = $ARGV[0];
if ($name && $name =~ /^([A-Za-z0-9 ,.&()\/\-]+)$/) { # Allow alphanumeric and " ,.&()/-" if ( $name ) {
if ( $name =~ /^([A-Za-z0-9 ,.&()\/\-]+)$/ ) { # Allow alphanumeric and " ,.&()/-"
$name = $1; $name = $1;
$command .= qq( --where="Name = '$name'"); $command .= qq( --where="Name = '$name'");
} else {
print "Invalid characters in Name\n";
}
} }
$command .= " zm Controls MonitorPresets"; $command .= " zm Controls MonitorPresets";

View File

@ -196,7 +196,7 @@ my $last_action = 0;
while( !$zm_terminate ) { while( !$zm_terminate ) {
my $now = time; my $now = time;
if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} ) { if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} ) {
Debug("Reloading filters"); Debug('Reloading filters');
$last_action = $now; $last_action = $now;
@filters = getFilters({ Name=>$filter_name, Id=>$filter_id }); @filters = getFilters({ Name=>$filter_name, Id=>$filter_id });
} }
@ -699,8 +699,10 @@ sub substituteTags {
$text =~ s/%ESM%/$Event->{MaxScore}/g; $text =~ s/%ESM%/$Event->{MaxScore}/g;
if ( $first_alarm_frame ) { if ( $first_alarm_frame ) {
$text =~ s/%EPI1%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$first_alarm_frame->{FrameId}/g; $text =~ s/%EPF1%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$first_alarm_frame->{FrameId}/g;
$text =~ s/%EPIM%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$max_alarm_frame->{FrameId}/g; $text =~ s/%EPFM%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$max_alarm_frame->{FrameId}/g;
$text =~ s/%EPI1%/$url?view=image&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$first_alarm_frame->{FrameId}/g;
$text =~ s/%EPIM%/$url?view=image&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$max_alarm_frame->{FrameId}/g;
if ( $attachments_ref ) { if ( $attachments_ref ) {
if ( $text =~ s/%EI1%//g ) { if ( $text =~ s/%EI1%//g ) {
my $path = generateImage($Event, $first_alarm_frame); my $path = generateImage($Event, $first_alarm_frame);
@ -748,13 +750,14 @@ sub substituteTags {
} }
} }
if ( $text =~ s/%EIMOD%//g ) { if ( $text =~ s/%EIMOD%//g or $text =~ s/%EFMOD%//g ) {
$text =~ s/%EIMOD%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=objdetect/g; $text =~ s/%EFMOD%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=objdetect/g;
$text =~ s/%EIMOD%/$url?view=image&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=objdetect/g;
my $path = $Event->Path().'/objdetect.jpg'; my $path = $Event->Path().'/objdetect.jpg';
if ( -e $path ) { if ( -e $path ) {
push @$attachments_ref, { type=>'image/jpeg', path=>$path }; push @$attachments_ref, { type=>'image/jpeg', path=>$path };
} else { } else {
Warning('No image for EIMOD at ' . $path); Warning('No image for MOD at '.$path);
} }
} }
@ -796,17 +799,17 @@ sub sendEmail {
Error('No from email address defined, not sending email'); Error('No from email address defined, not sending email');
return 0; return 0;
} }
if ( ! $Config{ZM_EMAIL_ADDRESS} ) { if ( ! $$filter{EmailTo} ) {
Error('No email address defined, not sending email'); Error('No email address defined, not sending email');
return 0; return 0;
} }
Info('Creating notification email'); Info('Creating notification email');
my $subject = substituteTags($Config{ZM_EMAIL_SUBJECT}, $filter, $Event); my $subject = substituteTags($$filter{EmailSubject}, $filter, $Event);
return 0 if !$subject; return 0 if !$subject;
my @attachments; my @attachments;
my $body = substituteTags($Config{ZM_EMAIL_BODY}, $filter, $Event, \@attachments); my $body = substituteTags($$filter{EmailBody}, $filter, $Event, \@attachments);
return 0 if !$body; return 0 if !$body;
Info("Sending notification email '$subject'"); Info("Sending notification email '$subject'");
@ -816,7 +819,7 @@ sub sendEmail {
### Create the multipart container ### Create the multipart container
my $mail = MIME::Lite->new ( my $mail = MIME::Lite->new (
From => $Config{ZM_FROM_EMAIL}, From => $Config{ZM_FROM_EMAIL},
To => $Config{ZM_EMAIL_ADDRESS}, To => $$filter{EmailTo},
Subject => $subject, Subject => $subject,
Type => 'multipart/mixed' Type => 'multipart/mixed'
); );
@ -826,14 +829,20 @@ sub sendEmail {
Data => $body Data => $body
); );
### Add the attachments ### Add the attachments
my $total_size = 0;
foreach my $attachment ( @attachments ) { foreach my $attachment ( @attachments ) {
Info( "Attaching '$attachment->{path}'" ); my $size = -s $attachment->{path};
$total_size += $size;
Info("Attaching '$attachment->{path}' which is $size bytes");
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Disposition => 'attachment' Disposition => 'attachment'
); );
} }
if ( $total_size > 10*1024*1024 ) {
Warning('Emails larger than 10Mb will often not be delivered! This one is '.int($total_size/(1024*1024)).'Mb');
}
### Send the Message ### Send the Message
if ( $Config{ZM_SSMTP_MAIL} ) { if ( $Config{ZM_SSMTP_MAIL} ) {
my $ssmtp_location = $Config{ZM_SSMTP_PATH}; my $ssmtp_location = $Config{ZM_SSMTP_PATH};
@ -849,7 +858,7 @@ sub sendEmail {
$mail->send(); $mail->send();
} else { } else {
### Send using SSMTP ### Send using SSMTP
$mail->send('sendmail', $ssmtp_location, $Config{ZM_EMAIL_ADDRESS}); $mail->send('sendmail', $ssmtp_location, $$filter{EmailTo});
} }
} else { } else {
MIME::Lite->send('smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60); MIME::Lite->send('smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60);
@ -858,19 +867,26 @@ sub sendEmail {
} else { } else {
my $mail = MIME::Entity->build( my $mail = MIME::Entity->build(
From => $Config{ZM_FROM_EMAIL}, From => $Config{ZM_FROM_EMAIL},
To => $Config{ZM_EMAIL_ADDRESS}, To => $$filter{EmailTo},
Subject => $subject, Subject => $subject,
Type => (($body=~/<html>/)?'text/html':'text/plain'), Type => (($body=~/<html/)?'text/html':'text/plain'),
Data => $body Data => $body
); );
my $total_size = 0;
foreach my $attachment ( @attachments ) { foreach my $attachment ( @attachments ) {
Info("Attaching '$attachment->{path}'"); my $size = -s $attachment->{path};
$total_size += $size;
Info("Attaching '$attachment->{path}' which is $size bytes");
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Encoding => 'base64' Encoding => 'base64'
); );
} # end foreach attachment
if ( $total_size > 10*1024*1024 ) {
Warning('Emails larger than 10Mb will often not be delivered! This one is '.int($total_size/(1024*1024)).'Mb');
} }
$mail->smtpsend(Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL}); $mail->smtpsend(Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL});
} }
@ -962,7 +978,7 @@ sub sendMessage {
From => $Config{ZM_FROM_EMAIL}, From => $Config{ZM_FROM_EMAIL},
To => $Config{ZM_MESSAGE_ADDRESS}, To => $Config{ZM_MESSAGE_ADDRESS},
Subject => $subject, Subject => $subject,
Type => (($body=~/<html>/)?'text/html':'text/plain'), Type => (($body=~/<html/)?'text/html':'text/plain'),
Data => $body Data => $body
); );

View File

@ -41,7 +41,7 @@ my $OPTIONS = 'v';
sub HELP_MESSAGE { sub HELP_MESSAGE {
my ($fh, $pkg, $ver, $opts) = @_; my ($fh, $pkg, $ver, $opts) = @_;
print $fh "Usage: " . __FILE__ . " [-v] probe <soap version>\n"; print $fh "Usage: " . __FILE__ . " [-v] probe <soap version> <network interface>\n";
print $fh " " . __FILE__ . " [-v] <command> <device URI> <soap version> <user> <password>\n"; print $fh " " . __FILE__ . " [-v] <command> <device URI> <soap version> <user> <password>\n";
print $fh <<EOF print $fh <<EOF
Commands are: Commands are:
@ -69,7 +69,7 @@ if ( !getopts($OPTIONS) ) {
my $action = shift; my $action = shift;
if(!defined $action) { if ( ! defined $action ) {
HELP_MESSAGE(\*STDOUT); HELP_MESSAGE(\*STDOUT);
exit(1); exit(1);
} }
@ -84,7 +84,8 @@ if ( defined $opt_v ) {
if ( $action eq 'probe' ) { if ( $action eq 'probe' ) {
my $soap_version = shift; my $soap_version = shift;
ZoneMinder::ONVIF::discover($soap_version); my $net_interface = shift;
ZoneMinder::ONVIF::discover($soap_version, $net_interface);
} else { } else {
# all other actions need URI and credentials # all other actions need URI and credentials
my $url_svc_device = shift @ARGV; my $url_svc_device = shift @ARGV;

View File

@ -214,7 +214,7 @@ sub getUUID {
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array(); $uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
$sth->finish(); $sth->finish();
$sql = q`UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`; $sql = q`UPDATE Config SET Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`;
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() ); $res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish(); $sth->finish();
@ -250,9 +250,9 @@ sub countQuery {
my $dbh = shift; my $dbh = shift;
my $table = shift; my $table = shift;
my $sql = "SELECT count(*) FROM $table"; my $sql = "SELECT count(*) FROM `$table`";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached($sql) or die "Can't prepare '$sql': ".$dbh->errstr();
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); my $res = $sth->execute() or die 'Can\'t execute: '.$sth->errstr();
my $count = $sth->fetchrow_array(); my $count = $sth->fetchrow_array();
$sth->finish(); $sth->finish();
@ -263,7 +263,7 @@ sub countQuery {
sub getMonitorRef { sub getMonitorRef {
my $dbh = shift; my $dbh = shift;
my $sql = 'SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors'; my $sql = 'SELECT `Id`,`Name`,`Type`,`Function`,`Width`,`Height`,`Colours`,`MaxFPS`,`AlarmMaxFPS` FROM `Monitors`';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({}); my $arrayref = $sth->fetchall_arrayref({});

View File

@ -847,9 +847,9 @@ if ( $version ) {
} }
$cascade = !undef; $cascade = !undef;
} }
if ( $cascade || $version eq "1.24.4" ) { if ( $cascade || $version eq '1.24.4' ) {
# Patch the database # Patch the database
patchDB( $dbh, "1.24.4" ); patchDB($dbh, '1.24.4');
# Copy the FTP specific values to the new general config # Copy the FTP specific values to the new general config
my $fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'"; my $fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'";
@ -863,12 +863,12 @@ if ( $version ) {
} }
$cascade = !undef; $cascade = !undef;
} }
if ( $cascade || $version lt "1.26.0" ) { if ( $cascade || $version lt '1.26.0' ) {
my $sth = $dbh->prepare_cached( 'select * from Monitors LIMIT 0,1' ); my $sth = $dbh->prepare_cached('SELECT * FROM Monitors LIMIT 0,1');
die "Error: " . $dbh->errstr . "\n" unless ($sth); die "Error: " . $dbh->errstr . "\n" unless ($sth);
die "Error: " . $sth->errstr . "\n" unless ($sth->execute); die "Error: " . $sth->errstr . "\n" unless ($sth->execute);
my $columns = $sth->{'NAME'}; my $columns = $sth->{NAME};
if ( ! grep(/^Colours$/, @$columns ) ) { if ( ! grep(/^Colours$/, @$columns ) ) {
$dbh->do(q{alter table Monitors add column `Colours` tinyint(3) unsigned NOT NULL default '1' after `Height`;}); $dbh->do(q{alter table Monitors add column `Colours` tinyint(3) unsigned NOT NULL default '1' after `Height`;});
} # end if } # end if
@ -898,28 +898,31 @@ if ( $version ) {
die "Should have found upgrade scripts at $updateDir\n"; die "Should have found upgrade scripts at $updateDir\n";
} # end if } # end if
my $sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_DYN_DB_VERSION'";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
foreach my $patch ( @files ) { foreach my $patch ( @files ) {
my ( $v ) = $patch =~ /^zm_update\-([\d\.]+)\.sql$/; my ( $v ) = $patch =~ /^zm_update\-([\d\.]+)\.sql$/;
#PP make sure we use version compare #PP make sure we use version compare
if ( version->parse('v' . $v) > version->parse('v' . $version) ) { if ( version->parse('v'.$v) > version->parse('v'.$version) ) {
print( "Upgrading DB to $v from $version\n" ); print("Upgrading DB to $v from $version\n");
patchDB( $dbh, $v ); if ( patchDB($dbh, $v) ) {
my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; my $res = $sth->execute($version) or die( "Can't execute: ".$sth->errstr() );
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); }
my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
#patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch ); #patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch );
} # end if newer version } # end if newer version
} # end foreach patchfile } # end foreach patchfile
$sth->finish();
$cascade = !undef; $cascade = !undef;
} # end if } # end if
if ( $cascade ) { if ( $cascade ) {
my $installed_version = ZM_VERSION; # This is basically here so that we don't need zm-update-blah.sql files for versions without db changes
my $sql = 'update Config set Value = ? where Name = ?'; my $sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = ?';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( "$installed_version", 'ZM_DYN_DB_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); $sth->execute(ZM_VERSION, 'ZM_DYN_DB_VERSION') or die( "Can't execute: ".$sth->errstr() );
$res = $sth->execute( "$installed_version", 'ZM_DYN_CURR_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); $sth->execute(ZM_VERSION, 'ZM_DYN_CURR_VERSION') or die( "Can't execute: ".$sth->errstr() );
$sth->finish(); $sth->finish();
} else { } else {
zmDbDisconnect(); zmDbDisconnect();
@ -930,41 +933,42 @@ if ( $version ) {
#my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); #my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
#my $res = $sth->execute( ) or die( "Can't execute: ".$sth->errstr() ); #my $res = $sth->execute( ) or die( "Can't execute: ".$sth->errstr() );
#$sth->finish(); #$sth->finish();
print( "\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n" ); print("\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n");
} } # end if version
zmDbDisconnect(); zmDbDisconnect();
exit( 0 ); exit(0);
sub patchDB_using_do { sub patchDB_using_do {
my ( $dbh, $version, $file ) = @_; my ( $dbh, $version, $file ) = @_;
open( my $fh, '<', $file ) or die "Unable to open $file $!"; open(my $fh, '<', $file) or die "Unable to open $file $!";
$/ = undef; $/ = undef;
my $sql = <$fh>; my $sql = <$fh>;
close $fh; close $fh;
if ( $sql ) { if ( $sql ) {
$dbh->{'AutoCommit'} = 0; $dbh->{AutoCommit} = 0;
$dbh->do($sql); $dbh->do($sql);
if ( $dbh->errstr() ) { if ( $dbh->errstr() ) {
$dbh->rollback(); $dbh->rollback();
die "Error: " . $dbh->errstr(). ". Rolled back.\n"; die 'Error: '.$dbh->errstr().". Rolled back.\n";
} # end if error } # end if error
my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; my $sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = \'ZM_DYN_DB_VERSION\'';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached($sql) or die "Can't prepare '$sql': ".$dbh->errstr();
my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); my $res = $sth->execute($version) or die 'Can\'t execute: '.$sth->errstr();
$sth->finish(); $sth->finish();
$dbh->{'AutoCommit'} = 1; $dbh->{AutoCommit} = 1;
} else { } else {
Warning("Empty db update file at $file"); Warning("Empty db update file at $file");
} }
} } # end sub patchDB_using_do
sub patchDB { sub patchDB {
my $dbh = shift; my $dbh = shift;
my $version = shift; my $version = shift;
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
my $command = 'mysql'; my $command = 'mysql';
if ( defined($portOrSocket) ) { if ( defined($portOrSocket) ) {
@ -988,39 +992,38 @@ sub patchDB {
} }
$command .= '/zm_update-'.$version.'.sql'; $command .= '/zm_update-'.$version.'.sql';
print( "Executing '$command'\n" ) if ( logDebugging() ); print("Executing '$command'\n") if logDebugging();
my $output = qx($command); my $output = qx($command);
my $status = $? >> 8; my $status = $? >> 8;
if ( $status || logDebugging() ) { if ( $status || logDebugging() ) {
chomp( $output ); chomp($output);
print( "Output: $output\n" ); print("Output: $output\n");
} }
if ( $status ) { if ( $status ) {
die( "Command '$command' exited with status: $status\n" ); die("Command '$command' exited with status: $status\n");
} }
print( "\nDatabase successfully upgraded to version $version.\n" ); print("\nDatabase successfully upgraded to version $version.\n");
} # end sub patchDB
}
sub migratePasswords { sub migratePasswords {
print ("Migratings passwords, if any...\n"); print ("Migratings passwords, if any...\n");
my $sql = "select * from Users"; my $sql = 'SELECT * FROM `Users`';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached($sql) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); my $res = $sth->execute() or die("Can't execute: ".$sth->errstr());
while( my $user = $sth->fetchrow_hashref() ) { while( my $user = $sth->fetchrow_hashref() ) {
my $scheme = substr($user->{Password}, 0, 1); my $scheme = substr($user->{Password}, 0, 1);
if ($scheme eq "*") { if ($scheme eq '*') {
print ("-->".$user->{Username}. " password will be migrated\n"); print ('-->'.$user->{Username}." password will be migrated\n");
my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8)); my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8));
my $settings = '$2a$10$'.$salt; my $settings = '$2a$10$'.$salt;
my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings); my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings);
my $new_pass_hash = "-ZM-".$pass_hash; my $new_pass_hash = '-ZM-'.$pass_hash;
$sql = "UPDATE Users SET PASSWORD=? WHERE Username=?"; $sql = 'UPDATE Users SET `Password`=? WHERE `Username`=?';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($new_pass_hash, $user->{Username}) or die( "Can't execute: ".$sth->errstr() ); my $res = $sth->execute($new_pass_hash, $user->{Username}) or die("Can't execute: ".$sth->errstr());
} }
} }
} } # end sub migratePasswords
sub migratePaths { sub migratePaths {

View File

@ -93,62 +93,54 @@ if ( $version ) {
exit(0); exit(0);
} }
die( 'No command given' ) unless( $command ); die 'No command given' unless $command;
die( 'No unit code given' ) die 'No unit code given'
unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) ); unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) );
if ( $command eq 'start' ) if ( $command eq 'start' ) {
{
X10Server::runServer(); X10Server::runServer();
exit(); exit();
} }
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) socket(CLIENT, PF_UNIX, SOCK_STREAM, 0)
or Fatal( "Can't open socket: $!" ); or Fatal("Can't open socket: $!");
my $saddr = sockaddr_un( SOCK_FILE ); my $saddr = sockaddr_un(SOCK_FILE);
if ( !connect( CLIENT, $saddr ) ) if ( !connect(CLIENT, $saddr) ) {
{
# The server isn't there # The server isn't there
print( "Unable to connect, starting server\n" ); print("Unable to connect, starting server\n");
close( CLIENT ); close(CLIENT);
if ( my $cpid = fork() ) if ( my $cpid = fork() ) {
{
# Parent process just sleep and fall through # Parent process just sleep and fall through
sleep( 2 ); sleep(2);
logReinit(); logReinit();
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) socket(CLIENT, PF_UNIX, SOCK_STREAM, 0)
or Fatal( "Can't open socket: $!" ); or Fatal("Can't open socket: $!");
connect( CLIENT, $saddr ) connect(CLIENT, $saddr)
or Fatal( "Can't connect: $!" ); or Fatal("Can't connect: $!");
} } elsif ( defined($cpid) ) {
elsif ( defined($cpid) )
{
setpgrp(); setpgrp();
logReinit(); logReinit();
X10Server::runServer(); X10Server::runServer();
} } else {
else Fatal("Can't fork: $!");
{
Fatal( "Can't fork: $!" );
} }
} }
# The server is there, connect to it # The server is there, connect to it
#print( "Writing commands\n" ); #print( "Writing commands\n" );
CLIENT->autoflush(); CLIENT->autoflush();
my $message = "$command"; my $message = $command;
$message .= ";$unit_code" if ( $unit_code ); $message .= ';'.$unit_code if $unit_code;
print( CLIENT $message ); print(CLIENT $message);
shutdown( CLIENT, 1 ); shutdown(CLIENT, 1);
while ( my $line = <CLIENT> ) while ( my $line = <CLIENT> ) {
{ chomp($line);
chomp( $line ); print("$line\n");
print( "$line\n" );
} }
close( CLIENT ); close(CLIENT);
#print( "Finished writing, bye\n" ); #print( "Finished writing, bye\n" );
exit; exit;
@ -178,73 +170,68 @@ our %monitor_hash;
our %device_hash; our %device_hash;
our %pending_tasks; our %pending_tasks;
sub runServer sub runServer {
{ Info('X10 server starting');
Info( "X10 server starting\n" );
socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) socket(SERVER, PF_UNIX, SOCK_STREAM, 0)
or Fatal( "Can't open socket: $!" ); or Fatal("Can't open socket: $!");
unlink( main::SOCK_FILE ); unlink(main::SOCK_FILE);
my $saddr = sockaddr_un( main::SOCK_FILE ); my $saddr = sockaddr_un(main::SOCK_FILE);
bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); bind(SERVER, $saddr) or Fatal("Can't bind: $!");
listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
$dbh = zmDbConnect(); $dbh = zmDbConnect();
$x10 = new X10::ActiveHome( port=>$Config{ZM_X10_DEVICE}, house_code=>$Config{ZM_X10_HOUSE_CODE}, debug=>0 ); $x10 = new X10::ActiveHome(
port=>$Config{ZM_X10_DEVICE},
house_code=>$Config{ZM_X10_HOUSE_CODE},
debug=>0
);
loadTasks(); loadTasks();
$x10->register_listener( \&x10listen ); $x10->register_listener(\&x10listen);
my $rin = ''; my $rin = '';
vec( $rin, fileno(SERVER),1) = 1; vec($rin, fileno(SERVER),1) = 1;
vec( $rin, $x10->select_fds(),1) = 1; vec($rin, $x10->select_fds(),1) = 1;
my $timeout = 0.2; my $timeout = 0.2;
#print( 'F:'.fileno(SERVER)."\n" ); #print( 'F:'.fileno(SERVER)."\n" );
my $reload = undef; my $reload = undef;
my $reload_count = 0; my $reload_count = 0;
my $reload_limit = $Config{ZM_X10_DB_RELOAD_INTERVAL} / $timeout; my $reload_limit = $Config{ZM_X10_DB_RELOAD_INTERVAL} / $timeout;
while( 1 ) while( 1 ) {
{ my $nfound = select(my $rout = $rin, undef, undef, $timeout);
my $nfound = select( my $rout = $rin, undef, undef, $timeout );
#print( "Off select, NF:$nfound, ER:$!\n" ); #print( "Off select, NF:$nfound, ER:$!\n" );
#print( vec( $rout, fileno(SERVER),1)."\n" ); #print( vec( $rout, fileno(SERVER),1)."\n" );
#print( vec( $rout, $x10->select_fds(),1)."\n" ); #print( vec( $rout, $x10->select_fds(),1)."\n" );
if ( $nfound > 0 ) if ( $nfound > 0 ) {
{ if ( vec($rout, fileno(SERVER),1) ) {
if ( vec( $rout, fileno(SERVER),1) ) my $paddr = accept(CLIENT, SERVER);
{
my $paddr = accept( CLIENT, SERVER );
my $message = <CLIENT>; my $message = <CLIENT>;
my ( $command, $unit_code ) = split( /;/, $message ); my ($command, $unit_code) = split(';', $message);
my $device; my $device;
if ( defined($unit_code) ) if ( defined($unit_code) ) {
{ if ( $unit_code < 1 || $unit_code > 16 ) {
if ( $unit_code < 1 || $unit_code > 16 ) dPrint(ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n");
{
dPrint( ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n" );
next; next;
} }
$device = $device_hash{$unit_code}; $device = $device_hash{$unit_code};
if ( !$device ) if ( !$device ) {
{ $device = $device_hash{$unit_code} = {
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), appliance=>$x10->Appliance(unit_code=>$unit_code),
status=>'unknown' status=>'unknown'
}; };
} }
} } # end if defined($unit_code)
my $result; my $result;
if ( $command eq 'on' ) if ( $command eq 'on' ) {
{
$result = $device->{appliance}->on(); $result = $device->{appliance}->on();
} } elsif ( $command eq 'off' ) {
elsif ( $command eq 'off' )
{
$result = $device->{appliance}->off(); $result = $device->{appliance}->off();
} }
#elsif ( $command eq 'dim' ) #elsif ( $command eq 'dim' )
@ -255,528 +242,425 @@ sub runServer
#{ #{
#$result = $device->{appliance}->bright(); #$result = $device->{appliance}->bright();
#} #}
elsif ( $command eq 'status' ) elsif ( $command eq 'status' ) {
{ if ( $device ) {
if ( $device ) dPrint(ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n");
{ } else {
dPrint( ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n" ); foreach my $unit_code ( sort( keys(%device_hash) ) ) {
}
else
{
foreach my $unit_code ( sort( keys(%device_hash) ) )
{
my $device = $device_hash{$unit_code}; my $device = $device_hash{$unit_code};
dPrint( ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n" ); dPrint(ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n");
} }
} }
} } elsif ( $command eq 'shutdown' ) {
elsif ( $command eq 'shutdown' )
{
last; last;
} else {
dPrint(ZoneMinder::Logger::ERROR, "Invalid command '$command'\n");
} }
else if ( defined($result) ) {
{ # FIXME
dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); if ( 1 || $result ) {
}
if ( defined($result) )
{
if ( 1 || $result )
{
$device->{status} = uc($command); $device->{status} = uc($command);
dPrint( ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n" ); dPrint(ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n");
#x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) );
} else {
dPrint(ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n");
} }
else } # end if defined result
{ close(CLIENT);
dPrint( ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n" ); } elsif ( vec($rout, $x10->select_fds(),1) ) {
}
}
close( CLIENT );
}
elsif ( vec( $rout, $x10->select_fds(),1) )
{
$x10->handle_input(); $x10->handle_input();
} else {
Fatal('Bogus descriptor');
} }
else } elsif ( $nfound < 0 ) {
{ if ( $! != EINTR ) {
Fatal( 'Bogus descriptor' ); Fatal("Can't select: $!");
} }
} } else {
elsif ( $nfound < 0 )
{
if ( $! != EINTR )
{
Fatal( "Can't select: $!" );
}
}
else
{
#print( "Select timed out\n" ); #print( "Select timed out\n" );
# Check for state changes # Check for state changes
foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) {
{
my $monitor = $monitor_hash{$monitor_id}; my $monitor = $monitor_hash{$monitor_id};
my $state = zmGetMonitorState( $monitor ); my $state = zmGetMonitorState($monitor);
if ( !defined($state) ) if ( !defined($state) ) {
{
$reload = !undef; $reload = !undef;
next; next;
} }
if ( defined( $monitor->{LastState} ) ) if ( defined( $monitor->{LastState} ) ) {
{
my $task_list; my $task_list;
if ( ($state == STATE_ALARM || $state == STATE_ALERT) if ( ($state == STATE_ALARM || $state == STATE_ALERT)
&& ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE) && ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE)
) # Gone into alarm state ) # Gone into alarm state
{ {
Debug( "Applying ON_list for $monitor_id\n" ); Debug("Applying ON_list for $monitor_id");
$task_list = $monitor->{'ON_list'}; $task_list = $monitor->{ON_list};
} } elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE)
elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE)
|| ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE)
) # Come out of alarm state ) # Come out of alarm state
{ {
Debug( "Applying OFF_list for $monitor_id\n" ); Debug("Applying OFF_list for $monitor_id");
$task_list = $monitor->{'OFF_list'}; $task_list = $monitor->{OFF_list};
}
if ( $task_list )
{
foreach my $task ( @$task_list )
{
processTask( $task );
} }
if ( $task_list ) {
foreach my $task ( @$task_list ) {
processTask($task);
} }
} }
} # end if defined laststate
$monitor->{LastState} = $state; $monitor->{LastState} = $state;
} } # end foreach monitor
# Check for pending tasks # Check for pending tasks
my $now = time(); my $now = time();
foreach my $activation_time ( sort(keys(%pending_tasks) ) ) foreach my $activation_time ( sort(keys(%pending_tasks) ) ) {
{
last if ( $activation_time > $now ); last if ( $activation_time > $now );
my $pending_list = $pending_tasks{$activation_time}; my $pending_list = $pending_tasks{$activation_time};
foreach my $task ( @$pending_list ) foreach my $task ( @$pending_list ) {
{ processTask($task);
processTask( $task );
} }
delete( $pending_tasks{$activation_time} ); delete $pending_tasks{$activation_time};
} }
if ( $reload || ++$reload_count >= $reload_limit ) if ( $reload or (++$reload_count >= $reload_limit) ) {
{
loadTasks(); loadTasks();
$reload = undef; $reload = undef;
$reload_count = 0; $reload_count = 0;
} }
} }
} }
Info( "X10 server exiting\n" ); Info("X10 server exiting");
close( SERVER ); close(SERVER);
exit(); exit();
} }
sub addToDeviceList sub addToDeviceList {
{
my $unit_code = shift; my $unit_code = shift;
my $event = shift; my $event = shift;
my $monitor = shift; my $monitor = shift;
my $function = shift; my $function = shift;
my $limit = shift; my $limit = shift;
Debug( "Adding to device list, uc:$unit_code, ev:$event, mo:" Debug("Adding to device list, uc:$unit_code, ev:$event, mo:"
.$monitor->{Id}.", fu:$function, li:$limit\n" .$monitor->{Id}.", fu:$function, li:$limit"
); );
my $device = $device_hash{$unit_code}; my $device = $device_hash{$unit_code};
if ( !$device ) if ( !$device ) {
{ $device = $device_hash{$unit_code} = {
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), appliance=>$x10->Appliance(unit_code=>$unit_code),
status=>'unknown' status=>'unknown'
}; };
} }
my $task = { type=>'device', my $task = {
type=>'device',
monitor=>$monitor, monitor=>$monitor,
address=>$device->{appliance}->address(), address=>$device->{appliance}->address(),
function=>$function function=>$function
}; };
if ( $limit )
{ if ( $limit ) {
$task->{limit} = $limit $task->{limit} = $limit
} }
my $task_list = $device->{$event.'_list'}; my $task_list = $device->{$event.'_list'};
if ( !$task_list ) if ( !$task_list ) {
{
$task_list = $device->{$event.'_list'} = []; $task_list = $device->{$event.'_list'} = [];
} }
push( @$task_list, $task ); push @$task_list, $task;
} } # end sub addToDeviceList
sub addToMonitorList sub addToMonitorList {
{
my $monitor = shift; my $monitor = shift;
my $event = shift; my $event = shift;
my $unit_code = shift; my $unit_code = shift;
my $function = shift; my $function = shift;
my $limit = shift; my $limit = shift;
Debug( "Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id} Debug("Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id}
.", fu:$function, li:$limit\n" .", fu:$function, li:$limit"
); );
my $device = $device_hash{$unit_code}; my $device = $device_hash{$unit_code};
if ( !$device ) if ( !$device ) {
{ $device = $device_hash{$unit_code} = {
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), appliance=>$x10->Appliance(unit_code=>$unit_code),
status=>'unknown' status=>'unknown'
}; };
} }
my $task = { type=>'monitor', my $task = {
type=>'monitor',
device=>$device, device=>$device,
id=>$monitor->{Id}, id=>$monitor->{Id},
function=>$function function=>$function
}; };
if ( $limit ) if ( $limit ) {
{
$task->{limit} = $limit; $task->{limit} = $limit;
} }
my $task_list = $monitor->{$event.'_list'}; my $task_list = $monitor->{$event.'_list'};
if ( !$task_list ) if ( !$task_list ) {
{
$task_list = $monitor->{$event.'_list'} = []; $task_list = $monitor->{$event.'_list'} = [];
} }
push( @$task_list, $task ); push @$task_list, $task;
} } # end sub addToMonitorList
sub loadTasks sub loadTasks {
{
%monitor_hash = (); %monitor_hash = ();
Debug( "Loading tasks\n" ); Debug('Loading tasks');
# Clear out all old device task lists # Clear out all old device task lists
foreach my $unit_code ( sort( keys(%device_hash) ) ) foreach my $unit_code ( sort keys(%device_hash) ) {
{
my $device = $device_hash{$unit_code}; my $device = $device_hash{$unit_code};
$device->{ON_list} = []; $device->{ON_list} = [];
$device->{OFF_list} = []; $device->{OFF_list} = [];
} }
my $sql = "SELECT M.*,T.* from Monitors as M my $sql = 'SELECT M.*,T.* FROM Monitors as M
INNER JOIN TriggersX10 as T on (M.Id = T.MonitorId) INNER JOIN TriggersX10 as T on (M.Id = T.MonitorId)
WHERE find_in_set( M.Function, 'Modect,Record,Mocord,Nodect' ) WHERE find_in_set(M.`Function`, \'Modect,Record,Mocord,Nodect\')
AND M.Enabled = 1 AND M.`Enabled` = 1
AND find_IN_set( 'X10', M.Triggers )" AND find_IN_set(\'X10\', M.Triggers)';
;
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() my $res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() ); or Fatal("Can't execute: ".$sth->errstr());
while( my $monitor = $sth->fetchrow_hashref() ) while( my $monitor = $sth->fetchrow_hashref() ) {
{ # Check shared memory ok
# Check shared memory ok if ( !zmMemVerify($monitor) ) {
if ( !zmMemVerify( $monitor ) ) { zmMemInvalidate($monitor);
zmMemInvalidate( $monitor ); next;
next ;
} }
$monitor_hash{$monitor->{Id}} = $monitor; $monitor_hash{$monitor->{Id}} = $monitor;
if ( $monitor->{Activation} ) if ( $monitor->{Activation} ) {
{ Debug("$monitor->{Name} has active string '$monitor->{Activation}'");
Debug( "$monitor->{Name} has active string '$monitor->{Activation}'\n" ); foreach my $code_string ( split(',', $monitor->{Activation}) ) {
foreach my $code_string ( split( /,/, $monitor->{Activation} ) )
{
#Debug( "Code string: $code_string\n" ); #Debug( "Code string: $code_string\n" );
my ( $invert, $unit_code, $modifier, $limit ) my ( $invert, $unit_code, $modifier, $limit )
= ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ );
$limit = 0 if ( !$limit ); $limit = 0 if !$limit;
if ( $unit_code ) if ( $unit_code ) {
{ if ( !$modifier || $modifier eq '+' ) {
if ( !$modifier || $modifier eq '+' )
{
addToDeviceList( $unit_code, addToDeviceList( $unit_code,
'ON', 'ON',
$monitor, $monitor,
!$invert ? 'start_active' (!$invert ? 'start_active' : 'stop_active'),
: 'stop_active',
$limit $limit
); );
} }
if ( !$modifier || $modifier eq '-' ) if ( !$modifier || $modifier eq '-' ) {
{
addToDeviceList( $unit_code, addToDeviceList( $unit_code,
'OFF', 'OFF',
$monitor, $monitor,
!$invert ? 'stop_active' (!$invert ? 'stop_active' : 'start_active'),
: 'start_active',
$limit $limit
); );
} }
} # end if unit_code
} # end foreach code_string
} }
} if ( $monitor->{AlarmInput} ) {
} Debug("$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'");
if ( $monitor->{AlarmInput} ) foreach my $code_string ( split(',', $monitor->{AlarmInput}) ) {
{
Debug( "$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'\n" );
foreach my $code_string ( split( /,/, $monitor->{AlarmInput} ) )
{
#Debug( "Code string: $code_string\n" ); #Debug( "Code string: $code_string\n" );
my ( $invert, $unit_code, $modifier, $limit ) my ( $invert, $unit_code, $modifier, $limit )
= ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ );
$limit = 0 if ( !$limit ); $limit = 0 if !$limit;
if ( $unit_code ) if ( $unit_code ) {
{ if ( !$modifier || $modifier eq '+' ) {
if ( !$modifier || $modifier eq '+' )
{
addToDeviceList( $unit_code, addToDeviceList( $unit_code,
'ON', 'ON',
$monitor, $monitor,
!$invert ? 'start_alarm' (!$invert ? 'start_alarm' : 'stop_alarm'),
: 'stop_alarm',
$limit $limit
); );
} }
if ( !$modifier || $modifier eq '-' ) if ( !$modifier || $modifier eq '-' ) {
{
addToDeviceList( $unit_code, addToDeviceList( $unit_code,
'OFF', 'OFF',
$monitor, $monitor,
!$invert ? 'stop_alarm' (!$invert ? 'stop_alarm' : 'start_alarm'),
: 'start_alarm',
$limit $limit
); );
} }
} } # end if unit_code
} } # end foreach code_string
} } # end if AlarmInput
if ( $monitor->{AlarmOutput} ) if ( $monitor->{AlarmOutput} ) {
{ Debug("$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'");
Debug( "$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'\n" ); foreach my $code_string ( split( ',', $monitor->{AlarmOutput} ) ) {
foreach my $code_string ( split( /,/, $monitor->{AlarmOutput} ) )
{
#Debug( "Code string: $code_string\n" ); #Debug( "Code string: $code_string\n" );
my ( $invert, $unit_code, $modifier, $limit ) my ( $invert, $unit_code, $modifier, $limit )
= ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ );
$limit = 0 if ( !$limit ); $limit = 0 if !$limit;
if ( $unit_code ) if ( $unit_code ) {
{ if ( !$modifier || $modifier eq '+' ) {
if ( !$modifier || $modifier eq '+' )
{
addToMonitorList( $monitor, addToMonitorList( $monitor,
'ON', 'ON',
$unit_code, $unit_code,
!$invert ? 'on' (!$invert ? 'on' : 'off'),
: 'off',
$limit $limit
); );
} }
if ( !$modifier || $modifier eq '-' ) if ( !$modifier || $modifier eq '-' ) {
{
addToMonitorList( $monitor, addToMonitorList( $monitor,
'OFF', 'OFF',
$unit_code, $unit_code,
!$invert ? 'off' (!$invert ? 'off' : 'on'),
: 'on',
$limit $limit
); );
} }
} # end if unit_code
} # end foreach code_string
} # end if AlarmOutput
zmMemInvalidate($monitor);
} }
} } # end sub loadTasks
}
zmMemInvalidate( $monitor );
}
}
sub addPendingTask sub addPendingTask {
{
my $task = shift; my $task = shift;
# Check whether we are just extending a previous pending task # Check whether we are just extending a previous pending task
# and remove it if it's there # and remove it if it's there
foreach my $activation_time ( sort(keys(%pending_tasks) ) ) foreach my $activation_time ( sort keys(%pending_tasks) ) {
{
my $pending_list = $pending_tasks{$activation_time}; my $pending_list = $pending_tasks{$activation_time};
my $new_pending_list = []; my $new_pending_list = [];
foreach my $pending_task ( @$pending_list ) foreach my $pending_task ( @$pending_list ) {
{ if ( $task->{type} ne $pending_task->{type} ) {
if ( $task->{type} ne $pending_task->{type} )
{
push( @$new_pending_list, $pending_task ) push( @$new_pending_list, $pending_task )
} } elsif ( $task->{type} eq 'device' ) {
elsif ( $task->{type} eq 'device' )
{
if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} ) if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} )
|| ( $task->{function} ne $pending_task->{function} )) || ( $task->{function} ne $pending_task->{function} ))
{ {
push( @$new_pending_list, $pending_task ) push @$new_pending_list, $pending_task;
} }
} } elsif ( $task->{type} eq 'monitor' ) {
elsif ( $task->{type} eq 'monitor' )
{
if (( $task->{device}->{appliance}->unit_code() if (( $task->{device}->{appliance}->unit_code()
!= $pending_task->{device}->{appliance}->unit_code() != $pending_task->{device}->{appliance}->unit_code()
) )
|| ( $task->{function} ne $pending_task->{function} ) || ( $task->{function} ne $pending_task->{function} )
) ) {
{ push @$new_pending_list, $pending_task;
push( @$new_pending_list, $pending_task )
} }
} } # end switch task->type
} } # end foreach pending_task
if ( @$new_pending_list )
{ if ( @$new_pending_list ) {
$pending_tasks{$activation_time} = $new_pending_list; $pending_tasks{$activation_time} = $new_pending_list;
} else {
delete $pending_tasks{$activation_time};
} }
else } # end foreach activation_time
{
delete( $pending_tasks{$activation_time} );
}
}
my $end_time = time() + $task->{limit}; my $end_time = time() + $task->{limit};
my $pending_list = $pending_tasks{$end_time}; my $pending_list = $pending_tasks{$end_time};
if ( !$pending_list ) if ( !$pending_list ) {
{
$pending_list = $pending_tasks{$end_time} = []; $pending_list = $pending_tasks{$end_time} = [];
} }
my $pending_task; my $pending_task;
if ( $task->{type} eq 'device' ) if ( $task->{type} eq 'device' ) {
{ $pending_task = {
$pending_task = { type=>$task->{type}, type=>$task->{type},
monitor=>$task->{monitor}, monitor=>$task->{monitor},
function=>$task->{function} function=>$task->{function}
}; };
$pending_task->{function} =~ s/start/stop/; $pending_task->{function} =~ s/start/stop/;
} } elsif ( $task->{type} eq 'monitor' ) {
elsif ( $task->{type} eq 'monitor' ) $pending_task = {
{ type=>$task->{type},
$pending_task = { type=>$task->{type},
device=>$task->{device}, device=>$task->{device},
function=>$task->{function} function=>$task->{function}
}; };
$pending_task->{function} =~ s/on/off/; $pending_task->{function} =~ s/on/off/;
} }
push( @$pending_list, $pending_task ); push @$pending_list, $pending_task;
} } # end sub addPendingTask
sub processTask sub processTask {
{
my $task = shift; my $task = shift;
if ( $task->{type} eq 'device' ) if ( $task->{type} eq 'device' ) {
{
my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ ); my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ );
if ( $class eq 'active' ) if ( $class eq 'active' ) {
{ if ( $instruction eq 'start' ) {
if ( $instruction eq 'start' ) zmMonitorEnable($task->{monitor});
{ if ( $task->{limit} ) {
zmMonitorEnable( $task->{monitor} ); addPendingTask($task);
if ( $task->{limit} )
{
addPendingTask( $task );
} }
} elsif( $instruction eq 'stop' ) {
zmMonitorDisable($task->{monitor});
} }
elsif( $instruction eq 'stop' ) } elsif( $class eq 'alarm' ) {
{ if ( $instruction eq 'start' ) {
zmMonitorDisable( $task->{monitor} ); zmTriggerEventOn(
} $task->{monitor},
}
elsif( $class eq 'alarm' )
{
if ( $instruction eq 'start' )
{
zmTriggerEventOn( $task->{monitor},
0, 0,
main::CAUSE_STRING, main::CAUSE_STRING,
$task->{address} $task->{address}
); );
if ( $task->{limit} ) if ( $task->{limit} ) {
{ addPendingTask($task);
addPendingTask( $task );
} }
} elsif( $instruction eq 'stop' ) {
zmTriggerEventCancel($task->{monitor});
} }
elsif( $instruction eq 'stop' ) } # end switch class
{ } elsif( $task->{type} eq 'monitor' ) {
zmTriggerEventCancel( $task->{monitor} ); if ( $task->{function} eq 'on' ) {
}
}
}
elsif( $task->{type} eq 'monitor' )
{
if ( $task->{function} eq 'on' )
{
$task->{device}->{appliance}->on(); $task->{device}->{appliance}->on();
if ( $task->{limit} ) if ( $task->{limit} ) {
{ addPendingTask($task);
addPendingTask( $task );
} }
} } elsif ( $task->{function} eq 'off' ) {
elsif ( $task->{function} eq 'off' )
{
$task->{device}->{appliance}->off(); $task->{device}->{appliance}->off();
} }
} }
} }
sub dPrint sub dPrint {
{
my $dbg_level = shift; my $dbg_level = shift;
if ( fileno(CLIENT) ) if ( fileno(CLIENT) ) {
{
print CLIENT @_ print CLIENT @_
} }
if ( $dbg_level == ZoneMinder::Logger::DEBUG ) if ( $dbg_level == ZoneMinder::Logger::DEBUG ) {
{ Debug(@_);
Debug( @_ ); } elsif ( $dbg_level == ZoneMinder::Logger::INFO ) {
Info(@_);
} elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) {
Warning(@_);
} }
elsif ( $dbg_level == ZoneMinder::Logger::INFO ) elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) {
{
Info( @_ );
}
elsif ( $dbg_level == ZoneMinder::Logger::WARNING )
{
Warning( @_ );
}
elsif ( $dbg_level == ZoneMinder::Logger::ERROR )
{
Error( @_ ); Error( @_ );
} } elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) {
elsif ( $dbg_level == ZoneMinder::Logger::FATAL )
{
Fatal( @_ ); Fatal( @_ );
} }
} }
sub x10listen sub x10listen {
{ foreach my $event ( @_ ) {
foreach my $event ( @_ )
{
#print( Data::Dumper( $_ )."\n" ); #print( Data::Dumper( $_ )."\n" );
if ( $event->house_code() eq $Config{ZM_X10_HOUSE_CODE} ) if ( $event->house_code() eq $Config{ZM_X10_HOUSE_CODE} ) {
{
my $unit_code = $event->unit_code(); my $unit_code = $event->unit_code();
my $device = $device_hash{$unit_code}; my $device = $device_hash{$unit_code};
if ( !$device ) if ( !$device ) {
{ $device = $device_hash{$unit_code} = {
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), appliance=>$x10->Appliance(unit_code=>$unit_code),
status=>'unknown' status=>'unknown'
}; };
} }
next if ( $event->func() !~ /(?:ON|OFF)/ ); next if ( $event->func() !~ /(?:ON|OFF)/ );
$device->{status} = $event->func(); $device->{status} = $event->func();
my $task_list = $device->{$event->func().'_list'}; my $task_list = $device->{$event->func().'_list'};
if ( $task_list ) if ( $task_list ) {
{ foreach my $task ( @$task_list ) {
foreach my $task ( @$task_list ) processTask($task);
{
processTask( $task );
} }
} }
} # end if correct house code
Info('Got event - '.$event->as_string());
} }
Info( "Got event - ".$event->as_string()."\n" ); } # end sub x10listen
}
}
1; 1;
__END__

View File

@ -4,7 +4,7 @@
configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY) configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY)
# Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc) # Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc)
set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_frame.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_input.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp zm_fifo.cpp zm_crypt.cpp) set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_frame.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_input.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_libvnc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp zm_fifo.cpp zm_crypt.cpp)
# A fix for cmake recompiling the source files for every target. # A fix for cmake recompiling the source files for every target.

View File

@ -33,37 +33,33 @@
// Class used for storing a box, which is defined as a region // Class used for storing a box, which is defined as a region
// defined by two coordinates // defined by two coordinates
// //
class Box class Box {
{
private: private:
Coord lo, hi; Coord lo, hi;
Coord size; Coord size;
public: public:
inline Box() inline Box() { }
{
}
explicit inline Box( int p_size ) : lo( 0, 0 ), hi ( p_size-1, p_size-1 ), size( Coord::Range( hi, lo ) ) { } explicit inline Box( int p_size ) : lo( 0, 0 ), hi ( p_size-1, p_size-1 ), size( Coord::Range( hi, lo ) ) { }
inline Box( int p_x_size, int p_y_size ) : lo( 0, 0 ), hi ( p_x_size-1, p_y_size-1 ), size( Coord::Range( hi, lo ) ) { } inline Box( int p_x_size, int p_y_size ) : lo( 0, 0 ), hi ( p_x_size-1, p_y_size-1 ), size( Coord::Range( hi, lo ) ) { }
inline Box( int lo_x, int lo_y, int hi_x, int hi_y ) : lo( lo_x, lo_y ), hi( hi_x, hi_y ), size( Coord::Range( hi, lo ) ) { } inline Box( int lo_x, int lo_y, int hi_x, int hi_y ) : lo( lo_x, lo_y ), hi( hi_x, hi_y ), size( Coord::Range( hi, lo ) ) { }
inline Box( const Coord &p_lo, const Coord &p_hi ) : lo( p_lo ), hi( p_hi ), size( Coord::Range( hi, lo ) ) { } inline Box( const Coord &p_lo, const Coord &p_hi ) : lo( p_lo ), hi( p_hi ), size( Coord::Range( hi, lo ) ) { }
inline const Coord &Lo() const { return( lo ); } inline const Coord &Lo() const { return lo; }
inline int LoX() const { return( lo.X() ); } inline int LoX() const { return lo.X(); }
inline int LoY() const { return( lo.Y() ); } inline int LoY() const { return lo.Y(); }
inline const Coord &Hi() const { return( hi ); } inline const Coord &Hi() const { return hi; }
inline int HiX() const { return( hi.X() ); } inline int HiX() const { return hi.X(); }
inline int HiY() const { return( hi.Y() ); } inline int HiY() const { return hi.Y(); }
inline const Coord &Size() const { return( size ); } inline const Coord &Size() const { return size; }
inline int Width() const { return( size.X() ); } inline int Width() const { return size.X(); }
inline int Height() const { return( size.Y() ); } inline int Height() const { return size.Y(); }
inline int Area() const { return( size.X()*size.Y() ); } inline int Area() const { return size.X()*size.Y(); }
inline const Coord Centre() const inline const Coord Centre() const {
{
int mid_x = int(round(lo.X()+(size.X()/2.0))); int mid_x = int(round(lo.X()+(size.X()/2.0)));
int mid_y = int(round(lo.Y()+(size.Y()/2.0))); int mid_y = int(round(lo.Y()+(size.Y()/2.0)));
return( Coord( mid_x, mid_y ) ); return Coord( mid_x, mid_y );
} }
inline bool Inside( const Coord &coord ) const inline bool Inside( const Coord &coord ) const
{ {

View File

@ -35,7 +35,7 @@ class Camera;
// //
class Camera { class Camera {
protected: protected:
typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC } SourceType; typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC, VNC_SRC } SourceType;
unsigned int monitor_id; unsigned int monitor_id;
Monitor * monitor; // Null on instantiation, set as soon as possible. Monitor * monitor; // Null on instantiation, set as soon as possible.
@ -68,6 +68,7 @@ public:
bool IsFfmpeg() const { return type == FFMPEG_SRC; } bool IsFfmpeg() const { return type == FFMPEG_SRC; }
bool IsLibvlc() const { return type == LIBVLC_SRC; } bool IsLibvlc() const { return type == LIBVLC_SRC; }
bool IscURL() const { return type == CURL_SRC; } bool IscURL() const { return type == CURL_SRC; }
bool IsVNC() const { return type == VNC_SRC; }
unsigned int Width() const { return width; } unsigned int Width() const { return width; }
unsigned int Height() const { return height; } unsigned int Height() const { return height; }
unsigned int Colours() const { return colours; } unsigned int Colours() const { return colours; }

View File

@ -63,7 +63,9 @@ void zmLoadConfig() {
closedir(configSubFolder); closedir(configSubFolder);
} }
zmDbConnect(); if ( !zmDbConnect() ) {
Fatal("Can't connect to db. Can't continue.");
}
config.Load(); config.Load();
config.Assign(); config.Assign();

View File

@ -25,8 +25,7 @@
// //
// Class used for storing an x,y pair, i.e. a coordinate // Class used for storing an x,y pair, i.e. a coordinate
// //
class Coord class Coord {
{
private: private:
int x, y; int x, y;
@ -44,8 +43,7 @@ public:
inline int &Y() { return( y ); } inline int &Y() { return( y ); }
inline const int &Y() const { return( y ); } inline const int &Y() const { return( y ); }
inline static Coord Range( const Coord &coord1, const Coord &coord2 ) inline static Coord Range( const Coord &coord1, const Coord &coord2 ) {
{
Coord result( (coord1.x-coord2.x)+1, (coord1.y-coord2.y)+1 ); Coord result( (coord1.x-coord2.x)+1, (coord1.y-coord2.y)+1 );
return( result ); return( result );
} }

View File

@ -108,6 +108,23 @@ Event::Event(
return; return;
} }
id = mysql_insert_id(&dbconn); id = mysql_insert_id(&dbconn);
//
/* Update event record with DefaultVideo name if possible so image.php can extract frames
if needed, while recording is in progress */
if ( monitor->GetOptVideoWriter() != 0 ) {
video_name[0] = 0;
snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s", id, "video.mp4");
Debug(1, "Updating inserted event with DefaultVideo=%s",video_name);
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name,id);
if ( mysql_query(&dbconn, sql) ) {
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
db_mutex.unlock();
return;
}
} else {
Debug (1, "GetOptVideoWriter() returned 0, not updating DefaultVideo");
}
db_mutex.unlock(); db_mutex.unlock();
if ( untimedEvent ) { if ( untimedEvent ) {
Warning("Event %d has zero time, setting to current", id); Warning("Event %d has zero time, setting to current", id);

View File

@ -100,6 +100,7 @@ bool EventStream::loadInitialEventData(uint64_t init_event_id, unsigned int init
if ( init_frame_id >= event_data->frame_count ) { if ( init_frame_id >= event_data->frame_count ) {
Error("Invalid frame id specified. %d > %d", init_frame_id, event_data->frame_count); Error("Invalid frame id specified. %d > %d", init_frame_id, event_data->frame_count);
curr_stream_time = event_data->start_time; curr_stream_time = event_data->start_time;
curr_frame_id = 1;
} else { } else {
curr_stream_time = event_data->frames[init_frame_id-1].timestamp; curr_stream_time = event_data->frames[init_frame_id-1].timestamp;
curr_frame_id = init_frame_id; curr_frame_id = init_frame_id;
@ -373,18 +374,20 @@ void EventStream::processCommand(const CmdMsg *msg) {
} }
break; break;
case CMD_SLOWFWD : case CMD_SLOWFWD :
Debug(1, "Got SLOW FWD command");
paused = true; paused = true;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
step = 1; step = 1;
if ( (unsigned int)curr_frame_id < event_data->frame_count ) if ( (unsigned int)curr_frame_id < event_data->frame_count )
curr_frame_id += 1; curr_frame_id += 1;
Debug(1, "Got SLOWFWD command new frame id %d", curr_frame_id);
break; break;
case CMD_SLOWREV : case CMD_SLOWREV :
Debug(1, "Got SLOW REV command");
paused = true; paused = true;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
step = -1; step = -1;
curr_frame_id -= 1;
if ( curr_frame_id < 1 ) curr_frame_id = 1;
Debug(1, "Got SLOWREV command new frame id %d", curr_frame_id);
break; break;
case CMD_FASTREV : case CMD_FASTREV :
Debug(1, "Got FAST REV command"); Debug(1, "Got FAST REV command");
@ -929,7 +932,7 @@ void EventStream::runStream() {
send_frame = true; send_frame = true;
} }
} else if ( step != 0 ) { } else if ( step != 0 ) {
Debug(2, "Paused with step"); Debug(2, "Paused with step %d", step);
// We are paused and are just stepping forward or backward one frame // We are paused and are just stepping forward or backward one frame
step = 0; step = 0;
send_frame = true; send_frame = true;

View File

@ -20,9 +20,6 @@
#ifndef ZM_EVENTSTREAM_H #ifndef ZM_EVENTSTREAM_H
#define ZM_EVENTSTREAM_H #define ZM_EVENTSTREAM_H
#include <set>
#include <map>
#include "zm_image.h" #include "zm_image.h"
#include "zm_stream.h" #include "zm_stream.h"
#include "zm_video.h" #include "zm_video.h"

View File

@ -321,6 +321,7 @@ void zm_dump_codecpar(const AVCodecParameters *par);
frame->pts \ frame->pts \
); );
#if LIBAVUTIL_VERSION_CHECK(54, 4, 0, 74, 100)
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \ #define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
text, \ text, \
frame->format, \ frame->format, \
@ -331,6 +332,18 @@ void zm_dump_codecpar(const AVCodecParameters *par);
frame->pts \ frame->pts \
); );
#else
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
text, \
frame->format, \
"unsupported", \
frame->width, \
frame->height, \
frame->linesize[0], frame->linesize[1], \
frame->pts \
);
#endif
#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 )
#define zm_av_packet_ref( dst, src ) av_packet_ref( dst, src ) #define zm_av_packet_ref( dst, src ) av_packet_ref( dst, src )

View File

@ -603,6 +603,8 @@ int FfmpegCamera::OpenFfmpeg() {
Error("Unable to allocate frame for %s", mPath.c_str()); Error("Unable to allocate frame for %s", mPath.c_str());
return -1; return -1;
} }
mFrame->width = width;
mFrame->height = height;
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
int pSize = av_image_get_buffer_size(imagePixFormat, width, height, 1); int pSize = av_image_get_buffer_size(imagePixFormat, width, height, 1);
@ -630,20 +632,6 @@ int FfmpegCamera::OpenFfmpeg() {
return -1; return -1;
} }
# if 0
// Must get a frame first to find out the actual format returned by decoding
mConvertContext = sws_getContext(
mVideoCodecContext->width,
mVideoCodecContext->height,
mVideoCodecContext->pix_fmt,
width, height,
imagePixFormat, SWS_BICUBIC, NULL,
NULL, NULL);
if ( mConvertContext == NULL ) {
Error("Unable to create conversion context for %s", mPath.c_str());
return -1;
}
#endif
#else // HAVE_LIBSWSCALE #else // HAVE_LIBSWSCALE
Fatal("You must compile ffmpeg with the --enable-swscale " Fatal("You must compile ffmpeg with the --enable-swscale "
"option to use ffmpeg cameras"); "option to use ffmpeg cameras");
@ -1090,7 +1078,9 @@ int FfmpegCamera::transfer_to_image(
// From what I've read, we should align the linesizes to 32bit so that ffmpeg can use SIMD instructions too. // From what I've read, we should align the linesizes to 32bit so that ffmpeg can use SIMD instructions too.
int size = av_image_fill_arrays( int size = av_image_fill_arrays(
output_frame->data, output_frame->linesize, output_frame->data, output_frame->linesize,
directbuffer, imagePixFormat, width, height, 32); directbuffer, imagePixFormat, width, height,
(AV_PIX_FMT_RGBA == imagePixFormat ? 32 : 1)
);
if ( size < 0 ) { if ( size < 0 ) {
Error("Problem setting up data pointers into image %s", Error("Problem setting up data pointers into image %s",
av_make_error_string(size).c_str()); av_make_error_string(size).c_str());
@ -1130,12 +1120,12 @@ int FfmpegCamera::transfer_to_image(
0, mVideoCodecContext->height, 0, mVideoCodecContext->height,
output_frame->data, output_frame->linesize); output_frame->data, output_frame->linesize);
if ( ret < 0 ) { if ( ret < 0 ) {
Error("Unable to convert format %u %s linesize %d height %d to format %u %s linesize %d at frame %d codec %u %s lines %d: code: %d", Error("Unable to convert format %u %s linesize %d,%d height %d to format %u %s linesize %d,%d at frame %d codec %u %s lines %d: code: %d",
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format), input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
input_frame->linesize, mVideoCodecContext->height, input_frame->linesize[0], input_frame->linesize[1], mVideoCodecContext->height,
imagePixFormat, imagePixFormat,
av_get_pix_fmt_name(imagePixFormat), av_get_pix_fmt_name(imagePixFormat),
output_frame->linesize, output_frame->linesize[0], output_frame->linesize[1],
frameCount, frameCount,
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt), mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt),
mVideoCodecContext->height, mVideoCodecContext->height,
@ -1143,6 +1133,17 @@ int FfmpegCamera::transfer_to_image(
); );
return -1; return -1;
} }
Debug(4, "Able to convert format %u %s linesize %d,%d height %d to format %u %s linesize %d,%d at frame %d codec %u %s %dx%d ",
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
input_frame->linesize[0], input_frame->linesize[1], mVideoCodecContext->height,
imagePixFormat,
av_get_pix_fmt_name(imagePixFormat),
output_frame->linesize[0], output_frame->linesize[1],
frameCount,
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt),
output_frame->width,
output_frame->height
);
#else // HAVE_LIBSWSCALE #else // HAVE_LIBSWSCALE
Fatal("You must compile ffmpeg with the --enable-swscale " Fatal("You must compile ffmpeg with the --enable-swscale "
"option to use ffmpeg cameras"); "option to use ffmpeg cameras");

View File

@ -145,8 +145,12 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
av_frame_free(&frame); av_frame_free(&frame);
continue; continue;
} else { } else {
if ( is_video_stream(input_format_context->streams[packet.stream_index]) ) {
zm_dump_video_frame(frame, "resulting video frame");
} else {
zm_dump_frame(frame, "resulting frame"); zm_dump_frame(frame, "resulting frame");
} }
}
frameComplete = 1; frameComplete = 1;
} // end if it's the right stream } // end if it's the right stream

View File

@ -167,8 +167,10 @@ Image::Image( const AVFrame *frame ) {
width = frame->width; width = frame->width;
height = frame->height; height = frame->height;
pixels = width*height; pixels = width*height;
colours = ZM_COLOUR_RGB32; colours = ZM_COLOUR_RGB32;
subpixelorder = ZM_SUBPIX_ORDER_RGBA; subpixelorder = ZM_SUBPIX_ORDER_RGBA;
size = pixels*colours; size = pixels*colours;
buffer = 0; buffer = 0;
holdbuffer = 0; holdbuffer = 0;

151
src/zm_libvnc_camera.cpp Normal file
View File

@ -0,0 +1,151 @@
#include "zm.h"
#include "zm_signal.h"
#include "zm_libvnc_camera.h"
#include "zm_swscale.h"
#if HAVE_LIBVNC
static int TAG_0;
static int TAG_1;
static int TAG_2;
static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, int h){
VncPrivateData *data = (VncPrivateData *)rfbClientGetClientData(rfb, &TAG_0);
data->buffer = rfb->frameBuffer;
}
static char* GetPasswordCallback(rfbClient* cl){
return strdup((const char *)rfbClientGetClientData(cl, &TAG_1));
}
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential));
if ( credentialType != rfbCredentialTypeUser ) {
free(c);
return NULL;
}
c->userCredential.password = strdup((const char *)rfbClientGetClientData(cl, &TAG_1));
c->userCredential.username = strdup((const char *)rfbClientGetClientData(cl, &TAG_2));
return c;
}
VncCamera::VncCamera(
unsigned int p_monitor_id,
const std::string &host,
const std::string &port,
const std::string &user,
const std::string &pass,
int p_width,
int p_height,
int p_colours,
int p_brightness,
int p_contrast,
int p_hue,
int p_colour,
bool p_capture,
bool p_record_audio ) :
Camera(
p_monitor_id,
VNC_SRC,
p_width,
p_height,
p_colours,
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
p_brightness,
p_contrast,
p_hue,
p_colour,
p_capture,
p_record_audio
),
mHost(host),
mPort(port),
mUser(user),
mPass(pass)
{
Debug(2, "Host:%s Port: %s User: %s Pass:%s", mHost.c_str(), mPort.c_str(), mUser.c_str(), mPass.c_str());
if ( colours == ZM_COLOUR_RGB32 ) {
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
mImgPixFmt = AV_PIX_FMT_RGBA;
mBpp = 4;
} else if ( colours == ZM_COLOUR_RGB24 ) {
subpixelorder = ZM_SUBPIX_ORDER_RGB;
mImgPixFmt = AV_PIX_FMT_RGB24;
mBpp = 3;
} else if ( colours == ZM_COLOUR_GRAY8 ) {
subpixelorder = ZM_SUBPIX_ORDER_NONE;
mImgPixFmt = AV_PIX_FMT_GRAY8;
mBpp = 1;
} else {
Panic("Unexpected colours: %d", colours);
}
if ( capture )
Initialise();
}
VncCamera::~VncCamera() {
if( capture )
Terminate();
}
void VncCamera::Initialise() {
Debug(2, "Initializing Client");
mRfb = rfbGetClient(8, 3, 4);
rfbClientSetClientData(mRfb, &TAG_0, &mVncData);
rfbClientSetClientData(mRfb, &TAG_1, (void *)mPass.c_str());
rfbClientSetClientData(mRfb, &TAG_2, (void *)mUser.c_str());
mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback;
mRfb->GetPassword = GetPasswordCallback;
mRfb->GetCredential = GetCredentialsCallback;
mRfb->programName = "Zoneminder VNC Monitor";
mRfb->serverHost = strdup(mHost.c_str());
mRfb->serverPort = atoi(mPort.c_str());
rfbInitClient(mRfb, 0, nullptr);
scale.init();
}
void VncCamera::Terminate() {
if(mRfb->frameBuffer)
free(mRfb->frameBuffer);
rfbClientCleanup(mRfb);
return;
}
int VncCamera::PrimeCapture() {
Info("Priming capture from %s", mHost.c_str());
return 0;
}
int VncCamera::PreCapture() {
Debug(2, "PreCapture");
WaitForMessage(mRfb, 500);
rfbBool res = HandleRFBServerMessage(mRfb);
return res == TRUE ? 1 : -1 ;
}
int VncCamera::Capture(Image &image) {
Debug(2, "Capturing");
uint8_t *directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
scale.Convert(mVncData.buffer, mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, directbuffer, width * height * mBpp, AV_PIX_FMT_RGBA, mImgPixFmt, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, width, height);
return 1;
}
int VncCamera::PostCapture() {
return 0;
}
int VncCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) {
return 0;
}
int VncCamera::Close() {
return 0;
}
#endif

62
src/zm_libvnc_camera.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef ZN_LIBVNC_CAMERA_H
#define ZN_LIBVNC_CAMERA_H
#include "zm_buffer.h"
#include "zm_camera.h"
#include "zm_thread.h"
#include "zm_swscale.h"
#if HAVE_LIBVNC
#include <rfb/rfbclient.h>
// Used by vnc callbacks
struct VncPrivateData
{
uint8_t *buffer;
uint8_t width;
uint8_t height;
};
class VncCamera : public Camera {
protected:
rfbClient *mRfb;
VncPrivateData mVncData;
int mBpp;
SWScale scale;
AVPixelFormat mImgPixFmt;
std::string mHost;
std::string mPort;
std::string mUser;
std::string mPass;
public:
VncCamera(
unsigned int p_monitor_id,
const std::string &host,
const std::string &port,
const std::string &user,
const std::string &pass,
int p_width,
int p_height,
int p_colours,
int p_brightness,
int p_contrast,
int p_hue,
int p_colour,
bool p_capture,
bool p_record_audio );
~VncCamera();
void Initialise();
void Terminate();
int PreCapture();
int PrimeCapture();
int Capture( Image &image );
int PostCapture();
int CaptureAndRecord( Image &image, timeval recording, char* event_directory );
int Close();
};
#endif // HAVE_LIBVNC
#endif // ZN_LIBVNC_CAMERA_H

View File

@ -55,7 +55,7 @@ static _AVPIXELFORMAT getFfPixFormatFromV4lPalette(int v4l_version, int palette)
#if ZM_HAS_V4L2 #if ZM_HAS_V4L2
if ( v4l_version == 2 ) { if ( v4l_version == 2 ) {
switch( palette ) { switch ( palette ) {
#if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444) #if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444)
case V4L2_PIX_FMT_RGB444 : case V4L2_PIX_FMT_RGB444 :
pixFormat = AV_PIX_FMT_RGB444; pixFormat = AV_PIX_FMT_RGB444;
@ -745,12 +745,12 @@ void LocalCamera::Initialise() {
Debug(4, Debug(4,
" v4l2_data.fmt.type = %08x\n" " v4l2_data.fmt.type = %08x\n"
" v4l2_data.fmt.fmt.pix.width = %08x\n" " v4l2_data.fmt.fmt.pix.width = %d\n"
" v4l2_data.fmt.fmt.pix.height = %08x\n" " v4l2_data.fmt.fmt.pix.height = %d\n"
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
" v4l2_data.fmt.fmt.pix.field = %08x\n" " v4l2_data.fmt.fmt.pix.field = %08x\n"
" v4l2_data.fmt.fmt.pix.bytesperline = %08x\n" " v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
" v4l2_data.fmt.fmt.pix.sizeimage = %08x\n" " v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n" " v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
" v4l2_data.fmt.fmt.pix.priv = %08x\n" " v4l2_data.fmt.fmt.pix.priv = %08x\n"
, v4l2_data.fmt.type , v4l2_data.fmt.type
@ -788,12 +788,12 @@ void LocalCamera::Initialise() {
/* Note VIDIOC_S_FMT may change width and height. */ /* Note VIDIOC_S_FMT may change width and height. */
Debug(4, Debug(4,
" v4l2_data.fmt.type = %08x\n" " v4l2_data.fmt.type = %08x\n"
" v4l2_data.fmt.fmt.pix.width = %08x\n" " v4l2_data.fmt.fmt.pix.width = %d\n"
" v4l2_data.fmt.fmt.pix.height = %08x\n" " v4l2_data.fmt.fmt.pix.height = %d\n"
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
" v4l2_data.fmt.fmt.pix.field = %08x\n" " v4l2_data.fmt.fmt.pix.field = %08x\n"
" v4l2_data.fmt.fmt.pix.bytesperline = %08x\n" " v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
" v4l2_data.fmt.fmt.pix.sizeimage = %08x\n" " v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n" " v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
" v4l2_data.fmt.fmt.pix.priv = %08x\n" " v4l2_data.fmt.fmt.pix.priv = %08x\n"
, v4l2_data.fmt.type , v4l2_data.fmt.type

View File

@ -536,8 +536,11 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con
fflush(stdout); fflush(stdout);
} }
if ( level <= mFileLevel ) { if ( level <= mFileLevel ) {
if ( !mLogFileFP ) if ( !mLogFileFP ) {
log_mutex.unlock();
openFile(); openFile();
log_mutex.lock();
}
if ( mLogFileFP ) { if ( mLogFileFP ) {
fputs(logString, mLogFileFP); fputs(logString, mLogFileFP);
if ( mFlush ) if ( mFlush )

View File

@ -51,6 +51,9 @@
#if HAVE_LIBCURL #if HAVE_LIBCURL
#include "zm_curl_camera.h" #include "zm_curl_camera.h"
#endif // HAVE_LIBCURL #endif // HAVE_LIBCURL
#if HAVE_LIBVNC
#include "zm_libvnc_camera.h"
#endif // HAVE_LIBVNC
#if ZM_MEM_MAPPED #if ZM_MEM_MAPPED
#include <sys/mman.h> #include <sys/mman.h>
@ -89,6 +92,7 @@ std::string CameraType_Strings[] = {
"Ffmpeg", "Ffmpeg",
"LibVLC", "LibVLC",
"CURL", "CURL",
"VNC",
}; };
@ -2332,6 +2336,27 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) {
#else // HAVE_LIBCURL #else // HAVE_LIBCURL
Fatal("You must have libcurl installed to use ffmpeg cameras for monitor %d", id); Fatal("You must have libcurl installed to use ffmpeg cameras for monitor %d", id);
#endif // HAVE_LIBCURL #endif // HAVE_LIBCURL
} else if ( type == "VNC" ) {
#if HAVE_LIBVNC
camera = new VncCamera(
id,
host.c_str(),
port.c_str(),
user.c_str(),
pass.c_str(),
width,
height,
colours,
brightness,
contrast,
hue,
colour,
purpose==CAPTURE,
record_audio
);
#else // HAVE_LIBVNC
Fatal("You must have libvnc installed to use VNC cameras for monitor id %d", id);
#endif // HAVE_LIBVNC
} else { } else {
Fatal("Bogus monitor type '%s' for monitor %d", type.c_str(), id); Fatal("Bogus monitor type '%s' for monitor %d", type.c_str(), id);
} // end if type } // end if type

View File

@ -75,6 +75,7 @@ public:
FFMPEG, FFMPEG,
LIBVLC, LIBVLC,
CURL, CURL,
VNC,
} CameraType; } CameraType;
typedef enum { typedef enum {

View File

@ -26,11 +26,9 @@
#include <cmath> #include <cmath>
#endif #endif
void Polygon::calcArea() void Polygon::calcArea() {
{
double float_area = 0.0L; double float_area = 0.0L;
for ( int i = 0, j = n_coords-1; i < n_coords; j = i++ ) for ( int i = 0, j = n_coords-1; i < n_coords; j = i++ ) {
{
double trap_area = ((coords[i].X()-coords[j].X())*((coords[i].Y()+coords[j].Y())))/2.0L; double trap_area = ((coords[i].X()-coords[j].X())*((coords[i].Y()+coords[j].Y())))/2.0L;
float_area += trap_area; float_area += trap_area;
//printf( "%.2f (%.2f)\n", float_area, trap_area ); //printf( "%.2f (%.2f)\n", float_area, trap_area );
@ -38,13 +36,11 @@ void Polygon::calcArea()
area = (int)round(fabs(float_area)); area = (int)round(fabs(float_area));
} }
void Polygon::calcCentre() void Polygon::calcCentre() {
{
if ( !area && n_coords ) if ( !area && n_coords )
calcArea(); calcArea();
double float_x = 0.0L, float_y = 0.0L; double float_x = 0.0L, float_y = 0.0L;
for ( int i = 0, j = n_coords-1; i < n_coords; j = i++ ) for ( int i = 0, j = n_coords-1; i < n_coords; j = i++ ) {
{
float_x += ((coords[i].Y()-coords[j].Y())*((coords[i].X()*2)+(coords[i].X()*coords[j].X())+(coords[j].X()*2))); float_x += ((coords[i].Y()-coords[j].Y())*((coords[i].X()*2)+(coords[i].X()*coords[j].X())+(coords[j].X()*2)));
float_y += ((coords[j].X()-coords[i].X())*((coords[i].Y()*2)+(coords[i].Y()*coords[j].Y())+(coords[j].Y()*2))); float_y += ((coords[j].X()-coords[i].X())*((coords[i].Y()*2)+(coords[i].Y()*coords[j].Y())+(coords[j].Y()*2)));
} }
@ -54,16 +50,14 @@ void Polygon::calcCentre()
centre = Coord( (int)round(float_x), (int)round(float_y) ); centre = Coord( (int)round(float_x), (int)round(float_y) );
} }
Polygon::Polygon( int p_n_coords, const Coord *p_coords ) : n_coords( p_n_coords ) Polygon::Polygon(int p_n_coords, const Coord *p_coords) : n_coords( p_n_coords ) {
{
coords = new Coord[n_coords]; coords = new Coord[n_coords];
int min_x = -1; int min_x = -1;
int max_x = -1; int max_x = -1;
int min_y = -1; int min_y = -1;
int max_y = -1; int max_y = -1;
for( int i = 0; i < n_coords; i++ ) for ( int i = 0; i < n_coords; i++ ) {
{
coords[i] = p_coords[i]; coords[i] = p_coords[i];
if ( min_x == -1 || coords[i].X() < min_x ) if ( min_x == -1 || coords[i].X() < min_x )
min_x = coords[i].X(); min_x = coords[i].X();
@ -79,38 +73,36 @@ Polygon::Polygon( int p_n_coords, const Coord *p_coords ) : n_coords( p_n_coords
calcCentre(); calcCentre();
} }
Polygon::Polygon( const Polygon &p_polygon ) : n_coords( p_polygon.n_coords ), extent( p_polygon.extent ), area( p_polygon.area ), centre( p_polygon.centre ) Polygon::Polygon( const Polygon &p_polygon ) :
n_coords(p_polygon.n_coords),
extent(p_polygon.extent),
area(p_polygon.area),
centre(p_polygon.centre)
{ {
coords = new Coord[n_coords]; coords = new Coord[n_coords];
for( int i = 0; i < n_coords; i++ ) for( int i = 0; i < n_coords; i++ ) {
{
coords[i] = p_polygon.coords[i]; coords[i] = p_polygon.coords[i];
} }
} }
Polygon &Polygon::operator=( const Polygon &p_polygon ) Polygon &Polygon::operator=( const Polygon &p_polygon ) {
{ if ( n_coords < p_polygon.n_coords ) {
if ( n_coords < p_polygon.n_coords )
{
delete[] coords; delete[] coords;
coords = new Coord[p_polygon.n_coords]; coords = new Coord[p_polygon.n_coords];
} }
n_coords = p_polygon.n_coords; n_coords = p_polygon.n_coords;
for( int i = 0; i < n_coords; i++ ) for ( int i = 0; i < n_coords; i++ ) {
{
coords[i] = p_polygon.coords[i]; coords[i] = p_polygon.coords[i];
} }
extent = p_polygon.extent; extent = p_polygon.extent;
area = p_polygon.area; area = p_polygon.area;
centre = p_polygon.centre; centre = p_polygon.centre;
return( *this ); return *this ;
} }
bool Polygon::isInside( const Coord &coord ) const bool Polygon::isInside( const Coord &coord ) const {
{
bool inside = false; bool inside = false;
for ( int i = 0, j = n_coords-1; i < n_coords; j = i++ ) for ( int i = 0, j = n_coords-1; i < n_coords; j = i++ ) {
{
if ( (((coords[i].Y() <= coord.Y()) && (coord.Y() < coords[j].Y()) ) if ( (((coords[i].Y() <= coord.Y()) && (coord.Y() < coords[j].Y()) )
|| ((coords[j].Y() <= coord.Y()) && (coord.Y() < coords[i].Y()))) || ((coords[j].Y() <= coord.Y()) && (coord.Y() < coords[i].Y())))
&& (coord.X() < (coords[j].X() - coords[i].X()) * (coord.Y() - coords[i].Y()) / (coords[j].Y() - coords[i].Y()) + coords[i].X())) && (coord.X() < (coords[j].X() - coords[i].X()) * (coord.Y() - coords[i].Y()) / (coords[j].Y() - coords[i].Y()) + coords[i].X()))
@ -118,5 +110,5 @@ bool Polygon::isInside( const Coord &coord ) const
inside = !inside; inside = !inside;
} }
} }
return( inside ); return inside;
} }

View File

@ -41,13 +41,13 @@ protected:
static int CompareYX( const void *p1, const void *p2 ) { static int CompareYX( const void *p1, const void *p2 ) {
const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2); const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2);
if ( e1->min_y == e2->min_y ) if ( e1->min_y == e2->min_y )
return( int(e1->min_x - e2->min_x) ); return int(e1->min_x - e2->min_x);
else else
return( int(e1->min_y - e2->min_y) ); return int(e1->min_y - e2->min_y);
} }
static int CompareX( const void *p1, const void *p2 ) { static int CompareX( const void *p1, const void *p2 ) {
const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2); const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2);
return( int(e1->min_x - e2->min_x) ); return int(e1->min_x - e2->min_x);
} }
}; };
@ -83,32 +83,32 @@ protected:
void calcCentre(); void calcCentre();
public: public:
inline Polygon() : n_coords( 0 ), coords( 0 ), area( 0 ), edges(0), slices(0) { inline Polygon() : n_coords(0), coords(0), area(0), edges(0), slices(0) {
} }
Polygon( int p_n_coords, const Coord *p_coords ); Polygon(int p_n_coords, const Coord *p_coords);
Polygon( const Polygon &p_polygon ); Polygon(const Polygon &p_polygon);
~Polygon() { ~Polygon() {
delete[] coords; delete[] coords;
} }
Polygon &operator=( const Polygon &p_polygon ); Polygon &operator=( const Polygon &p_polygon );
inline int getNumCoords() const { return( n_coords ); } inline int getNumCoords() const { return n_coords; }
inline const Coord &getCoord( int index ) const { inline const Coord &getCoord( int index ) const {
return( coords[index] ); return coords[index];
} }
inline const Box &Extent() const { return( extent ); } inline const Box &Extent() const { return extent; }
inline int LoX() const { return( extent.LoX() ); } inline int LoX() const { return extent.LoX(); }
inline int HiX() const { return( extent.HiX() ); } inline int HiX() const { return extent.HiX(); }
inline int LoY() const { return( extent.LoY() ); } inline int LoY() const { return extent.LoY(); }
inline int HiY() const { return( extent.HiY() ); } inline int HiY() const { return extent.HiY(); }
inline int Width() const { return( extent.Width() ); } inline int Width() const { return extent.Width(); }
inline int Height() const { return( extent.Height() ); } inline int Height() const { return extent.Height(); }
inline int Area() const { return( area ); } inline int Area() const { return area; }
inline const Coord &Centre() const { inline const Coord &Centre() const {
return( centre ); return centre;
} }
bool isInside( const Coord &coord ) const; bool isInside( const Coord &coord ) const;
}; };

View File

@ -234,7 +234,7 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
} else { } else {
if ( ioctl( sd, FIONREAD, &total_bytes_to_read ) < 0 ) { if ( ioctl( sd, FIONREAD, &total_bytes_to_read ) < 0 ) {
Error( "Can't ioctl(): %s", strerror(errno) ); Error( "Can't ioctl(): %s", strerror(errno) );
return( -1 ); return -1;
} }
if ( total_bytes_to_read == 0 ) { if ( total_bytes_to_read == 0 ) {
@ -242,20 +242,20 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
int error = 0; int error = 0;
socklen_t len = sizeof (error); socklen_t len = sizeof (error);
int retval = getsockopt( sd, SOL_SOCKET, SO_ERROR, &error, &len ); int retval = getsockopt( sd, SOL_SOCKET, SO_ERROR, &error, &len );
if(retval != 0 ) { if ( retval != 0 ) {
Debug( 1, "error getting socket error code %s", strerror(retval) ); Debug( 1, "error getting socket error code %s", strerror(retval) );
} }
if (error != 0) { if ( error != 0 ) {
return -1; return -1;
} }
// Case where we are grabbing a single jpg, but no content-length was given, so the expectation is that we read until close. // Case where we are grabbing a single jpg, but no content-length was given, so the expectation is that we read until close.
return( 0 ); return 0;
} }
// If socket is closed locally, then select will fail, but if it is closed remotely // If socket is closed locally, then select will fail, but if it is closed remotely
// then we have an exception on our socket.. but no data. // then we have an exception on our socket.. but no data.
Debug( 3, "Socket closed remotely" ); Debug(3, "Socket closed remotely");
//Disconnect(); // Disconnect is done outside of ReadData now. //Disconnect(); // Disconnect is done outside of ReadData now.
return( -1 ); return -1;
} }
// There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily. // There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily.
@ -292,6 +292,18 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
return total_bytes_read; return total_bytes_read;
} }
int RemoteCameraHttp::GetData() {
time_t start_time = time(NULL);
int buffer_len = 0;
while ( !( buffer_len = ReadData(buffer) ) ) {
if ( zm_terminate || ( start_time - time(NULL) < ZM_WATCH_MAX_DELAY ))
return -1;
Debug(4, "Timeout waiting for REGEXP HEADER");
usleep(100000);
}
return buffer_len;
}
int RemoteCameraHttp::GetResponse() { int RemoteCameraHttp::GetResponse() {
int buffer_len; int buffer_len;
#if HAVE_LIBPCRE #if HAVE_LIBPCRE
@ -314,9 +326,7 @@ int RemoteCameraHttp::GetResponse() {
switch( state ) { switch( state ) {
case HEADER : case HEADER :
{ {
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { buffer_len = GetData();
Debug(4, "Timeout waiting for REGEXP HEADER");
}
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error("Unable to read header data"); Error("Unable to read header data");
return -1; return -1;
@ -478,9 +488,7 @@ int RemoteCameraHttp::GetResponse() {
else else
{ {
Debug( 3, "Unable to extract subheader from stream, retrying" ); Debug( 3, "Unable to extract subheader from stream, retrying" );
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { buffer_len = GetData();
Debug(4, "Timeout waiting to extract subheader");
}
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to extract subheader data" ); Error( "Unable to extract subheader data" );
return( -1 ); return( -1 );
@ -521,7 +529,7 @@ int RemoteCameraHttp::GetResponse() {
while ( ((long)buffer.size() < content_length ) && ! zm_terminate ) while ( ((long)buffer.size() < content_length ) && ! zm_terminate )
{ {
Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_length ); Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_length );
int bytes_read = ReadData( buffer ); int bytes_read = GetData();
if ( bytes_read < 0 ) { if ( bytes_read < 0 ) {
Error( "Unable to read content" ); Error( "Unable to read content" );
@ -535,9 +543,7 @@ int RemoteCameraHttp::GetResponse() {
{ {
while ( !content_length ) while ( !content_length )
{ {
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { buffer_len = GetData();
Debug(4, "Timeout waiting for content");
}
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to read content" ); Error( "Unable to read content" );
return( -1 ); return( -1 );
@ -652,9 +658,7 @@ int RemoteCameraHttp::GetResponse() {
} }
case HEADERCONT : case HEADERCONT :
{ {
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { buffer_len = GetData();
Debug(1, "Timeout waiting for HEADERCONT");
}
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error("Unable to read header"); Error("Unable to read header");
return -1; return -1;
@ -939,9 +943,7 @@ int RemoteCameraHttp::GetResponse() {
state = CONTENT; state = CONTENT;
} else { } else {
Debug( 3, "Unable to extract subheader from stream, retrying" ); Debug( 3, "Unable to extract subheader from stream, retrying" );
while ( !( buffer_len = ReadData(buffer) ) &&!zm_terminate ) { buffer_len = GetData();
Debug(1, "Timeout waiting to extra subheader non regexp");
}
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to read subheader" ); Error( "Unable to read subheader" );
return( -1 ); return( -1 );
@ -981,7 +983,7 @@ int RemoteCameraHttp::GetResponse() {
if ( content_length ) { if ( content_length ) {
while ( ( (long)buffer.size() < content_length ) && ! zm_terminate ) { while ( ( (long)buffer.size() < content_length ) && ! zm_terminate ) {
Debug(4, "getting more data"); Debug(4, "getting more data");
int bytes_read = ReadData(buffer); int bytes_read = GetData();
if ( bytes_read < 0 ) { if ( bytes_read < 0 ) {
Error("Unable to read content"); Error("Unable to read content");
return -1; return -1;
@ -994,8 +996,7 @@ int RemoteCameraHttp::GetResponse() {
while ( !content_length && !zm_terminate ) { while ( !content_length && !zm_terminate ) {
Debug(4, "!content_length, ReadData"); Debug(4, "!content_length, ReadData");
buffer_len = ReadData( buffer ); buffer_len = ReadData( buffer );
if ( buffer_len < 0 ) if ( buffer_len < 0 ) {
{
Error( "Unable to read content" ); Error( "Unable to read content" );
return( -1 ); return( -1 );
} }

View File

@ -53,6 +53,7 @@ public:
int Disconnect(); int Disconnect();
int SendRequest(); int SendRequest();
int ReadData( Buffer &buffer, unsigned int bytes_expected=0 ); int ReadData( Buffer &buffer, unsigned int bytes_expected=0 );
int GetData();
int GetResponse(); int GetResponse();
int PreCapture(); int PreCapture();
int Capture( Image &image ); int Capture( Image &image );

View File

@ -84,7 +84,7 @@ int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf,
return 0; return 0;
} }
int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height, unsigned int new_width, unsigned int new_height) {
/* Parameter checking */ /* Parameter checking */
if(in_buffer == NULL || out_buffer == NULL) { if(in_buffer == NULL || out_buffer == NULL) {
Error("NULL Input or output buffer"); Error("NULL Input or output buffer");
@ -94,7 +94,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
// Error("Invalid input or output pixel formats"); // Error("Invalid input or output pixel formats");
// return -2; // return -2;
// } // }
if (!width || !height) { if (!width || !height || !new_height || !new_width) {
Error("Invalid width or height"); Error("Invalid width or height");
return -3; return -3;
} }
@ -111,7 +111,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
/* Check the buffer sizes */ /* Check the buffer sizes */
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
size_t insize = av_image_get_buffer_size(in_pf, width, height,1); size_t insize = av_image_get_buffer_size(in_pf, width, height, 1);
#else #else
size_t insize = avpicture_get_size(in_pf, width, height); size_t insize = avpicture_get_size(in_pf, width, height);
#endif #endif
@ -120,9 +120,9 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
return -4; return -4;
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
size_t outsize = av_image_get_buffer_size(out_pf, width, height,1); size_t outsize = av_image_get_buffer_size(out_pf, new_width, new_height, 1);
#else #else
size_t outsize = avpicture_get_size(out_pf, width, height); size_t outsize = avpicture_get_size(out_pf, new_width, new_height);
#endif #endif
if(outsize < out_buffer_size) { if(outsize < out_buffer_size) {
@ -131,7 +131,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
} }
/* Get the context */ /* Get the context */
swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL ); swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, new_width, new_height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL );
if(swscale_ctx == NULL) { if(swscale_ctx == NULL) {
Error("Failed getting swscale context"); Error("Failed getting swscale context");
return -6; return -6;
@ -150,10 +150,10 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize, if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
out_buffer, out_pf, width, height, 1) <= 0) { out_buffer, out_pf, new_width, new_height, 1) <= 0) {
#else #else
if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, width, if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width,
height) <= 0) { new_height) <= 0) {
#endif #endif
Error("Failed filling output frame with output buffer"); Error("Failed filling output frame with output buffer");
return -8; return -8;
@ -168,6 +168,10 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
return 0; return 0;
} }
int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
return Convert(in_buffer, in_buffer_size, out_buffer, out_buffer_size, in_pf, out_pf, width, height, width, height);
}
int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
if(img->Width() != width) { if(img->Width() != width) {
Error("Source image width differs. Source: %d Output: %d",img->Width(), width); Error("Source image width differs. Source: %d Output: %d",img->Width(), width);

View File

@ -16,6 +16,7 @@ class SWScale {
int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size); int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size);
int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height, unsigned int new_width, unsigned int new_height);
protected: protected:
bool gotdefaults; bool gotdefaults;

View File

@ -26,6 +26,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <utility>
#if HAVE_GNUTLS_GNUTLS_H #if HAVE_GNUTLS_GNUTLS_H
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
@ -35,7 +36,7 @@
#include <gcrypt.h> #include <gcrypt.h>
#elif HAVE_LIBCRYPTO #elif HAVE_LIBCRYPTO
#include <openssl/md5.h> #include <openssl/md5.h>
#endif // HAVE_L || HAVE_LIBCRYPTO #endif // HAVE_GCRYPT_H || HAVE_LIBCRYPTO
#include "zm_utils.h" #include "zm_utils.h"
#include "zm_crypt.h" #include "zm_crypt.h"
@ -52,7 +53,7 @@ User::User(const MYSQL_ROW &dbrow) {
id = atoi(dbrow[index++]); id = atoi(dbrow[index++]);
strncpy(username, dbrow[index++], sizeof(username)-1); strncpy(username, dbrow[index++], sizeof(username)-1);
strncpy(password, dbrow[index++], sizeof(password)-1); strncpy(password, dbrow[index++], sizeof(password)-1);
enabled = (bool)atoi(dbrow[index++]); enabled = static_cast<bool>atoi(dbrow[index++]);
stream = (Permission)atoi(dbrow[index++]); stream = (Permission)atoi(dbrow[index++]);
events = (Permission)atoi(dbrow[index++]); events = (Permission)atoi(dbrow[index++]);
control = (Permission)atoi(dbrow[index++]); control = (Permission)atoi(dbrow[index++]);
@ -61,7 +62,7 @@ User::User(const MYSQL_ROW &dbrow) {
char *monitor_ids_str = dbrow[index++]; char *monitor_ids_str = dbrow[index++];
if ( monitor_ids_str && *monitor_ids_str ) { if ( monitor_ids_str && *monitor_ids_str ) {
StringVector ids = split(monitor_ids_str, ","); StringVector ids = split(monitor_ids_str, ",");
for( StringVector::iterator i = ids.begin(); i < ids.end(); ++i ) { for ( StringVector::iterator i = ids.begin(); i < ids.end(); ++i ) {
monitor_ids.push_back(atoi((*i).c_str())); monitor_ids.push_back(atoi((*i).c_str()));
} }
} }
@ -72,7 +73,7 @@ User::~User() {
} }
void User::Copy(const User &u) { void User::Copy(const User &u) {
id=u.id; id = u.id;
strncpy(username, u.username, sizeof(username)-1); strncpy(username, u.username, sizeof(username)-1);
strncpy(password, u.password, sizeof(password)-1); strncpy(password, u.password, sizeof(password)-1);
enabled = u.enabled; enabled = u.enabled;
@ -88,7 +89,8 @@ bool User::canAccess(int monitor_id) {
if ( monitor_ids.empty() ) if ( monitor_ids.empty() )
return true; return true;
for ( std::vector<int>::iterator i = monitor_ids.begin(); i != monitor_ids.end(); ++i ) { for ( std::vector<int>::iterator i = monitor_ids.begin();
i != monitor_ids.end(); ++i ) {
if ( *i == monitor_id ) { if ( *i == monitor_id ) {
return true; return true;
} }
@ -103,12 +105,16 @@ User *zmLoadUser(const char *username, const char *password) {
int username_length = strlen(username); int username_length = strlen(username);
char *safer_username = new char[(username_length * 2) + 1]; char *safer_username = new char[(username_length * 2) + 1];
// According to docs, size of safer_whatever must be 2*length+1 due to unicode conversions + null terminator. // According to docs, size of safer_whatever must be 2*length+1
// due to unicode conversions + null terminator.
mysql_real_escape_string(&dbconn, safer_username, username, username_length); mysql_real_escape_string(&dbconn, safer_username, username, username_length);
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"SELECT `Id`, `Username`, `Password`, `Enabled`, `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0, `MonitorIds`" "SELECT `Id`, `Username`, `Password`, `Enabled`,"
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", safer_username); " `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0,"
" `MonitorIds`"
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1",
safer_username);
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn)); Error("Can't run query: %s", mysql_error(&dbconn));
@ -146,31 +152,34 @@ User *zmLoadUser(const char *username, const char *password) {
return NULL; return NULL;
} }
User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr) {
std::string key = config.auth_hash_secret; std::string key = config.auth_hash_secret;
std::string remote_addr = ""; std::string remote_addr = "";
if (use_remote_addr) { if ( use_remote_addr ) {
remote_addr = std::string(getenv( "REMOTE_ADDR" )); remote_addr = std::string(getenv("REMOTE_ADDR"));
if ( remote_addr == "" ) { if ( remote_addr == "" ) {
Warning( "Can't determine remote address, using null" ); Warning("Can't determine remote address, using null");
remote_addr = ""; remote_addr = "";
} }
key += remote_addr; key += remote_addr;
} }
Debug (1,"Inside zmLoadTokenUser, formed key=%s", key.c_str()); Debug(1, "Inside zmLoadTokenUser, formed key=%s", key.c_str());
std::pair<std::string, unsigned int> ans = verifyToken(jwt_token_str, key); std::pair<std::string, unsigned int> ans = verifyToken(jwt_token_str, key);
std::string username = ans.first; std::string username = ans.first;
unsigned int iat = ans.second; unsigned int iat = ans.second;
Debug (1,"retrieved user '%s' from token", username.c_str()); Debug(1, "retrieved user '%s' from token", username.c_str());
if (username != "") { if ( username != "" ) {
char sql[ZM_SQL_MED_BUFSIZ] = ""; char sql[ZM_SQL_MED_BUFSIZ] = "";
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"SELECT `Id`, `Username`, `Password`, `Enabled`, `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0, `MonitorIds`, `TokenMinExpiry`" "SELECT `Id`, `Username`, `Password`, `Enabled`,"
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", username.c_str() ); " `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0,"
" `MonitorIds`, `TokenMinExpiry`"
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1",
username.c_str());
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn)); Error("Can't run query: %s", mysql_error(&dbconn));
@ -192,70 +201,71 @@ User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) {
MYSQL_ROW dbrow = mysql_fetch_row(result); MYSQL_ROW dbrow = mysql_fetch_row(result);
User *user = new User(dbrow); User *user = new User(dbrow);
unsigned int stored_iat = strtoul(dbrow[10], NULL,0 ); unsigned int stored_iat = strtoul(dbrow[10], NULL, 0);
if (stored_iat > iat ) { // admin revoked tokens if ( stored_iat > iat ) { // admin revoked tokens
mysql_free_result(result); mysql_free_result(result);
Error("Token was revoked for '%s'", username.c_str()); Error("Token was revoked for '%s'", username.c_str());
return NULL; return NULL;
} }
Debug (1,"Got stored expiry time of %u",stored_iat); Debug(1, "Authenticated user '%s' via token with last revoke time: %u",
Debug (1,"Authenticated user '%s' via token", username.c_str()); username.c_str(), stored_iat);
mysql_free_result(result); mysql_free_result(result);
return user; return user;
} } else {
else {
return NULL; return NULL;
} }
} // end User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr)
}
// Function to validate an authentication string // Function to validate an authentication string
User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT #if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
#ifdef HAVE_GCRYPT_H #ifdef HAVE_GCRYPT_H
// Special initialisation for libgcrypt // Special initialisation for libgcrypt
if ( !gcry_check_version( GCRYPT_VERSION ) ) { if ( !gcry_check_version(GCRYPT_VERSION) ) {
Fatal( "Unable to initialise libgcrypt" ); Fatal("Unable to initialise libgcrypt");
} }
gcry_control( GCRYCTL_DISABLE_SECMEM, 0 ); gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
gcry_control( GCRYCTL_INITIALIZATION_FINISHED, 0 ); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
#endif // HAVE_GCRYPT_H #endif // HAVE_GCRYPT_H
const char *remote_addr = ""; const char *remote_addr = "";
if ( use_remote_addr ) { if ( use_remote_addr ) {
remote_addr = getenv( "REMOTE_ADDR" ); remote_addr = getenv("REMOTE_ADDR");
if ( !remote_addr ) { if ( !remote_addr ) {
Warning( "Can't determine remote address, using null" ); Warning("Can't determine remote address, using null");
remote_addr = ""; remote_addr = "";
} }
} }
Debug( 1, "Attempting to authenticate user from auth string '%s'", auth ); Debug(1, "Attempting to authenticate user from auth string '%s'", auth);
char sql[ZM_SQL_SML_BUFSIZ] = ""; char sql[ZM_SQL_SML_BUFSIZ] = "";
snprintf( sql, sizeof(sql), "SELECT `Id`, `Username`, `Password`, `Enabled`, `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0, `MonitorIds` FROM `Users` WHERE `Enabled` = 1" ); snprintf(sql, sizeof(sql),
"SELECT `Id`, `Username`, `Password`, `Enabled`,"
" `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0,"
" `MonitorIds` FROM `Users` WHERE `Enabled` = 1");
if ( mysql_query( &dbconn, sql ) ) { if ( mysql_query(&dbconn, sql) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) ); Error("Can't run query: %s", mysql_error(&dbconn));
exit( mysql_errno( &dbconn ) ); exit(mysql_errno(&dbconn));
} }
MYSQL_RES *result = mysql_store_result( &dbconn ); MYSQL_RES *result = mysql_store_result(&dbconn);
if ( !result ) { if ( !result ) {
Error( "Can't use query result: %s", mysql_error( &dbconn ) ); Error("Can't use query result: %s", mysql_error(&dbconn));
exit( mysql_errno( &dbconn ) ); exit(mysql_errno(&dbconn));
} }
int n_users = mysql_num_rows( result ); int n_users = mysql_num_rows(result);
if ( n_users < 1 ) { if ( n_users < 1 ) {
mysql_free_result( result ); mysql_free_result(result);
Warning( "Unable to authenticate user" ); Warning("Unable to authenticate user");
return( 0 ); return 0;
} }
while( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) { while ( MYSQL_ROW dbrow = mysql_fetch_row(result) ) {
const char *user = dbrow[1]; const char *user = dbrow[1];
const char *pass = dbrow[2]; const char *pass = dbrow[2];
@ -264,20 +274,20 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
size_t md5len = 16; size_t md5len = 16;
unsigned char md5sum[md5len]; unsigned char md5sum[md5len];
time_t now = time( 0 ); time_t now = time(0);
unsigned int hours = config.auth_hash_ttl; unsigned int hours = config.auth_hash_ttl;
if ( ! hours ) { if ( !hours ) {
Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2."); Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2.");
hours = 2; hours = 2;
} else { } else {
Debug( 1, "AUTH_HASH_TTL is %d", hours ); Debug(1, "AUTH_HASH_TTL is %d", hours);
} }
for ( unsigned int i = 0; i < hours; i++, now -= 3600 ) { for ( unsigned int i = 0; i < hours; i++, now -= 3600 ) {
struct tm *now_tm = localtime( &now ); struct tm *now_tm = localtime(&now);
snprintf( auth_key, sizeof(auth_key), "%s%s%s%s%d%d%d%d", snprintf(auth_key, sizeof(auth_key), "%s%s%s%s%d%d%d%d",
config.auth_hash_secret, config.auth_hash_secret,
user, user,
pass, pass,
@ -285,50 +295,51 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
now_tm->tm_hour, now_tm->tm_hour,
now_tm->tm_mday, now_tm->tm_mday,
now_tm->tm_mon, now_tm->tm_mon,
now_tm->tm_year now_tm->tm_year);
);
#if HAVE_DECL_MD5 #if HAVE_DECL_MD5
MD5( (unsigned char *)auth_key, strlen(auth_key), md5sum ); MD5((unsigned char *)auth_key, strlen(auth_key), md5sum);
#elif HAVE_DECL_GNUTLS_FINGERPRINT #elif HAVE_DECL_GNUTLS_FINGERPRINT
gnutls_datum_t md5data = { (unsigned char *)auth_key, strlen(auth_key) }; gnutls_datum_t md5data = { (unsigned char *)auth_key, strlen(auth_key) };
gnutls_fingerprint( GNUTLS_DIG_MD5, &md5data, md5sum, &md5len ); gnutls_fingerprint(GNUTLS_DIG_MD5, &md5data, md5sum, &md5len);
#endif #endif
for ( unsigned int j = 0; j < md5len; j++ ) { for ( unsigned int j = 0; j < md5len; j++ ) {
snprintf(&auth_md5[2*j], 2, "%02x", md5sum[j]); snprintf(&auth_md5[2*j], 2, "%02x", md5sum[j]);
} }
Debug( 1, "Checking auth_key '%s' -> auth_md5 '%s' == '%s'", auth_key, auth_md5, auth ); Debug(1, "Checking auth_key '%s' -> auth_md5 '%s' == '%s'",
auth_key, auth_md5, auth);
if ( !strcmp( auth, auth_md5 ) ) { if ( !strcmp(auth, auth_md5) ) {
// We have a match // We have a match
User *user = new User( dbrow ); User *user = new User(dbrow);
Debug(1, "Authenticated user '%s'", user->getUsername() ); Debug(1, "Authenticated user '%s'", user->getUsername());
mysql_free_result( result ); mysql_free_result(result);
return( user ); return user;
} else { } else {
Debug(1, "No match for %s", auth ); Debug(1, "No match for %s", auth);
} }
} } // end foreach hour
} } // end foreach user
mysql_free_result( result ); mysql_free_result(result);
#else // HAVE_DECL_MD5 #else // HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
Error( "You need to build with gnutls or openssl installed to use hash based authentication" ); Error("You need to build with gnutls or openssl to use hash based auth");
#endif // HAVE_DECL_MD5 #endif // HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
Debug(1, "No user found for auth_key %s", auth ); Debug(1, "No user found for auth_key %s", auth);
return 0; return 0;
} } // end User *zmLoadAuthUser( const char *auth, bool use_remote_addr )
//Function to check Username length // Function to check Username length
bool checkUser ( const char *username) { bool checkUser(const char *username) {
if ( ! username ) if ( !username )
return false; return false;
if ( strlen(username) > 32 ) if ( strlen(username) > 32 )
return false; return false;
return true; return true;
} }
//Function to check password length
bool checkPass (const char *password) { // Function to check password length
bool checkPass(const char *password) {
if ( !password ) if ( !password )
return false; return false;
if ( strlen(password) > 64 ) if ( strlen(password) > 64 )

View File

@ -409,7 +409,7 @@ bool VideoStore::open() {
AVDictionary *opts = NULL; AVDictionary *opts = NULL;
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
// Shiboleth reports that this may break seeking in mp4 before it downloads // Shiboleth reports that this may break seeking in mp4 before it downloads
//av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0); av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
// av_dict_set(&opts, "movflags", // av_dict_set(&opts, "movflags",
// "frag_keyframe+empty_moov+default_base_moof", 0); // "frag_keyframe+empty_moov+default_base_moof", 0);
if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { if ( (ret = avformat_write_header(oc, &opts)) < 0 ) {

View File

@ -106,9 +106,9 @@ int main(int argc, const char *argv[]) {
for ( int p = 0; p < parm_no; p++ ) { for ( int p = 0; p < parm_no; p++ ) {
char *name = strtok(parms[p], "="); char *name = strtok(parms[p], "=");
char *value = strtok(NULL, "="); char const *value = strtok(NULL, "=");
if ( !value ) if ( !value )
value = (char *)""; value = "";
if ( !strcmp(name, "source") ) { if ( !strcmp(name, "source") ) {
source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR; source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR;
if ( !strcmp(value, "fifo") ) if ( !strcmp(value, "fifo") )
@ -127,10 +127,10 @@ int main(int argc, const char *argv[]) {
} else if ( !strcmp(name, "time") ) { } else if ( !strcmp(name, "time") ) {
event_time = atoi(value); event_time = atoi(value);
} else if ( !strcmp(name, "event") ) { } else if ( !strcmp(name, "event") ) {
event_id = strtoull(value, (char **)NULL, 10); event_id = strtoull(value, NULL, 10);
source = ZMS_EVENT; source = ZMS_EVENT;
} else if ( !strcmp(name, "frame") ) { } else if ( !strcmp(name, "frame") ) {
frame_id = strtoull(value, (char **)NULL, 10); frame_id = strtoull(value, NULL, 10);
source = ZMS_EVENT; source = ZMS_EVENT;
} else if ( !strcmp(name, "scale") ) { } else if ( !strcmp(name, "scale") ) {
scale = atoi(value); scale = atoi(value);
@ -159,7 +159,7 @@ int main(int argc, const char *argv[]) {
} else if ( !strcmp(name, "buffer") ) { } else if ( !strcmp(name, "buffer") ) {
playback_buffer = atoi(value); playback_buffer = atoi(value);
} else if ( !strcmp(name, "auth") ) { } else if ( !strcmp(name, "auth") ) {
strncpy( auth, value, sizeof(auth)-1 ); strncpy(auth, value, sizeof(auth)-1);
} else if ( !strcmp(name, "token") ) { } else if ( !strcmp(name, "token") ) {
jwt_token_str = value; jwt_token_str = value;
Debug(1, "ZMS: JWT token found: %s", jwt_token_str.c_str()); Debug(1, "ZMS: JWT token found: %s", jwt_token_str.c_str());
@ -237,11 +237,13 @@ int main(int argc, const char *argv[]) {
time_t now = time(0); time_t now = time(0);
char date_string[64]; char date_string[64];
strftime(date_string, sizeof(date_string)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); strftime(date_string, sizeof(date_string)-1,
"%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
fprintf(stdout, "Last-Modified: %s\r\n", date_string); fputs("Last-Modified: ", stdout);
fputs(date_string, stdout);
fputs( fputs(
"Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" "\r\nExpires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
"Cache-Control: no-store, no-cache, must-revalidate\r\n" "Cache-Control: no-store, no-cache, must-revalidate\r\n"
"Cache-Control: post-check=0, pre-check=0\r\n" "Cache-Control: post-check=0, pre-check=0\r\n"
"Pragma: no-cache\r\n", "Pragma: no-cache\r\n",
@ -279,7 +281,9 @@ int main(int argc, const char *argv[]) {
stream.setStreamType(MonitorStream::STREAM_MPEG); stream.setStreamType(MonitorStream::STREAM_MPEG);
#else // HAVE_LIBAVCODEC #else // HAVE_LIBAVCODEC
Error("MPEG streaming of '%s' attempted while disabled", query); Error("MPEG streaming of '%s' attempted while disabled", query);
fprintf(stderr, "MPEG streaming is disabled.\nYou should configure with the --with-ffmpeg option and rebuild to use this functionality.\n"); fprintf(stderr, "MPEG streaming is disabled.\n"
"You should configure with the --with-ffmpeg"
" option and rebuild to use this functionality.\n");
logTerm(); logTerm();
zmDbClose(); zmDbClose();
return -1; return -1;

View File

@ -476,14 +476,12 @@ int main(int argc, char *argv[]) {
} // end if auth } // end if auth
if ( mon_id > 0 ) { if ( mon_id > 0 ) {
//fprintf(stderr,"Monitor %d\n", mon_id);
Monitor *monitor = Monitor::Load(mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY); Monitor *monitor = Monitor::Load(mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY);
if ( monitor ) { if ( monitor ) {
//fprintf(stderr,"Monitor %d(%s)\n", monitor->Id(), monitor->Name());
if ( verbose ) { if ( verbose ) {
printf("Monitor %d(%s)\n", monitor->Id(), monitor->Name()); printf("Monitor %d(%s)\n", monitor->Id(), monitor->Name());
} }
if ( ! monitor->connect() ) { if ( !monitor->connect() ) {
Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name());
exit_zmu(-1); exit_zmu(-1);
} }
@ -495,13 +493,13 @@ int main(int argc, char *argv[]) {
if ( verbose ) { if ( verbose ) {
printf("Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle")); printf("Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle"));
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
printf("%d", state); printf("%d", state);
have_output = true; have_output = true;
} }
} }
if ( function & ZMU_TIME ) { if ( function & ZMU_TIME ) {
struct timeval timestamp = monitor->GetTimestamp( image_idx ); struct timeval timestamp = monitor->GetTimestamp(image_idx);
if ( verbose ) { if ( verbose ) {
char timestamp_str[64] = "None"; char timestamp_str[64] = "None";
if ( timestamp.tv_sec ) if ( timestamp.tv_sec )
@ -511,7 +509,7 @@ int main(int argc, char *argv[]) {
else else
printf("Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000); printf("Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000);
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
printf("%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000); printf("%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000);
have_output = true; have_output = true;
} }
@ -520,7 +518,7 @@ int main(int argc, char *argv[]) {
if ( verbose ) if ( verbose )
printf("Last read index: %d\n", monitor->GetLastReadIndex()); printf("Last read index: %d\n", monitor->GetLastReadIndex());
else { else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
printf("%d", monitor->GetLastReadIndex()); printf("%d", monitor->GetLastReadIndex());
have_output = true; have_output = true;
} }
@ -529,7 +527,7 @@ int main(int argc, char *argv[]) {
if ( verbose ) { if ( verbose ) {
printf("Last write index: %d\n", monitor->GetLastWriteIndex()); printf("Last write index: %d\n", monitor->GetLastWriteIndex());
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
printf("%d", monitor->GetLastWriteIndex()); printf("%d", monitor->GetLastWriteIndex());
have_output = true; have_output = true;
} }
@ -538,16 +536,16 @@ int main(int argc, char *argv[]) {
if ( verbose ) { if ( verbose ) {
printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId()); printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId());
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
printf("%" PRIu64, monitor->GetLastEventId()); printf("%" PRIu64, monitor->GetLastEventId());
have_output = true; have_output = true;
} }
} }
if ( function & ZMU_FPS ) { if ( function & ZMU_FPS ) {
if ( verbose ) if ( verbose ) {
printf("Current capture rate: %.2f frames per second\n", monitor->GetFPS()); printf("Current capture rate: %.2f frames per second\n", monitor->GetFPS());
else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
printf("%.2f", monitor->GetFPS()); printf("%.2f", monitor->GetFPS());
have_output = true; have_output = true;
} }
@ -573,10 +571,16 @@ int main(int argc, char *argv[]) {
if ( monitor->GetFunction() == Monitor::Function::MONITOR ) { if ( monitor->GetFunction() == Monitor::Function::MONITOR ) {
printf("A Monitor in monitor mode cannot handle alarms. Please use NoDect\n"); printf("A Monitor in monitor mode cannot handle alarms. Please use NoDect\n");
} else { } else {
if ( verbose ) Monitor::State state = monitor->GetState();
printf("Forcing alarm on\n");
if ( verbose ) {
printf("Forcing alarm on current state: %s, event %" PRIu64 "\n",
state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle"),
monitor->GetLastEventId()
);
}
monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web"); monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web");
while ( (monitor->GetState() != Monitor::ALARM) && !zm_terminate ) { while ( ((state = monitor->GetState()) != Monitor::ALARM) && !zm_terminate ) {
// Wait for monitor to notice. // Wait for monitor to notice.
usleep(1000); usleep(1000);
} }
@ -630,7 +634,7 @@ int main(int argc, char *argv[]) {
else else
printf("Current brightness: %d\n", monitor->actionBrightness()); printf("Current brightness: %d\n", monitor->actionBrightness());
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
if ( brightness >= 0 ) if ( brightness >= 0 )
printf("%d", monitor->actionBrightness(brightness)); printf("%d", monitor->actionBrightness(brightness));
else else
@ -645,7 +649,7 @@ int main(int argc, char *argv[]) {
else else
printf("Current contrast: %d\n", monitor->actionContrast()); printf("Current contrast: %d\n", monitor->actionContrast());
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
if ( contrast >= 0 ) if ( contrast >= 0 )
printf("%d", monitor->actionContrast(contrast)); printf("%d", monitor->actionContrast(contrast));
else else
@ -660,7 +664,7 @@ int main(int argc, char *argv[]) {
else else
printf("Current hue: %d\n", monitor->actionHue()); printf("Current hue: %d\n", monitor->actionHue());
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
if ( hue >= 0 ) if ( hue >= 0 )
printf("%d", monitor->actionHue(hue)); printf("%d", monitor->actionHue(hue));
else else
@ -675,7 +679,7 @@ int main(int argc, char *argv[]) {
else else
printf("Current colour: %d\n", monitor->actionColour()); printf("Current colour: %d\n", monitor->actionColour());
} else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) fputc(separator, stdout);
if ( colour >= 0 ) if ( colour >= 0 )
printf("%d", monitor->actionColour(colour)); printf("%d", monitor->actionColour(colour));
else else
@ -708,11 +712,11 @@ int main(int argc, char *argv[]) {
} }
if ( function & ZMU_LIST ) { if ( function & ZMU_LIST ) {
std::string sql = "select Id, Function+0 from Monitors"; std::string sql = "SELECT `Id`, `Function`+0 FROM `Monitors`";
if ( !verbose ) { if ( !verbose ) {
sql += "where Function != 'None'"; sql += "WHERE `Function` != 'None'";
} }
sql += " order by Id asc"; sql += " ORDER BY Id ASC";
if ( mysql_query(&dbconn, sql.c_str()) ) { if ( mysql_query(&dbconn, sql.c_str()) ) {
Error("Can't run query: %s", mysql_error(&dbconn)); Error("Can't run query: %s", mysql_error(&dbconn));

View File

@ -110,7 +110,12 @@ else
fi; fi;
if [ "$SNAPSHOT" == "stable" ]; then if [ "$SNAPSHOT" == "stable" ]; then
if [ "$BRANCH" == "" ]; then if [ "$BRANCH" == "" ]; then
BRANCH=$(git describe --tags $(git rev-list --tags --max-count=1)); #REV=$(git rev-list --tags --max-count=1)
BRANCH=`git describe --tags $(git rev-list --tags --max-count=1)`;
if [ "$BRANCH" == "" ]; then
echo "Unable to determine latest stable branch!"
exit 0;
fi
echo "Latest stable branch is $BRANCH"; echo "Latest stable branch is $BRANCH";
fi; fi;
else else

View File

@ -1 +1 @@
1.34.9 1.35.2

View File

@ -50,8 +50,10 @@ class HostController extends AppController {
$cred_depr = []; $cred_depr = [];
if ( $username && $password ) { if ( $username && $password ) {
ZM\Logger::Debug('Username and password provided, generating access and refresh tokens');
$cred = $this->_getCredentials(true, '', $username); // generate refresh $cred = $this->_getCredentials(true, '', $username); // generate refresh
} else { } else {
ZM\Logger::Debug('Only generating access token');
$cred = $this->_getCredentials(false, $token); // don't generate refresh $cred = $this->_getCredentials(false, $token); // don't generate refresh
} }
@ -69,6 +71,8 @@ class HostController extends AppController {
$cred_depr = $this->_getCredentialsDeprecated(); $cred_depr = $this->_getCredentialsDeprecated();
$login_array['credentials'] = $cred_depr[0]; $login_array['credentials'] = $cred_depr[0];
$login_array['append_password'] = $cred_depr[1]; $login_array['append_password'] = $cred_depr[1];
} else {
ZM\Logger::Debug('Legacy Auth is disabled, not generating auth= credentials');
} }
$login_array['version'] = $ver[0]; $login_array['version'] = $ver[0];
@ -108,8 +112,11 @@ class HostController extends AppController {
private function _getCredentials($generate_refresh_token=false, $token='', $username='') { private function _getCredentials($generate_refresh_token=false, $token='', $username='') {
if ( !ZM_OPT_USE_AUTH ) if ( !ZM_OPT_USE_AUTH ) {
ZM\Error('OPT_USE_AUTH is turned off. Tokens will be null');
return; return;
}
if ( !ZM_AUTH_HASH_SECRET ) if ( !ZM_AUTH_HASH_SECRET )
throw new ForbiddenException(__('Please create a valid AUTH_HASH_SECRET in ZoneMinder')); throw new ForbiddenException(__('Please create a valid AUTH_HASH_SECRET in ZoneMinder'));

View File

@ -17,12 +17,17 @@ class ServersController extends AppController {
public function beforeFilter() { public function beforeFilter() {
parent::beforeFilter(); parent::beforeFilter();
/*
* A user needs the server data to calculate how to view a monitor, and there really isn't anything sensitive in this data.
* So it has been decided for now to just let everyone read it.
global $user; global $user;
$canView = (!$user) || ($user['System'] != 'None'); $canView = (!$user) || ($user['System'] != 'None');
if ( !$canView ) { if ( !$canView ) {
throw new UnauthorizedException(__('Insufficient Privileges')); throw new UnauthorizedException(__('Insufficient Privileges'));
return; return;
} }
*/
} }
/** /**
@ -34,7 +39,7 @@ class ServersController extends AppController {
$this->Server->recursive = 0; $this->Server->recursive = 0;
$options = ''; $options = '';
$servers = $this->Server->find('all',$options); $servers = $this->Server->find('all', $options);
$this->set(array( $this->set(array(
'servers' => $servers, 'servers' => $servers,
'_serialize' => array('servers') '_serialize' => array('servers')
@ -50,13 +55,13 @@ class ServersController extends AppController {
*/ */
public function view($id = null) { public function view($id = null) {
$this->Server->recursive = 0; $this->Server->recursive = 0;
if (!$this->Server->exists($id)) { if ( !$this->Server->exists($id) ) {
throw new NotFoundException(__('Invalid server')); throw new NotFoundException(__('Invalid server'));
} }
$restricted = ''; $restricted = '';
$options = array('conditions' => array( $options = array('conditions' => array(
array('Server.' . $this->Server->primaryKey => $id), array('Server.'.$this->Server->primaryKey => $id),
$restricted $restricted
) )
); );

View File

@ -119,7 +119,7 @@ class Monitor extends AppModel {
); );
public $actsAs = array( public $actsAs = array(
'CakePHP-Enum-Behavior.Enum' => array( 'CakePHP-Enum-Behavior.Enum' => array(
'Type' => array('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite'), 'Type' => array('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite', 'VNC'),
'Function' => array('None','Monitor','Modect','Record','Mocord','Nodect'), 'Function' => array('None','Monitor','Modect','Record','Mocord','Nodect'),
'Orientation' => array('ROTATE_0','ROTATE_90','ROTATE_180','ROTATE_270','FLIP_HORI','FLIP_VERT'), 'Orientation' => array('ROTATE_0','ROTATE_90','ROTATE_180','ROTATE_270','FLIP_HORI','FLIP_VERT'),
'OutputCodec' => array('h264','mjpeg','mpeg1','mpeg2'), 'OutputCodec' => array('h264','mjpeg','mpeg1','mpeg2'),

View File

@ -417,31 +417,27 @@ class Event extends ZM_Object {
} }
} // end if capture file exists } // end if capture file exists
} // end if analyze file exists } // end if analyze file exists
} } // end if frame or snapshot
$captPath = $eventPath.'/'.$captImage; $captPath = $eventPath.'/'.$captImage;
if ( ! file_exists($captPath) ) { if ( ! file_exists($captPath) ) {
Error("Capture file does not exist at $captPath"); Error("Capture file does not exist at $captPath");
} }
//echo "CI:$captImage, CP:$captPath, TCP:$captPath<br>";
$analImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyse.jpg', $frame['FrameId']); $analImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyse.jpg', $frame['FrameId']);
$analPath = $eventPath.'/'.$analImage; $analPath = $eventPath.'/'.$analImage;
//echo "AI:$analImage, AP:$analPath, TAP:$analPath<br>";
$alarmFrame = $frame['Type']=='Alarm'; $alarmFrame = $frame['Type']=='Alarm';
$hasAnalImage = $alarmFrame && file_exists($analPath) && filesize($analPath); $hasAnalImage = $alarmFrame && file_exists($analPath) && filesize($analPath);
$isAnalImage = $hasAnalImage && !$captureOnly; $isAnalImage = $hasAnalImage && !$captureOnly;
if ( !ZM_WEB_SCALE_THUMBS || $scale >= SCALE_BASE || !function_exists('imagecreatefromjpeg') ) { if ( !ZM_WEB_SCALE_THUMBS || ($scale >= SCALE_BASE) || !function_exists('imagecreatefromjpeg') ) {
$imagePath = $thumbPath = $isAnalImage ? $analPath : $captPath; $imagePath = $thumbPath = $isAnalImage ? $analPath : $captPath;
$imageFile = $imagePath; $imageFile = $imagePath;
$thumbFile = $thumbPath; $thumbFile = $thumbPath;
} else { } else {
if ( version_compare( phpversion(), '4.3.10', '>=') ) if ( version_compare(phpversion(), '4.3.10', '>=') )
$fraction = sprintf('%.3F', $scale/SCALE_BASE); $fraction = sprintf('%.3F', $scale/SCALE_BASE);
else else
$fraction = sprintf('%.3f', $scale/SCALE_BASE); $fraction = sprintf('%.3f', $scale/SCALE_BASE);
@ -459,19 +455,19 @@ class Event extends ZM_Object {
} }
$thumbFile = $thumbPath; $thumbFile = $thumbPath;
if ( $overwrite || ! file_exists( $thumbFile ) || ! filesize( $thumbFile ) ) { if ( $overwrite || ! file_exists($thumbFile) || ! filesize($thumbFile) ) {
// Get new dimensions // Get new dimensions
list( $imageWidth, $imageHeight ) = getimagesize( $imagePath ); list( $imageWidth, $imageHeight ) = getimagesize($imagePath);
$thumbWidth = $imageWidth * $fraction; $thumbWidth = $imageWidth * $fraction;
$thumbHeight = $imageHeight * $fraction; $thumbHeight = $imageHeight * $fraction;
// Resample // Resample
$thumbImage = imagecreatetruecolor( $thumbWidth, $thumbHeight ); $thumbImage = imagecreatetruecolor($thumbWidth, $thumbHeight);
$image = imagecreatefromjpeg( $imagePath ); $image = imagecreatefromjpeg($imagePath);
imagecopyresampled( $thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight ); imagecopyresampled($thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight);
if ( !imagejpeg( $thumbImage, $thumbPath ) ) if ( !imagejpeg($thumbImage, $thumbPath) )
Error( "Can't create thumbnail '$thumbPath'" ); Error("Can't create thumbnail '$thumbPath'");
} }
} # Create thumbnails } # Create thumbnails
@ -555,7 +551,7 @@ class Event extends ZM_Object {
$Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server(); $Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server();
if ( $Server->Id() != ZM_SERVER_ID ) { if ( $Server->Id() != ZM_SERVER_ID ) {
$url = $Server->UrlToApi() . '/events/'.$this->{'Id'}.'.json'; $url = $Server->UrlToApi().'/events/'.$this->{'Id'}.'.json';
if ( ZM_OPT_USE_AUTH ) { if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) { if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS); $url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);

View File

@ -11,6 +11,9 @@ class Filter extends ZM_Object {
'AutoExecute' => 0, 'AutoExecute' => 0,
'AutoExecuteCmd' => 0, 'AutoExecuteCmd' => 0,
'AutoEmail' => 0, 'AutoEmail' => 0,
'EmailTo' => '',
'EmailSubject' => '',
'EmailBody' => '',
'AutoDelete' => 0, 'AutoDelete' => 0,
'AutoArchive' => 0, 'AutoArchive' => 0,
'AutoVideo' => 0, 'AutoVideo' => 0,

View File

@ -441,14 +441,17 @@ class Monitor extends ZM_Object {
$source = ''; $source = '';
if ( $this->{'Type'} == 'Local' ) { if ( $this->{'Type'} == 'Local' ) {
$source = $this->{'Device'}.' ('.$this->{'Channel'}.')'; $source = $this->{'Device'}.' ('.$this->{'Channel'}.')';
} elseif ( $this->{'Type'} == 'Remote' ) { } else if ( $this->{'Type'} == 'Remote' ) {
$source = preg_replace( '/^.*@/', '', $this->{'Host'} ); $source = preg_replace( '/^.*@/', '', $this->{'Host'} );
if ( $this->{'Port'} != '80' and $this->{'Port'} != '554' ) { if ( $this->{'Port'} != '80' and $this->{'Port'} != '554' ) {
$source .= ':'.$this->{'Port'}; $source .= ':'.$this->{'Port'};
} }
} elseif ( $this->{'Type'} == 'File' || $this->{'Type'} == 'cURL' ) { } else if ( $this->{'Type'} == 'VNC' ) {
$source = preg_replace( '/^.*\//', '', $this->{'Path'} ); $source = preg_replace( '/^.*@/', '', $this->{'Host'} );
} elseif ( $this->{'Type'} == 'Ffmpeg' || $this->{'Type'} == 'Libvlc' || $this->{'Type'} == 'WebSite' ) { if ( $this->{'Port'} != '5900' ) {
$source .= ':'.$this->{'Port'};
}
} else if ( $this->{'Type'} == 'Ffmpeg' || $this->{'Type'} == 'Libvlc' || $this->{'Type'} == 'WebSite' ) {
$url_parts = parse_url( $this->{'Path'} ); $url_parts = parse_url( $this->{'Path'} );
if ( ZM_WEB_FILTER_SOURCE == 'Hostname' ) { if ( ZM_WEB_FILTER_SOURCE == 'Hostname' ) {
# Filter out everything but the hostname # Filter out everything but the hostname
@ -457,7 +460,7 @@ class Monitor extends ZM_Object {
} else { } else {
$source = $this->{'Path'}; $source = $this->{'Path'};
} }
} elseif ( ZM_WEB_FILTER_SOURCE == 'NoCredentials' ) { } else if ( ZM_WEB_FILTER_SOURCE == 'NoCredentials' ) {
# Filter out sensitive and common items # Filter out sensitive and common items
unset($url_parts['user']); unset($url_parts['user']);
unset($url_parts['pass']); unset($url_parts['pass']);

View File

@ -216,7 +216,8 @@ Logger::Debug("$k => Have default for $v: ");
} }
} }
} # end foreach default } # end foreach default
} } # end if defaults
foreach ( $new_values as $field => $value ) { foreach ( $new_values as $field => $value ) {
if ( method_exists($this, $field) ) { if ( method_exists($this, $field) ) {
@ -299,7 +300,7 @@ Logger::Debug("$k => Have default for $v: ");
# Set defaults. Note that we only replace "" with null, not other values # Set defaults. Note that we only replace "" with null, not other values
# because for example if we want to clear TimestampFormat, we clear it, but the default is a string value # because for example if we want to clear TimestampFormat, we clear it, but the default is a string value
foreach ( $this->defaults as $field => $default ) { foreach ( $this->defaults as $field => $default ) {
if ( (!array_key_exists($field, $this)) or ($this->{$field} == '') ) { if ( (!property_exists($this, $field)) or ($this->{$field} === '') ) {
if ( is_array($default) ) { if ( is_array($default) ) {
$this->{$field} = $default['default']; $this->{$field} = $default['default'];
} else if ( $default == null ) { } else if ( $default == null ) {

View File

@ -16,6 +16,7 @@ class Storage extends ZM_Object {
'Scheme' => 'Medium', 'Scheme' => 'Medium',
'ServerId' => 0, 'ServerId' => 0,
'DoDelete' => 1, 'DoDelete' => 1,
'Enabled' => 1,
); );
public static function find($parameters = array(), $options = array()) { public static function find($parameters = array(), $options = array()) {
return ZM_Object::_find(get_class(), $parameters, $options); return ZM_Object::_find(get_class(), $parameters, $options);

41
web/includes/Zone.php Normal file
View File

@ -0,0 +1,41 @@
<?php
namespace ZM;
require_once('database.php');
require_once('Object.php');
class Zone extends ZM_Object {
protected static $table = 'Zones';
protected $defaults = array(
'Id' => null,
'Name' => '',
'Type' => 'Active',
'Units' => 'Pixels',
'CheckMethod' => 'Blobs',
'MinPixelThreshold' => null,
'MaxPixelThreshold' => null,
'MinAlarmPixels' => null,
'MaxAlarmPixels' => null,
'FilterX' => null,
'FilterY' => null,
'MinFilterPixels' => null,
'MaxFilterPixels' => null,
'MinBlobPixels' => null,
'MaxBlobPixels' => null,
'MinBlobs' => null,
'MaxBlobs' => null,
'OverloadFrames' => 0,
'ExtendAlarmFrames' => 0,
);
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);
}
} # end class Zone
?>

View File

@ -21,38 +21,27 @@
// Group edit actions // Group edit actions
# Should probably verify that each monitor id is a valid monitor, that we have access to. # Should probably verify that each monitor id is a valid monitor, that we have access to.
# However at the moment, you have to have System permissions to do this # However at the moment, you have to have System permissions to do this
if ( ! canEdit('Groups') ) { if ( !canEdit('Groups') ) {
ZM\Warning('Need group edit permissions to edit groups'); ZM\Warning('Need group edit permissions to edit groups');
return; return;
} }
if ( $action == 'Save' ) { if ( $action == 'Save' ) {
$monitors = empty($_POST['newGroup']['MonitorIds']) ? '' : implode(',', $_POST['newGroup']['MonitorIds']);
$group_id = null; $group_id = null;
if ( !empty($_POST['gid']) ) { if ( !empty($_POST['gid']) )
$group_id = $_POST['gid']; $group_id = $_POST['gid'];
dbQuery( $group = new ZM\Group($group_id);
'UPDATE Groups SET Name=?, ParentId=? WHERE Id=?', $group->save(
array( array(
$_POST['newGroup']['Name'], 'Name'=> $_POST['newGroup']['Name'],
( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), 'ParentId'=>( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ),
$group_id,
) )
); );
dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($group_id)); dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id));
} else { $group_id = $group->Id();
dbQuery(
'INSERT INTO Groups (Name,ParentId) VALUES (?,?)',
array(
$_POST['newGroup']['Name'],
( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ),
)
);
$group_id = dbInsertId();
}
if ( $group_id ) { if ( $group_id ) {
foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) { foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) {
dbQuery('INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($group_id, $mid)); dbQuery('INSERT INTO `Groups_Monitors` (`GroupId`,`MonitorId`) VALUES (?,?)', array($group_id, $mid));
} }
} }
$view = 'none'; $view = 'none';

View File

@ -442,9 +442,10 @@ function makeLink($url, $label, $condition=1, $options='') {
*/ */
function makePopupLink($url, $winName, $winSize, $label, $condition=1, $options='') { function makePopupLink($url, $winName, $winSize, $label, $condition=1, $options='') {
// Avoid double-encoding since some consumers incorrectly pass a pre-escaped URL. // Avoid double-encoding since some consumers incorrectly pass a pre-escaped URL.
$string = '<a class="popup-link" href="' . htmlspecialchars($url, ENT_COMPAT | ENT_HTML401, ini_get("default_charset"), false) . '"'; $string = '<a';
$string .= ' data-window-name="' . htmlspecialchars($winName) . '"';
if ( $condition ) { if ( $condition ) {
$string .= ' class="popup-link" href="' . htmlspecialchars($url, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false) . '"';
$string .= ' data-window-name="' . htmlspecialchars($winName) . '"';
if ( is_array( $winSize ) ) { if ( is_array( $winSize ) ) {
$string .= ' data-window-tag="' . htmlspecialchars($winSize[0]) . '"'; $string .= ' data-window-tag="' . htmlspecialchars($winSize[0]) . '"';
$string .= ' data-window-width="' . htmlspecialchars($winSize[1]) . '"'; $string .= ' data-window-width="' . htmlspecialchars($winSize[1]) . '"';
@ -455,7 +456,7 @@ function makePopupLink($url, $winName, $winSize, $label, $condition=1, $options=
$string .= ($options ? (' ' . $options ) : '') . '>'; $string .= ($options ? (' ' . $options ) : '') . '>';
} else { } else {
$string .= '<a>'; $string .= '>';
} }
$string .= $label; $string .= $label;
$string .= '</a>'; $string .= '</a>';
@ -520,7 +521,8 @@ function htmlOptions($contents, $values) {
$options_html .= '<option value="'.htmlspecialchars($value, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'"'. $options_html .= '<option value="'.htmlspecialchars($value, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'"'.
($selected?' selected="selected"':''). ($selected?' selected="selected"':'').
($disabled?' disabled="disabled"':''). ($disabled?' disabled="disabled"':'').
'>'.htmlspecialchars($text, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'</option>'; '>'.htmlspecialchars($text, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'</option>
';
} }
return $options_html; return $options_html;
} }
@ -776,7 +778,7 @@ function canStreamIframe() {
function canStreamNative() { function canStreamNative() {
// Old versions of Chrome can display the stream, but then it blocks everything else (Chrome bug 5876) // Old versions of Chrome can display the stream, but then it blocks everything else (Chrome bug 5876)
return( ZM_WEB_CAN_STREAM == 'yes' || ( ZM_WEB_CAN_STREAM == 'auto' && (!isInternetExplorer() && !isOldChrome()) ) ); return ( ZM_WEB_CAN_STREAM == 'yes' || ( ZM_WEB_CAN_STREAM == 'auto' && (!isInternetExplorer() && !isOldChrome()) ) );
} }
function canStreamApplet() { function canStreamApplet() {
@ -908,11 +910,11 @@ function createListThumbnail($event, $overwrite=false) {
if ( ZM_WEB_LIST_THUMB_WIDTH ) { if ( ZM_WEB_LIST_THUMB_WIDTH ) {
$thumbWidth = ZM_WEB_LIST_THUMB_WIDTH; $thumbWidth = ZM_WEB_LIST_THUMB_WIDTH;
$scale = (SCALE_BASE*ZM_WEB_LIST_THUMB_WIDTH)/$event['Width']; $scale = (SCALE_BASE*ZM_WEB_LIST_THUMB_WIDTH)/$event['Width'];
$thumbHeight = reScale( $event['Height'], $scale ); $thumbHeight = reScale($event['Height'], $scale);
} elseif ( ZM_WEB_LIST_THUMB_HEIGHT ) { } elseif ( ZM_WEB_LIST_THUMB_HEIGHT ) {
$thumbHeight = ZM_WEB_LIST_THUMB_HEIGHT; $thumbHeight = ZM_WEB_LIST_THUMB_HEIGHT;
$scale = (SCALE_BASE*ZM_WEB_LIST_THUMB_HEIGHT)/$event['Height']; $scale = (SCALE_BASE*ZM_WEB_LIST_THUMB_HEIGHT)/$event['Height'];
$thumbWidth = reScale( $event['Width'], $scale ); $thumbWidth = reScale($event['Width'], $scale);
} else { } else {
ZM\Fatal('No thumbnail width or height specified, please check in Options->Web'); ZM\Fatal('No thumbnail width or height specified, please check in Options->Web');
} }
@ -949,11 +951,11 @@ function createVideo($event, $format, $rate, $scale, $overwrite=false) {
# This takes more than one scale amount, so it runs through each and alters dimension. # This takes more than one scale amount, so it runs through each and alters dimension.
# I can't imagine why you would want to do that. # I can't imagine why you would want to do that.
function reScale( $dimension, $dummy ) { function reScale($dimension, $dummy) {
$new_dimension = $dimension; $new_dimension = $dimension;
for ( $i = 1; $i < func_num_args(); $i++ ) { for ( $i = 1; $i < func_num_args(); $i++ ) {
$scale = func_get_arg( $i ); $scale = func_get_arg($i);
if ( !empty($scale) && ($scale != 'auto') && ($scale != SCALE_BASE) ) if ( !empty($scale) && ($scale != '0') && ($scale != 'auto') && ($scale != SCALE_BASE) )
$new_dimension = (int)(($new_dimension*$scale)/SCALE_BASE); $new_dimension = (int)(($new_dimension*$scale)/SCALE_BASE);
} }
return $new_dimension; return $new_dimension;
@ -1115,6 +1117,9 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][attr]").'='.urlencode($term['attr']); $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][attr]").'='.urlencode($term['attr']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][attr]\" value=\"".htmlspecialchars($term['attr'])."\"/>\n"; $filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][attr]\" value=\"".htmlspecialchars($term['attr'])."\"/>\n";
switch ( $term['attr'] ) { switch ( $term['attr'] ) {
case 'AlarmedZoneId':
$term['op'] = 'EXISTS';
break;
case 'MonitorName': case 'MonitorName':
$filter['sql'] .= 'M.Name'; $filter['sql'] .= 'M.Name';
break; break;
@ -1232,11 +1237,15 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
$valueList = array(); $valueList = array();
foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) { foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) {
switch ( $term['attr'] ) { switch ( $term['attr'] ) {
case 'AlarmedZoneId':
$value = '(SELECT * FROM Stats WHERE EventId=E.Id AND ZoneId='.$value.')';
break;
case 'MonitorName': case 'MonitorName':
case 'Name': case 'Name':
case 'Cause': case 'Cause':
case 'Notes': case 'Notes':
if($term['op'] == 'LIKE' || $term['op'] == 'NOT LIKE') { if ( $term['op'] == 'LIKE' || $term['op'] == 'NOT LIKE' ) {
$value = '%'.$value.'%'; $value = '%'.$value.'%';
} }
$value = dbEscape($value); $value = dbEscape($value);
@ -1267,8 +1276,11 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
case 'Date': case 'Date':
case 'StartDate': case 'StartDate':
case 'EndDate': case 'EndDate':
if ( $value != 'NULL' ) if ( $value == 'CURDATE()' or $value == 'NOW()' ) {
$value = 'to_days('.$value.')';
} else if ( $value != 'NULL' ) {
$value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; $value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
}
break; break;
case 'Time': case 'Time':
case 'StartTime': case 'StartTime':
@ -1303,10 +1315,13 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
break; break;
case '=[]' : case '=[]' :
case 'IN' : case 'IN' :
$filter['sql'] .= ' in ('.join(',', $valueList).')'; $filter['sql'] .= ' IN ('.join(',', $valueList).')';
break; break;
case '![]' : case '![]' :
$filter['sql'] .= ' not in ('.join(',', $valueList).')'; $filter['sql'] .= ' not in ('.join(',', $valueList).')';
break;
case 'EXISTS' :
$filter['sql'] .= ' EXISTS ' .$value;
break; break;
case 'IS' : case 'IS' :
if ( $value == 'Odd' ) { if ( $value == 'Odd' ) {
@ -2289,7 +2304,7 @@ function validHtmlStr($input) {
function getStreamHTML($monitor, $options = array()) { function getStreamHTML($monitor, $options = array()) {
if ( isset($options['scale']) ) { if ( isset($options['scale']) ) {
if ( $options['scale'] != 'auto' ) { if ( $options['scale'] and ( $options['scale'] != 'auto' ) ) {
$options['width'] = reScale($monitor->ViewWidth(), $options['scale']).'px'; $options['width'] = reScale($monitor->ViewWidth(), $options['scale']).'px';
$options['height'] = reScale($monitor->ViewHeight(), $options['scale']).'px'; $options['height'] = reScale($monitor->ViewHeight(), $options['scale']).'px';
} else { } else {

View File

@ -18,32 +18,44 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// //
function translate( $name ) { function translate($name) {
global $SLANG; global $SLANG;
if ( array_key_exists($name, $SLANG) ) // The isset is more performant
if ( isset($SLANG[$name]) || array_key_exists($name, $SLANG) )
return $SLANG[$name]; return $SLANG[$name];
else else
return $name; return $name;
} }
function loadLanguage( $prefix='' ) { function loadLanguage($prefix='') {
global $user; global $user;
if ( $prefix ) if ( $prefix )
$prefix = $prefix.'/'; $prefix = $prefix.'/';
$fallbackLangFile = $prefix.'lang/en_gb.php'; if ( isset($user['Language']) and $user['Language'] ) {
$systemLangFile = $prefix.'lang/'.ZM_LANG_DEFAULT.'.php';
if ( isset($user['Language']) )
$userLangFile = $prefix.'lang/'.$user['Language'].'.php'; $userLangFile = $prefix.'lang/'.$user['Language'].'.php';
if ( isset($userLangFile) && file_exists($userLangFile) ) if ( file_exists($userLangFile) ) {
return $userLangFile; return $userLangFile;
elseif ( file_exists($systemLangFile) ) } else {
ZM\Warning("User language file $userLangFile does not exist.");
}
}
$systemLangFile = $prefix.'lang/'.ZM_LANG_DEFAULT.'.php';
if ( file_exists($systemLangFile) ) {
return $systemLangFile; return $systemLangFile;
elseif ( file_exists($fallbackLangFile) ) } else {
ZM\Warning("System language file $systemLangFile does not exist.");
}
$fallbackLangFile = $prefix.'lang/en_gb.php';
if ( file_exists($fallbackLangFile) ) {
return $fallbackLangFile; return $fallbackLangFile;
else } else {
ZM\Error("Default language file $fallbackLangFile does not exist.");
}
return false; return false;
} }
@ -51,7 +63,7 @@ if ( $langFile = loadLanguage() ) {
require_once($langFile); require_once($langFile);
require_once('lang/default.php'); require_once('lang/default.php');
foreach ($DLANG as $key => $value) { foreach ($DLANG as $key => $value) {
if ( ! array_key_exists($key, $SLANG) ) if ( ! (isset($SLANG[$key]) || array_key_exists($key, $SLANG)) )
$SLANG[$key] = $DLANG[$key]; $SLANG[$key] = $DLANG[$key];
} }
} }

View File

@ -34,7 +34,7 @@ if ( version_compare(phpversion(), '4.1.0', '<') ) {
} }
// Useful debugging lines for mobile devices // Useful debugging lines for mobile devices
if ( false ) { if ( true ) {
ob_start(); ob_start();
phpinfo(INFO_VARIABLES); phpinfo(INFO_VARIABLES);
$fp = fopen('/tmp/env.html', 'w+'); $fp = fopen('/tmp/env.html', 'w+');
@ -52,6 +52,8 @@ require_once('includes/Event.php');
require_once('includes/Group.php'); require_once('includes/Group.php');
require_once('includes/Monitor.php'); require_once('includes/Monitor.php');
$Servers = ZM\Server::find();
if ( if (
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
or or
@ -71,7 +73,7 @@ define('ZM_BASE_URL', '');
require_once('includes/functions.php'); require_once('includes/functions.php');
if ( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ) { if ( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ) {
ZM\Logger::Debug("OPTIONS Method, only doing CORS"); ZM\Logger::Debug('OPTIONS Method, only doing CORS');
# Add Cross domain access headers # Add Cross domain access headers
CORSHeaders(); CORSHeaders();
return; return;

View File

@ -49,6 +49,8 @@ function logReport( level, message, file, line ) {
/* eslint-disable no-caller */ /* eslint-disable no-caller */
if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.caller && arguments.callee.caller.caller.name ) { if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.caller && arguments.callee.caller.caller.name ) {
message += ' - '+arguments.callee.caller.caller.name+'()'; message += ' - '+arguments.callee.caller.caller.name+'()';
} else {
message += new Error().stack;
} }
/* eslint-enable no-caller */ /* eslint-enable no-caller */

View File

@ -51,8 +51,8 @@ var Overlay = new Class({
}, },
show: function() { show: function() {
this.mask.show(); this.mask.show();
window.addEventListener( 'resize', this.update.bind(this) ); window.addEventListener( 'resize', this.update.bind(this), {passive: true} );
window.addEventListener( 'scroll', this.update.bind(this) ); window.addEventListener( 'scroll', this.update.bind(this), {passive: true} );
this.element.tween( 'opacity', [0, 1.0] ); this.element.tween( 'opacity', [0, 1.0] );
this.element.show(); this.element.show();
this.element.position(); this.element.position();
@ -80,8 +80,8 @@ var Overlay = new Class({
} }
updateOverlayLoading(); updateOverlayLoading();
this.loading.setStyle( 'display', 'block' ); this.loading.setStyle( 'display', 'block' );
window.addEventListener( 'resize', this.update.bind(this) ); window.addEventListener( 'resize', this.update.bind(this), {passive: true} );
window.addEventListener( 'scroll', this.update.bind(this) ); window.addEventListener( 'scroll', this.update.bind(this), {passive: true} );
}, },
hideAnimation: function() { hideAnimation: function() {
if ( this.loading ) { if ( this.loading ) {

View File

@ -116,6 +116,7 @@ $SLANG = array(
'Area' => 'Area', 'Area' => 'Area',
'AreaUnits' => 'Area (px/%)', 'AreaUnits' => 'Area (px/%)',
'AttrAlarmFrames' => 'Alarm Frames', 'AttrAlarmFrames' => 'Alarm Frames',
'AttrAlarmedZone' => 'Alarmed Zone',
'AttrArchiveStatus' => 'Archive Status', 'AttrArchiveStatus' => 'Archive Status',
'AttrAvgScore' => 'Avg. Score', 'AttrAvgScore' => 'Avg. Score',
'AttrCause' => 'Cause', 'AttrCause' => 'Cause',
@ -361,6 +362,9 @@ $SLANG = array(
'FilterCopyEvents' => 'Copy 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',
'FilterEmailTo' => 'Email To',
'FilterEmailSubject' => 'Email Subject',
'FilterEmailBody' => 'Email Body',
'FilterExecuteEvents' => 'Execute command on all matches', 'FilterExecuteEvents' => 'Execute command on all matches',
'FilterLog' => 'Filter log', 'FilterLog' => 'Filter log',
'FilterMessageEvents' => 'Message details of all matches', 'FilterMessageEvents' => 'Message details of all matches',

View File

@ -56,9 +56,14 @@ select {
width: 300px; width: 300px;
text-align: right; text-align: right;
} }
input[name="filter[EmailSubject]"],
input[name="filter[EmailTo]"],
textarea[name="filter[EmailBody]"] {
width: 500px;
}
select#Id { select#Id {
min-width: 400px; min-width: 500px;
} }
.Name input { .Name input {
min-width: 400px; min-width: 500px;
} }

View File

@ -10,7 +10,9 @@
} }
textarea, textarea,
input[name="newMonitor[Name]"] { input[name="newMonitor[Name]"],
input[name="newMonitor[ControlDevice]"],
input[name="newMonitor[ControlAddress]"] {
width: 100%; width: 100%;
} }
input[name="newMonitor[Width]"], input[name="newMonitor[Width]"],

View File

@ -31,7 +31,7 @@ $rates = array(
); );
$scales = array( $scales = array(
'auto' => translate('Scale to Fit'), '0' => translate('Scale to Fit'),
'' => translate('Fixed Width/Height'), '' => translate('Fixed Width/Height'),
'400' => '4x', '400' => '4x',
'300' => '3x', '300' => '3x',
@ -45,7 +45,7 @@ $scales = array(
'12.5' => '1/8x', '12.5' => '1/8x',
); );
if (isset($_REQUEST['view']) && ($_REQUEST['view'] == 'montage')) { if ( isset($_REQUEST['view']) && ($_REQUEST['view'] == 'montage') ) {
unset($scales['auto']); //Remove auto on montage, use everywhere else unset($scales['auto']); //Remove auto on montage, use everywhere else
} else { } else {
unset($scales['']); //Remove fixed on everything but montage unset($scales['']); //Remove fixed on everything but montage

View File

@ -352,7 +352,7 @@ if ( ZM_OPT_USE_AUTH and $user ) {
?> ?>
<p class="navbar-text"> <p class="navbar-text">
<i class="material-icons">account_circle</i> <i class="material-icons">account_circle</i>
<?php echo makePopupLink( '?view=logout', 'zmLogout', 'logout', $user['Username'], (ZM_AUTH_TYPE == "builtin") ) ?> <?php echo makePopupLink('?view=logout', 'zmLogout', 'logout', $user['Username'], (ZM_AUTH_TYPE == 'builtin')) ?>
</p> </p>
<?php <?php
} }
@ -396,7 +396,7 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) {
?> ?>
<li><?php echo translate('Storage') ?>: <li><?php echo translate('Storage') ?>:
<?php <?php
$storage_areas = ZM\Storage::find(); $storage_areas = ZM\Storage::find(array('Enabled'=>true));
$storage_paths = null; $storage_paths = null;
$storage_areas_with_no_server_id = array(); $storage_areas_with_no_server_id = array();
foreach ( $storage_areas as $area ) { foreach ( $storage_areas as $area ) {

View File

@ -63,7 +63,7 @@ var popupSizes = {
'shutdown': {'width': 400, 'height': 400}, 'shutdown': {'width': 400, 'height': 400},
'state': {'width': 400, 'height': 170}, 'state': {'width': 400, 'height': 170},
'stats': {'width': 840, 'height': 200}, 'stats': {'width': 840, 'height': 200},
'storage': {'width': 600, 'height': 405}, 'storage': {'width': 600, 'height': 425},
'timeline': {'width': 760, 'height': 540}, 'timeline': {'width': 760, 'height': 540},
'user': {'width': 460, 'height': 720}, 'user': {'width': 460, 'height': 720},
'version': {'width': 360, 'height': 210}, 'version': {'width': 360, 'height': 210},

View File

@ -63,7 +63,7 @@ var popupSizes = {
'settings': {'width': 220, 'height': 225}, 'settings': {'width': 220, 'height': 225},
'state': {'width': 370, 'height': 134}, 'state': {'width': 370, 'height': 134},
'stats': {'width': 840, 'height': 200}, 'stats': {'width': 840, 'height': 200},
'storage': {'width': 600, 'height': 405}, 'storage': {'width': 600, 'height': 425},
'timeline': {'width': 760, 'height': 540}, 'timeline': {'width': 760, 'height': 540},
'user': {'width': 360, 'height': 720}, 'user': {'width': 360, 'height': 720},
'version': {'width': 360, 'height': 140}, 'version': {'width': 360, 'height': 140},

View File

@ -530,3 +530,17 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) {
autoScale = closest; autoScale = closest;
return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale}; return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale};
} }
function setButtonState(element_id, butClass) {
var element = $(element_id);
if ( element ) {
element.className = butClass;
if (butClass == 'unavail' || (butClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) {
element.disabled = true;
} else {
element.disabled = false;
}
} else {
console.log('Element was null or not found in setButtonState. id:'+element_id);
}
}

View File

@ -233,7 +233,7 @@ $html .= '</span>
} }
} }
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name']; $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Id'].' '.$monitors[$i]['Name'];
if ( count($selected_monitor_ids) and ! in_array($monitors[$i]['Id'], $selected_monitor_ids) ) { if ( count($selected_monitor_ids) and ! in_array($monitors[$i]['Id'], $selected_monitor_ids) ) {
continue; continue;

View File

@ -40,7 +40,7 @@ if ( empty($_REQUEST['mode']) ) {
} }
$widths = array( $widths = array(
'' => translate('auto'), 'auto' => translate('auto'),
'100%' => '100%', '100%' => '100%',
'160px' => '160px', '160px' => '160px',
'320px' => '320px', '320px' => '320px',
@ -62,13 +62,11 @@ session_start();
if ( isset($_REQUEST['scale']) ) { if ( isset($_REQUEST['scale']) ) {
$options['scale'] = validInt($_REQUEST['scale']); $options['scale'] = validInt($_REQUEST['scale']);
ZM\Logger::Debug('Setting scale from request to '.$options['scale']);
} else if ( isset($_COOKIE['zmCycleScale']) ) { } else if ( isset($_COOKIE['zmCycleScale']) ) {
$options['scale'] = $_COOKIE['zmCycleScale']; $options['scale'] = $_COOKIE['zmCycleScale'];
ZM\Logger::Debug('Setting scale from cookie to '.$options['scale']);
} }
if ( !(isset($options['scale']) and $options['scale']) ) if ( !isset($options['scale']) )
$options['scale'] = 100; $options['scale'] = 100;
if ( isset($_COOKIE['zmCycleWidth']) and $_COOKIE['zmCycleWidth'] ) { if ( isset($_COOKIE['zmCycleWidth']) and $_COOKIE['zmCycleWidth'] ) {

View File

@ -48,7 +48,7 @@ if ( isset($_REQUEST['scale']) ) {
$scale = validInt($_REQUEST['scale']); $scale = validInt($_REQUEST['scale']);
} else if ( isset($_COOKIE['zmEventScaleAuto']) ) { } else if ( isset($_COOKIE['zmEventScaleAuto']) ) {
// If we're using scale to fit use it on all monitors // If we're using scale to fit use it on all monitors
$scale = 'auto'; $scale = '0';
} else if ( isset($_COOKIE['zmEventScale'.$Event->MonitorId()]) ) { } else if ( isset($_COOKIE['zmEventScale'.$Event->MonitorId()]) ) {
$scale = $_COOKIE['zmEventScale'.$Event->MonitorId()]; $scale = $_COOKIE['zmEventScale'.$Event->MonitorId()];
} else { } else {
@ -85,9 +85,9 @@ else
$streamMode = 'video'; $streamMode = 'video';
$replayMode = ''; $replayMode = '';
if ( isset( $_REQUEST['replayMode'] ) ) if ( isset($_REQUEST['replayMode']) )
$replayMode = validHtmlStr($_REQUEST['replayMode']); $replayMode = validHtmlStr($_REQUEST['replayMode']);
if ( isset( $_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) ) if ( isset($_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) )
$replayMode = validHtmlStr($_COOKIE['replayMode']); $replayMode = validHtmlStr($_COOKIE['replayMode']);
if ( ( ! $replayMode ) or ( ! $replayModes[$replayMode] ) ) { if ( ( ! $replayMode ) or ( ! $replayModes[$replayMode] ) ) {
@ -104,7 +104,10 @@ if ( $Monitor->VideoWriter() == '2' ) {
$Zoom = $Event->Height()/$Event->Width(); $Zoom = $Event->Height()/$Event->Width();
} }
// These are here to figure out the next/prev event // These are here to figure out the next/prev event, however id there is no filter, then default to one that specifies the Monitor
if ( !isset($_REQUEST['filter']) ) {
$_REQUEST['filter'] = array( 'Query'=>array('terms'=> array( array('attr' => 'MonitorId', 'op' => '=', 'val' => $Event->MonitorId() ) ) ) );
}
parseSort(); parseSort();
parseFilter($_REQUEST['filter']); parseFilter($_REQUEST['filter']);
$filterQuery = $_REQUEST['filter']['query']; $filterQuery = $_REQUEST['filter']['query'];
@ -122,7 +125,7 @@ xhtmlHeaders(__FILE__, translate('Event'));
<?php if ( !$popup ) echo getNavBarHTML() ?> <?php if ( !$popup ) echo getNavBarHTML() ?>
<div id="header"> <div id="header">
<?php <?php
if ( ! $Event->Id() ) { if ( !$Event->Id() ) {
echo 'Event was not found.'; echo 'Event was not found.';
} else { } else {
?> ?>
@ -193,9 +196,9 @@ if ( ($codec == 'MP4' || $codec == 'auto' ) && $Event->DefaultVideo() ) {
?> ?>
<div id="videoFeed"> <div id="videoFeed">
<video id="videoobj" class="video-js vjs-default-skin" <video id="videoobj" class="video-js vjs-default-skin"
style="transform: matrix(1, 0, 0, 1, 0, 0)" style="transform: matrix(1, 0, 0, 1, 0, 0);"
width="<?php echo reScale($Event->Width(), $scale) ?>" <?php echo $scale ? 'width="'.reScale($Event->Width(), $scale).'"' : '' ?>
height="<?php echo reScale($Event->Height(), $scale) ?>" <?php echo $scale ? 'height="'.reScale($Event->Height(), $scale).'"' : '' ?>
data-setup='{ "controls": true, "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}' data-setup='{ "controls": true, "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'
> >
<source src="<?php echo $Event->getStreamSrc(array('mode'=>'mpeg','format'=>'h264'),'&amp;'); ?>" type="video/mp4"> <source src="<?php echo $Event->getStreamSrc(array('mode'=>'mpeg','format'=>'h264'),'&amp;'); ?>" type="video/mp4">
@ -208,7 +211,7 @@ if ( ($codec == 'MP4' || $codec == 'auto' ) && $Event->DefaultVideo() ) {
?> ?>
<div id="imageFeed"> <div id="imageFeed">
<?php <?php
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { if ( (ZM_WEB_STREAM_METHOD == 'mpeg') && ZM_MPEG_LIVE_FORMAT ) {
$streamSrc = $Event->getStreamSrc(array('mode'=>'mpeg', 'scale'=>$scale, 'rate'=>$rate, 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format'=>ZM_MPEG_REPLAY_FORMAT, 'replay'=>$replayMode),'&amp;'); $streamSrc = $Event->getStreamSrc(array('mode'=>'mpeg', 'scale'=>$scale, 'rate'=>$rate, 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format'=>ZM_MPEG_REPLAY_FORMAT, 'replay'=>$replayMode),'&amp;');
outputVideoStream('evtStream', $streamSrc, reScale( $Event->Width(), $scale ).'px', reScale( $Event->Height(), $scale ).'px', ZM_MPEG_LIVE_FORMAT ); outputVideoStream('evtStream', $streamSrc, reScale( $Event->Width(), $scale ).'px', reScale( $Event->Height(), $scale ).'px', ZM_MPEG_LIVE_FORMAT );
} else { } else {
@ -257,7 +260,12 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
</p> </p>
<div id="replayStatus"> <div id="replayStatus">
<span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue">Replay</span></span> <span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue">Replay</span></span>
<span id="rate"><?php echo translate('Rate') ?>: <span id="rateValue"><?php echo $rate/100 ?></span>x</span> <span id="rate"><?php echo translate('Rate') ?>:
<?php
$rates = array( -800=>'-8x', -400=>'-4x', -200=>'-2x', -100=>'-1x', 0=>translate('Stop'), 100 => '1x', 200=>'2x', 400=>'4x', 800=>'8x' );
echo htmlSelect('rate', $rates, intval($rate), array('id'=>'rateValue'));
?>
<!--<span id="rateValue"><?php echo $rate/100 ?></span>x</span>-->
<span id="progress"><?php echo translate('Progress') ?>: <span id="progressValue">0</span>s</span> <span id="progress"><?php echo translate('Progress') ?>: <span id="progressValue">0</span>s</span>
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue">1</span>x</span> <span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue">1</span>x</span>
</div> </div>

View File

@ -191,21 +191,25 @@ while ( $event_row = dbFetchNext($results) ) {
?> ?>
<tr<?php if ($event->Archived()) echo ' class="archived"' ?>> <tr<?php if ($event->Archived()) echo ' class="archived"' ?>>
<td class="colId"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.$event->Id().($event->Archived()?'*':'') ?></a></td> <td class="colId"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.$event->Id().($event->Archived()?'*':'') ?></a></td>
<td class="colName"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a></td> <td class="colName"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a><br/>
<?php
if ( $event->Emailed() )
echo 'Emailed ';
?>
</td>
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->MonitorId(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td> <td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->MonitorId(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?> <td class="colCause"><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?>
<?php <?php
# display notes as small text # display notes as small text
if ($event->Notes()) { if ( $event->Notes() ) {
# if notes include detection objects, then link it to objdetect.jpg # if notes include detection objects, then link it to objdetect.jpg
if (strpos($event->Notes(),'detected:')!== false){ if ( strpos($event->Notes(), 'detected:') !== false ) {
# make a link # make a link
echo makePopupLink( '?view=image&amp;eid='.$event->Id().'&amp;fid=objdetect', 'zmImage', echo makePopupLink( '?view=image&amp;eid='.$event->Id().'&amp;fid=objdetect', 'zmImage',
array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)), array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)),
"<div class=\"small text-nowrap text-muted\"><u>".$event->Notes()."</u></div>"); '<div class="small text-nowrap text-muted"><u>'.$event->Notes().'</u></div>');
} } else if ( $event->Notes() != 'Forced Web: ' ) {
elseif ($event->Notes() != 'Forced Web: ') { echo '<br/><div class="small text-nowrap text-muted">'.$event->Notes().'</div>';
echo "<br/><div class=\"small text-nowrap text-muted\">".$event->Notes()."</div>";
} }
} }
?> ?>

View File

@ -1,6 +1,6 @@
<?php <?php
// //
// ZoneMinder web filter view file, $Date$, $Revision$ // ZoneMinder web filter view file
// Copyright (C) 2001-2008 Philip Coombes // Copyright (C) 2001-2008 Philip Coombes
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
@ -25,6 +25,8 @@ if ( !canView('Events') ) {
require_once('includes/Object.php'); require_once('includes/Object.php');
require_once('includes/Storage.php'); require_once('includes/Storage.php');
require_once('includes/Filter.php'); require_once('includes/Filter.php');
require_once('includes/Monitor.php');
require_once('includes/Zone.php');
parseSort(); parseSort();
$filterNames = array(''=>translate('ChooseFilter')); $filterNames = array(''=>translate('ChooseFilter'));
@ -69,6 +71,7 @@ if ( count($terms) ) {
$attrTypes = array( $attrTypes = array(
'AlarmFrames' => translate('AttrAlarmFrames'), 'AlarmFrames' => translate('AttrAlarmFrames'),
'AlarmedZoneId' => translate('AttrAlarmedZone'),
'Archived' => translate('AttrArchiveStatus'), 'Archived' => translate('AttrArchiveStatus'),
'AvgScore' => translate('AttrAvgScore'), 'AvgScore' => translate('AttrAvgScore'),
'Cause' => translate('AttrCause'), 'Cause' => translate('AttrCause'),
@ -78,17 +81,17 @@ $attrTypes = array(
'EndDateTime' => translate('AttrEndDateTime'), 'EndDateTime' => translate('AttrEndDateTime'),
'EndDate' => translate('AttrEndDate'), 'EndDate' => translate('AttrEndDate'),
'EndTime' => translate('AttrEndTime'), 'EndTime' => translate('AttrEndTime'),
'EndWeekday' => translate('AttrEndWeekday'),
'FilterServerId' => translate('AttrFilterServer'), 'FilterServerId' => translate('AttrFilterServer'),
'Frames' => translate('AttrFrames'), 'Frames' => translate('AttrFrames'),
'EndWeekday' => translate('AttrEndWeekday'),
'Id' => translate('AttrId'), 'Id' => translate('AttrId'),
'Length' => translate('AttrDuration'), 'Length' => translate('AttrDuration'),
'Name' => translate('AttrName'),
'Notes' => translate('AttrNotes'),
'MaxScore' => translate('AttrMaxScore'), 'MaxScore' => translate('AttrMaxScore'),
'MonitorId' => translate('AttrMonitorId'), 'MonitorId' => translate('AttrMonitorId'),
'MonitorName' => translate('AttrMonitorName'), 'MonitorName' => translate('AttrMonitorName'),
'MonitorServerId' => translate('AttrMonitorServer'), 'MonitorServerId' => translate('AttrMonitorServer'),
'Name' => translate('AttrName'),
'Notes' => translate('AttrNotes'),
'SecondaryStorageId' => translate('AttrSecondaryStorageArea'), 'SecondaryStorageId' => translate('AttrSecondaryStorageArea'),
'ServerId' => translate('AttrMonitorServer'), 'ServerId' => translate('AttrMonitorServer'),
'StartDateTime' => translate('AttrStartDateTime'), 'StartDateTime' => translate('AttrStartDateTime'),
@ -143,13 +146,22 @@ foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Servers` ORDER BY lower(`Name`)
$servers[$server['Id']] = validHtmlStr($server['Name']); $servers[$server['Id']] = validHtmlStr($server['Name']);
} }
$monitors = array(); $monitors = array();
$monitor_names = array();
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Monitors` ORDER BY lower(`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['Id']] = new ZM\Monitor($monitor);
$monitor_names[] = validHtmlStr($monitor['Name']);
}
}
$zones = array();
foreach ( dbFetchAll('SELECT Id, Name, MonitorId FROM Zones ORDER BY lower(`Name`) ASC') as $zone ) {
if ( visibleMonitor($zone['MonitorId']) ) {
$zone['Name'] = validHtmlStr($monitors[$zone['MonitorId']]->Name().': '.$zone['Name']);
$zones[$zone['Id']] = new ZM\Zone($zone);
} }
} }
xhtmlHeaders(__FILE__, translate('EventFilter') ); xhtmlHeaders(__FILE__, translate('EventFilter'));
?> ?>
<body> <body>
<div id="page"> <div id="page">
@ -259,10 +271,15 @@ 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]", $weekdays, $term['val']); ?></td> <td><?php echo htmlSelect("filter[Query][terms][$i][val]", $weekdays, $term['val']); ?></td>
<?php <?php
} elseif ( $term['attr'] == 'MonitorName' ) { } elseif ( $term['attr'] == 'Monitor' ) {
?> ?>
<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]", $monitors, $term['val']); ?></td> <td><?php echo htmlSelect("filter[Query][terms][$i][val]", $monitors, $term['val']); ?></td>
<?php
} elseif ( $term['attr'] == 'MonitorName' ) {
?>
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", array_combine($monitor_names,$monitor_names), $term['val']); ?></td>
<?php <?php
} elseif ( $term['attr'] == 'ServerId' || $term['attr'] == 'MonitorServerId' || $term['attr'] == 'StorageServerId' || $term['attr'] == 'FilterServerId' ) { } elseif ( $term['attr'] == 'ServerId' || $term['attr'] == 'MonitorServerId' || $term['attr'] == 'StorageServerId' || $term['attr'] == 'FilterServerId' ) {
?> ?>
@ -273,6 +290,11 @@ 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]", $storageareas, $term['val']); ?></td> <td><?php echo htmlSelect("filter[Query][terms][$i][val]", $storageareas, $term['val']); ?></td>
<?php
} elseif ( $term['attr'] == 'AlarmedZoneId' ) {
?>
<td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
<td><?php echo htmlSelect("filter[Query][terms][$i][val]", $zones, $term['val']); ?></td>
<?php <?php
} else { } else {
?> ?>
@ -365,8 +387,22 @@ if ( ZM_OPT_EMAIL ) {
?> ?>
<p> <p>
<label><?php echo translate('FilterEmailEvents') ?></label> <label><?php echo translate('FilterEmailEvents') ?></label>
<input type="checkbox" name="filter[AutoEmail]" value="1"<?php if ( $filter->AutoEmail() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/> <input type="checkbox" name="filter[AutoEmail]" value="1"<?php if ( $filter->AutoEmail() ) { ?> checked="checked"<?php } ?> data-on-click-this="click_AutoEmail"/>
</p> </p>
<div id="EmailOptions"<?php echo $filter->AutoEmail() ? '' : ' style="display:none;"' ?>>
<p>
<label><?php echo translate('FilterEmailTo') ?></label>
<input type="email" name="filter[EmailTo]" value="<?php echo validHtmlStr($filter->EmailTo()) ?>" multiple/>
</p>
<p>
<label><?php echo translate('FilterEmailSubject') ?></label>
<input type="text" name="filter[EmailSubject]" value="<?php echo validHtmlStr($filter->EmailSubject()) ?>"/>
</p>
<p>
<label><?php echo translate('FilterEmailBody') ?></label>
<textarea name="filter[EmailBody]"><?php echo validHtmlStr($filter->EmailBody()) ?></textarea>
</p>
</div>
<?php <?php
} }
if ( ZM_OPT_MESSAGE ) { if ( ZM_OPT_MESSAGE ) {
@ -409,7 +445,7 @@ if ( ZM_OPT_MESSAGE ) {
<hr/> <hr/>
<div id="contentButtons"> <div id="contentButtons">
<button type="submit" data-on-click-this="submitToEvents"><?php echo translate('ListMatches') ?></button> <button type="submit" data-on-click-this="submitToEvents"><?php echo translate('ListMatches') ?></button>
<!--<button type="submit" data-on-click-this="submitToMontageReview"><?php echo translate('ViewMatches') ?></button>--> <button type="button" data-on-click-this="submitToMontageReview"><?php echo translate('ViewMatches') ?></button>
<button type="button" data-on-click-this="submitToExport"><?php echo translate('ExportMatches') ?></button> <button type="button" data-on-click-this="submitToExport"><?php echo translate('ExportMatches') ?></button>
<button type="button" name="executeButton" id="executeButton" data-on-click-this="executeFilter"><?php echo translate('Execute') ?></button> <button type="button" name="executeButton" id="executeButton" data-on-click-this="executeFilter"><?php echo translate('Execute') ?></button>
<?php <?php

View File

@ -46,7 +46,7 @@ function changeSize() {
// Scale the frame // Scale the frame
monitor_frame = $j('#imageFeed'); monitor_frame = $j('#imageFeed');
if ( !monitor_frame ) { if ( !monitor_frame ) {
console.log("Error finding frame"); console.log('Error finding frame');
return; return;
} }
if ( width ) { if ( width ) {
@ -92,15 +92,21 @@ function changeScale() {
// Scale the frame // Scale the frame
monitor_frame = $j('#imageFeed'); monitor_frame = $j('#imageFeed');
if ( !monitor_frame ) { if ( !monitor_frame ) {
console.log("Error finding frame"); console.log('Error finding frame');
return; return;
} }
if ( scale != '0' ) {
if ( newWidth ) { if ( newWidth ) {
monitor_frame.css('width', newWidth+'px'); monitor_frame.css('width', newWidth+'px');
} }
if ( newHeight ) { if ( newHeight ) {
monitor_frame.css('height', newHeight+'px'); monitor_frame.css('height', newHeight+'px');
} }
} else {
monitor_frame.css('width', '100%');
monitor_frame.css('height', 'auto');
}
/*Stream could be an applet so can't use moo tools*/ /*Stream could be an applet so can't use moo tools*/
var streamImg = $j('#liveStream'+monitorData[monIdx].id)[0]; var streamImg = $j('#liveStream'+monitorData[monIdx].id)[0];
if ( streamImg ) { if ( streamImg ) {
@ -110,12 +116,22 @@ function changeScale() {
//src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) )); //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
src = src.replace(/scale=[\.\d]+/i, 'scale='+scale); src = src.replace(/scale=[\.\d]+/i, 'scale='+scale);
if ( scale != '0' ) {
src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); src = src.replace(/width=[\.\d]+/i, 'width='+newWidth);
src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); src = src.replace(/height=[\.\d]+/i, 'height='+newHeight);
} else {
src = src.replace(/width=[\.\d]+/i, 'width='+monitorData[monIdx].width);
src = src.replace(/height=[\.\d]+/i, 'height='+monitorData[monIdx].height);
}
streamImg.src = src; streamImg.src = src;
} }
streamImg.style.width = newWidth + 'px'; if ( scale != '0' ) {
streamImg.style.height = newHeight + 'px'; streamImg.style.width = newWidth+'px';
streamImg.style.height = newHeight+'px';
} else {
streamImg.style.width = '100%';
streamImg.style.height = 'auto';
}
} else { } else {
console.log("Did not find liveStream"+monitorData[monIdx].id); console.log("Did not find liveStream"+monitorData[monIdx].id);
} }

View File

@ -1,4 +1,7 @@
var vid = null; var vid = null;
var spf = Math.round((eventData.Length / eventData.Frames)*1000000 )/1000000;//Seconds per frame for videojs frame by frame.
var intervalRewind;
var revSpeed = .5;
// Function called when video.js hits the end of the video // Function called when video.js hits the end of the video
function vjsReplay() { function vjsReplay() {
@ -39,7 +42,7 @@ function vjsReplay() {
streamNext(true); streamNext(true);
break; break;
} }
} } // end function vjsReplay
$j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON. $j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON.
@ -67,14 +70,14 @@ function renderAlarmCues(containerEl) {
var spanTimeStart = 0; var spanTimeStart = 0;
var spanTimeEnd = 0; var spanTimeEnd = 0;
var alarmed = 0; var alarmed = 0;
var alarmHtml = ""; var alarmHtml = '';
var pixSkew = 0; var pixSkew = 0;
var skip = 0; var skip = 0;
var num_cueFrames = cueFrames.length; var num_cueFrames = cueFrames.length;
for ( var i = 0; i < num_cueFrames; i++ ) { for ( var i = 0; i < num_cueFrames; i++ ) {
skip = 0; skip = 0;
frame = cueFrames[i]; frame = cueFrames[i];
if (frame.Type == "Alarm" && alarmed == 0) { //From nothing to alarm. End nothing and start alarm. if ( (frame.Type == 'Alarm') && (alarmed == 0) ) { //From nothing to alarm. End nothing and start alarm.
alarmed = 1; alarmed = 1;
if (frame.Delta == 0) continue; //If event starts with an alarm or too few for a nonespan if (frame.Delta == 0) continue; //If event starts with an alarm or too few for a nonespan
spanTimeEnd = frame.Delta * 100; spanTimeEnd = frame.Delta * 100;
@ -88,24 +91,24 @@ function renderAlarmCues(containerEl) {
} }
alarmHtml += '<span class="alarmCue noneCue" style="width: ' + pix + 'px;"></span>'; alarmHtml += '<span class="alarmCue noneCue" style="width: ' + pix + 'px;"></span>';
spanTimeStart = spanTimeEnd; spanTimeStart = spanTimeEnd;
} else if (frame.Type !== "Alarm" && alarmed == 1) { //from alarm to nothing. End alarm and start nothing. } else if ( (frame.Type !== 'Alarm') && (alarmed == 1) ) { //from alarm to nothing. End alarm and start nothing.
futNone = 0; futNone = 0;
indexPlus = i+1; indexPlus = i+1;
if (((frame.Delta * 100) - spanTimeStart) < minAlarm && indexPlus < num_cueFrames) { if (((frame.Delta * 100) - spanTimeStart) < minAlarm && indexPlus < num_cueFrames) {
//alarm is too short and there is more event //alarm is too short and there is more event
continue; continue;
} }
while (futNone < minAlarm) { //check ahead to see if there's enough for a nonespan while ( futNone < minAlarm ) { //check ahead to see if there's enough for a nonespan
if (indexPlus >= cueFrames.length) break; //check if end of event. if ( indexPlus >= cueFrames.length ) break; //check if end of event.
futNone = (cueFrames[indexPlus].Delta *100) - (frame.Delta *100); futNone = (cueFrames[indexPlus].Delta *100) - (frame.Delta *100);
if (cueFrames[indexPlus].Type == "Alarm") { if ( cueFrames[indexPlus].Type == 'Alarm' ) {
i = --indexPlus; i = --indexPlus;
skip = 1; skip = 1;
break; break;
} }
indexPlus++; indexPlus++;
} }
if (skip == 1) continue; //javascript doesn't support continue 2; if ( skip == 1 ) continue; //javascript doesn't support continue 2;
spanTimeEnd = frame.Delta *100; spanTimeEnd = frame.Delta *100;
spanTime = spanTimeEnd - spanTimeStart; spanTime = spanTimeEnd - spanTimeStart;
alarmed = 0; alarmed = 0;
@ -118,7 +121,7 @@ function renderAlarmCues(containerEl) {
} }
alarmHtml += '<span class="alarmCue" style="width: ' + pix + 'px;"></span>'; alarmHtml += '<span class="alarmCue" style="width: ' + pix + 'px;"></span>';
spanTimeStart = spanTimeEnd; spanTimeStart = spanTimeEnd;
} else if (frame.Type == "Alarm" && alarmed == 1 && i + 1 >= cueFrames.length) { //event ends on an alarm } else if ( (frame.Type == 'Alarm') && (alarmed == 1) && (i + 1 >= cueFrames.length) ) { //event ends on an alarm
spanTimeEnd = frame.Delta * 100; spanTimeEnd = frame.Delta * 100;
spanTime = spanTimeEnd - spanTimeStart; spanTime = spanTimeEnd - spanTimeStart;
alarmed = 0; alarmed = 0;
@ -130,18 +133,6 @@ function renderAlarmCues(containerEl) {
return alarmHtml; return alarmHtml;
} }
function setButtonState( element, butClass ) {
if ( element ) {
element.className = butClass;
if (butClass == 'unavail' || (butClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) {
element.disabled = true;
} else {
element.disabled = false;
}
} else {
console.log('Element was null in setButtonState');
}
}
function changeCodec() { function changeCodec() {
location.replace(thisUrl + '?view=event&eid=' + eventData.Id + filterQuery + sortQuery+'&codec='+$j('#codec').val()); location.replace(thisUrl + '?view=event&eid=' + eventData.Id + filterQuery + sortQuery+'&codec='+$j('#codec').val());
@ -155,12 +146,12 @@ function changeScale() {
var eventViewer; var eventViewer;
var alarmCue = $j('div.alarmCue'); var alarmCue = $j('div.alarmCue');
var bottomEl = streamMode == 'stills' ? $j('#eventImageNav') : $j('#replayStatus'); var bottomEl = streamMode == 'stills' ? $j('#eventImageNav') : $j('#replayStatus');
if (streamMode == 'stills') { if ( streamMode == 'stills' ) {
eventViewer = $j('#eventThumbs'); eventViewer = $j('#eventThumbs');
} else { } else {
eventViewer = $j(vid ? '#videoobj' : '#evtStream'); eventViewer = $j(vid ? '#videoobj' : '#evtStream');
} }
if ( scale == "auto" ) { if ( scale == '0' || scale == 'auto' ) {
var newSize = scaleToFit(eventData.Width, eventData.Height, eventViewer, bottomEl); var newSize = scaleToFit(eventData.Width, eventData.Height, eventViewer, bottomEl);
newWidth = newSize.width; newWidth = newSize.width;
newHeight = newSize.height; newHeight = newSize.height;
@ -172,10 +163,10 @@ function changeScale() {
} }
if ( !(streamMode == 'stills') ) { if ( !(streamMode == 'stills') ) {
eventViewer.width(newWidth); eventViewer.width(newWidth);
} //stills handles its own width } // stills handles its own width
eventViewer.height(newHeight); eventViewer.height(newHeight);
if ( !vid ) { // zms needs extra sizing if ( !vid ) { // zms needs extra sizing
streamScale(scale == "auto" ? autoScale : scale); streamScale(scale == '0' ? autoScale : scale);
drawProgressBar(); drawProgressBar();
} }
if ( streamMode == 'stills' ) { if ( streamMode == 'stills' ) {
@ -184,7 +175,7 @@ function changeScale() {
} else { } else {
alarmCue.html(renderAlarmCues(eventViewer));//just re-render alarmCues. skip ajax call alarmCue.html(renderAlarmCues(eventViewer));//just re-render alarmCues. skip ajax call
} }
if ( scale == "auto" ) { if ( scale == '0' ) {
Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365}); Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365});
} else { } else {
Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365}); Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365});
@ -200,6 +191,32 @@ function changeReplayMode() {
refreshWindow(); refreshWindow();
} }
function changeRate() {
var rate = parseInt($j('select[name="rate"]').val());
if ( ! rate ) {
pauseClicked();
} else if ( rate < 0 ) {
if ( vid ) { //There is no reverse play with mp4. Set the speed to 0 and manually set the time back.
revSpeed = rates[rates.indexOf(-1*rate)-1]/100;
clearInterval(intervalRewind);
intervalRewind = setInterval(function() {
if ( vid.currentTime() <= 0 ) {
clearInterval(intervalRewind);
vid.pause();
} else {
vid.playbackRate(0);
vid.currentTime(vid.currentTime() - (revSpeed/2)); //Half of reverse speed because our interval is 500ms.
}
}, 500); //500ms is a compromise between smooth reverse and realistic performance
} // end if vid
} else { // Forward rate
if ( vid ) {
vid.playbackRate(rate/100);
}
}
Cookie.write('zmEventRate', rate, {duration: 10*365});
} // end function changeRate
var streamParms = "view=request&request=stream&connkey="+connKey; var streamParms = "view=request&request=stream&connkey="+connKey;
if ( auth_hash ) { if ( auth_hash ) {
streamParms += '&auth='+auth_hash; streamParms += '&auth='+auth_hash;
@ -245,7 +262,8 @@ function getCmdResponse( respObj, respText ) {
if ( streamStatus.paused == true ) { if ( streamStatus.paused == true ) {
streamPause( ); streamPause( );
} else { } else {
$j('#rateValue').html(streamStatus.rate); console.log('streamStatus.rate: ' + streamStatus.rate);
$j('select[name="rate"]').val(streamStatus.rate*100);
Cookie.write('zmEventRate', streamStatus.rate*100, {duration: 10*365}); Cookie.write('zmEventRate', streamStatus.rate*100, {duration: 10*365});
streamPlay( ); streamPlay( );
} }
@ -280,23 +298,18 @@ var streamReq = new Request.JSON( {
function pauseClicked() { function pauseClicked() {
if ( vid ) { if ( vid ) {
if ( intervalRewind ) {
stopFastRev();
}
vid.pause(); vid.pause();
} else { } else {
streamReq.send(streamParms+"&command="+CMD_PAUSE); streamReq.send(streamParms+"&command="+CMD_PAUSE);
streamPause();
}
}
function vjsPause() {
if ( intervalRewind ) {
stopFastRev();
} }
streamPause(); streamPause();
} }
function streamPause( ) { function streamPause( ) {
$j('#modeValue').html('Paused'); $j('#modeValue').html('Paused');
$j('#rateValue').html('0');
setButtonState( $('pauseBtn'), 'active' ); setButtonState( $('pauseBtn'), 'active' );
setButtonState( $('playBtn'), 'inactive' ); setButtonState( $('playBtn'), 'inactive' );
setButtonState( $('fastFwdBtn'), 'unavail' ); setButtonState( $('fastFwdBtn'), 'unavail' );
@ -306,6 +319,10 @@ function streamPause( ) {
} }
function playClicked( ) { function playClicked( ) {
var rate_select = $j('select[name="rate"]');
if ( ! rate_select.val() ) {
$j('select[name="rate"]').val(100);
}
if ( vid ) { if ( vid ) {
if ( vid.paused() ) { if ( vid.paused() ) {
vid.play(); vid.play();
@ -314,21 +331,20 @@ function playClicked( ) {
} }
} else { } else {
streamReq.send(streamParms+"&command="+CMD_PLAY); streamReq.send(streamParms+"&command="+CMD_PLAY);
streamPlay();
} }
streamPlay();
} }
function vjsPlay() { //catches if we change mode programatically function vjsPlay() { //catches if we change mode programatically
if ( intervalRewind ) { if ( intervalRewind ) {
stopFastRev(); stopFastRev();
} }
$j('#rateValue').html(vid.playbackRate()); $j('select[name="rate"]').val(vid.playbackRate()*100);
Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365}); Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365});
streamPlay(); streamPlay();
} }
function streamPlay( ) { function streamPlay( ) {
$j('#modeValue').html('Replay');
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState( $('pauseBtn'), 'inactive' );
setButtonState( $('playBtn'), 'active' ); setButtonState( $('playBtn'), 'active' );
setButtonState( $('fastFwdBtn'), 'inactive' ); setButtonState( $('fastFwdBtn'), 'inactive' );
@ -350,16 +366,13 @@ function streamFastFwd( action ) {
if ( rates.indexOf(vid.playbackRate()*100)-1 == -1 ) { if ( rates.indexOf(vid.playbackRate()*100)-1 == -1 ) {
setButtonState($('fastFwdBtn'), 'unavail'); setButtonState($('fastFwdBtn'), 'unavail');
} }
$j('#rateValue').html(vid.playbackRate()); $j('select[name="rate"]').val(vid.playbackRate()*100);
Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365}); Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365});
} else { } else {
streamReq.send(streamParms+"&command="+CMD_FASTFWD); streamReq.send(streamParms+"&command="+CMD_FASTFWD);
} }
} }
var spf = Math.round((eventData.Length / eventData.Frames)*1000000 )/1000000;//Seconds per frame for videojs frame by frame.
var intervalRewind;
var revSpeed = .5;
function streamSlowFwd( action ) { function streamSlowFwd( action ) {
if ( vid ) { if ( vid ) {
@ -380,6 +393,7 @@ function streamSlowRev( action ) {
function stopFastRev() { function stopFastRev() {
clearInterval(intervalRewind); clearInterval(intervalRewind);
vid.playbackRate(1); vid.playbackRate(1);
$j('select[name="rate"]').val(vid.playbackRate()*100);
Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365}); Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365});
revSpeed = .5; revSpeed = .5;
} }
@ -397,7 +411,7 @@ function streamFastRev( action ) {
setButtonState( $('fastRevBtn'), 'unavail' ); setButtonState( $('fastRevBtn'), 'unavail' );
} }
clearInterval(intervalRewind); clearInterval(intervalRewind);
$j('#rateValue').html(-revSpeed); $j('select[name="rate"]').val(-revSpeed*100);
Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365}); Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365});
intervalRewind = setInterval(function() { intervalRewind = setInterval(function() {
if (vid.currentTime() <= 0) { if (vid.currentTime() <= 0) {
@ -588,7 +602,7 @@ function getEventResponse(respObj, respText) {
CurEventDefVideoPath = null; CurEventDefVideoPath = null;
$j('#modeValue').html('Replay'); $j('#modeValue').html('Replay');
$j('#zoomValue').html('1'); $j('#zoomValue').html('1');
$j('#rateValue').html('1'); $j('#rate').val('100');
vjsPanZoom('zoomOut'); vjsPanZoom('zoomOut');
} else { } else {
drawProgressBar(); drawProgressBar();
@ -1059,7 +1073,7 @@ function initPage() {
$j('.vjs-progress-control').append('<div class="alarmCue"></div>');//add a place for videojs only on first load $j('.vjs-progress-control').append('<div class="alarmCue"></div>');//add a place for videojs only on first load
vid.on('ended', vjsReplay); vid.on('ended', vjsReplay);
vid.on('play', vjsPlay); vid.on('play', vjsPlay);
vid.on('pause', vjsPause); vid.on('pause', pauseClicked);
vid.on('click', function(event) { vid.on('click', function(event) {
handleClick(event); handleClick(event);
}); });
@ -1067,7 +1081,8 @@ function initPage() {
$j('#progressValue').html(secsToTime(Math.floor(vid.currentTime()))); $j('#progressValue').html(secsToTime(Math.floor(vid.currentTime())));
}); });
if ( rate > 1 ) { // rate is in % so 100 would be 1x
if ( rate > 0 ) {
// rate should be 100 = 1x, etc. // rate should be 100 = 1x, etc.
vid.playbackRate(rate/100); vid.playbackRate(rate/100);
} }
@ -1091,7 +1106,10 @@ function initPage() {
} }
nearEventsQuery(eventData.Id); nearEventsQuery(eventData.Id);
initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues
if ( scale == 'auto' ) changeScale(); if ( scale == '0' || scale == 'auto' ) changeScale();
document.querySelectorAll('select[name="rate"]').forEach(function(el) {
el.onchange = window['changeRate'];
});
} }
// Kick everything off // Kick everything off

View File

@ -66,6 +66,15 @@ function updateButtons(element) {
} }
} }
function click_AutoEmail(element) {
updateButtons(this);
if ( this.checked ) {
$j('#EmailOptions').show();
} else {
$j('#EmailOptions').hide();
}
}
function click_automove(element) { function click_automove(element) {
updateButtons(this); updateButtons(this);
if ( this.checked ) { if ( this.checked ) {
@ -105,10 +114,11 @@ function submitToEvents( element ) {
history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); history.replaceState(null, null, '?view=filter&' + $j(form).serialize());
} }
function submitToMontageReview( element ) { function submitToMontageReview(element) {
var form = element.form; var form = element.form;
form.action = thisUrl + '?view=montagereview'; form.action = thisUrl + '?view=montagereview';
history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); window.location.assign('?view=montagereview&'+$j(form).serialize());
history.replaceState(null, null, '?view=montagereview&live=0&' + $j(form).serialize());
} }
function submitToExport(element) { function submitToExport(element) {
@ -183,7 +193,8 @@ function parseRows(rows) {
} }
var attr = inputTds.eq(2).children().val(); var attr = inputTds.eq(2).children().val();
if ( attr == 'Archived' ) { // Archived types
if ( attr == 'Archived' ) { //Archived types
inputTds.eq(3).html('equal to<input type="hidden" name="filter[Query][terms][' + rowNum + '][op]" value="=">'); inputTds.eq(3).html('equal to<input type="hidden" name="filter[Query][terms][' + rowNum + '][op]" value="=">');
var archiveSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); var archiveSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (var i = 0; i < archiveTypes.length; i++) { for (var i = 0; i < archiveTypes.length; i++) {
@ -191,6 +202,18 @@ function parseRows(rows) {
} }
var archiveVal = inputTds.eq(4).children().val(); var archiveVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(archiveSelect).children().val(archiveVal).chosen({width: "101%"}); inputTds.eq(4).html(archiveSelect).children().val(archiveVal).chosen({width: "101%"});
} else if ( attr == 'AlarmedZoneId' ) {
var zoneSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for ( monitor_id in monitors ) {
for ( zone_id in zones ) {
var zone = zones[zone_id];
if ( monitor_id == zone.MonitorId ) {
zoneSelect.append('<option value="' + zone_id + '">' + zone.Name + '</option>');
}
} // end foreach zone
} // end foreach monitor
var zoneVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(zoneSelect).children().val(zoneVal).chosen({width: "101%"});
} else if ( attr.indexOf('Weekday') >= 0 ) { //Weekday selection } else if ( attr.indexOf('Weekday') >= 0 ) { //Weekday selection
var weekdaySelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); var weekdaySelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (var i = 0; i < weekdays.length; i++) { for (var i = 0; i < weekdays.length; i++) {
@ -221,22 +244,29 @@ function parseRows(rows) {
inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"}); inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"});
} else if ( attr == 'MonitorName' ) { //Monitor names } else if ( attr == 'MonitorName' ) { //Monitor names
var monitorSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); var monitorSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (var key in monitors) { for ( var monitor_id in monitors ) {
monitorSelect.append('<option value="' + key + '">' + monitors[key] + '</option>'); monitorSelect.append('<option value="' + monitors[monitor_id].Name + '">' + monitors[monitor_id].Name + '</option>');
} }
var monitorVal = inputTds.eq(4).children().val(); var monitorVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(monitorSelect).children().val(monitorVal); inputTds.eq(4).html(monitorSelect).children().val(monitorVal);
} else { //Reset to regular text field and operator for everything that isn't special } else { // Reset to regular text field and operator for everything that isn't special
var opSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][op]').attr('id', queryPrefix + rowNum + '][op]');
for (var key in opTypes) {
opSelect.append('<option value="' + key + '">' + opTypes[key] + '</option>');
}
var opVal = inputTds.eq(3).children().val();
inputTds.eq(3).html(opSelect).children().val(opVal).chosen({width: "101%"});
var textInput = $j('<input></input>').attr('type', 'text').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); var textInput = $j('<input></input>').attr('type', 'text').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
var textVal = inputTds.eq(4).children().val(); var textVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(textInput).children().val(textVal); inputTds.eq(4).html(textInput).children().val(textVal);
} }
// Validate the operator
var opSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][op]').attr('id', queryPrefix + rowNum + '][op]');
var opVal = inputTds.eq(3).children().val();
if ( ! opVal ) {
// Default to equals so that something gets selected
console.log("No value for operator. Defaulting to =");
opVal = '=';
}
for ( var key in opTypes ) {
opSelect.append('<option value="' + key + '"'+(key == opVal ? ' selected="selected"' : '')+'>' + opTypes[key] + '</option>');
}
inputTds.eq(3).html(opSelect).children().val(opVal).chosen({width: "101%"});
if ( attr.endsWith('DateTime') ) { //Start/End DateTime if ( attr.endsWith('DateTime') ) { //Start/End DateTime
inputTds.eq(4).children().datetimepicker({timeFormat: "HH:mm:ss", dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false}); inputTds.eq(4).children().datetimepicker({timeFormat: "HH:mm:ss", dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false});
} else if ( attr.endsWith('Date') ) { //Start/End Date } else if ( attr.endsWith('Date') ) { //Start/End Date

View File

@ -10,6 +10,7 @@ var states = <?php echo isset($states) ? json_encode($states) : '' ?>;
var servers = <?php echo isset($servers) ? json_encode($servers) : '' ?>; var servers = <?php echo isset($servers) ? json_encode($servers) : '' ?>;
var storageareas = <?php echo isset($storageareas) ? json_encode($storageareas) : '' ?>; var storageareas = <?php echo isset($storageareas) ? json_encode($storageareas) : '' ?>;
var monitors = <?php echo isset($monitors) ? json_encode($monitors) : '' ?>; var monitors = <?php echo isset($monitors) ? json_encode($monitors) : '' ?>;
var zones = <?php echo isset($zones) ? json_encode($zones) : '' ?>;
var errorBrackets = '<?php echo translate('ErrorBrackets') ?>'; var errorBrackets = '<?php echo translate('ErrorBrackets') ?>';
var errorValue = '<?php echo translate('ErrorValidValue') ?>'; var errorValue = '<?php echo translate('ErrorValidValue') ?>';

View File

@ -334,7 +334,7 @@ function changeScale() {
Cookie.write('zmMontageScale', scale, {duration: 10*365}); Cookie.write('zmMontageScale', scale, {duration: 10*365});
Cookie.write('zmMontageWidth', '', {duration: 10*365}); Cookie.write('zmMontageWidth', '', {duration: 10*365});
Cookie.write('zmMontageHeight', '', {duration: 10*365}); Cookie.write('zmMontageHeight', '', {duration: 10*365});
if ( !scale ) { if ( scale == '' ) {
selectLayout('#zmMontageLayout'); selectLayout('#zmMontageLayout');
return; return;
} }
@ -349,9 +349,13 @@ function changeScale() {
console.log("Error finding frame for " + monitor.id); console.log("Error finding frame for " + monitor.id);
continue; continue;
} }
if ( scale != '0' ) {
if ( newWidth ) { if ( newWidth ) {
monitor_frame.css('width', newWidth); monitor_frame.css('width', newWidth);
} }
} else {
monitor_frame.css('width', '100%');
}
// We don't set the frame height because it has the status bar as well // We don't set the frame height because it has the status bar as well
//if ( height ) { //if ( height ) {
////monitor_frame.css('height', height+'px'); ////monitor_frame.css('height', height+'px');
@ -364,13 +368,24 @@ function changeScale() {
streamImg.src = ''; streamImg.src = '';
//src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) )); //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
if ( scale != '0' ) {
src = src.replace(/scale=[\.\d]+/i, 'scale='+scale); src = src.replace(/scale=[\.\d]+/i, 'scale='+scale);
src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); src = src.replace(/width=[\.\d]+/i, 'width='+newWidth);
src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); src = src.replace(/height=[\.\d]+/i, 'height='+newHeight);
} else {
src = src.replace(/scale=[\.\d]+/i, 'scale=100');
src = src.replace(/width=[\.\d]+/i, 'width='+monitorData[i].width);
src = src.replace(/height=[\.\d]+/i, 'height='+monitorData[i].height);
}
streamImg.src = src; streamImg.src = src;
} }
if ( scale != '0' ) {
streamImg.style.width = newWidth + "px"; streamImg.style.width = newWidth + "px";
streamImg.style.height = newHeight + "px"; streamImg.style.height = newHeight + "px";
} else {
streamImg.style.width = '100%';
streamImg.style.height = 'auto';
}
} }
} }
} }
@ -467,6 +482,7 @@ function initPage() {
// Start the fps and status updates. give a random delay so that we don't assault the server // Start the fps and status updates. give a random delay so that we don't assault the server
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
console.log("delay: " + delay);
monitors[i].start(delay); monitors[i].start(delay);
var interval = monitors[i].refresh; var interval = monitors[i].refresh;

View File

@ -936,6 +936,10 @@ function changeDateTime(e) {
} }
} }
// Reloading can take a while, so stop interrupts to reduce load
clearInterval(timerObj);
timerObj = null;
var uri = "?view=" + currentView + fitStr + minStr + maxStr + liveStr + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value]; var uri = "?view=" + currentView + fitStr + minStr + maxStr + liveStr + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value];
window.location = uri; window.location = uri;
} }
@ -967,6 +971,7 @@ function initPage() {
imagedone(this, this.monId, false); imagedone(this, this.monId, false);
}; };
loadImage2Monitor(monId, monitorImageURL[monId]); loadImage2Monitor(monId, monitorImageURL[monId]);
monitorCanvasObj[monId].addEventListener('click', clickMonitor, false);
} }
} // end foreach monitor } // end foreach monitor
@ -982,15 +987,6 @@ function initPage() {
ctx = canvas.getContext('2d'); ctx = canvas.getContext('2d');
drawGraph(); drawGraph();
} }
for ( i=0, len=monitorPtr.length; i < len; i += 1 ) {
var monitor_id = monitorPtr[i];
monitor_canvas = $('Monitor'+monitor_id);
if ( ! monitor_canvas ) {
console.log("No canvas found for monitor " + monitor_id);
continue;
}
monitor_canvas.addEventListener('click', clickMonitor, false);
}
setSpeed(speedIndex); setSpeed(speedIndex);
//setFit(fitMode); // will redraw //setFit(fitMode); // will redraw
//setLive(liveMode); // will redraw //setLive(liveMode); // will redraw

View File

@ -68,7 +68,7 @@ if ( !$liveMode ) {
$frame['NextFrameId'] = $next_frames[$frame['EventId']]['Id']; $frame['NextFrameId'] = $next_frames[$frame['EventId']]['Id'];
} }
$event['FramesById'] += array($frame['Id']=>$frame); $event['FramesById'] += array($frame['Id']=>$frame);
$next_frames[$frame['EventId']] = $frame; $next_frames[$frame['EventId']] = &$event['FramesById'][$frame['Id']];
} }
} // end if dbQuery } // end if dbQuery

View File

@ -1,11 +1,11 @@
function deleteVideo( e ) { function deleteVideo(e) {
index = e.getAttribute('data-file-index'); index = e.getAttribute('data-file-index');
window.location.replace( thisUrl+'?view='+currentView+'&eid='+eventId+'&deleteIndex='+index ); window.location.replace(thisUrl+'?view='+currentView+'&eid='+eventId+'&deleteIndex='+index);
} }
function downloadVideo( e ) { function downloadVideo(e) {
index = e.getAttribute('data-file-index'); index = e.getAttribute('data-file-index');
window.location.replace( thisUrl+'?view='+currentView+'&eid='+eventId+'&downloadIndex='+index ); window.location.replace(thisUrl+'?view='+currentView+'&eid='+eventId+'&downloadIndex='+index);
} }
var generateVideoTimer = null; var generateVideoTimer = null;
@ -13,25 +13,25 @@ var generateVideoTimer = null;
function generateVideoProgress() { function generateVideoProgress() {
var tickerText = $('videoProgressTicker').get('text'); var tickerText = $('videoProgressTicker').get('text');
if ( tickerText.length < 1 || tickerText.length > 4 ) { if ( tickerText.length < 1 || tickerText.length > 4 ) {
$('videoProgressTicker').set( 'text', '.' ); $('videoProgressTicker').set('text', '.');
} else { } else {
$('videoProgressTicker').appendText( '.' ); $('videoProgressTicker').appendText('.');
} }
} }
function generateVideoResponse( respObj, respText ) { function generateVideoResponse( respObj, respText ) {
window.location.replace( thisUrl+'?view='+currentView+'&eid='+eventId+'&generated='+((respObj.result=='Ok')?1:0) ); window.location.replace(thisUrl+'?view='+currentView+'&eid='+eventId+'&generated='+((respObj.result=='Ok')?1:0));
} }
function generateVideo() { function generateVideo() {
form = $j('#contentForm')[0]; form = $j('#contentForm')[0];
var parms = 'view=request&request=event&action=video'; var parms = 'view=request&request=event&action=video';
parms += '&'+$(form).toQueryString(); parms += '&'+$(form).toQueryString();
var query = new Request.JSON( {url: thisUrl, method: 'post', data: parms, onSuccess: generateVideoResponse} ); var query = new Request.JSON({url: thisUrl, method: 'post', data: parms, onSuccess: generateVideoResponse});
query.send(); query.send();
$('videoProgress').removeClass( 'hidden' ); $('videoProgress').removeClass('hidden');
$('videoProgress').setProperty( 'class', 'warnText' ); $('videoProgress').setProperty('class', 'warnText');
$('videoProgressText').set( 'text', videoGenProgressString ); $('videoProgressText').set('text', videoGenProgressString);
generateVideoProgress(); generateVideoProgress();
generateVideoTimer = generateVideoProgress.periodical( 500 ); generateVideoTimer = generateVideoProgress.periodical(500);
} }

View File

@ -1,39 +1,33 @@
function setButtonState(element, butClass) {
if ( element ) {
element.className = butClass;
element.disabled = (butClass != 'inactive');
}
}
function showEvents() { function showEvents() {
$('ptzControls').addClass( 'hidden' ); $('ptzControls').addClass('hidden');
$('events').removeClass( 'hidden' ); $('events').removeClass('hidden');
if ( $('eventsControl') ) { if ( $('eventsControl') ) {
$('eventsControl').addClass('hidden'); $('eventsControl').addClass('hidden');
} }
if ( $('controlControl') ) { if ( $('controlControl') ) {
$('controlControl').removeClass('hidden'); $('controlControl').removeClass('hidden');
} }
showMode = "events"; showMode = 'events';
} }
function showPtzControls() { function showPtzControls() {
$('events').addClass( 'hidden' ); $('events').addClass('hidden');
$('ptzControls').removeClass( 'hidden' ); $('ptzControls').removeClass('hidden');
if ( $('eventsControl') ) { if ( $('eventsControl') ) {
$('eventsControl').removeClass('hidden'); $('eventsControl').removeClass('hidden');
} }
if ( $('controlControl') ) { if ( $('controlControl') ) {
$('controlControl').addClass('hidden'); $('controlControl').addClass('hidden');
} }
showMode = "control"; showMode = 'control';
} }
function changeScale() { function changeScale() {
var scale = $('scale').get('value'); var scale = $('scale').get('value');
var newWidth; var newWidth;
var newHeight; var newHeight;
if (scale == "auto") { if ( scale == '0' || scale == 'auto' ) {
var newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus')); var newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus'));
newWidth = newSize.width; newWidth = newSize.width;
newHeight = newSize.height; newHeight = newSize.height;
@ -87,7 +81,7 @@ function setAlarmState( currentAlarmState ) {
if ( SOUND_ON_ALARM ) { if ( SOUND_ON_ALARM ) {
// Enable the alarm sound // Enable the alarm sound
if ( !canPlayPauseAudio ) { if ( !canPlayPauseAudio ) {
$('alarmSound').removeClass( 'hidden' ); $('alarmSound').removeClass('hidden');
} else { } else {
$('MediaPlayer').Play(); $('MediaPlayer').Play();
} }
@ -96,22 +90,20 @@ function setAlarmState( currentAlarmState ) {
window.focus(); window.focus();
} }
} }
if ( oldAlarm ) { // done with an event do a refresh
if ( SOUND_ON_ALARM ) { if ( SOUND_ON_ALARM ) {
if ( oldAlarm ) {
// Disable alarm sound // Disable alarm sound
if ( !canPlayPauseAudio ) { if ( !canPlayPauseAudio ) {
$('alarmSound').addClass( 'hidden' ); $('alarmSound').addClass('hidden');
} else { } else {
$('MediaPlayer').Stop(); $('MediaPlayer').Stop();
} }
} }
}
if (oldAlarm) { // done with an event do a refresh
eventCmdQuery(); eventCmdQuery();
} }
lastAlarmState = alarmState; lastAlarmState = alarmState;
} } // end function setAlarmState( currentAlarmState )
if ( monitorType != 'WebSite' ) { if ( monitorType != 'WebSite' ) {
var streamCmdParms = 'view=request&request=stream&connkey='+connKey; var streamCmdParms = 'view=request&request=stream&connkey='+connKey;
@ -155,11 +147,11 @@ function getStreamCmdResponse(respObj, respText) {
$('levelValue').set('text', streamStatus.level); $('levelValue').set('text', streamStatus.level);
if ( streamStatus.level > 95 ) { if ( streamStatus.level > 95 ) {
$('levelValue').className = "alarm"; $('levelValue').className = 'alarm';
} else if ( streamStatus.level > 80 ) { } else if ( streamStatus.level > 80 ) {
$('levelValue').className = "alert"; $('levelValue').className = 'alert';
} else { } else {
$('levelValue').className = "ok"; $('levelValue').className = 'ok';
} }
var delayString = secsToTime(streamStatus.delay); var delayString = secsToTime(streamStatus.delay);
@ -194,7 +186,7 @@ function getStreamCmdResponse(respObj, respText) {
} }
} // rate } // rate
} else { } else {
$('modeValue').set( 'text', "Live" ); $('modeValue').set( 'text', 'Live' );
$('rate').addClass( 'hidden' ); $('rate').addClass( 'hidden' );
$('delay').addClass( 'hidden' ); $('delay').addClass( 'hidden' );
$('level').addClass( 'hidden' ); $('level').addClass( 'hidden' );
@ -203,9 +195,9 @@ function getStreamCmdResponse(respObj, respText) {
$('zoomValue').set('text', streamStatus.zoom); $('zoomValue').set('text', streamStatus.zoom);
if ( streamStatus.zoom == '1.0' ) { if ( streamStatus.zoom == '1.0' ) {
setButtonState($('zoomOutBtn'), 'unavail'); setButtonState('zoomOutBtn', 'unavail');
} else { } else {
setButtonState($('zoomOutBtn'), 'inactive'); setButtonState('zoomOutBtn', 'inactive');
} }
if ( canEditMonitors ) { if ( canEditMonitors ) {
@ -230,7 +222,6 @@ function getStreamCmdResponse(respObj, respText) {
if ( streamStatus.auth ) { if ( streamStatus.auth ) {
auth_hash = streamStatus.auth; auth_hash = streamStatus.auth;
console.log("Have a new auth hash" + streamStatus.auth);
// Try to reload the image stream. // Try to reload the image stream.
var streamImg = $('liveStream'); var streamImg = $('liveStream');
if ( streamImg ) { if ( streamImg ) {
@ -243,7 +234,7 @@ function getStreamCmdResponse(respObj, respText) {
} // end if have a new auth hash } // end if have a new auth hash
} // end if respObj.status } // end if respObj.status
} else { } else {
checkStreamForErrors("getStreamCmdResponse", respObj);//log them checkStreamForErrors('getStreamCmdResponse', respObj);//log them
// Try to reload the image stream. // Try to reload the image stream.
// If it's an auth error, we should reload the whole page. // If it's an auth error, we should reload the whole page.
window.location.reload(); window.location.reload();
@ -251,9 +242,9 @@ function getStreamCmdResponse(respObj, respText) {
var streamImg = $('liveStream'+monitorId); var streamImg = $('liveStream'+monitorId);
if ( streamImg ) { if ( streamImg ) {
streamImg.src = streamImg.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); streamImg.src = streamImg.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
console.log("Changing livestream src to " + streamImg.src); console.log('Changing livestream src to ' + streamImg.src);
} else { } else {
console.log("Unable to find streamImg liveStream"); console.log('Unable to find streamImg liveStream');
} }
} }
} }
@ -262,132 +253,152 @@ function getStreamCmdResponse(respObj, respText) {
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) {
streamCmdTimeout = streamCmdTimeout/5; streamCmdTimeout = streamCmdTimeout/5;
} }
streamCmdTimer = streamCmdQuery.delay( streamCmdTimeout ); streamCmdTimer = streamCmdQuery.delay(streamCmdTimeout);
} }
function streamCmdPause( action ) { function streamCmdPause( action ) {
setButtonState( $('pauseBtn'), 'active' ); setButtonState('pauseBtn', 'active');
setButtonState( $('playBtn'), 'inactive' ); setButtonState('playBtn', 'inactive');
setButtonState( $('stopBtn'), 'inactive' ); setButtonState('stopBtn', 'inactive');
setButtonState( $('fastFwdBtn'), 'inactive' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'inactive' ); setButtonState('fastFwdBtn', 'inactive');
setButtonState( $('slowRevBtn'), 'inactive' ); setButtonState('slowFwdBtn', 'inactive');
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) { if ( action ) {
streamCmdReq.send( streamCmdParms+"&command="+CMD_PAUSE ); streamCmdReq.send(streamCmdParms+"&command="+CMD_PAUSE);
} }
} }
function streamCmdPlay( action ) { function streamCmdPlay( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState('pauseBtn', 'inactive');
setButtonState( $('playBtn'), 'active' ); setButtonState('playBtn', 'active');
if ( streamStatus.delayed == true ) { if ( streamStatus.delayed == true ) {
setButtonState( $('stopBtn'), 'inactive' ); setButtonState('stopBtn', 'inactive');
setButtonState( $('fastFwdBtn'), 'inactive' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'inactive' ); setButtonState('fastFwdBtn', 'inactive');
setButtonState( $('slowRevBtn'), 'inactive' ); setButtonState('slowFwdBtn', 'inactive');
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
} else { } else {
setButtonState( $('stopBtn'), 'unavail' ); setButtonState('stopBtn', 'unavail');
setButtonState( $('fastFwdBtn'), 'unavail' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'unavail' ); setButtonState('fastFwdBtn', 'unavail');
setButtonState( $('slowRevBtn'), 'unavail' ); setButtonState('slowFwdBtn', 'unavail');
setButtonState( $('fastRevBtn'), 'unavail' ); setButtonState('slowRevBtn', 'unavail');
setButtonState('fastRevBtn', 'unavail');
}
} }
if ( action ) { if ( action ) {
streamCmdReq.send( streamCmdParms+"&command="+CMD_PLAY ); streamCmdReq.send(streamCmdParms+"&command="+CMD_PLAY);
} }
} }
function streamCmdStop( action ) { function streamCmdStop( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState('pauseBtn', 'inactive');
setButtonState( $('playBtn'), 'unavail' ); setButtonState('playBtn', 'unavail');
setButtonState( $('stopBtn'), 'active' ); setButtonState('stopBtn', 'active');
setButtonState( $('fastFwdBtn'), 'unavail' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'unavail' ); setButtonState('fastFwdBtn', 'unavail');
setButtonState( $('slowRevBtn'), 'unavail' ); setButtonState('slowFwdBtn', 'unavail');
setButtonState( $('fastRevBtn'), 'unavail' ); setButtonState('slowRevBtn', 'unavail');
if ( action ) { setButtonState('fastRevBtn', 'unavail');
streamCmdReq.send( streamCmdParms+"&command="+CMD_STOP );
} }
setButtonState( $('stopBtn'), 'unavail' ); if ( action ) {
setButtonState( $('playBtn'), 'active' ); streamCmdReq.send(streamCmdParms+"&command="+CMD_STOP);
}
setButtonState('stopBtn', 'unavail');
setButtonState('playBtn', 'active');
} }
function streamCmdFastFwd( action ) { function streamCmdFastFwd( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState('pauseBtn', 'inactive');
setButtonState( $('playBtn'), 'inactive' ); setButtonState('playBtn', 'inactive');
setButtonState( $('stopBtn'), 'inactive' ); setButtonState('stopBtn', 'inactive');
setButtonState( $('fastFwdBtn'), 'inactive' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'inactive' ); setButtonState('fastFwdBtn', 'inactive');
setButtonState( $('slowRevBtn'), 'inactive' ); setButtonState('slowFwdBtn', 'inactive');
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) { if ( action ) {
streamCmdReq.send( streamCmdParms+"&command="+CMD_FASTFWD ); streamCmdReq.send(streamCmdParms+"&command="+CMD_FASTFWD);
} }
} }
function streamCmdSlowFwd( action ) { function streamCmdSlowFwd( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState('pauseBtn', 'inactive');
setButtonState( $('playBtn'), 'inactive' ); setButtonState('playBtn', 'inactive');
setButtonState( $('stopBtn'), 'inactive' ); setButtonState('stopBtn', 'inactive');
setButtonState( $('fastFwdBtn'), 'inactive' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'active' ); setButtonState('fastFwdBtn', 'inactive');
setButtonState( $('slowRevBtn'), 'inactive' ); setButtonState('slowFwdBtn', 'active');
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState('slowRevBtn', 'inactive');
if ( action ) { setButtonState('fastRevBtn', 'inactive');
streamCmdReq.send( streamCmdParms+"&command="+CMD_SLOWFWD ); }
if ( action ) {
streamCmdReq.send(streamCmdParms+"&command="+CMD_SLOWFWD);
}
setButtonState('pauseBtn', 'active');
if ( monitorStreamReplayBuffer ) {
setButtonState('slowFwdBtn', 'inactive');
} }
setButtonState( $('pauseBtn'), 'active' );
setButtonState( $('slowFwdBtn'), 'inactive' );
} }
function streamCmdSlowRev( action ) { function streamCmdSlowRev( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState('pauseBtn', 'inactive');
setButtonState( $('playBtn'), 'inactive' ); setButtonState('playBtn', 'inactive');
setButtonState( $('stopBtn'), 'inactive' ); setButtonState('stopBtn', 'inactive');
setButtonState( $('fastFwdBtn'), 'inactive' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'inactive' ); setButtonState('fastFwdBtn', 'inactive');
setButtonState( $('slowRevBtn'), 'active' ); setButtonState('slowFwdBtn', 'inactive');
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState('slowRevBtn', 'active');
if ( action ) { setButtonState('fastRevBtn', 'inactive');
streamCmdReq.send( streamCmdParms+"&command="+CMD_SLOWREV ); }
if ( action ) {
streamCmdReq.send(streamCmdParms+"&command="+CMD_SLOWREV);
}
setButtonState('pauseBtn', 'active');
if ( monitorStreamReplayBuffer ) {
setButtonState('slowRevBtn', 'inactive');
} }
setButtonState( $('pauseBtn'), 'active' );
setButtonState( $('slowRevBtn'), 'inactive' );
} }
function streamCmdFastRev( action ) { function streamCmdFastRev( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState('pauseBtn', 'inactive');
setButtonState( $('playBtn'), 'inactive' ); setButtonState('playBtn', 'inactive');
setButtonState( $('stopBtn'), 'inactive' ); setButtonState('stopBtn', 'inactive');
setButtonState( $('fastFwdBtn'), 'inactive' ); if ( monitorStreamReplayBuffer ) {
setButtonState( $('slowFwdBtn'), 'inactive' ); setButtonState('fastFwdBtn', 'inactive');
setButtonState( $('slowRevBtn'), 'inactive' ); setButtonState('slowFwdBtn', 'inactive');
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) { if ( action ) {
streamCmdReq.send( streamCmdParms+"&command="+CMD_FASTREV ); streamCmdReq.send(streamCmdParms+"&command="+CMD_FASTREV);
} }
} }
function streamCmdZoomIn( x, y ) { function streamCmdZoomIn( x, y ) {
streamCmdReq.send( streamCmdParms+"&command="+CMD_ZOOMIN+"&x="+x+"&y="+y ); streamCmdReq.send(streamCmdParms+"&command="+CMD_ZOOMIN+"&x="+x+"&y="+y);
} }
function streamCmdZoomOut() { function streamCmdZoomOut() {
streamCmdReq.send( streamCmdParms+"&command="+CMD_ZOOMOUT ); streamCmdReq.send(streamCmdParms+"&command="+CMD_ZOOMOUT);
} }
function streamCmdScale( scale ) { function streamCmdScale( scale ) {
streamCmdReq.send( streamCmdParms+"&command="+CMD_SCALE+"&scale="+scale ); streamCmdReq.send(streamCmdParms+"&command="+CMD_SCALE+"&scale="+scale);
} }
function streamCmdPan( x, y ) { function streamCmdPan( x, y ) {
streamCmdReq.send( streamCmdParms+"&command="+CMD_PAN+"&x="+x+"&y="+y ); streamCmdReq.send(streamCmdParms+"&command="+CMD_PAN+"&x="+x+"&y="+y);
} }
function streamCmdQuery() { function streamCmdQuery() {
streamCmdReq.send( streamCmdParms+"&command="+CMD_QUERY ); streamCmdReq.send(streamCmdParms+"&command="+CMD_QUERY);
} }
if ( monitorType != 'WebSite' ) { if ( monitorType != 'WebSite' ) {
@ -395,12 +406,18 @@ if ( monitorType != 'WebSite' ) {
if ( auth_hash ) { if ( auth_hash ) {
statusCmdParms += '&auth='+auth_hash; statusCmdParms += '&auth='+auth_hash;
} }
var statusCmdReq = new Request.JSON( {url: monitorUrl, method: 'get', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse} ); var statusCmdReq = new Request.JSON( {
url: monitorUrl,
method: 'get',
timeout: AJAX_TIMEOUT,
link: 'cancel',
onSuccess: getStatusCmdResponse
} );
var statusCmdTimer = null; var statusCmdTimer = null;
} }
function getStatusCmdResponse(respObj, respText) { function getStatusCmdResponse(respObj, respText) {
watchdogOk("status"); watchdogOk('status');
if ( statusCmdTimer ) { if ( statusCmdTimer ) {
statusCmdTimer = clearTimeout(statusCmdTimer); statusCmdTimer = clearTimeout(statusCmdTimer);
} }
@ -409,22 +426,22 @@ function getStatusCmdResponse(respObj, respText) {
$('fpsValue').set('text', respObj.monitor.FrameRate); $('fpsValue').set('text', respObj.monitor.FrameRate);
setAlarmState(respObj.monitor.Status); setAlarmState(respObj.monitor.Status);
} else { } else {
checkStreamForErrors("getStatusCmdResponse", respObj); checkStreamForErrors('getStatusCmdResponse', respObj);
} }
var statusCmdTimeout = statusRefreshTimeout; var statusCmdTimeout = statusRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) {
statusCmdTimeout = statusCmdTimeout/5; statusCmdTimeout = statusCmdTimeout/5;
} }
statusCmdTimer = statusCmdQuery.delay( statusCmdTimeout ); statusCmdTimer = statusCmdQuery.delay(statusCmdTimeout);
} }
function statusCmdQuery() { function statusCmdQuery() {
statusCmdReq.send(); statusCmdReq.send(statusCmdParms);
} }
if ( monitorType != 'WebSite' ) { if ( monitorType != 'WebSite' ) {
var alarmCmdParms = "view=request&request=alarm&id="+monitorId; var alarmCmdParms = 'view=request&request=alarm&id='+monitorId;
if ( auth_hash ) { if ( auth_hash ) {
alarmCmdParms += '&auth='+auth_hash; alarmCmdParms += '&auth='+auth_hash;
} }
@ -439,8 +456,8 @@ if ( monitorType != 'WebSite' ) {
var alarmCmdFirst = true; var alarmCmdFirst = true;
} }
function getAlarmCmdResponse( respObj, respText ) { function getAlarmCmdResponse(respObj, respText) {
checkStreamForErrors("getAlarmCmdResponse", respObj); checkStreamForErrors('getAlarmCmdResponse', respObj);
} }
function cmdDisableAlarms() { function cmdDisableAlarms() {
@ -453,14 +470,14 @@ function cmdEnableAlarms() {
function cmdForceAlarm() { function cmdForceAlarm() {
alarmCmdReq.send(alarmCmdParms+"&command=forceAlarm"); alarmCmdReq.send(alarmCmdParms+"&command=forceAlarm");
if (window.event) { if ( window.event ) {
window.event.preventDefault(); window.event.preventDefault();
} }
} }
function cmdCancelForcedAlarm() { function cmdCancelForcedAlarm() {
alarmCmdReq.send(alarmCmdParms+"&command=cancelForcedAlarm"); alarmCmdReq.send(alarmCmdParms+"&command=cancelForcedAlarm");
if (window.event) { if ( window.event ) {
window.event.preventDefault(); window.event.preventDefault();
} }
return false; return false;
@ -476,8 +493,8 @@ function getActResponse( respObj, respText ) {
eventCmdQuery(); eventCmdQuery();
} }
function deleteEvent( event, eventId ) { function deleteEvent(event, eventId) {
var actParms = "view=request&request=event&action=delete&id="+eventId; var actParms = 'view=request&request=event&action=delete&id='+eventId;
if ( auth_hash ) { if ( auth_hash ) {
actParms += '&auth='+auth_hash; actParms += '&auth='+auth_hash;
} }
@ -485,10 +502,9 @@ function deleteEvent( event, eventId ) {
url: thisUrl, url: thisUrl,
method: 'post', method: 'post',
timeout: 3000, timeout: 3000,
data: actParms,
onSuccess: getActResponse onSuccess: getActResponse
} ); } );
actReq.send(); actReq.send(actParms);
event.stop(); event.stop();
} }
@ -501,7 +517,6 @@ if ( monitorType != 'WebSite' ) {
url: monitorUrl, url: monitorUrl,
method: 'get', method: 'get',
timeout: AJAX_TIMEOUT, timeout: AJAX_TIMEOUT,
data: eventCmdParms,
link: 'cancel', link: 'cancel',
onSuccess: getEventCmdResponse, onSuccess: getEventCmdResponse,
onTimeout: eventCmdQuery onTimeout: eventCmdQuery
@ -515,19 +530,19 @@ function highlightRow( row ) {
} }
function getEventCmdResponse( respObj, respText ) { function getEventCmdResponse( respObj, respText ) {
watchdogOk("event"); watchdogOk('event');
if ( eventCmdTimer ) { if ( eventCmdTimer ) {
eventCmdTimer = clearTimeout( eventCmdTimer ); eventCmdTimer = clearTimeout(eventCmdTimer);
} }
if ( respObj.result == 'Ok' ) { if ( respObj.result == 'Ok' ) {
var dbEvents = respObj.events.reverse(); var dbEvents = respObj.events.reverse();
var eventList = $('eventList'); var eventList = $('eventList');
var eventListBody = $(eventList).getElement( 'tbody' ); var eventListBody = $(eventList).getElement('tbody');
var eventListRows = $(eventListBody).getElements( 'tr' ); var eventListRows = $(eventListBody).getElements('tr');
eventListRows.each( function( row ) { eventListRows.each( function(row) {
row.removeClass( 'updated' ); row.removeClass('updated');
} ); } );
for ( var i = 0; i < dbEvents.length; i++ ) { for ( var i = 0; i < dbEvents.length; i++ ) {
@ -581,30 +596,30 @@ function getEventCmdResponse( respObj, respText ) {
'mouseout': highlightRow.pass(row) 'mouseout': highlightRow.pass(row)
} }
}); });
link.set( 'text', 'X' ); link.set('text', 'X');
link.inject( row.getElement( 'td.colDelete' ) ); link.inject(row.getElement('td.colDelete'));
if ( i == 0 ) { if ( i == 0 ) {
row.inject( $(eventListBody) ); row.inject($(eventListBody));
} else { } else {
row.inject( $(eventListBody), 'top' ); row.inject($(eventListBody), 'top');
if ( !eventCmdFirst ) { if ( !eventCmdFirst ) {
row.addClass( 'recent' ); row.addClass('recent');
} }
} }
} else { } else {
row.getElement( 'td.colName a' ).set( 'text', event.Name ); row.getElement('td.colName a').set('text', event.Name);
row.getElement( 'td.colSecs' ).set( 'text', event.Length ); row.getElement('td.colSecs').set('text', event.Length);
row.getElement( 'td.colFrames a' ).set( 'text', event.Frames+'/'+event.AlarmFrames ); row.getElement('td.colFrames a').set('text', event.Frames+'/'+event.AlarmFrames);
row.getElement( 'td.colScore a' ).set( 'text', event.AvgScore+'/'+event.MaxScore ); row.getElement('td.colScore a').set('text', event.AvgScore+'/'+event.MaxScore);
row.removeClass( 'recent' ); row.removeClass('recent');
} }
row.addClass( 'updated' ); row.addClass('updated');
} }
var rows = $(eventListBody).getElements( 'tr' ); var rows = $(eventListBody).getElements('tr');
for ( var i = 0; i < rows.length; i++ ) { for ( var i = 0; i < rows.length; i++ ) {
if ( !rows[i].hasClass( 'updated' ) ) { if ( !rows[i].hasClass('updated') ) {
rows[i].destroy(); rows[i].destroy();
rows.splice( i, 1 ); rows.splice( i, 1 );
i--; i--;
@ -615,39 +630,45 @@ function getEventCmdResponse( respObj, respText ) {
rows.length--; rows.length--;
} }
} else { } else {
checkStreamForErrors("getEventCmdResponse", respObj); checkStreamForErrors('getEventCmdResponse', respObj);
} }
var eventCmdTimeout = eventsRefreshTimeout; var eventCmdTimeout = eventsRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) {
eventCmdTimeout = eventCmdTimeout/5; eventCmdTimeout = eventCmdTimeout/5;
} }
eventCmdTimer = eventCmdQuery.delay( eventCmdTimeout ); eventCmdTimer = eventCmdQuery.delay(eventCmdTimeout);
eventCmdFirst = false; eventCmdFirst = false;
} }
function eventCmdQuery() { function eventCmdQuery() {
if ( eventCmdTimer ) { // avoid firing another if we are firing one if ( eventCmdTimer ) { // avoid firing another if we are firing one
eventCmdTimer = clearTimeout( eventCmdTimer ); eventCmdTimer = clearTimeout(eventCmdTimer);
} }
eventCmdReq.send(); eventCmdReq.send(eventCmdParms);
} }
if ( monitorType != 'WebSite' ) { if ( monitorType != 'WebSite' ) {
var controlParms = "view=request&request=control&id="+monitorId; var controlParms = 'view=request&request=control&id='+monitorId;
if ( auth_hash ) { if ( auth_hash ) {
controlParms += '&auth='+auth_hash; controlParms += '&auth='+auth_hash;
} }
var controlReq = new Request.JSON( {url: monitorUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getControlResponse} ); var controlReq = new Request.JSON( {
url: monitorUrl,
method: 'post',
timeout: AJAX_TIMEOUT,
link: 'cancel',
onSuccess: getControlResponse
} );
} }
function getControlResponse( respObj, respText ) { function getControlResponse(respObj, respText) {
if ( !respObj ) { if ( !respObj ) {
return; return;
} }
//console.log( respText ); //console.log( respText );
if ( respObj.result != 'Ok' ) { if ( respObj.result != 'Ok' ) {
alert( "Control response was status = "+respObj.status+"\nmessage = "+respObj.message ); alert("Control response was status = "+respObj.status+"\nmessage = "+respObj.message);
} }
} }
@ -680,19 +701,19 @@ function controlCmd( control, event, xtell, ytell ) {
locParms += "&yge="+yge; locParms += "&yge="+yge;
} }
} }
controlReq.send( controlParms+"&control="+control+locParms ); controlReq.send(controlParms+"&control="+control+locParms);
if ( streamMode == "single" ) { if ( streamMode == 'single' ) {
fetchImage.pass( $('imageFeed').getElement('img') ).delay( 1000 ); fetchImage.pass($('imageFeed').getElement('img')).delay(1000);
} }
} }
function controlCmdImage( x, y ) { function controlCmdImage( x, y ) {
var imageControlParms = controlParms; var imageControlParms = controlParms;
imageControlParms += "&scale="+scale; imageControlParms += '&scale='+scale;
imageControlParms += "&control="+imageControlMode; imageControlParms += '&control='+imageControlMode;
controlReq.send( imageControlParms+"&x="+x+"&y="+y ); controlReq.send( imageControlParms+"&x="+x+"&y="+y );
if ( streamMode == "single" ) { if ( streamMode == 'single' ) {
fetchImage.pass( $('imageFeed').getElement('img') ).delay( 1000 ); fetchImage.pass( $('imageFeed').getElement('img') ).delay( 1000 );
} }
} }
@ -706,7 +727,7 @@ function handleClick( event ) {
var x = event.page.x - $(target).getLeft(); var x = event.page.x - $(target).getLeft();
var y = event.page.y - $(target).getTop(); var y = event.page.y - $(target).getTop();
if ( showMode == "events" || !imageControlMode ) { if ( showMode == 'events' || !imageControlMode ) {
if ( event.shift ) { if ( event.shift ) {
streamCmdPan( x, y ); streamCmdPan( x, y );
} else if ( event.event.ctrlKey ) { } else if ( event.event.ctrlKey ) {
@ -803,7 +824,7 @@ function initPage() {
if ( refreshApplet && appletRefreshTime ) { if ( refreshApplet && appletRefreshTime ) {
appletRefresh.delay(appletRefreshTime*1000); appletRefresh.delay(appletRefreshTime*1000);
} }
if ( scale == "auto" ) changeScale(); if ( scale == 'auto' ) changeScale();
if ( window.history.length == 1 ) { if ( window.history.length == 1 ) {
$j('#closeControl').html(''); $j('#closeControl').html('');
} }

View File

@ -44,13 +44,13 @@ var showMode = "<?php echo ($showPtzControls && !empty($control))?"control":"eve
var connKey = '<?php echo $connkey ?>'; var connKey = '<?php echo $connkey ?>';
var maxDisplayEvents = <?php echo 2 * MAX_EVENTS ?>; var maxDisplayEvents = <?php echo 2 * MAX_EVENTS ?>;
var monitorId = <?php echo $monitor->Id() ?>; var monitorId = <?php echo $monitor->Id() ?>;
var monitorWidth = <?php echo $monitor->ViewWidth() ?>; var monitorWidth = <?php echo $monitor->ViewWidth() ?>;
var monitorHeight = <?php echo $monitor->ViewHeight() ?>; var monitorHeight = <?php echo $monitor->ViewHeight() ?>;
var monitorUrl = '<?php echo $monitor->UrlToIndex(); ?>'; var monitorUrl = '<?php echo $monitor->UrlToIndex() ?>';
var monitorType = '<?php echo ( $monitor->Type() ) ?>'; var monitorType = '<?php echo $monitor->Type() ?>';
var monitorRefresh = '<?php echo ( $monitor->Refresh() ) ?>'; var monitorRefresh = '<?php echo $monitor->Refresh() ?>';
var monitorStreamReplayBuffer = <?php echo $monitor->StreamReplayBuffer() ?>;
var scale = '<?php echo $scale ?>'; var scale = '<?php echo $scale ?>';

View File

@ -123,7 +123,8 @@ $sourceTypes = array(
'Libvlc' => translate('Libvlc'), 'Libvlc' => translate('Libvlc'),
'cURL' => 'cURL (HTTP(S) only)', 'cURL' => 'cURL (HTTP(S) only)',
'WebSite'=> 'Web Site', 'WebSite'=> 'Web Site',
'NVSocket' => translate('NVSocket') 'NVSocket' => translate('NVSocket'),
'VNC' => translate('VNC'),
); );
if ( !ZM_HAS_V4L ) if ( !ZM_HAS_V4L )
unset($sourceTypes['Local']); unset($sourceTypes['Local']);
@ -367,8 +368,8 @@ $fastblendopts_alarm = array(
); );
$label_size = array( $label_size = array(
'Default' => 1, 1 => translate('Default'),
'Large' => 2 2 => translate('Large'),
); );
$codecs = array( $codecs = array(
@ -639,7 +640,7 @@ switch ( $tab ) {
</tr> </tr>
<tr> <tr>
<td><?php echo translate('Enabled') ?></td> <td><?php echo translate('Enabled') ?></td>
<td><input type="checkbox" name="newMonitor[Enabled]" value="1"<?php if ( $monitor->Enabled() ) { ?> checked="checked"<?php } ?>/></td> <td><input type="checkbox" name="newMonitor[Enabled]" value="1"<?php echo $monitor->Enabled() ? ' checked="checked"' : '' ?>/></td>
</tr> </tr>
<?php <?php
if ( $monitor->Type() != 'WebSite' ) { if ( $monitor->Type() != 'WebSite' ) {
@ -779,23 +780,45 @@ switch ( $tab ) {
} else if ( $monitor->Type() == 'NVSocket' ) { } else if ( $monitor->Type() == 'NVSocket' ) {
include('_monitor_source_nvsocket.php'); include('_monitor_source_nvsocket.php');
} else if ( $monitor->Type() == 'VNC' ) {
?>
<tr>
<td><?php echo translate('RemoteHostName') ?></td>
<td><input type="text" name="newMonitor[Host]" value="<?php echo validHtmlStr($monitor->Host()) ?>"/></td>
</tr>
<tr>
<td><?php echo translate('RemoteHostPort') ?></td>
<td><input type="number" name="newMonitor[Port]" value="<?php echo validHtmlStr($monitor->Port()) ?>" size="6"/></td>
</tr>
<tr>
<td><?php echo translate('Username') ?></td>
<td><input type="text" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>"/></td>
</tr>
<tr>
<td><?php echo translate('Password') ?></td>
<td><input type="text" name="newMonitor[Pass]" value="<?php echo validHtmlStr($monitor->Pass()) ?>"/></td>
</tr>
<?php
} else if ( $monitor->Type() == 'Remote' ) { } else if ( $monitor->Type() == 'Remote' ) {
?> ?>
<tr><td><?php echo translate('RemoteProtocol') ?></td><td><?php echo htmlSelect( "newMonitor[Protocol]", $remoteProtocols, $monitor->Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?></td></tr> <tr><td><?php echo translate('RemoteProtocol') ?></td><td><?php echo htmlSelect( "newMonitor[Protocol]", $remoteProtocols, $monitor->Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?></td></tr>
<?php
?>
<tr>
<td><?php echo translate('RemoteMethod') ?></td>
<td>
<?php <?php
if ( !$monitor->Protocol() || $monitor->Protocol() == 'http' ) { if ( !$monitor->Protocol() || $monitor->Protocol() == 'http' ) {
?> echo htmlSelect('newMonitor[Method]', $httpMethods, $monitor->Method() );
<tr><td><?php echo translate('RemoteMethod') ?></td><td><?php echo htmlSelect( "newMonitor[Method]", $httpMethods, $monitor->Method() ); ?></td></tr>
<?php
} else { } else {
?> echo htmlSelect('newMonitor[Method]', $rtspMethods, $monitor->Method() );
<tr><td><?php echo translate('RemoteMethod') ?></td><td><?php echo htmlSelect( "newMonitor[Method]", $rtspMethods, $monitor->Method() ); ?></td></tr>
<?php
} }
?> ?>
<tr><td><?php echo translate('RemoteHostName') ?></td><td><input type="text" name="newMonitor[Host]" value="<?php echo validHtmlStr($monitor->Host()) ?>" size="36"/></td></tr> </td>
</tr>
<tr><td><?php echo translate('RemoteHostName') ?></td><td><input type="text" name="newMonitor[Host]" value="<?php echo validHtmlStr($monitor->Host()) ?>"/></td></tr>
<tr><td><?php echo translate('RemoteHostPort') ?></td><td><input type="number" name="newMonitor[Port]" value="<?php echo validHtmlStr($monitor->Port()) ?>" size="6"/></td></tr> <tr><td><?php echo translate('RemoteHostPort') ?></td><td><input type="number" name="newMonitor[Port]" value="<?php echo validHtmlStr($monitor->Port()) ?>" size="6"/></td></tr>
<tr><td><?php echo translate('RemoteHostPath') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>" size="36"/></td></tr> <tr><td><?php echo translate('RemoteHostPath') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>"/></td></tr>
<?php <?php
} else if ( $monitor->Type() == 'File' ) { } else if ( $monitor->Type() == 'File' ) {
?> ?>
@ -803,23 +826,44 @@ include('_monitor_source_nvsocket.php');
<?php <?php
} elseif ( $monitor->Type() == 'cURL' ) { } elseif ( $monitor->Type() == 'cURL' ) {
?> ?>
<tr><td><?php echo 'URL' ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>" size="36"/></td></tr> <tr><td><?php echo 'URL' ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>"/></td></tr>
<tr><td><?php echo 'Username' ?></td><td><input type="text" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>" size="12"/></td></tr> <tr><td><?php echo 'Username' ?></td><td><input type="text" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>"/></td></tr>
<tr><td><?php echo 'Password' ?></td><td><input type="text" name="newMonitor[Pass]" value="<?php echo validHtmlStr($monitor->Pass()) ?>" size="12"/></td></tr> <tr><td><?php echo 'Password' ?></td><td><input type="text" name="newMonitor[Pass]" value="<?php echo validHtmlStr($monitor->Pass()) ?>"/></td></tr>
<?php <?php
} elseif ( $monitor->Type() == 'WebSite' ) { } elseif ( $monitor->Type() == 'WebSite' ) {
?> ?>
<tr><td><?php echo translate('WebSiteUrl') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>" size="36"/></td></tr> <tr>
<tr><td><?php echo translate('Width') ?> (<?php echo translate('Pixels') ?>)</td><td><input type="text" name="newMonitor[Width]" value="<?php echo validHtmlStr($monitor->Width()) ?>" size="4";"/></td></tr> <td><?php echo translate('WebSiteUrl') ?></td>
<tr><td><?php echo translate('Height') ?> (<?php echo translate('Pixels') ?>)</td><td><input type="text" name="newMonitor[Height]" value="<?php echo validHtmlStr($monitor->Height()) ?>" size="4";"/></td></tr> <td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>"/></td>
<tr><td><?php echo 'Web Site Refresh (Optional)' ?></td><td><input type="number" name="newMonitor[Refresh]" value="<?php echo validHtmlStr($monitor->Refresh()); ?>"/></td></tr> </tr>
<tr>
<td><?php echo translate('Width') ?> (<?php echo translate('Pixels') ?>)</td>
<td><input type="number" name="newMonitor[Width]" value="<?php echo validHtmlStr($monitor->Width()) ?>" size="4"/></td>
</tr>
<tr>
<td><?php echo translate('Height') ?> (<?php echo translate('Pixels') ?>)</td>
<td><input type="number" name="newMonitor[Height]" value="<?php echo validHtmlStr($monitor->Height()) ?>" size="4"/></td>
</tr>
<tr>
<td><?php echo 'Web Site Refresh (Optional)' ?></td>
<td><input type="number" name="newMonitor[Refresh]" value="<?php echo validHtmlStr($monitor->Refresh()) ?>"/></td>
</tr>
<?php <?php
} elseif ( $monitor->Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { } else if ( $monitor->Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) {
?> ?>
<tr class="SourcePath"><td><?php echo translate('SourcePath') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>" /></td></tr> <tr class="SourcePath">
<tr><td><?php echo translate('RemoteMethod') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_RTSPTrans', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><?php echo htmlSelect( "newMonitor[Method]", $rtspFFMpegMethods, $monitor->Method() ); ?></td></tr> <td><?php echo translate('SourcePath') ?></td>
<td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>" /></td>
</tr>
<tr>
<td><?php
echo translate('RemoteMethod');
echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_RTSPTrans', 'zmOptionHelp', 'optionhelp', '?' );
?>)</td>
<td><?php echo htmlSelect('newMonitor[Method]', $rtspFFMpegMethods, $monitor->Method()) ?></td>
</tr>
<tr class="SourceOptions"> <tr class="SourceOptions">
<td><?php echo translate('Options') ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option=OPTIONS_'.strtoupper($monitor->Type()), 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td> <td><?php echo translate('Options') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_'.strtoupper($monitor->Type()), 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
<td><input type="text" name="newMonitor[Options]" value="<?php echo validHtmlStr($monitor->Options()) ?>"/></td> <td><input type="text" name="newMonitor[Options]" value="<?php echo validHtmlStr($monitor->Options()) ?>"/></td>
</tr> </tr>
<?php <?php
@ -840,10 +884,12 @@ include('_monitor_source_nvsocket.php');
</tr> </tr>
<?php <?php
} }
if ( $monitor->Type() != 'NVSocket' && $monitor->Type() != 'WebSite' ) { if ( $monitor->Type() != 'NVSocket' && $monitor->Type() != 'WebSite' ) {
?> ?>
<tr><td><?php echo translate('TargetColorspace') ?></td><td><?php echo htmlSelect('newMonitor[Colours]', $Colours, $monitor->Colours() ); ?> <tr>
</td></tr> <td><?php echo translate('TargetColorspace') ?></td>
<td><?php echo htmlSelect('newMonitor[Colours]', $Colours, $monitor->Colours()) ?></td>
</tr>
<tr> <tr>
<td><?php echo translate('CaptureResolution') ?> (<?php echo translate('Pixels') ?>)</td> <td><?php echo translate('CaptureResolution') ?> (<?php echo translate('Pixels') ?>)</td>
<td> <td>
@ -884,23 +930,30 @@ if ( $monitor->Type() != 'NVSocket' && $monitor->Type() != 'WebSite' ) {
<td><?php echo htmlselect('newMonitor[Orientation]', $orientations, $monitor->Orientation());?></td> <td><?php echo htmlselect('newMonitor[Orientation]', $orientations, $monitor->Orientation());?></td>
</tr> </tr>
<?php <?php
} }
if ( $monitor->Type() == 'Local' ) { if ( $monitor->Type() == 'Local' ) {
?> ?>
<tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts_v4l2 as $name => $value ) { ?><option value="<?php echo validHtmlStr($value); ?>"<?php if ( $value == $monitor->Deinterlacing()) { ?> selected="selected"<?php } ?>><?php echo validHtmlStr($name); ?></option><?php } ?></select></td></tr> <tr>
<?php <td><?php echo translate('Deinterlacing') ?></td>
<td><?php echo htmlselect('newMonitor[Deinterlacing]', $deinterlaceopts_v4l2, $monitor->Deinterlacing())?></td>
</tr>
<?php
} else if ( $monitor->Type() != 'WebSite' ) { } else if ( $monitor->Type() != 'WebSite' ) {
?> ?>
<tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts as $name => $value ) { ?><option value="<?php echo validHtmlStr($value); ?>"<?php if ( $value == $monitor->Deinterlacing()) { ?> selected="selected"<?php } ?>><?php echo validHtmlStr($name); ?></option><?php } ?></select></td></tr> <tr>
<td><?php echo translate('Deinterlacing') ?></td>
<td><?php echo htmlselect('newMonitor[Deinterlacing]', $deinterlaceopts, $monitor->Deinterlacing())?></td>
</tr>
<?php <?php
} }
?>
<?php
if ( $monitor->Type() == 'Remote' ) { if ( $monitor->Type() == 'Remote' ) {
?> ?>
<tr id="RTSPDescribe"<?php if ( $monitor->Protocol()!= 'rtsp' ) { echo ' style="display:none;"'; } ?>><td><?php echo translate('RTSPDescribe') ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option=OPTIONS_RTSPDESCRIBE', 'zmOptionHelp', 'optionhelp', '?' ) ?>) </td><td><input type="checkbox" name="newMonitor[RTSPDescribe]" value="1"<?php if ( $monitor->RTSPDescribe() ) { ?> checked="checked"<?php } ?>/></td></tr> <tr id="RTSPDescribe"<?php if ( $monitor->Protocol()!= 'rtsp' ) { echo ' style="display:none;"'; } ?>>
<td><?php echo translate('RTSPDescribe') ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option=OPTIONS_RTSPDESCRIBE', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
<td><input type="checkbox" name="newMonitor[RTSPDescribe]" value="1"<?php if ( $monitor->RTSPDescribe() ) { ?> checked="checked"<?php } ?>/></td>
</tr>
<?php <?php
} } # end if monitor->Type() == 'Remote'
break; break;
} }
case 'storage' : case 'storage' :
@ -910,7 +963,7 @@ if ( $monitor->Type() == 'Local' ) {
<td> <td>
<?php <?php
$storage_areas = array(0=>'Default'); $storage_areas = array(0=>'Default');
foreach ( ZM\Storage::find(NULL, array('order'=>'lower(Name)')) as $Storage ) { foreach ( ZM\Storage::find(array('Enabled'=>true), array('order'=>'lower(Name)')) as $Storage ) {
$storage_areas[$Storage->Id()] = $Storage->Name(); $storage_areas[$Storage->Id()] = $Storage->Name();
} }
echo htmlSelect('newMonitor[StorageId]', $storage_areas, $monitor->StorageId()); echo htmlSelect('newMonitor[StorageId]', $storage_areas, $monitor->StorageId());
@ -939,15 +992,17 @@ if ( $monitor->Type() == 'Local' ) {
$videowriteropts[1] = 'X264 Encode'; $videowriteropts[1] = 'X264 Encode';
if ($monitor->Type() == 'Ffmpeg' ) if ( $monitor->Type() == 'Ffmpeg' )
$videowriteropts[2] = 'H264 Camera Passthrough'; $videowriteropts[2] = 'H264 Camera Passthrough';
else else
$videowriteropts[2] = array('text'=>'H264 Camera Passthrough - only for FFMPEG','disabled'=>1); $videowriteropts[2] = array('text'=>'H264 Camera Passthrough - only for FFMPEG','disabled'=>1);
echo htmlselect( 'newMonitor[VideoWriter]', $videowriteropts, $monitor->VideoWriter() ); echo htmlselect('newMonitor[VideoWriter]', $videowriteropts, $monitor->VideoWriter());
?> ?>
</td></tr> </td></tr>
<tr><td><?php echo translate('OptionalEncoderParam') ?></td><td><textarea name="newMonitor[EncoderParameters]" rows="4" cols="36"><?php echo validHtmlStr($monitor->EncoderParameters()) ?></textarea></td></tr> <tr>
<td><?php echo translate('OptionalEncoderParam') ?></td>
<td><textarea name="newMonitor[EncoderParameters]" rows="4" cols="36"><?php echo validHtmlStr($monitor->EncoderParameters()) ?></textarea></td></tr>
<tr><td><?php echo translate('RecordAudio') ?></td><td> <tr><td><?php echo translate('RecordAudio') ?></td><td>
<?php if ( $monitor->Type() == 'Ffmpeg' ) { ?> <?php if ( $monitor->Type() == 'Ffmpeg' ) { ?>
<input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ( $monitor->RecordAudio() ) { ?> checked="checked"<?php } ?>/> <input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ( $monitor->RecordAudio() ) { ?> checked="checked"<?php } ?>/>
@ -962,22 +1017,52 @@ if ( $monitor->Type() == 'Local' ) {
case 'timestamp' : case 'timestamp' :
{ {
?> ?>
<tr><td><?php echo translate('TimestampLabelFormat') ?></td><td><input type="text" name="newMonitor[LabelFormat]" value="<?php echo validHtmlStr($monitor->LabelFormat()) ?>" size="32"/></td></tr> <tr>
<tr><td><?php echo translate('TimestampLabelX') ?></td><td><input type="text" name="newMonitor[LabelX]" value="<?php echo validHtmlStr($monitor->LabelX()) ?>" size="4"/></td></tr> <td><?php echo translate('TimestampLabelFormat') ?></td>
<tr><td><?php echo translate('TimestampLabelY') ?></td><td><input type="text" name="newMonitor[LabelY]" value="<?php echo validHtmlStr($monitor->LabelY()) ?>" size="4"/></td></tr> <td><input type="text" name="newMonitor[LabelFormat]" value="<?php echo validHtmlStr($monitor->LabelFormat()) ?>"/></td>
<tr><td><?php echo translate('TimestampLabelSize') ?></td><td><select name="newMonitor[LabelSize]"><?php foreach ( $label_size as $name => $value ) { ?><option value="<?php echo validHtmlStr($value); ?>"<?php if ( $value == $monitor->LabelSize() ) { ?> selected="selected"<?php } ?>><?php echo validHtmlStr($name); ?></option><?php } ?></select></td></tr> </tr>
<tr>
<td><?php echo translate('TimestampLabelX') ?></td>
<td><input type="number" name="newMonitor[LabelX]" value="<?php echo validHtmlStr($monitor->LabelX()) ?>" size="4"/></td>
</tr>
<tr>
<td><?php echo translate('TimestampLabelY') ?></td>
<td><input type="number" name="newMonitor[LabelY]" value="<?php echo validHtmlStr($monitor->LabelY()) ?>" size="4"/></td>
</tr>
<tr>
<td><?php echo translate('TimestampLabelSize') ?></td>
<td><?php echo htmlselect('newMonitor[LabelSize]', $label_size, $monitor->LabelSize()) ?></td>
</tr>
<?php <?php
break; break;
} }
case 'buffers' : case 'buffers' :
{ {
?> ?>
<tr><td><?php echo translate('ImageBufferSize') ?></td><td><input type="text" name="newMonitor[ImageBufferCount]" value="<?php echo validHtmlStr($monitor->ImageBufferCount()) ?>" size="6"/></td></tr> <tr>
<tr><td><?php echo translate('WarmupFrames') ?></td><td><input type="text" name="newMonitor[WarmupCount]" value="<?php echo validHtmlStr($monitor->WarmupCount()) ?>" size="4"/></td></tr> <td><?php echo translate('ImageBufferSize') ?></td>
<tr><td><?php echo translate('PreEventImageBuffer') ?></td><td><input type="text" name="newMonitor[PreEventCount]" value="<?php echo validHtmlStr($monitor->PreEventCount()) ?>" size="4"/></td></tr> <td><input type="number" name="newMonitor[ImageBufferCount]" value="<?php echo validHtmlStr($monitor->ImageBufferCount()) ?>" size="6"/></td>
<tr><td><?php echo translate('PostEventImageBuffer') ?></td><td><input type="text" name="newMonitor[PostEventCount]" value="<?php echo validHtmlStr($monitor->PostEventCount()) ?>" size="4"/></td></tr> </tr>
<tr><td><?php echo translate('StreamReplayBuffer') ?></td><td><input type="text" name="newMonitor[StreamReplayBuffer]" value="<?php echo validHtmlStr($monitor->StreamReplayBuffer()) ?>" size="6"/></td></tr> <tr>
<tr><td><?php echo translate('AlarmFrameCount') ?></td><td><input type="text" name="newMonitor[AlarmFrameCount]" value="<?php echo validHtmlStr($monitor->AlarmFrameCount()) ?>" size="4"/></td></tr> <td><?php echo translate('WarmupFrames') ?></td>
<td><input type="number" name="newMonitor[WarmupCount]" value="<?php echo validHtmlStr($monitor->WarmupCount()) ?>" size="4"/></td>
</tr>
<tr>
<td><?php echo translate('PreEventImageBuffer') ?></td>
<td><input type="number" name="newMonitor[PreEventCount]" value="<?php echo validHtmlStr($monitor->PreEventCount()) ?>" size="4"/></td>
</tr>
<tr>
<td><?php echo translate('PostEventImageBuffer') ?></td>
<td><input type="number" name="newMonitor[PostEventCount]" value="<?php echo validHtmlStr($monitor->PostEventCount()) ?>" size="4"/></td>
</tr>
<tr>
<td><?php echo translate('StreamReplayBuffer') ?></td>
<td><input type="number" name="newMonitor[StreamReplayBuffer]" value="<?php echo validHtmlStr($monitor->StreamReplayBuffer()) ?>" size="6"/></td>
</tr>
<tr>
<td><?php echo translate('AlarmFrameCount') ?></td>
<td><input type="number" name="newMonitor[AlarmFrameCount]" value="<?php echo validHtmlStr($monitor->AlarmFrameCount()) ?>" size="4"/></td>
</tr>
<?php <?php
break; break;
} }
@ -986,7 +1071,8 @@ if ( $monitor->Type() == 'Local' ) {
?> ?>
<tr> <tr>
<td><?php echo translate('Controllable') ?></td> <td><?php echo translate('Controllable') ?></td>
<td><input type="checkbox" name="newMonitor[Controllable]" value="1"<?php if ( $monitor->Controllable() ) { ?> checked="checked"<?php } ?>/></td></tr> <td><input type="checkbox" name="newMonitor[Controllable]" value="1"<?php if ( $monitor->Controllable() ) { ?> checked="checked"<?php } ?>/></td>
</tr>
<tr> <tr>
<td><?php echo translate('ControlType') ?></td> <td><?php echo translate('ControlType') ?></td>
<td><?php echo htmlSelect('newMonitor[ControlId]', $controlTypes, $monitor->ControlId()); <td><?php echo htmlSelect('newMonitor[ControlId]', $controlTypes, $monitor->ControlId());
@ -1011,20 +1097,19 @@ if ( canEdit('Control') ) {
<td><?php echo translate('TrackMotion') ?></td> <td><?php echo translate('TrackMotion') ?></td>
<td><input type="checkbox" name="newMonitor[TrackMotion]" value="1"<?php if ( $monitor->TrackMotion() ) { ?> checked="checked"<?php } ?>/></td> <td><input type="checkbox" name="newMonitor[TrackMotion]" value="1"<?php if ( $monitor->TrackMotion() ) { ?> checked="checked"<?php } ?>/></td>
</tr> </tr>
<?php
$return_options = array(
'-1' => translate('None'),
'0' => translate('Home'),
'1' => translate('Preset').' 1',
);
?>
<tr> <tr>
<td><?php echo translate('TrackDelay') ?></td> <td><?php echo translate('TrackDelay') ?></td>
<td><input type="number" name="newMonitor[TrackDelay]" value="<?php echo validHtmlStr($monitor->TrackDelay()) ?>"/></td> <td><input type="number" name="newMonitor[TrackDelay]" value="<?php echo validHtmlStr($monitor->TrackDelay()) ?>"/></td>
</tr> </tr>
<tr> <tr>
<td><?php echo translate('ReturnLocation') ?></td> <td><?php echo translate('ReturnLocation') ?></td>
<td><?php echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnLocation()); ?></td> <td><?php
$return_options = array(
'-1' => translate('None'),
'0' => translate('Home'),
'1' => translate('Preset').' 1',
);
echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnLocation()); ?></td>
</tr> </tr>
<tr> <tr>
<td><?php echo translate('ReturnDelay') ?></td> <td><?php echo translate('ReturnDelay') ?></td>

View File

@ -57,9 +57,6 @@ if ( isset($_REQUEST['scale']) ) {
$scale = $_COOKIE['zmMontageScale']; $scale = $_COOKIE['zmMontageScale'];
} }
if ( ! $scale )
$scale = 100;
$layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')")); $layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')"));
$layoutsById = array(); $layoutsById = array();
foreach ( $layouts as $l ) { foreach ( $layouts as $l ) {
@ -111,7 +108,7 @@ if ( isset($_COOKIE['zmMontageHeight']) and $_COOKIE['zmMontageHeight'] )
else else
$options['height'] = ''; $options['height'] = '';
if ( $scale ) #if ( $scale )
$options['scale'] = $scale; $options['scale'] = $scale;
session_write_close(); session_write_close();
@ -127,7 +124,7 @@ foreach( $displayMonitors as &$row ) {
continue; continue;
$row['Scale'] = $scale; $row['Scale'] = $scale;
$row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); $row['PopupScale'] = reScale(SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE);
if ( ZM_OPT_CONTROL && $row['ControlId'] && $row['Controllable'] ) if ( ZM_OPT_CONTROL && $row['ControlId'] && $row['Controllable'] )
$showControl = true; $showControl = true;
@ -207,7 +204,12 @@ if ( $showZones ) {
foreach ( $monitors as $monitor ) { foreach ( $monitors as $monitor ) {
$connkey = $monitor->connKey(); // Minor hack $connkey = $monitor->connKey(); // Minor hack
?> ?>
<div id="monitorFrame<?php echo $monitor->Id() ?>" class="monitorFrame" title="<?php echo $monitor->Id() . ' ' .$monitor->Name() ?>" style="<?php echo $options['width'] ? 'width:'.$options['width'].';':''?>"> <div
id="monitorFrame<?php echo $monitor->Id() ?>"
class="monitorFrame"
title="<?php echo $monitor->Id() . ' ' .$monitor->Name() ?>"
style="<?php echo $options['width'] ? 'width:'.$options['width'].';':''?>"
>
<div id="monitor<?php echo $monitor->Id() ?>" class="monitor idle"> <div id="monitor<?php echo $monitor->Id() ?>" class="monitor idle">
<div <div
id="imageFeed<?php echo $monitor->Id() ?>" id="imageFeed<?php echo $monitor->Id() ?>"

View File

@ -62,6 +62,17 @@ ob_end_clean();
$filter = array(); $filter = array();
if ( isset($_REQUEST['filter']) ) { if ( isset($_REQUEST['filter']) ) {
$filter = $_REQUEST['filter']; $filter = $_REQUEST['filter'];
# Try to guess min/max time from filter
foreach ( $filter['Query'] as $term ) {
if ( $term['attr'] == 'StartDateTime' ) {
if ( $term['op'] == '<=' or $term['op'] == '<' ) {
$maxTime = $term['val'];
} else if ( $term['op'] == '>=' or $term['op'] == '>' ) {
$minTime = $term['val'];
}
}
}
} else { } else {
if ( isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && (count($displayMonitors) != 0) ) { if ( isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && (count($displayMonitors) != 0) ) {

View File

@ -1,7 +1,7 @@
<?php <?php
// //
// ZoneMinder web user view file, $Date$, $Revision$ // ZoneMinder web user view file
// Copyright (C) 2001-2008 Philip Coombes // Copyright (C) 2020 ZoneMinder LLC
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -23,22 +23,17 @@ if ( !canEdit('System') ) {
return; return;
} }
require_once('includes/Server.php');
require_once('includes/Storage.php');
if ( $_REQUEST['id'] ) { if ( $_REQUEST['id'] ) {
if ( !($newStorage = dbFetchOne('SELECT * FROM Storage WHERE Id=?', NULL, ARRAY($_REQUEST['id'])) ) ) { if ( !($newStorage = ZM\Storage::find_one(array('Id'=>$_REQUEST['id'])) ) ) {
$view = 'error'; $view = 'error';
return; return;
$newStorage['ServerId'] = '';
} }
} else { } else {
$newStorage = array(); $newStorage = new ZM\Storage();
$newStorage['Name'] = translate('NewStorage'); $newStorage->Name(translate('NewStorage'));
$newStorage['Path'] = '';
$newStorage['Type'] = 'local';
$newStorage['Url'] = '';
$newStorage['Scheme'] = 'Medium';
$newStorage['StorageId'] = '';
$newStorage['ServerId'] = '';
$newStorage['DoDelete'] = 1;
} }
$type_options = array( 'local' => translate('Local'), 's3fs' => translate('s3fs') ); $type_options = array( 'local' => translate('Local'), 's3fs' => translate('s3fs') );
@ -55,12 +50,12 @@ foreach ( $servers as $S ) {
} }
$focusWindow = true; $focusWindow = true;
xhtmlHeaders(__FILE__, translate('Storage').' - '.$newStorage['Name']); xhtmlHeaders(__FILE__, translate('Storage').' - '.$newStorage->Name());
?> ?>
<body> <body>
<div id="page"> <div id="page">
<div id="header"> <div id="header">
<h2><?php echo translate('Storage').' - '.$newStorage['Name'] ?></h2> <h2><?php echo translate('Storage').' - '.$newStorage->Name() ?></h2>
</div> </div>
<div id="content"> <div id="content">
<form name="contentForm" method="post" action="?" class="validateFormOnSubmit"> <form name="contentForm" method="post" action="?" class="validateFormOnSubmit">
@ -71,33 +66,40 @@ xhtmlHeaders(__FILE__, translate('Storage').' - '.$newStorage['Name']);
<tbody> <tbody>
<tr> <tr>
<th scope="row"><?php echo translate('Name') ?></th> <th scope="row"><?php echo translate('Name') ?></th>
<td><input type="text" name="newStorage[Name]" value="<?php echo $newStorage['Name'] ?>"/></td> <td><input type="text" name="newStorage[Name]" value="<?php echo $newStorage->Name() ?>"/></td>
</tr> </tr>
<tr> <tr>
<th scope="row"><?php echo translate('Path') ?></th> <th scope="row"><?php echo translate('Path') ?></th>
<td><input type="text" name="newStorage[Path]" value="<?php echo $newStorage['Path'] ?>"/></td> <td><input type="text" name="newStorage[Path]" value="<?php echo $newStorage->Path() ?>"/></td>
</tr> </tr>
<tr> <tr>
<th scope="row"><?php echo translate('Url') ?></th> <th scope="row"><?php echo translate('Url') ?></th>
<td><input type="text" name="newStorage[Url]" value="<?php echo $newStorage['Url'] ?>"/></td> <td><input type="text" name="newStorage[Url]" value="<?php echo $newStorage->Url() ?>"/></td>
</tr> </tr>
<tr> <tr>
<th scope="row"><?php echo translate('Server') ?></th> <th scope="row"><?php echo translate('Server') ?></th>
<td><?php echo htmlSelect('newStorage[ServerId]', array(''=>'Remote / No Specific Server') + $ServersById, $newStorage['ServerId']); ?></td> <td><?php echo htmlSelect('newStorage[ServerId]', array(''=>'Remote / No Specific Server') + $ServersById, $newStorage->ServerId()); ?></td>
</tr> </tr>
<tr> <tr>
<th scope="row"><?php echo translate('Type') ?></th> <th scope="row"><?php echo translate('Type') ?></th>
<td><?php echo htmlSelect('newStorage[Type]', $type_options, $newStorage['Type']); ?></td> <td><?php echo htmlSelect('newStorage[Type]', $type_options, $newStorage->Type()); ?></td>
</tr> </tr>
<tr> <tr>
<th scope="row"><?php echo translate('StorageScheme') ?></th> <th scope="row"><?php echo translate('StorageScheme') ?></th>
<td><?php echo htmlSelect('newStorage[Scheme]', $scheme_options, $newStorage['Scheme']); ?></td> <td><?php echo htmlSelect('newStorage[Scheme]', $scheme_options, $newStorage->Scheme()); ?></td>
</tr> </tr>
<tr> <tr>
<th scope="row"><?php echo translate('StorageDoDelete') ?></th> <th scope="row"><?php echo translate('StorageDoDelete') ?></th>
<td> <td>
<input type="radio" name="newStorage[DoDelete]" value="1"<?php echo $newStorage['DoDelete'] ? 'checked="checked"' : '' ?>/>Yes <input type="radio" name="newStorage[DoDelete]" value="1"<?php echo $newStorage->DoDelete() ? 'checked="checked"' : '' ?>/>Yes
<input type="radio" name="newStorage[DoDelete]" value="0"<?php echo $newStorage['DoDelete'] ? '' : 'checked="checked"' ?>/>No <input type="radio" name="newStorage[DoDelete]" value="0"<?php echo $newStorage->DoDelete() ? '' : 'checked="checked"' ?>/>No
</td>
</tr>
<tr>
<th scope="row"><?php echo translate('Enabled') ?></th>
<td>
<input type="radio" name="newStorage[Enabled]" value="1"<?php echo $newStorage->Enabled() ? 'checked="checked"' : '' ?>/>Yes
<input type="radio" name="newStorage[Enabled]" value="0"<?php echo $newStorage->Enabled() ? '' : 'checked="checked"' ?>/>No
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -57,6 +57,7 @@ $filename = '';
$Frame = null; $Frame = null;
$Event = null; $Event = null;
$path = null; $path = null;
$media_type='image/jpeg';
if ( empty($_REQUEST['path']) ) { if ( empty($_REQUEST['path']) ) {
@ -77,6 +78,47 @@ if ( empty($_REQUEST['path']) ) {
} }
if ( $_REQUEST['fid'] == 'objdetect' ) { if ( $_REQUEST['fid'] == 'objdetect' ) {
// if animation file is found, return that, else return image
// we are only looking for GIF or jpg here, not mp4
// as most often, browsers asking for this link will be expecting
// media types that can be rendered as <img src=>
$path_anim_gif = $Event->Path().'/objdetect.gif';
$path_image = $Event->Path().'/objdetect.jpg';
if (file_exists($path_anim_gif)) {
// we found the animation gif file
$media_type = 'image/gif';
ZM\Logger::Debug("Animation file found at $path");
$path = $path_anim_gif;
} else if (file_exists($path_image)) {
// animation not found, but image found
ZM\Logger::Debug("Image file found at $path");
$path = $path_image;
} else {
// neither animation nor image found
header('HTTP/1.0 404 Not Found');
ZM\Fatal("Object detection animation and image not found for this event");
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
} else if ( $_REQUEST['fid'] == 'objdetect_mp4' ) {
$path = $Event->Path().'/objdetect.mp4';
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation");
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
$media_type = 'video/mp4';
} else if ( $_REQUEST['fid'] == 'objdetect_gif' ) {
$path = $Event->Path().'/objdetect.gif';
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation");
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
$media_type = 'image/gif';
} else if ( $_REQUEST['fid'] == 'objdetect_jpg' ) {
$path = $Event->Path().'/objdetect.jpg'; $path = $Event->Path().'/objdetect.jpg';
if ( !file_exists($path) ) { if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found'); header('HTTP/1.0 404 Not Found');
@ -281,7 +323,7 @@ if ( !empty($_REQUEST['height']) ) {
if ( $errorText ) { if ( $errorText ) {
ZM\Error($errorText); ZM\Error($errorText);
} else { } else {
header('Content-type: image/jpeg'); header("Content-type: $media_type");
if ( ( $scale==0 || $scale==100 ) && ($width==0) && ($height==0) ) { if ( ( $scale==0 || $scale==100 ) && ($width==0) && ($height==0) ) {
# This is so that Save Image As give a useful filename # This is so that Save Image As give a useful filename
if ( $Event ) { if ( $Event ) {

View File

@ -25,13 +25,13 @@
# #
use strict; use strict;
use lib './scripts/ZoneMinder/lib'; use lib '@CMAKE_CURRENT_BINARY_DIR@/scripts/ZoneMinder/lib';
use ZoneMinder::ConfigData qw/:data/; use ZoneMinder::ConfigData qw/:data/;
$| = 1; $| = 1;
my $config_header = "src/zm_config_defines.h"; my $config_header = '@CMAKE_CURRENT_BINARY_DIR@/src/zm_config_defines.h';
my $config_sql = "db/zm_create.sql"; my $config_sql = '@CMAKE_CURRENT_BINARY_DIR@/db/zm_create.sql';
generateConfigFiles(); generateConfigFiles();

View File

@ -59,6 +59,8 @@
#cmakedefine HAVE_LIBAVRESAMPLE_AVRESAMPLE_H 1 #cmakedefine HAVE_LIBAVRESAMPLE_AVRESAMPLE_H 1
#cmakedefine HAVE_LIBVLC 1 #cmakedefine HAVE_LIBVLC 1
#cmakedefine HAVE_VLC_VLC_H 1 #cmakedefine HAVE_VLC_VLC_H 1
#cmakedefine HAVE_LIBVNC 1
#cmakedefine HAVE_RFB_RFB_H 1
#cmakedefine HAVE_LIBX264 1 #cmakedefine HAVE_LIBX264 1
#cmakedefine HAVE_X264_H 1 #cmakedefine HAVE_X264_H 1
#cmakedefine HAVE_LIBMP4V2 1 #cmakedefine HAVE_LIBMP4V2 1