Merge branch 'master' into zma_to_thread
This commit is contained in:
commit
2eda49333f
|
@ -0,0 +1,83 @@
|
||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [master]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 3 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Override automatic language detection by changing the below list
|
||||||
|
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||||
|
language: ['cpp', 'javascript']
|
||||||
|
# Learn more...
|
||||||
|
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
# We must fetch at least the immediate parents so that if this is
|
||||||
|
# a pull request then we can checkout the head.
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
# If this run was triggered by a pull request event, then checkout
|
||||||
|
# the head of the pull request instead of the merge commit.
|
||||||
|
- run: git checkout HEAD^2
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
- name: Clean install dependencies and build
|
||||||
|
run: |
|
||||||
|
git submodule init
|
||||||
|
git submodule update --init --recursive
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install libx264-dev libmp4v2-dev libavdevice-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev
|
||||||
|
sudo apt-get install libbz2-dev libgcrypt20-dev libcurl4-gnutls-dev libjpeg-turbo8-dev libturbojpeg0-dev
|
||||||
|
sudo apt-get install default-libmysqlclient-dev libpcre3-dev libpolkit-gobject-1-dev libv4l-dev libvlc-dev
|
||||||
|
sudo apt-get install libdate-manip-perl libdbd-mysql-perl libphp-serialization-perl libsys-mmap-perl
|
||||||
|
sudo apt-get install libwww-perl libdata-uuid-perl libssl-dev libcrypt-eksblowfish-perl libdata-entropy-perl
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl-
|
||||||
|
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
|
@ -808,7 +808,7 @@ find_package(
|
||||||
Getopt::Long Time::HiRes Date::Manip LWP::UserAgent
|
Getopt::Long Time::HiRes Date::Manip LWP::UserAgent
|
||||||
ExtUtils::MakeMaker ${ZM_MMAP_PERLPACKAGE})
|
ExtUtils::MakeMaker ${ZM_MMAP_PERLPACKAGE})
|
||||||
if(NOT PERLMODULES_FOUND)
|
if(NOT PERLMODULES_FOUND)
|
||||||
message(FATAL_ERROR
|
message(WARNING
|
||||||
"Not all required perl modules were found on your system")
|
"Not all required perl modules were found on your system")
|
||||||
endif(NOT PERLMODULES_FOUND)
|
endif(NOT PERLMODULES_FOUND)
|
||||||
|
|
||||||
|
@ -844,7 +844,7 @@ if(WITH_SYSTEMD)
|
||||||
# Check for polkit
|
# Check for polkit
|
||||||
find_package(Polkit)
|
find_package(Polkit)
|
||||||
if(NOT POLKIT_FOUND)
|
if(NOT POLKIT_FOUND)
|
||||||
message(FATAL_ERROR
|
message(WARNING
|
||||||
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
|
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
|
||||||
endif(NOT POLKIT_FOUND)
|
endif(NOT POLKIT_FOUND)
|
||||||
endif(WITH_SYSTEMD)
|
endif(WITH_SYSTEMD)
|
||||||
|
|
|
@ -285,6 +285,7 @@ CREATE TABLE `Filters` (
|
||||||
`UserId` int(10) unsigned,
|
`UserId` int(10) unsigned,
|
||||||
`Query_json` text NOT NULL,
|
`Query_json` text NOT NULL,
|
||||||
`AutoArchive` tinyint(3) unsigned NOT NULL default '0',
|
`AutoArchive` tinyint(3) unsigned NOT NULL default '0',
|
||||||
|
`AutoUnarchive` tinyint(3) unsigned NOT NULL default '0',
|
||||||
`AutoVideo` tinyint(3) unsigned NOT NULL default '0',
|
`AutoVideo` tinyint(3) unsigned NOT NULL default '0',
|
||||||
`AutoUpload` tinyint(3) unsigned NOT NULL default '0',
|
`AutoUpload` tinyint(3) unsigned NOT NULL default '0',
|
||||||
`AutoEmail` tinyint(3) unsigned NOT NULL default '0',
|
`AutoEmail` tinyint(3) unsigned NOT NULL default '0',
|
||||||
|
@ -537,6 +538,8 @@ CREATE TABLE `Monitors` (
|
||||||
`ArchivedEventDiskSpace` bigint default NULL,
|
`ArchivedEventDiskSpace` bigint default NULL,
|
||||||
`ZoneCount` TINYINT NOT NULL DEFAULT 0,
|
`ZoneCount` TINYINT NOT NULL DEFAULT 0,
|
||||||
`Refresh` int(10) unsigned default NULL,
|
`Refresh` int(10) unsigned default NULL,
|
||||||
|
`Latitude` DECIMAL(10,8),
|
||||||
|
`Longitude` DECIMAL(10,8),
|
||||||
PRIMARY KEY (`Id`)
|
PRIMARY KEY (`Id`)
|
||||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||||
|
|
||||||
|
@ -550,7 +553,7 @@ CREATE TABLE `Monitor_Status` (
|
||||||
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
||||||
`CaptureBandwidth` INT NOT NULL default 0,
|
`CaptureBandwidth` INT NOT NULL default 0,
|
||||||
PRIMARY KEY (`MonitorId`)
|
PRIMARY KEY (`MonitorId`)
|
||||||
) ENGINE=MEMORY;
|
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||||
--
|
--
|
||||||
-- Table structure for table `States`
|
-- Table structure for table `States`
|
||||||
-- PP - Added IsActive to track custom run states
|
-- PP - Added IsActive to track custom run states
|
||||||
|
@ -1023,6 +1026,13 @@ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{
|
||||||
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%","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"} }' );
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
||||||
|
|
||||||
|
CREATE TABLE Sessions (
|
||||||
|
id char(32) not null,
|
||||||
|
access INT(10) UNSIGNED DEFAULT NULL,
|
||||||
|
data text,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
-- 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 @PKGDATADIR@/db/triggers.sql
|
source @PKGDATADIR@/db/triggers.sql
|
||||||
--
|
--
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
--
|
||||||
|
-- Add AutoUnarchive action to Filters
|
||||||
|
--
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Filters'
|
||||||
|
AND column_name = 'AutoUnarchive'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column AutoUunarchive already exists in Filters'",
|
||||||
|
"ALTER TABLE Filters ADD `AutoUnarchive` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoArchive`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -0,0 +1,23 @@
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Monitors'
|
||||||
|
AND column_name = 'Latitude'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column Latitude already exists in Monitors'",
|
||||||
|
"ALTER TABLE `Monitors` ADD `Latitude` DECIMAL(10,8) AFTER `Refresh`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Monitors'
|
||||||
|
AND column_name = 'Longitude'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column Longitude already exists in Monitors'",
|
||||||
|
"ALTER TABLE `Monitors` ADD `Longitude` DECIMAL(10,8) AFTER `Latitude`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* The MEMORY TABLE TYPE IS BAD! Switch to regular InnoDB */
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `Monitor_Status`;
|
||||||
|
CREATE TABLE `Monitor_Status` (
|
||||||
|
`MonitorId` int(10) unsigned NOT NULL,
|
||||||
|
`Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown',
|
||||||
|
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
|
||||||
|
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
||||||
|
`CaptureBandwidth` INT NOT NULL default 0,
|
||||||
|
PRIMARY KEY (`MonitorId`)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
--
|
||||||
|
-- This adds Sessions Table
|
||||||
|
--
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE table_name = 'Sessions'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Sessions table exists'",
|
||||||
|
"CREATE TABLE Sessions (
|
||||||
|
id char(32) not null,
|
||||||
|
access INT(10) UNSIGNED DEFAULT NULL,
|
||||||
|
data text,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
) ENGINE=InnoDB;"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -28,7 +28,7 @@
|
||||||
%global _hardened_build 1
|
%global _hardened_build 1
|
||||||
|
|
||||||
Name: zoneminder
|
Name: zoneminder
|
||||||
Version: 1.35.6
|
Version: 1.35.10
|
||||||
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
|
||||||
|
|
|
@ -17,6 +17,7 @@ Build-Depends: debhelper, dh-systemd, sphinx-doc, python3-sphinx, dh-linktree, d
|
||||||
,libbz2-dev
|
,libbz2-dev
|
||||||
,libgcrypt20-dev
|
,libgcrypt20-dev
|
||||||
,libcurl4-gnutls-dev
|
,libcurl4-gnutls-dev
|
||||||
|
,libjpeg-turbo8-dev | libjpeg62-turbo-dev | libjpeg8-dev | libjpeg9-dev
|
||||||
,libturbojpeg0-dev
|
,libturbojpeg0-dev
|
||||||
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
|
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
|
||||||
,libpcre3-dev
|
,libpcre3-dev
|
||||||
|
@ -32,6 +33,7 @@ Build-Depends: debhelper, dh-systemd, sphinx-doc, python3-sphinx, dh-linktree, d
|
||||||
,libssl-dev
|
,libssl-dev
|
||||||
,libcrypt-eksblowfish-perl
|
,libcrypt-eksblowfish-perl
|
||||||
,libdata-entropy-perl
|
,libdata-entropy-perl
|
||||||
|
,libvncserver-dev
|
||||||
# Unbundled (dh_linktree):
|
# Unbundled (dh_linktree):
|
||||||
,libjs-jquery
|
,libjs-jquery
|
||||||
,libjs-mootools
|
,libjs-mootools
|
||||||
|
@ -80,6 +82,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||||
,libpcre3
|
,libpcre3
|
||||||
,libcrypt-eksblowfish-perl
|
,libcrypt-eksblowfish-perl
|
||||||
,libdata-entropy-perl
|
,libdata-entropy-perl
|
||||||
|
,libvncclient1|libvncclient0
|
||||||
Recommends: ${misc:Recommends}
|
Recommends: ${misc:Recommends}
|
||||||
,libapache2-mod-php | php-fpm
|
,libapache2-mod-php | php-fpm
|
||||||
,mysql-server | mariadb-server | virtual-mysql-server
|
,mysql-server | mariadb-server | virtual-mysql-server
|
||||||
|
|
|
@ -16,17 +16,20 @@ create_db () {
|
||||||
else
|
else
|
||||||
echo "Db exists."
|
echo "Db exists."
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
create_update_user () {
|
||||||
USER_EXISTS="$(mysql --defaults-file=/etc/mysql/debian.cnf -sse "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '$ZM_DB_USER')")"
|
USER_EXISTS="$(mysql --defaults-file=/etc/mysql/debian.cnf -sse "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '$ZM_DB_USER')")"
|
||||||
if [ $USER_EXISTS -ne 1 ]; then
|
if [ $USER_EXISTS -ne 1 ]; then
|
||||||
echo "Creating zm user $ZM_DB_USER"
|
echo "Creating zm user $ZM_DB_USER"
|
||||||
# This creates the user.
|
# This creates the user.
|
||||||
echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
fi
|
fi
|
||||||
|
echo "Updating permissions"
|
||||||
|
echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
}
|
}
|
||||||
|
|
||||||
update_db () {
|
update_db () {
|
||||||
echo "Updating permissions"
|
|
||||||
echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
|
||||||
|
|
||||||
zmupdate.pl --nointeractive
|
zmupdate.pl --nointeractive
|
||||||
zmupdate.pl --nointeractive -f
|
zmupdate.pl --nointeractive -f
|
||||||
|
@ -94,6 +97,7 @@ if [ "$1" = "configure" ]; then
|
||||||
# Make sure systemctl status exit code is 0; i.e. the DB is running
|
# Make sure systemctl status exit code is 0; i.e. the DB is running
|
||||||
if systemctl is-active --quiet "$DBSERVICE"; then
|
if systemctl is-active --quiet "$DBSERVICE"; then
|
||||||
create_db
|
create_db
|
||||||
|
create_update_user
|
||||||
update_db
|
update_db
|
||||||
else
|
else
|
||||||
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||||
|
@ -108,6 +112,7 @@ if [ "$1" = "configure" ]; then
|
||||||
fi
|
fi
|
||||||
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||||
create_db
|
create_db
|
||||||
|
create_update_user
|
||||||
update_db
|
update_db
|
||||||
else
|
else
|
||||||
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||||
|
|
|
@ -479,6 +479,33 @@ our @options = (
|
||||||
type => $types{string},
|
type => $types{string},
|
||||||
category => 'system',
|
category => 'system',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name => 'ZM_OPT_USE_GEOLOCATION',
|
||||||
|
description => 'Add geolocation features to ZoneMinder.',
|
||||||
|
help => 'Whether or not to enable Latitude/Longitude settings on Monitors and enable mapping options.',
|
||||||
|
type => $types{boolean},
|
||||||
|
category => 'system',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'ZM_OPT_GEOLOCATION_TILE_PROVIDER',
|
||||||
|
description => 'Tile provider to use for maps.',
|
||||||
|
help => 'OpenStreetMaps does not itself provide the images to use in the map. There are many to choose from. Mapbox.com is one example that offers free tiles and has been tested during development of this feature.',
|
||||||
|
requires => [
|
||||||
|
{name=>'ZM_OPT_USE_GEOLOCATION', value=>'yes'}
|
||||||
|
],
|
||||||
|
type => $types{string},
|
||||||
|
category => 'system',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'ZM_OPT_GEOLOCATION_ACCESS_TOKEN',
|
||||||
|
description => 'Access Token for the tile provider used for maps.',
|
||||||
|
help => 'OpenStreetMaps does not itself provide the images to use in the map. There are many to choose from. Mapbox.com is one example that offers free tiles and has been tested during development of this feature. You must go to mapbox.com and sign up and get an access token and cutnpaste it here.',
|
||||||
|
requires => [
|
||||||
|
{name=>'ZM_OPT_USE_GEOLOCATION', value=>'yes'}
|
||||||
|
],
|
||||||
|
type => $types{string},
|
||||||
|
category => 'system',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name => 'ZM_SYSTEM_SHUTDOWN',
|
name => 'ZM_SYSTEM_SHUTDOWN',
|
||||||
default => 'true',
|
default => 'true',
|
||||||
|
|
|
@ -58,6 +58,7 @@ Id
|
||||||
Name
|
Name
|
||||||
Query_json
|
Query_json
|
||||||
AutoArchive
|
AutoArchive
|
||||||
|
AutoUnarchive
|
||||||
AutoVideo
|
AutoVideo
|
||||||
AutoUpload
|
AutoUpload
|
||||||
AutoEmail
|
AutoEmail
|
||||||
|
@ -201,28 +202,25 @@ sub Sql {
|
||||||
$self->{Sql} .= 'extract( hour_second from E.EndTime )';
|
$self->{Sql} .= 'extract( hour_second from E.EndTime )';
|
||||||
} elsif ( $term->{attr} eq 'EndWeekday' ) {
|
} elsif ( $term->{attr} eq 'EndWeekday' ) {
|
||||||
$self->{Sql} .= "weekday( E.EndTime )";
|
$self->{Sql} .= "weekday( E.EndTime )";
|
||||||
|
|
||||||
#
|
|
||||||
} elsif ( $term->{attr} eq 'ExistsInFileSystem' ) {
|
} elsif ( $term->{attr} eq 'ExistsInFileSystem' ) {
|
||||||
push @{$self->{PostSQLConditions}}, $term;
|
push @{$self->{PostSQLConditions}}, $term;
|
||||||
} elsif ( $term->{attr} eq 'DiskSpace' ) {
|
$self->{Sql} .= 'TRUE /* ExistsInFileSystem */';
|
||||||
$self->{Sql} .= 'E.DiskSpace';
|
|
||||||
} elsif ( $term->{attr} eq 'DiskPercent' ) {
|
} elsif ( $term->{attr} eq 'DiskPercent' ) {
|
||||||
$self->{Sql} .= 'zmDiskPercent';
|
$self->{Sql} .= 'zmDiskPercent';
|
||||||
$self->{HasDiskPercent} = !undef;
|
$self->{HasDiskPercent} = !undef;
|
||||||
$self->{HasPreCondition} = !undef;
|
|
||||||
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
|
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
|
||||||
$self->{Sql} .= 'zmDiskBlocks';
|
$self->{Sql} .= 'zmDiskBlocks';
|
||||||
$self->{HasDiskBlocks} = !undef;
|
$self->{HasDiskBlocks} = !undef;
|
||||||
$self->{HasPreCondition} = !undef;
|
|
||||||
} elsif ( $term->{attr} eq 'SystemLoad' ) {
|
} elsif ( $term->{attr} eq 'SystemLoad' ) {
|
||||||
$self->{Sql} .= 'zmSystemLoad';
|
$self->{Sql} .= 'zmSystemLoad';
|
||||||
$self->{HasSystemLoad} = !undef;
|
$self->{HasSystemLoad} = !undef;
|
||||||
$self->{HasPreCondition} = !undef;
|
|
||||||
} else {
|
} else {
|
||||||
$self->{Sql} .= 'E.'.$term->{attr};
|
$self->{Sql} .= 'E.'.$term->{attr};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( $term->{attr} eq 'ExistsInFileSystem' ) {
|
||||||
|
# PostCondition, so no further SQL
|
||||||
|
} else {
|
||||||
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
|
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
|
||||||
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
|
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
|
||||||
|
|
||||||
|
@ -297,11 +295,12 @@ sub Sql {
|
||||||
push @value_list, $value;
|
push @value_list, $value;
|
||||||
} # end foreach temp_value
|
} # end foreach temp_value
|
||||||
} # end if has an attr
|
} # end if has an attr
|
||||||
|
|
||||||
if ( $term->{op} ) {
|
if ( $term->{op} ) {
|
||||||
if ( $term->{op} eq '=~' ) {
|
if ( $term->{op} eq '=~' ) {
|
||||||
$self->{Sql} .= " regexp $value";
|
$self->{Sql} .= ' REGEXP '.$value;
|
||||||
} elsif ( $term->{op} eq '!~' ) {
|
} elsif ( $term->{op} eq '!~' ) {
|
||||||
$self->{Sql} .= " not regexp $value";
|
$self->{Sql} .= ' NOT REGEXP '.$value;
|
||||||
} elsif ( $term->{op} eq 'IS' ) {
|
} elsif ( $term->{op} eq 'IS' ) {
|
||||||
if ( $value eq 'Odd' ) {
|
if ( $value eq 'Odd' ) {
|
||||||
$self->{Sql} .= ' % 2 = 1';
|
$self->{Sql} .= ' % 2 = 1';
|
||||||
|
@ -311,21 +310,22 @@ sub Sql {
|
||||||
$self->{Sql} .= " IS $value";
|
$self->{Sql} .= " IS $value";
|
||||||
}
|
}
|
||||||
} elsif ( $term->{op} eq 'EXISTS' ) {
|
} elsif ( $term->{op} eq 'EXISTS' ) {
|
||||||
$self->{Sql} .= " EXISTS $value";
|
$self->{Sql} .= ' EXISTS '.$value;
|
||||||
} elsif ( $term->{op} eq 'IS NOT' ) {
|
} elsif ( $term->{op} eq 'IS NOT' ) {
|
||||||
$self->{Sql} .= " IS NOT $value";
|
$self->{Sql} .= ' IS NOT '.$value;
|
||||||
} elsif ( $term->{op} eq '=[]' ) {
|
} elsif ( $term->{op} eq '=[]' or $term->{op} eq 'IN' ) {
|
||||||
$self->{Sql} .= ' IN ('.join(',', @value_list).')';
|
$self->{Sql} .= ' IN ('.join(',', @value_list).')';
|
||||||
} elsif ( $term->{op} eq '!~' ) {
|
} elsif ( $term->{op} eq '![]' ) {
|
||||||
$self->{Sql} .= ' NOT IN ('.join(',', @value_list).')';
|
$self->{Sql} .= ' NOT IN ('.join(',', @value_list).')';
|
||||||
} elsif ( $term->{op} eq 'LIKE' ) {
|
} elsif ( $term->{op} eq 'LIKE' ) {
|
||||||
$self->{Sql} .= " LIKE $value";
|
$self->{Sql} .= ' LIKE '.$value;
|
||||||
} elsif ( $term->{op} eq 'NOT LIKE' ) {
|
} elsif ( $term->{op} eq 'NOT LIKE' ) {
|
||||||
$self->{Sql} .= " NOT LIKE $value";
|
$self->{Sql} .= ' NOT LIKE '.$value;
|
||||||
} else {
|
} else {
|
||||||
$self->{Sql} .= ' '.$term->{op}.' '.$value;
|
$self->{Sql} .= ' '.$term->{op}.' '.$value;
|
||||||
}
|
}
|
||||||
} # end if has an operator
|
} # end if has an operator
|
||||||
|
} # end if Pre/Post or SQL
|
||||||
if ( exists($term->{cbr}) ) {
|
if ( exists($term->{cbr}) ) {
|
||||||
$self->{Sql} .= ' '.str_repeat(')', $term->{cbr}).' ';
|
$self->{Sql} .= ' '.str_repeat(')', $term->{cbr}).' ';
|
||||||
}
|
}
|
||||||
|
@ -341,6 +341,9 @@ sub Sql {
|
||||||
if ( $self->{AutoArchive} ) {
|
if ( $self->{AutoArchive} ) {
|
||||||
push @auto_terms, 'E.Archived = 0';
|
push @auto_terms, 'E.Archived = 0';
|
||||||
}
|
}
|
||||||
|
if ( $self->{AutoUnarchive} ) {
|
||||||
|
push @auto_terms, 'E.Archived = 1';
|
||||||
|
}
|
||||||
# Don't do this, it prevents re-generation and concatenation.
|
# Don't do this, it prevents re-generation and concatenation.
|
||||||
# If the file already exists, then the video won't be re-recreated
|
# If the file already exists, then the video won't be re-recreated
|
||||||
if ( $self->{AutoVideo} ) {
|
if ( $self->{AutoVideo} ) {
|
||||||
|
@ -394,7 +397,7 @@ sub Sql {
|
||||||
$sort_column = 'E.StartTime';
|
$sort_column = 'E.StartTime';
|
||||||
}
|
}
|
||||||
my $sort_order = $filter_expr->{sort_asc} ? 'ASC' : 'DESC';
|
my $sort_order = $filter_expr->{sort_asc} ? 'ASC' : 'DESC';
|
||||||
$sql .= ' ORDER BY '.$sort_column." ".$sort_order;
|
$sql .= ' ORDER BY '.$sort_column.' '.$sort_order;
|
||||||
if ( $filter_expr->{limit} ) {
|
if ( $filter_expr->{limit} ) {
|
||||||
$sql .= ' LIMIT 0,'.$filter_expr->{limit};
|
$sql .= ' LIMIT 0,'.$filter_expr->{limit};
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,24 @@ $serial = $primary_key = 'Id';
|
||||||
WebColour
|
WebColour
|
||||||
Exif
|
Exif
|
||||||
Sequence
|
Sequence
|
||||||
|
TotalEvents
|
||||||
|
TotalEventDiskSpace
|
||||||
|
HourEvents
|
||||||
|
HourEventDiskSpace
|
||||||
|
DayEvents
|
||||||
|
DayEventDiskSpace
|
||||||
|
WeekEvents
|
||||||
|
WeekEventDiskSpace
|
||||||
|
MonthEvents
|
||||||
|
MonthEventDiskSpace
|
||||||
|
ArchivedEvents
|
||||||
|
ArchivedEventDiskSpace
|
||||||
|
ZoneCount
|
||||||
|
Refresh
|
||||||
|
DefaultCodec
|
||||||
|
GroupIds
|
||||||
|
Latitude
|
||||||
|
Longitude
|
||||||
);
|
);
|
||||||
|
|
||||||
%defaults = (
|
%defaults = (
|
||||||
|
@ -201,6 +219,23 @@ $serial = $primary_key = 'Id';
|
||||||
WebColour => '#ff0000',
|
WebColour => '#ff0000',
|
||||||
Exif => 0,
|
Exif => 0,
|
||||||
Sequence => undef,
|
Sequence => undef,
|
||||||
|
TotalEvents => undef,
|
||||||
|
TotalEventDiskSpace => undef,
|
||||||
|
HourEvents => undef,
|
||||||
|
HourEventDiskSpace => undef,
|
||||||
|
DayEvents => undef,
|
||||||
|
DayEventDiskSpace => undef,
|
||||||
|
WeekEvents => undef,
|
||||||
|
WeekEventDiskSpace => undef,
|
||||||
|
MonthEvents => undef,
|
||||||
|
MonthEventDiskSpace => undef,
|
||||||
|
ArchivedEvents => undef,
|
||||||
|
ArchivedEventDiskSpace => undef,
|
||||||
|
ZoneCount => 0,
|
||||||
|
Refresh => undef,
|
||||||
|
DefaultCodec => 'auto',
|
||||||
|
Latitude => undef,
|
||||||
|
Longitude => undef,
|
||||||
);
|
);
|
||||||
|
|
||||||
sub Server {
|
sub Server {
|
||||||
|
@ -211,6 +246,30 @@ sub Storage {
|
||||||
return new ZoneMinder::Storage( $_[0]{StorageId} );
|
return new ZoneMinder::Storage( $_[0]{StorageId} );
|
||||||
} # end sub Storage
|
} # end sub Storage
|
||||||
|
|
||||||
|
sub control {
|
||||||
|
my $monitor = shift;
|
||||||
|
my $command = shift;
|
||||||
|
my $process = shift;
|
||||||
|
|
||||||
|
if ( $command eq 'stop' or $command eq 'restart' ) {
|
||||||
|
if ( $process ) {
|
||||||
|
`/usr/bin/zmdc.pl stop $process -m $$monitor{Id}`;
|
||||||
|
} else {
|
||||||
|
`/usr/bin/zmdc.pl stop zma -m $$monitor{Id}`;
|
||||||
|
`/usr/bin/zmdc.pl stop zmc -m $$monitor{Id}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( $command eq 'start' or $command eq 'restart' ) {
|
||||||
|
if ( $process ) {
|
||||||
|
`/usr/bin/zmdc.pl start $process -m $$monitor{Id}`;
|
||||||
|
} else {
|
||||||
|
`/usr/bin/zmdc.pl start zmc -m $$monitor{Id}`;
|
||||||
|
`/usr/bin/zmdc.pl start zma -m $$monitor{Id}`;
|
||||||
|
} # end if
|
||||||
|
}
|
||||||
|
} # end sub control
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
# ==========================================================================
|
||||||
|
#
|
||||||
|
# ZoneMinder Zone Module
|
||||||
|
# Copyright (C) 2020 ZoneMinder LLC
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# ==========================================================================
|
||||||
|
|
||||||
|
package ZoneMinder::Zone;
|
||||||
|
|
||||||
|
use 5.006;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
require ZoneMinder::Base;
|
||||||
|
require ZoneMinder::Object;
|
||||||
|
|
||||||
|
#our @ISA = qw(Exporter ZoneMinder::Base);
|
||||||
|
use parent qw(ZoneMinder::Object);
|
||||||
|
|
||||||
|
use vars qw/ $table $primary_key %fields $serial %defaults $debug/;
|
||||||
|
$table = 'Zones';
|
||||||
|
$serial = $primary_key = 'Id';
|
||||||
|
%fields = map { $_ => $_ } qw(
|
||||||
|
Id
|
||||||
|
Name
|
||||||
|
MonitorId
|
||||||
|
Type
|
||||||
|
Units
|
||||||
|
CheckMethod
|
||||||
|
MinPixelThreshold
|
||||||
|
MaxPixelThreshold
|
||||||
|
MinAlarmPixels
|
||||||
|
MaxAlarmPixels
|
||||||
|
FilterX
|
||||||
|
FilterY
|
||||||
|
MinFilterPixels
|
||||||
|
MaxFilterPixels
|
||||||
|
MinBlobPixels
|
||||||
|
MaxBlobPixels
|
||||||
|
MinBlobs
|
||||||
|
MaxBlobs
|
||||||
|
OverloadFrames
|
||||||
|
ExtendAlarmFrames
|
||||||
|
);
|
||||||
|
|
||||||
|
%defaults = (
|
||||||
|
Name => '',
|
||||||
|
Type => 'Active',
|
||||||
|
Units => 'Pixels',
|
||||||
|
CheckMethod => 'Blobs',
|
||||||
|
MinPixelThreshold => undef,
|
||||||
|
MaxPixelThreshold => undef,
|
||||||
|
MinAlarmPixels => undef,
|
||||||
|
MaxAlarmPixels => undef,
|
||||||
|
FilterX => undef,
|
||||||
|
FilterY => undef,
|
||||||
|
MinFilterPixels => undef,
|
||||||
|
MaxFilterPixels => undef,
|
||||||
|
MinBlobPixels => undef,
|
||||||
|
MaxBlobPixels => undef,
|
||||||
|
MinBlobs => undef,
|
||||||
|
MaxBlobs => undef,
|
||||||
|
OverloadFrames => 0,
|
||||||
|
ExtendAlarmFrames => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
ZoneMinder::Zone - Perl Class for Zones
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use ZoneMinder::Zone;
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
|
||||||
|
|
||||||
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
|
Copyright (C) 2001-2017 ZoneMinder LLC
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or modify
|
||||||
|
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||||
|
at your option, any later version of Perl 5 you may have available.
|
||||||
|
|
||||||
|
|
||||||
|
=cut
|
|
@ -98,6 +98,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
|
||||||
;
|
;
|
||||||
|
|
||||||
logInit($filter_id?(id=>'zmfilter_'.$filter_id):());
|
logInit($filter_id?(id=>'zmfilter_'.$filter_id):());
|
||||||
|
|
||||||
sub HupHandler {
|
sub HupHandler {
|
||||||
# This idea at this time is to just exit, freeing up the memory.
|
# This idea at this time is to just exit, freeing up the memory.
|
||||||
# zmfilter.pl will be respawned by zmdc.
|
# zmfilter.pl will be respawned by zmdc.
|
||||||
|
@ -236,6 +237,7 @@ sub getFilters {
|
||||||
$sql .= ' `Background` = 1 AND';
|
$sql .= ' `Background` = 1 AND';
|
||||||
}
|
}
|
||||||
$sql .= '( `AutoArchive` = 1
|
$sql .= '( `AutoArchive` = 1
|
||||||
|
or `AutoUnarchive` = 1
|
||||||
or `AutoVideo` = 1
|
or `AutoVideo` = 1
|
||||||
or `AutoUpload` = 1
|
or `AutoUpload` = 1
|
||||||
or `AutoEmail` = 1
|
or `AutoEmail` = 1
|
||||||
|
@ -282,6 +284,7 @@ sub checkFilter {
|
||||||
join(', ',
|
join(', ',
|
||||||
($filter->{AutoDelete}?'delete':()),
|
($filter->{AutoDelete}?'delete':()),
|
||||||
($filter->{AutoArchive}?'archive':()),
|
($filter->{AutoArchive}?'archive':()),
|
||||||
|
($filter->{AutoUnarchive}?'unarchive':()),
|
||||||
($filter->{AutoVideo}?'video':()),
|
($filter->{AutoVideo}?'video':()),
|
||||||
($filter->{AutoUpload}?'upload':()),
|
($filter->{AutoUpload}?'upload':()),
|
||||||
($filter->{AutoEmail}?'email':()),
|
($filter->{AutoEmail}?'email':()),
|
||||||
|
@ -299,7 +302,7 @@ sub checkFilter {
|
||||||
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} ) {
|
||||||
|
@ -311,6 +314,15 @@ sub checkFilter {
|
||||||
my $res = $sth->execute($Event->{Id})
|
my $res = $sth->execute($Event->{Id})
|
||||||
or Error("Unable to execute '$sql': ".$dbh->errstr());
|
or Error("Unable to execute '$sql': ".$dbh->errstr());
|
||||||
}
|
}
|
||||||
|
if ( $filter->{AutoUnarchive} ) {
|
||||||
|
Info("Unarchiving event $Event->{Id}");
|
||||||
|
# Do it individually to avoid locking up the table for new events
|
||||||
|
my $sql = 'UPDATE `Events` SET `Archived` = 0 WHERE `Id` = ?';
|
||||||
|
my $sth = $dbh->prepare_cached($sql)
|
||||||
|
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||||
|
my $res = $sth->execute($Event->{Id})
|
||||||
|
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);
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
//#define USE_PREPARED_SQL 1
|
//#define USE_PREPARED_SQL 1
|
||||||
|
|
||||||
const char * Event::frame_type_names[3] = { "Normal", "Bulk", "Alarm" };
|
const char * Event::frame_type_names[3] = { "Normal", "Bulk", "Alarm" };
|
||||||
|
char frame_insert_sql[ZM_SQL_LGE_BUFSIZ] = "INSERT INTO `Frames` (`EventId`, `FrameId`, `Type`, `TimeStamp`, `Delta`, `Score`) VALUES ";
|
||||||
|
|
||||||
int Event::pre_alarm_count = 0;
|
int Event::pre_alarm_count = 0;
|
||||||
|
|
||||||
|
@ -109,9 +110,11 @@ Event::Event(
|
||||||
|
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't insert event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
|
||||||
db_mutex.unlock();
|
db_mutex.unlock();
|
||||||
|
Error("Can't insert event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
Debug(2, "Created new event with %s", sql);
|
||||||
}
|
}
|
||||||
id = mysql_insert_id(&dbconn);
|
id = mysql_insert_id(&dbconn);
|
||||||
|
|
||||||
|
@ -219,8 +222,8 @@ Event::Event(
|
||||||
video_name = stringtf("%" PRIu64 "-%s.%s", id, "video", container.c_str());
|
video_name = stringtf("%" PRIu64 "-%s.%s", id, "video", container.c_str());
|
||||||
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
|
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
|
||||||
db_mutex.unlock();
|
db_mutex.unlock();
|
||||||
|
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
video_file = path + "/" + video_name;
|
video_file = path + "/" + video_name;
|
||||||
|
@ -479,8 +482,9 @@ void Event::AddFrames(int n_frames, Image **images, struct timeval **timestamps)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, struct timeval **timestamps) {
|
void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, struct timeval **timestamps) {
|
||||||
static char sql[ZM_SQL_LGE_BUFSIZ];
|
char *frame_insert_values = (char *)&frame_insert_sql + 90; // 90 == strlen(frame_insert_sql);
|
||||||
strncpy(sql, "INSERT INTO `Frames` (`EventId`, `FrameId`, `TimeStamp`, `Delta`) VALUES ", sizeof(sql));
|
//static char sql[ZM_SQL_LGE_BUFSIZ];
|
||||||
|
//strncpy(sql, "INSERT INTO `Frames` (`EventId`, `FrameId`, `TimeStamp`, `Delta`) VALUES ", sizeof(sql));
|
||||||
int frameCount = 0;
|
int frameCount = 0;
|
||||||
for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) {
|
for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) {
|
||||||
if ( timestamps[i]->tv_sec <= 0 ) {
|
if ( timestamps[i]->tv_sec <= 0 ) {
|
||||||
|
@ -520,21 +524,24 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
|
||||||
delta_time.sec = 0;
|
delta_time.sec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sql_len = strlen(sql);
|
frame_insert_values += snprintf(frame_insert_values,
|
||||||
snprintf(sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ",
|
sizeof(frame_insert_sql)-(frame_insert_values-(char *)&frame_insert_sql),
|
||||||
|
"\n( %" PRIu64 ", %d, 'Normal', from_unixtime(%ld), %s%ld.%02ld, 0 ),",
|
||||||
id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec);
|
id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec);
|
||||||
|
|
||||||
frameCount++;
|
frameCount++;
|
||||||
} // end foreach frame
|
} // end foreach frame
|
||||||
|
|
||||||
if ( frameCount ) {
|
if ( frameCount ) {
|
||||||
Debug(1, "Adding %d/%d frames to DB", frameCount, n_frames);
|
*(frame_insert_values-1) = '\0';
|
||||||
*(sql+strlen(sql)-2) = '\0';
|
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
int rc = mysql_query(&dbconn, frame_insert_sql);
|
||||||
Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), sql);
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
db_mutex.unlock();
|
||||||
|
if ( rc ) {
|
||||||
|
Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), frame_insert_sql);
|
||||||
|
} else {
|
||||||
|
Debug(1, "INSERT %d/%d frames sql %s", frameCount, n_frames, frame_insert_sql);
|
||||||
|
}
|
||||||
last_db_frame = frames;
|
last_db_frame = frames;
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "No valid pre-capture frames to add");
|
Debug(1, "No valid pre-capture frames to add");
|
||||||
|
@ -559,16 +566,15 @@ void Event::AddPacket(ZMPacket *packet, int score, Image *alarm_image) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Event::WriteDbFrames() {
|
void Event::WriteDbFrames() {
|
||||||
static char sql[ZM_SQL_LGE_BUFSIZ];
|
char *frame_insert_values_ptr = (char *)&frame_insert_sql + 90; // 90 == strlen(frame_insert_sql);
|
||||||
char * sql_ptr = (char *)&sql;
|
|
||||||
sql_ptr += snprintf(sql, sizeof(sql),
|
|
||||||
"INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) VALUES "
|
|
||||||
);
|
|
||||||
while ( frame_data.size() ) {
|
while ( frame_data.size() ) {
|
||||||
Frame *frame = frame_data.front();
|
Frame *frame = frame_data.front();
|
||||||
frame_data.pop();
|
frame_data.pop();
|
||||||
sql_ptr += snprintf(sql_ptr, sizeof(sql)-(sql_ptr-(char *)&sql), "( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d ), ",
|
frame_insert_values_ptr += snprintf(frame_insert_values_ptr,
|
||||||
id, frame->frame_id, frame_type_names[frame->type],
|
sizeof(frame_insert_sql)-(frame_insert_values_ptr-(char *)&frame_insert_sql),
|
||||||
|
"\n( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d ),",
|
||||||
|
id, frame->frame_id,
|
||||||
|
frame_type_names[frame->type],
|
||||||
frame->timestamp.tv_sec,
|
frame->timestamp.tv_sec,
|
||||||
frame->delta.positive?"":"-",
|
frame->delta.positive?"":"-",
|
||||||
frame->delta.sec,
|
frame->delta.sec,
|
||||||
|
@ -576,14 +582,17 @@ void Event::WriteDbFrames() {
|
||||||
frame->score);
|
frame->score);
|
||||||
delete frame;
|
delete frame;
|
||||||
}
|
}
|
||||||
*(sql_ptr-2) = '\0';
|
*(frame_insert_values_ptr-1) = '\0'; // The -2 is for the extra , added for values above
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
int rc = mysql_query(&dbconn, frame_insert_sql);
|
||||||
db_mutex.unlock();
|
db_mutex.unlock();
|
||||||
Error("Can't insert frames: %s, sql was %s", mysql_error(&dbconn), sql);
|
|
||||||
|
if ( rc ) {
|
||||||
|
Error("Can't insert frames: %s, sql was %s", mysql_error(&dbconn), frame_insert_sql);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
Debug(1, "INSERT FRAMES: sql was %s", frame_insert_sql);
|
||||||
}
|
}
|
||||||
db_mutex.unlock();
|
|
||||||
} // end void Event::WriteDbFrames()
|
} // end void Event::WriteDbFrames()
|
||||||
|
|
||||||
// Subtract an offset time from frames deltas to match with video start time
|
// Subtract an offset time from frames deltas to match with video start time
|
||||||
|
@ -666,20 +675,18 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
struct DeltaTimeval delta_time;
|
struct DeltaTimeval delta_time;
|
||||||
DELTA_TIMEVAL(delta_time, timestamp, start_time, DT_PREC_2);
|
DELTA_TIMEVAL(delta_time, timestamp, start_time, DT_PREC_2);
|
||||||
|
Debug(1, "Frame delta is %d.%d - %d.%d = %d.%d",
|
||||||
|
start_time.tv_sec, start_time.tv_usec, timestamp.tv_sec, timestamp.tv_usec, delta_time.sec, delta_time.fsec);
|
||||||
|
|
||||||
// The idea is to write out 1/sec
|
// The idea is to write out 1/sec
|
||||||
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
|
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
|
||||||
double fps = monitor->get_capture_fps();
|
double fps = monitor->get_capture_fps();
|
||||||
if ( write_to_db || ( fps && (frame_data.size() > fps) ) ) {
|
if ( write_to_db or ( monitor->get_fps() and (frame_data.size() > monitor->get_fps())) or frame_type==BULK ) {
|
||||||
Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > fps %f",
|
Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > capture fps %f or BULK",
|
||||||
frame_data.size(), write_to_db, fps);
|
frame_data.size(), write_to_db, fps);
|
||||||
WriteDbFrames();
|
WriteDbFrames();
|
||||||
last_db_frame = frames;
|
last_db_frame = frames;
|
||||||
Debug(1, "Adding %d frames to DB, done", frame_data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are writing a Bulk frame
|
|
||||||
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?"":"-" ),
|
||||||
|
@ -703,5 +710,4 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||||
} // end if db_frame
|
} // end if db_frame
|
||||||
|
|
||||||
end_time = timestamp;
|
end_time = timestamp;
|
||||||
|
|
||||||
} // end void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image)
|
} // end void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image)
|
||||||
|
|
|
@ -117,6 +117,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"SELECT `MonitorId`, `StorageId`, `Frames`, unix_timestamp( `StartTime` ) AS StartTimestamp, "
|
"SELECT `MonitorId`, `StorageId`, `Frames`, unix_timestamp( `StartTime` ) AS StartTimestamp, "
|
||||||
|
"unix_timestamp( `EndTime` ) AS EndTimestamp, "
|
||||||
"(SELECT max(`Delta`)-min(`Delta`) FROM `Frames` WHERE `EventId`=`Events`.`Id`) AS Duration, "
|
"(SELECT max(`Delta`)-min(`Delta`) FROM `Frames` WHERE `EventId`=`Events`.`Id`) AS Duration, "
|
||||||
"`DefaultVideo`, `Scheme`, `SaveJPEGs`, `Orientation`+0 FROM `Events` WHERE `Id` = %" PRIu64, event_id);
|
"`DefaultVideo`, `Scheme`, `SaveJPEGs`, `Orientation`+0 FROM `Events` WHERE `Id` = %" PRIu64, event_id);
|
||||||
|
|
||||||
|
@ -150,9 +151,10 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0;
|
event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0;
|
||||||
event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]);
|
event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]);
|
||||||
event_data->start_time = atoi(dbrow[3]);
|
event_data->start_time = atoi(dbrow[3]);
|
||||||
event_data->duration = dbrow[4] ? atof(dbrow[4]) : 0.0;
|
event_data->end_time = dbrow[4] ? atoi(dbrow[4]) : 0;
|
||||||
strncpy(event_data->video_file, dbrow[5], sizeof(event_data->video_file)-1);
|
event_data->duration = dbrow[5] ? atof(dbrow[5]) : 0.0;
|
||||||
std::string scheme_str = std::string(dbrow[6]);
|
strncpy(event_data->video_file, dbrow[6], sizeof(event_data->video_file)-1);
|
||||||
|
std::string scheme_str = std::string(dbrow[7]);
|
||||||
if ( scheme_str == "Deep" ) {
|
if ( scheme_str == "Deep" ) {
|
||||||
event_data->scheme = Storage::DEEP;
|
event_data->scheme = Storage::DEEP;
|
||||||
} else if ( scheme_str == "Medium" ) {
|
} else if ( scheme_str == "Medium" ) {
|
||||||
|
@ -160,8 +162,8 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
} else {
|
} else {
|
||||||
event_data->scheme = Storage::SHALLOW;
|
event_data->scheme = Storage::SHALLOW;
|
||||||
}
|
}
|
||||||
event_data->SaveJPEGs = dbrow[7] == nullptr ? 0 : atoi(dbrow[7]);
|
event_data->SaveJPEGs = dbrow[8] == nullptr ? 0 : atoi(dbrow[8]);
|
||||||
event_data->Orientation = (Monitor::Orientation)(dbrow[8] == nullptr ? 0 : atoi(dbrow[8]));
|
event_data->Orientation = (Monitor::Orientation)(dbrow[9] == nullptr ? 0 : atoi(dbrow[9]));
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
|
|
||||||
if ( !monitor ) {
|
if ( !monitor ) {
|
||||||
|
@ -223,8 +225,6 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFrameRate((double)event_data->frame_count/event_data->duration);
|
updateFrameRate((double)event_data->frame_count/event_data->duration);
|
||||||
Debug(3, "fps set by frame_count(%d)/duration(%f)",
|
|
||||||
event_data->frame_count, event_data->duration);
|
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "SELECT `FrameId`, unix_timestamp(`TimeStamp`), `Delta` "
|
snprintf(sql, sizeof(sql), "SELECT `FrameId`, unix_timestamp(`TimeStamp`), `Delta` "
|
||||||
"FROM `Frames` WHERE `EventId` = %" PRIu64 " ORDER BY `FrameId` ASC", event_id);
|
"FROM `Frames` WHERE `EventId` = %" PRIu64 " ORDER BY `FrameId` ASC", event_id);
|
||||||
|
@ -284,11 +284,13 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
event_data->frames[id-1].in_db
|
event_data->frames[id-1].in_db
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Incomplete events might not have any frame data
|
||||||
|
event_data->last_frame_id = last_id;
|
||||||
|
|
||||||
if ( mysql_errno(&dbconn) ) {
|
if ( mysql_errno(&dbconn) ) {
|
||||||
Error("Can't fetch row: %s", mysql_error(&dbconn));
|
Error("Can't fetch row: %s", mysql_error(&dbconn));
|
||||||
exit(mysql_errno(&dbconn));
|
exit(mysql_errno(&dbconn));
|
||||||
}
|
}
|
||||||
|
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
|
|
||||||
if ( event_data->video_file[0] || (monitor->GetOptVideoWriter() > 0) ) {
|
if ( event_data->video_file[0] || (monitor->GetOptVideoWriter() > 0) ) {
|
||||||
|
@ -296,9 +298,10 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
snprintf(event_data->video_file, sizeof(event_data->video_file), "%" PRIu64 "-%s", event_data->event_id, "video.mp4");
|
snprintf(event_data->video_file, sizeof(event_data->video_file), "%" PRIu64 "-%s", event_data->event_id, "video.mp4");
|
||||||
}
|
}
|
||||||
std::string filepath = std::string(event_data->path) + "/" + std::string(event_data->video_file);
|
std::string filepath = std::string(event_data->path) + "/" + std::string(event_data->video_file);
|
||||||
//char filepath[PATH_MAX];
|
|
||||||
//snprintf(filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file);
|
|
||||||
Debug(1, "Loading video file from %s", filepath.c_str());
|
Debug(1, "Loading video file from %s", filepath.c_str());
|
||||||
|
if ( ffmpeg_input )
|
||||||
|
delete ffmpeg_input;
|
||||||
|
|
||||||
ffmpeg_input = new FFmpeg_Input();
|
ffmpeg_input = new FFmpeg_Input();
|
||||||
if ( 0 > ffmpeg_input->Open(filepath.c_str()) ) {
|
if ( 0 > ffmpeg_input->Open(filepath.c_str()) ) {
|
||||||
Warning("Unable to open ffmpeg_input %s", filepath.c_str());
|
Warning("Unable to open ffmpeg_input %s", filepath.c_str());
|
||||||
|
@ -307,14 +310,15 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not sure about this
|
||||||
if ( forceEventChange || mode == MODE_ALL_GAPLESS ) {
|
if ( forceEventChange || mode == MODE_ALL_GAPLESS ) {
|
||||||
if ( replay_rate > 0 )
|
if ( replay_rate > 0 )
|
||||||
curr_stream_time = event_data->frames[0].timestamp;
|
curr_stream_time = event_data->frames[0].timestamp;
|
||||||
else
|
else
|
||||||
curr_stream_time = event_data->frames[event_data->frame_count-1].timestamp;
|
curr_stream_time = event_data->frames[event_data->last_frame_id-1].timestamp;
|
||||||
}
|
}
|
||||||
Debug(2, "Event:%" PRIu64 ", Frames:%ld, Duration: %.2f",
|
Debug(2, "Event:%" PRIu64 ", Frames:%ld, Last Frame ID(%ld, Duration: %.2f",
|
||||||
event_data->event_id, event_data->frame_count, event_data->duration);
|
event_data->event_id, event_data->frame_count, event_data->last_frame_id, event_data->duration);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} // bool EventStream::loadEventData( int event_id )
|
} // bool EventStream::loadEventData( int event_id )
|
||||||
|
@ -341,12 +345,12 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
if (
|
if (
|
||||||
(mode == MODE_SINGLE || mode == MODE_NONE)
|
(mode == MODE_SINGLE || mode == MODE_NONE)
|
||||||
&&
|
&&
|
||||||
((unsigned int)curr_frame_id == event_data->frame_count)
|
((unsigned int)curr_frame_id == event_data->last_frame_id)
|
||||||
) {
|
) {
|
||||||
Debug(1, "Was in single or no replay mode, and at last frame, so jumping to 1st frame");
|
Debug(1, "Was in single or no replay mode, and at last frame, so jumping to 1st frame");
|
||||||
curr_frame_id = 1;
|
curr_frame_id = 1;
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "mode is %s, current frame is %d, frame count is %d",
|
Debug(1, "mode is %s, current frame is %ld, frame count is %ld, last frame id is %ld",
|
||||||
(mode == MODE_SINGLE ? "single" : "not single"),
|
(mode == MODE_SINGLE ? "single" : "not single"),
|
||||||
curr_frame_id, event_data->frame_count );
|
curr_frame_id, event_data->frame_count );
|
||||||
}
|
}
|
||||||
|
@ -359,6 +363,13 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
paused = false;
|
paused = false;
|
||||||
}
|
}
|
||||||
replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768;
|
replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768;
|
||||||
|
if ( replay_rate > 50 * ZM_RATE_BASE ) {
|
||||||
|
Warning("requested replay rate (%d) is too high. We only support up to 50x", replay_rate);
|
||||||
|
replay_rate = 50 * ZM_RATE_BASE;
|
||||||
|
} else if ( replay_rate < -50*ZM_RATE_BASE ) {
|
||||||
|
Warning("requested replay rate (%d) is too low. We only support up to -50x", replay_rate);
|
||||||
|
replay_rate = -50 * ZM_RATE_BASE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_STOP :
|
case CMD_STOP :
|
||||||
Debug(1, "Got STOP command");
|
Debug(1, "Got STOP command");
|
||||||
|
@ -394,7 +405,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
paused = true;
|
paused = true;
|
||||||
replay_rate = ZM_RATE_BASE;
|
replay_rate = ZM_RATE_BASE;
|
||||||
step = 1;
|
step = 1;
|
||||||
if ( (unsigned int)curr_frame_id < event_data->frame_count )
|
if ( (unsigned int)curr_frame_id < event_data->last_frame_id )
|
||||||
curr_frame_id += 1;
|
curr_frame_id += 1;
|
||||||
Debug(1, "Got SLOWFWD command new frame id %d", curr_frame_id);
|
Debug(1, "Got SLOWFWD command new frame id %d", curr_frame_id);
|
||||||
break;
|
break;
|
||||||
|
@ -411,6 +422,8 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
paused = false;
|
paused = false;
|
||||||
// Set play rate
|
// Set play rate
|
||||||
switch ( replay_rate ) {
|
switch ( replay_rate ) {
|
||||||
|
case -1 * ZM_RATE_BASE :
|
||||||
|
replay_rate = -2 * ZM_RATE_BASE;
|
||||||
case -2 * ZM_RATE_BASE :
|
case -2 * ZM_RATE_BASE :
|
||||||
replay_rate = -5 * ZM_RATE_BASE;
|
replay_rate = -5 * ZM_RATE_BASE;
|
||||||
break;
|
break;
|
||||||
|
@ -425,7 +438,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
replay_rate = -50 * ZM_RATE_BASE;
|
replay_rate = -50 * ZM_RATE_BASE;
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
replay_rate = -2 * ZM_RATE_BASE;
|
replay_rate = -1 * ZM_RATE_BASE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -489,14 +502,14 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
if ( replay_rate >= 0 )
|
if ( replay_rate >= 0 )
|
||||||
curr_frame_id = 0;
|
curr_frame_id = 0;
|
||||||
else
|
else
|
||||||
curr_frame_id = event_data->frame_count+1;
|
curr_frame_id = event_data->last_frame_id+1;
|
||||||
paused = false;
|
paused = false;
|
||||||
forceEventChange = true;
|
forceEventChange = true;
|
||||||
break;
|
break;
|
||||||
case CMD_NEXT :
|
case CMD_NEXT :
|
||||||
Debug(1, "Got NEXT command");
|
Debug(1, "Got NEXT command");
|
||||||
if ( replay_rate >= 0 )
|
if ( replay_rate >= 0 )
|
||||||
curr_frame_id = event_data->frame_count+1;
|
curr_frame_id = event_data->last_frame_id+1;
|
||||||
else
|
else
|
||||||
curr_frame_id = 0;
|
curr_frame_id = 0;
|
||||||
paused = false;
|
paused = false;
|
||||||
|
@ -505,9 +518,33 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
case CMD_SEEK :
|
case CMD_SEEK :
|
||||||
{
|
{
|
||||||
// offset is in seconds
|
// offset is in seconds
|
||||||
int offset = ((unsigned char)msg->msg_data[1]<<24)|((unsigned char)msg->msg_data[2]<<16)|((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
|
||||||
curr_frame_id = (int)(event_data->frame_count*offset/event_data->duration);
|
int int_part = ((unsigned char)msg->msg_data[1]<<24)|((unsigned char)msg->msg_data[2]<<16)|((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||||
Debug(1, "Got SEEK command, to %d (new cfid: %d)", offset, curr_frame_id);
|
int dec_part = ((unsigned char)msg->msg_data[5]<<24)|((unsigned char)msg->msg_data[6]<<16)|((unsigned char)msg->msg_data[7]<<8)|(unsigned char)msg->msg_data[8];
|
||||||
|
|
||||||
|
double offset = (double)int_part + (double)(dec_part / (double)1000000);
|
||||||
|
if ( offset < 0.0 ) {
|
||||||
|
Warning("Invalid offset, not seeking");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// This should get us close, but not all frames will have the same duration
|
||||||
|
curr_frame_id = (int)(event_data->frame_count*offset/event_data->duration)+1;
|
||||||
|
if ( event_data->frames[curr_frame_id-1].offset > offset ) {
|
||||||
|
while ( (curr_frame_id --) && ( event_data->frames[curr_frame_id-1].offset > offset ) ) {
|
||||||
|
}
|
||||||
|
} else if ( event_data->frames[curr_frame_id-1].offset < offset ) {
|
||||||
|
while ( (curr_frame_id ++) && ( event_data->frames[curr_frame_id-1].offset > offset ) ) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( curr_frame_id < 1 ) {
|
||||||
|
curr_frame_id = 1;
|
||||||
|
} else if ( curr_frame_id > event_data->last_frame_id ) {
|
||||||
|
curr_frame_id = event_data->last_frame_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr_stream_time = event_data->frames[curr_frame_id-1].timestamp;
|
||||||
|
Debug(1, "Got SEEK command, to %f (new current frame id: %d offset %f)",
|
||||||
|
offset, curr_frame_id, event_data->frames[curr_frame_id-1].offset);
|
||||||
send_frame = true;
|
send_frame = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -524,19 +561,22 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint64_t event_id;
|
uint64_t event_id;
|
||||||
int progress;
|
double duration;
|
||||||
|
double progress;
|
||||||
int rate;
|
int rate;
|
||||||
int zoom;
|
int zoom;
|
||||||
bool paused;
|
bool paused;
|
||||||
} status_data;
|
} status_data;
|
||||||
|
|
||||||
status_data.event_id = event_data->event_id;
|
status_data.event_id = event_data->event_id;
|
||||||
status_data.progress = (int)event_data->frames[curr_frame_id-1].offset;
|
status_data.duration = event_data->duration;
|
||||||
|
status_data.progress = event_data->frames[curr_frame_id-1].offset;
|
||||||
status_data.rate = replay_rate;
|
status_data.rate = replay_rate;
|
||||||
status_data.zoom = zoom;
|
status_data.zoom = zoom;
|
||||||
status_data.paused = paused;
|
status_data.paused = paused;
|
||||||
Debug(2, "Event:%" PRIu64 ", Paused:%d, progress:%d Rate:%d, Zoom:%d",
|
Debug(2, "Event:%" PRIu64 ", Duration %f, Paused:%d, progress:%f Rate:%d, Zoom:%d",
|
||||||
status_data.event_id,
|
status_data.event_id,
|
||||||
|
status_data.duration,
|
||||||
status_data.paused,
|
status_data.paused,
|
||||||
status_data.progress,
|
status_data.progress,
|
||||||
status_data.rate,
|
status_data.rate,
|
||||||
|
@ -568,7 +608,14 @@ bool EventStream::checkEventLoaded() {
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||||
event_data->monitor_id, event_data->event_id);
|
event_data->monitor_id, event_data->event_id);
|
||||||
} else if ( (unsigned int)curr_frame_id > event_data->frame_count ) {
|
} else if ( (unsigned int)curr_frame_id > event_data->last_frame_id ) {
|
||||||
|
if ( !event_data->end_time ) {
|
||||||
|
// We are viewing an in-process event, so just reload it.
|
||||||
|
loadEventData(event_data->event_id);
|
||||||
|
if ( (unsigned int)curr_frame_id > event_data->last_frame_id )
|
||||||
|
curr_frame_id = event_data->last_frame_id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||||
event_data->monitor_id, event_data->event_id);
|
event_data->monitor_id, event_data->event_id);
|
||||||
|
@ -581,6 +628,7 @@ bool EventStream::checkEventLoaded() {
|
||||||
|
|
||||||
// Event change required.
|
// Event change required.
|
||||||
if ( forceEventChange || ( (mode != MODE_SINGLE) && (mode != MODE_NONE) ) ) {
|
if ( forceEventChange || ( (mode != MODE_SINGLE) && (mode != MODE_NONE) ) ) {
|
||||||
|
Debug(1, "Checking for next event %s", sql);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
exit(mysql_errno(&dbconn));
|
exit(mysql_errno(&dbconn));
|
||||||
|
@ -591,6 +639,9 @@ bool EventStream::checkEventLoaded() {
|
||||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||||
exit(mysql_errno(&dbconn));
|
exit(mysql_errno(&dbconn));
|
||||||
}
|
}
|
||||||
|
if ( mysql_num_rows(result) != 1 ) {
|
||||||
|
Debug(1, "No rows returned for %s", sql);
|
||||||
|
}
|
||||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||||
|
|
||||||
if ( mysql_errno(&dbconn)) {
|
if ( mysql_errno(&dbconn)) {
|
||||||
|
@ -605,7 +656,7 @@ bool EventStream::checkEventLoaded() {
|
||||||
loadEventData(event_id);
|
loadEventData(event_id);
|
||||||
|
|
||||||
if ( replay_rate < 0 ) // rewind
|
if ( replay_rate < 0 ) // rewind
|
||||||
curr_frame_id = event_data->frame_count;
|
curr_frame_id = event_data->last_frame_id;
|
||||||
else
|
else
|
||||||
curr_frame_id = 1;
|
curr_frame_id = 1;
|
||||||
Debug(2, "New frame id = %d", curr_frame_id);
|
Debug(2, "New frame id = %d", curr_frame_id);
|
||||||
|
@ -626,7 +677,7 @@ bool EventStream::checkEventLoaded() {
|
||||||
if ( curr_frame_id <= 0 )
|
if ( curr_frame_id <= 0 )
|
||||||
curr_frame_id = 1;
|
curr_frame_id = 1;
|
||||||
else
|
else
|
||||||
curr_frame_id = event_data->frame_count;
|
curr_frame_id = event_data->last_frame_id;
|
||||||
paused = true;
|
paused = true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -683,9 +734,6 @@ bool EventStream::sendFrame(int delta_us) {
|
||||||
#endif // HAVE_LIBAVCODEC
|
#endif // HAVE_LIBAVCODEC
|
||||||
{
|
{
|
||||||
|
|
||||||
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
|
||||||
int img_buffer_size = 0;
|
|
||||||
uint8_t *img_buffer = temp_img_buffer;
|
|
||||||
|
|
||||||
bool send_raw = (type == STREAM_JPEG) && ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0];
|
bool send_raw = (type == STREAM_JPEG) && ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0];
|
||||||
|
|
||||||
|
@ -748,6 +796,9 @@ bool EventStream::sendFrame(int delta_us) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Image *send_image = prepareImage(image);
|
Image *send_image = prepareImage(image);
|
||||||
|
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
||||||
|
int img_buffer_size = 0;
|
||||||
|
uint8_t *img_buffer = temp_img_buffer;
|
||||||
|
|
||||||
switch ( type ) {
|
switch ( type ) {
|
||||||
case STREAM_JPEG :
|
case STREAM_JPEG :
|
||||||
|
@ -776,7 +827,7 @@ bool EventStream::sendFrame(int delta_us) {
|
||||||
|
|
||||||
} // end if stream MPEG or other
|
} // end if stream MPEG or other
|
||||||
|
|
||||||
fputs("\r\n\r\n", stdout);
|
fputs("\r\n", stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
last_frame_sent = TV_2_FLOAT(now);
|
last_frame_sent = TV_2_FLOAT(now);
|
||||||
return true;
|
return true;
|
||||||
|
@ -795,13 +846,11 @@ void EventStream::runStream() {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug(3, "frame rate is: (%f)", (double)event_data->frame_count/event_data->duration);
|
|
||||||
updateFrameRate((double)event_data->frame_count/event_data->duration);
|
updateFrameRate((double)event_data->frame_count/event_data->duration);
|
||||||
gettimeofday(&start, nullptr);
|
gettimeofday(&start, nullptr);
|
||||||
uint64_t start_usec = start.tv_sec * 1000000 + start.tv_usec;
|
uint64_t start_usec = start.tv_sec * 1000000 + start.tv_usec;
|
||||||
uint64_t last_frame_offset = 0;
|
uint64_t last_frame_offset = 0;
|
||||||
|
|
||||||
bool in_event = true;
|
|
||||||
double time_to_event = 0;
|
double time_to_event = 0;
|
||||||
|
|
||||||
while ( !zm_terminate ) {
|
while ( !zm_terminate ) {
|
||||||
|
@ -843,8 +892,8 @@ void EventStream::runStream() {
|
||||||
send_frame = true;
|
send_frame = true;
|
||||||
} else if ( !send_frame ) {
|
} else if ( !send_frame ) {
|
||||||
// We are paused, not stepping and doing nothing, meaning that comms didn't set send_frame to true
|
// We are paused, not stepping and doing nothing, meaning that comms didn't set send_frame to true
|
||||||
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
|
double time_since_last_send = TV_2_FLOAT(now) - last_frame_sent;
|
||||||
if ( actual_delta_time > MAX_STREAM_DELAY ) {
|
if ( time_since_last_send > MAX_STREAM_DELAY ) {
|
||||||
// Send keepalive
|
// Send keepalive
|
||||||
Debug(2, "Sending keepalive frame");
|
Debug(2, "Sending keepalive frame");
|
||||||
send_frame = true;
|
send_frame = true;
|
||||||
|
@ -852,21 +901,19 @@ void EventStream::runStream() {
|
||||||
} // end if streaming stepping or doing nothing
|
} // end if streaming stepping or doing nothing
|
||||||
|
|
||||||
// time_to_event > 0 means that we are not in the event
|
// time_to_event > 0 means that we are not in the event
|
||||||
if ( time_to_event > 0 ) {
|
if ( ( time_to_event > 0 ) and ( mode == MODE_ALL ) ) {
|
||||||
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
|
double time_since_last_send = TV_2_FLOAT(now) - last_frame_sent;
|
||||||
Debug(1, "Actual delta time = %f = %f - %f", actual_delta_time, TV_2_FLOAT(now), last_frame_sent);
|
Debug(1, "Time since last send = %f = %f - %f", time_since_last_send, TV_2_FLOAT(now), last_frame_sent);
|
||||||
// > 1 second
|
if ( time_since_last_send > 1 /* second */ ) {
|
||||||
if ( actual_delta_time > 1 ) {
|
|
||||||
Debug(1, "Sending time to next event frame");
|
|
||||||
static char frame_text[64];
|
static char frame_text[64];
|
||||||
snprintf(frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event);
|
|
||||||
|
snprintf(frame_text, sizeof(frame_text), "Time to %s event = %d seconds",
|
||||||
|
(replay_rate > 0 ? "next" : "previous" ), (int)time_to_event);
|
||||||
if ( !sendTextFrame(frame_text) )
|
if ( !sendTextFrame(frame_text) )
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
} else {
|
send_frame = false; // In case keepalive was set
|
||||||
Debug(1, "Not Sending time to next event frame because actual delta time is %f", actual_delta_time);
|
|
||||||
}
|
}
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// FIXME ICON But we are not paused. We are somehow still in the event?
|
// FIXME ICON But we are not paused. We are somehow still in the event?
|
||||||
double sleep_time = (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000));
|
double sleep_time = (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000));
|
||||||
//double sleep_time = (replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000);
|
//double sleep_time = (replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000);
|
||||||
|
@ -976,6 +1023,7 @@ void EventStream::runStream() {
|
||||||
//if ( step != 0 )// Adding 0 is cheaper than an if 0
|
//if ( step != 0 )// Adding 0 is cheaper than an if 0
|
||||||
// curr_frame_id starts at 1 though, so we might skip the first frame?
|
// curr_frame_id starts at 1 though, so we might skip the first frame?
|
||||||
curr_frame_id += step;
|
curr_frame_id += step;
|
||||||
|
} // end if !paused
|
||||||
|
|
||||||
// Detects when we hit end of event and will load the next event or previous event
|
// Detects when we hit end of event and will load the next event or previous event
|
||||||
if ( checkEventLoaded() ) {
|
if ( checkEventLoaded() ) {
|
||||||
|
@ -996,9 +1044,7 @@ void EventStream::runStream() {
|
||||||
Debug(1, "replay rate(%d) time_to_event(%f)=curr_stream_time(%f)-frame timestamp:%f",
|
Debug(1, "replay rate(%d) time_to_event(%f)=curr_stream_time(%f)-frame timestamp:%f",
|
||||||
replay_rate, time_to_event, curr_stream_time, event_data->frames[event_data->frame_count-1].timestamp);
|
replay_rate, time_to_event, curr_stream_time, event_data->frames[event_data->frame_count-1].timestamp);
|
||||||
} // end if forward or reverse
|
} // end if forward or reverse
|
||||||
|
|
||||||
} // end if checkEventLoaded
|
} // end if checkEventLoaded
|
||||||
} // end if !paused
|
|
||||||
} // end while ! zm_terminate
|
} // end while ! zm_terminate
|
||||||
#if HAVE_LIBAVCODEC
|
#if HAVE_LIBAVCODEC
|
||||||
if ( type == STREAM_MPEG )
|
if ( type == STREAM_MPEG )
|
||||||
|
@ -1010,6 +1056,7 @@ void EventStream::runStream() {
|
||||||
|
|
||||||
bool EventStream::send_file(const char * filepath) {
|
bool EventStream::send_file(const char * filepath) {
|
||||||
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
||||||
|
int rc;
|
||||||
|
|
||||||
int img_buffer_size = 0;
|
int img_buffer_size = 0;
|
||||||
uint8_t *img_buffer = temp_img_buffer;
|
uint8_t *img_buffer = temp_img_buffer;
|
||||||
|
@ -1020,47 +1067,50 @@ bool EventStream::send_file(const char * filepath) {
|
||||||
Error("Can't open %s: %s", filepath, strerror(errno));
|
Error("Can't open %s: %s", filepath, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool size_sent = false;
|
|
||||||
|
|
||||||
#if HAVE_SENDFILE
|
#if HAVE_SENDFILE
|
||||||
static struct stat filestat;
|
static struct stat filestat;
|
||||||
if ( fstat(fileno(fdj), &filestat) < 0 ) {
|
if ( fstat(fileno(fdj), &filestat) < 0 ) {
|
||||||
|
fclose(fdj); /* Close the file handle */
|
||||||
Error("Failed getting information about file %s: %s", filepath, strerror(errno));
|
Error("Failed getting information about file %s: %s", filepath, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ( !filestat.st_size ) {
|
||||||
|
fclose(fdj); /* Close the file handle */
|
||||||
|
Info("File size is zero. Unable to send raw frame %u: %s", curr_frame_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size) ) {
|
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size) ) {
|
||||||
fclose(fdj); /* Close the file handle */
|
fclose(fdj); /* Close the file handle */
|
||||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_sent = true;
|
rc = zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size);
|
||||||
|
if ( rc == (int)filestat.st_size ) {
|
||||||
if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) {
|
// Success
|
||||||
fclose(fdj); /* Close the file handle */
|
fclose(fdj); /* Close the file handle */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Warning("Unable to send raw frame %u: %s rc %d", curr_frame_id, strerror(errno), rc);
|
||||||
#endif
|
#endif
|
||||||
img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj);
|
img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj);
|
||||||
if ( !size_sent ) {
|
|
||||||
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) ) {
|
|
||||||
fclose(fdj); /* Close the file handle */
|
fclose(fdj); /* Close the file handle */
|
||||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
if ( !img_buffer_size ) {
|
||||||
return false;
|
Info("Unable to read raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
|
||||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fdj); /* Close the file handle */
|
return send_buffer(img_buffer, img_buffer_size);
|
||||||
return true;
|
|
||||||
} // end bool EventStream::send_file(const char * filepath)
|
} // end bool EventStream::send_file(const char * filepath)
|
||||||
|
|
||||||
bool EventStream::send_buffer(uint8_t* buffer, int size) {
|
bool EventStream::send_buffer(uint8_t* buffer, int size) {
|
||||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", size);
|
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", size) ) {
|
||||||
if ( fwrite(buffer, size, 1, stdout) != 1 ) {
|
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
return false;
|
||||||
|
}
|
||||||
|
int rc = fwrite(buffer, size, 1, stdout);
|
||||||
|
|
||||||
|
if ( 1 != rc ) {
|
||||||
|
Error("Unable to send raw frame %u: %s %d", curr_frame_id, strerror(errno), rc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -54,11 +54,13 @@ class EventStream : public StreamBase {
|
||||||
uint64_t event_id;
|
uint64_t event_id;
|
||||||
unsigned int monitor_id;
|
unsigned int monitor_id;
|
||||||
unsigned long storage_id;
|
unsigned long storage_id;
|
||||||
unsigned long frame_count;
|
unsigned long frame_count; // Value of Frames column in Event
|
||||||
|
unsigned long last_frame_id; // Highest frame id known about. Can be < frame_count in incomplete events
|
||||||
time_t start_time;
|
time_t start_time;
|
||||||
|
time_t end_time;
|
||||||
double duration;
|
double duration;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
int n_frames;
|
int n_frames; // # of frame rows returned from database
|
||||||
FrameData *frames;
|
FrameData *frames;
|
||||||
char video_file[PATH_MAX];
|
char video_file[PATH_MAX];
|
||||||
Storage::Schemes scheme;
|
Storage::Schemes scheme;
|
||||||
|
@ -74,7 +76,7 @@ class EventStream : public StreamBase {
|
||||||
StreamMode mode;
|
StreamMode mode;
|
||||||
bool forceEventChange;
|
bool forceEventChange;
|
||||||
|
|
||||||
int curr_frame_id;
|
unsigned long curr_frame_id;
|
||||||
double curr_stream_time;
|
double curr_stream_time;
|
||||||
bool send_frame;
|
bool send_frame;
|
||||||
struct timeval start; // clock time when started the event
|
struct timeval start; // clock time when started the event
|
||||||
|
|
|
@ -20,7 +20,7 @@ FFmpeg_Input::~FFmpeg_Input() {
|
||||||
if ( streams ) {
|
if ( streams ) {
|
||||||
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
|
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
|
||||||
avcodec_close(streams[i].context);
|
avcodec_close(streams[i].context);
|
||||||
streams[i].context = nullptr;
|
avcodec_free_context(&streams[i].context);
|
||||||
}
|
}
|
||||||
delete[] streams;
|
delete[] streams;
|
||||||
streams = nullptr;
|
streams = nullptr;
|
||||||
|
@ -247,7 +247,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
||||||
if (
|
if (
|
||||||
(last_seek_request >= 0)
|
(last_seek_request >= 0)
|
||||||
&&
|
&&
|
||||||
(last_seek_request > seek_target )
|
(last_seek_request > seek_target)
|
||||||
&&
|
&&
|
||||||
(frame->pts > seek_target)
|
(frame->pts > seek_target)
|
||||||
) {
|
) {
|
||||||
|
@ -262,6 +262,9 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
||||||
// Have to grab a frame to update our current frame to know where we are
|
// Have to grab a frame to update our current frame to know where we are
|
||||||
get_frame(stream_id);
|
get_frame(stream_id);
|
||||||
zm_dump_frame(frame, "frame->pts > seek_target, got");
|
zm_dump_frame(frame, "frame->pts > seek_target, got");
|
||||||
|
} else if ( last_seek_request == seek_target ) {
|
||||||
|
// paused case, sending keepalives
|
||||||
|
return frame;
|
||||||
} // end if frame->pts > seek_target
|
} // end if frame->pts > seek_target
|
||||||
|
|
||||||
last_seek_request = seek_target;
|
last_seek_request = seek_target;
|
||||||
|
|
|
@ -1859,10 +1859,10 @@ void Image::Delta(const Image &image, Image* targetimage) const {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const Coord Image::centreCoord( const char *text ) const {
|
const Coord Image::centreCoord( const char *text, int size=1 ) const {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int line_no = 0;
|
int line_no = 0;
|
||||||
int text_len = strlen( text );
|
int text_len = strlen(text);
|
||||||
int line_len = 0;
|
int line_len = 0;
|
||||||
int max_line_len = 0;
|
int max_line_len = 0;
|
||||||
const char *line = text;
|
const char *line = text;
|
||||||
|
@ -1878,8 +1878,8 @@ const Coord Image::centreCoord( const char *text ) const {
|
||||||
line = text+index;
|
line = text+index;
|
||||||
line_no++;
|
line_no++;
|
||||||
}
|
}
|
||||||
int x = (width - (max_line_len * ZM_CHAR_WIDTH) ) / 2;
|
int x = (width - (max_line_len * ZM_CHAR_WIDTH * size) ) / 2;
|
||||||
int y = (height - (line_no * LINE_HEIGHT) ) / 2;
|
int y = (height - (line_no * LINE_HEIGHT * size) ) / 2;
|
||||||
return Coord(x, y);
|
return Coord(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,7 @@ public:
|
||||||
//Image *Delta( const Image &image ) const;
|
//Image *Delta( const Image &image ) const;
|
||||||
void Delta( const Image &image, Image* targetimage) const;
|
void Delta( const Image &image, Image* targetimage) const;
|
||||||
|
|
||||||
const Coord centreCoord(const char *p_text) const;
|
const Coord centreCoord(const char *text, const int size) const;
|
||||||
void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 );
|
void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 );
|
||||||
void Annotate( const char *p_text, const Coord &coord, const unsigned int size=1, const Rgb fg_colour=RGB_WHITE, const Rgb bg_colour=RGB_BLACK );
|
void Annotate( const char *p_text, const Coord &coord, const unsigned int size=1, const Rgb fg_colour=RGB_WHITE, const Rgb bg_colour=RGB_BLACK );
|
||||||
Image *HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits=0 );
|
Image *HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits=0 );
|
||||||
|
|
|
@ -1766,9 +1766,7 @@ bool Monitor::Analyse() {
|
||||||
int motion_score = last_motion_score;
|
int motion_score = last_motion_score;
|
||||||
if ( !(analysis_image_count % (motion_frame_skip+1) ) ) {
|
if ( !(analysis_image_count % (motion_frame_skip+1) ) ) {
|
||||||
if ( snap->image ) {
|
if ( snap->image ) {
|
||||||
|
|
||||||
// Get new score.
|
// Get new score.
|
||||||
Debug(3, "before DetectMotion packet index is %d", snap->image_index);
|
|
||||||
motion_score = DetectMotion(*snap_image, zoneSet);
|
motion_score = DetectMotion(*snap_image, zoneSet);
|
||||||
|
|
||||||
Debug(3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score);
|
Debug(3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score);
|
||||||
|
@ -1780,11 +1778,9 @@ bool Monitor::Analyse() {
|
||||||
}
|
}
|
||||||
if ( motion_score ) {
|
if ( motion_score ) {
|
||||||
score += motion_score;
|
score += motion_score;
|
||||||
if ( !event ) {
|
|
||||||
if ( cause.length() )
|
if ( cause.length() )
|
||||||
cause += ", ";
|
cause += ", ";
|
||||||
cause += MOTION_CAUSE;
|
cause += MOTION_CAUSE;
|
||||||
}
|
|
||||||
noteSetMap[MOTION_CAUSE] = zoneSet;
|
noteSetMap[MOTION_CAUSE] = zoneSet;
|
||||||
} // end if motion_score
|
} // end if motion_score
|
||||||
//shared_data->active = signal; // unneccessary active gets set on signal change
|
//shared_data->active = signal; // unneccessary active gets set on signal change
|
||||||
|
@ -1887,7 +1883,6 @@ bool Monitor::Analyse() {
|
||||||
( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length
|
( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
|
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
|
||||||
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
||||||
std::string alarm_cause = "";
|
std::string alarm_cause = "";
|
||||||
|
@ -1914,7 +1909,7 @@ bool Monitor::Analyse() {
|
||||||
Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name, image_count, event->Id());
|
Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name, image_count, event->Id());
|
||||||
}
|
}
|
||||||
if ( alarm_frame_count ) {
|
if ( alarm_frame_count ) {
|
||||||
Debug(1, "alarm frame count so SavePreAlarmFrames");
|
Debug(1, "alarm frame count so SavePreAlarmFrames");
|
||||||
event->SavePreAlarmFrames();
|
event->SavePreAlarmFrames();
|
||||||
}
|
}
|
||||||
} else if ( state != PREALARM ) {
|
} else if ( state != PREALARM ) {
|
||||||
|
@ -1947,6 +1942,8 @@ Debug(1, "alarm frame count so SavePreAlarmFrames");
|
||||||
} else if ( state == PREALARM ) {
|
} else if ( state == PREALARM ) {
|
||||||
// Back to IDLE
|
// Back to IDLE
|
||||||
shared_data->state = state = function != MOCORD ? IDLE : TAPE;
|
shared_data->state = state = function != MOCORD ? IDLE : TAPE;
|
||||||
|
} else {
|
||||||
|
Debug(1, "Not leaving ALERT beacuse image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%d) - recording.tv_src(%d) >= min_section_length(%d)", image_count, last_alarm_count, post_event_count, timestamp->tv_sec, video_store_data->recording.tv_sec, min_section_length);
|
||||||
}
|
}
|
||||||
if ( Event::PreAlarmCount() )
|
if ( Event::PreAlarmCount() )
|
||||||
Event::EmptyPreAlarmFrames();
|
Event::EmptyPreAlarmFrames();
|
||||||
|
|
|
@ -502,6 +502,8 @@ public:
|
||||||
inline void setStartupTime( time_t p_time ) { shared_data->startup_time = p_time; }
|
inline void setStartupTime( time_t p_time ) { shared_data->startup_time = p_time; }
|
||||||
void get_ref_image();
|
void get_ref_image();
|
||||||
|
|
||||||
|
int LabelSize() { return label_size; }
|
||||||
|
|
||||||
void actionReload();
|
void actionReload();
|
||||||
void actionEnable();
|
void actionEnable();
|
||||||
void actionDisable();
|
void actionDisable();
|
||||||
|
|
|
@ -39,7 +39,7 @@ StreamBase::~StreamBase() {
|
||||||
closeComms();
|
closeComms();
|
||||||
if ( monitor ) {
|
if ( monitor ) {
|
||||||
delete monitor;
|
delete monitor;
|
||||||
monitor = NULL;
|
monitor = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +252,8 @@ bool StreamBase::sendTextFrame(const char *frame_text) {
|
||||||
monitor->Width(), monitor->Height(), scale, frame_text);
|
monitor->Width(), monitor->Height(), scale, frame_text);
|
||||||
|
|
||||||
Image image(monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder());
|
Image image(monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder());
|
||||||
image.Annotate(frame_text, image.centreCoord(frame_text));
|
image.Clear();
|
||||||
|
image.Annotate(frame_text, image.centreCoord(frame_text, monitor->LabelSize()), monitor->LabelSize());
|
||||||
|
|
||||||
if ( scale != 100 ) {
|
if ( scale != 100 ) {
|
||||||
image.Scale(scale);
|
image.Scale(scale);
|
||||||
|
|
|
@ -116,7 +116,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
StreamBase():
|
StreamBase():
|
||||||
monitor_id(0),
|
monitor_id(0),
|
||||||
monitor(0),
|
monitor(nullptr),
|
||||||
type(DEFAULT_TYPE),
|
type(DEFAULT_TYPE),
|
||||||
format(""),
|
format(""),
|
||||||
replay_rate(DEFAULT_RATE),
|
replay_rate(DEFAULT_RATE),
|
||||||
|
|
|
@ -239,63 +239,31 @@ void hwcaps_detect() {
|
||||||
neonversion = 0;
|
neonversion = 0;
|
||||||
sse_version = 0;
|
sse_version = 0;
|
||||||
#if (defined(__i386__) || defined(__x86_64__))
|
#if (defined(__i386__) || defined(__x86_64__))
|
||||||
/* x86 or x86-64 processor */
|
__builtin_cpu_init();
|
||||||
uint32_t r_edx, r_ecx, r_ebx;
|
|
||||||
|
|
||||||
#ifdef __x86_64__
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"push %%rbx\n\t"
|
|
||||||
"mov $0x0,%%ecx\n\t"
|
|
||||||
"mov $0x7,%%eax\n\t"
|
|
||||||
"cpuid\n\t"
|
|
||||||
"push %%rbx\n\t"
|
|
||||||
"mov $0x1,%%eax\n\t"
|
|
||||||
"cpuid\n\t"
|
|
||||||
"pop %%rax\n\t"
|
|
||||||
"pop %%rbx\n\t"
|
|
||||||
: "=d" (r_edx), "=c" (r_ecx), "=a" (r_ebx)
|
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"push %%ebx\n\t"
|
|
||||||
"mov $0x0,%%ecx\n\t"
|
|
||||||
"mov $0x7,%%eax\n\t"
|
|
||||||
"cpuid\n\t"
|
|
||||||
"push %%ebx\n\t"
|
|
||||||
"mov $0x1,%%eax\n\t"
|
|
||||||
"cpuid\n\t"
|
|
||||||
"pop %%eax\n\t"
|
|
||||||
"pop %%ebx\n\t"
|
|
||||||
: "=d" (r_edx), "=c" (r_ecx), "=a" (r_ebx)
|
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( r_ebx & 0x00000020 ) {
|
if ( __builtin_cpu_supports("avx2") ) {
|
||||||
sse_version = 52; /* AVX2 */
|
sse_version = 52; /* AVX2 */
|
||||||
Debug(1, "Detected a x86\\x86-64 processor with AVX2");
|
Debug(1, "Detected a x86\\x86-64 processor with AVX2");
|
||||||
} else if ( r_ecx & 0x10000000 ) {
|
} else if ( __builtin_cpu_supports("avx") ) {
|
||||||
sse_version = 51; /* AVX */
|
sse_version = 51; /* AVX */
|
||||||
Debug(1, "Detected a x86\\x86-64 processor with AVX");
|
Debug(1, "Detected a x86\\x86-64 processor with AVX");
|
||||||
} else if ( r_ecx & 0x00100000 ) {
|
} else if ( __builtin_cpu_supports("sse4.2") ) {
|
||||||
sse_version = 42; /* SSE4.2 */
|
sse_version = 42; /* SSE4.2 */
|
||||||
Debug(1, "Detected a x86\\x86-64 processor with SSE4.2");
|
Debug(1, "Detected a x86\\x86-64 processor with SSE4.2");
|
||||||
} else if ( r_ecx & 0x00080000 ) {
|
} else if ( __builtin_cpu_supports("sse4.1") ) {
|
||||||
sse_version = 41; /* SSE4.1 */
|
sse_version = 41; /* SSE4.1 */
|
||||||
Debug(1, "Detected a x86\\x86-64 processor with SSE4.1");
|
Debug(1, "Detected a x86\\x86-64 processor with SSE4.1");
|
||||||
} else if ( r_ecx & 0x00000200 ) {
|
} else if ( __builtin_cpu_supports("ssse3") ) {
|
||||||
sse_version = 35; /* SSSE3 */
|
sse_version = 35; /* SSSE3 */
|
||||||
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
|
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
|
||||||
} else if ( r_ecx & 0x00000001 ) {
|
} else if ( __builtin_cpu_supports("sse3") ) {
|
||||||
sse_version = 30; /* SSE3 */
|
sse_version = 30; /* SSE3 */
|
||||||
Debug(1, "Detected a x86\\x86-64 processor with SSE3");
|
Debug(1, "Detected a x86\\x86-64 processor with SSE3");
|
||||||
} else if ( r_edx & 0x04000000 ) {
|
} else if ( __builtin_cpu_supports("sse2") ) {
|
||||||
sse_version = 20; /* SSE2 */
|
sse_version = 20; /* SSE2 */
|
||||||
Debug(1, "Detected a x86\\x86-64 processor with SSE2");
|
Debug(1, "Detected a x86\\x86-64 processor with SSE2");
|
||||||
} else if ( r_edx & 0x02000000 ) {
|
} else if ( __builtin_cpu_supports("sse") ) {
|
||||||
sse_version = 10; /* SSE */
|
sse_version = 10; /* SSE */
|
||||||
Debug(1, "Detected a x86\\x86-64 processor with SSE");
|
Debug(1, "Detected a x86\\x86-64 processor with SSE");
|
||||||
} else {
|
} else {
|
||||||
|
@ -330,7 +298,7 @@ __attribute__((noinline,__target__("sse2")))
|
||||||
#endif
|
#endif
|
||||||
void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
||||||
#if ((defined(__i386__) || defined(__x86_64__) || defined(ZM_KEEP_SSE)) && !defined(ZM_STRIP_SSE))
|
#if ((defined(__i386__) || defined(__x86_64__) || defined(ZM_KEEP_SSE)) && !defined(ZM_STRIP_SSE))
|
||||||
if ( bytes > 128 ) {
|
if(bytes > 128) {
|
||||||
unsigned int remainder = bytes % 128;
|
unsigned int remainder = bytes % 128;
|
||||||
const uint8_t* lastsrc = (uint8_t*)src + (bytes - remainder);
|
const uint8_t* lastsrc = (uint8_t*)src + (bytes - remainder);
|
||||||
|
|
||||||
|
@ -372,7 +340,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Non x86\x86-64 platform, use memcpy */
|
/* Non x86\x86-64 platform, use memcpy */
|
||||||
memcpy(dest, src, bytes);
|
memcpy(dest,src,bytes);
|
||||||
#endif
|
#endif
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,7 @@ void Zone::Setup(
|
||||||
|
|
||||||
Zone::~Zone() {
|
Zone::~Zone() {
|
||||||
delete[] label;
|
delete[] label;
|
||||||
|
if ( image )
|
||||||
delete image;
|
delete image;
|
||||||
delete pg_image;
|
delete pg_image;
|
||||||
delete[] ranges;
|
delete[] ranges;
|
||||||
|
@ -158,6 +159,7 @@ void Zone::SetScore(unsigned int nScore) {
|
||||||
} // end void Zone::SetScore(unsigned int nScore)
|
} // end void Zone::SetScore(unsigned int nScore)
|
||||||
|
|
||||||
void Zone::SetAlarmImage(const Image* srcImage) {
|
void Zone::SetAlarmImage(const Image* srcImage) {
|
||||||
|
if ( image )
|
||||||
delete image;
|
delete image;
|
||||||
image = new Image(*srcImage);
|
image = new Image(*srcImage);
|
||||||
} // end void Zone::SetAlarmImage( const Image* srcImage )
|
} // end void Zone::SetAlarmImage( const Image* srcImage )
|
||||||
|
@ -205,6 +207,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( image )
|
||||||
delete image;
|
delete image;
|
||||||
// Get the difference image
|
// Get the difference image
|
||||||
Image *diff_image = image = new Image(*delta_image);
|
Image *diff_image = image = new Image(*delta_image);
|
||||||
|
@ -734,14 +737,12 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
||||||
|
|
||||||
// Only need to delete this when 'image' becomes detached and points somewhere else
|
// Only need to delete this when 'image' becomes detached and points somewhere else
|
||||||
delete diff_image;
|
delete diff_image;
|
||||||
} else {
|
diff_image = nullptr;
|
||||||
delete image;
|
} // end if ( (type < PRECLUSIVE) && (check_method >= BLOBS) && (monitor->GetOptSaveJPEGs() > 1)
|
||||||
image = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug(1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d",
|
Debug(1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d",
|
||||||
Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score);
|
Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score);
|
||||||
}
|
} // end if score
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ function probe( &$url_bits ) {
|
||||||
|
|
||||||
$cam_list_html = file_get_contents('http://'.$url_bits['host'].':5000/monitoring/');
|
$cam_list_html = file_get_contents('http://'.$url_bits['host'].':5000/monitoring/');
|
||||||
if ( $cam_list_html ) {
|
if ( $cam_list_html ) {
|
||||||
ZM\Logger::Debug("Have content at port 5000/monitoring");
|
ZM\Debug("Have content at port 5000/monitoring");
|
||||||
$matches_count = preg_match_all(
|
$matches_count = preg_match_all(
|
||||||
'/<a href="http:\/\/([.[:digit:]]+):([[:digit:]]+)\/\?action=stream" target="_blank">([^<]+)<\/a>/',
|
'/<a href="http:\/\/([.[:digit:]]+):([[:digit:]]+)\/\?action=stream" target="_blank">([^<]+)<\/a>/',
|
||||||
$cam_list_html, $cam_list );
|
$cam_list_html, $cam_list );
|
||||||
ZM\Logger::Debug(print_r($cam_list,true));
|
ZM\Debug(print_r($cam_list,true));
|
||||||
}
|
}
|
||||||
if ( $matches_count ) {
|
if ( $matches_count ) {
|
||||||
for( $index = 0; $index < $matches_count; $index ++ ) {
|
for( $index = 0; $index < $matches_count; $index ++ ) {
|
||||||
|
@ -41,7 +41,7 @@ function probe( &$url_bits ) {
|
||||||
if ( ! isset($new_stream['scheme'] ) )
|
if ( ! isset($new_stream['scheme'] ) )
|
||||||
$new_stream['scheme'] = 'http';
|
$new_stream['scheme'] = 'http';
|
||||||
$available_streams[] = $new_stream;
|
$available_streams[] = $new_stream;
|
||||||
ZM\Logger::Debug("Have new stream " . print_r($new_stream,true) );
|
ZM\Debug("Have new stream " . print_r($new_stream,true) );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ZM\Info('No matches');
|
ZM\Info('No matches');
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
if ( !canEdit('Control') ) {
|
||||||
|
ZM\Warning('Need Control permissions to edit control capabilities');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty($_REQUEST['action']) ) {
|
||||||
|
ajaxError('Action Not Provided');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
$action = $_REQUEST['action'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset($_REQUEST['cids']) ) {
|
||||||
|
$cids = $_REQUEST['cids'];
|
||||||
|
} else {
|
||||||
|
ajaxError('At least one Control Id must be Provided.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $action == 'delete' ) {
|
||||||
|
foreach( $cids as $cid ) {
|
||||||
|
dbQuery('UPDATE Monitors SET Controllable = 0, ControlId = 0 WHERE ControlId = ?', array($cid));
|
||||||
|
dbQuery('DELETE FROM Controls WHERE Id = ?', array($cid));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ajaxError('Unrecognised action ' .$_REQUEST['action']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ajaxResponse();
|
||||||
|
return;
|
||||||
|
?>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web action file
|
||||||
|
// Copyright (C) 2019 ZoneMinder LLC
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Device view actions
|
||||||
|
if ( !canEdit('Devices') ) {
|
||||||
|
ajaxError('Insufficient permissions for user '.$user['Username']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $action == 'device' ) {
|
||||||
|
if ( !empty($_REQUEST['command']) ) {
|
||||||
|
setDeviceStatusX10($_REQUEST['key'], $_REQUEST['command']);
|
||||||
|
} else if ( isset($_REQUEST['newDevice']) ) {
|
||||||
|
if ( isset($_REQUEST['did']) && $_REQUEST['did'] ) {
|
||||||
|
ZM\Warning('did value is: '.$_REQUEST['did']);
|
||||||
|
ZM\Warning('newDevice array value is: '.print_r($_REQUEST['newDevice'],true));
|
||||||
|
dbQuery('UPDATE Devices SET Name=?, KeyString=? WHERE Id=?',
|
||||||
|
array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'], $_REQUEST['did']) );
|
||||||
|
} else {
|
||||||
|
|
||||||
|
dbQuery('INSERT INTO Devices SET Name=?, KeyString=?',
|
||||||
|
array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString']) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxResponse();
|
||||||
|
} else {
|
||||||
|
ajaxError('Unrecognised action '.$_REQUEST['action']);
|
||||||
|
} // end if action
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web action file
|
||||||
|
// Copyright (C) 2019 ZoneMinder LLC
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Device view actions
|
||||||
|
if ( !canEdit('Devices') ) {
|
||||||
|
ajaxError('Insufficient permissions for user '.$user['Username']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $action == 'delete' ) {
|
||||||
|
if ( isset($_REQUEST['markDids']) ) {
|
||||||
|
foreach( $_REQUEST['markDids'] as $markDid ) {
|
||||||
|
dbQuery('DELETE FROM Devices WHERE Id=?', array($markDid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxResponse();
|
||||||
|
} else {
|
||||||
|
ajaxError('Unrecognised action '.$_REQUEST['action']);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -1,28 +1,107 @@
|
||||||
<?php
|
<?php
|
||||||
ini_set('display_errors', '0');
|
|
||||||
|
|
||||||
if ( empty($_REQUEST['eids']) ) {
|
$message = '';
|
||||||
ajaxError('No event id(s) supplied');
|
$data = array();
|
||||||
|
|
||||||
|
//
|
||||||
|
// INITIALIZE AND CHECK SANITY
|
||||||
|
//
|
||||||
|
|
||||||
|
if ( !canEdit('Events') ) $message = 'Insufficient permissions for user '.$user['Username'];
|
||||||
|
|
||||||
|
if ( empty($_REQUEST['task']) ) {
|
||||||
|
$message = 'Must specify a task';
|
||||||
|
} else {
|
||||||
|
$task = $_REQUEST['task'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( canView('Events') ) {
|
if ( empty($_REQUEST['eids']) ) {
|
||||||
} // end if canView('Events')
|
if ( isset($_REQUEST['task']) && $_REQUEST['task'] != "query" ) $message = 'No event id(s) supplied';
|
||||||
|
} else {
|
||||||
|
$eids = $_REQUEST['eids'];
|
||||||
|
}
|
||||||
|
|
||||||
if ( canEdit('Events') ) {
|
if ( $message ) {
|
||||||
$message = array();
|
ajaxError($message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ( $_REQUEST['eids'] as $eid ) {
|
// Search contains a user entered string to search on
|
||||||
|
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
|
||||||
|
|
||||||
switch ( $_REQUEST['action'] ) {
|
// Advanced search contains an array of "column name" => "search text" pairs
|
||||||
|
// Bootstrap table sends json_ecoded array, which we must decode
|
||||||
|
$advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array();
|
||||||
|
|
||||||
|
// Sort specifies the name of the column to sort on
|
||||||
|
$sort = 'StartTime';
|
||||||
|
if ( isset($_REQUEST['sort']) ) {
|
||||||
|
if ( !in_array($_REQUEST['sort'], array_merge($columns, $col_alt)) ) {
|
||||||
|
ZM\Error('Invalid sort field: ' . $_REQUEST['sort']);
|
||||||
|
} else {
|
||||||
|
$sort = $_REQUEST['sort'];
|
||||||
|
//if ( $sort == 'DateTime' ) $sort = 'TimeKey';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset specifies the starting row to return, used for pagination
|
||||||
|
$offset = 0;
|
||||||
|
if ( isset($_REQUEST['offset']) ) {
|
||||||
|
if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) {
|
||||||
|
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']);
|
||||||
|
} else {
|
||||||
|
$offset = $_REQUEST['offset'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order specifies the sort direction, either asc or desc
|
||||||
|
$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC';
|
||||||
|
|
||||||
|
// Limit specifies the number of rows to return
|
||||||
|
$limit = 100;
|
||||||
|
if ( isset($_REQUEST['limit']) ) {
|
||||||
|
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
||||||
|
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
|
||||||
|
} else {
|
||||||
|
$limit = $_REQUEST['limit'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// MAIN LOOP
|
||||||
|
//
|
||||||
|
|
||||||
|
switch ( $task ) {
|
||||||
case 'archive' :
|
case 'archive' :
|
||||||
case 'unarchive' :
|
case 'unarchive' :
|
||||||
$archiveVal = ($_REQUEST['action'] == 'archive') ? 1 : 0;
|
foreach ( $eids as $eid ) archiveRequest($task, $eid);
|
||||||
|
break;
|
||||||
|
case 'delete' :
|
||||||
|
foreach ( $eids as $eid ) $data[] = deleteRequest($eid);
|
||||||
|
break;
|
||||||
|
case 'query' :
|
||||||
|
$data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
ZM\Fatal("Unrecognised task '$task'");
|
||||||
|
} // end switch task
|
||||||
|
|
||||||
|
ajaxResponse($data);
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION DEFINITIONS
|
||||||
|
//
|
||||||
|
|
||||||
|
function archiveRequest($task, $eid) {
|
||||||
|
$archiveVal = ($task == 'archive') ? 1 : 0;
|
||||||
dbQuery(
|
dbQuery(
|
||||||
'UPDATE Events SET Archived = ? WHERE Id = ?',
|
'UPDATE Events SET Archived = ? WHERE Id = ?',
|
||||||
array($archiveVal, $eid)
|
array($archiveVal, $eid)
|
||||||
);
|
);
|
||||||
break;
|
}
|
||||||
case 'delete' :
|
|
||||||
|
function deleteRequest($eid) {
|
||||||
|
$message = array();
|
||||||
$event = new ZM\Event($eid);
|
$event = new ZM\Event($eid);
|
||||||
if ( !$event->Id() ) {
|
if ( !$event->Id() ) {
|
||||||
$message[] = array($eid=>'Event not found.');
|
$message[] = array($eid=>'Event not found.');
|
||||||
|
@ -31,11 +110,105 @@ if ( canEdit('Events') ) {
|
||||||
} else {
|
} else {
|
||||||
$event->delete();
|
$event->delete();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} // end switch action
|
|
||||||
} // end foreach
|
|
||||||
ajaxResponse($message);
|
|
||||||
} // end if canEdit('Events')
|
|
||||||
|
|
||||||
ajaxError('Unrecognised action '.$_REQUEST['action'].' or insufficient permissions for user '.$user['Username']);
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) {
|
||||||
|
// Put server pagination code here
|
||||||
|
// The table we want our data from
|
||||||
|
$table = 'Events';
|
||||||
|
|
||||||
|
// The names of the dB columns in the log table we are interested in
|
||||||
|
$columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartTime', 'EndTime', 'Length', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'Notes', 'DiskSpace');
|
||||||
|
|
||||||
|
// The names of columns shown in the log view that are NOT dB columns in the database
|
||||||
|
$col_alt = array('Monitor', 'Storage');
|
||||||
|
|
||||||
|
$col_str = implode(', ', $columns);
|
||||||
|
$data = array();
|
||||||
|
$query = array();
|
||||||
|
$query['values'] = array();
|
||||||
|
$likes = array();
|
||||||
|
$where = '';
|
||||||
|
// There are two search bars in the log view, normal and advanced
|
||||||
|
// Making an exuctive decision to ignore the normal search, when advanced search is in use
|
||||||
|
// Alternatively we could try to do both
|
||||||
|
if ( count($advsearch) ) {
|
||||||
|
|
||||||
|
foreach ( $advsearch as $col=>$text ) {
|
||||||
|
if ( !in_array($col, array_merge($columns, $col_alt)) ) {
|
||||||
|
ZM\Error("'$col' is not a sortable column name");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$text = '%' .$text. '%';
|
||||||
|
array_push($likes, $col.' LIKE ?');
|
||||||
|
array_push($query['values'], $text);
|
||||||
|
}
|
||||||
|
$wherevalues = $query['values'];
|
||||||
|
$where = ' WHERE (' .implode(' OR ', $likes). ')';
|
||||||
|
|
||||||
|
} else if ( $search != '' ) {
|
||||||
|
|
||||||
|
$search = '%' .$search. '%';
|
||||||
|
foreach ( $columns as $col ) {
|
||||||
|
array_push($likes, $col.' LIKE ?');
|
||||||
|
array_push($query['values'], $search);
|
||||||
|
}
|
||||||
|
$wherevalues = $query['values'];
|
||||||
|
$where = ' WHERE (' .implode(' OR ', $likes). ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?';
|
||||||
|
array_push($query['values'], $offset, $limit);
|
||||||
|
|
||||||
|
//ZM\Warning('Calling the following sql query: ' .$query['sql']);
|
||||||
|
|
||||||
|
$data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total');
|
||||||
|
if ( $search != '' || count($advsearch) ) {
|
||||||
|
$data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues);
|
||||||
|
} else {
|
||||||
|
$data['total'] = $data['totalNotFiltered'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$storage_areas = ZM\Storage::find();
|
||||||
|
$StorageById = array();
|
||||||
|
foreach ( $storage_areas as $S ) {
|
||||||
|
$StorageById[$S->Id()] = $S;
|
||||||
|
}
|
||||||
|
|
||||||
|
$monitor_names = ZM\Monitor::find();
|
||||||
|
$MonitorById = array();
|
||||||
|
foreach ( $monitor_names as $S ) {
|
||||||
|
$MonitorById[$S->Id()] = $S;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) {
|
||||||
|
$event = new ZM\Event($row['Id']);
|
||||||
|
$scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width());
|
||||||
|
$imgSrc = $event->getThumbnailSrc(array(),'&');
|
||||||
|
$streamSrc = $event->getStreamSrc(array(
|
||||||
|
'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single', 'rate'=>'400'), '&');
|
||||||
|
|
||||||
|
// Modify the row data as needed
|
||||||
|
$row['imgHtml'] = '<img id="thumbnail' .$event->Id(). '" src="' .$imgSrc. '" alt="' .validHtmlStr('Event ' .$event->Id()). '" style="width:' .validInt($event->ThumbnailWidth()). 'px;height:' .validInt($event->ThumbnailHeight()).'px;" stream_src="' .$streamSrc. '" still_src="' .$imgSrc. '"/>';
|
||||||
|
$row['Name'] = validHtmlStr($row['Name']);
|
||||||
|
$row['Archived'] = $row['Archived'] ? translate('Yes') : translate('No');
|
||||||
|
$row['Emailed'] = $row['Emailed'] ? translate('Yes') : translate('No');
|
||||||
|
$row['Monitor'] = ( $row['MonitorId'] and isset($MonitorById[$row['MonitorId']]) ) ? $MonitorById[$row['MonitorId']]->Name() : '';
|
||||||
|
$row['Cause'] = validHtmlStr($row['Cause']);
|
||||||
|
$row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime']));
|
||||||
|
$row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime']));
|
||||||
|
$row['Length'] = gmdate('H:i:s', $row['Length'] );
|
||||||
|
$row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default';
|
||||||
|
$row['Notes'] = htmlspecialchars($row['Notes']);
|
||||||
|
$row['DiskSpace'] = human_filesize($row['DiskSpace']);
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
$data['rows'] = $rows;
|
||||||
|
$data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
552
web/ajax/log.php
552
web/ajax/log.php
|
@ -1,466 +1,132 @@
|
||||||
<?php
|
<?php
|
||||||
ini_set('display_errors', '0');
|
global $Servers;
|
||||||
|
|
||||||
# Moved up here because it is used in several spots.
|
if ( !canView('System') ) {
|
||||||
# These are the valid columns that you can filter on.
|
ajaxError('Insufficient permissions to view log entries');
|
||||||
$filterFields = array('Component', 'ServerId', 'Pid', 'Level', 'File', 'Line');
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function buildLogQuery($action) {
|
// Only the query task is supported at the moment
|
||||||
global $filterFields;
|
if ( !isset($_REQUEST['task']) or $_REQUEST['task'] != 'query' ) {
|
||||||
|
ajaxError('Unrecognised action');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// The table we want our data from
|
||||||
|
$table = 'Logs';
|
||||||
|
|
||||||
$minTime = isset($_REQUEST['minTime']) ? $_REQUEST['minTime'] : NULL;
|
// The names of the dB columns in the log table we are interested in
|
||||||
$maxTime = isset($_REQUEST['maxTime']) ? $_REQUEST['maxTime'] : NULL;
|
$columns = array('TimeKey', 'Component', 'ServerId', 'Pid', 'Code', 'Message', 'File', 'Line');
|
||||||
|
|
||||||
$limit = 100;
|
// The names of columns shown in the log view that are NOT dB columns in the database
|
||||||
if ( isset($_REQUEST['limit']) ) {
|
$col_alt = array('DateTime', 'Server');
|
||||||
if ( ( !is_integer($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
|
||||||
ZM\Error('Invalid value for limit ' . $_REQUEST['limit']);
|
// Search contains a user entered string to search on
|
||||||
|
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
|
||||||
|
|
||||||
|
// Advanced search contains an array of "column name" => "search text" pairs
|
||||||
|
// Bootstrap table sends json_ecoded array, which we must decode
|
||||||
|
$advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array();
|
||||||
|
|
||||||
|
// Sort specifies the name of the column to sort on
|
||||||
|
$sort = 'TimeKey';
|
||||||
|
if ( isset($_REQUEST['sort']) ) {
|
||||||
|
if ( !in_array($_REQUEST['sort'], array_merge($columns, $col_alt)) ) {
|
||||||
|
ZM\Error('Invalid sort field: ' . $_REQUEST['sort']);
|
||||||
|
} else {
|
||||||
|
$sort = $_REQUEST['sort'];
|
||||||
|
if ( $sort == 'DateTime' ) $sort = 'TimeKey';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset specifies the starting row to return, used for pagination
|
||||||
|
$offset = 0;
|
||||||
|
if ( isset($_REQUEST['offset']) ) {
|
||||||
|
if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) {
|
||||||
|
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']);
|
||||||
|
} else {
|
||||||
|
$offset = $_REQUEST['offset'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order specifies the sort direction, either asc or desc
|
||||||
|
$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC';
|
||||||
|
|
||||||
|
// Limit specifies the number of rows to return
|
||||||
|
$limit = 100;
|
||||||
|
if ( isset($_REQUEST['limit']) ) {
|
||||||
|
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
||||||
|
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
|
||||||
} else {
|
} else {
|
||||||
$limit = $_REQUEST['limit'];
|
$limit = $_REQUEST['limit'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$sortField = 'TimeKey';
|
|
||||||
if ( isset($_REQUEST['sortField']) ) {
|
|
||||||
if ( !in_array($_REQUEST['sortField'], $filterFields) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) {
|
|
||||||
ZM\Error('Invalid sort field ' . $_REQUEST['sortField']);
|
|
||||||
} else {
|
|
||||||
$sortField = $_REQUEST['sortField'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sortOrder = (isset($_REQUEST['sortOrder']) and ($_REQUEST['sortOrder'] == 'asc')) ? 'asc' : 'desc';
|
|
||||||
$filter = isset($_REQUEST['filter']) ? $_REQUEST['filter'] : array();
|
|
||||||
|
|
||||||
$sql = $action.' FROM Logs';
|
$col_str = implode(', ', $columns);
|
||||||
$where = array();
|
$data = array();
|
||||||
$values = array();
|
$query = array();
|
||||||
if ( $minTime ) {
|
$query['values'] = array();
|
||||||
$where[] = 'TimeKey > ?';
|
$likes = array();
|
||||||
$values[] = $minTime;
|
$where = '';
|
||||||
} elseif ( $maxTime ) {
|
// There are two search bars in the log view, normal and advanced
|
||||||
$where[] = 'TimeKey < ?';
|
// Making an exuctive decision to ignore the normal search, when advanced search is in use
|
||||||
$values[] = $maxTime;
|
// Alternatively we could try to do both
|
||||||
}
|
if ( count($advsearch) ) {
|
||||||
|
|
||||||
foreach ( $filter as $field=>$value ) {
|
foreach ( $advsearch as $col=>$text ) {
|
||||||
if ( !in_array($field, $filterFields) ) {
|
if ( !in_array($col, array_merge($columns, $col_alt)) ) {
|
||||||
ZM\Error("'$field' is not in valid filter fields " . print_r($filterField, true));
|
ZM\Error("'$col' is not a sortable column name");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( $field == 'Level' ) {
|
$text = '%' .$text. '%';
|
||||||
$where[] = $field.' <= ?';
|
array_push($likes, $col.' LIKE ?');
|
||||||
$values[] = $value;
|
array_push($query['values'], $text);
|
||||||
} else {
|
|
||||||
$where[] = $field.' = ?';
|
|
||||||
$values[] = $value;
|
|
||||||
}
|
}
|
||||||
|
$wherevalues = $query['values'];
|
||||||
|
$where = ' WHERE (' .implode(' OR ', $likes). ')';
|
||||||
|
|
||||||
|
} else if ( $search != '' ) {
|
||||||
|
|
||||||
|
$search = '%' .$search. '%';
|
||||||
|
foreach ( $columns as $col ) {
|
||||||
|
array_push($likes, $col.' LIKE ?');
|
||||||
|
array_push($query['values'], $search);
|
||||||
}
|
}
|
||||||
if ( count($where) )
|
$wherevalues = $query['values'];
|
||||||
$sql.= ' WHERE '.join(' AND ', $where);
|
$where = ' WHERE (' .implode(' OR ', $likes). ')';
|
||||||
$sql .= ' ORDER BY '.$sortField.' '.$sortOrder.' LIMIT '.$limit;
|
}
|
||||||
|
|
||||||
return array('sql'=>$sql, 'values'=>$values);
|
$query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?';
|
||||||
} # function buildLogQuery($action)
|
array_push($query['values'], $offset, $limit);
|
||||||
|
|
||||||
switch ( $_REQUEST['task'] ) {
|
//ZM\Warning('Calling the following sql query: ' .$query['sql']);
|
||||||
case 'create' :
|
|
||||||
{
|
|
||||||
// Silently ignore bogus requests
|
|
||||||
if ( !empty($_POST['level']) && !empty($_POST['message']) ) {
|
|
||||||
ZM\logInit(array('id'=>'web_js'));
|
|
||||||
|
|
||||||
$string = $_POST['message'];
|
$data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total');
|
||||||
|
if ( $search != '' || count($advsearch) ) {
|
||||||
|
$data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues);
|
||||||
|
} else {
|
||||||
|
$data['total'] = $data['totalNotFiltered'];
|
||||||
|
}
|
||||||
|
|
||||||
$file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : '';
|
if ( !$Servers )
|
||||||
if ( !empty($_POST['line']) ) {
|
|
||||||
$line = validInt($_POST['line']);
|
|
||||||
} else {
|
|
||||||
$line = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
$levels = array_flip(ZM\Logger::$codes);
|
|
||||||
if ( !isset($levels[$_POST['level']]) ) {
|
|
||||||
ZM\Panic('Unexpected logger level '.$_POST['level']);
|
|
||||||
}
|
|
||||||
$level = $levels[$_POST['level']];
|
|
||||||
ZM\Logger::fetch()->logPrint($level, $string, $file, $line);
|
|
||||||
} else {
|
|
||||||
ZM\Error('Invalid log create: '.print_r($_POST, true));
|
|
||||||
}
|
|
||||||
ajaxResponse();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'delete' :
|
|
||||||
{
|
|
||||||
if ( !canEdit('System') )
|
|
||||||
ajaxError('Insufficient permissions to delete log entries');
|
|
||||||
|
|
||||||
$query = buildLogQuery('DELETE');
|
|
||||||
$result = dbQuery($query['sql'], $query['values']);
|
|
||||||
ajaxResponse(array('result'=>'Ok', 'deleted'=>$result->rowCount()));
|
|
||||||
}
|
|
||||||
case 'query' :
|
|
||||||
{
|
|
||||||
if ( !canView('System') )
|
|
||||||
ajaxError('Insufficient permissions to view log entries');
|
|
||||||
$total = dbFetchOne('SELECT count(*) AS Total FROM Logs', 'Total');
|
|
||||||
$query = buildLogQuery('SELECT *');
|
|
||||||
|
|
||||||
global $Servers;
|
|
||||||
if ( !$Servers )
|
|
||||||
$Servers = ZM\Server::find();
|
$Servers = ZM\Server::find();
|
||||||
$servers_by_Id = array();
|
$servers_by_Id = array();
|
||||||
# There is probably a better way to do this.
|
# There is probably a better way to do this.
|
||||||
foreach ( $Servers as $server ) {
|
foreach ( $Servers as $server ) {
|
||||||
$servers_by_Id[$server->Id()] = $server;
|
$servers_by_Id[$server->Id()] = $server;
|
||||||
}
|
}
|
||||||
|
|
||||||
$logs = array();
|
$rows = array();
|
||||||
$options = array();
|
foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) {
|
||||||
|
$row['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($row['TimeKey']));
|
||||||
|
$row['Server'] = ( $row['ServerId'] and isset($servers_by_Id[$row['ServerId']]) ) ? $servers_by_Id[$row['ServerId']]->Name() : '';
|
||||||
|
// First strip out any html tags
|
||||||
|
// Second strip out all characters that are not ASCII 32-126 (yes, 126)
|
||||||
|
$row['Message'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['Message']));
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
$data['rows'] = $rows;
|
||||||
|
$data['logstate'] = logState();
|
||||||
|
$data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG);
|
||||||
|
|
||||||
foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $log ) {
|
ajaxResponse($data);
|
||||||
|
|
||||||
$log['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($log['TimeKey']));
|
|
||||||
$log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : '';
|
|
||||||
$log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message']);
|
|
||||||
foreach ( $filterFields as $field ) {
|
|
||||||
if ( !isset($options[$field]) )
|
|
||||||
$options[$field] = array();
|
|
||||||
$value = $log[$field];
|
|
||||||
|
|
||||||
if ( $field == 'Level' ) {
|
|
||||||
if ( $value <= ZM\Logger::INFO )
|
|
||||||
$options[$field][$value] = ZM\Logger::$codes[$value];
|
|
||||||
else
|
|
||||||
$options[$field][$value] = 'DB'.$value;
|
|
||||||
} else if ( $field == 'ServerId' ) {
|
|
||||||
$options['ServerId'][$value] = ( $value and isset($servers_by_Id[$value]) ) ? $servers_by_Id[$value]->Name() : '';
|
|
||||||
} else if ( isset($log[$field]) ) {
|
|
||||||
$options[$field][$log[$field]] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$logs[] = $log;
|
|
||||||
} # end foreach log db row
|
|
||||||
|
|
||||||
foreach ( $options as $field => $values ) {
|
|
||||||
asort($options[$field]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$available = count($logs);
|
|
||||||
ajaxResponse(array(
|
|
||||||
'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG),
|
|
||||||
'total' => $total,
|
|
||||||
'available' => isset($available) ? $available : $total,
|
|
||||||
'logs' => $logs,
|
|
||||||
'state' => logState(),
|
|
||||||
'options' => $options,
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'export' :
|
|
||||||
{
|
|
||||||
if ( !canView('System') )
|
|
||||||
ajaxError('Insufficient permissions to export logs');
|
|
||||||
|
|
||||||
$minTime = isset($_POST['minTime']) ? $_POST['minTime'] : NULL;
|
|
||||||
$maxTime = isset($_POST['maxTime']) ? $_POST['maxTime'] : NULL;
|
|
||||||
if ( !is_null($minTime) && !is_null($maxTime) && ($minTime > $maxTime) ) {
|
|
||||||
$tempTime = $minTime;
|
|
||||||
$minTime = $maxTime;
|
|
||||||
$maxTime = $tempTime;
|
|
||||||
}
|
|
||||||
//$limit = isset($_POST['limit'])?$_POST['limit']:1000;
|
|
||||||
$filter = isset($_POST['filter'])?$_POST['filter']:array();
|
|
||||||
$sortField = 'TimeKey';
|
|
||||||
if ( isset($_POST['sortField']) ) {
|
|
||||||
if ( !in_array($_POST['sortField'], $filterFields) and ($_POST['sortField'] != 'TimeKey') ) {
|
|
||||||
ZM\Error('Invalid sort field '.$_POST['sortField']);
|
|
||||||
} else {
|
|
||||||
$sortField = $_POST['sortField'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc' : 'desc';
|
|
||||||
|
|
||||||
global $Servers;
|
|
||||||
if ( !$Servers )
|
|
||||||
$Servers = ZM\Server::find();
|
|
||||||
$servers_by_Id = array();
|
|
||||||
# There is probably a better way to do this.
|
|
||||||
foreach ( $Servers as $server ) {
|
|
||||||
$servers_by_Id[$server->Id()] = $server;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql = 'SELECT * FROM Logs';
|
|
||||||
$where = array();
|
|
||||||
$values = array();
|
|
||||||
if ( $minTime ) {
|
|
||||||
if ( preg_match('/(.+)(\.\d+)/', $minTime, $matches) ) {
|
|
||||||
# This handles sub second precision
|
|
||||||
$minTime = strtotime($matches[1]).$matches[2];
|
|
||||||
} else {
|
|
||||||
$minTime = strtotime($minTime);
|
|
||||||
}
|
|
||||||
$where[] = 'TimeKey >= ?';
|
|
||||||
$values[] = $minTime;
|
|
||||||
}
|
|
||||||
if ( $maxTime ) {
|
|
||||||
if ( preg_match('/(.+)(\.\d+)/', $maxTime, $matches) ) {
|
|
||||||
$maxTime = strtotime($matches[1]).$matches[2];
|
|
||||||
} else {
|
|
||||||
$maxTime = strtotime($maxTime);
|
|
||||||
}
|
|
||||||
$where[] = 'TimeKey <= ?';
|
|
||||||
$values[] = $maxTime;
|
|
||||||
}
|
|
||||||
foreach ( $filter as $field=>$value ) {
|
|
||||||
if ( $value != '' ) {
|
|
||||||
if ( $field == 'Level' ) {
|
|
||||||
$where[] = $field.' <= ?';
|
|
||||||
$values[] = $value;
|
|
||||||
} else {
|
|
||||||
$where[] = $field.' = ?';
|
|
||||||
$values[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( count($where) )
|
|
||||||
$sql.= ' WHERE '.join(' AND ', $where);
|
|
||||||
$sql .= ' ORDER BY '.$sortField.' '.$sortOrder;
|
|
||||||
//$sql .= " limit ".dbEscape($limit);
|
|
||||||
$format = isset($_POST['format']) ? $_POST['format'] : 'text';
|
|
||||||
switch ( $format ) {
|
|
||||||
case 'text' :
|
|
||||||
$exportExt = 'txt';
|
|
||||||
break;
|
|
||||||
case 'tsv' :
|
|
||||||
$exportExt = 'tsv';
|
|
||||||
break;
|
|
||||||
case 'html' :
|
|
||||||
$exportExt = 'html';
|
|
||||||
break;
|
|
||||||
case 'xml' :
|
|
||||||
$exportExt = 'xml';
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
ZM\Fatal("Unrecognised log export format '$format'");
|
|
||||||
}
|
|
||||||
$exportKey = substr(md5(rand()), 0, 8);
|
|
||||||
$exportFile = 'zm-log.'.$exportExt;
|
|
||||||
|
|
||||||
// mkdir will generate a warning if it exists, but that is ok
|
|
||||||
error_reporting(0);
|
|
||||||
if ( ! ( mkdir(ZM_DIR_EXPORTS) || file_exists(ZM_DIR_EXPORTS) ) ) {
|
|
||||||
ZM\Fatal('Can\'t create exports dir at \''.ZM_DIR_EXPORTS.'\'');
|
|
||||||
}
|
|
||||||
$exportPath = ZM_DIR_EXPORTS.'/zm-log-'.$exportKey.$exportExt;
|
|
||||||
ZM\Logger::Debug("Exporting to $exportPath");
|
|
||||||
if ( !($exportFP = fopen($exportPath, 'w')) )
|
|
||||||
ZM\Fatal("Unable to open log export file $exportPath");
|
|
||||||
$logs = array();
|
|
||||||
foreach ( dbFetchAll($sql, NULL, $values) as $log ) {
|
|
||||||
$log['DateTime'] = preg_replace('/^\d+/', strftime('%Y-%m-%d %H:%M:%S', intval($log['TimeKey'])), $log['TimeKey']);
|
|
||||||
$log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : '';
|
|
||||||
$logs[] = $log;
|
|
||||||
}
|
|
||||||
ZM\Logger::Debug(count($logs).' lines being exported by '.$sql.implode(',', $values));
|
|
||||||
|
|
||||||
switch( $format ) {
|
|
||||||
case 'text' :
|
|
||||||
{
|
|
||||||
foreach ( $logs as $log ) {
|
|
||||||
if ( $log['Line'] )
|
|
||||||
fprintf($exportFP, "%s %s[%d].%s-%s/%d [%s]\n",
|
|
||||||
$log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message']);
|
|
||||||
else
|
|
||||||
fprintf($exportFP, "%s %s[%d].%s-%s [%s]\n",
|
|
||||||
$log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message']);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'tsv' :
|
|
||||||
{
|
|
||||||
# This line doesn't need fprintf, it could use fwrite
|
|
||||||
fprintf($exportFP, join("\t",
|
|
||||||
translate('DateTime'),
|
|
||||||
translate('Component'),
|
|
||||||
translate('Server'),
|
|
||||||
translate('Pid'),
|
|
||||||
translate('Level'),
|
|
||||||
translate('Message'),
|
|
||||||
translate('File'),
|
|
||||||
translate('Line')
|
|
||||||
)."\n");
|
|
||||||
foreach ( $logs as $log ) {
|
|
||||||
fprintf($exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n",
|
|
||||||
$log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line']);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'html' :
|
|
||||||
{
|
|
||||||
fwrite($exportFP,
|
|
||||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>'.translate('ZoneMinderLog').'</title>
|
|
||||||
<style type="text/css">
|
|
||||||
body, h3, p, table, td {
|
|
||||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
th {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
th, td {
|
|
||||||
border: 1px solid #888888;
|
|
||||||
padding: 1px 2px;
|
|
||||||
}
|
|
||||||
tr.log-fat td {
|
|
||||||
background-color:#ffcccc;
|
|
||||||
font-weight: bold;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
tr.log-err td {
|
|
||||||
background-color:#ffcccc;
|
|
||||||
}
|
|
||||||
tr.log-war td {
|
|
||||||
background-color: #ffe4b5;
|
|
||||||
}
|
|
||||||
tr.log-dbg td {
|
|
||||||
color: #666666;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h3>'.translate('ZoneMinderLog').'</h3>
|
|
||||||
<p>'.htmlspecialchars(preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG)).'</p>
|
|
||||||
<p>'.count($logs).' '.translate('Logs').'</p>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr><th>'.translate('DateTime').'</th><th>'.translate('Component').'</th><th>'.translate('Server').'</th><th>'.translate('Pid').'</th><th>'.translate('Level').'</th><th>'.translate('Message').'</th><th>'.translate('File').'</th><th>'.translate('Line').'</th></tr>
|
|
||||||
');
|
|
||||||
foreach ( $logs as $log ) {
|
|
||||||
$classLevel = $log['Level'];
|
|
||||||
if ( $classLevel < ZM\Logger::FATAL ) {
|
|
||||||
$classLevel = ZM\Logger::FATAL;
|
|
||||||
} else if ( $classLevel > ZM\Logger::DEBUG ) {
|
|
||||||
$classLevel = ZM\Logger::DEBUG;
|
|
||||||
}
|
|
||||||
$logClass = 'log-'.strtolower(ZM\Logger::$codes[$classLevel]);
|
|
||||||
fprintf($exportFP, ' <tr class="%s"><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>
|
|
||||||
', $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line']);
|
|
||||||
}
|
|
||||||
fwrite($exportFP,
|
|
||||||
' </tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'xml' :
|
|
||||||
{
|
|
||||||
fwrite($exportFP,
|
|
||||||
'<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<logexport title="'.translate('ZoneMinderLog').'" date="'.htmlspecialchars(preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG)).'">
|
|
||||||
<selector>'.$_POST['selector'].'</selector>');
|
|
||||||
foreach ( $filter as $field=>$value )
|
|
||||||
if ( $value != '' )
|
|
||||||
fwrite( $exportFP,
|
|
||||||
' <filter>
|
|
||||||
<'.strtolower($field).'>'.htmlspecialchars($value).'</'.strtolower($field).'>
|
|
||||||
</filter>' );
|
|
||||||
fwrite( $exportFP,
|
|
||||||
'
|
|
||||||
<columns>
|
|
||||||
<column field="datetime">'.translate('DateTime').'</column>
|
|
||||||
<column field="component">'.translate('Component').'</column>
|
|
||||||
<column field="server">'.translate('Server').'</column>
|
|
||||||
<column field="pid">'.translate('Pid').'</column>
|
|
||||||
<column field="level">'.translate('Level').'</column>
|
|
||||||
<column field="message">'.translate('Message').'</column>
|
|
||||||
<column field="file">'.translate('File').'</column>
|
|
||||||
<column field="line">'.translate('Line').'</column>
|
|
||||||
</columns>
|
|
||||||
<logs count="'.count($logs).'">
|
|
||||||
' );
|
|
||||||
foreach ( $logs as $log ) {
|
|
||||||
fprintf( $exportFP,
|
|
||||||
' <log>
|
|
||||||
<datetime>%s</datetime>
|
|
||||||
<component>%s</component>
|
|
||||||
<server>%s</server>
|
|
||||||
<pid>%d</pid>
|
|
||||||
<level>%s</level>
|
|
||||||
<message><![CDATA[%s]]></message>
|
|
||||||
<file>%s</file>
|
|
||||||
<line>%d</line>
|
|
||||||
</log>
|
|
||||||
', $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] );
|
|
||||||
}
|
|
||||||
fwrite( $exportFP,
|
|
||||||
' </logs>
|
|
||||||
</logexport>' );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$exportExt = 'xml';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fclose( $exportFP );
|
|
||||||
ajaxResponse( array(
|
|
||||||
'key' => $exportKey,
|
|
||||||
'format' => $format,
|
|
||||||
) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'download' :
|
|
||||||
{
|
|
||||||
if ( !canView('System') )
|
|
||||||
ajaxError('Insufficient permissions to download logs');
|
|
||||||
|
|
||||||
if ( empty($_REQUEST['key']) )
|
|
||||||
ZM\Fatal('No log export key given');
|
|
||||||
$exportKey = $_REQUEST['key'];
|
|
||||||
if ( empty($_REQUEST['format']) )
|
|
||||||
ZM\Fatal('No log export format given');
|
|
||||||
$format = $_REQUEST['format'];
|
|
||||||
|
|
||||||
switch ( $format ) {
|
|
||||||
case 'text' :
|
|
||||||
$exportExt = 'txt';
|
|
||||||
break;
|
|
||||||
case 'tsv' :
|
|
||||||
$exportExt = 'tsv';
|
|
||||||
break;
|
|
||||||
case 'html' :
|
|
||||||
$exportExt = 'html';
|
|
||||||
break;
|
|
||||||
case 'xml' :
|
|
||||||
$exportExt = 'xml';
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
ZM\Fatal("Unrecognised log export format '$format'");
|
|
||||||
}
|
|
||||||
|
|
||||||
$exportFile = 'zm-log.'.$exportExt;
|
|
||||||
$exportPath = ZM_DIR_EXPORTS.'/zm-log-'.$exportKey.$exportExt;
|
|
||||||
|
|
||||||
header('Pragma: public');
|
|
||||||
header('Expires: 0');
|
|
||||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
|
||||||
header('Cache-Control: private', false); // required by certain browsers
|
|
||||||
header('Content-Description: File Transfer');
|
|
||||||
header('Content-Disposition: attachment; filename="'.$exportFile.'"');
|
|
||||||
header('Content-Transfer-Encoding: binary');
|
|
||||||
header('Content-Type: application/force-download');
|
|
||||||
header('Content-Length: '.filesize($exportPath));
|
|
||||||
readfile($exportPath);
|
|
||||||
exit(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // end switch ( $_REQUEST['task'] )
|
|
||||||
ajaxError('Unrecognised action or insufficient permissions');
|
|
||||||
?>
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ if ( empty($_REQUEST['modal']) ) {
|
||||||
$modal = validJsStr($_REQUEST['modal']);
|
$modal = validJsStr($_REQUEST['modal']);
|
||||||
$data = array();
|
$data = array();
|
||||||
|
|
||||||
ZM\Logger::Debug("Including modals/$modal.php");
|
ZM\Debug("Including modals/$modal.php");
|
||||||
# Shouldn't be necessary but at the moment we have last .conf file contents
|
# Shouldn't be necessary but at the moment we have last .conf file contents
|
||||||
ob_start();
|
ob_start();
|
||||||
@$result = include('modals/'.$modal.'.php');
|
@$result = include('modals/'.$modal.'.php');
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if ( !canEdit('Monitors') ) return;
|
||||||
|
|
||||||
|
$monitor = dbFetchOne('SELECT C.*,M.* FROM Monitors AS M INNER JOIN Controls AS C ON (M.ControlId = C.Id ) WHERE M.Id = ?', NULL, array( $_REQUEST['mid']) );
|
||||||
|
|
||||||
|
$labels = array();
|
||||||
|
foreach( dbFetchAll( 'SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, array( $monitor['Id'] ) ) as $row ) {
|
||||||
|
$labels[$row['Preset']] = $row['Label'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$presets = array();
|
||||||
|
for ( $i = 1; $i <= $monitor['NumPresets']; $i++ ) {
|
||||||
|
$presets[$i] = translate('Preset').' '.$i;
|
||||||
|
if ( !empty($labels[$i]) ) {
|
||||||
|
$presets[$i] .= ' ('.validHtmlStr($labels[$i]).')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="modal" id="ctrlPresetModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title"><?php echo translate('SetPreset') ?></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form name="contentForm" id="ctrlPresetForm" method="post" action="?">
|
||||||
|
<?php
|
||||||
|
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
|
||||||
|
echo getCSRFinputHTML();
|
||||||
|
?>
|
||||||
|
<input type="hidden" name="view" value="control"/>
|
||||||
|
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>"/>
|
||||||
|
<input type="hidden" name="action" value="control"/>
|
||||||
|
<input type="hidden" name="control" value="presetSet"/>
|
||||||
|
<input type="hidden" name="showControls" value="1"/>
|
||||||
|
<p><?php echo buildSelect('preset', $presets) ?></p>
|
||||||
|
<p>
|
||||||
|
<label for="newLabel"><?php echo translate('NewLabel') ?></label>
|
||||||
|
<input type="text" name="newLabel" id="newLabel" value=""/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" class="btn btn-primary" id="cPresetSubmitModal" value="Save"><?php echo translate('Save') ?></button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,18 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
// This is the HTML representing the Delete confirmation modal on the Events page
|
// This is the HTML representing the Delete confirmation modal on the Events page and other pages
|
||||||
|
|
||||||
|
$delTextKey = isset($_REQUEST['key']) ? $_REQUEST['key'] : 'ConfirmDeleteEvents';
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<div id="deleteConfirm" class="modal fade" class="modal" tabindex="-1">
|
<div id="deleteConfirm" class="modal fade" class="modal" tabindex="-1">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">Delete Confirmation</h5>
|
<h5 class="modal-title"><?php echo translate('ConfirmDeleteTitle') ?></h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p><?php echo translate('ConfirmDeleteEvents') ?></p>
|
<p><?php echo translate($delTextKey) ?></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button id="delCancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
|
<button id="delCancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if ( !canEdit( 'Devices' ) ) return;
|
||||||
|
|
||||||
|
if ( !empty($_REQUEST['did']) ) {
|
||||||
|
$newDevice = dbFetchOne( 'SELECT * FROM Devices WHERE Id = ?', NULL, array($_REQUEST['did']) );
|
||||||
|
} else {
|
||||||
|
$newDevice = array(
|
||||||
|
"Id" => "",
|
||||||
|
"Name" => "New Device",
|
||||||
|
"KeyString" => ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="modal fade" id="deviceModal" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="staticBackdropLabel"><?php echo translate('Device')." - ".validHtmlStr($newDevice['Name']) ?></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="deviceModalForm" name="contentForm" method="get" action="?view=device&action=device">
|
||||||
|
<?php
|
||||||
|
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
|
||||||
|
echo getCSRFinputHTML();
|
||||||
|
?>
|
||||||
|
<input type="hidden" name="view" value="device"/>
|
||||||
|
<input type="hidden" name="action" value="device"/>
|
||||||
|
<input type="hidden" name="did" value="<?php echo $newDevice['Id'] ?>"/>
|
||||||
|
<table class="table-sm table-borderless" cellspacing="0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row" class="text-right pr-2"><?php echo translate('Name') ?></th>
|
||||||
|
<td><input type="text" name="newDevice[Name]" value="<?php echo validHtmlStr($newDevice['Name']) ?>"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row" class="text-right pr-2"><?php echo translate('KeyString') ?></th>
|
||||||
|
<td><input type="text" name="newDevice[KeyString]" value="<?php echo validHtmlStr($newDevice['KeyString']) ?>"/></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" id="deviceSaveBtn" class="btn btn-primary"><?php echo translate('Save') ?></button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
// This is the HTML representing the Download event modal on the Events page and other pages
|
||||||
|
|
||||||
|
function getDLEventHTML($eid, $eids) {
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
if ( !empty($eid) ) {
|
||||||
|
$result .= '<input type="hidden" name="id" value="' .validInt($eid). '"/>'.PHP_EOL;
|
||||||
|
|
||||||
|
$Event = new ZM\Event($eid);
|
||||||
|
if ( !$Event->Id() ) {
|
||||||
|
ZM\Error('Invalid event id');
|
||||||
|
$result .= '<div class="error">Invalid event id</div>'.PHP_EOL;
|
||||||
|
} else {
|
||||||
|
$result .= 'Downloading event ' . $Event->Id . '. Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() ).PHP_EOL;
|
||||||
|
}
|
||||||
|
} else if ( !empty($eids) ) {
|
||||||
|
$total_size = 0;
|
||||||
|
foreach ( $eids as $eid ) {
|
||||||
|
if ( !validInt($eid) ) {
|
||||||
|
ZM\Warning("Invalid event id in eids[] $eid");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$Event = new ZM\Event($eid);
|
||||||
|
$total_size += $Event->DiskSpace();
|
||||||
|
$result .= '<input type="hidden" name="eids[]" value="' .validInt($eid). '"/>'.PHP_EOL;
|
||||||
|
}
|
||||||
|
unset($eid);
|
||||||
|
$result .= 'Downloading ' . count($eids) . ' events. Resulting file should be approximately ' . human_filesize($total_size).PHP_EOL;
|
||||||
|
} else {
|
||||||
|
$result .= '<div class="warning">There are no events found. Resulting download will be empty.</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !canView('Events') ) {
|
||||||
|
$view = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$eid = isset($_REQUEST['eid']) ? $_REQUEST['eid'] : '';
|
||||||
|
$eids = isset($_REQUEST['eids']) ? $_REQUEST['eids'] : array();
|
||||||
|
$generated = isset($_REQUEST['generated']) ? $_REQUEST['generated'] : '';
|
||||||
|
|
||||||
|
$total_size = 0;
|
||||||
|
if ( isset($_SESSION['montageReviewFilter']) and !$eids ) {
|
||||||
|
# Handles montageReview filter
|
||||||
|
$eventsSql = 'SELECT E.Id, E.DiskSpace FROM Events AS E WHERE 1';
|
||||||
|
$eventsSql .= $_SESSION['montageReviewFilter']['sql'];
|
||||||
|
$results = dbQuery($eventsSql);
|
||||||
|
while ( $event_row = dbFetchNext( $results ) ) {
|
||||||
|
array_push($eids, $event_row['Id']);
|
||||||
|
$total_size += $event_row['DiskSpace'];
|
||||||
|
}
|
||||||
|
if ( ! count($eids) ) {
|
||||||
|
ZM\Error("No events found for download using $eventsSql");
|
||||||
|
}
|
||||||
|
#session_start();
|
||||||
|
#unset($_SESSION['montageReviewFilter']);
|
||||||
|
#session_write_close();
|
||||||
|
#} else {
|
||||||
|
#Debug("NO montageReviewFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
$exportFormat = '';
|
||||||
|
if ( isset($_REQUEST['exportFormat']) ) {
|
||||||
|
if ( !in_array($_REQUEST['exportFormat'], array('zip', 'tar')) ) {
|
||||||
|
ZM\Error('Invalid exportFormat: '.$_REQUEST['exportFormat']);
|
||||||
|
} else {
|
||||||
|
$exportFormat = $_REQUEST['exportFormat'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$focusWindow = true;
|
||||||
|
$connkey = isset($_REQUEST['connkey']) ? validInt($_REQUEST['connkey']) : generateConnKey();
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div id="downloadModal" class="modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title"><?php echo translate('Download') ?></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form name="contentForm" id="downloadForm" method="post" action="?">
|
||||||
|
<?php
|
||||||
|
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
|
||||||
|
echo getCSRFinputHTML();
|
||||||
|
?>
|
||||||
|
<input type="hidden" name="connkey" value="<?php echo $connkey; ?>"/>
|
||||||
|
<input type="hidden" name="exportVideo" value="1"/>
|
||||||
|
<div>
|
||||||
|
<?php echo getDLEventHTML($eid, $eids) ?>
|
||||||
|
</div>
|
||||||
|
<div class="font-weight-bold py-2">
|
||||||
|
<span class="pr-3"><?php echo translate('ExportFormat') ?></span>
|
||||||
|
<input type="radio" id="exportFormatTar" name="exportFormat" value="tar"/>
|
||||||
|
<label for="exportFormatTar"><?php echo translate('ExportFormatTar') ?></label>
|
||||||
|
<input type="radio" id="exportFormatZip" name="exportFormat" value="zip" checked="checked"/>
|
||||||
|
<label for="exportFormatZip"><?php echo translate('ExportFormatZip') ?></label>
|
||||||
|
</div>
|
||||||
|
<button type="button" id="exportButton" name="exportButton" value="GenerateDownload"><?php echo translate('GenerateDownload') ?></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<h2 id="exportProgress" class="text-warning invisible">
|
||||||
|
<span class="spinner-grow" role="status" aria-hidden="true"></span>
|
||||||
|
Exporting...
|
||||||
|
</h2>
|
||||||
|
<h3><a id="downloadLink" href="#"></a></h3>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,135 @@
|
||||||
|
<?php
|
||||||
|
// This is the HTML representing the Group modal accessed from the Groups (plural) view
|
||||||
|
|
||||||
|
//
|
||||||
|
// DEFINE SUPPORTING FUNCTIONS
|
||||||
|
//
|
||||||
|
|
||||||
|
function get_Id( $G ) {
|
||||||
|
return $G->Id();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_children($Group) {
|
||||||
|
global $children;
|
||||||
|
|
||||||
|
$kids = array();
|
||||||
|
if ( isset( $children[$Group->Id()] ) ) {
|
||||||
|
$kids += array_map('get_Id', $children[$Group->Id()]);
|
||||||
|
foreach ( $children[$Group->Id()] as $G ) {
|
||||||
|
foreach ( get_children($G) as $id ) {
|
||||||
|
$kids[] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $kids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parentGrpSelect($newGroup) {
|
||||||
|
$Groups = array();
|
||||||
|
foreach ( ZM\Group::find() as $Group ) {
|
||||||
|
$Groups[$Group->Id()] = $Group;
|
||||||
|
}
|
||||||
|
|
||||||
|
# This array is indexed by parent_id
|
||||||
|
$children = array();
|
||||||
|
|
||||||
|
foreach ( $Groups as $id=>$Group ) {
|
||||||
|
if ( $Group->ParentId() != null ) {
|
||||||
|
if ( ! isset( $children[$Group->ParentId()] ) )
|
||||||
|
$children[$Group->ParentId()] = array();
|
||||||
|
$children[$Group->ParentId()][] = $Group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$kids = get_children($newGroup);
|
||||||
|
if ( $newGroup->Id() )
|
||||||
|
$kids[] = $newGroup->Id();
|
||||||
|
$sql = 'SELECT Id,Name FROM `Groups`'.(count($kids)?' WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids)).')' : '').' ORDER BY Name';
|
||||||
|
$options = array(''=>'None');
|
||||||
|
|
||||||
|
foreach ( dbFetchAll($sql, null, $kids) as $option ) {
|
||||||
|
$options[$option['Id']] = str_repeat(' ', $Groups[$option['Id']]->depth()) . $option['Name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlSelect('newGroup[ParentId]', $options, $newGroup->ParentId(), array('data-on-change'=>'configModalBtns'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function monitorList($newGroup) {
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
$monitors = dbFetchAll('SELECT Id,Name FROM Monitors ORDER BY Sequence ASC');
|
||||||
|
$monitorIds = $newGroup->MonitorIds();
|
||||||
|
foreach ( $monitors as $monitor ) {
|
||||||
|
if ( visibleMonitor($monitor['Id']) ) {
|
||||||
|
$result .= '<option value="' .$monitor['Id']. '"' .( in_array( $monitor['Id'], $monitorIds ) ? ' selected="selected"' : ''). '>' .validHtmlStr($monitor['Name']). '</option>'.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// INITIAL SANITY CHECKS
|
||||||
|
//
|
||||||
|
|
||||||
|
if ( !canEdit('Groups') ) {
|
||||||
|
$view = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !empty($_REQUEST['gid']) ) {
|
||||||
|
$newGroup = new ZM\Group($_REQUEST['gid']);
|
||||||
|
} else {
|
||||||
|
$newGroup = new ZM\Group();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BEGIN HTML
|
||||||
|
//
|
||||||
|
?>
|
||||||
|
<div id="groupModal" class="modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title"><?php echo translate('Group').($newGroup->Name() ? ' - ' .validHtmlStr($newGroup->Name()) : '') ?></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="groupForm" name="groupForm" method="post" action="?view=group&action=save">
|
||||||
|
<?php
|
||||||
|
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
|
||||||
|
echo getCSRFinputHTML();
|
||||||
|
?>
|
||||||
|
<input type="hidden" name="view" value="group"/>
|
||||||
|
<input type="hidden" name="gid" value="<?php echo $newGroup->Id() ?>"/>
|
||||||
|
<table id="groupModalTable" class="table-sm table-borderless">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th class="text-right pr-3" scope="row"><?php echo translate('Name') ?></th>
|
||||||
|
<td><input type="text" name="newGroup[Name]" value="<?php echo validHtmlStr($newGroup->Name()) ?>" data-on-input="configModalBtns"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="text-right pr-3" scope="row"><?php echo translate('ParentGroup') ?></th>
|
||||||
|
<td><?php echo parentGrpSelect($newGroup) ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="text-right pr-3" scope="row"><?php echo translate('Monitor') ?></th>
|
||||||
|
<td>
|
||||||
|
<select name="newGroup[MonitorIds][]" class="chosen" multiple="multiple" data-on-change="configModalBtns">
|
||||||
|
<?php echo monitorList($newGroup) ?>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" class="btn btn-primary" name="action" id="grpModalSaveBtn" value="save"<?php $newGroup->Id() ? '' : ' disabled="disabled"'?>><?php echo translate('Save') ?></button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -30,14 +30,73 @@ global $CLANG;
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p><?php echo sprintf( $CLANG['CurrentLogin'], $user['Username'] ) ?></p>
|
<p><?php echo sprintf( $CLANG['CurrentLogin'], $user['Username'] ) ?></p>
|
||||||
|
<?php if ( canView('System') ) { ?>
|
||||||
|
<p>Other logged in users:<br/>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-left"><?php echo translate('Username') ?></th>
|
||||||
|
<th class="text-left"><?php echo translate('IPAddress') ?></th>
|
||||||
|
<th class="text-left"><?php echo translate('Last Access') ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
require_once('includes/User.php');
|
||||||
|
$result = dbQuery('SELECT * FROM Sessions ORDER BY access DESC');
|
||||||
|
if ( ! $result ) return;
|
||||||
|
|
||||||
|
$current_session = $_SESSION;
|
||||||
|
zm_session_start();
|
||||||
|
|
||||||
|
$user_cache = array();
|
||||||
|
while ( $row = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||||
|
$_SESSION = array();
|
||||||
|
if ( ! session_decode($row['data']) ) {
|
||||||
|
ZM\Warning('Failed to decode ' . $row['data']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ZM\Debug(print_r($_SESSION, true));
|
||||||
|
if ( isset($_SESSION['last_time']) ) {
|
||||||
|
# This is a dead session
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( !isset($_SESSION['username']) ) {
|
||||||
|
# Not logged in
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( isset($user_cache[$_SESSION['username']]) ) {
|
||||||
|
$user = $user_cache[$_SESSION['username']];
|
||||||
|
} else {
|
||||||
|
$user = ZM\User::find_one(array('Username'=>$_SESSION['username']));
|
||||||
|
if ( ! $user ) {
|
||||||
|
ZM\Debug('User not found for ' . $_SESSION['username']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$user_cache[$_SESSION['username']] = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<tr>
|
||||||
|
<td>'.$user->Username().'</td>
|
||||||
|
<td>'.$_SESSION['remoteAddr'].'</td>
|
||||||
|
<td>'.strftime(STRF_FMT_DATETIME_SHORTER, $row['access']).'</td>
|
||||||
|
</tr>
|
||||||
|
';
|
||||||
|
} # end while
|
||||||
|
session_abort();
|
||||||
|
$_SESSION = $current_session;
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php } # end if canView(System) ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<form name="logoutForm" id="logoutForm" method="post" action="?">
|
<form name="logoutForm" id="logoutForm" method="post" action="?view=logout">
|
||||||
<?php
|
<?php
|
||||||
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
|
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
|
||||||
echo getCSRFinputHTML();
|
echo getCSRFinputHTML();
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="view" value="logout"/>
|
|
||||||
<button type="submit" name="action" value="logout"><?php echo translate('Logout') ?></button>
|
<button type="submit" name="action" value="logout"><?php echo translate('Logout') ?></button>
|
||||||
<?php if ( ZM_USER_SELF_EDIT ) echo '<button type="submit" name="action" value="config">'.translate('Config').'</button>'.PHP_EOL; ?>
|
<?php if ( ZM_USER_SELF_EDIT ) echo '<button type="submit" name="action" value="config">'.translate('Config').'</button>'.PHP_EOL; ?>
|
||||||
<button type="button" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
|
<button type="button" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
|
||||||
|
|
|
@ -1,27 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
//
|
if ( !canView('Control') ) return;
|
||||||
// ZoneMinder web settings view file, $Date$, $Revision$
|
|
||||||
// Copyright (C) 2001-2008 Philip Coombes
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License
|
|
||||||
// as published by the Free Software Foundation; either version 2
|
|
||||||
// of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
//
|
|
||||||
|
|
||||||
if ( !canView('Control') ) {
|
|
||||||
$view = 'error';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$monitor = ZM\Monitor::find_one(array('Id'=>$_REQUEST['mid']));
|
$monitor = ZM\Monitor::find_one(array('Id'=>$_REQUEST['mid']));
|
||||||
|
|
||||||
$zmuCommand = getZmuCommand(' -m '.escapeshellarg($_REQUEST['mid']).' -B -C -H -O');
|
$zmuCommand = getZmuCommand(' -m '.escapeshellarg($_REQUEST['mid']).' -B -C -H -O');
|
||||||
|
@ -35,17 +14,22 @@ if ( $zmuOutput ) {
|
||||||
$monitor->Colour($colour);
|
$monitor->Colour($colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
$focusWindow = true;
|
|
||||||
|
|
||||||
xhtmlHeaders(__FILE__, validHtmlStr($monitor->Name()).' - '.translate('Settings'));
|
|
||||||
?>
|
?>
|
||||||
<body>
|
<div class="modal" id="settingsModal" tabindex="-1">
|
||||||
<div id="page">
|
<div class="modal-dialog">
|
||||||
<div id="header">
|
<div class="modal-content">
|
||||||
<h2><?php echo validHtmlStr($monitor->Name()) ?> - <?php echo translate('Settings') ?></h2>
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title"><?php echo validHtmlStr($monitor->Name()) ?> - <?php echo translate('Settings') ?></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div class="modal-body">
|
||||||
<form name="contentForm" id="contentForm" method="post" action="?">
|
<form name="contentForm" id="settingsForm" method="post" action="?">
|
||||||
|
<?php
|
||||||
|
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
|
||||||
|
echo getCSRFinputHTML();
|
||||||
|
?>
|
||||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||||
<input type="hidden" name="action" value="settings"/>
|
<input type="hidden" name="action" value="settings"/>
|
||||||
<input type="hidden" name="mid" value="<?php echo validInt($_REQUEST['mid']) ?>"/>
|
<input type="hidden" name="mid" value="<?php echo validInt($_REQUEST['mid']) ?>"/>
|
||||||
|
@ -69,11 +53,12 @@ xhtmlHeaders(__FILE__, validHtmlStr($monitor->Name()).' - '.translate('Settings'
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div id="contentButtons">
|
</div>
|
||||||
<button type="submit" value="Save"<?php echo canView('Control') ? '' : ' disabled="disabled"' ?>><?php echo translate('Save') ?></button>
|
<div class="modal-footer">
|
||||||
<button type="button" value="Close" data-on-click="closeWindow"/><?php echo translate('Close') ?></button>
|
<button type="submit" class="btn btn-primary" id="settingsSubmitModal" value="Save"<?php echo canView('Control') ? '' : ' disabled="disabled"' ?>><?php echo translate('Save') ?></button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php xhtmlFooter() ?>
|
</div>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
$error='';
|
||||||
|
|
||||||
|
if ( !canEdit('System') ) {
|
||||||
|
$error = 'Insufficient permissions';
|
||||||
|
} else if ( !defined('ZM_PATH_SHUTDOWN') or ZM_PATH_SHUTDOWN == '' ) {
|
||||||
|
$error = 'ZM_PATH_SHUTDOWN is not defined. This is normally configured in /etc/zm/conf.d/01-system-paths.conf';
|
||||||
|
} else if ( !file_exists(ZM_PATH_SHUTDOWN) ) {
|
||||||
|
$error = 'Path does not exist for ZM_PATH_SHUTDOWN. Current value is '.ZM_PATH_SHUTDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $error ) {
|
||||||
|
ZM\Error($error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="modal" id="shutdownModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title"><?php echo translate('Shutdown').' '.translate('Restart') ?></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p class="warning"><h2>Warning</h2>
|
||||||
|
This command will either shutdown or restart all ZoneMinder Servers<br/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="radio" name="when" value="now" id="whennow"/><label for="whennow">Now</label>
|
||||||
|
<input type="radio" name="when" value="1min" id="when1min" checked="checked"/><label for="when1min">1 Minute</label>
|
||||||
|
</p>
|
||||||
|
<p id="respText" class="invisible">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" data-command="cancel" data-on-click-this="manageShutdownBtns" id="cancelBtn" disabled><?php echo translate('Cancel') ?></button>
|
||||||
|
<button type="button" class="btn btn-primary" data-command="restart" data-on-click-this="manageShutdownBtns"><?php echo translate('Restart') ?></button>
|
||||||
|
<button type="button" class="btn btn-primary" data-command="shutdown" data-on-click-this="manageShutdownBtns"><?php echo translate('Shutdown') ?></button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Close') ?></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,132 +0,0 @@
|
||||||
<?php
|
|
||||||
global $Servers;
|
|
||||||
|
|
||||||
if ( !canView('System') ) {
|
|
||||||
ajaxError('Insufficient permissions to view log entries');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only the query task is supported at the moment
|
|
||||||
if ( !isset($_REQUEST['task']) or $_REQUEST['task'] != 'query' ) {
|
|
||||||
ajaxError('Unrecognised action');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// The table we want our data from
|
|
||||||
$table = 'Logs';
|
|
||||||
|
|
||||||
// The names of the dB columns in the log table we are interested in
|
|
||||||
$columns = array('TimeKey', 'Component', 'ServerId', 'Pid', 'Code', 'Message', 'File', 'Line');
|
|
||||||
|
|
||||||
// The names of columns shown in the log view that are NOT dB columns in the database
|
|
||||||
$col_alt = array('DateTime', 'Server');
|
|
||||||
|
|
||||||
// Search contains a user entered string to search on
|
|
||||||
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
|
|
||||||
|
|
||||||
// Advanced search contains an array of "column name" => "search text" pairs
|
|
||||||
// Bootstrap table sends json_ecoded array, which we must decode
|
|
||||||
$advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array();
|
|
||||||
|
|
||||||
// Sort specifies the name of the column to sort on
|
|
||||||
$sort = 'TimeKey';
|
|
||||||
if ( isset($_REQUEST['sort']) ) {
|
|
||||||
if ( !in_array($_REQUEST['sort'], array_merge($columns, $col_alt)) ) {
|
|
||||||
ZM\Error('Invalid sort field: ' . $_REQUEST['sort']);
|
|
||||||
} else {
|
|
||||||
$sort = $_REQUEST['sort'];
|
|
||||||
if ( $sort == 'DateTime' ) $sort = 'TimeKey';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Offset specifies the starting row to return, used for pagination
|
|
||||||
$offset = 0;
|
|
||||||
if ( isset($_REQUEST['offset']) ) {
|
|
||||||
if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) {
|
|
||||||
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']);
|
|
||||||
} else {
|
|
||||||
$offset = $_REQUEST['offset'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order specifies the sort direction, either asc or desc
|
|
||||||
$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC';
|
|
||||||
|
|
||||||
// Limit specifies the number of rows to return
|
|
||||||
$limit = 100;
|
|
||||||
if ( isset($_REQUEST['limit']) ) {
|
|
||||||
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
|
||||||
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
|
|
||||||
} else {
|
|
||||||
$limit = $_REQUEST['limit'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$col_str = implode(', ', $columns);
|
|
||||||
$data = array();
|
|
||||||
$query = array();
|
|
||||||
$query['values'] = array();
|
|
||||||
$likes = array();
|
|
||||||
$where = '';
|
|
||||||
// There are two search bars in the log view, normal and advanced
|
|
||||||
// Making an exuctive decision to ignore the normal search, when advanced search is in use
|
|
||||||
// Alternatively we could try to do both
|
|
||||||
if ( count($advsearch) ) {
|
|
||||||
|
|
||||||
foreach ( $advsearch as $col=>$text ) {
|
|
||||||
if ( !in_array($col, array_merge($columns, $col_alt)) ) {
|
|
||||||
ZM\Error("'$col' is not a sortable column name");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$text = '%' .$text. '%';
|
|
||||||
array_push($likes, $col.' LIKE ?');
|
|
||||||
array_push($query['values'], $text);
|
|
||||||
}
|
|
||||||
$wherevalues = $query['values'];
|
|
||||||
$where = ' WHERE (' .implode(' OR ', $likes). ')';
|
|
||||||
|
|
||||||
} else if ( $search != '' ) {
|
|
||||||
|
|
||||||
$search = '%' .$search. '%';
|
|
||||||
foreach ( $columns as $col ) {
|
|
||||||
array_push($likes, $col.' LIKE ?');
|
|
||||||
array_push($query['values'], $search);
|
|
||||||
}
|
|
||||||
$wherevalues = $query['values'];
|
|
||||||
$where = ' WHERE (' .implode(' OR ', $likes). ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
$query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?';
|
|
||||||
array_push($query['values'], $offset, $limit);
|
|
||||||
|
|
||||||
//ZM\Warning('Calling the following sql query: ' .$query['sql']);
|
|
||||||
|
|
||||||
$data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total');
|
|
||||||
if ( $search != '' || count($advsearch) ) {
|
|
||||||
$data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues);
|
|
||||||
} else {
|
|
||||||
$data['total'] = $data['totalNotFiltered'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !$Servers )
|
|
||||||
$Servers = ZM\Server::find();
|
|
||||||
$servers_by_Id = array();
|
|
||||||
# There is probably a better way to do this.
|
|
||||||
foreach ( $Servers as $server ) {
|
|
||||||
$servers_by_Id[$server->Id()] = $server;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rows = array();
|
|
||||||
foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) {
|
|
||||||
$row['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($row['TimeKey']));
|
|
||||||
$row['Server'] = ( $row['ServerId'] and isset($servers_by_Id[$row['ServerId']]) ) ? $servers_by_Id[$row['ServerId']]->Name() : '';
|
|
||||||
// First strip out any html tags
|
|
||||||
// Second strip out all characters that are not ASCII 32-126 (yes, 126)
|
|
||||||
$row['Message'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['Message']));
|
|
||||||
$rows[] = $row;
|
|
||||||
}
|
|
||||||
$data['rows'] = $rows;
|
|
||||||
$data['logstate'] = logState();
|
|
||||||
$data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG);
|
|
||||||
|
|
||||||
ajaxResponse($data);
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web action file
|
||||||
|
// Copyright (C) 2019 ZoneMinder LLC
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
if ( !canEdit('System') ) {
|
||||||
|
$message = 'Need System permissions to shutdown server';
|
||||||
|
} else if ( !isset($_REQUEST['command']) ) {
|
||||||
|
$message = 'A command is required. Cannot continue';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $message ) {
|
||||||
|
ZM\Warning($message);
|
||||||
|
ajaxError($message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
$when = isset($_REQUEST['when']) and $_REQUEST['when'] == 'now' ? 'now' : '+1';
|
||||||
|
$command = $_REQUEST['command'];
|
||||||
|
|
||||||
|
if ( $command == 'shutdown' ) {
|
||||||
|
exec('sudo -n '.ZM_PATH_SHUTDOWN." -P $when 2>&1", $data['output'], $data['rc']);
|
||||||
|
#exec('sudo -n /bin/systemctl poweroff -i 2>&1', $data['output'], $data['rc']);
|
||||||
|
ZM\Debug('Shutdown output ' .$data['rc'].' '.implode("\n",$data['output']));
|
||||||
|
#ZM\Debug("Shutdown output " . shell_exec('/bin/systemctl poweroff -i 2>&1'));
|
||||||
|
} else if ( $command == 'restart' ) {
|
||||||
|
$data['output'] = array();
|
||||||
|
exec('sudo -n '.ZM_PATH_SHUTDOWN." -r $when 2>&1", $data['output'], $data['rc']);
|
||||||
|
#exec('sudo -n /bin/systemctl reboot -i 2>&1', $data['output'], $data['rc']);
|
||||||
|
ZM\Debug("Shutdown output " . implode("\n",$data['output']));
|
||||||
|
} else if ( $command == 'cancel' ) {
|
||||||
|
$data['output'] = array();
|
||||||
|
exec('sudo '.ZM_PATH_SHUTDOWN.' -c 2>&1', $data['output'], $data['rc']);
|
||||||
|
} else {
|
||||||
|
ajaxError('Unknwn command:'.$command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ajaxResponse($data);
|
||||||
|
return;
|
||||||
|
?>
|
|
@ -336,7 +336,7 @@ function collectData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ZM\Logger::Debug(print_r($data, true));
|
#ZM\Debug(print_r($data, true));
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +411,10 @@ function getNearEvents() {
|
||||||
global $user, $sortColumn, $sortOrder;
|
global $user, $sortColumn, $sortOrder;
|
||||||
|
|
||||||
$eventId = $_REQUEST['id'];
|
$eventId = $_REQUEST['id'];
|
||||||
|
$NearEvents = array( 'EventId'=>$eventId );
|
||||||
|
|
||||||
$event = dbFetchOne('SELECT * FROM Events WHERE Id=?', NULL, array($eventId));
|
$event = dbFetchOne('SELECT * FROM Events WHERE Id=?', NULL, array($eventId));
|
||||||
|
if ( !$event ) return $NearEvents;
|
||||||
|
|
||||||
if ( isset($_REQUEST['filter']) )
|
if ( isset($_REQUEST['filter']) )
|
||||||
parseFilter( $_REQUEST['filter'] );
|
parseFilter( $_REQUEST['filter'] );
|
||||||
|
@ -424,10 +427,10 @@ function getNearEvents() {
|
||||||
|
|
||||||
# When listing, it may make sense to list them in descending order. But when viewing Prev should timewise earlier and Next should be after.
|
# When listing, it may make sense to list them in descending order. But when viewing Prev should timewise earlier and Next should be after.
|
||||||
if ( $sortColumn == 'E.Id' or $sortColumn == 'E.StartTime' ) {
|
if ( $sortColumn == 'E.Id' or $sortColumn == 'E.StartTime' ) {
|
||||||
$sortOrder = 'asc';
|
$sortOrder = 'ASC';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql.' AND E.Id<'.$event['Id'] . " ORDER BY $sortColumn ".($sortOrder=='asc'?'desc':'asc');
|
$sql = 'SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$sortColumn.' '.($sortOrder=='ASC'?'<=':'>=').' \''.$event[$_REQUEST['sort_field']].'\''.$_REQUEST['filter']['sql'].$midSql.' AND E.Id<'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'DESC':'ASC');
|
||||||
if ( $sortColumn != 'E.Id' ) {
|
if ( $sortColumn != 'E.Id' ) {
|
||||||
# When sorting by starttime, if we have two events with the same starttime (diffreent monitors) then we should sort secondly by Id
|
# When sorting by starttime, if we have two events with the same starttime (diffreent monitors) then we should sort secondly by Id
|
||||||
$sql .= ', E.Id DESC';
|
$sql .= ', E.Id DESC';
|
||||||
|
@ -436,31 +439,30 @@ function getNearEvents() {
|
||||||
$result = dbQuery($sql);
|
$result = dbQuery($sql);
|
||||||
$prevEvent = dbFetchNext($result);
|
$prevEvent = dbFetchNext($result);
|
||||||
|
|
||||||
$sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql.' AND E.Id>'.$event['Id'] . " ORDER BY $sortColumn $sortOrder";
|
$sql = 'SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$sortColumn .' '.($sortOrder=='ASC'?'>=':'<=').' \''.$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql.' AND E.Id>'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'ASC':'DESC');
|
||||||
if ( $sortColumn != 'E.Id' ) {
|
if ( $sortColumn != 'E.Id' ) {
|
||||||
# When sorting by starttime, if we have two events with the same starttime (diffreent monitors) then we should sort secondly by Id
|
# When sorting by starttime, if we have two events with the same starttime (diffreent monitors) then we should sort secondly by Id
|
||||||
$sql .= ', E.Id ASC';
|
$sql .= ', E.Id ASC';
|
||||||
}
|
}
|
||||||
$sql .= ' LIMIT 1';
|
$sql .= ' LIMIT 1';
|
||||||
$result = dbQuery( $sql );
|
$result = dbQuery($sql);
|
||||||
$nextEvent = dbFetchNext( $result );
|
$nextEvent = dbFetchNext($result);
|
||||||
|
|
||||||
$result = array( 'EventId'=>$eventId );
|
|
||||||
if ( $prevEvent ) {
|
if ( $prevEvent ) {
|
||||||
$result['PrevEventId'] = $prevEvent['Id'];
|
$NearEvents['PrevEventId'] = $prevEvent['Id'];
|
||||||
$result['PrevEventStartTime'] = $prevEvent['StartTime'];
|
$NearEvents['PrevEventStartTime'] = $prevEvent['StartTime'];
|
||||||
$result['PrevEventDefVideoPath'] = getEventDefaultVideoPath($prevEvent['Id']);
|
$NearEvents['PrevEventDefVideoPath'] = getEventDefaultVideoPath($prevEvent['Id']);
|
||||||
} else {
|
} else {
|
||||||
$result['PrevEventId'] = $result['PrevEventStartTime'] = $result['PrevEventDefVideoPath'] = 0;
|
$NearEvents['PrevEventId'] = $result['PrevEventStartTime'] = $result['PrevEventDefVideoPath'] = 0;
|
||||||
}
|
}
|
||||||
if ( $nextEvent ) {
|
if ( $nextEvent ) {
|
||||||
$result['NextEventId'] = $nextEvent['Id'];
|
$NearEvents['NextEventId'] = $nextEvent['Id'];
|
||||||
$result['NextEventStartTime'] = $nextEvent['StartTime'];
|
$NearEvents['NextEventStartTime'] = $nextEvent['StartTime'];
|
||||||
$result['NextEventDefVideoPath'] = getEventDefaultVideoPath($nextEvent['Id']);
|
$NearEvents['NextEventDefVideoPath'] = getEventDefaultVideoPath($nextEvent['Id']);
|
||||||
} else {
|
} else {
|
||||||
$result['NextEventId'] = $result['NextEventStartTime'] = $result['NextEventDefVideoPath'] = 0;
|
$NearEvents['NextEventId'] = $NearEvents['NextEventStartTime'] = $NearEvents['NextEventDefVideoPath'] = 0;
|
||||||
}
|
}
|
||||||
return $result;
|
return $NearEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -31,27 +31,29 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
||||||
|
|
||||||
switch ( $_REQUEST['command'] ) {
|
switch ( $_REQUEST['command'] ) {
|
||||||
case CMD_VARPLAY :
|
case CMD_VARPLAY :
|
||||||
ZM\Logger::Debug('Varplaying to '.$_REQUEST['rate']);
|
ZM\Debug('Varplaying to '.$_REQUEST['rate']);
|
||||||
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768);
|
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768);
|
||||||
break;
|
break;
|
||||||
case CMD_ZOOMIN :
|
case CMD_ZOOMIN :
|
||||||
ZM\Logger::Debug('Zooming to '.$_REQUEST['x'].','.$_REQUEST['y']);
|
ZM\Debug('Zooming to '.$_REQUEST['x'].','.$_REQUEST['y']);
|
||||||
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
|
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
|
||||||
break;
|
break;
|
||||||
case CMD_PAN :
|
case CMD_PAN :
|
||||||
ZM\Logger::Debug('Panning to '.$_REQUEST['x'].','.$_REQUEST['y']);
|
ZM\Debug('Panning to '.$_REQUEST['x'].','.$_REQUEST['y']);
|
||||||
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
|
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
|
||||||
break;
|
break;
|
||||||
case CMD_SCALE :
|
case CMD_SCALE :
|
||||||
ZM\Logger::Debug('Scaling to '.$_REQUEST['scale']);
|
ZM\Debug('Scaling to '.$_REQUEST['scale']);
|
||||||
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['scale']);
|
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['scale']);
|
||||||
break;
|
break;
|
||||||
case CMD_SEEK :
|
case CMD_SEEK :
|
||||||
ZM\Logger::Debug('Seeking to '.$_REQUEST['offset']);
|
# Pack int two 32 bit integers instead of trying to deal with floats
|
||||||
$msg = pack('lcN', MSG_CMD, $_REQUEST['command'], $_REQUEST['offset']);
|
$msg = pack('lcNN', MSG_CMD, $_REQUEST['command'],
|
||||||
|
intval($_REQUEST['offset']),
|
||||||
|
1000000*( $_REQUEST['offset']-intval($_REQUEST['offset'])));
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
ZM\Logger::Debug('Sending command ' . $_REQUEST['command']);
|
ZM\Debug('Sending command ' . $_REQUEST['command']);
|
||||||
$msg = pack('lc', MSG_CMD, $_REQUEST['command']);
|
$msg = pack('lc', MSG_CMD, $_REQUEST['command']);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +67,7 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
||||||
// WHY? We will just send another one...
|
// WHY? We will just send another one...
|
||||||
// ANSWER: Because otherwise we get a log of errors logged
|
// ANSWER: Because otherwise we get a log of errors logged
|
||||||
|
|
||||||
//ZM\Logger::Debug("$remSockFile does not exist, waiting, current " . (time() - $start_time) . ' seconds' );
|
//ZM\Debug("$remSockFile does not exist, waiting, current " . (time() - $start_time) . ' seconds' );
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,20 +126,20 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
||||||
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
|
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
|
||||||
if ( isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash) ) {
|
if ( isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash) ) {
|
||||||
$data['auth'] = $auth_hash;
|
$data['auth'] = $auth_hash;
|
||||||
ZM\Logger::Debug("including nw auth hash " . $data['auth']);
|
ZM\Debug("including nw auth hash " . $data['auth']);
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('Not including nw auth hash becase it hashn\'t changed '.$auth_hash);
|
ZM\Debug('Not including nw auth hash becase it hashn\'t changed '.$auth_hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ajaxResponse(array('status'=>$data));
|
ajaxResponse(array('status'=>$data));
|
||||||
break;
|
break;
|
||||||
case MSG_DATA_EVENT :
|
case MSG_DATA_EVENT :
|
||||||
if ( version_compare( phpversion(), '5.6.0', '<') ) {
|
if ( version_compare( phpversion(), '5.6.0', '<') ) {
|
||||||
ZM\Logger::Debug('Using old unpack methods to handle 64bit event id');
|
ZM\Debug('Using old unpack methods to handle 64bit event id');
|
||||||
$data = unpack('ltype/ieventlow/ieventhigh/iprogress/irate/izoom/Cpaused', $msg);
|
$data = unpack('ltype/ieventlow/ieventhigh/dduration/dprogress/irate/izoom/Cpaused', $msg);
|
||||||
$data['event'] = $data['eventhigh'] << 32 | $data['eventlow'];
|
$data['event'] = $data['eventhigh'] << 32 | $data['eventlow'];
|
||||||
} else {
|
} else {
|
||||||
$data = unpack('ltype/Qevent/iprogress/irate/izoom/Cpaused', $msg);
|
$data = unpack('ltype/Qevent/dduration/dprogress/irate/izoom/Cpaused', $msg);
|
||||||
}
|
}
|
||||||
$data['rate'] /= RATE_BASE;
|
$data['rate'] /= RATE_BASE;
|
||||||
$data['zoom'] = round($data['zoom']/SCALE_BASE, 1);
|
$data['zoom'] = round($data['zoom']/SCALE_BASE, 1);
|
||||||
|
@ -154,7 +156,7 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
||||||
}
|
}
|
||||||
sem_release($semaphore);
|
sem_release($semaphore);
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('Couldn\'t get semaphore');
|
ZM\Debug('Couldn\'t get semaphore');
|
||||||
ajaxResponse(array());
|
ajaxResponse(array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ class AppController extends Controller {
|
||||||
if ( ! is_session_started() )
|
if ( ! is_session_started() )
|
||||||
zm_session_start();
|
zm_session_start();
|
||||||
|
|
||||||
ZM\Logger::Debug(print_r($_SESSION, true));
|
ZM\Debug(print_r($_SESSION, true));
|
||||||
$user = userFromSession();
|
$user = userFromSession();
|
||||||
session_write_close();
|
session_write_close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,10 +50,10 @@ class HostController extends AppController {
|
||||||
$cred_depr = [];
|
$cred_depr = [];
|
||||||
|
|
||||||
if ( $username && $password ) {
|
if ( $username && $password ) {
|
||||||
ZM\Logger::Debug('Username and password provided, generating access and refresh tokens');
|
ZM\Debug('Username and password provided, generating access and refresh tokens');
|
||||||
$cred = $this->_getCredentials(true, '', $username); // generate refresh
|
$cred = $this->_getCredentials(true, '', $username); // generate refresh
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('Only generating access token');
|
ZM\Debug('Only generating access token');
|
||||||
$cred = $this->_getCredentials(false, $token); // don't generate refresh
|
$cred = $this->_getCredentials(false, $token); // don't generate refresh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ class HostController extends AppController {
|
||||||
$login_array['credentials'] = $cred_depr[0];
|
$login_array['credentials'] = $cred_depr[0];
|
||||||
$login_array['append_password'] = $cred_depr[1];
|
$login_array['append_password'] = $cred_depr[1];
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('Legacy Auth is disabled, not generating auth= credentials');
|
ZM\Debug('Legacy Auth is disabled, not generating auth= credentials');
|
||||||
}
|
}
|
||||||
|
|
||||||
$login_array['version'] = $ver[0];
|
$login_array['version'] = $ver[0];
|
||||||
|
@ -203,7 +203,7 @@ class HostController extends AppController {
|
||||||
|
|
||||||
if ( $mid ) {
|
if ( $mid ) {
|
||||||
// Get disk usage for $mid
|
// Get disk usage for $mid
|
||||||
ZM\Logger::Debug("Executing du -s0 $zm_dir_events/$mid | awk '{print $1}'");
|
ZM\Debug("Executing du -s0 $zm_dir_events/$mid | awk '{print $1}'");
|
||||||
$usage = shell_exec("du -s0 $zm_dir_events/$mid | awk '{print $1}'");
|
$usage = shell_exec("du -s0 $zm_dir_events/$mid | awk '{print $1}'");
|
||||||
} else {
|
} else {
|
||||||
$monitors = $this->Monitor->find('all', array(
|
$monitors = $this->Monitor->find('all', array(
|
||||||
|
|
|
@ -178,7 +178,7 @@ class MonitorsController extends AppController {
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if ( !defined('ZM_SERVER_ID')) {
|
if ( !defined('ZM_SERVER_ID')) {
|
||||||
ZM\Logger::Debug("Not defined ZM_SERVER_ID");
|
ZM\Debug("Not defined ZM_SERVER_ID");
|
||||||
}
|
}
|
||||||
$this->daemonControl($this->Monitor->id, 'start');
|
$this->daemonControl($this->Monitor->id, 'start');
|
||||||
}
|
}
|
||||||
|
@ -386,7 +386,7 @@ class MonitorsController extends AppController {
|
||||||
}
|
}
|
||||||
|
|
||||||
$shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
|
$shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
|
||||||
ZM\Logger::Debug("Command $shellcmd");
|
ZM\Debug("Command $shellcmd");
|
||||||
$status = exec($shellcmd);
|
$status = exec($shellcmd);
|
||||||
$status_text .= $status."\n";
|
$status_text .= $status."\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,10 +133,10 @@ class Event extends AppModel {
|
||||||
if ( file_exists($this->Path().'/'.$event['DefaultVideo']) ) {
|
if ( file_exists($this->Path().'/'.$event['DefaultVideo']) ) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('File does not exist at ' . $this->Path().'/'.$event['DefaultVideo'] );
|
ZM\Debug('File does not exist at ' . $this->Path().'/'.$event['DefaultVideo'] );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('No DefaultVideo in Event' . $this->Event);
|
ZM\Debug('No DefaultVideo in Event' . $this->Event);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // end function fileExists($event)
|
} // end function fileExists($event)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
|
* bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
|
||||||
*
|
*
|
||||||
* @version v1.18.0
|
* @version v1.17.1
|
||||||
* @homepage https://bootstrap-table.com
|
* @homepage https://bootstrap-table.com
|
||||||
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
||||||
* @license MIT
|
* @license MIT
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
|
* bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
|
||||||
*
|
*
|
||||||
* @version v1.18.0
|
* @version v1.17.1
|
||||||
* @homepage https://bootstrap-table.com
|
* @homepage https://bootstrap-table.com
|
||||||
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
||||||
* @license MIT
|
* @license MIT
|
||||||
|
|
|
@ -291,7 +291,7 @@ class Event extends ZM_Object {
|
||||||
# The idea here is that we don't really want to use the analysis jpeg as the thumbnail.
|
# The idea here is that we don't really want to use the analysis jpeg as the thumbnail.
|
||||||
# The snapshot image will be generated during capturing
|
# The snapshot image will be generated during capturing
|
||||||
if ( file_exists($this->Path().'/snapshot.jpg') ) {
|
if ( file_exists($this->Path().'/snapshot.jpg') ) {
|
||||||
Logger::Debug("snapshot exists");
|
Debug("snapshot exists");
|
||||||
$frame = null;
|
$frame = null;
|
||||||
} else {
|
} else {
|
||||||
# Load the frame with the highest score to use as a thumbnail
|
# Load the frame with the highest score to use as a thumbnail
|
||||||
|
@ -396,14 +396,14 @@ class Event extends ZM_Object {
|
||||||
|
|
||||||
if ( $frame and !is_array($frame) ) {
|
if ( $frame and !is_array($frame) ) {
|
||||||
# Must be an Id
|
# Must be an Id
|
||||||
Logger::Debug("Assuming that $frame is an Id");
|
Debug("Assuming that $frame is an Id");
|
||||||
$frame = array('FrameId'=>$frame, 'Type'=>'', 'Delta'=>0);
|
$frame = array('FrameId'=>$frame, 'Type'=>'', 'Delta'=>0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( !$frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
|
if ( ( !$frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
|
||||||
# No frame specified, so look for a snapshot to use
|
# No frame specified, so look for a snapshot to use
|
||||||
$captImage = 'snapshot.jpg';
|
$captImage = 'snapshot.jpg';
|
||||||
Logger::Debug('Frame not specified, using snapshot');
|
Debug('Frame not specified, using snapshot');
|
||||||
$frame = array('FrameId'=>'snapshot', 'Type'=>'', 'Delta'=>0);
|
$frame = array('FrameId'=>'snapshot', 'Type'=>'', 'Delta'=>0);
|
||||||
} else {
|
} else {
|
||||||
$captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId']);
|
$captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId']);
|
||||||
|
@ -421,11 +421,11 @@ class Event extends ZM_Object {
|
||||||
|
|
||||||
#$command ='ffmpeg -v 0 -i '.$videoPath.' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage;
|
#$command ='ffmpeg -v 0 -i '.$videoPath.' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage;
|
||||||
$command ='ffmpeg -ss '. $frame['Delta'] .' -i '.$videoPath.' -frames:v 1 '.$eventPath.'/'.$captImage;
|
$command ='ffmpeg -ss '. $frame['Delta'] .' -i '.$videoPath.' -frames:v 1 '.$eventPath.'/'.$captImage;
|
||||||
Logger::Debug('Running '.$command);
|
Debug('Running '.$command);
|
||||||
$output = array();
|
$output = array();
|
||||||
$retval = 0;
|
$retval = 0;
|
||||||
exec($command, $output, $retval);
|
exec($command, $output, $retval);
|
||||||
Logger::Debug("Retval: $retval, output: " . implode("\n", $output));
|
Debug("Retval: $retval, output: " . implode("\n", $output));
|
||||||
} else {
|
} else {
|
||||||
Error('Can\'t create frame images from video because there is no video file for event '.$Event->Id().' at ' .$Event->Path());
|
Error('Can\'t create frame images from video because there is no video file for event '.$Event->Id().' at ' .$Event->Path());
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ class Event extends ZM_Object {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger::Debug("sending command to $url");
|
Debug("sending command to $url");
|
||||||
// use key 'http' even if you send the request to https://...
|
// use key 'http' even if you send the request to https://...
|
||||||
$options = array(
|
$options = array(
|
||||||
'http' => array(
|
'http' => array(
|
||||||
|
@ -545,7 +545,7 @@ class Event extends ZM_Object {
|
||||||
Error("Error restarting zmc using $url");
|
Error("Error restarting zmc using $url");
|
||||||
}
|
}
|
||||||
$event_data = json_decode($result,true);
|
$event_data = json_decode($result,true);
|
||||||
Logger::Debug(print_r($event_data['event']['Event'],1));
|
Debug(print_r($event_data['event']['Event'],1));
|
||||||
return $event_data['event']['Event']['fileExists'];
|
return $event_data['event']['Event']['fileExists'];
|
||||||
} catch ( Exception $e ) {
|
} catch ( Exception $e ) {
|
||||||
Error("Except $e thrown trying to get event data");
|
Error("Except $e thrown trying to get event data");
|
||||||
|
@ -577,7 +577,7 @@ class Event extends ZM_Object {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger::Debug("sending command to $url");
|
Debug("sending command to $url");
|
||||||
// use key 'http' even if you send the request to https://...
|
// use key 'http' even if you send the request to https://...
|
||||||
$options = array(
|
$options = array(
|
||||||
'http' => array(
|
'http' => array(
|
||||||
|
@ -593,7 +593,7 @@ class Event extends ZM_Object {
|
||||||
Error("Error restarting zmc using $url");
|
Error("Error restarting zmc using $url");
|
||||||
}
|
}
|
||||||
$event_data = json_decode($result,true);
|
$event_data = json_decode($result,true);
|
||||||
Logger::Debug(print_r($event_data['event']['Event'], 1));
|
Debug(print_r($event_data['event']['Event'], 1));
|
||||||
return $event_data['event']['Event']['fileSize'];
|
return $event_data['event']['Event']['fileSize'];
|
||||||
} catch ( Exception $e ) {
|
} catch ( Exception $e ) {
|
||||||
Error("Except $e thrown trying to get event data");
|
Error("Except $e thrown trying to get event data");
|
||||||
|
|
|
@ -16,6 +16,7 @@ class Filter extends ZM_Object {
|
||||||
'EmailBody' => '',
|
'EmailBody' => '',
|
||||||
'AutoDelete' => 0,
|
'AutoDelete' => 0,
|
||||||
'AutoArchive' => 0,
|
'AutoArchive' => 0,
|
||||||
|
'AutoUnarchive' => 0,
|
||||||
'AutoVideo' => 0,
|
'AutoVideo' => 0,
|
||||||
'AutoUpload' => 0,
|
'AutoUpload' => 0,
|
||||||
'AutoMessage' => 0,
|
'AutoMessage' => 0,
|
||||||
|
@ -55,6 +56,9 @@ class Filter extends ZM_Object {
|
||||||
foreach ( $this->FilterTerms() as $term ) {
|
foreach ( $this->FilterTerms() as $term ) {
|
||||||
$this->_querystring .= $term->querystring($separator);
|
$this->_querystring .= $term->querystring($separator);
|
||||||
} # end foreach term
|
} # end foreach term
|
||||||
|
if ( $this->Id() ) {
|
||||||
|
$this->_querystring .= $separator.'filter[Id]='.$this->Id();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $this->_querystring;
|
return $this->_querystring;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +230,7 @@ class Filter extends ZM_Object {
|
||||||
|
|
||||||
if ( (!defined('ZM_SERVER_ID')) or (!$Server->Id()) or (ZM_SERVER_ID==$Server->Id()) ) {
|
if ( (!defined('ZM_SERVER_ID')) or (!$Server->Id()) or (ZM_SERVER_ID==$Server->Id()) ) {
|
||||||
# Local
|
# Local
|
||||||
Logger::Debug("Controlling filter locally $command for server ".$Server->Id());
|
Debug("Controlling filter locally $command for server ".$Server->Id());
|
||||||
daemonControl($command, 'zmfilter.pl', '--filter_id='.$this->{'Id'}.' --daemon');
|
daemonControl($command, 'zmfilter.pl', '--filter_id='.$this->{'Id'}.' --daemon');
|
||||||
} else {
|
} else {
|
||||||
# Remote case
|
# Remote case
|
||||||
|
@ -243,7 +247,7 @@ class Filter extends ZM_Object {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$url .= '&view=filter&object=filter&action=control&command='.$command.'&Id='.$this->Id().'&ServerId='.$Server->Id();
|
$url .= '&view=filter&object=filter&action=control&command='.$command.'&Id='.$this->Id().'&ServerId='.$Server->Id();
|
||||||
Logger::Debug("sending command to $url");
|
Debug("sending command to $url");
|
||||||
$data = array();
|
$data = array();
|
||||||
if ( defined('ZM_ENABLE_CSRF_MAGIC') ) {
|
if ( defined('ZM_ENABLE_CSRF_MAGIC') ) {
|
||||||
require_once( 'includes/csrf/csrf-magic.php' );
|
require_once( 'includes/csrf/csrf-magic.php' );
|
||||||
|
@ -274,7 +278,7 @@ class Filter extends ZM_Object {
|
||||||
public function execute() {
|
public function execute() {
|
||||||
$command = ZM_PATH_BIN.'/zmfilter.pl --filter_id='.escapeshellarg($this->Id());
|
$command = ZM_PATH_BIN.'/zmfilter.pl --filter_id='.escapeshellarg($this->Id());
|
||||||
$result = exec($command, $output, $status);
|
$result = exec($command, $output, $status);
|
||||||
Logger::Debug("$command status:$status output:".implode("\n", $output));
|
Debug("$command status:$status output:".implode("\n", $output));
|
||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,14 +329,14 @@ class FilterTerm {
|
||||||
public function test($event=null) {
|
public function test($event=null) {
|
||||||
if ( !isset($event) ) {
|
if ( !isset($event) ) {
|
||||||
# Is a Pre Condition
|
# Is a Pre Condition
|
||||||
Logger::Debug("Testing " . $this->attr);
|
Debug("Testing " . $this->attr);
|
||||||
if ( $this->attr == 'DiskPercent' ) {
|
if ( $this->attr == 'DiskPercent' ) {
|
||||||
# The logic on this is really ugly. We are going to treat it as an OR
|
# The logic on this is really ugly. We are going to treat it as an OR
|
||||||
foreach ( $this->filter->get_StorageAreas() as $storage ) {
|
foreach ( $this->filter->get_StorageAreas() as $storage ) {
|
||||||
$string_to_eval = 'return $storage->disk_usage_percent() '.$this->op.' '.$this->val.';';
|
$string_to_eval = 'return $storage->disk_usage_percent() '.$this->op.' '.$this->val.';';
|
||||||
try {
|
try {
|
||||||
$ret = eval($string_to_eval);
|
$ret = eval($string_to_eval);
|
||||||
Logger::Debug("Evalled $string_to_eval = $ret");
|
Debug("Evalled $string_to_eval = $ret");
|
||||||
if ( $ret )
|
if ( $ret )
|
||||||
return true;
|
return true;
|
||||||
} catch ( Throwable $t ) {
|
} catch ( Throwable $t ) {
|
||||||
|
@ -348,7 +348,7 @@ class FilterTerm {
|
||||||
$string_to_eval = 'return getLoad() '.$this->op.' '.$this->val.';';
|
$string_to_eval = 'return getLoad() '.$this->op.' '.$this->val.';';
|
||||||
try {
|
try {
|
||||||
$ret = eval($string_to_eval);
|
$ret = eval($string_to_eval);
|
||||||
Logger::Debug("Evaled $string_to_eval = $ret");
|
Debug("Evaled $string_to_eval = $ret");
|
||||||
if ( $ret )
|
if ( $ret )
|
||||||
return true;
|
return true;
|
||||||
} catch ( Throwable $t ) {
|
} catch ( Throwable $t ) {
|
||||||
|
@ -374,7 +374,7 @@ class FilterTerm {
|
||||||
$string_to_eval = 'return $event->Storage()->disk_usage_percent() '.$this->op.' '.$this->val.';';
|
$string_to_eval = 'return $event->Storage()->disk_usage_percent() '.$this->op.' '.$this->val.';';
|
||||||
try {
|
try {
|
||||||
$ret = eval($string_to_eval);
|
$ret = eval($string_to_eval);
|
||||||
Logger::Debug("Evalled $string_to_eval = $ret");
|
Debug("Evalled $string_to_eval = $ret");
|
||||||
if ( $ret )
|
if ( $ret )
|
||||||
return true;
|
return true;
|
||||||
} catch ( Throwable $t ) {
|
} catch ( Throwable $t ) {
|
||||||
|
@ -385,7 +385,7 @@ class FilterTerm {
|
||||||
$string_to_eval = 'return $event->Storage()->disk_usage_blocks() '.$this->op.' '.$this->val.';';
|
$string_to_eval = 'return $event->Storage()->disk_usage_blocks() '.$this->op.' '.$this->val.';';
|
||||||
try {
|
try {
|
||||||
$ret = eval($string_to_eval);
|
$ret = eval($string_to_eval);
|
||||||
Logger::Debug("Evalled $string_to_eval = $ret");
|
Debug("Evalled $string_to_eval = $ret");
|
||||||
if ( $ret )
|
if ( $ret )
|
||||||
return true;
|
return true;
|
||||||
} catch ( Throwable $t ) {
|
} catch ( Throwable $t ) {
|
||||||
|
|
|
@ -130,6 +130,8 @@ class Monitor extends ZM_Object {
|
||||||
'Refresh' => null,
|
'Refresh' => null,
|
||||||
'DefaultCodec' => 'auto',
|
'DefaultCodec' => 'auto',
|
||||||
'GroupIds' => array('default'=>array(), 'do_not_update'=>1),
|
'GroupIds' => array('default'=>array(), 'do_not_update'=>1),
|
||||||
|
'Latitude' => null,
|
||||||
|
'Longitude' => null,
|
||||||
);
|
);
|
||||||
private $status_fields = array(
|
private $status_fields = array(
|
||||||
'Status' => null,
|
'Status' => null,
|
||||||
|
@ -180,7 +182,7 @@ class Monitor extends ZM_Object {
|
||||||
FROM `Monitor_Status` WHERE `MonitorId`=?';
|
FROM `Monitor_Status` WHERE `MonitorId`=?';
|
||||||
$row = dbFetchOne($sql, NULL, array($this->{'Id'}));
|
$row = dbFetchOne($sql, NULL, array($this->{'Id'}));
|
||||||
if ( !$row ) {
|
if ( !$row ) {
|
||||||
Error('Unable to load Monitor record for Id='.$this->{'Id'});
|
Warning('Unable to load Monitor status record for Id='.$this->{'Id'}.' using '.$sql);
|
||||||
foreach ( $this->status_fields as $k => $v ) {
|
foreach ( $this->status_fields as $k => $v ) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
}
|
}
|
||||||
|
@ -292,7 +294,7 @@ class Monitor extends ZM_Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
function zmcControl( $mode=false ) {
|
function zmcControl( $mode=false ) {
|
||||||
if ( ! $this->{'Id'} ) {
|
if ( !(property_exists($this,'Id') and $this->{'Id'}) ) {
|
||||||
Warning('Attempt to control a monitor with no Id');
|
Warning('Attempt to control a monitor with no Id');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -328,7 +330,7 @@ class Monitor extends ZM_Object {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger::Debug('sending command to '.$url);
|
Debug('sending command to '.$url);
|
||||||
|
|
||||||
$context = stream_context_create();
|
$context = stream_context_create();
|
||||||
try {
|
try {
|
||||||
|
@ -345,7 +347,7 @@ class Monitor extends ZM_Object {
|
||||||
} // end function zmcControl
|
} // end function zmcControl
|
||||||
|
|
||||||
function zmaControl($mode=false) {
|
function zmaControl($mode=false) {
|
||||||
if ( !$this->{'Id'} ) {
|
if ( ! (property_exists($this, 'Id') and $this->{'Id'}) ) {
|
||||||
Warning('Attempt to control a monitor with no Id');
|
Warning('Attempt to control a monitor with no Id');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -388,7 +390,7 @@ class Monitor extends ZM_Object {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger::Debug("sending command to $url");
|
Debug("sending command to $url");
|
||||||
|
|
||||||
$context = stream_context_create();
|
$context = stream_context_create();
|
||||||
try {
|
try {
|
||||||
|
@ -537,7 +539,7 @@ class Monitor extends ZM_Object {
|
||||||
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) {
|
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) {
|
||||||
# These are special as we now run zmcontrol as a daemon through zmdc.
|
# These are special as we now run zmcontrol as a daemon through zmdc.
|
||||||
$status = daemonStatus('zmcontrol.pl', array('--id', $this->{'Id'}));
|
$status = daemonStatus('zmcontrol.pl', array('--id', $this->{'Id'}));
|
||||||
Logger::Debug("Current status $status");
|
Debug("Current status $status");
|
||||||
if ( $status or ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) ) {
|
if ( $status or ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) ) {
|
||||||
daemonControl($command, 'zmcontrol.pl', '--id '.$this->{'Id'});
|
daemonControl($command, 'zmcontrol.pl', '--id '.$this->{'Id'});
|
||||||
return;
|
return;
|
||||||
|
@ -551,10 +553,10 @@ class Monitor extends ZM_Object {
|
||||||
|
|
||||||
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) {
|
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) {
|
||||||
# Local
|
# Local
|
||||||
Logger::Debug('Trying to send options ' . print_r($options, true));
|
Debug('Trying to send options ' . print_r($options, true));
|
||||||
|
|
||||||
$optionString = jsonEncode($options);
|
$optionString = jsonEncode($options);
|
||||||
Logger::Debug("Trying to send options $optionString");
|
Debug("Trying to send options $optionString");
|
||||||
// Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command.
|
// Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command.
|
||||||
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
|
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if ( $socket < 0 ) {
|
if ( $socket < 0 ) {
|
||||||
|
@ -588,7 +590,7 @@ class Monitor extends ZM_Object {
|
||||||
$url .= '?user='.$_SESSION['username'];
|
$url .= '?user='.$_SESSION['username'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger::Debug("sending command to $url");
|
Debug("sending command to $url");
|
||||||
|
|
||||||
$context = stream_context_create();
|
$context = stream_context_create();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -94,7 +94,7 @@ class Storage extends ZM_Object {
|
||||||
}
|
}
|
||||||
$used = $this->disk_used_space();
|
$used = $this->disk_used_space();
|
||||||
$usage = round(($used / $total) * 100);
|
$usage = round(($used / $total) * 100);
|
||||||
//Logger::Debug("Used $usage = round( ( $used / $total ) * 100 )");
|
//Debug("Used $usage = round( ( $used / $total ) * 100 )");
|
||||||
return $usage;
|
return $usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,11 @@ class User extends ZM_Object {
|
||||||
'Monitors' => 'None',
|
'Monitors' => 'None',
|
||||||
'Groups' => 'None',
|
'Groups' => 'None',
|
||||||
'Devices' => 'None',
|
'Devices' => 'None',
|
||||||
'System'=> 'None',
|
'System' => 'None',
|
||||||
'MaxBandwidth' =>'',
|
'MaxBandwidth' => '',
|
||||||
'MonitorIds' =>'',
|
'MonitorIds' => '',
|
||||||
'TokenMinExpiry' => 0,
|
'TokenMinExpiry' => 0,
|
||||||
'APIEnabled'=> 1,
|
'APIEnabled' => 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
public static function find( $parameters = array(), $options = array() ) {
|
public static function find( $parameters = array(), $options = array() ) {
|
||||||
|
|
|
@ -36,6 +36,6 @@ if ( $action == 'control' ) {
|
||||||
|
|
||||||
$ctrlCommand = buildControlCommand($monitor);
|
$ctrlCommand = buildControlCommand($monitor);
|
||||||
$monitor->sendControlCommand($ctrlCommand);
|
$monitor->sendControlCommand($ctrlCommand);
|
||||||
$view = 'none';
|
$redirect = $_SERVER['HTTP_REFERER'];
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -89,7 +89,6 @@ if ( $action == 'controlcap' ) {
|
||||||
|
|
||||||
//$changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns );
|
//$changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns );
|
||||||
$Control->save($_REQUEST['newControl']);
|
$Control->save($_REQUEST['newControl']);
|
||||||
$refreshParent = true;
|
$redirect = '?view=controlcaps';
|
||||||
$view = 'none';
|
|
||||||
} // end if action
|
} // end if action
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -28,15 +28,15 @@ if ( $action == 'device' ) {
|
||||||
if ( !empty($_REQUEST['command']) ) {
|
if ( !empty($_REQUEST['command']) ) {
|
||||||
setDeviceStatusX10($_REQUEST['key'], $_REQUEST['command']);
|
setDeviceStatusX10($_REQUEST['key'], $_REQUEST['command']);
|
||||||
} else if ( isset($_REQUEST['newDevice']) ) {
|
} else if ( isset($_REQUEST['newDevice']) ) {
|
||||||
if ( isset($_REQUEST['did']) ) {
|
if ( isset($_REQUEST['did']) && $_REQUEST['did'] ) {
|
||||||
dbQuery('UPDATE Devices SET Name=?, KeyString=? WHERE Id=?',
|
dbQuery('UPDATE Devices SET Name=?, KeyString=? WHERE Id=?',
|
||||||
array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'], $_REQUEST['did']) );
|
array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'], $_REQUEST['did']) );
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
dbQuery('INSERT INTO Devices SET Name=?, KeyString=?',
|
dbQuery('INSERT INTO Devices SET Name=?, KeyString=?',
|
||||||
array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString']) );
|
array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString']) );
|
||||||
}
|
}
|
||||||
$refreshParent = true;
|
$redirect = '?view=devices';
|
||||||
$view = 'none';
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ZM\Error('Unknown action in device');
|
ZM\Error('Unknown action in device');
|
||||||
|
|
|
@ -32,7 +32,7 @@ if ( !canEdit('Events') ) {
|
||||||
if ( $action == 'archive' ) {
|
if ( $action == 'archive' ) {
|
||||||
$dbConn->beginTransaction();
|
$dbConn->beginTransaction();
|
||||||
$eids = getAffectedIds('eids');
|
$eids = getAffectedIds('eids');
|
||||||
ZM\Logger::Debug("E IDS" . print_r($eids, true));
|
ZM\Debug("E IDS" . print_r($eids, true));
|
||||||
foreach ( $eids as $markEid ) {
|
foreach ( $eids as $markEid ) {
|
||||||
dbQuery('UPDATE Events SET Archived=? WHERE Id=?', array(1, $markEid));
|
dbQuery('UPDATE Events SET Archived=? WHERE Id=?', array(1, $markEid));
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ if ( $action == 'archive' ) {
|
||||||
} else if ( $action == 'unarchive' ) {
|
} else if ( $action == 'unarchive' ) {
|
||||||
$dbConn->beginTransaction();
|
$dbConn->beginTransaction();
|
||||||
$eids = getAffectedIds('eids');
|
$eids = getAffectedIds('eids');
|
||||||
ZM\Logger::Debug("E IDS" . print_r($eids, true));
|
ZM\Debug("E IDS" . print_r($eids, true));
|
||||||
foreach ( $eids as $markEid ) {
|
foreach ( $eids as $markEid ) {
|
||||||
dbQuery('UPDATE Events SET Archived=? WHERE Id=?', array(0, $markEid));
|
dbQuery('UPDATE Events SET Archived=? WHERE Id=?', array(0, $markEid));
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
|
||||||
$_REQUEST['filter']['Background'] = empty($_REQUEST['filter']['Background']) ? 0 : 1;
|
$_REQUEST['filter']['Background'] = empty($_REQUEST['filter']['Background']) ? 0 : 1;
|
||||||
$_REQUEST['filter']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1;
|
$_REQUEST['filter']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1;
|
||||||
$changes = $filter->changes($_REQUEST['filter']);
|
$changes = $filter->changes($_REQUEST['filter']);
|
||||||
ZM\Logger::Debug('Changes: ' . print_r($changes,true));
|
ZM\Debug('Changes: ' . print_r($changes,true));
|
||||||
|
|
||||||
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
|
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
|
||||||
if ( $filter->Background() )
|
if ( $filter->Background() )
|
||||||
|
|
|
@ -32,7 +32,7 @@ if ( !canEdit('Monitors', $mid) ) {
|
||||||
|
|
||||||
if ( $action == 'function' ) {
|
if ( $action == 'function' ) {
|
||||||
$monitor = new ZM\Monitor($mid);
|
$monitor = new ZM\Monitor($mid);
|
||||||
if ( !$monitor ) {
|
if ( !$monitor->Id() ) {
|
||||||
ZM\Error("Monitor not found with Id=$mid");
|
ZM\Error("Monitor not found with Id=$mid");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -46,14 +46,14 @@ if ( $action == 'function' ) {
|
||||||
$monitor->save(array('Function'=>$newFunction, 'Enabled'=>$newEnabled));
|
$monitor->save(array('Function'=>$newFunction, 'Enabled'=>$newEnabled));
|
||||||
|
|
||||||
if ( daemonCheck() && ($monitor->Type() != 'WebSite') ) {
|
if ( daemonCheck() && ($monitor->Type() != 'WebSite') ) {
|
||||||
zmaControl($monitor, 'stop');
|
$monitor->zmaControl('stop');
|
||||||
zmcControl($monitor, ($newFunction != 'None') ? 'restart' : 'stop');
|
$monitor->zmcControl(($newFunction != 'None') ? 'restart' : 'stop');
|
||||||
if ( $newFunction != 'None' && $newFunction != 'NoDect' )
|
if ( $newFunction != 'None' && $newFunction != 'NoDect' )
|
||||||
zmaControl($monitor, 'start');
|
$monitor->zmaControl('start');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('No change to function, not doing anything.');
|
ZM\Debug('No change to function, not doing anything.');
|
||||||
}
|
}
|
||||||
} // end if action
|
} // end if action
|
||||||
$view = 'console';
|
$redirect = '?view=console';
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -26,26 +26,24 @@ if ( !canEdit('Groups') ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $action == 'Save' ) {
|
if ( $action == 'save' ) {
|
||||||
$group_id = null;
|
$group_id = null;
|
||||||
if ( !empty($_POST['gid']) )
|
if ( !empty($_REQUEST['gid']) )
|
||||||
$group_id = $_POST['gid'];
|
$group_id = $_REQUEST['gid'];
|
||||||
$group = new ZM\Group($group_id);
|
$group = new ZM\Group($group_id);
|
||||||
$group->save(
|
$group->save(
|
||||||
array(
|
array(
|
||||||
'Name'=> $_POST['newGroup']['Name'],
|
'Name'=> $_REQUEST['newGroup']['Name'],
|
||||||
'ParentId'=>( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ),
|
'ParentId'=>( $_REQUEST['newGroup']['ParentId'] == '' ? null : $_REQUEST['newGroup']['ParentId'] ),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id));
|
dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id));
|
||||||
$group_id = $group->Id();
|
$group_id = $group->Id();
|
||||||
if ( $group_id ) {
|
if ( $group_id ) {
|
||||||
foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) {
|
foreach ( $_REQUEST['newGroup']['MonitorIds'] as $mid ) {
|
||||||
dbQuery('INSERT INTO `Groups_Monitors` (`GroupId`,`MonitorId`) VALUES (?,?)', array($group_id, $mid));
|
dbQuery('INSERT INTO `Groups_Monitors` (`GroupId`,`MonitorId`) VALUES (?,?)', array($group_id, $mid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$view = 'none';
|
$redirect = '?view=groups';
|
||||||
$refreshParent = true;
|
|
||||||
$closePopup = true;
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -22,9 +22,8 @@
|
||||||
if ( $action == 'logout' ) {
|
if ( $action == 'logout' ) {
|
||||||
userLogout();
|
userLogout();
|
||||||
$view = 'login';
|
$view = 'login';
|
||||||
ZM\Logger::Debug("User: " . print_r($user,true));
|
|
||||||
} elseif ( $action == 'config' ) {
|
} elseif ( $action == 'config' ) {
|
||||||
$redirect = '?view=user&uid='.$user['Id'];
|
$redirect = '?view=user&prev=console&uid='.$user['Id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -75,10 +75,10 @@ if ( $action == 'save' ) {
|
||||||
if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) {
|
if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) {
|
||||||
$_REQUEST['newMonitor']['ServerId'] = dbFetchOne(
|
$_REQUEST['newMonitor']['ServerId'] = dbFetchOne(
|
||||||
'SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id');
|
'SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id');
|
||||||
ZM\Logger::Debug('Auto selecting server: Got ' . $_REQUEST['newMonitor']['ServerId']);
|
ZM\Debug('Auto selecting server: Got ' . $_REQUEST['newMonitor']['ServerId']);
|
||||||
if ( ( !$_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) {
|
if ( ( !$_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) {
|
||||||
$_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID;
|
$_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID;
|
||||||
ZM\Logger::Debug('Auto selecting server to ' . ZM_SERVER_ID);
|
ZM\Debug('Auto selecting server to ' . ZM_SERVER_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ if ( $action == 'save' ) {
|
||||||
|
|
||||||
$restart = true;
|
$restart = true;
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('No action due to no changes to Monitor');
|
ZM\Debug('No action due to no changes to Monitor');
|
||||||
} # end if count(changes)
|
} # end if count(changes)
|
||||||
|
|
||||||
if ( !$mid ) {
|
if ( !$mid ) {
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<?php
|
|
||||||
//
|
|
||||||
// ZoneMinder web action file
|
|
||||||
// Copyright (C) 2019 ZoneMinder LLC
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License
|
|
||||||
// as published by the Free Software Foundation; either version 2
|
|
||||||
// of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
//
|
|
||||||
|
|
||||||
if ( !canEdit('System') ) {
|
|
||||||
ZM\Warning('Need System permissions to shutdown server');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( $action ) {
|
|
||||||
$when = isset($_POST['when']) and $_POST['when'] == 'now' ? 'now' : '+1';
|
|
||||||
if ( $action == 'shutdown' ) {
|
|
||||||
$output = array();
|
|
||||||
$rc = 0;
|
|
||||||
exec('sudo -n '.ZM_PATH_SHUTDOWN." -P $when 2>&1", $output, $rc);
|
|
||||||
#exec('sudo -n /bin/systemctl poweroff -i 2>&1', $output, $rc);
|
|
||||||
ZM\Logger::Debug("Shutdown output $rc " . implode("\n",$output));
|
|
||||||
#ZM\Logger::Debug("Shutdown output " . shell_exec('/bin/systemctl poweroff -i 2>&1'));
|
|
||||||
} else if ( $action == 'restart' ) {
|
|
||||||
$output = array();
|
|
||||||
exec('sudo -n '.ZM_PATH_SHUTDOWN." -r $when 2>&1", $output);
|
|
||||||
#exec('sudo -n /bin/systemctl reboot -i 2>&1', $output);
|
|
||||||
ZM\Logger::Debug("Shutdown output " . implode("\n",$output));
|
|
||||||
} else if ( $action == 'cancel' ) {
|
|
||||||
$output = array();
|
|
||||||
exec('sudo '.ZM_PATH_SHUTDOWN.' -c 2>&1', $output);
|
|
||||||
}
|
|
||||||
} # end if action
|
|
||||||
?>
|
|
|
@ -34,7 +34,6 @@ if ( $action == 'Save' ) {
|
||||||
|
|
||||||
$changes = getFormChanges($dbUser, $_REQUEST['newUser'], $types);
|
$changes = getFormChanges($dbUser, $_REQUEST['newUser'], $types);
|
||||||
|
|
||||||
|
|
||||||
if ( isset($_REQUEST['newUser']['Password']) ) {
|
if ( isset($_REQUEST['newUser']['Password']) ) {
|
||||||
if ( function_exists('password_hash') ) {
|
if ( function_exists('password_hash') ) {
|
||||||
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
|
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
|
||||||
|
@ -67,9 +66,7 @@ if ( $action == 'Save' ) {
|
||||||
} else {
|
} else {
|
||||||
dbQuery('INSERT INTO Users SET '.implode(', ', $changes));
|
dbQuery('INSERT INTO Users SET '.implode(', ', $changes));
|
||||||
}
|
}
|
||||||
$refreshParent = true;
|
} # end if changes
|
||||||
}
|
|
||||||
$view = 'none';
|
|
||||||
} else if ( ZM_USER_SELF_EDIT and ( $_REQUEST['uid'] == $user['Id'] ) ) {
|
} else if ( ZM_USER_SELF_EDIT and ( $_REQUEST['uid'] == $user['Id'] ) ) {
|
||||||
$uid = $user['Id'];
|
$uid = $user['Id'];
|
||||||
|
|
||||||
|
@ -100,9 +97,7 @@ if ( $action == 'Save' ) {
|
||||||
zm_session_start();
|
zm_session_start();
|
||||||
generateAuthHash(ZM_AUTH_HASH_IPS, true);
|
generateAuthHash(ZM_AUTH_HASH_IPS, true);
|
||||||
session_write_close();
|
session_write_close();
|
||||||
$refreshParent = true;
|
|
||||||
}
|
}
|
||||||
$view = 'none';
|
|
||||||
}
|
}
|
||||||
} // end if $action == user
|
} // end if $action == user
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -70,9 +70,8 @@ if ( !empty($_REQUEST['mid']) && canEdit('Monitors', $_REQUEST['mid']) ) {
|
||||||
if ( ($_REQUEST['newZone']['Type'] == 'Privacy') && $monitor->Controllable() ) {
|
if ( ($_REQUEST['newZone']['Type'] == 'Privacy') && $monitor->Controllable() ) {
|
||||||
$monitor->sendControlCommand('quit');
|
$monitor->sendControlCommand('quit');
|
||||||
}
|
}
|
||||||
$refreshParent = true;
|
|
||||||
} // end if changes
|
} // end if changes
|
||||||
$view = 'none';
|
$redirect = $_SERVER['HTTP_REFERER'];
|
||||||
} // end if action
|
} // end if action
|
||||||
} // end if $mid and canEdit($mid)
|
} // end if $mid and canEdit($mid)
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -72,12 +72,12 @@ function validateUser($username='', $password='') {
|
||||||
// We assume we don't need to support mysql < 4.1
|
// We assume we don't need to support mysql < 4.1
|
||||||
// Starting MY SQL 4.1, mysql concats a '*' in front of its password hash
|
// Starting MY SQL 4.1, mysql concats a '*' in front of its password hash
|
||||||
// https://blog.pythian.com/hashing-algorithm-in-mysql-password-2/
|
// https://blog.pythian.com/hashing-algorithm-in-mysql-password-2/
|
||||||
ZM\Logger::Debug('Saved password is using MYSQL password function');
|
ZM\Debug('Saved password is using MYSQL password function');
|
||||||
$input_password_hash = '*'.strtoupper(sha1(sha1($password, true)));
|
$input_password_hash = '*'.strtoupper(sha1(sha1($password, true)));
|
||||||
$password_correct = ($user['Password'] == $input_password_hash);
|
$password_correct = ($user['Password'] == $input_password_hash);
|
||||||
break;
|
break;
|
||||||
case 'bcrypt' :
|
case 'bcrypt' :
|
||||||
ZM\Logger::Debug('bcrypt signature found, assumed bcrypt password');
|
ZM\Debug('bcrypt signature found, assumed bcrypt password');
|
||||||
$password_correct = password_verify($password, $user['Password']);
|
$password_correct = password_verify($password, $user['Password']);
|
||||||
break;
|
break;
|
||||||
case 'mysql+bcrypt' :
|
case 'mysql+bcrypt' :
|
||||||
|
@ -85,10 +85,10 @@ function validateUser($username='', $password='') {
|
||||||
// this is done so that we don't spend cycles doing two bcrypt password_verify calls
|
// this is done so that we don't spend cycles doing two bcrypt password_verify calls
|
||||||
// for every wrong password entered. This will only be invoked for passwords zmupdate.pl has
|
// for every wrong password entered. This will only be invoked for passwords zmupdate.pl has
|
||||||
// overlay hashed
|
// overlay hashed
|
||||||
ZM\Logger::Debug("Detected bcrypt overlay hashing for $username");
|
ZM\Debug("Detected bcrypt overlay hashing for $username");
|
||||||
$bcrypt_hash = substr($user['Password'], 4);
|
$bcrypt_hash = substr($user['Password'], 4);
|
||||||
$mysql_encoded_password = '*'.strtoupper(sha1(sha1($password, true)));
|
$mysql_encoded_password = '*'.strtoupper(sha1(sha1($password, true)));
|
||||||
ZM\Logger::Debug("Comparing password $mysql_encoded_password to bcrypt hash: $bcrypt_hash");
|
ZM\Debug("Comparing password $mysql_encoded_password to bcrypt hash: $bcrypt_hash");
|
||||||
$password_correct = password_verify($mysql_encoded_password, $bcrypt_hash);
|
$password_correct = password_verify($mysql_encoded_password, $bcrypt_hash);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -130,7 +130,7 @@ function validateToken($token, $allowed_token_type='access') {
|
||||||
return array(false, 'Incorrect token type');
|
return array(false, 'Incorrect token type');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('Not comparing token types as [any] was passed');
|
ZM\Debug('Not comparing token types as [any] was passed');
|
||||||
}
|
}
|
||||||
|
|
||||||
$username = $jwt_payload['user'];
|
$username = $jwt_payload['user'];
|
||||||
|
@ -210,7 +210,7 @@ function generateAuthHash($useRemoteAddr, $force=false) {
|
||||||
} else {
|
} else {
|
||||||
$authKey = ZM_AUTH_HASH_SECRET.$user['Username'].$user['Password'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
|
$authKey = ZM_AUTH_HASH_SECRET.$user['Username'].$user['Password'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
|
||||||
}
|
}
|
||||||
#ZM\Logger::Debug("Generated using hour:".$local_time[2] . ' mday:' . $local_time[3] . ' month:'.$local_time[4] . ' year: ' . $local_time[5] );
|
#ZM\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['AuthHash'.$_SESSION['remoteAddr']] = $auth;
|
$_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
|
||||||
$_SESSION['AuthHashGeneratedAt'] = $time;
|
$_SESSION['AuthHashGeneratedAt'] = $time;
|
||||||
|
@ -248,14 +248,14 @@ function userFromSession() {
|
||||||
if ( isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) )
|
if ( isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) )
|
||||||
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
|
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
|
||||||
else
|
else
|
||||||
ZM\Logger::Debug("No auth hash in session, there should have been");
|
ZM\Debug("No auth hash in session, there should have been");
|
||||||
} else {
|
} else {
|
||||||
# Need to refresh permissions and validate that the user still exists
|
# Need to refresh permissions and validate that the user still exists
|
||||||
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
|
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
|
||||||
$user = dbFetchOne($sql, NULL, array($_SESSION['username']));
|
$user = dbFetchOne($sql, NULL, array($_SESSION['username']));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug('No username in session');
|
ZM\Debug('No username in session');
|
||||||
}
|
}
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,21 +193,21 @@ function csrf_check($fatal = true) {
|
||||||
$tokens = '';
|
$tokens = '';
|
||||||
do {
|
do {
|
||||||
if (!isset($_POST[$name])) {
|
if (!isset($_POST[$name])) {
|
||||||
#Logger::Debug("POST[$name] is not set");
|
#Debug("POST[$name] is not set");
|
||||||
break;
|
break;
|
||||||
#} else {
|
#} else {
|
||||||
#Logger::Debug("POST[$name] is set as " . $_POST[$name] );
|
#Debug("POST[$name] is set as " . $_POST[$name] );
|
||||||
|
|
||||||
}
|
}
|
||||||
// we don't regenerate a token and check it because some token creation
|
// we don't regenerate a token and check it because some token creation
|
||||||
// schemes are volatile.
|
// schemes are volatile.
|
||||||
$tokens = $_POST[$name];
|
$tokens = $_POST[$name];
|
||||||
if (!csrf_check_tokens($tokens)) {
|
if (!csrf_check_tokens($tokens)) {
|
||||||
#Logger::Debug("Failed checking tokens");
|
#Debug("Failed checking tokens");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#} else {
|
#} else {
|
||||||
#Logger::Debug("Token passed");
|
#Debug("Token passed");
|
||||||
}
|
}
|
||||||
$ok = true;
|
$ok = true;
|
||||||
} while (false);
|
} while (false);
|
||||||
|
@ -296,7 +296,7 @@ function csrf_callback($tokens) {
|
||||||
// Don't make it too easy for users to inflict a CSRF attack on themselves.
|
// Don't make it too easy for users to inflict a CSRF attack on themselves.
|
||||||
echo "<p><strong>Only try again if you weren't sent to this page by someone as this is potentially a sign of an attack.</strong></p>";
|
echo "<p><strong>Only try again if you weren't sent to this page by someone as this is potentially a sign of an attack.</strong></p>";
|
||||||
echo "<form method='post' action=''>$data<input type='submit' value='Try again' /></form>";
|
echo "<form method='post' action=''>$data<input type='submit' value='Try again' /></form>";
|
||||||
ZM\Logger::Debug("Failed csrf check");
|
ZM\Debug("Failed csrf check");
|
||||||
}
|
}
|
||||||
echo "<p>Debug: $tokens</p></body></html>
|
echo "<p>Debug: $tokens</p></body></html>
|
||||||
";
|
";
|
||||||
|
@ -318,27 +318,27 @@ function csrf_check_tokens($tokens) {
|
||||||
* Checks if a token is valid.
|
* Checks if a token is valid.
|
||||||
*/
|
*/
|
||||||
function csrf_check_token($token) {
|
function csrf_check_token($token) {
|
||||||
#Logger::Debug("Checking CSRF token $token");
|
#Debug("Checking CSRF token $token");
|
||||||
if (strpos($token, ':') === false) {
|
if (strpos($token, ':') === false) {
|
||||||
#Logger::Debug("Checking CSRF token $token bad because no :");
|
#Debug("Checking CSRF token $token bad because no :");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list($type, $value) = explode(':', $token, 2);
|
list($type, $value) = explode(':', $token, 2);
|
||||||
if (strpos($value, ',') === false) {
|
if (strpos($value, ',') === false) {
|
||||||
#Logger::Debug("Checking CSRF token $token bad because no ,");
|
#Debug("Checking CSRF token $token bad because no ,");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list($x, $time) = explode(',', $token, 2);
|
list($x, $time) = explode(',', $token, 2);
|
||||||
if ($GLOBALS['csrf']['expires']) {
|
if ($GLOBALS['csrf']['expires']) {
|
||||||
if (time() > $time + $GLOBALS['csrf']['expires']) {
|
if (time() > $time + $GLOBALS['csrf']['expires']) {
|
||||||
#Logger::Debug("Checking CSRF token $token bad because expired");
|
#Debug("Checking CSRF token $token bad because expired");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'sid':
|
case 'sid':
|
||||||
{
|
{
|
||||||
#Logger::Debug("Checking sid: $value === " . csrf_hash(session_id(), $time) );
|
#Debug("Checking sid: $value === " . csrf_hash(session_id(), $time) );
|
||||||
return $value === csrf_hash(session_id(), $time);
|
return $value === csrf_hash(session_id(), $time);
|
||||||
}
|
}
|
||||||
case 'cookie':
|
case 'cookie':
|
||||||
|
@ -348,10 +348,10 @@ return false;
|
||||||
return $value === csrf_hash($_COOKIE[$n], $time);
|
return $value === csrf_hash($_COOKIE[$n], $time);
|
||||||
case 'key':
|
case 'key':
|
||||||
if (!$GLOBALS['csrf']['key']) {
|
if (!$GLOBALS['csrf']['key']) {
|
||||||
Logger::Debug("Checking key: no key set" );
|
Debug("Checking key: no key set" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#Logger::Debug("Checking sid: $value === " . csrf_hash($GLOBALS['csrf']['key'], $time) );
|
#Debug("Checking sid: $value === " . csrf_hash($GLOBALS['csrf']['key'], $time) );
|
||||||
return $value === csrf_hash($GLOBALS['csrf']['key'], $time);
|
return $value === csrf_hash($GLOBALS['csrf']['key'], $time);
|
||||||
// We could disable these 'weaker' checks if 'key' was set, but
|
// We could disable these 'weaker' checks if 'key' was set, but
|
||||||
// that doesn't make me feel good then about the cookie-based
|
// that doesn't make me feel good then about the cookie-based
|
||||||
|
|
|
@ -105,7 +105,7 @@ function dbLog($sql, $update=false) {
|
||||||
global $dbLogLevel;
|
global $dbLogLevel;
|
||||||
$noExecute = $update && ($dbLogLevel >= DB_LOG_DEBUG);
|
$noExecute = $update && ($dbLogLevel >= DB_LOG_DEBUG);
|
||||||
if ( $dbLogLevel > DB_LOG_OFF )
|
if ( $dbLogLevel > DB_LOG_OFF )
|
||||||
ZM\Logger::Debug( "SQL-LOG: $sql".($noExecute?' (not executed)':'') );
|
ZM\Debug( "SQL-LOG: $sql".($noExecute?' (not executed)':'') );
|
||||||
return( $noExecute );
|
return( $noExecute );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ function dbQuery($sql, $params=NULL) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( defined('ZM_DB_DEBUG') ) {
|
if ( defined('ZM_DB_DEBUG') ) {
|
||||||
ZM\Logger::Debug("SQL: $sql values:" . ($params?implode(',',$params):''));
|
ZM\Debug("SQL: $sql values:" . ($params?implode(',',$params):''));
|
||||||
}
|
}
|
||||||
$result = $dbConn->query($sql);
|
$result = $dbConn->query($sql);
|
||||||
if ( ! $result ) {
|
if ( ! $result ) {
|
||||||
|
@ -155,7 +155,7 @@ function dbQuery($sql, $params=NULL) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( defined('ZM_DB_DEBUG') ) {
|
if ( defined('ZM_DB_DEBUG') ) {
|
||||||
ZM\Logger::Debug('SQL: '.$sql.' '.($params?implode(',',$params):'').' rows: '.$result->rowCount());
|
ZM\Debug('SQL: '.$sql.' '.($params?implode(',',$params):'').' rows: '.$result->rowCount());
|
||||||
}
|
}
|
||||||
} catch(PDOException $e) {
|
} catch(PDOException $e) {
|
||||||
ZM\Error("SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . ($params?implode(',',$params):''));
|
ZM\Error("SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . ($params?implode(',',$params):''));
|
||||||
|
|
|
@ -104,7 +104,7 @@ function CORSHeaders() {
|
||||||
# Only need CORSHeaders in the event that there are multiple servers in use.
|
# Only need CORSHeaders in the event that there are multiple servers in use.
|
||||||
# ICON: Might not be true. multi-port?
|
# ICON: Might not be true. multi-port?
|
||||||
if ( ZM_MIN_STREAMING_PORT ) {
|
if ( ZM_MIN_STREAMING_PORT ) {
|
||||||
ZM\Logger::Debug('Setting default Access-Control-Allow-Origin from ' . $_SERVER['HTTP_ORIGIN']);
|
ZM\Debug('Setting default Access-Control-Allow-Origin from ' . $_SERVER['HTTP_ORIGIN']);
|
||||||
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
|
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
|
||||||
header('Access-Control-Allow-Headers: x-requested-with,x-request');
|
header('Access-Control-Allow-Headers: x-requested-with,x-request');
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ function CORSHeaders() {
|
||||||
preg_match('/^(https?:\/\/)?'.preg_quote($Server->Name(),'/').'/i', $_SERVER['HTTP_ORIGIN'])
|
preg_match('/^(https?:\/\/)?'.preg_quote($Server->Name(),'/').'/i', $_SERVER['HTTP_ORIGIN'])
|
||||||
) {
|
) {
|
||||||
$valid = true;
|
$valid = true;
|
||||||
ZM\Logger::Debug('Setting Access-Control-Allow-Origin from '.$_SERVER['HTTP_ORIGIN']);
|
ZM\Debug('Setting Access-Control-Allow-Origin from '.$_SERVER['HTTP_ORIGIN']);
|
||||||
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
|
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
|
||||||
header('Access-Control-Allow-Headers: x-requested-with,x-request');
|
header('Access-Control-Allow-Headers: x-requested-with,x-request');
|
||||||
break;
|
break;
|
||||||
|
@ -392,7 +392,7 @@ function getEventDefaultVideoPath($event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function deletePath( $path ) {
|
function deletePath( $path ) {
|
||||||
ZM\Logger::Debug('Deleting '.$path);
|
ZM\Debug('Deleting '.$path);
|
||||||
if ( is_dir($path) ) {
|
if ( is_dir($path) ) {
|
||||||
system(escapeshellcmd('rm -rf '.$path));
|
system(escapeshellcmd('rm -rf '.$path));
|
||||||
} else if ( file_exists($path) ) {
|
} else if ( file_exists($path) ) {
|
||||||
|
@ -424,6 +424,9 @@ function deleteEvent($event) {
|
||||||
} # CAN EDIT
|
} # CAN EDIT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $label must be already escaped. It can't be done here since it sometimes contains HTML tags.
|
||||||
|
*/
|
||||||
function makeLink($url, $label, $condition=1, $options='') {
|
function makeLink($url, $label, $condition=1, $options='') {
|
||||||
$string = '';
|
$string = '';
|
||||||
if ( $condition ) {
|
if ( $condition ) {
|
||||||
|
@ -443,50 +446,6 @@ function makeHelpLink($ohndx) {
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* $label must be already escaped. It can't be done here since it sometimes contains HTML tags.
|
|
||||||
*/
|
|
||||||
function makePopupLink($url, $winName, $winSize, $label, $condition=1, $options='') {
|
|
||||||
// Avoid double-encoding since some consumers incorrectly pass a pre-escaped URL.
|
|
||||||
$string = '<a';
|
|
||||||
if ( $condition ) {
|
|
||||||
$string .= ' class="popup-link" href="' . htmlspecialchars($url, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false) . '"';
|
|
||||||
$string .= ' data-window-name="' . htmlspecialchars($winName) . '"';
|
|
||||||
if ( is_array( $winSize ) ) {
|
|
||||||
$string .= ' data-window-tag="' . htmlspecialchars($winSize[0]) . '"';
|
|
||||||
$string .= ' data-window-width="' . htmlspecialchars($winSize[1]) . '"';
|
|
||||||
$string .= ' data-window-height="' . htmlspecialchars($winSize[2]) . '"';
|
|
||||||
} else {
|
|
||||||
$string .= ' data-window-tag="' . htmlspecialchars($winSize) . '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
$string .= ($options ? (' ' . $options ) : '') . '>';
|
|
||||||
} else {
|
|
||||||
$string .= '>';
|
|
||||||
}
|
|
||||||
$string .= $label;
|
|
||||||
$string .= '</a>';
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makePopupButton($url, $winName, $winSize, $buttonValue, $condition=1, $options='') {
|
|
||||||
$string = '<input type="button" class="popup-link" value="' . htmlspecialchars($buttonValue) . '"';
|
|
||||||
$string .= ' data-url="' . htmlspecialchars($url, ENT_COMPAT | ENT_HTML401, ini_get("default_charset"), false) . '"';
|
|
||||||
$string .= ' data-window-name="' . htmlspecialchars($winName) . '"';
|
|
||||||
if ( is_array($winSize) ) {
|
|
||||||
$string .= ' data-window-tag="' . htmlspecialchars($winSize[0]) . '"';
|
|
||||||
$string .= ' data-window-width="' . htmlspecialchars($winSize[1]) . '"';
|
|
||||||
$string .= ' data-window-height="' . htmlspecialchars($winSize[2]) . '"';
|
|
||||||
} else {
|
|
||||||
$string .= ' data-window-tag="' . htmlspecialchars($winSize) . '"';
|
|
||||||
}
|
|
||||||
if (!$condition) {
|
|
||||||
$string .= ' disabled="disabled"';
|
|
||||||
}
|
|
||||||
$string .= ($options ? (' ' . $options) : '') . '/>';
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeButton($url, $buttonValue, $condition=1, $options='') {
|
function makeButton($url, $buttonValue, $condition=1, $options='') {
|
||||||
$string = '<button type="button" data-on-click-this="'.$buttonValue.'"';
|
$string = '<button type="button" data-on-click-this="'.$buttonValue.'"';
|
||||||
$string .= ' data-url="' .$url. '"';
|
$string .= ' data-url="' .$url. '"';
|
||||||
|
@ -509,7 +468,7 @@ function htmlSelect($name, $contents, $values, $behaviours=false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<select name="'.$name.'" '.$behaviourText.'>'.htmlOptions($contents, $values).'</select>';
|
return '<select name="'.$name.'" '.$behaviourText.'>'.PHP_EOL.htmlOptions($contents, $values).'</select>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function htmlOptions($options, $values) {
|
function htmlOptions($options, $values) {
|
||||||
|
@ -540,11 +499,10 @@ function htmlOptions($options, $values) {
|
||||||
$options_html .= '<option value="'.htmlspecialchars($value, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'"'.
|
$options_html .= '<option value="'.htmlspecialchars($value, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'"'.
|
||||||
($selected?' selected="selected"':'').
|
($selected?' selected="selected"':'').
|
||||||
($disabled?' disabled="disabled"':'').
|
($disabled?' disabled="disabled"':'').
|
||||||
'>'.htmlspecialchars($text, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'</option>
|
'>'.htmlspecialchars($text, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'</option>'.PHP_EOL;
|
||||||
';
|
|
||||||
} # end foreach options
|
} # end foreach options
|
||||||
if ( $values and ! $has_selected ) {
|
if ( $values and ((!is_array($values)) or count($values) ) and ! $has_selected ) {
|
||||||
ZM\Warning('Specified value '.$values.' not in contents: '.print_r($options, true));
|
ZM\Warning('Specified value '.print_r($values, true).' not in contents: '.print_r($options, true));
|
||||||
}
|
}
|
||||||
return $options_html;
|
return $options_html;
|
||||||
} # end function htmlOptions
|
} # end function htmlOptions
|
||||||
|
@ -582,7 +540,7 @@ function buildSelect($name, $contents, $behaviours=false) {
|
||||||
$behaviourText .= ' '.$event.'="'.$action.'"';
|
$behaviourText .= ' '.$event.'="'.$action.'"';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$behaviourText = ' onchange="'.$behaviours.'"';
|
$behaviourText = ' data-on-change-this="'.$behaviours.'"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -832,7 +790,7 @@ function daemonControl($command, $daemon=false, $args=false) {
|
||||||
}
|
}
|
||||||
$string = escapeshellcmd($string);
|
$string = escapeshellcmd($string);
|
||||||
#$string .= ' 2>/dev/null >&- <&- >/dev/null';
|
#$string .= ' 2>/dev/null >&- <&- >/dev/null';
|
||||||
ZM\Logger::Debug('daemonControl '.$string);
|
ZM\Debug('daemonControl '.$string);
|
||||||
exec($string);
|
exec($string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -973,7 +931,7 @@ function createVideo($event, $format, $rate, $scale, $overwrite=false) {
|
||||||
$command .= ' -o';
|
$command .= ' -o';
|
||||||
$command = escapeshellcmd($command);
|
$command = escapeshellcmd($command);
|
||||||
$result = exec($command, $output, $status);
|
$result = exec($command, $output, $status);
|
||||||
ZM\Logger::Debug("generating Video $command: result($result outptu:(".implode("\n", $output )." status($status");
|
ZM\Debug("generating Video $command: result($result outptu:(".implode("\n", $output )." status($status");
|
||||||
return $status ? '' : rtrim($result);
|
return $status ? '' : rtrim($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1676,17 +1634,17 @@ function coordsToPoints($coords) {
|
||||||
function limitPoints(&$points, $min_x, $min_y, $max_x, $max_y) {
|
function limitPoints(&$points, $min_x, $min_y, $max_x, $max_y) {
|
||||||
foreach ( $points as &$point ) {
|
foreach ( $points as &$point ) {
|
||||||
if ( $point['x'] < $min_x ) {
|
if ( $point['x'] < $min_x ) {
|
||||||
ZM\Logger::Debug('Limiting point x'.$point['x'].' to min_x '.$min_x);
|
ZM\Debug('Limiting point x'.$point['x'].' to min_x '.$min_x);
|
||||||
$point['x'] = $min_x;
|
$point['x'] = $min_x;
|
||||||
} else if ( $point['x'] > $max_x ) {
|
} else if ( $point['x'] > $max_x ) {
|
||||||
ZM\Logger::Debug('Limiting point x'.$point['x'].' to max_x '.$max_x);
|
ZM\Debug('Limiting point x'.$point['x'].' to max_x '.$max_x);
|
||||||
$point['x'] = $max_x;
|
$point['x'] = $max_x;
|
||||||
}
|
}
|
||||||
if ( $point['y'] < $min_y ) {
|
if ( $point['y'] < $min_y ) {
|
||||||
ZM\Logger::Debug('Limiting point y'.$point['y'].' to min_y '.$min_y);
|
ZM\Debug('Limiting point y'.$point['y'].' to min_y '.$min_y);
|
||||||
$point['y'] = $min_y;
|
$point['y'] = $min_y;
|
||||||
} else if ( $point['y'] > $max_y ) {
|
} else if ( $point['y'] > $max_y ) {
|
||||||
ZM\Logger::Debug('Limiting point y'.$point['y'].' to max_y '.$max_y);
|
ZM\Debug('Limiting point y'.$point['y'].' to max_y '.$max_y);
|
||||||
$point['y'] = $max_y;
|
$point['y'] = $max_y;
|
||||||
}
|
}
|
||||||
} // end foreach point
|
} // end foreach point
|
||||||
|
@ -2111,7 +2069,7 @@ function getStreamHTML($monitor, $options = array()) {
|
||||||
if ( $scale < $options['scale'] )
|
if ( $scale < $options['scale'] )
|
||||||
$options['scale'] = $scale;
|
$options['scale'] = $scale;
|
||||||
} else {
|
} else {
|
||||||
Warning('Invalid value for width: '.$options['width']);
|
ZM\Warning('Invalid value for width: '.$options['width']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2211,7 +2169,7 @@ function check_timezone() {
|
||||||
'TIME_FORMAT(TIMEDIFF(NOW(), UTC_TIMESTAMP),\'%H%i\')'
|
'TIME_FORMAT(TIMEDIFF(NOW(), UTC_TIMESTAMP),\'%H%i\')'
|
||||||
));
|
));
|
||||||
|
|
||||||
#Logger::Debug("System timezone offset determine to be: $sys_tzoffset,\x20
|
#Debug("System timezone offset determine to be: $sys_tzoffset,\x20
|
||||||
#PHP timezone offset determine to be: $php_tzoffset,\x20
|
#PHP timezone offset determine to be: $php_tzoffset,\x20
|
||||||
#Mysql timezone offset determine to be: $mysql_tzoffset
|
#Mysql timezone offset determine to be: $mysql_tzoffset
|
||||||
#");
|
#");
|
||||||
|
@ -2450,4 +2408,11 @@ function zm_random_bytes($length = 32) {
|
||||||
}
|
}
|
||||||
ZM\Error('No random_bytes function found.');
|
ZM\Error('No random_bytes function found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function i18n() {
|
||||||
|
$string = explode('_', ZM_LANG_DEFAULT, 2);
|
||||||
|
$string[1] = strtoupper($string[1]);
|
||||||
|
|
||||||
|
return implode('-', $string);
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -158,7 +158,7 @@ class Logger {
|
||||||
|
|
||||||
$this->initialised = true;
|
$this->initialised = true;
|
||||||
|
|
||||||
//Logger::Debug( "LogOpts: level=".self::$codes[$this->level]."/".self::$codes[$this->effectiveLevel].", screen=".self::$codes[$this->termLevel].", database=".self::$codes[$this->databaseLevel].", logfile=".self::$codes[$this->fileLevel]."->".$this->logFile.", weblog=".self::$codes[$this->weblogLevel].", syslog=".self::$codes[$this->syslogLevel] );
|
//Debug( "LogOpts: level=".self::$codes[$this->level]."/".self::$codes[$this->effectiveLevel].", screen=".self::$codes[$this->termLevel].", database=".self::$codes[$this->databaseLevel].", logfile=".self::$codes[$this->fileLevel]."->".$this->logFile.", weblog=".self::$codes[$this->weblogLevel].", syslog=".self::$codes[$this->syslogLevel] );
|
||||||
}
|
}
|
||||||
|
|
||||||
private function terminate() {
|
private function terminate() {
|
||||||
|
@ -199,9 +199,6 @@ class Logger {
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function Debug( $string ) {
|
|
||||||
Logger::fetch()->logPrint( Logger::DEBUG, $string );
|
|
||||||
}
|
|
||||||
|
|
||||||
public function id( $id=NULL ) {
|
public function id( $id=NULL ) {
|
||||||
if ( isset($id) && $this->id != $id ) {
|
if ( isset($id) && $this->id != $id ) {
|
||||||
|
@ -459,6 +456,10 @@ function Dump( &$var, $label='VAR' ) {
|
||||||
Logger::fetch()->logPrint( Logger::DEBUG, ob_get_clean() );
|
Logger::fetch()->logPrint( Logger::DEBUG, ob_get_clean() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Debug( $string ) {
|
||||||
|
Logger::fetch()->logPrint( Logger::DEBUG, $string );
|
||||||
|
}
|
||||||
|
|
||||||
function Info( $string ) {
|
function Info( $string ) {
|
||||||
Logger::fetch()->logPrint( Logger::INFO, $string );
|
Logger::fetch()->logPrint( Logger::INFO, $string );
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ function zm_session_start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ini_set('session.name', 'ZMSESSID');
|
ini_set('session.name', 'ZMSESSID');
|
||||||
ZM\Logger::Debug('Setting cookie parameters to '.print_r($currentCookieParams, true));
|
ZM\Debug('Setting cookie parameters to '.print_r($currentCookieParams, true));
|
||||||
}
|
}
|
||||||
session_start();
|
session_start();
|
||||||
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
|
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
|
||||||
|
@ -37,7 +37,7 @@ function zm_session_start() {
|
||||||
session_start();
|
session_start();
|
||||||
} else if ( !empty($_SESSION['generated_at']) ) {
|
} else if ( !empty($_SESSION['generated_at']) ) {
|
||||||
if ( $_SESSION['generated_at']<($now-(ZM_COOKIE_LIFETIME/2)) ) {
|
if ( $_SESSION['generated_at']<($now-(ZM_COOKIE_LIFETIME/2)) ) {
|
||||||
ZM\Logger::Debug('Regenerating session because generated_at ' . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
|
ZM\Debug('Regenerating session because generated_at ' . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
|
||||||
zm_session_regenerate_id();
|
zm_session_regenerate_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,4 +87,69 @@ function zm_session_clear() {
|
||||||
session_write_close();
|
session_write_close();
|
||||||
session_start();
|
session_start();
|
||||||
} // function zm_session_clear()
|
} // function zm_session_clear()
|
||||||
|
|
||||||
|
|
||||||
|
class Session {
|
||||||
|
private $db;
|
||||||
|
public function __construct() {
|
||||||
|
global $dbConn;
|
||||||
|
$this->db = $dbConn;
|
||||||
|
|
||||||
|
// Set handler to overide SESSION
|
||||||
|
session_set_save_handler(
|
||||||
|
array($this, '_open'),
|
||||||
|
array($this, '_close'),
|
||||||
|
array($this, '_read'),
|
||||||
|
array($this, '_write'),
|
||||||
|
array($this, '_destroy'),
|
||||||
|
array($this, '_gc')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start the session
|
||||||
|
//zm_session_start();
|
||||||
|
}
|
||||||
|
public function _open() {
|
||||||
|
return $this->db ? true : false;
|
||||||
|
}
|
||||||
|
public function _close(){
|
||||||
|
// The example code closed the db connection.. I don't think we care to.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public function _read($id){
|
||||||
|
$sth = $this->db->prepare('SELECT data FROM Sessions WHERE id = :id');
|
||||||
|
$sth->bindParam(':id', $id, PDO::PARAM_STR, 32);
|
||||||
|
|
||||||
|
if ( $sth->execute() and ( $row = $sth->fetch(PDO::FETCH_ASSOC) ) ) {
|
||||||
|
return $row['data'];
|
||||||
|
}
|
||||||
|
// Return an empty string
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
public function _write($id, $data){
|
||||||
|
// Create time stamp
|
||||||
|
$access = time();
|
||||||
|
|
||||||
|
$sth = $this->db->prepare('REPLACE INTO Sessions VALUES (:id, :access, :data)');
|
||||||
|
|
||||||
|
$sth->bindParam(':id', $id, PDO::PARAM_STR, 32);
|
||||||
|
$sth->bindParam(':access', $access, PDO::PARAM_INT);
|
||||||
|
$sth->bindParam(':data', $data);
|
||||||
|
|
||||||
|
return $sth->execute() ? true : false;
|
||||||
|
}
|
||||||
|
public function _destroy($id) {
|
||||||
|
$sth = $this->db->prepare('DELETE FROM Sessions WHERE Id = :id');
|
||||||
|
$sth->bindParam(':id', $id, PDO::PARAM_STR, 32);
|
||||||
|
return $sth->execute() ? true : false;
|
||||||
|
}
|
||||||
|
public function _gc($max) {
|
||||||
|
// Calculate what is to be deemed old
|
||||||
|
$old = time() - $max;
|
||||||
|
$sth = $this->db->prepare('DELETE * FROM Sessions WHERE access < :old');
|
||||||
|
$sth->bindParam(':old', $old, PDO::PARAM_INT);
|
||||||
|
return $sth->execute() ? true : false;
|
||||||
|
}
|
||||||
|
} # end class Session
|
||||||
|
|
||||||
|
$session = new Session;
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -56,7 +56,7 @@ require_once('includes/Monitor.php');
|
||||||
if ( 0 and ZM\Logger::fetch()->debugOn() ) {
|
if ( 0 and ZM\Logger::fetch()->debugOn() ) {
|
||||||
ob_start();
|
ob_start();
|
||||||
phpinfo(INFO_VARIABLES);
|
phpinfo(INFO_VARIABLES);
|
||||||
ZM\Logger::Debug(ob_get_contents());
|
ZM\Debug(ob_get_contents());
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ define('ZM_BASE_URL', '');
|
||||||
|
|
||||||
require_once('includes/functions.php');
|
require_once('includes/functions.php');
|
||||||
if ( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ) {
|
if ( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ) {
|
||||||
ZM\Logger::Debug('OPTIONS Method, only doing CORS');
|
ZM\Debug('OPTIONS Method, only doing CORS');
|
||||||
# Add Cross domain access headers
|
# Add Cross domain access headers
|
||||||
CORSHeaders();
|
CORSHeaders();
|
||||||
return;
|
return;
|
||||||
|
@ -183,6 +183,9 @@ $user = null;
|
||||||
if ( isset($_REQUEST['view']) )
|
if ( isset($_REQUEST['view']) )
|
||||||
$view = detaintPath($_REQUEST['view']);
|
$view = detaintPath($_REQUEST['view']);
|
||||||
|
|
||||||
|
if ( isset($_REQUEST['redirect']) )
|
||||||
|
$redirect = '?view='.detaintPath($_REQUEST['redirect']);
|
||||||
|
|
||||||
# Add CSP Headers
|
# Add CSP Headers
|
||||||
$cspNonce = bin2hex(zm_random_bytes(16));
|
$cspNonce = bin2hex(zm_random_bytes(16));
|
||||||
|
|
||||||
|
@ -218,7 +221,7 @@ if ( (!$view and !$request) or ($view == 'console') ) {
|
||||||
check_timezone();
|
check_timezone();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZM\Logger::Debug("View: $view Request: $request Action: $action User: " . ( isset($user) ? $user['Username'] : 'none' ));
|
ZM\Debug("View: $view Request: $request Action: $action User: " . ( isset($user) ? $user['Username'] : 'none' ));
|
||||||
if (
|
if (
|
||||||
ZM_ENABLE_CSRF_MAGIC &&
|
ZM_ENABLE_CSRF_MAGIC &&
|
||||||
( $action != 'login' ) &&
|
( $action != 'login' ) &&
|
||||||
|
@ -229,14 +232,14 @@ if (
|
||||||
( $view != 'archive' ) // returns data
|
( $view != 'archive' ) // returns data
|
||||||
) {
|
) {
|
||||||
require_once('includes/csrf/csrf-magic.php');
|
require_once('includes/csrf/csrf-magic.php');
|
||||||
#ZM\Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
|
#ZM\Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
|
||||||
csrf_check();
|
csrf_check();
|
||||||
}
|
}
|
||||||
|
|
||||||
# Need to include actions because it does auth
|
# Need to include actions because it does auth
|
||||||
if ( $action and !$request ) {
|
if ( $action and !$request ) {
|
||||||
if ( file_exists('includes/actions/'.$view.'.php') ) {
|
if ( file_exists('includes/actions/'.$view.'.php') ) {
|
||||||
ZM\Logger::Debug("Including includes/actions/$view.php");
|
ZM\Debug("Including includes/actions/$view.php");
|
||||||
require_once('includes/actions/'.$view.'.php');
|
require_once('includes/actions/'.$view.'.php');
|
||||||
} else {
|
} else {
|
||||||
ZM\Warning("No includes/actions/$view.php for action $action");
|
ZM\Warning("No includes/actions/$view.php for action $action");
|
||||||
|
@ -251,7 +254,7 @@ if ( ZM_OPT_USE_AUTH and (!isset($user)) and ($view != 'login') and ($view != 'n
|
||||||
header('HTTP/1.1 401 Unauthorized');
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
ZM\Logger::Debug('Redirecting to login');
|
ZM\Debug('Redirecting to login');
|
||||||
$view = 'none';
|
$view = 'none';
|
||||||
$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login';
|
$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login';
|
||||||
if ( ! $request ) {
|
if ( ! $request ) {
|
||||||
|
@ -268,7 +271,7 @@ if ( ZM_OPT_USE_AUTH and (!isset($user)) and ($view != 'login') and ($view != 'n
|
||||||
|
|
||||||
|
|
||||||
if ( $redirect ) {
|
if ( $redirect ) {
|
||||||
ZM\Logger::Debug("Redirecting to $redirect");
|
ZM\Debug("Redirecting to $redirect");
|
||||||
header('Location: '.$redirect);
|
header('Location: '.$redirect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,14 +72,10 @@ function MonitorStream(monitorData) {
|
||||||
|
|
||||||
this.onclick = function(evt) {
|
this.onclick = function(evt) {
|
||||||
var el = evt.currentTarget;
|
var el = evt.currentTarget;
|
||||||
var tag = 'watch';
|
|
||||||
var id = el.getAttribute("data-monitor-id");
|
var id = el.getAttribute("data-monitor-id");
|
||||||
var width = el.getAttribute("data-width");
|
|
||||||
var height = el.getAttribute("data-height");
|
|
||||||
var url = '?view=watch&mid='+id;
|
var url = '?view=watch&mid='+id;
|
||||||
var name = 'zmWatch'+id;
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
createPopup(url, name, tag, width, height);
|
window.location.assign(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setup_onclick = function() {
|
this.setup_onclick = function() {
|
||||||
|
|
|
@ -989,7 +989,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -951,7 +951,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -947,7 +947,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -949,7 +949,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -973,7 +973,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -261,7 +261,10 @@ $SLANG = array(
|
||||||
'ConfigType' => 'Config Type',
|
'ConfigType' => 'Config Type',
|
||||||
'ConfiguredFor' => 'Configured for',
|
'ConfiguredFor' => 'Configured for',
|
||||||
'ConfigURL' => 'Config Base URL',
|
'ConfigURL' => 'Config Base URL',
|
||||||
|
'ConfirmDeleteControl' => 'Warning, deleting a control will reset all monitors that use it to be uncontrollable.<br><br>Are you sure you wish to delete?',
|
||||||
|
'ConfirmDeleteDevices' => 'Are you sure you wish to delete the selected devices?',
|
||||||
'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?',
|
'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?',
|
||||||
|
'ConfirmDeleteTitle' => 'Delete Confirmation',
|
||||||
'ConfirmPassword' => 'Confirm Password',
|
'ConfirmPassword' => 'Confirm Password',
|
||||||
'ConjAnd' => 'and',
|
'ConjAnd' => 'and',
|
||||||
'ConjOr' => 'or',
|
'ConjOr' => 'or',
|
||||||
|
@ -320,6 +323,7 @@ $SLANG = array(
|
||||||
'DuplicateMonitorName' => 'Duplicate Monitor Name',
|
'DuplicateMonitorName' => 'Duplicate Monitor Name',
|
||||||
'Duration' => 'Duration',
|
'Duration' => 'Duration',
|
||||||
'Edit' => 'Edit',
|
'Edit' => 'Edit',
|
||||||
|
'EditControl' => 'Edit Control',
|
||||||
'EditLayout' => 'Edit Layout',
|
'EditLayout' => 'Edit Layout',
|
||||||
'Email' => 'Email',
|
'Email' => 'Email',
|
||||||
'EnableAlarms' => 'Enable Alarms',
|
'EnableAlarms' => 'Enable Alarms',
|
||||||
|
@ -363,6 +367,7 @@ $SLANG = array(
|
||||||
'Ffmpeg' => 'Ffmpeg',
|
'Ffmpeg' => 'Ffmpeg',
|
||||||
'File' => 'File',
|
'File' => 'File',
|
||||||
'FilterArchiveEvents' => 'Archive all matches',
|
'FilterArchiveEvents' => 'Archive all matches',
|
||||||
|
'FilterUnarchiveEvents' => 'Unarchive all matches',
|
||||||
'FilterUpdateDiskSpace' => 'Update used disk space',
|
'FilterUpdateDiskSpace' => 'Update used disk space',
|
||||||
'FilterDeleteEvents' => 'Delete all matches',
|
'FilterDeleteEvents' => 'Delete all matches',
|
||||||
'FilterCopyEvents' => 'Copy all matches',
|
'FilterCopyEvents' => 'Copy all matches',
|
||||||
|
@ -1070,7 +1075,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -953,7 +953,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -946,7 +946,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -990,7 +990,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -953,7 +953,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -948,7 +948,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -948,7 +948,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -942,7 +942,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -887,7 +887,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -957,7 +957,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,9 @@
|
||||||
//
|
//
|
||||||
// Examples
|
// Examples
|
||||||
// setlocale( 'LC_ALL', 'en_GB' ); All locale settings pre-4.3.0
|
// setlocale( 'LC_ALL', 'en_GB' ); All locale settings pre-4.3.0
|
||||||
setlocale( LC_ALL, 'cn_ZH' ); //All locale settings 4.3.0 and after
|
setlocale( LC_ALL, 'zh_CN' ); //All locale settings 4.3.0 and after
|
||||||
setlocale( LC_CTYPE, 'cn_ZH' ); //Character class settings 4.3.0 and after
|
setlocale( LC_CTYPE, 'zh_CN' ); //Character class settings 4.3.0 and after
|
||||||
setlocale( LC_TIME, 'cn_ZH' ); //Date and time formatting 4.3.0 and after
|
setlocale( LC_TIME, 'zh_CN' ); //Date and time formatting 4.3.0 and after
|
||||||
|
|
||||||
// Simple String Replacements
|
// Simple String Replacements
|
||||||
$SLANG = array(
|
$SLANG = array(
|
||||||
|
@ -989,7 +989,7 @@ $OLANG = array(
|
||||||
|
|
||||||
// 'LANG_DEFAULT' => array(
|
// 'LANG_DEFAULT' => array(
|
||||||
// 'Prompt' => "This is a new prompt for this option",
|
// 'Prompt' => "This is a new prompt for this option",
|
||||||
// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked"
|
// 'Help' => "This is some new help for this option which will be displayed in the window when the ? is clicked"
|
||||||
// ),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
|
@ -508,6 +508,7 @@ th.table-th-sort-rev span.table-th-sort-span {
|
||||||
margin: 0 auto 8px auto;
|
margin: 0 auto 8px auto;
|
||||||
line-height: 130%;
|
line-height: 130%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content p {
|
#content p {
|
||||||
|
|
|
@ -1,19 +1,3 @@
|
||||||
#logSummary {
|
|
||||||
font-size:10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logSummary tr {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logSummary td {
|
|
||||||
border: 1px solid #7f7fb2;
|
|
||||||
padding: 0 6px;
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.log-fat td {
|
tr.log-fat td {
|
||||||
background-color:#ffcccc;
|
background-color:#ffcccc;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -32,20 +16,3 @@ tr.log-dbg td {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
#exportLog label {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
#exportLog input[type=radio] {
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
#exportError {
|
|
||||||
display: none;
|
|
||||||
color: #dc143c;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#exportErrorText {
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
tr.log-fat td {
|
|
||||||
background-color:#ffcccc;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.log-err td {
|
|
||||||
background-color:#ffcccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.log-war td {
|
|
||||||
background-color: #ffe4b5;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.log-dbg td {
|
|
||||||
color: #666666;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#definitionPanel {
|
#definitionPanel {
|
||||||
float: left;
|
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,15 +19,23 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
$rates = array(
|
$rates = array(
|
||||||
'10000' => '100x',
|
-5000 => '-50x',
|
||||||
'5000' => '50x',
|
-2500 => '-25x',
|
||||||
'2500' => '25x',
|
-1000 => '-10x',
|
||||||
'1000' => '10x',
|
-500 => '-5x',
|
||||||
'400' => '4x',
|
-200 => '-2x',
|
||||||
'200' => '2x',
|
-100 => '-1x',
|
||||||
'100' => translate('Real'),
|
-50 => '-1/2x',
|
||||||
'50' => '1/2x',
|
-25 => '-1/4x',
|
||||||
'25' => '1/4x',
|
0 => translate('Stop'),
|
||||||
|
25 => '1/4x',
|
||||||
|
50 => '1/2x',
|
||||||
|
100 => '1x',
|
||||||
|
200 => '2x',
|
||||||
|
500 => '5x',
|
||||||
|
1000 => '10x',
|
||||||
|
2500 => '25x',
|
||||||
|
5000 => '50x'
|
||||||
);
|
);
|
||||||
|
|
||||||
$scales = array(
|
$scales = array(
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue