Merge branch 'storageareas' of github.com:connortechnology/ZoneMinder into storageareas

This commit is contained in:
Isaac Connor 2018-04-30 15:11:32 -04:00
commit cae2c9e237
55 changed files with 854 additions and 540 deletions

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','Ffmpeg','Libvlc','cURL') NOT NULL default 'Local', `Type` enum('Local','Remote','Ffmpeg','Libvlc','cURL','WebSite') 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',
@ -892,7 +892,7 @@ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' ); INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
-- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts. -- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts.
source @ZM_PATH_DATA@/db/triggers.sql source @PKGDATADIR@/db/triggers.sql
-- --
-- Apply the initial configuration -- Apply the initial configuration
-- --

24
db/zm_update-1.31.43.sql Normal file
View File

@ -0,0 +1,24 @@
--
-- This updates a 1.31.42 database to 1.31.43
--
-- Add WebSite enum to Monitor.Type
-- Add Refresh column to Monitors table
--
ALTER TABLE `zm`.`Monitors`
CHANGE COLUMN `Type` `Type` ENUM('Local', 'Remote', 'File', 'Ffmpeg', 'Libvlc', 'cURL', 'WebSite') NOT NULL DEFAULT 'Local' ;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Monitors'
AND table_schema = DATABASE()
AND column_name = 'Refresh'
) > 0,
"SELECT 'Column Refresh exists in Monitors'",
"ALTER TABLE Monitors ADD `Refresh` int(10) unsigned default NULL"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -26,7 +26,7 @@
%global _hardened_build 1 %global _hardened_build 1
Name: zoneminder Name: zoneminder
Version: 1.31.42 Version: 1.31.43
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

@ -54,7 +54,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,liburi-encode-perl ,liburi-encode-perl
,libwww-perl ,libwww-perl
,libdata-uuid-perl ,libdata-uuid-perl
,libnumber-bytes-human ,libnumber-bytes-human-perl
,libfile-slurp-perl ,libfile-slurp-perl
,mysql-client | virtual-mysql-client ,mysql-client | virtual-mysql-client
,perl-modules ,perl-modules

View File

@ -71,6 +71,7 @@ The 1.2 at the start is basically adding 20% on top of the calculation to accoun
The math breakdown for 4 cameras running at 1280x960 capture, 50 frame buffer, 24 bit color space: The math breakdown for 4 cameras running at 1280x960 capture, 50 frame buffer, 24 bit color space:
:: ::
1280*960 = 1,228,800 (bytes) 1280*960 = 1,228,800 (bytes)
1,228,800 * (3 bytes for 24 bit) = 3,686,400 (bytes) 1,228,800 * (3 bytes for 24 bit) = 3,686,400 (bytes)
3,686,400 * 50 = 184,320,000 (bytes) 3,686,400 * 50 = 184,320,000 (bytes)

View File

@ -14,7 +14,7 @@ If you are using an older version of ZoneMinder, please follow the legacy steps
**Step 2:** Mount your dedicated drive, partition, or network share to the local filesystem in any folder of your choosing. **Step 2:** Mount your dedicated drive, partition, or network share to the local filesystem in any folder of your choosing.
We recommend you use systemd to manage the mount points. We recommend you use systemd to manage the mount points.
Instructions on how to accomplish this can be found `here <https://zoneminder.blogspot.com/p/blog-page.html>`_ and `here <https://wiki.zoneminder.com/Common_Issues_with_Zoneminder_Installation_on_Ubuntu#Use_Systemd_to_Mount_Internal_Drive_or_NAS>`_. Instructions on how to accomplish this can be found `here <https://zoneminder.blogspot.com/p/blog-page.html>`__ and `here <https://wiki.zoneminder.com/Common_Issues_with_Zoneminder_Installation_on_Ubuntu#Use_Systemd_to_Mount_Internal_Drive_or_NAS>`__.
Note that bind mounting ZoneMinder's images folder is optional. Newer version of ZoneMinder write very little, if anything, to the images folder. Note that bind mounting ZoneMinder's images folder is optional. Newer version of ZoneMinder write very little, if anything, to the images folder.
Verify the dedicated drive, partition, or network share is successfully mounted before proceeding to the next step. Verify the dedicated drive, partition, or network share is successfully mounted before proceeding to the next step.

View File

@ -45,7 +45,7 @@ The following notes are based on real problems which have occurred by those who
How to Install ZoneMinder How to Install ZoneMinder
------------------------- -------------------------
ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site <https://rpmfusion.org>`_ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site <https://fedoraproject.org/wiki/EPEL>`_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline: ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site <https://rpmfusion.org>`__ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site <https://fedoraproject.org/wiki/EPEL>`_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline:
:: ::
@ -65,9 +65,9 @@ The feedback we get from those who use these development packages is extremely h
How to Change from Zmrepo to RPM Fusion How to Change from Zmrepo to RPM Fusion
--------------------------------------- ---------------------------------------
As mentioned above, the place to get the latest ZoneMinder release is now `RPM Fusion <https://rpmfusion.org>`_. If you are currently using ZoneMinder release packages from Zmrepo, then the following steps will change you over to RPM Fusion: As mentioned above, the place to get the latest ZoneMinder release is now `RPM Fusion <https://rpmfusion.org>`__. If you are currently using ZoneMinder release packages from Zmrepo, then the following steps will change you over to RPM Fusion:
- Navigate to the `RPM Fusion site <https://rpmfusion.org>`_ and enable RPM Fusion on your system - Navigate to the `RPM Fusion site <https://rpmfusion.org>`__ and enable RPM Fusion on your system
- Now issue the following from the command line: - Now issue the following from the command line:
:: ::
@ -123,7 +123,7 @@ Your build environment is now set up.
Build from SRPM Build from SRPM
*************** ***************
To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site <https://rpmfusion.org/>`_. If instead you wish to rebuild the latest source rpm from our master branch then browse the `Zmrepo site <http://zmrepo.zoneminder.com/>`_. To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site <https://rpmfusion.org/>`__. If instead you wish to rebuild the latest source rpm from our master branch then browse the `Zmrepo site <http://zmrepo.zoneminder.com/>`_.
For this example, I'll use one of the source rpms from zmrepo: For this example, I'll use one of the source rpms from zmrepo:

View File

@ -147,6 +147,23 @@ Keep aspect ratio
Orientation Orientation
As per local devices. As per local devices.
WebSite
^^^^^^^
This Source Type allows one to configure an arbitrary website as a non-reocrdable, fully interactive, monitor in ZoneMinder. Note that sites with self-signed certificates will not display until the end user first manually navigates to the site and accpets the unsigned certificate. Also note that some sites will set an X-Frame option in the header, which discourages their site from being displayed within a frame. ZoneMinder will detect this condition and present a warning in the log. When this occurs, the end user can choose to install a browser plugin or extension to workaround this issue.
Website URL
Enter the full http or https url to the desired website.
Width (pixels)
Chose a desired width in pixels that gives an acceptable appearance. This may take some expirimentation.
Height (pixels)
Chose a desired height in pixels that gives an acceptable appearance. This may take some expirimentation.
Web Site Refresh
If the website in question has static content, optionally enter a time period in seconds for ZoneMinder to refresh the content.
Timestamp Tab Timestamp Tab
------------- -------------

View File

@ -2946,6 +2946,23 @@ our @options = (
type => $types{boolean}, type => $types{boolean},
category => 'web', category => 'web',
}, },
{
name => 'ZM_WEB_XFRAME_WARN',
default => 'yes',
description => 'Warn when website X-Frame-Options is set to sameorigin',
help => q`
When creating a Web Site monitor, if the target web site has
X-Frame-Options set to sameorigin in the header, the site will
not display in ZoneMinder. This is a design feature in most modern
browsers. When this condiction has occured, ZoneMinder will write a
warning to the log file. To get around this, one can install a browser
plugin or extension to ignore X-Frame headers, and then the page will
display properly. Once the plugin or extenstion has ben installed,
the end user may choose to turn this warning off.
`,
type => $types{boolean},
category => 'web',
},
{ {
name => 'ZM_WEB_H_REFRESH_MAIN', name => 'ZM_WEB_H_REFRESH_MAIN',
default => '60', default => '60',

View File

@ -77,39 +77,39 @@ sub zmDbConnect {
} }
my $options = shift; my $options = shift;
if ( ( ! defined( $dbh ) ) or ! $dbh->ping() ) { if ( ( !defined($dbh) ) or ! $dbh->ping() ) {
my ( $host, $portOrSocket ) = ( $ZoneMinder::Config::Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my ( $host, $portOrSocket ) = ( $ZoneMinder::Config::Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
my $socket; my $socket;
if ( defined($portOrSocket) ) { if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) { if ( $portOrSocket =~ /^\// ) {
$socket = ";mysql_socket=".$portOrSocket; $socket = ';mysql_socket='.$portOrSocket;
} else { } else {
$socket = ";host=".$host.";port=".$portOrSocket; $socket = ';host='.$host.';port='.$portOrSocket;
} }
} else { } else {
$socket = ";host=".$Config{ZM_DB_HOST}; $socket = ';host='.$Config{ZM_DB_HOST};
} }
my $sslOptions = ""; my $sslOptions = '';
if ( $Config{ZM_DB_SSL_CA_CERT} ) { if ( $Config{ZM_DB_SSL_CA_CERT} ) {
$sslOptions = ';'.join(';', $sslOptions = ';'.join(';',
"mysql_ssl=1", 'mysql_ssl=1',
"mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT}, 'mysql_ssl_ca_file='.$Config{ZM_DB_SSL_CA_CERT},
"mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY}, 'mysql_ssl_client_key='.$Config{ZM_DB_SSL_CLIENT_KEY},
"mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT} 'mysql_ssl_client_cert='.$Config{ZM_DB_SSL_CLIENT_CERT}
); );
} }
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} $dbh = DBI->connect( 'DBI:mysql:database='.$Config{ZM_DB_NAME}
.$socket . $sslOptions . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' ) .$socket . $sslOptions . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' )
, $Config{ZM_DB_USER} , $Config{ZM_DB_USER}
, $Config{ZM_DB_PASS} , $Config{ZM_DB_PASS}
); );
$dbh->trace( 0 ); $dbh->trace(0) if $dbh;
} }
return( $dbh ); return $dbh;
} } # end sub zmDbConnect
sub zmDbDisconnect { sub zmDbDisconnect {
if ( defined( $dbh ) ) { if ( defined( $dbh ) ) {

View File

@ -529,6 +529,8 @@ sub MoveTo {
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
if ( ! $$NewStorage{Id} ) { if ( ! $$NewStorage{Id} ) {
return "New storage does not have an id. Moving will not happen."; return "New storage does not have an id. Moving will not happen.";
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
return "Event is already located at " . $NewPath;
} elsif ( !$NewPath ) { } elsif ( !$NewPath ) {
return "New path ($NewPath) is empty."; return "New path ($NewPath) is empty.";
} elsif ( ! -e $NewPath ) { } elsif ( ! -e $NewPath ) {

View File

@ -160,9 +160,12 @@ sub Sql {
if ( $term->{attr} =~ /^Monitor/ ) { if ( $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} =~ /^Server/ ) { } elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) {
$self->{Sql} .= 'S.'.$term->{attr}; $self->{Sql} .= 'M.ServerId';
} elsif ( $term->{attr} eq 'StorageServerId' ) {
$self->{Sql} .= 'S.ServerId';
} elsif ( $term->{attr} eq 'FilterServerId' ) {
$self->{Sql} .= $Config{ZM_SERVER_ID};
# StartTime options # StartTime options
} elsif ( $term->{attr} eq 'DateTime' ) { } elsif ( $term->{attr} eq 'DateTime' ) {
$self->{Sql} .= 'E.StartTime'; $self->{Sql} .= 'E.StartTime';
@ -208,7 +211,7 @@ sub Sql {
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} =~ /^MonitorName/ ) {
$value = "'$temp_value'"; $value = "'$temp_value'";
} elsif ( $term->{attr} eq 'ServerId' ) { } elsif ( $term->{attr} =~ /ServerId/) {
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})"); Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
if ( $temp_value eq 'ZM_SERVER_ID' ) { if ( $temp_value eq 'ZM_SERVER_ID' ) {
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'"; $value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
@ -241,7 +244,7 @@ sub Sql {
} }
$value = "'$value'"; $value = "'$value'";
} }
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) { } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
if ( $temp_value eq 'NULL' ) { if ( $temp_value eq 'NULL' ) {
$value = $temp_value; $value = $temp_value;
} else { } else {

View File

@ -158,6 +158,7 @@ sub new {
( $this->{fileName} = $0 ) =~ s|^.*/||; ( $this->{fileName} = $0 ) =~ s|^.*/||;
$this->{logPath} = $Config{ZM_PATH_LOGS}; $this->{logPath} = $Config{ZM_PATH_LOGS};
$this->{logFile} = $this->{logPath}.'/'.$this->{id}.'.log'; $this->{logFile} = $this->{logPath}.'/'.$this->{id}.'.log';
($this->{logFile}) = $this->{logFile} =~ /^([\w\.\/]+)$/;
$this->{trace} = 0; $this->{trace} = 0;
@ -207,6 +208,7 @@ sub initialise( @ ) {
if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) { if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) {
$tempLogFile = $logFile; $tempLogFile = $logFile;
} }
($tempLogFile) = $tempLogFile =~ /^([\w\.\/]+)$/;
my $tempLevel = INFO; my $tempLevel = INFO;
my $tempTermLevel = $this->{termLevel}; my $tempTermLevel = $this->{termLevel};
@ -581,28 +583,34 @@ sub logPrint {
syslog($priorities{$level}, $code.' [%s]', $string); syslog($priorities{$level}, $code.' [%s]', $string);
} }
print($LOGFILE $message) if $level <= $this->{fileLevel}; print($LOGFILE $message) if $level <= $this->{fileLevel};
print(STDERR $message) if $level <= $this->{termLevel};
if ( $level <= $this->{databaseLevel} ) { if ( $level <= $this->{databaseLevel} ) {
my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )'; if ( ( $this->{dbh} and $this->{dbh}->ping() ) or ( $this->{dbh} = zmDbConnect() ) ) {
$this->{sth} = $this->{dbh}->prepare_cached($sql);
if ( !$this->{sth} ) { my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )';
$this->{databaseLevel} = NOLOG; $this->{sth} = $this->{dbh}->prepare_cached($sql);
Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr()); if ( !$this->{sth} ) {
} else {
my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0)
, $this->{id}
, $$
, $level
, $code
, $string
, $this->{fileName}
);
if ( !$res ) {
$this->{databaseLevel} = NOLOG; $this->{databaseLevel} = NOLOG;
Error("Can't execute log entry '$sql': ".$this->{sth}->errstr()); Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr());
} else {
my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0)
, $this->{id}
, $$
, $level
, $code
, $string
, $this->{fileName}
);
if ( !$res ) {
$this->{databaseLevel} = NOLOG;
Error("Can't execute log entry '$sql': ".$this->{dbh}->errstr());
}
} }
} else {
print(STDERR "Can't log to database: ");
} }
} # end if doing db logging } # end if doing db logging
print(STDERR $message) if $level <= $this->{termLevel};
} # end if level < effectivelevel } # end if level < effectivelevel
} }

View File

@ -242,6 +242,7 @@ use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sendin
our %cmd_hash; our %cmd_hash;
our %pid_hash; our %pid_hash;
our %terminating_processes; our %terminating_processes;
our $zm_terminate = 0;
sub run { sub run {
my $fd = 0; my $fd = 0;
@ -276,9 +277,9 @@ sub run {
listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
$SIG{CHLD} = \&reaper; $SIG{CHLD} = \&reaper;
$SIG{INT} = \&shutdownAll; $SIG{INT} = \&shutdown_sig_handler;
$SIG{TERM} = \&shutdownAll; $SIG{TERM} = \&shutdown_sig_handler;
$SIG{ABRT} = \&shutdownAll; $SIG{ABRT} = \&shutdown_sig_handler;
$SIG{HUP} = \&logrot; $SIG{HUP} = \&logrot;
my $rin = ''; my $rin = '';
@ -295,12 +296,17 @@ sub run {
dPrint(ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name}); dPrint(ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name});
} }
while( 1 ) { while( !$zm_terminate ) {
if ( $Config{ZM_SERVER_ID} ) { if ( $Config{ZM_SERVER_ID} ) {
if ( ! ( $secs_count % 60 ) ) { if ( ! ( $secs_count % 60 ) ) {
$dbh = zmDbConnect() if ! $dbh->ping(); Debug("Connecting");
while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) {
Warning("Not connected to db ($dbh). Reconnecting");
$dbh = zmDbConnect();
}
my @cpuload = CpuLoad(); my @cpuload = CpuLoad();
Debug("UPdating Server record @cpuload");
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { 'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
@ -308,7 +314,9 @@ sub run {
} }
$secs_count += 1; $secs_count += 1;
} }
Debug("Before select");
my $nfound = select(my $rout = $rin, undef, undef, $timeout); my $nfound = select(my $rout = $rin, undef, undef, $timeout);
Debug("Aftere select $nfound");
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);
@ -330,7 +338,8 @@ sub run {
# Do nothing, this is all we're here for # Do nothing, this is all we're here for
dPrint(ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n"); dPrint(ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n");
} elsif ( $command eq 'shutdown' ) { } elsif ( $command eq 'shutdown' ) {
shutdownAll(); # Breka out of while loop
last;
} elsif ( $command eq 'check' ) { } elsif ( $command eq 'check' ) {
check($daemon, @args); check($daemon, @args);
} elsif ( $command eq 'status' ) { } elsif ( $command eq 'status' ) {
@ -346,14 +355,13 @@ sub run {
} }
close(CLIENT); close(CLIENT);
} else { } else {
Fatal('Bogus descriptor'); Error('Bogus descriptor');
} }
} elsif ( $nfound < 0 ) { } elsif ( $nfound < 0 ) {
if ( $! == EINTR ) { if ( $! == EINTR ) {
# Dead child, will be reaped # Dead child, will be reaped
#print( "Probable dead child\n" ); #print( "Probable dead child\n" );
# See if it needs to start up again # See if it needs to start up again
restartPending();
} elsif ( $! == EPIPE ) { } elsif ( $! == EPIPE ) {
Error("Can't select: $!"); Error("Can't select: $!");
} else { } else {
@ -361,12 +369,15 @@ sub run {
} }
} else { } else {
#print( "Select timed out\n" ); #print( "Select timed out\n" );
restartPending();
} }
Debug("restartPending");
restartPending();
Debug("check_for_processes_to_kill");
check_for_processes_to_kill(); check_for_processes_to_kill();
} # end while } # end while
dPrint(ZoneMinder::Logger::INFO, 'Server exiting at ' dPrint(ZoneMinder::Logger::INFO, 'Server exiting at '
.strftime( '%y/%m/%d %H:%M:%S', localtime() ) .strftime( '%y/%m/%d %H:%M:%S', localtime() )
."\n" ."\n"
@ -377,9 +388,7 @@ sub run {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
} }
} }
unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE ); shutdownAll();
unlink(ZM_PID) or Error('Unable to unlink ' . ZM_PID .". Error message was: $!") if ( -e ZM_PID );
exit();
} }
sub cPrint { sub cPrint {
@ -426,10 +435,12 @@ sub start {
} }
my $sigset = POSIX::SigSet->new; my $sigset = POSIX::SigSet->new;
my $blockset = POSIX::SigSet->new( SIGCHLD ); my $blockset = POSIX::SigSet->new(SIGCHLD);
Debug("Blocking SIGCHLD");
sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!"); sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!");
Debug("forking");
if ( my $cpid = fork() ) { if ( my $cpid = fork() ) {
logReinit(); #logReinit();
$process->{pid} = $cpid; $process->{pid} = $cpid;
$process->{started} = time(); $process->{started} = time();
@ -442,6 +453,7 @@ sub start {
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process; $cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!"); sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!");
Debug("unblocko child");
} elsif ( defined($cpid) ) { } elsif ( defined($cpid) ) {
# Force reconnection to the db. # Force reconnection to the db.
$dbh = zmDbConnect(1); $dbh = zmDbConnect(1);
@ -527,16 +539,18 @@ sub check_for_processes_to_kill {
my $sigset = POSIX::SigSet->new; my $sigset = POSIX::SigSet->new;
my $blockset = POSIX::SigSet->new(SIGCHLD); my $blockset = POSIX::SigSet->new(SIGCHLD);
sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n"; sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n";
foreach my $command ( %terminating_processes ) { foreach my $command ( keys %terminating_processes ) {
my $process = $cmd_hash{$command}; my $process = $cmd_hash{$command};
Debug("Have process $command at pid $$process{pid} $$process{term_sent_at}"); my $now = time;
if ( $$process{term_sent_at} - time > KILL_DELAY ) { Debug("Have process $command at pid $$process{pid} $$process{term_sent_at} - $now = " . ( $$process{term_sent_at} - $now ) );
if ( $$process{term_sent_at} and ( $$process{term_sent_at} - $now > KILL_DELAY ) ) {
dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at "
.strftime('%y/%m/%d %H:%M:%S', localtime()) .strftime('%y/%m/%d %H:%M:%S', localtime())
.' after ' . KILL_DELAY . ' seconds.' .' after ' . KILL_DELAY . ' seconds.'
." Sending KILL to pid $$process{pid}\n" ." Sending KILL to pid $$process{pid}\n"
); );
kill('KILL', $$process{pid}); kill('KILL', $$process{pid});
delete $terminating_processes{$command};
} }
} }
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
@ -595,8 +609,14 @@ sub logrot {
} }
} }
sub shutdown_sig_handler {
$zm_terminate = 1;
}
sub reaper { sub reaper {
my $saved_status = $!; my $saved_status = $!;
# Wait for a child to terminate
while ( (my $cpid = waitpid(-1, WNOHANG)) > 0 ) { while ( (my $cpid = waitpid(-1, WNOHANG)) > 0 ) {
my $status = $?; my $status = $?;
@ -620,8 +640,8 @@ sub reaper {
my $out_str = "'$process->{command}' "; my $out_str = "'$process->{command}' ";
if ( $exit_signal ) { if ( $exit_signal ) {
# 15 == TERM, 14 == ALARM
if ( $exit_signal == 15 || $exit_signal == 14 ) { if ( $exit_signal == 15 || $exit_signal == 14 ) {
# TERM or ALRM
$out_str .= 'exited'; $out_str .= 'exited';
} else { } else {
$out_str .= 'crashed'; $out_str .= 'crashed';
@ -659,22 +679,26 @@ sub reaper {
$process->{delay} = $Config{ZM_MAX_RESTART_DELAY}; $process->{delay} = $Config{ZM_MAX_RESTART_DELAY};
} }
} }
Debug("Delay for $$process{command} is now $$process{delay}");
} else { } else {
delete $cmd_hash{$$process{command}}; delete $cmd_hash{$$process{command}};
} }
} } # end while waitpid
$SIG{CHLD} = \&reaper; $SIG{CHLD} = \&reaper;
$! = $saved_status; $! = $saved_status;
Debug("Leaving reaper");
} }
sub restartPending { sub restartPending {
# Restart any pending processes # Restart any pending processes, we list them first because cmd_hash may change in foreach
foreach my $process ( values( %cmd_hash ) ) { my @processes = values %cmd_hash;
foreach my $process ( @processes ) {
if ( $process->{pending} && $process->{pending} <= time() ) { if ( $process->{pending} && $process->{pending} <= time() ) {
dPrint(ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n"); dPrint(ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n");
start($process->{daemon}, @{$process->{args}}); start($process->{daemon}, @{$process->{args}});
} }
} }
dPrint(ZoneMinder::Logger::INFO, "done restartPending");
} }
sub shutdownAll { sub shutdownAll {
@ -683,9 +707,14 @@ sub shutdownAll {
next if ! $pid_hash{$pid}; next if ! $pid_hash{$pid};
send_stop(1, $pid_hash{$pid}); send_stop(1, $pid_hash{$pid});
} }
while ( %terminating_processes ) { my $count= KILL_DELAY;
while ( (keys %terminating_processes) and $count) {
check_for_processes_to_kill(); check_for_processes_to_kill();
sleep(1) if %terminating_processes; if ( %terminating_processes ) {
Debug("Still " . %terminating_processes . ' to die. count is: ' . $count . ' sleeping');
sleep(1);
$count --;
}
} }
dPrint(ZoneMinder::Logger::INFO, "Server shutdown at " dPrint(ZoneMinder::Logger::INFO, "Server shutdown at "
.strftime('%y/%m/%d %H:%M:%S', localtime()) .strftime('%y/%m/%d %H:%M:%S', localtime())

View File

@ -94,7 +94,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS})
; ;
logInit(); logInit($filter_id?(id=>'zmfilter_'.$filter_id):());
sub HupHandler { sub HupHandler {
Info("Received HUP, reloading"); Info("Received HUP, reloading");
&ZoneMinder::Logger::logHupHandler(); &ZoneMinder::Logger::logHupHandler();
@ -154,38 +154,38 @@ my $delay = $Config{ZM_FILTER_EXECUTE_INTERVAL};
my $event_id = 0; my $event_id = 0;
if ( ! EVENT_PATH ) { if ( ! EVENT_PATH ) {
Error( "No event path defined. Config was $Config{ZM_DIR_EVENTS}\n" ); Error("No event path defined. Config was $Config{ZM_DIR_EVENTS}\n");
die; die;
} }
# In future, should not be neccessary wrt StorageAreas # In future, should not be neccessary wrt StorageAreas
chdir( EVENT_PATH ); chdir( EVENT_PATH );
# SHould not be neccessary... but nice to get a local var. What if it fails? # Should not be neccessary... but nice to get a local var. What if it fails?
my $dbh = zmDbConnect(); my $dbh = zmDbConnect();
if ( $filter_name ) { if ( $filter_name ) {
Info( "Scanning for events using filter '$filter_name'\n" ); Info("Scanning for events using filter '$filter_name'\n");
} elsif ( $filter_id ) { } elsif ( $filter_id ) {
Info( "Scanning for events using filter id '$filter_id'\n" ); Info("Scanning for events using filter id '$filter_id'\n");
} else { } else {
Info( "Scanning for events using all filters\n" ); Info("Scanning for events using all filters\n");
} }
if ( ! ( $filter_name or $filter_id ) ) { if ( ! ( $filter_name or $filter_id ) ) {
Debug("Sleeping due to start delay: " . START_DELAY . ' seconds...' ); Debug("Sleeping due to start delay: " . START_DELAY . ' seconds...');
sleep( START_DELAY ); sleep(START_DELAY);
} }
my @filters; my @filters;
my $last_action = 0; 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\n" ); Debug("Reloading filters\n");
$last_action = $now; $last_action = $now;
@filters = getFilters( { Name=>$filter_name, Id=>$filter_id } ); @filters = getFilters({ Name=>$filter_name, Id=>$filter_id });
} }
foreach my $filter ( @filters ) { foreach my $filter ( @filters ) {
@ -195,16 +195,16 @@ while( ! $zm_terminate ) {
my ( $id ) = $$filter{Id} =~ /(\d+)/; my ( $id ) = $$filter{Id} =~ /(\d+)/;
Debug("Running concurrent filter process $proc --filter_id $$filter{Id} => $id for $$filter{Name}"); Debug("Running concurrent filter process $proc --filter_id $$filter{Id} => $id for $$filter{Name}");
system( qq`$proc --filter "$$filter{Name}" &` ); system(qq`$proc --filter "$$filter{Name}" &`);
} else { } else {
checkFilter( $filter ); checkFilter($filter);
} }
} }
last if $filter_name or $filter_id or $zm_terminate; last if $filter_name or $filter_id or $zm_terminate;
Debug( "Sleeping for $delay seconds\n" ); Debug("Sleeping for $delay seconds\n");
sleep( $delay ); sleep($delay);
} }
sub getFilters { sub getFilters {
@ -232,18 +232,18 @@ sub getFilters {
or UpdateDiskSpace = 1 or UpdateDiskSpace = 1
or AutoMove = 1 or AutoMove = 1
) ORDER BY Name'; ) ORDER BY Name';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached($sql)
or Fatal( "Unable to prepare '$sql': ".$dbh->errstr() ); or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( @sql_values ) my $res = $sth->execute(@sql_values)
or Fatal( "Unable to execute '$sql': ".$sth->errstr() ); or Fatal("Unable to execute '$sql': ".$dbh->errstr());
FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) { FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter ); my $filter = new ZoneMinder::Filter($$db_filter{Id}, $db_filter);
Debug( "Found filter '$db_filter->{Name}'\n" ); Debug("Found filter '$db_filter->{Name}'");
# The undef here is to make sure the Sql gets regenerated because the Filter object may be cached # The undef here is to make sure the Sql gets regenerated because the Filter object may be cached
my $filter_sql = $filter->Sql(undef); my $filter_sql = $filter->Sql(undef);
if ( ! $filter_sql ) { if ( ! $filter_sql ) {
Error( "Error parsing Sql. skipping filter '$db_filter->{Name}'\n" ); Error("Error parsing Sql. skipping filter '$db_filter->{Name}'");
next FILTER; next FILTER;
} }
push @filters, $filter; push @filters, $filter;
@ -252,7 +252,7 @@ FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
if ( ! @filters ) { if ( ! @filters ) {
Warning("No filter found for $sql with values(@sql_values)"); Warning("No filter found for $sql with values(@sql_values)");
} else { } else {
Debug( "Got " . @filters . " filters" ); Debug("Got " . @filters . " filters");
} }
return @filters; return @filters;
@ -283,56 +283,56 @@ sub checkFilter {
foreach my $event ( @Events ) { foreach my $event ( @Events ) {
last if $zm_terminate; last if $zm_terminate;
my $Event = new ZoneMinder::Event( $$event{Id}, $event ); my $Event = new ZoneMinder::Event($$event{Id}, $event);
Debug( "Checking event $event->{Id}" ); Debug("Checking event $event->{Id}");
my $delete_ok = !undef; my $delete_ok = !undef;
$dbh->ping(); $dbh->ping();
if ( $filter->{AutoArchive} ) { if ( $filter->{AutoArchive} ) {
Info( "Archiving event $event->{Id}" ); Info("Archiving event $event->{Id}");
# Do it individually to avoid locking up the table for new events # Do it individually to avoid locking up the table for new events
my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?'; my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Error( "Unable toexecute '$sql': ".$sth->errstr() ); or Error("Unable to execute '$sql': ".$dbh->errstr());
} }
if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) { if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) {
if ( !$event->{Videoed} ) { if ( !$event->{Videoed} ) {
$delete_ok = undef if ( !generateVideo( $filter, $event ) ); $delete_ok = undef if !generateVideo($filter, $event);
} }
} }
if ( $Config{ZM_OPT_EMAIL} && $filter->{AutoEmail} ) { if ( $Config{ZM_OPT_EMAIL} && $filter->{AutoEmail} ) {
if ( !$event->{Emailed} ) { if ( !$event->{Emailed} ) {
$delete_ok = undef if ( !sendEmail( $filter, $Event ) ); $delete_ok = undef if !sendEmail($filter, $Event);
} }
} }
if ( $Config{ZM_OPT_MESSAGE} && $filter->{AutoMessage} ) { if ( $Config{ZM_OPT_MESSAGE} && $filter->{AutoMessage} ) {
if ( !$event->{Messaged} ) { if ( !$event->{Messaged} ) {
$delete_ok = undef if ( !sendMessage( $filter, $event ) ); $delete_ok = undef if !sendMessage($filter, $event);
} }
} }
if ( $Config{ZM_OPT_UPLOAD} && $filter->{AutoUpload} ) { if ( $Config{ZM_OPT_UPLOAD} && $filter->{AutoUpload} ) {
if ( !$event->{Uploaded} ) { if ( !$event->{Uploaded} ) {
$delete_ok = undef if ( !uploadArchFile( $filter, $event ) ); $delete_ok = undef if !uploadArchFile($filter, $event);
} }
} }
if ( $filter->{AutoExecute} ) { if ( $filter->{AutoExecute} ) {
if ( !$event->{Executed} ) { if ( !$event->{Executed} ) {
$delete_ok = undef if ( !executeCommand( $filter, $event ) ); $delete_ok = undef if !executeCommand($filter, $event);
} }
} }
if ( $filter->{AutoDelete} ) { if ( $filter->{AutoDelete} ) {
if ( $delete_ok ) { if ( $delete_ok ) {
$Event->delete(); $Event->delete();
} else { } else {
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" ); Error("Unable toto delete event $event->{Id} as previous operations failed");
} }
} # end if AutoDelete } # end if AutoDelete
if ( $filter->{AutoMove} ) { if ( $filter->{AutoMove} ) {
my $NewStorage = new ZoneMinder::Storage( $filter->{AutoMoveTo} ); my $NewStorage = new ZoneMinder::Storage($filter->{AutoMoveTo});
$_ = $Event->MoveTo( $NewStorage ); $_ = $Event->MoveTo($NewStorage);
Error($_) if $_; Error($_) if $_;
} }
@ -364,7 +364,7 @@ sub generateVideo {
my $scale = $event->{DefaultScale}/100; my $scale = $event->{DefaultScale}/100;
my $format; my $format;
my @ffmpeg_formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} ); my @ffmpeg_formats = split(/\s+/, $Config{ZM_FFMPEG_FORMATS});
my $default_video_format; my $default_video_format;
my $default_phone_format; my $default_phone_format;
foreach my $ffmpeg_format( @ffmpeg_formats ) { foreach my $ffmpeg_format( @ffmpeg_formats ) {
@ -408,10 +408,10 @@ sub generateVideo {
return 0; return 0;
} else { } else {
my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?'; my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached($sql)
or Fatal( "Unable to prepare '$sql': ".$dbh->errstr()); or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute($event->{Id})
or Fatal("Unable toexecute '$sql': ".$sth->errstr()); or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
if ( wantarray() ) { if ( wantarray() ) {
return( $format, $output ); return( $format, $output );
} }
@ -463,12 +463,12 @@ sub uploadArchFile {
my $event = shift; my $event = shift;
if ( ! $Config{ZM_UPLOAD_HOST} ) { if ( ! $Config{ZM_UPLOAD_HOST} ) {
Error( 'Cannot upload archive as no upload host defined' ); Error('Cannot upload archive as no upload host defined');
return( 0 ); return( 0 );
} }
my $archFile = $event->{MonitorName}.'-'.$event->{Id}; my $archFile = $event->{MonitorName}.'-'.$event->{Id};
my $archImagePath = getEventPath( $event ) my $archImagePath = getEventPath($event)
.'/' .'/'
.( .(
( $Config{ZM_UPLOAD_ARCH_ANALYSE} ) ( $Config{ZM_UPLOAD_ARCH_ANALYSE} )
@ -485,14 +485,14 @@ sub uploadArchFile {
$archFile .= '.zip'; $archFile .= '.zip';
$archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile; $archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile;
my $zip = Archive::Zip->new(); my $zip = Archive::Zip->new();
Info( "Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n" ); Info("Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n");
my $status = &AZ_OK; my $status = &AZ_OK;
foreach my $imageFile ( @archImageFiles ) { foreach my $imageFile ( @archImageFiles ) {
Debug( "Adding $imageFile\n" ); Debug("Adding $imageFile\n");
my $member = $zip->addFile( $imageFile ); my $member = $zip->addFile($imageFile);
if ( !$member ) { if ( !$member ) {
Error( "Unable toto add image file $imageFile to zip archive $archLocPath" ); Error("Unable toto add image file $imageFile to zip archive $archLocPath");
$archError = 1; $archError = 1;
last; last;
} }
@ -505,10 +505,10 @@ sub uploadArchFile {
$status = $zip->writeToFileNamed( $archLocPath ); $status = $zip->writeToFileNamed( $archLocPath );
if ( $archError = ($status != &AZ_OK) ) { if ( $archError = ($status != &AZ_OK) ) {
Error( "Zip error: $status\n " ); Error("Zip error: $status");
} }
} else { } else {
Error( "Error adding images to zip archive $archLocPath, not writing" ); Error("Error adding images to zip archive $archLocPath, not writing");
} }
} elsif ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq 'tar' ) { } elsif ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq 'tar' ) {
if ( $Config{ZM_UPLOAD_ARCH_COMPRESS} ) { if ( $Config{ZM_UPLOAD_ARCH_COMPRESS} ) {
@ -517,7 +517,7 @@ sub uploadArchFile {
$archFile .= '.tar'; $archFile .= '.tar';
} }
$archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile; $archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile;
Info( "Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n" ); Info("Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n");
if ( $archError = !Archive::Tar->create_archive( if ( $archError = !Archive::Tar->create_archive(
$archLocPath, $archLocPath,
@ -525,7 +525,7 @@ sub uploadArchFile {
@archImageFiles @archImageFiles
) )
) { ) {
Error( 'Tar error: '.Archive::Tar->error()."\n " ); Error('Tar error: '.Archive::Tar->error());
} }
} }
@ -533,7 +533,7 @@ sub uploadArchFile {
return( 0 ); return( 0 );
} else { } else {
if ( $Config{ZM_UPLOAD_PROTOCOL} eq 'ftp' ) { if ( $Config{ZM_UPLOAD_PROTOCOL} eq 'ftp' ) {
Info( 'Uploading to '.$Config{ZM_UPLOAD_HOST}." using FTP\n" ); Info('Uploading to '.$Config{ZM_UPLOAD_HOST}." using FTP");
my $ftp = Net::FTP->new( my $ftp = Net::FTP->new(
$Config{ZM_UPLOAD_HOST}, $Config{ZM_UPLOAD_HOST},
Timeout=>$Config{ZM_UPLOAD_TIMEOUT}, Timeout=>$Config{ZM_UPLOAD_TIMEOUT},
@ -541,58 +541,56 @@ sub uploadArchFile {
Debug=>$Config{ZM_UPLOAD_DEBUG} Debug=>$Config{ZM_UPLOAD_DEBUG}
); );
if ( !$ftp ) { if ( !$ftp ) {
Error( "Unable tocreate FTP connection: $@" ); Error("Unable tocreate FTP connection: $@");
return( 0 ); return 0;
} }
$ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} ) $ftp->login($Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS})
or Error( "FTP - Unable tologin" ); or Error("FTP - Unable tologin");
$ftp->binary() $ftp->binary()
or Error( "FTP - Unable togo binary" ); or Error("FTP - Unable togo binary");
$ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} ) $ftp->cwd($Config{ZM_UPLOAD_REM_DIR})
or Error( "FTP - Unable tocwd" ) or Error("FTP - Unable tocwd")
if ( $Config{ZM_UPLOAD_REM_DIR} ); if ( $Config{ZM_UPLOAD_REM_DIR} );
$ftp->put( $archLocPath ) $ftp->put( $archLocPath )
or Error( "FTP - Unable toupload '$archLocPath'" ); or Error("FTP - Unable toupload '$archLocPath'");
$ftp->quit() $ftp->quit()
or Error( "FTP - Unable toquit" ); or Error("FTP - Unable toquit");
} else { } else {
my $host = $Config{ZM_UPLOAD_HOST}; my $host = $Config{ZM_UPLOAD_HOST};
$host .= ':'.$Config{ZM_UPLOAD_PORT} $host .= ':'.$Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT};
if $Config{ZM_UPLOAD_PORT}; Info('Uploading to '.$host." using SFTP\n");
Info( 'Uploading to '.$host." using SFTP\n" ); my %sftpOptions = (
my %sftpOptions = ( host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} ); host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER}
$sftpOptions{password} = $Config{ZM_UPLOAD_PASS} ($Config{ZM_UPLOAD_PASS} ? (password=>$Config{ZM_UPLOAD_PASS}) : ()),
if $Config{ZM_UPLOAD_PASS}; ($Config{ZM_UPLOAD_PORT} ? (port=>$Config{ZM_UPLOAD_PORT}) : ()),
$sftpOptions{port} = $Config{ZM_UPLOAD_PORT} ($Config{ZM_UPLOAD_TIMEOUT} ? (timeout=>$Config{ZM_UPLOAD_TIMEOUT}) : ()),
if $Config{ZM_UPLOAD_PORT}; );
$sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT}
if $Config{ZM_UPLOAD_TIMEOUT};
my @more_ssh_args; my @more_ssh_args;
push @more_ssh_args, '-o'=>'StrictHostKeyChecking=no' push @more_ssh_args, '-o'=>'StrictHostKeyChecking=no'
if ! $Config{ZM_UPLOAD_STRICT}; if ! $Config{ZM_UPLOAD_STRICT};
push @more_ssh_args, '-v' push @more_ssh_args, '-v'
if $Config{ZM_UPLOAD_DEBUG}; if $Config{ZM_UPLOAD_DEBUG};
$sftpOptions{more} = [@more_ssh_args]; $sftpOptions{more} = [@more_ssh_args];
my $sftp = Net::SFTP::Foreign->new( $Config{ZM_UPLOAD_HOST}, %sftpOptions ); my $sftp = Net::SFTP::Foreign->new($Config{ZM_UPLOAD_HOST}, %sftpOptions);
if ( $sftp->error ) { if ( $sftp->error ) {
Error( "Unable tocreate SFTP connection: ".$sftp->error ); Error("Unable tocreate SFTP connection: ".$sftp->error);
return( 0 ); return 0;
} }
$sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) $sftp->setcwd($Config{ZM_UPLOAD_REM_DIR})
or Error( "SFTP - Unable tosetcwd: ".$sftp->error ) or Error("SFTP - Unable to setcwd: ".$sftp->error)
if $Config{ZM_UPLOAD_REM_DIR}; if $Config{ZM_UPLOAD_REM_DIR};
$sftp->put( $archLocPath, $archFile ) $sftp->put($archLocPath, $archFile)
or Error( "SFTP - Unable toupload '$archLocPath': ".$sftp->error ); or Error("SFTP - Unable to upload '$archLocPath': ".$sftp->error);
} }
unlink( $archLocPath ); unlink($archLocPath);
my $sql = 'UPDATE Events SET Uploaded = 1 WHERE Id = ?'; my $sql = 'UPDATE Events SET Uploaded = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached($sql)
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute($event->{Id})
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
} }
return( 1 ); return 1;
} } # end sub uploadArchFile
sub substituteTags { sub substituteTags {
my $text = shift; my $text = shift;
@ -613,14 +611,13 @@ sub substituteTags {
my $max_alarm_frame; my $max_alarm_frame;
my $max_alarm_score = 0; my $max_alarm_score = 0;
if ( $need_images ) { if ( $need_images ) {
my $sql = "SELECT * FROM Frames my $sql = q`SELECT * FROM Frames
WHERE EventId = ? AND Type = 'Alarm' WHERE EventId = ? AND Type = 'Alarm'
ORDER BY FrameId" ORDER BY FrameId`;
; my $sth = $dbh->prepare_cached($sql)
my $sth = $dbh->prepare_cached( $sql ) or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute($Event->{Id})
my $res = $sth->execute( $Event->{Id} ) or Fatal( "Unable toexecute '$sql': ".$dbh->errstr());
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
my $rows = 0; my $rows = 0;
while( my $frame = $sth->fetchrow_hashref() ) { while( my $frame = $sth->fetchrow_hashref() ) {
if ( !$first_alarm_frame ) { if ( !$first_alarm_frame ) {
@ -646,8 +643,8 @@ sub substituteTags {
$text =~ s/%MEM%/$Monitor->{MonthEvents}/g; $text =~ s/%MEM%/$Monitor->{MonthEvents}/g;
$text =~ s/%MEA%/$Monitor->{ArchivedEvents}/g; $text =~ s/%MEA%/$Monitor->{ArchivedEvents}/g;
$text =~ s/%MP%/$url?view=watch&mid=$Event->{MonitorId}/g; $text =~ s/%MP%/$url?view=watch&mid=$Event->{MonitorId}/g;
$text =~ s/%MPS%/$url?view=watchfeed&mid=$Event->{MonitorId}&mode=stream/g; $text =~ s/%MPS%/$url?view=watch&mid=$Event->{MonitorId}&mode=stream/g;
$text =~ s/%MPI%/$url?view=watchfeed&mid=$Event->{MonitorId}&mode=still/g; $text =~ s/%MPI%/$url?view=watch&mid=$Event->{MonitorId}&mode=still/g;
$text =~ s/%EP%/$url?view=event&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; $text =~ s/%EP%/$url?view=event&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
$text =~ s/%EPS%/$url?view=event&mode=stream&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; $text =~ s/%EPS%/$url?view=event&mode=stream&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
$text =~ s/%EPI%/$url?view=event&mode=still&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; $text =~ s/%EPI%/$url?view=event&mode=still&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
@ -697,13 +694,13 @@ sub substituteTags {
if ( $attachments_ref && $text =~ s/%EIMA%//g ) { if ( $attachments_ref && $text =~ s/%EIMA%//g ) {
# Don't attach the same image twice # Don't attach the same image twice
if ( !@$attachments_ref if ( !@$attachments_ref
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId})
) { ) {
my $path = generateImage($Event, $max_alarm_frame, 'analyse'); my $path = generateImage($Event, $max_alarm_frame, 'analyse');
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 EIMA"); Warning('No image for EIMA');
} }
} }
} }
@ -737,7 +734,7 @@ sub sendEmail {
my $Event = shift; my $Event = shift;
if ( ! $Config{ZM_FROM_EMAIL} ) { if ( ! $Config{ZM_FROM_EMAIL} ) {
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 ( ! $Config{ZM_EMAIL_ADDRESS} ) {
@ -745,7 +742,7 @@ sub sendEmail {
return 0; return 0;
} }
Info("Creating notification email\n"); Info('Creating notification email');
my $subject = substituteTags($Config{ZM_EMAIL_SUBJECT}, $filter, $Event); my $subject = substituteTags($Config{ZM_EMAIL_SUBJECT}, $filter, $Event);
return 0 if !$subject; return 0 if !$subject;
@ -753,7 +750,7 @@ sub sendEmail {
my $body = substituteTags($Config{ZM_EMAIL_BODY}, $filter, $Event, \@attachments); my $body = substituteTags($Config{ZM_EMAIL_BODY}, $filter, $Event, \@attachments);
return 0 if !$body; return 0 if !$body;
Info("Sending notification email '$subject'\n"); Info("Sending notification email '$subject'");
eval { eval {
if ( $Config{ZM_NEW_MAIL_MODULES} ) { if ( $Config{ZM_NEW_MAIL_MODULES} ) {
@ -771,7 +768,7 @@ sub sendEmail {
); );
### Add the attachments ### Add the attachments
foreach my $attachment ( @attachments ) { foreach my $attachment ( @attachments ) {
Info( "Attaching '$attachment->{path}\n" ); Info( "Attaching '$attachment->{path}'" );
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
@ -783,20 +780,20 @@ sub sendEmail {
my $ssmtp_location = $Config{ZM_SSMTP_PATH}; my $ssmtp_location = $Config{ZM_SSMTP_PATH};
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
if ( logDebugging() ) { if ( logDebugging() ) {
Debug( "which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message\n" ); Debug("which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message");
} }
$ssmtp_location = qx('which ssmtp'); $ssmtp_location = qx('which ssmtp');
} }
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
Debug( "Unable tofind ssmtp, trying MIME::Lite->send" ); Debug('Unable tofind ssmtp, trying MIME::Lite->send');
MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send('smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60);
$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, $Config{ZM_EMAIL_ADDRESS});
} }
} else { } else {
MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send('smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60);
$mail->send(); $mail->send();
} }
} else { } else {
@ -809,29 +806,29 @@ sub sendEmail {
); );
foreach my $attachment ( @attachments ) { foreach my $attachment ( @attachments ) {
Info( "Attaching '$attachment->{path}\n" ); Info("Attaching '$attachment->{path}'");
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Encoding => 'base64' Encoding => 'base64'
); );
} }
$mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} ); $mail->smtpsend(Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL});
} }
}; };
if ( $@ ) { if ( $@ ) {
Error( "Unable tosend email: $@" ); Error("Unable tosend email: $@");
return( 0 ); return 0;
} else { } else {
Info( "Notification email sent\n" ); Info('Notification email sent');
} }
my $sql = 'update Events set Emailed = 1 where Id = ?'; my $sql = 'UPDATE Events SET Emailed = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached($sql) my $sth = $dbh->prepare_cached($sql)
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id}) my $res = $sth->execute($Event->{Id})
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
return( 1 ); return 1;
} }
sub sendMessage { sub sendMessage {
@ -839,28 +836,28 @@ sub sendMessage {
my $event = shift; my $event = shift;
if ( ! $Config{ZM_FROM_EMAIL} ) { if ( ! $Config{ZM_FROM_EMAIL} ) {
Error( "No 'from' email address defined, not sending message" ); Error('No from email address defined, not sending message');
return( 0 ); return 0;
} }
if ( ! $Config{ZM_MESSAGE_ADDRESS} ) { if ( ! $Config{ZM_MESSAGE_ADDRESS} ) {
Error( 'No message address defined, not sending message' ); Error('No message address defined, not sending message');
return( 0 ); return 0;
} }
Info( "Creating notification message\n" ); Info('Creating notification message');
my $subject = substituteTags( $Config{ZM_MESSAGE_SUBJECT}, $filter, $event ); my $subject = substituteTags($Config{ZM_MESSAGE_SUBJECT}, $filter, $event);
return( 0 ) if ( !$subject ); return 0 if !$subject;
my @attachments; my @attachments;
my $body = substituteTags( $Config{ZM_MESSAGE_BODY}, $filter, $event, \@attachments ); my $body = substituteTags($Config{ZM_MESSAGE_BODY}, $filter, $event, \@attachments);
return( 0 ) if ( !$body ); return 0 if !$body;
Info( "Sending notification message '$subject'\n" ); Info("Sending notification message '$subject'");
eval { eval {
if ( $Config{ZM_NEW_MAIL_MODULES} ) { if ( $Config{ZM_NEW_MAIL_MODULES} ) {
### 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_MESSAGE_ADDRESS}, To => $Config{ZM_MESSAGE_ADDRESS},
Subject => $subject, Subject => $subject,
@ -873,7 +870,7 @@ sub sendMessage {
); );
### Add the attachments ### Add the attachments
foreach my $attachment ( @attachments ) { foreach my $attachment ( @attachments ) {
Info( "Attaching '$attachment->{path}\n" ); Info("Attaching '$attachment->{path}");
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
@ -885,20 +882,20 @@ sub sendMessage {
my $ssmtp_location = $Config{ZM_SSMTP_PATH}; my $ssmtp_location = $Config{ZM_SSMTP_PATH};
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
if ( logDebugging() ) { if ( logDebugging() ) {
Debug( "which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message\n" ); Debug("which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message");
} }
$ssmtp_location = qx('which ssmtp'); $ssmtp_location = qx('which ssmtp');
} }
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
Debug( 'Unable tofind ssmtp, trying MIME::Lite->send' ); Debug('Unable tofind ssmtp, trying MIME::Lite->send');
MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send(smtp=>$Config{ZM_EMAIL_HOST}, Timeout=>60);
$mail->send(); $mail->send();
} else { } else {
### Send using SSMTP ### Send using SSMTP
$mail->send( 'sendmail', $ssmtp_location, $Config{ZM_MESSAGE_ADDRESS} ); $mail->send('sendmail', $ssmtp_location, $Config{ZM_MESSAGE_ADDRESS});
} }
} else { } else {
MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send(smtp=>$Config{ZM_EMAIL_HOST}, Timeout=>60);
$mail->send(); $mail->send();
} }
} else { } else {
@ -911,59 +908,60 @@ sub sendMessage {
); );
foreach my $attachment ( @attachments ) { foreach my $attachment ( @attachments ) {
Info( "Attaching '$attachment->{path}\n" ); Info("Attaching '$attachment->{path}'");
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Encoding => 'base64' Encoding => 'base64'
); );
} }
$mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, $mail->smtpsend(
Host => $Config{ZM_EMAIL_HOST},
MailFrom => $Config{ZM_FROM_EMAIL} MailFrom => $Config{ZM_FROM_EMAIL}
); );
} }
}; };
if ( $@ ) { if ( $@ ) {
Error( "Unable tosend email: $@" ); Error("Unable tosend email: $@");
return( 0 ); return 0;
} else { } else {
Info( "Notification message sent\n" ); Info('Notification message sent');
} }
my $sql = 'update Events set Messaged = 1 where Id = ?'; my $sql = 'UPDATE Events SET Messaged = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached($sql)
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute($event->{Id})
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
return( 1 ); return 1;
} }
sub executeCommand { sub executeCommand {
my $filter = shift; my $filter = shift;
my $event = shift; my $event = shift;
my $event_path = getEventPath( $event ); my $event_path = getEventPath($event);
my $command = $filter->{AutoExecuteCmd}; my $command = $filter->{AutoExecuteCmd};
$command .= " $event_path"; $command .= " $event_path";
$command = substituteTags( $command, $filter, $event ); $command = substituteTags($command, $filter, $event);
Info( "Executing '$command'\n" ); Info("Executing '$command'");
my $output = qx($command); my $output = qx($command);
my $status = $? >> 8; my $status = $? >> 8;
if ( $status || logDebugging() ) { if ( $status || logDebugging() ) {
chomp( $output ); chomp($output);
Debug( "Output: $output\n" ); Debug("Output: $output");
} }
if ( $status ) { if ( $status ) {
Error( "Command '$command' exited with status: $status\n" ); Error("Command '$command' exited with status: $status");
return( 0 ); return 0;
} else { } else {
my $sql = 'update Events set Executed = 1 where Id = ?'; my $sql = 'UPDATE Events SET Executed = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached($sql)
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); or Fatal("Unable to execute '$sql': ".$dbh->errstr());
} }
return( 1 ); return( 1 );
} }

View File

@ -211,7 +211,7 @@ if ( $command =~ /^(?:start|restart)$/ ) {
my $res = $sth->execute( @values ) my $res = $sth->execute( @values )
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() ) {
if ( $monitor->{Function} ne 'None' ) { if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) {
if ( $monitor->{Type} eq 'Local' ) { if ( $monitor->{Type} eq 'Local' ) {
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
} else { } else {

View File

@ -84,6 +84,7 @@ while( 1 ) {
while( my $monitor = $sth->fetchrow_hashref() ) { while( my $monitor = $sth->fetchrow_hashref() ) {
my $now = time(); my $now = time();
next if $monitor->{Function} eq 'None'; next if $monitor->{Function} eq 'None';
next if $monitor->{Type} eq 'WebSite';
my $restart = 0; my $restart = 0;
if ( zmMemVerify( $monitor ) ) { if ( zmMemVerify( $monitor ) ) {
# Check we have got an image recently # Check we have got an image recently

View File

@ -69,7 +69,9 @@ Event::Event(
untimedEvent = true; untimedEvent = true;
start_time = now; start_time = now;
} else if ( start_time.tv_sec > now.tv_sec ) { } else if ( start_time.tv_sec > now.tv_sec ) {
Error("StartTime in the future"); Error("StartTime in the future %d.%d > $d.%d",
start_time.tv_sec, start_time.tv_usec, now.tv_sec, now.tv_usec
);
start_time = now; start_time = now;
} }
@ -257,7 +259,7 @@ Event::~Event() {
"UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64, "UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64,
monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id );
db_mutex.lock(); db_mutex.lock();
while ( mysql_query(&dbconn, sql) ) { while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn));
db_mutex.unlock(); db_mutex.unlock();
sleep(1); sleep(1);
@ -422,16 +424,16 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
#else #else
static char escapedNotes[ZM_SQL_MED_BUFSIZ]; static char escapedNotes[ZM_SQL_MED_BUFSIZ];
mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() ); mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length());
snprintf( sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %" PRIu64, escapedNotes, id ); snprintf(sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %" PRIu64, escapedNotes, id);
db_mutex.lock(); db_mutex.lock();
if ( mysql_query( &dbconn, sql ) ) { if ( mysql_query(&dbconn, sql) ) {
Error( "Can't insert event: %s", mysql_error( &dbconn ) ); Error("Can't insert event: %s", mysql_error(&dbconn));
} }
db_mutex.unlock(); db_mutex.unlock();
#endif #endif
} } // end if update
} }
void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps ) { void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps ) {
@ -485,7 +487,7 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
frameCount++; frameCount++;
} } // end foreach frame
if ( frameCount ) { if ( frameCount ) {
Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames ); Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames );
@ -543,7 +545,10 @@ Debug(3, "Writing video");
Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type] ); Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type] );
static char sql[ZM_SQL_MED_BUFSIZ]; static char sql[ZM_SQL_MED_BUFSIZ];
snprintf(sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score); snprintf(sql, sizeof(sql),
"INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score )"
" VALUES ( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )",
id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score);
db_mutex.lock(); db_mutex.lock();
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't insert frame: %s", mysql_error(&dbconn)); Error("Can't insert frame: %s", mysql_error(&dbconn));
@ -556,7 +561,7 @@ Debug(3, "Writing video");
// We are writing a Bulk frame // We are writing a Bulk frame
if ( frame_type == BULK ) { if ( frame_type == BULK ) {
snprintf( sql, sizeof(sql), snprintf(sql, sizeof(sql),
"UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %" PRIu64, "UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %" PRIu64,
( delta_time.positive?"":"-" ), ( delta_time.positive?"":"-" ),
delta_time.sec, delta_time.fsec, delta_time.sec, delta_time.fsec,
@ -568,7 +573,7 @@ Debug(3, "Writing video");
id id
); );
db_mutex.lock(); db_mutex.lock();
while ( mysql_query(&dbconn, sql) ) { while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
Error("Can't update event: %s", mysql_error(&dbconn)); Error("Can't update event: %s", mysql_error(&dbconn));
db_mutex.unlock(); db_mutex.unlock();
sleep(1); sleep(1);

View File

@ -27,6 +27,7 @@
#include <getopt.h> #include <getopt.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <glob.h> #include <glob.h>
#include <cinttypes>
#include "zm.h" #include "zm.h"
#include "zm_db.h" #include "zm_db.h"

View File

@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <cinttypes>
#include "zm_ffmpeg.h" #include "zm_ffmpeg.h"
#include "zm_image.h" #include "zm_image.h"

View File

@ -18,6 +18,7 @@
// //
#include "zm.h" #include "zm.h"
#include "zm_signal.h"
#if HAVE_LIBAVFORMAT #if HAVE_LIBAVFORMAT
@ -180,7 +181,7 @@ int FfmpegCamera::Capture( Image &image ) {
// If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread. // If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread.
int frameComplete = false; int frameComplete = false;
while ( !frameComplete ) { while ( !frameComplete && !zm_terminate) {
int avResult = av_read_frame(mFormatContext, &packet); int avResult = av_read_frame(mFormatContext, &packet);
char errbuf[AV_ERROR_MAX_STRING_SIZE]; char errbuf[AV_ERROR_MAX_STRING_SIZE];
if ( avResult < 0 ) { if ( avResult < 0 ) {
@ -295,12 +296,12 @@ int FfmpegCamera::Capture( Image &image ) {
bytes += packet.size; bytes += packet.size;
zm_av_packet_unref( &packet ); zm_av_packet_unref( &packet );
} // end while ! frameComplete } // end while ! frameComplete
return 1; return frameComplete ? 1 : 0;
} // FfmpegCamera::Capture } // FfmpegCamera::Capture
int FfmpegCamera::PostCapture() { int FfmpegCamera::PostCapture() {
// Nothing to do here // Nothing to do here
return( 0 ); return 0;
} }
int FfmpegCamera::OpenFfmpeg() { int FfmpegCamera::OpenFfmpeg() {

View File

@ -543,7 +543,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) );
snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line );
if (mysql_query(&dbconn, sql)) { if ( mysql_query(&dbconn, sql) ) {
Level tempDatabaseLevel = mDatabaseLevel; Level tempDatabaseLevel = mDatabaseLevel;
databaseLevel(NOLOG); databaseLevel(NOLOG);
Error("Can't insert log entry: sql(%s) error(%s)", sql, mysql_error(&dbconn)); Error("Can't insert log entry: sql(%s) error(%s)", sql, mysql_error(&dbconn));

View File

@ -21,6 +21,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <glob.h> #include <glob.h>
#include <cinttypes>
#include "zm.h" #include "zm.h"
#include "zm_db.h" #include "zm_db.h"
@ -1245,9 +1246,9 @@ bool Monitor::Analyse() {
Info("%s: %d - Analysing at %.2f fps", name, image_count, new_fps); Info("%s: %d - Analysing at %.2f fps", name, image_count, new_fps);
if ( fps != new_fps ) { if ( fps != new_fps ) {
fps = new_fps; fps = new_fps;
db_mutex.lock();
static char sql[ZM_SQL_SML_BUFSIZ]; static char sql[ZM_SQL_SML_BUFSIZ];
snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, fps, fps); snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, fps, fps);
db_mutex.lock();
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));
} }

View File

@ -20,7 +20,7 @@
#define __STDC_FORMAT_MACROS 1 #define __STDC_FORMAT_MACROS 1
#include <inttypes.h> #include <cinttypes>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@ -19,6 +19,7 @@
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/msg.h> #include <sys/msg.h>
#include <cinttypes>
#include "zm.h" #include "zm.h"
#include "zm_db.h" #include "zm_db.h"

View File

@ -87,6 +87,7 @@ Options for use with monitors:
*/ */
#include <getopt.h> #include <getopt.h>
#include <cinttypes>
#include "zm.h" #include "zm.h"
#include "zm_db.h" #include "zm_db.h"

View File

@ -55,6 +55,22 @@ DocumentRoot /usr/share/zoneminder/www
qq` qq`
ErrorLog $$opts{error_log} ErrorLog $$opts{error_log}
Alias /zm/cache "/var/cache/zoneminder/cache"
Alias /cache "/var/cache/zoneminder/cache"
<Directory "/var/cache/zoneminder/cache">
Options -Indexes +FollowSymLinks
AllowOverride None
<IfModule mod_authz_core.c>
# Apache 2.4
Require all granted
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order deny,allow
Allow from all
</IfModule>
</Directory>
ScriptAlias /zm/cgi-bin/ /usr/lib/zoneminder/cgi-bin/ ScriptAlias /zm/cgi-bin/ /usr/lib/zoneminder/cgi-bin/
ScriptAlias /cgi-bin/ /usr/lib/zoneminder/cgi-bin/ ScriptAlias /cgi-bin/ /usr/lib/zoneminder/cgi-bin/
<Directory "/usr/lib/zoneminder/cgi-bin"> <Directory "/usr/lib/zoneminder/cgi-bin">
@ -67,7 +83,6 @@ ScriptAlias /cgi-bin/ /usr/lib/zoneminder/cgi-bin/
</Directory> </Directory>
Alias /zm /usr/share/zoneminder/www Alias /zm /usr/share/zoneminder/www
<Directory /usr/share/zoneminder/www> <Directory /usr/share/zoneminder/www>
php_flag register_globals off php_flag register_globals off
Options +Indexes +FollowSymLinks Options +Indexes +FollowSymLinks
@ -81,6 +96,32 @@ Alias /zm /usr/share/zoneminder/www
Allow from all Allow from all
</Directory> </Directory>
# For better visibility, the following directives have been migrated from the
# default .htaccess files included with the CakePHP project.
# Parameters not set here are inherited from the parent directive above.
<Directory "/usr/share/zoneminder/www/api">
RewriteEngine on
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app">
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app/webroot">
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
RewriteBase /zm/api
</Directory>
`; `;
if ( $$opts{protocol} eq 'https' ) { if ( $$opts{protocol} eq 'https' ) {
$template .= qq` $template .= qq`

View File

@ -105,10 +105,11 @@ commonprep () {
fi fi
# fix 32bit rpm builds # fix 32bit rpm builds
patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch # FIXME: breaks arm rpm builds
if [ $? -eq 0 ]; then #patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch
patch -p1 < utils/packpack/setarch.patch #if [ $? -eq 0 ]; then
fi # patch -p1 < utils/packpack/setarch.patch
#fi
# The rpm specfile requires we download each submodule as a tarball then manually move it into place # The rpm specfile requires we download each submodule as a tarball then manually move it into place
# Might as well do this for Debian as well, rather than git submodule init # Might as well do this for Debian as well, rather than git submodule init

View File

@ -1 +1 @@
1.31.42 1.31.44

View File

@ -6,14 +6,14 @@ class HostController extends AppController {
public $components = array('RequestHandler'); public $components = array('RequestHandler');
public function daemonCheck($daemon=false, $args=false) { public function daemonCheck($daemon=false, $args=false) {
$string = Configure::read('ZM_PATH_BIN')."/zmdc.pl check"; $string = Configure::read('ZM_PATH_BIN').'/zmdc.pl check';
if ( $daemon ) { if ( $daemon ) {
$string .= " $daemon"; $string .= " $daemon";
if ( $args ) if ( $args )
$string .= " $args"; $string .= " $args";
} }
$result = exec( $string ); $result = exec($string);
$result = preg_match( '/running/', $result ); $result = preg_match('/running/', $result);
$this->set(array( $this->set(array(
'result' => $result, 'result' => $result,
@ -31,10 +31,18 @@ class HostController extends AppController {
} }
function getAuthHash() { function getAuthHash() {
$this->set(array( if ( $zmOptAuth == '1' ) {
'auth_hash'=> generateAuthHash( ZM_AUTH_HASH_IPS ), require_once '../../../includes/auth.php';
'_serialize' => array('auth_hash') $this->set(array(
) ); 'auth_hash' => generateAuthHash(ZM_AUTH_HASH_IPS),
'_serialize' => array('auth_hash')
) );
} else {
$this->set(array(
'auth_hash' => '',
'_serialize' => array('auth_hash')
) );
}
} }
// If $mid is set, only return disk usage for that monitor // If $mid is set, only return disk usage for that monitor

@ -1 +1 @@
Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298 Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef

View File

@ -1,30 +1,30 @@
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: ::
:: Bake is a shell script for running CakePHP bake script :: Bake is a shell script for running CakePHP bake script
:: ::
:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) :: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) :: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
:: ::
:: Licensed under The MIT License :: Licensed under The MIT License
:: Redistributions of files must retain the above copyright notice. :: Redistributions of files must retain the above copyright notice.
:: ::
:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) :: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
:: @link https://cakephp.org CakePHP(tm) Project :: @link https://cakephp.org CakePHP(tm) Project
:: @package app.Console :: @package app.Console
:: @since CakePHP(tm) v 2.0 :: @since CakePHP(tm) v 2.0
:: ::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: In order for this script to work as intended, the cake\console\ folder must be in your PATH :: In order for this script to work as intended, the cake\console\ folder must be in your PATH
@echo. @echo.
@echo off @echo off
SET app=%0 SET app=%0
SET lib=%~dp0 SET lib=%~dp0
php -q "%lib%cake.php" -working "%CD% " %* php -q "%lib%cake.php" -working "%CD% " %*
echo. echo.
exit /B %ERRORLEVEL% exit /B %ERRORLEVEL%

View File

@ -1,28 +1,28 @@
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: ::
:: Bake is a shell script for running CakePHP bake script :: Bake is a shell script for running CakePHP bake script
:: ::
:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) :: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) :: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
:: ::
:: Licensed under The MIT License :: Licensed under The MIT License
:: Redistributions of files must retain the above copyright notice. :: Redistributions of files must retain the above copyright notice.
:: ::
:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) :: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
:: @link https://cakephp.org CakePHP(tm) Project :: @link https://cakephp.org CakePHP(tm) Project
:: @package Cake.Console :: @package Cake.Console
:: @since CakePHP(tm) v 1.2.0.5012 :: @since CakePHP(tm) v 1.2.0.5012
:: @license https://opensource.org/licenses/mit-license.php MIT License :: @license https://opensource.org/licenses/mit-license.php MIT License
:: ::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off @echo off
SET app=%0 SET app=%0
SET lib=%~dp0 SET lib=%~dp0
php -q "%lib%cake.php" -working "%CD% " %* php -q "%lib%cake.php" -working "%CD% " %*
echo. echo.
exit /B %ERRORLEVEL% exit /B %ERRORLEVEL%

View File

@ -451,6 +451,11 @@ class Event {
$values[] = $this->{'Id'}; $values[] = $this->{'Id'};
dbQuery( $sql, $values ); dbQuery( $sql, $values );
} }
public function link_to($text=null) {
if ( !$text )
$text = $this->{'Id'};
return '<a href="?view=event&amp;eid='. $this->{'Id'}.'">'.$text.'</a>';
}
} # end class } # end class

View File

@ -13,7 +13,7 @@ class Storage {
if ( ! $row ) { if ( ! $row ) {
Error("Unable to load Storage record for Id=" . $IdOrRow ); Error("Unable to load Storage record for Id=" . $IdOrRow );
} }
} elseif ( is_array( $IdOrRow ) ) { } else if ( is_array($IdOrRow) ) {
$row = $IdOrRow; $row = $IdOrRow;
} }
} }

View File

@ -299,10 +299,12 @@ if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) {
continue; continue;
} }
$Monitor = new Monitor( $mid ); $Monitor = new Monitor( $mid );
$Monitor->zmaControl('stop'); if ( $Monitor->Type() != 'WebSite' ) {
$Monitor->zmcControl('stop'); $Monitor->zmaControl('stop');
$Monitor->zmcControl('stop');
}
$Monitor->save( $_REQUEST['newMonitor'] ); $Monitor->save( $_REQUEST['newMonitor'] );
if ($Monitor->Function() != 'None' ) { if ($Monitor->Function() != 'None' && $Monitor->Type() != 'WebSite' ) {
$Monitor->zmcControl('start'); $Monitor->zmcControl('start');
if ( $Monitor->Enabled() ) { if ( $Monitor->Enabled() ) {
$Monitor->zmaControl('start'); $Monitor->zmaControl('start');
@ -330,7 +332,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
$monitor['Function'] = $newFunction; $monitor['Function'] = $newFunction;
$monitor['Enabled'] = $newEnabled; $monitor['Enabled'] = $newEnabled;
if ( daemonCheck() ) { if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
$restart = ($oldFunction == 'None') || ($newFunction == 'None') || ($newEnabled != $oldEnabled); $restart = ($oldFunction == 'None') || ($newFunction == 'None') || ($newEnabled != $oldEnabled);
zmaControl( $monitor, 'stop' ); zmaControl( $monitor, 'stop' );
zmcControl( $monitor, $restart?'restart':'' ); zmcControl( $monitor, $restart?'restart':'' );
@ -371,7 +373,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
} else { } else {
dbQuery( 'INSERT INTO Zones SET MonitorId=?, '.implode( ', ', $changes ), array( $mid ) ); dbQuery( 'INSERT INTO Zones SET MonitorId=?, '.implode( ', ', $changes ), array( $mid ) );
} }
if ( daemonCheck() ) { if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
if ( $_REQUEST['newZone']['Type'] == 'Privacy' ) { if ( $_REQUEST['newZone']['Type'] == 'Privacy' ) {
zmaControl( $monitor, 'stop' ); zmaControl( $monitor, 'stop' );
zmcControl( $monitor, 'restart' ); zmcControl( $monitor, 'restart' );
@ -399,7 +401,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
} }
} }
if($changes>0) { if($changes>0) {
if ( daemonCheck() ) { if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
zmaControl( $mid, 'restart' ); zmaControl( $mid, 'restart' );
} }
$refreshParent = true; $refreshParent = true;
@ -424,7 +426,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
$deletedZid = 1; $deletedZid = 1;
} }
if ( $deletedZid ) { if ( $deletedZid ) {
if ( daemonCheck() ) { if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
if ( $zone['Type'] == 'Privacy' ) { if ( $zone['Type'] == 'Privacy' ) {
zmaControl( $mid, 'stop' ); zmaControl( $mid, 'stop' );
zmcControl( $mid, 'restart' ); zmcControl( $mid, 'restart' );
@ -492,8 +494,10 @@ if ( canEdit( 'Monitors' ) ) {
if ( $mid ) { if ( $mid ) {
# If we change anything that changes the shared mem size, zma can complain. So let's stop first. # If we change anything that changes the shared mem size, zma can complain. So let's stop first.
zmaControl( $monitor, 'stop' ); if ( $monitor['Type'] != 'WebSite' ) {
zmcControl( $monitor, 'stop' ); zmaControl( $monitor, 'stop' );
zmcControl( $monitor, 'stop' );
}
dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) ); dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) );
// Groups will be added below // Groups will be added below
if ( isset($changes['Name']) or isset($changes['StorageId']) ) { if ( isset($changes['Name']) or isset($changes['StorageId']) ) {
@ -606,8 +610,10 @@ if ( canEdit( 'Monitors' ) ) {
$new_monitor = new Monitor($mid); $new_monitor = new Monitor($mid);
//fixDevices(); //fixDevices();
$new_monitor->zmcControl('start'); if ( $monitor['Type'] != 'WebSite' ) {
$new_monitor->zmaControl('start'); $new_monitor->zmcControl('start');
$new_monitor->zmaControl('start');
}
if ( $new_monitor->Controllable() ) { if ( $new_monitor->Controllable() ) {
require_once( 'control_functions.php' ); require_once( 'control_functions.php' );

View File

@ -18,7 +18,7 @@
// 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 userLogin( $username, $password='', $passwordHashed=false ) { function userLogin($username, $password='', $passwordHashed=false) {
global $user, $cookies; global $user, $cookies;
$sql = 'SELECT * FROM Users WHERE Enabled=1'; $sql = 'SELECT * FROM Users WHERE Enabled=1';
@ -29,10 +29,10 @@ function userLogin( $username, $password='', $passwordHashed=false ) {
} else { } else {
$sql .= ' AND Username=? AND Password=password(?)'; $sql .= ' AND Username=? AND Password=password(?)';
} }
$sql_values = array( $username, $password ); $sql_values = array($username, $password);
} else { } else {
$sql .= ' AND Username=?'; $sql .= ' AND Username=?';
$sql_values = array( $username ); $sql_values = array($username);
} }
session_start(); session_start();
$_SESSION['username'] = $username; $_SESSION['username'] = $username;
@ -41,8 +41,8 @@ function userLogin( $username, $password='', $passwordHashed=false ) {
$_SESSION['password'] = $password; $_SESSION['password'] = $password;
} }
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking $_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
if ( $dbUser = dbFetchOne( $sql, NULL, $sql_values ) ) { if ( $dbUser = dbFetchOne($sql, NULL, $sql_values) ) {
Info( "Login successful for user \"$username\"" ); Info("Login successful for user \"$username\"");
$_SESSION['user'] = $user = $dbUser; $_SESSION['user'] = $user = $dbUser;
unset($_SESSION['loginFailed']); unset($_SESSION['loginFailed']);
if ( ZM_AUTH_TYPE == 'builtin' ) { if ( ZM_AUTH_TYPE == 'builtin' ) {
@ -50,30 +50,30 @@ function userLogin( $username, $password='', $passwordHashed=false ) {
} }
session_regenerate_id(); session_regenerate_id();
} else { } else {
Warning( "Login denied for user \"$username\"" ); Warning("Login denied for user \"$username\"");
$_SESSION['loginFailed'] = true; $_SESSION['loginFailed'] = true;
unset( $user ); unset($user);
} }
session_write_close(); session_write_close();
} } # end function userLogin
function userLogout() { function userLogout() {
global $user; global $user;
Info( 'User "'.$user['Username'].'" logged out' ); Info('User "'.$user['Username'].'" logged out');
session_start(); session_start();
unset( $_SESSION['user'] ); unset($_SESSION['user']);
unset( $user ); unset($user);
session_destroy(); session_destroy();
} }
function getAuthUser( $auth ) { function getAuthUser($auth) {
if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' && !empty($auth) ) { if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' && !empty($auth) ) {
$remoteAddr = ''; $remoteAddr = '';
if ( ZM_AUTH_HASH_IPS ) { if ( ZM_AUTH_HASH_IPS ) {
$remoteAddr = $_SERVER['REMOTE_ADDR']; $remoteAddr = $_SERVER['REMOTE_ADDR'];
if ( !$remoteAddr ) { if ( !$remoteAddr ) {
Error( "Can't determine remote address for authentication, using empty string" ); Error("Can't determine remote address for authentication, using empty string");
$remoteAddr = ''; $remoteAddr = '';
} }
} }
@ -103,7 +103,7 @@ function getAuthUser( $auth ) {
return false; return false;
} // end getAuthUser($auth) } // end getAuthUser($auth)
function generateAuthHash( $useRemoteAddr ) { function generateAuthHash($useRemoteAddr) {
if ( ZM_OPT_USE_AUTH and ZM_AUTH_RELAY == 'hashed' and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) { if ( ZM_OPT_USE_AUTH and ZM_AUTH_RELAY == 'hashed' and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) {
# regenerate a hash at half the liftetime of a hash, an hour is 3600 so half is 1800 # regenerate a hash at half the liftetime of a hash, an hour is 3600 so half is 1800
$time = time(); $time = time();
@ -119,7 +119,7 @@ function generateAuthHash( $useRemoteAddr ) {
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$local_time[2].$local_time[3].$local_time[4].$local_time[5]; $authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
} }
#Logger::Debug("Generated using hour:".$local_time[2] . ' mday:' . $local_time[3] . ' month:'.$local_time[4] . ' year: ' . $local_time[5] ); #Logger::Debug("Generated using hour:".$local_time[2] . ' mday:' . $local_time[3] . ' month:'.$local_time[4] . ' year: ' . $local_time[5] );
$auth = md5( $authKey ); $auth = md5($authKey);
session_start(); session_start();
$_SESSION['AuthHash'] = $auth; $_SESSION['AuthHash'] = $auth;
$_SESSION['AuthHashGeneratedAt'] = $time; $_SESSION['AuthHashGeneratedAt'] = $time;
@ -135,22 +135,22 @@ function generateAuthHash( $useRemoteAddr ) {
return $auth; return $auth;
} }
function visibleMonitor( $mid ) { function visibleMonitor($mid) {
global $user; global $user;
return( empty($user['MonitorIds']) || in_array( $mid, explode( ',', $user['MonitorIds'] ) ) ); return ( empty($user['MonitorIds']) || in_array($mid, explode(',', $user['MonitorIds'])) );
} }
function canView( $area, $mid=false ) { function canView($area, $mid=false) {
global $user; global $user;
return( ($user[$area] == 'View' || $user[$area] == 'Edit') && ( !$mid || visibleMonitor( $mid ) ) ); return ( ($user[$area] == 'View' || $user[$area] == 'Edit') && ( !$mid || visibleMonitor($mid) ) );
} }
function canEdit( $area, $mid=false ) { function canEdit($area, $mid=false) {
global $user; global $user;
return( $user[$area] == 'Edit' && ( !$mid || visibleMonitor( $mid ) ) ); return ( $user[$area] == 'Edit' && ( !$mid || visibleMonitor($mid) ));
} }
?> ?>

View File

@ -133,7 +133,7 @@ function dbQuery( $sql, $params=NULL ) {
} }
} else { } else {
if ( defined('ZM_DB_DEBUG') ) { if ( defined('ZM_DB_DEBUG') ) {
Logger::Debug("SQL: $sql values:" . $params?implode(',',$params):'' ); Logger::Debug("SQL: $sql values:" . ($params?implode(',',$params):'') );
} }
$result = $dbConn->query($sql); $result = $dbConn->query($sql);
} }

View File

@ -280,6 +280,27 @@ function getImageStill( $id, $src, $width, $height, $title='' ) {
return '<img id="'.$id.'" src="'.$src.'" alt="'.$title.'"'.(validInt($width)?' width="'.$width.'"':'').(validInt($height)?' height="'.$height.'"':'').'/>'; return '<img id="'.$id.'" src="'.$src.'" alt="'.$title.'"'.(validInt($width)?' width="'.$width.'"':'').(validInt($height)?' height="'.$height.'"':'').'/>';
} }
function getWebSiteUrl( $id, $src, $width, $height, $title='' ) {
# Prevent unsightly warnings when php cannot verify the ssl certificate
stream_context_set_default( [
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
],
]);
# The End User can turn off the following warning under Options -> Web
if ( ZM_WEB_XFRAME_WARN ) {
$header = get_headers($src, 1);
# If the target website has set X-Frame-Options, check it for "sameorigin" and warn the end user
if (array_key_exists('X-Frame-Options', $header)) {
$header = $header['X-Frame-Options'];
if ( stripos($header, 'sameorigin') === 0 )
Warning("Web site $src has X-Frame-Options set to sameorigin. An X-Frame-Options browser plugin is required to display this site.");
}
}
return '<object id="'.$id.'" data="'.$src.'" alt="'.$title.'" width="'.$width.'" height="'.$height.'"></object>';
}
function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) { function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) {
?> ?>
<form name="ctrlForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>" target="<?php echo $target ?>"> <form name="ctrlForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>" target="<?php echo $target ?>">
@ -495,11 +516,11 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) {
switch( $types[$key] ) { switch( $types[$key] ) {
case 'set' : case 'set' :
{ {
if ( is_array( $newValues[$key] ) ) { if ( is_array($newValues[$key]) ) {
if ( join(',',$newValues[$key]) != $values[$key] ) { if ( (!isset($values[$key])) or ( join(',',$newValues[$key]) != $values[$key] ) ) {
$changes[$key] = "`$key` = ".dbEscape(join(',',$newValues[$key])); $changes[$key] = "`$key` = ".dbEscape(join(',',$newValues[$key]));
} }
} elseif ( $values[$key] ) { } else if ( (!isset($values[$key])) or $values[$key] ) {
$changes[$key] = "`$key` = ''"; $changes[$key] = "`$key` = ''";
} }
break; break;
@ -548,7 +569,7 @@ function getFormChanges( $values, $newValues, $types=false, $columns=false ) {
} }
case 'raw' : case 'raw' :
{ {
if ( $values[$key] != $value ) { if ( (!isset($values[$key])) or ($values[$key] != $value) ) {
$changes[$key] = $key . ' = '.dbEscape($value); $changes[$key] = $key . ' = '.dbEscape($value);
} }
break; break;
@ -1004,8 +1025,15 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
$filter['sql'] .= 'M.'.preg_replace('/^Monitor/', '', $terms[$i]['attr']); $filter['sql'] .= 'M.'.preg_replace('/^Monitor/', '', $terms[$i]['attr']);
break; break;
case 'ServerId': case 'ServerId':
case 'MonitorServerId':
$filter['sql'] .= 'M.ServerId'; $filter['sql'] .= 'M.ServerId';
break; break;
case 'StorageServerId':
$filter['sql'] .= 'S.ServerId';
break;
case 'FilterServerId':
$filter['sql'] .= ZM_SERVER_ID;
break;
# Unspecified start or end, so assume start, this is to support legacy filters # Unspecified start or end, so assume start, this is to support legacy filters
case 'DateTime': case 'DateTime':
$filter['sql'] .= 'E.StartTime'; $filter['sql'] .= 'E.StartTime';
@ -1100,6 +1128,9 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
case 'Notes': case 'Notes':
$value = dbEscape($value); $value = dbEscape($value);
break; break;
case 'MonitorServerId':
case 'FilterServerId':
case 'StorageServerId':
case 'ServerId': case 'ServerId':
if ( $value == 'ZM_SERVER_ID' ) { if ( $value == 'ZM_SERVER_ID' ) {
$value = ZM_SERVER_ID; $value = ZM_SERVER_ID;
@ -2128,8 +2159,14 @@ function getStreamHTML( $monitor, $options = array() ) {
$options['buffer'] = $monitor->StreamReplayBuffer(); $options['buffer'] = $monitor->StreamReplayBuffer();
//Warning("width: " . $options['width'] . ' height: ' . $options['height']. ' scale: ' . $options['scale'] ); //Warning("width: " . $options['width'] . ' height: ' . $options['height']. ' scale: ' . $options['scale'] );
if ( $monitor->Type() == "WebSite" ) {
return getWebSiteUrl( 'liveStream'.$monitor->Id(), $monitor->Path(),
( isset($options['width']) ? $options['width'] : NULL ),
( isset($options['height']) ? $options['height'] : NULL ),
$monitor->Name()
);
//FIXME, the width and height of the image need to be scaled. //FIXME, the width and height of the image need to be scaled.
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { } else if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
$streamSrc = $monitor->getStreamSrc( array( $streamSrc = $monitor->getStreamSrc( array(
'mode'=>'mpeg', 'mode'=>'mpeg',
'scale'=>(isset($options['scale'])?$options['scale']:100), 'scale'=>(isset($options['scale'])?$options['scale']:100),

View File

@ -130,7 +130,9 @@ $SLANG = array(
'AttrMonitorId' => 'Monitor Id', 'AttrMonitorId' => 'Monitor Id',
'AttrMonitorName' => 'Monitor Name', 'AttrMonitorName' => 'Monitor Name',
'AttrStorageArea' => 'Storage Area', 'AttrStorageArea' => 'Storage Area',
'AttrServer' => 'Server', 'AttrFilterServer' => 'Server Filter is Running On',
'AttrMonitorServer' => 'Server Monitor is Running On',
'AttrStorageServer' => 'Server Hosting Storage',
'AttrStateId' => 'Run State', 'AttrStateId' => 'Run State',
'AttrName' => 'Name', 'AttrName' => 'Name',
'AttrNotes' => 'Notes', 'AttrNotes' => 'Notes',
@ -174,8 +176,10 @@ $SLANG = array(
'BadSectionLength' => 'Section length must be an integer of 30 or more', 'BadSectionLength' => 'Section length must be an integer of 30 or more',
'BadSignalCheckColour' => 'Signal check colour must be a valid RGB colour string', 'BadSignalCheckColour' => 'Signal check colour must be a valid RGB colour string',
'BadStreamReplayBuffer' => 'Stream replay buffer must be an integer of zero or more', 'BadStreamReplayBuffer' => 'Stream replay buffer must be an integer of zero or more',
'BadSourceType' => 'Source Type \"Web Site\" requires the Function to be set to \"Monitor\"',
'BadWarmupCount' => 'Warmup frames must be an integer of zero or more', 'BadWarmupCount' => 'Warmup frames must be an integer of zero or more',
'BadWebColour' => 'Web colour must be a valid web colour string', 'BadWebColour' => 'Web colour must be a valid web colour string',
'BadWebSitePath' => 'Please enter a complete website url, including the http:// or https:// prefix.',
'BadWidth' => 'Width must be set to a valid value', 'BadWidth' => 'Width must be set to a valid value',
'Bandwidth' => 'Bandwidth', 'Bandwidth' => 'Bandwidth',
'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing
@ -768,6 +772,7 @@ $SLANG = array(
'Watch' => 'Watch', 'Watch' => 'Watch',
'WebColour' => 'Web Colour', 'WebColour' => 'Web Colour',
'Web' => 'Web', 'Web' => 'Web',
'WebSiteUrl' => 'Website URL',
'Week' => 'Week', 'Week' => 'Week',
'WhiteBalance' => 'White Balance', 'WhiteBalance' => 'White Balance',
'White' => 'White', 'White' => 'White',

View File

@ -244,7 +244,7 @@ function getNavBarHTML($reload = null) {
if ( logToDatabase() > Logger::NOLOG ) { if ( logToDatabase() > Logger::NOLOG ) {
if ( ! ZM_RUN_AUDIT ) { if ( ! ZM_RUN_AUDIT ) {
# zmaudit can clean the logs, but if we aren't running it, then we should clecan them regularly # zmaudit can clean the logs, but if we aren't running it, then we should clecan them regularly
dbQuery('DELETE FROM Logs WHERE TimeKey < unix_timestamp( NOW() - interval '.ZM_LOG_DATABASE_LIMIT.')'); dbQuery('DELETE FROM Logs WHERE TimeKey < unix_timestamp( NOW() - interval '.ZM_LOG_DATABASE_LIMIT.') LIMIT 100');
} }
echo makePopupLink( '?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>' ); echo makePopupLink( '?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>' );
} }

View File

@ -111,6 +111,9 @@ $status_counts = array();
for ( $i = 0; $i < count($displayMonitors); $i++ ) { for ( $i = 0; $i < count($displayMonitors); $i++ ) {
$monitor = &$displayMonitors[$i]; $monitor = &$displayMonitors[$i];
if ( ! $monitor['Status'] ) { if ( ! $monitor['Status'] ) {
if ( $monitor['Type'] == 'WebSite' )
$monitor['Status'] = 'Running';
else
$monitor['Status'] = 'NotRunning'; $monitor['Status'] = 'NotRunning';
} }
if ( !isset($status_counts[$monitor['Status']]) ) if ( !isset($status_counts[$monitor['Status']]) )
@ -238,7 +241,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
?> ?>
<tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>" title="<?php echo $monitor['Id'] ?>"> <tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>" title="<?php echo $monitor['Id'] ?>">
<?php <?php
if ( (!$monitor['Status']) or ($monitor['Status'] == 'NotRunning') ) { if ( (!$monitor['Status'] || $monitor['Status'] == 'NotRunning') && $monitor['Type']!='WebSite' ) {
$source_class = 'errorText'; $source_class = 'errorText';
} else { } else {
if ( $monitor['CaptureFPS'] == '0.00' ) { if ( $monitor['CaptureFPS'] == '0.00' ) {
@ -256,7 +259,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
if ( !$monitor['Enabled'] ) if ( !$monitor['Enabled'] )
$fclass .= ' disabledText'; $fclass .= ' disabledText';
$scale = max( reScale( SCALE_BASE, $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); $scale = max( reScale( SCALE_BASE, $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
$stream_available = canView('Stream') && $monitor['CaptureFPS'] && $monitor['Function'] != 'None'; $stream_available = canView('Stream') and $monitor['Type']=='WebSite' or ($monitor['CaptureFPS'] && $monitor['Function'] != 'None');
$dot_class=$source_class; $dot_class=$source_class;
if ( $fclass != 'infoText' ) $dot_class=$fclass; if ( $fclass != 'infoText' ) $dot_class=$fclass;
@ -313,7 +316,7 @@ if ( $fclass != 'infoText' ) $dot_class=$fclass;
} }
} elseif ( $monitor['Type'] == 'File' || $monitor['Type'] == 'cURL' ) { } elseif ( $monitor['Type'] == 'File' || $monitor['Type'] == 'cURL' ) {
$source = preg_replace( '/^.*\//', '', $monitor['Path'] ); $source = preg_replace( '/^.*\//', '', $monitor['Path'] );
} elseif ( $monitor['Type'] == 'Ffmpeg' || $monitor['Type'] == 'Libvlc' ) { } elseif ( $monitor['Type'] == 'Ffmpeg' || $monitor['Type'] == 'Libvlc' || $monitor['Type'] == 'WebSite' ) {
$url_parts = parse_url( $monitor['Path'] ); $url_parts = parse_url( $monitor['Path'] );
unset($url_parts['user']); unset($url_parts['user']);
unset($url_parts['pass']); unset($url_parts['pass']);

View File

@ -101,7 +101,10 @@ $attrTypes = array(
'DiskSpace' => translate('AttrDiskSpace'), 'DiskSpace' => translate('AttrDiskSpace'),
'SystemLoad' => translate('AttrSystemLoad'), 'SystemLoad' => translate('AttrSystemLoad'),
'StorageId' => translate('AttrStorageArea'), 'StorageId' => translate('AttrStorageArea'),
'ServerId' => translate('AttrServer'), 'ServerId' => translate('AttrMonitorServer'),
'FilterServerId' => translate('AttrFilterServer'),
'MonitorServerId' => translate('AttrMonitorServer'),
'StorageServerId' => translate('AttrStorageServer'),
'StateId' => translate('AttrStateId'), 'StateId' => translate('AttrStateId'),
); );
@ -268,7 +271,7 @@ for ( $i=0; $i < count($terms); $i++ ) {
<td><?php echo htmlSelect( "filter[Query][terms][$i][op]", $opTypes, $term['op'] ); ?></td> <td><?php echo htmlSelect( "filter[Query][terms][$i][op]", $opTypes, $term['op'] ); ?></td>
<td><?php echo htmlSelect( "filter[Query][terms][$i][val]", $monitors, $term['val'] ); ?></td> <td><?php echo htmlSelect( "filter[Query][terms][$i][val]", $monitors, $term['val'] ); ?></td>
<?php <?php
} elseif ( $term['attr'] == 'ServerId' ) { } elseif ( $term['attr'] == 'ServerId' || $term['attr'] == 'MonitorServerId' || $term['attr'] == 'StorageServerId' || $term['attr'] == 'FilterServerId' ) {
?> ?>
<td><?php echo htmlSelect( "filter[Query][terms][$i][op]", $opTypes, $term['op'] ); ?></td> <td><?php echo htmlSelect( "filter[Query][terms][$i][op]", $opTypes, $term['op'] ); ?></td>
<td><?php echo htmlSelect( "filter[Query][terms][$i][val]", $servers, $term['val'] ); ?></td> <td><?php echo htmlSelect( "filter[Query][terms][$i][val]", $servers, $term['val'] ); ?></td>

View File

@ -142,7 +142,9 @@ function parseRows (rows) {
inputTds.eq(6).find(':input[value="-"]').prop('disabled', false); inputTds.eq(6).find(':input[value="-"]').prop('disabled', false);
} }
if (inputTds.eq(2).children().val() == "Archived") { //Archived types var attr = inputTds.eq(2).children().val();
if ( attr == "Archived") { //Archived types
inputTds.eq(3).html('equal to<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="=">');
let archiveSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); let archiveSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (let i = 0; i < archiveTypes.length; i++) { for (let i = 0; i < archiveTypes.length; i++) {
@ -151,7 +153,7 @@ function parseRows (rows) {
let archiveVal = inputTds.eq(4).children().val(); let 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 (inputTds.eq(2).children().val().indexOf('Weekday') >= 0) { //Weekday selection } else if ( attr.indexOf('Weekday') >= 0 ) { //Weekday selection
let weekdaySelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); let weekdaySelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (let i = 0; i < weekdays.length; i++) { for (let i = 0; i < weekdays.length; i++) {
weekdaySelect.append('<option value="' + i + '">' + weekdays[i] + '</option>'); weekdaySelect.append('<option value="' + i + '">' + weekdays[i] + '</option>');
@ -159,7 +161,7 @@ function parseRows (rows) {
let weekdayVal = inputTds.eq(4).children().val(); let weekdayVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(weekdaySelect).children().val(weekdayVal).chosen({width: "101%"}); inputTds.eq(4).html(weekdaySelect).children().val(weekdayVal).chosen({width: "101%"});
} else if (inputTds.eq(2).children().val() == 'StateId') { //Run state } else if ( attr == 'StateId' ) { //Run state
let stateSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); let stateSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (let key in states) { for (let key in states) {
stateSelect.append('<option value="' + key + '">' + states[key] + '</option>'); stateSelect.append('<option value="' + key + '">' + states[key] + '</option>');
@ -167,8 +169,7 @@ function parseRows (rows) {
let stateVal = inputTds.eq(4).children().val(); let stateVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(stateSelect).children().val(stateVal).chosen({width: "101%"}); inputTds.eq(4).html(stateSelect).children().val(stateVal).chosen({width: "101%"});
} else if ( attr == 'ServerId' || attr == 'MonitorServerId' || attr == 'StorageServerId' || attr == 'FilterServerId' ) { //Select Server
} else if (inputTds.eq(2).children().val() == 'ServerId') { //Select Server
let serverSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); let serverSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (let key in servers) { for (let key in servers) {
serverSelect.append('<option value="' + key + '">' + servers[key] + '</option>'); serverSelect.append('<option value="' + key + '">' + servers[key] + '</option>');
@ -176,21 +177,15 @@ function parseRows (rows) {
let serverVal = inputTds.eq(4).children().val(); let serverVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(serverSelect).children().val(serverVal).chosen({width: "101%"}); inputTds.eq(4).html(serverSelect).children().val(serverVal).chosen({width: "101%"});
} else if (inputTds.eq(2).children().val() == 'StorageId') { //Choose by storagearea } else if ( attr == 'StorageId' ) { //Choose by storagearea
let storageSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); let storageSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for ( key in storageareas ) { for ( key in storageareas ) {
console.log(key + ' ' + storageareas[key]);
storageSelect.append('<option value="' + key + '">' + storageareas[key] + '</option>'); storageSelect.append('<option value="' + key + '">' + storageareas[key] + '</option>');
}
/*
for (let i=0; i < storageareas.length; i++) {
storageSelect.append('<option value="' + i + '">' + storageareas[i] + '</option>');
} }
*/
let storageVal = inputTds.eq(4).children().val(); let storageVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"}); inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"});
} else if (inputTds.eq(2).children().val() == 'MonitorName') { //Monitor names } else if ( attr == 'MonitorName' ) { //Monitor names
let monitorSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); let monitorSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
for (let key in monitors) { for (let key in monitors) {
monitorSelect.append('<option value="' + key + '">' + monitors[key] + '</option>'); monitorSelect.append('<option value="' + key + '">' + monitors[key] + '</option>');
@ -208,15 +203,15 @@ console.log(key + ' ' + storageareas[key]);
let textVal = inputTds.eq(4).children().val(); let textVal = inputTds.eq(4).children().val();
inputTds.eq(4).html(textInput).children().val(textVal); inputTds.eq(4).html(textInput).children().val(textVal);
} }
if (inputTds.eq(2).children().val().endsWith('DateTime')) { //Start/End DateTime if ( attr.endsWith('DateTime') ) { //Start/End DateTime
inputTds.eq(4).children().datetimepicker({timeFormat: "HH:mm:ss", dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false}); inputTds.eq(4).children().datetimepicker({timeFormat: "HH:mm:ss", dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false});
} else if (inputTds.eq(2).children().val().endsWith('Date')) { //Start/End Date } else if ( attr.endsWith('Date') ) { //Start/End Date
inputTds.eq(4).children().datepicker({dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false}); inputTds.eq(4).children().datepicker({dateFormat: "yy-mm-dd", maxDate: 0, constrainInput: false});
} else if (inputTds.eq(2).children().val().endsWith('Time')) { //Start/End Time } else if ( attr.endsWith('Time')) { //Start/End Time
inputTds.eq(4).children().timepicker({timeFormat: "HH:mm:ss", constrainInput: false}); inputTds.eq(4).children().timepicker({timeFormat: "HH:mm:ss", constrainInput: false});
} }
let attr = inputTds.find("[name$='attr\\]']") // Set attr list id and name attr = inputTds.find("[name$='attr\\]']") // Set attr list id and name
let term = attr.attr('name').split(/[[\]]{1,2}/); let term = attr.attr('name').split(/[[\]]{1,2}/);
term.length--; term.length--;
term.shift(); term.shift();

View File

@ -54,14 +54,6 @@ function validateForm( form ) {
else if ( monitorNames[form.elements['newMonitor[Name]'].value] ) else if ( monitorNames[form.elements['newMonitor[Name]'].value] )
errors[errors.length] = "<?php echo translate('DuplicateMonitorName') ?>"; errors[errors.length] = "<?php echo translate('DuplicateMonitorName') ?>";
if ( form.elements['newMonitor[AnalysisFPSLimit]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPSLimit]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadAnalysisFPS') ?>";
if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadMaxFPS') ?>";
if ( form.elements['newMonitor[AlarmMaxFPS]'].value && !(parseFloat(form.elements['newMonitor[AlarmMaxFPS]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadAlarmMaxFPS') ?>";
if ( !form.elements['newMonitor[RefBlendPerc]'].value || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) > 100 ) || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) < 0 ) )
errors[errors.length] = "<?php echo translate('BadRefBlendPerc') ?>";
if ( form.elements['newMonitor[Type]'].value == 'Local' ) { if ( form.elements['newMonitor[Type]'].value == 'Local' ) {
if ( !form.elements['newMonitor[Palette]'].value || !form.elements['newMonitor[Palette]'].value.match( /^\d+$/ ) ) if ( !form.elements['newMonitor[Palette]'].value || !form.elements['newMonitor[Palette]'].value.match( /^\d+$/ ) )
errors[errors.length] = "<?php echo translate('BadPalette') ?>"; errors[errors.length] = "<?php echo translate('BadPalette') ?>";
@ -81,44 +73,63 @@ function validateForm( form ) {
} else if ( form.elements['newMonitor[Type]'].value == 'File' ) { } else if ( form.elements['newMonitor[Type]'].value == 'File' ) {
if ( !form.elements['newMonitor[Path]'].value ) if ( !form.elements['newMonitor[Path]'].value )
errors[errors.length] = "<?php echo translate('BadPath') ?>"; errors[errors.length] = "<?php echo translate('BadPath') ?>";
} else if ( form.elements['newMonitor[Type]'].value == 'WebSite' ) {
if ( form.elements['newMonitor[Function]'].value != 'Monitor' && form.elements['newMonitor[Function]'].value != 'None')
errors[errors.length] = "<?php echo translate('BadSourceType') ?>";
if ( form.elements['newMonitor[Path]'].value.search(/^https?:\/\//i) )
errors[errors.length] = "<?php echo translate('BadWebSitePath') ?>";
}
if ( form.elements['newMonitor[Type]'].value != 'WebSite' ) {
if ( form.elements['newMonitor[AnalysisFPSLimit]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPSLimit]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadAnalysisFPS') ?>";
if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadMaxFPS') ?>";
if ( form.elements['newMonitor[AlarmMaxFPS]'].value && !(parseFloat(form.elements['newMonitor[AlarmMaxFPS]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadAlarmMaxFPS') ?>";
if ( !form.elements['newMonitor[RefBlendPerc]'].value || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) > 100 ) || (parseInt(form.elements['newMonitor[RefBlendPerc]'].value) < 0 ) )
errors[errors.length] = "<?php echo translate('BadRefBlendPerc') ?>";
if ( !form.elements['newMonitor[Colours]'].value || (parseInt(form.elements['newMonitor[Colours]'].value) != 1 && parseInt(form.elements['newMonitor[Colours]'].value) != 3 && parseInt(form.elements['newMonitor[Colours]'].value) != 4 ) )
errors[errors.length] = "<?php echo translate('BadColours') ?>";
if ( !form.elements['newMonitor[Width]'].value || !(parseInt(form.elements['newMonitor[Width]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadWidth') ?>";
if ( !form.elements['newMonitor[Height]'].value || !(parseInt(form.elements['newMonitor[Height]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadHeight') ?>";
if ( !form.elements['newMonitor[LabelX]'].value || !(parseInt(form.elements['newMonitor[LabelX]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadLabelX') ?>";
if ( !form.elements['newMonitor[LabelY]'].value || !(parseInt(form.elements['newMonitor[LabelY]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadLabelY') ?>";
if ( !form.elements['newMonitor[ImageBufferCount]'].value || !(parseInt(form.elements['newMonitor[ImageBufferCount]'].value) >= 10 ) )
errors[errors.length] = "<?php echo translate('BadImageBufferCount') ?>";
if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadWarmupCount') ?>";
if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) )
errors[errors.length] = "<?php echo translate('BadPreEventCount') ?>";
if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadPostEventCount') ?>";
if ( !form.elements['newMonitor[StreamReplayBuffer]'].value || !(parseInt(form.elements['newMonitor[StreamReplayBuffer]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadStreamReplayBuffer') ?>";
if ( !form.elements['newMonitor[AlarmFrameCount]'].value || !(parseInt(form.elements['newMonitor[AlarmFrameCount]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadAlarmFrameCount') ?>";
if ( !form.elements['newMonitor[SectionLength]'].value || !(parseInt(form.elements['newMonitor[SectionLength]'].value) >= 30 ) )
errors[errors.length] = "<?php echo translate('BadSectionLength') ?>";
if ( !form.elements['newMonitor[AnalysisUpdateDelay]'].value || !(parseInt(form.elements['newMonitor[AnalysisUpdateDelay]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadAnalysisUpdateDelay') ?>";
if ( !form.elements['newMonitor[FPSReportInterval]'].value || !(parseInt(form.elements['newMonitor[FPSReportInterval]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadFPSReportInterval') ?>";
if ( !form.elements['newMonitor[FrameSkip]'].value || !(parseInt(form.elements['newMonitor[FrameSkip]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadFrameSkip') ?>";
if ( !form.elements['newMonitor[MotionFrameSkip]'].value || !(parseInt(form.elements['newMonitor[MotionFrameSkip]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadMotionFrameSkip') ?>";
if ( form.elements['newMonitor[Type]'].value == 'Local' )
if ( !form.elements['newMonitor[SignalCheckColour]'].value || !form.elements['newMonitor[SignalCheckColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) )
errors[errors.length] = "<?php echo translate('BadSignalCheckColour') ?>";
if ( !form.elements['newMonitor[WebColour]'].value || !form.elements['newMonitor[WebColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) )
errors[errors.length] = "<?php echo translate('BadWebColour') ?>";
} }
if ( !form.elements['newMonitor[Colours]'].value || (parseInt(form.elements['newMonitor[Colours]'].value) != 1 && parseInt(form.elements['newMonitor[Colours]'].value) != 3 && parseInt(form.elements['newMonitor[Colours]'].value) != 4 ) )
errors[errors.length] = "<?php echo translate('BadColours') ?>";
if ( !form.elements['newMonitor[Width]'].value || !(parseInt(form.elements['newMonitor[Width]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadWidth') ?>";
if ( !form.elements['newMonitor[Height]'].value || !(parseInt(form.elements['newMonitor[Height]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadHeight') ?>";
if ( !form.elements['newMonitor[LabelX]'].value || !(parseInt(form.elements['newMonitor[LabelX]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadLabelX') ?>";
if ( !form.elements['newMonitor[LabelY]'].value || !(parseInt(form.elements['newMonitor[LabelY]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadLabelY') ?>";
if ( !form.elements['newMonitor[ImageBufferCount]'].value || !(parseInt(form.elements['newMonitor[ImageBufferCount]'].value) >= 10 ) )
errors[errors.length] = "<?php echo translate('BadImageBufferCount') ?>";
if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadWarmupCount') ?>";
if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) )
errors[errors.length] = "<?php echo translate('BadPreEventCount') ?>";
if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadPostEventCount') ?>";
if ( !form.elements['newMonitor[StreamReplayBuffer]'].value || !(parseInt(form.elements['newMonitor[StreamReplayBuffer]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadStreamReplayBuffer') ?>";
if ( !form.elements['newMonitor[AlarmFrameCount]'].value || !(parseInt(form.elements['newMonitor[AlarmFrameCount]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadAlarmFrameCount') ?>";
if ( !form.elements['newMonitor[SectionLength]'].value || !(parseInt(form.elements['newMonitor[SectionLength]'].value) >= 30 ) )
errors[errors.length] = "<?php echo translate('BadSectionLength') ?>";
if ( !form.elements['newMonitor[AnalysisUpdateDelay]'].value || !(parseInt(form.elements['newMonitor[AnalysisUpdateDelay]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadAnalysisUpdateDelay') ?>";
if ( !form.elements['newMonitor[FPSReportInterval]'].value || !(parseInt(form.elements['newMonitor[FPSReportInterval]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadFPSReportInterval') ?>";
if ( !form.elements['newMonitor[FrameSkip]'].value || !(parseInt(form.elements['newMonitor[FrameSkip]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadFrameSkip') ?>";
if ( !form.elements['newMonitor[MotionFrameSkip]'].value || !(parseInt(form.elements['newMonitor[MotionFrameSkip]'].value) >= 0 ) )
errors[errors.length] = "<?php echo translate('BadMotionFrameSkip') ?>";
if ( form.elements['newMonitor[Type]'].value == 'Local' )
if ( !form.elements['newMonitor[SignalCheckColour]'].value || !form.elements['newMonitor[SignalCheckColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) )
errors[errors.length] = "<?php echo translate('BadSignalCheckColour') ?>";
if ( !form.elements['newMonitor[WebColour]'].value || !form.elements['newMonitor[WebColour]'].value.match( /^[#0-9a-zA-Z]+$/ ) )
errors[errors.length] = "<?php echo translate('BadWebColour') ?>";
if ( errors.length ) { if ( errors.length ) {
alert( errors.join( "\n" ) ); alert( errors.join( "\n" ) );

View File

@ -12,6 +12,15 @@ function Monitor( monitorData ) {
if ( auth_hash ) if ( auth_hash )
this.streamCmdParms += '&auth='+auth_hash; this.streamCmdParms += '&auth='+auth_hash;
this.streamCmdTimer = null; this.streamCmdTimer = null;
this.type = monitorData.type;
this.refresh = monitorData.refresh;
this.start = function( delay ) {
if ( this.streamCmdQuery )
this.streamCmdTimer = this.streamCmdQuery.delay( delay, this );
else
console.log("No streamCmdQuery");
};
this.setStateClass = function( element, stateClass ) { this.setStateClass = function( element, stateClass ) {
if ( !element.hasClass( stateClass ) ) { if ( !element.hasClass( stateClass ) ) {
@ -68,7 +77,7 @@ function Monitor( monitorData ) {
else else
stateClass = "idle"; stateClass = "idle";
if ( !COMPACT_MONTAGE ) { if ( (!COMPACT_MONTAGE) && (this.type != 'WebSite') ) {
$('fpsValue'+this.id).set( 'text', this.status.fps ); $('fpsValue'+this.id).set( 'text', this.status.fps );
$('stateValue'+this.id).set( 'text', stateStrings[this.alarmState] ); $('stateValue'+this.id).set( 'text', stateStrings[this.alarmState] );
this.setStateClass( $('monitorState'+this.id), stateClass ); this.setStateClass( $('monitorState'+this.id), stateClass );
@ -137,22 +146,26 @@ function Monitor( monitorData ) {
this.streamCmdReq.cancel(); this.streamCmdReq.cancel();
} }
//console.log("Starting CmdQuery for " + this.connKey ); //console.log("Starting CmdQuery for " + this.connKey );
this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); if ( this.type != 'WebSite' ) {
this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY );
}
}; };
this.streamCmdReq = new Request.JSON( { if ( this.type != 'WebSite' ) {
url: this.server_url, this.streamCmdReq = new Request.JSON( {
method: 'get', url: this.server_url,
timeout: 1000+AJAX_TIMEOUT, method: 'get',
onSuccess: this.getStreamCmdResponse.bind( this ), timeout: 1000+AJAX_TIMEOUT,
onTimeout: this.streamCmdQuery.bind( this, true ), onSuccess: this.getStreamCmdResponse.bind( this ),
onError: this.onError.bind(this), onTimeout: this.streamCmdQuery.bind( this, true ),
onFailure: this.onFailure.bind(this), onError: this.onError.bind(this),
link: 'cancel' onFailure: this.onFailure.bind(this),
} ); link: 'cancel'
} );
console.log("queueing for " + this.id + " " + this.connKey );
requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq );
}
console.log("queueing for " + this.id + " " + this.connKey );
requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq );
} }
function selectLayout( element ) { function selectLayout( element ) {
@ -378,15 +391,26 @@ function cancel_layout(button) {
selectLayout('#zmMontageLayout'); selectLayout('#zmMontageLayout');
} }
function reloadWebSite(ndx) {
document.getElementById('imageFeed'+ndx).innerHTML = document.getElementById('imageFeed'+ndx).innerHTML;
}
var monitors = new Array(); var monitors = new Array();
function initPage() { function initPage() {
console.log("initPage");
for ( var i = 0; i < monitorData.length; i++ ) { for ( var i = 0; i < monitorData.length; i++ ) {
monitors[i] = new Monitor(monitorData[i]); monitors[i] = new Monitor(monitorData[i]);
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
var interval = monitors[i].refresh;
monitors[i].start( delay );
if ( monitors[i].type == 'WebSite' && interval > 0 ) {
setInterval(reloadWebSite, interval*1000, i);
}
} }
selectLayout('#zmMontageLayout'); selectLayout('#zmMontageLayout');
for ( var i = 0; i < monitorData.length; i++ ) { for ( var i = 0; i < monitorData.length; i++ ) {
if ( monitors[i].type == 'WebSite' )
continue;
var delay = Math.round( (Math.random()+0.75)*statusRefreshTimeout ); var delay = Math.round( (Math.random()+0.75)*statusRefreshTimeout );
console.log("Delay for monitor " + monitorData[i].id + " is " + delay ); console.log("Delay for monitor " + monitorData[i].id + " is " + delay );
monitors[i].streamCmdQuery.delay( delay, monitors[i] ); monitors[i].streamCmdQuery.delay( delay, monitors[i] );

View File

@ -36,7 +36,9 @@ monitorData[monitorData.length] = {
'width': <?php echo $monitor->Width() ?>, 'width': <?php echo $monitor->Width() ?>,
'height':<?php echo $monitor->Height() ?>, 'height':<?php echo $monitor->Height() ?>,
'server_url': '<?php echo $monitor->Server()->Url().$_SERVER['PHP_SELF'] ?>', 'server_url': '<?php echo $monitor->Server()->Url().$_SERVER['PHP_SELF'] ?>',
'onclick': function(){createPopup( '?view=watch&mid=<?php echo $monitor->Id() ?>', 'zmWatch<?php echo $monitor->Id() ?>', 'watch', <?php echo reScale( $monitor->Width(), $monitor->PopupScale() ); ?>, <?php echo reScale( $monitor->Height(), $monitor->PopupScale() ); ?> );} 'onclick': function(){createPopup( '?view=watch&mid=<?php echo $monitor->Id() ?>', 'zmWatch<?php echo $monitor->Id() ?>', 'watch', <?php echo reScale( $monitor->Width(), $monitor->PopupScale() ); ?>, <?php echo reScale( $monitor->Height(), $monitor->PopupScale() ); ?> );},
'type': '<?php echo $monitor->Type() ?>',
'refresh': '<?php echo $monitor->Refresh() ?>'
}; };
<?php <?php
} // end foreach monitor } // end foreach monitor

View File

@ -105,18 +105,20 @@ function setAlarmState( currentAlarmState ) {
lastAlarmState = alarmState; lastAlarmState = alarmState;
} }
var streamCmdParms = "view=request&request=stream&connkey="+connKey; if ( monitorType != 'WebSite' ) {
if ( auth_hash ) var streamCmdParms = "view=request&request=stream&connkey="+connKey;
streamCmdParms += '&auth='+auth_hash; if ( auth_hash )
var streamCmdReq = new Request.JSON( { streamCmdParms += '&auth='+auth_hash;
url: monitorUrl+thisUrl, var streamCmdReq = new Request.JSON( {
method: 'get', url: monitorUrl+thisUrl,
timeout: AJAX_TIMEOUT, method: 'get',
link: 'chain', timeout: AJAX_TIMEOUT,
onSuccess: getStreamCmdResponse, link: 'chain',
onFailure: getStreamCmdFailure onSuccess: getStreamCmdResponse,
} ); onFailure: getStreamCmdFailure
var streamCmdTimer = null; } );
var streamCmdTimer = null;
}
var streamStatus; var streamStatus;
@ -350,11 +352,13 @@ function streamCmdQuery() {
streamCmdReq.send( streamCmdParms+"&command="+CMD_QUERY ); streamCmdReq.send( streamCmdParms+"&command="+CMD_QUERY );
} }
var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate"; if ( monitorType != 'WebSite' ) {
if ( auth_hash ) var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate";
statusCmdParms += '&auth='+auth_hash; if ( auth_hash )
var statusCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'get', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } ); statusCmdParms += '&auth='+auth_hash;
var statusCmdTimer = null; var statusCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'get', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } );
var statusCmdTimer = null;
}
function getStatusCmdResponse( respObj, respText ) { function getStatusCmdResponse( respObj, respText ) {
watchdogOk("status"); watchdogOk("status");
@ -377,18 +381,20 @@ function statusCmdQuery() {
statusCmdReq.send(); statusCmdReq.send();
} }
var alarmCmdParms = "view=request&request=alarm&id="+monitorId; if ( monitorType != 'WebSite' ) {
if ( auth_hash ) var alarmCmdParms = "view=request&request=alarm&id="+monitorId;
alarmCmdParms += '&auth='+auth_hash; if ( auth_hash )
var alarmCmdReq = new Request.JSON( { alarmCmdParms += '&auth='+auth_hash;
url: monitorUrl+thisUrl, var alarmCmdReq = new Request.JSON( {
method: 'post', url: monitorUrl+thisUrl,
timeout: AJAX_TIMEOUT, method: 'post',
link: 'cancel', timeout: AJAX_TIMEOUT,
onSuccess: getAlarmCmdResponse, link: 'cancel',
onTimeout: streamCmdQuery onSuccess: getAlarmCmdResponse,
} ); onTimeout: streamCmdQuery
var alarmCmdFirst = true; } );
var alarmCmdFirst = true;
}
function getAlarmCmdResponse( respObj, respText ) { function getAlarmCmdResponse( respObj, respText ) {
checkStreamForErrors("getAlarmCmdResponse", respObj); checkStreamForErrors("getAlarmCmdResponse", respObj);
@ -428,12 +434,14 @@ function deleteEvent( event, eventId ) {
event.stop(); event.stop();
} }
var eventCmdParms = "view=request&request=status&entity=events&id="+monitorId+"&count="+maxDisplayEvents+"&sort=Id%20desc"; if ( monitorType != 'WebSite' ) {
if ( auth_hash ) var eventCmdParms = "view=request&request=status&entity=events&id="+monitorId+"&count="+maxDisplayEvents+"&sort=Id%20desc";
eventCmdParms += '&auth='+auth_hash; if ( auth_hash )
var eventCmdReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, data: eventCmdParms, link: 'cancel', onSuccess: getEventCmdResponse, onTimeout: eventCmdQuery } ); eventCmdParms += '&auth='+auth_hash;
var eventCmdTimer = null; var eventCmdReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, data: eventCmdParms, link: 'cancel', onSuccess: getEventCmdResponse, onTimeout: eventCmdQuery } );
var eventCmdFirst = true; var eventCmdTimer = null;
var eventCmdFirst = true;
}
function highlightRow( row ) { function highlightRow( row ) {
$(row).toggleClass( 'highlight' ); $(row).toggleClass( 'highlight' );
@ -536,10 +544,12 @@ function eventCmdQuery() {
eventCmdReq.send(); eventCmdReq.send();
} }
var controlParms = "view=request&request=control&id="+monitorId; if ( monitorType != 'WebSite' ) {
if ( auth_hash ) var controlParms = "view=request&request=control&id="+monitorId;
controlParms += '&auth='+auth_hash; if ( auth_hash )
var controlReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getControlResponse } ); controlParms += '&auth='+auth_hash;
var controlReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getControlResponse } );
}
function getControlResponse( respObj, respText ) { function getControlResponse( respObj, respText ) {
if ( !respObj ) if ( !respObj )
@ -652,33 +662,37 @@ function watchdogOk( type ) {
} }
function initPage() { function initPage() {
if ( streamMode == "single" ) { if ( monitorType != 'WebSite' ) {
statusCmdTimer = statusCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
watchdogCheck.pass('status').periodical(statusRefreshTimeout*2);
} else {
streamCmdTimer = streamCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
watchdogCheck.pass('stream').periodical(statusRefreshTimeout*2);
}
eventCmdTimer = eventCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
watchdogCheck.pass('event').periodical(eventsRefreshTimeout*2);
if ( canStreamNative || streamMode == "single" ) {
var streamImg = $('imageFeed').getElement('img');
if ( !streamImg )
streamImg = $('imageFeed').getElement('object');
if ( streamMode == "single" ) { if ( streamMode == "single" ) {
streamImg.addEvent( 'click', fetchImage.pass( streamImg ) ); statusCmdTimer = statusCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
fetchImage.pass( streamImg ).periodical( imageRefreshTimeout ); watchdogCheck.pass('status').periodical(statusRefreshTimeout*2);
} else } else {
streamImg.addEvent( 'click', function( event ) { handleClick( event ); } ); streamCmdTimer = streamCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
} watchdogCheck.pass('stream').periodical(statusRefreshTimeout*2);
}
if ( refreshApplet && appletRefreshTime ) eventCmdTimer = eventCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
appletRefresh.delay( appletRefreshTime*1000 ); watchdogCheck.pass('event').periodical(eventsRefreshTimeout*2);
if (scale == "auto") changeScale();
if (window.history.length == 1) { if ( canStreamNative || streamMode == "single" ) {
$j('#closeControl').html(''); var streamImg = $('imageFeed').getElement('img');
if ( !streamImg )
streamImg = $('imageFeed').getElement('object');
if ( streamMode == "single" ) {
streamImg.addEvent( 'click', fetchImage.pass( streamImg ) );
fetchImage.pass( streamImg ).periodical( imageRefreshTimeout );
} else
streamImg.addEvent( 'click', function( event ) { handleClick( event ); } );
}
if ( refreshApplet && appletRefreshTime )
appletRefresh.delay( appletRefreshTime*1000 );
if (scale == "auto") changeScale();
if (window.history.length == 1) {
$j('#closeControl').html('');
}
} else if ( monitorRefresh > 0 ) {
var myReload = setInterval(reloadWebSite, monitorRefresh*1000);
} }
} }

View File

@ -49,6 +49,8 @@ var monitorId = <?php echo $monitor->Id() ?>;
var monitorWidth = <?php echo $monitor->Width() ?>; var monitorWidth = <?php echo $monitor->Width() ?>;
var monitorHeight = <?php echo $monitor->Height() ?>; var monitorHeight = <?php echo $monitor->Height() ?>;
var monitorUrl = '<?php echo ( $monitor->Server()->Url() . ( ZM_MIN_STREAMING_PORT ? ':'. (ZM_MIN_STREAMING_PORT+$monitor->Id()) : '' ) ) ?>'; var monitorUrl = '<?php echo ( $monitor->Server()->Url() . ( ZM_MIN_STREAMING_PORT ? ':'. (ZM_MIN_STREAMING_PORT+$monitor->Id()) : '' ) ) ?>';
var monitorType = '<?php echo ( $monitor->Type() ) ?>';
var monitorRefresh = '<?php echo ( $monitor->Refresh() ) ?>';
var scale = '<?php echo $scale ?>'; var scale = '<?php echo $scale ?>';

View File

@ -26,23 +26,6 @@ if ( !canView( 'Monitors' ) ) {
return; return;
} }
$tabs = array();
$tabs['general'] = translate('General');
$tabs['source'] = translate('Source');
$tabs['storage'] = translate('Storage');
$tabs['timestamp'] = translate('Timestamp');
$tabs['buffers'] = translate('Buffers');
if ( ZM_OPT_CONTROL && canView( 'Control' ) )
$tabs['control'] = translate('Control');
if ( ZM_OPT_X10 )
$tabs['x10'] = translate('X10');
$tabs['misc'] = translate('Misc');
if ( isset($_REQUEST['tab']) )
$tab = validHtmlStr($_REQUEST['tab']);
else
$tab = 'general';
$Server = null; $Server = null;
if ( defined( 'ZM_SERVER_ID' ) ) { if ( defined( 'ZM_SERVER_ID' ) ) {
$Server = dbFetchOne( 'SELECT * FROM Servers WHERE Id=?', NULL, array( ZM_SERVER_ID ) ); $Server = dbFetchOne( 'SELECT * FROM Servers WHERE Id=?', NULL, array( ZM_SERVER_ID ) );
@ -142,6 +125,7 @@ if ( ! $monitor ) {
'V4LCapturesPerFrame' => 1, 'V4LCapturesPerFrame' => 1,
'ServerId' => 'auto', 'ServerId' => 'auto',
'StorageId' => '1', 'StorageId' => '1',
'Refresh' => '',
) ); ) );
} # end if $_REQUEST['dupID'] } # end if $_REQUEST['dupID']
} # end if $_REQUEST['mid'] } # end if $_REQUEST['mid']
@ -212,7 +196,8 @@ $sourceTypes = array(
'Ffmpeg' => translate('Ffmpeg'), 'Ffmpeg' => translate('Ffmpeg'),
'Libvlc' => translate('Libvlc'), 'Libvlc' => translate('Libvlc'),
'cURL' => 'cURL (HTTP(S) only)', 'cURL' => 'cURL (HTTP(S) only)',
'NVSocket' => translate('NVSocket') 'WebSite'=> 'Web Site',
'NVSocket' => translate('NVSocket')
); );
if ( !ZM_HAS_V4L ) if ( !ZM_HAS_V4L )
unset($sourceTypes['Local']); unset($sourceTypes['Local']);
@ -507,6 +492,25 @@ if ( canEdit( 'Monitors' ) ) {
<div id="content"> <div id="content">
<ul class="tabList"> <ul class="tabList">
<?php <?php
$tabs = array();
$tabs['general'] = translate('General');
$tabs['source'] = translate('Source');
if ( $monitor->Type() != 'WebSite' ) {
$tabs['storage'] = translate('Storage');
$tabs['timestamp'] = translate('Timestamp');
$tabs['buffers'] = translate('Buffers');
if ( ZM_OPT_CONTROL && canView( 'Control' ) )
$tabs['control'] = translate('Control');
if ( ZM_OPT_X10 )
$tabs['x10'] = translate('X10');
$tabs['misc'] = translate('Misc');
}
if ( isset($_REQUEST['tab']) )
$tab = validHtmlStr($_REQUEST['tab']);
else
$tab = 'general';
foreach ( $tabs as $name=>$value ) { foreach ( $tabs as $name=>$value ) {
if ( $tab == $name ) { if ( $tab == $name ) {
?> ?>
@ -583,7 +587,7 @@ if ( $tab != 'source' || ($monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Lib
<input type="hidden" name="newMonitor[Options]" value="<?php echo validHtmlStr($monitor->Options()) ?>"/> <input type="hidden" name="newMonitor[Options]" value="<?php echo validHtmlStr($monitor->Options()) ?>"/>
<?php <?php
} }
if ( $tab != 'source' || ($monitor->Type()!= 'Remote' && $monitor->Type()!= 'File' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' && $monitor->Type()!= 'cURL') ) { if ( $tab != 'source' || ($monitor->Type()!= 'Remote' && $monitor->Type()!= 'File' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' && $monitor->Type()!= 'cURL' && $monitor->Type() != 'WebSite') ) {
?> ?>
<input type="hidden" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>"/> <input type="hidden" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>"/>
<input type="hidden" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>"/> <input type="hidden" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>"/>
@ -713,6 +717,9 @@ switch ( $tab ) {
?> ?>
</select></td></tr> </select></td></tr>
<tr><td><?php echo translate('Enabled') ?></td><td><input type="checkbox" name="newMonitor[Enabled]" value="1"<?php if ( $monitor->Enabled() ) { ?> checked="checked"<?php } ?>/></td></tr> <tr><td><?php echo translate('Enabled') ?></td><td><input type="checkbox" name="newMonitor[Enabled]" value="1"<?php if ( $monitor->Enabled() ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php
if ( $monitor->Type != 'WebSite' ) {
?>
<tr> <tr>
<td><?php echo translate('LinkedMonitors') ?></td> <td><?php echo translate('LinkedMonitors') ?></td>
<td> <td>
@ -802,6 +809,7 @@ echo htmlOptions(Group::get_dropdown_options( ), $monitor->GroupIds() );
?> ?>
</td></tr> </td></tr>
<?php <?php
}
break; break;
} }
case 'source' : case 'source' :
@ -868,6 +876,13 @@ include('_monitor_source_nvsocket.php');
<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()) ?>" size="36"/></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()) ?>" size="12"/></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()) ?>" size="12"/></td></tr>
<?php
} 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><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>
<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>
<tr><td><?php echo 'Web Site Refresh (Optional)' ?></td><td><input type="number" name="newMonitor[Refresh]" value="<?php echo $monitor->Refresh()?>"/></td></tr>
<?php <?php
} elseif ( $monitor->Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { } elseif ( $monitor->Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) {
?> ?>
@ -876,7 +891,7 @@ include('_monitor_source_nvsocket.php');
<tr><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()) ?>" size="36"/></td></tr> <tr><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()) ?>" size="36"/></td></tr>
<?php <?php
} }
if ( $monitor->Type() != 'NVSocket' ) { 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><?php echo translate('TargetColorspace') ?></td><td><?php echo htmlSelect('newMonitor[Colours]', $Colours, $monitor->Colours() ); ?>
</td></tr> </td></tr>
@ -890,7 +905,7 @@ 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 $value ?>"<?php if ( $value == $monitor->Deinterlacing()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr> <tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts_v4l2 as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Deinterlacing()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php <?php
} else { } 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 $value ?>"<?php if ( $value == $monitor->Deinterlacing()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr> <tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Deinterlacing()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php <?php

View File

@ -204,7 +204,11 @@ foreach ( $monitors as $monitor ) {
} }
} }
echo getStreamHTML( $monitor, $monitor_options ); if ( $monitor->Type() == "WebSite" ) {
echo getWebSiteUrl( 'liveStream'.$monitor->Id(), $monitor->Path(), reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
} else {
echo getStreamHTML( $monitor, $monitor_options );
}
if ( $showZones ) { if ( $showZones ) {
$height = null; $height = null;
$width = null; $width = null;
@ -255,7 +259,7 @@ foreach ( $monitors as $monitor ) {
<?php } # end if showZones ?> <?php } # end if showZones ?>
</div> </div>
<?php <?php
if ( !ZM_WEB_COMPACT_MONTAGE ) { if ( (!ZM_WEB_COMPACT_MONTAGE) && ($monitor->Type() != 'WebSite') ) {
?> ?>
<div id="monitorState<?php echo $monitor->Id() ?>" class="monitorState idle"><?php echo translate('State') ?>:&nbsp;<span id="stateValue<?php echo $monitor->Id() ?>"></span>&nbsp;-&nbsp;<span id="fpsValue<?php echo $monitor->Id() ?>"></span>&nbsp;fps</div> <div id="monitorState<?php echo $monitor->Id() ?>" class="monitorState idle"><?php echo translate('State') ?>:&nbsp;<span id="stateValue<?php echo $monitor->Id() ?>"></span>&nbsp;-&nbsp;<span id="fpsValue<?php echo $monitor->Id() ?>"></span>&nbsp;fps</div>
<?php <?php

View File

@ -207,7 +207,7 @@ $frameSql .= ' ORDER BY Id DESC';
$monitors = array(); $monitors = array();
foreach( $displayMonitors as $row ) { foreach( $displayMonitors as $row ) {
if ( $row['Function'] == 'None' ) if ( $row['Function'] == 'None' || $row['Type'] == 'WebSite' )
continue; continue;
$Monitor = new Monitor( $row ); $Monitor = new Monitor( $row );
$monitors[] = $Monitor; $monitors[] = $Monitor;

View File

@ -234,7 +234,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
<td class="colMemory <td class="colMemory
<?php if ( $row['FreeMem']/$row['TotalMem'] < .1 ) { echo 'danger'; } ?>"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeMem']) . ' / ' . human_filesize($row['TotalMem']), $canEdit ) ?></td> <?php if ( $row['FreeMem']/$row['TotalMem'] < .1 ) { echo 'danger'; } ?>"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeMem']) . ' / ' . human_filesize($row['TotalMem']), $canEdit ) ?></td>
<td class="colSwap <td class="colSwap
<?php if ( $row['FreeSwap']/$row['TotalSwap'] < .1 ) { echo 'danger'; } ?>"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeSwap']) . ' / ' . human_filesize($row['TotalSwap']) , $canEdit ) ?></td> <?php if ( (!$row['TotalSwap']) or ($row['FreeSwap']/$row['TotalSwap'] < .1) ) { echo 'danger'; } ?>"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeSwap']) . ' / ' . human_filesize($row['TotalSwap']) , $canEdit ) ?></td>
<td class="colStats"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', $row['zmstats'] ? 'yes' : 'no', $canEdit ) ?></td> <td class="colStats"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', $row['zmstats'] ? 'yes' : 'no', $canEdit ) ?></td>
<td class="colAudit"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', $row['zmaudit'] ? 'yes' : 'no', $canEdit ) ?></td> <td class="colAudit"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', $row['zmaudit'] ? 'yes' : 'no', $canEdit ) ?></td>
<td class="colTrigger"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', $row['zmtrigger'] ? 'yes' : 'no', $canEdit ) ?></td> <td class="colTrigger"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', $row['zmtrigger'] ? 'yes' : 'no', $canEdit ) ?></td>
@ -265,21 +265,22 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
<th class="colType"><?php echo translate('Type') ?></th> <th class="colType"><?php echo translate('Type') ?></th>
<th class="colScheme"><?php echo translate('StorageScheme') ?></th> <th class="colScheme"><?php echo translate('StorageScheme') ?></th>
<th class="colServer"><?php echo translate('Server') ?></th> <th class="colServer"><?php echo translate('Server') ?></th>
<th class="colDiskSpace"><?php echo translate('DiskSpace') ?></th>
<th class="colMark"><?php echo translate('Mark') ?></th> <th class="colMark"><?php echo translate('Mark') ?></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php foreach( dbFetchAll( 'SELECT * FROM Storage ORDER BY Name' ) as $row ) { ?> <?php foreach( Storage::find_all( null, array('order'=>'lower(Name)') ) as $Storage ) { ?>
<tr> <tr>
<td class="colId"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Id']), $canEdit ) ?></td> <td class="colId"><?php echo makePopupLink('?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Id()), $canEdit ) ?></td>
<td class="colName"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Name']), $canEdit ) ?></td> <td class="colName"><?php echo makePopupLink( '?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?></td>
<td class="colPath"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Path']), $canEdit ) ?></td> <td class="colPath"><?php echo makePopupLink( '?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Path()), $canEdit ) ?></td>
<td class="colType"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Type']), $canEdit ) ?></td> <td class="colType"><?php echo makePopupLink( '?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Type()), $canEdit ) ?></td>
<td class="colScheme"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Scheme']), $canEdit ) ?></td> <td class="colScheme"><?php echo makePopupLink( '?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Scheme()), $canEdit ) ?></td>
<td class="colServer"><?php <td class="colServer"><?php
$Server = new Server($row['ServerId']); echo makePopupLink( '?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?></td>
echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($Server->Name()), $canEdit ) ?></td> <td class="colDiskSpace"><?php echo human_filesize($Storage->disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?><?td>
<td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $row['Id'] ?>" onclick="configureDeleteButton(this);"<?php if ( !$canEdit ) { ?> disabled="disabled"<?php } ?>/></td> <td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $Storage->Id() ?>" onclick="configureDeleteButton(this);"<?php if ( !$canEdit ) { ?> disabled="disabled"<?php } ?>/></td>
</tr> </tr>
<?php } #end foreach Server ?> <?php } #end foreach Server ?>
</tbody> </tbody>

View File

@ -102,6 +102,7 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
if ( count($EventsByMonitor[$event['MonitorId']]['Events']) ) { if ( count($EventsByMonitor[$event['MonitorId']]['Events']) ) {
$last_event = end($EventsByMonitor[$event['MonitorId']]['Events']); $last_event = end($EventsByMonitor[$event['MonitorId']]['Events']);
#Logger::Debug(print_r($last_event,true));
$gap = $last_event->EndTimeSecs() - $event['StartTimeSecs']; $gap = $last_event->EndTimeSecs() - $event['StartTimeSecs'];
if ( $gap < $EventsByMonitor[$event['MonitorId']]['MinGap'] ) if ( $gap < $EventsByMonitor[$event['MonitorId']]['MinGap'] )
@ -140,7 +141,10 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
<tr> <tr>
<th class="colId"><?php echo translate('Id') ?></th> <th class="colId"><?php echo translate('Id') ?></th>
<th class="colName"><i class="material-icons md-18">videocam</i>&nbsp;<?php echo translate('Name') ?></th> <th class="colName"><i class="material-icons md-18">videocam</i>&nbsp;<?php echo translate('Name') ?></th>
<th class="colServer"><?php echo translate('Server') ?></th>
<th class="colEvents"><?php echo translate('Events') ?></th> <th class="colEvents"><?php echo translate('Events') ?></th>
<th class="colFirstEvent"><?php echo translate('FirstEvent') ?></th>
<th class="colLastEvent"><?php echo translate('LastEvent') ?></th>
<th class="colMinGap"><?php echo translate('MinGap') ?></th> <th class="colMinGap"><?php echo translate('MinGap') ?></th>
<th class="colMaxGap"><?php echo translate('MaxGap') ?></th> <th class="colMaxGap"><?php echo translate('MaxGap') ?></th>
<th class="colMissingFiles"><?php echo translate('MissingFiles') ?></th> <th class="colMissingFiles"><?php echo translate('MissingFiles') ?></th>
@ -152,8 +156,25 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
$monitor = $displayMonitors[$monitor_i]; $monitor = $displayMonitors[$monitor_i];
$Monitor = new Monitor($monitor); $Monitor = new Monitor($monitor);
$montagereview_link = "?view=montagereview&live=0&MonitorId=". $monitor['Id'] . '&minTime='.$minTime.'&maxTime='.$maxTime; $montagereview_link = "?view=montagereview&live=0&MonitorId=". $monitor['Id'] . '&minTime='.$minTime.'&maxTime='.$maxTime;
if ( isset($EventsByMonitor[$Monitor->Id()]) ) {
$EventCounts = $EventsByMonitor[$Monitor->Id()];
$MinGap = $EventCounts['MinGap'];
$MaxGap = $EventCounts['MaxGap'];
$FileMissing = $EventCounts['FileMissing'];
$ZeroSize = $EventCounts['ZeroSize'];
$FirstEvent = $EventCounts['Events'][0];
$LastEvent = end($EventCounts['Events']);
} else {
$MinGap = 0;
$MaxGap = 0;
$FileMissing = 0;
$ZeroSize = 0;
$FirstEvent = 0;
$LastEvent = 0;
}
?> ?>
<tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>" title="<?php echo $monitor['Id'] ?>"> <tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>" title="<?php echo $monitor['Id'] ?>">
<td class="colId"><a href="<?php echo $montagereview_link ?>"><?php echo $monitor['Id'] ?></a></td> <td class="colId"><a href="<?php echo $montagereview_link ?>"><?php echo $monitor['Id'] ?></a></td>
@ -168,11 +189,14 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
}, $Monitor->GroupIds() ) ); }, $Monitor->GroupIds() ) );
?> ?>
</div></td> </div></td>
<td class="colServer"><?php echo $Monitor->Server()->Name()?></td>
<td class="colEvents"><?php echo isset($EventsByMonitor[$Monitor->Id()])?count($EventsByMonitor[$Monitor->Id()]['Events']):0 ?></td> <td class="colEvents"><?php echo isset($EventsByMonitor[$Monitor->Id()])?count($EventsByMonitor[$Monitor->Id()]['Events']):0 ?></td>
<td class="colMinGap"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['MinGap']:0 ?></td> <td class="colFirstEvent"><?php echo $FirstEvent ? $FirstEvent->link_to($FirstEvent->Id().' at ' . $FirstEvent->StartTime()) : 'none'?></td>
<td class="colMaxGap"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['MaxGap']:0 ?></td> <td class="colLastEvent"><?php echo $LastEvent ? $LastEvent->link_to($LastEvent->Id().' at ' . $LastEvent->StartTime()) : 'none'?></td>
<td class="colFileMissing"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['FileMissing']:0 ?></td> <td class="colMinGap"><?php echo $MinGap ?></td>
<td class="colZeroSize"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['ZeroSize']:0 ?></td> <td class="colMaxGap"><?php echo $MaxGap ?></td>
<td class="colFileMissing<?php echo $FileMissing ? ' errorText' : ''?>"><?php echo $FileMissing ?></td>
<td class="colZeroSize<?php echo $ZeroSize ? ' errorText' : ''?>"><?php echo $ZeroSize ?></td>
</tr> </tr>
<?php <?php
} # end for each monitor } # end for each monitor

View File

@ -41,7 +41,7 @@ if ( ! visibleMonitor( $mid ) ) {
$monitor = new Monitor( $mid ); $monitor = new Monitor( $mid );
#Whether to show the controls button #Whether to show the controls button
$showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView( 'Control' ) ); $showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' );
if ( isset( $_REQUEST['scale'] ) ) { if ( isset( $_REQUEST['scale'] ) ) {
$scale = validInt($_REQUEST['scale']); $scale = validInt($_REQUEST['scale']);
@ -80,6 +80,7 @@ if ( canView( 'Control' ) && $monitor->Type() == 'Local' ) {
</div> </div>
<div id="content"> <div id="content">
<div id="imageFeed"><?php echo getStreamHTML( $monitor, array('scale'=>$scale) ); ?></div> <div id="imageFeed"><?php echo getStreamHTML( $monitor, array('scale'=>$scale) ); ?></div>
<?php if ( $monitor->Type() != 'WebSite' ) { ?>
<div id="monitorStatus"> <div id="monitorStatus">
<?php if ( canEdit( 'Monitors' ) ) { ?> <?php if ( canEdit( 'Monitors' ) ) { ?>
<div id="enableDisableAlarms"><a id="enableAlarmsLink" href="#" onclick="cmdEnableAlarms(); return( false );" class="hidden"><?php echo translate('EnableAlarms') ?></a><a id="disableAlarmsLink" href="#" onclick="cmdDisableAlarms(); return( false );" class="hidden"><?php echo translate('DisableAlarms') ?></a></div> <div id="enableDisableAlarms"><a id="enableAlarmsLink" href="#" onclick="cmdEnableAlarms(); return( false );" class="hidden"><?php echo translate('EnableAlarms') ?></a><a id="disableAlarmsLink" href="#" onclick="cmdDisableAlarms(); return( false );" class="hidden"><?php echo translate('DisableAlarms') ?></a></div>
@ -119,7 +120,7 @@ if ( $streamMode == 'jpeg' ) {
?> ?>
<input type="button" value="&ndash;" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" onclick="streamCmdZoomOut()"/> <input type="button" value="&ndash;" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" onclick="streamCmdZoomOut()"/>
<?php <?php
} // end if streamMode==jpeg } // end if streamMode==jpeg
?> ?>
</div> </div>
<div id="replayStatus"<?php echo $streamMode=="single"?' class="hidden"':'' ?>> <div id="replayStatus"<?php echo $streamMode=="single"?' class="hidden"':'' ?>>
@ -129,6 +130,7 @@ if ( $streamMode == 'jpeg' ) {
<span id="level"><?php echo translate('Buffer') ?>: <span id="levelValue"></span>%</span> <span id="level"><?php echo translate('Buffer') ?>: <span id="levelValue"></span>%</span>
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue"></span>x</span> <span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue"></span>x</span>
</div> </div>
<?php } // end if $monitor->Type() != 'WebSite' ?>
<?php <?php
if ( $showPtzControls ) { if ( $showPtzControls ) {
foreach ( getSkinIncludes( 'includes/control_functions.php' ) as $includeFile ) foreach ( getSkinIncludes( 'includes/control_functions.php' ) as $includeFile )
@ -139,7 +141,7 @@ if ( $showPtzControls ) {
</div> </div>
<?php <?php
} }
if ( canView( 'Events' ) ) { if ( canView( 'Events' ) && $monitor->Type() != 'WebSite' ) {
?> ?>
<div id="events"> <div id="events">
<table id="eventList" cellspacing="0"> <table id="eventList" cellspacing="0">