Merge branch 'master' of github.com:/ZoneMinder/zoneminder
This commit is contained in:
commit
c8392feba3
|
@ -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
|
|
@ -806,7 +806,7 @@ find_package(
|
|||
Getopt::Long Time::HiRes Date::Manip LWP::UserAgent
|
||||
ExtUtils::MakeMaker ${ZM_MMAP_PERLPACKAGE})
|
||||
if(NOT PERLMODULES_FOUND)
|
||||
message(FATAL_ERROR
|
||||
message(WARNING
|
||||
"Not all required perl modules were found on your system")
|
||||
endif(NOT PERLMODULES_FOUND)
|
||||
|
||||
|
@ -842,7 +842,7 @@ if(WITH_SYSTEMD)
|
|||
# Check for polkit
|
||||
find_package(Polkit)
|
||||
if(NOT POLKIT_FOUND)
|
||||
message(FATAL_ERROR
|
||||
message(WARNING
|
||||
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
|
||||
endif(NOT POLKIT_FOUND)
|
||||
endif(WITH_SYSTEMD)
|
||||
|
|
|
@ -285,6 +285,7 @@ CREATE TABLE `Filters` (
|
|||
`UserId` int(10) unsigned,
|
||||
`Query_json` text NOT NULL,
|
||||
`AutoArchive` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoUnarchive` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoVideo` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoUpload` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoEmail` tinyint(3) unsigned NOT NULL default '0',
|
||||
|
@ -551,7 +552,7 @@ CREATE TABLE `Monitor_Status` (
|
|||
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
||||
`CaptureBandwidth` INT NOT NULL default 0,
|
||||
PRIMARY KEY (`MonitorId`)
|
||||
) ENGINE=MEMORY;
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
--
|
||||
-- Table structure for table `States`
|
||||
-- PP - Added IsActive to track custom run states
|
||||
|
@ -1024,6 +1025,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 ('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.
|
||||
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,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
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.35.7
|
||||
Version: 1.35.10
|
||||
Release: 1%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
|
|
|
@ -17,6 +17,7 @@ Build-Depends: debhelper, dh-systemd, sphinx-doc, python3-sphinx, dh-linktree, d
|
|||
,libbz2-dev
|
||||
,libgcrypt20-dev
|
||||
,libcurl4-gnutls-dev
|
||||
,libjpeg-turbo8-dev | libjpeg62-turbo-dev | libjpeg8-dev | libjpeg9-dev
|
||||
,libturbojpeg0-dev
|
||||
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
|
||||
,libpcre3-dev
|
||||
|
@ -32,6 +33,7 @@ Build-Depends: debhelper, dh-systemd, sphinx-doc, python3-sphinx, dh-linktree, d
|
|||
,libssl-dev
|
||||
,libcrypt-eksblowfish-perl
|
||||
,libdata-entropy-perl
|
||||
,libvncserver-dev
|
||||
# Unbundled (dh_linktree):
|
||||
,libjs-jquery
|
||||
,libjs-mootools
|
||||
|
@ -80,6 +82,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
|||
,libpcre3
|
||||
,libcrypt-eksblowfish-perl
|
||||
,libdata-entropy-perl
|
||||
,libvncclient1|libvncclient0
|
||||
Recommends: ${misc:Recommends}
|
||||
,libapache2-mod-php | php-fpm
|
||||
,mysql-server | mariadb-server | virtual-mysql-server
|
||||
|
|
|
@ -16,17 +16,20 @@ create_db () {
|
|||
else
|
||||
echo "Db exists."
|
||||
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')")"
|
||||
if [ $USER_EXISTS -ne 1 ]; then
|
||||
echo "Creating zm user $ZM_DB_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
|
||||
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 () {
|
||||
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 -f
|
||||
|
@ -94,6 +97,7 @@ if [ "$1" = "configure" ]; then
|
|||
# Make sure systemctl status exit code is 0; i.e. the DB is running
|
||||
if systemctl is-active --quiet "$DBSERVICE"; then
|
||||
create_db
|
||||
create_update_user
|
||||
update_db
|
||||
else
|
||||
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
|
||||
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||
create_db
|
||||
create_update_user
|
||||
update_db
|
||||
else
|
||||
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||
|
|
|
@ -2648,7 +2648,7 @@ our @options = (
|
|||
},
|
||||
{
|
||||
name => 'ZM_WEB_EVENT_SORT_FIELD',
|
||||
default => 'StartDateTime',
|
||||
default => 'StartTime',
|
||||
description => 'Default field the event lists are sorted by',
|
||||
help => q`
|
||||
Events in lists can be initially ordered in any way you want.
|
||||
|
@ -2660,7 +2660,7 @@ our @options = (
|
|||
`,
|
||||
type => {
|
||||
db_type =>'string',
|
||||
hint =>'Id|Name|Cause|DiskSpace|MonitorName|StartDateTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore',
|
||||
hint =>'Id|Name|Cause|DiskSpace|MonitorName|StartTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore',
|
||||
pattern =>qr|.|,
|
||||
format =>q( $1 )
|
||||
},
|
||||
|
|
|
@ -58,6 +58,7 @@ Id
|
|||
Name
|
||||
Query_json
|
||||
AutoArchive
|
||||
AutoUnarchive
|
||||
AutoVideo
|
||||
AutoUpload
|
||||
AutoEmail
|
||||
|
@ -201,28 +202,25 @@ sub Sql {
|
|||
$self->{Sql} .= 'extract( hour_second from E.EndTime )';
|
||||
} elsif ( $term->{attr} eq 'EndWeekday' ) {
|
||||
$self->{Sql} .= "weekday( E.EndTime )";
|
||||
|
||||
#
|
||||
} elsif ( $term->{attr} eq 'ExistsInFileSystem' ) {
|
||||
push @{$self->{PostSQLConditions}}, $term;
|
||||
} elsif ( $term->{attr} eq 'DiskSpace' ) {
|
||||
$self->{Sql} .= 'E.DiskSpace';
|
||||
$self->{Sql} .= 'TRUE /* ExistsInFileSystem */';
|
||||
} elsif ( $term->{attr} eq 'DiskPercent' ) {
|
||||
$self->{Sql} .= 'zmDiskPercent';
|
||||
$self->{HasDiskPercent} = !undef;
|
||||
$self->{HasPreCondition} = !undef;
|
||||
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
|
||||
$self->{Sql} .= 'zmDiskBlocks';
|
||||
$self->{HasDiskBlocks} = !undef;
|
||||
$self->{HasPreCondition} = !undef;
|
||||
} elsif ( $term->{attr} eq 'SystemLoad' ) {
|
||||
$self->{Sql} .= 'zmSystemLoad';
|
||||
$self->{HasSystemLoad} = !undef;
|
||||
$self->{HasPreCondition} = !undef;
|
||||
} else {
|
||||
$self->{Sql} .= 'E.'.$term->{attr};
|
||||
}
|
||||
|
||||
if ( $term->{attr} eq 'ExistsInFileSystem' ) {
|
||||
# PostCondition, so no further SQL
|
||||
} else {
|
||||
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
|
||||
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
|
||||
|
||||
|
@ -297,11 +295,12 @@ sub Sql {
|
|||
push @value_list, $value;
|
||||
} # end foreach temp_value
|
||||
} # end if has an attr
|
||||
|
||||
if ( $term->{op} ) {
|
||||
if ( $term->{op} eq '=~' ) {
|
||||
$self->{Sql} .= " regexp $value";
|
||||
$self->{Sql} .= ' REGEXP '.$value;
|
||||
} elsif ( $term->{op} eq '!~' ) {
|
||||
$self->{Sql} .= " not regexp $value";
|
||||
$self->{Sql} .= ' NOT REGEXP '.$value;
|
||||
} elsif ( $term->{op} eq 'IS' ) {
|
||||
if ( $value eq 'Odd' ) {
|
||||
$self->{Sql} .= ' % 2 = 1';
|
||||
|
@ -311,21 +310,22 @@ sub Sql {
|
|||
$self->{Sql} .= " IS $value";
|
||||
}
|
||||
} elsif ( $term->{op} eq 'EXISTS' ) {
|
||||
$self->{Sql} .= " EXISTS $value";
|
||||
$self->{Sql} .= ' EXISTS '.$value;
|
||||
} elsif ( $term->{op} eq 'IS NOT' ) {
|
||||
$self->{Sql} .= " IS NOT $value";
|
||||
} elsif ( $term->{op} eq '=[]' ) {
|
||||
$self->{Sql} .= ' IS NOT '.$value;
|
||||
} elsif ( $term->{op} eq '=[]' or $term->{op} eq 'IN' ) {
|
||||
$self->{Sql} .= ' IN ('.join(',', @value_list).')';
|
||||
} elsif ( $term->{op} eq '!~' ) {
|
||||
} elsif ( $term->{op} eq '![]' ) {
|
||||
$self->{Sql} .= ' NOT IN ('.join(',', @value_list).')';
|
||||
} elsif ( $term->{op} eq 'LIKE' ) {
|
||||
$self->{Sql} .= " LIKE $value";
|
||||
$self->{Sql} .= ' LIKE '.$value;
|
||||
} elsif ( $term->{op} eq 'NOT LIKE' ) {
|
||||
$self->{Sql} .= " NOT LIKE $value";
|
||||
$self->{Sql} .= ' NOT LIKE '.$value;
|
||||
} else {
|
||||
$self->{Sql} .= ' '.$term->{op}.' '.$value;
|
||||
}
|
||||
} # end if has an operator
|
||||
} # end if Pre/Post or SQL
|
||||
if ( exists($term->{cbr}) ) {
|
||||
$self->{Sql} .= ' '.str_repeat(')', $term->{cbr}).' ';
|
||||
}
|
||||
|
@ -341,6 +341,9 @@ sub Sql {
|
|||
if ( $self->{AutoArchive} ) {
|
||||
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.
|
||||
# If the file already exists, then the video won't be re-recreated
|
||||
if ( $self->{AutoVideo} ) {
|
||||
|
@ -394,7 +397,7 @@ sub Sql {
|
|||
$sort_column = 'E.StartTime';
|
||||
}
|
||||
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} ) {
|
||||
$sql .= ' LIMIT 0,'.$filter_expr->{limit};
|
||||
}
|
||||
|
|
|
@ -121,6 +121,24 @@ $serial = $primary_key = 'Id';
|
|||
WebColour
|
||||
Exif
|
||||
Sequence
|
||||
TotalEvents
|
||||
TotalEventDiskSpace
|
||||
HourEvents
|
||||
HourEventDiskSpace
|
||||
DayEvents
|
||||
DayEventDiskSpace
|
||||
WeekEvents
|
||||
WeekEventDiskSpace
|
||||
MonthEvents
|
||||
MonthEventDiskSpace
|
||||
ArchivedEvents
|
||||
ArchivedEventDiskSpace
|
||||
ZoneCount
|
||||
Refresh
|
||||
DefaultCodec
|
||||
GroupIds
|
||||
Latitude
|
||||
Longitude
|
||||
);
|
||||
|
||||
%defaults = (
|
||||
|
@ -201,6 +219,23 @@ $serial = $primary_key = 'Id';
|
|||
WebColour => '#ff0000',
|
||||
Exif => 0,
|
||||
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 {
|
||||
|
@ -211,6 +246,30 @@ sub Storage {
|
|||
return new ZoneMinder::Storage( $_[0]{StorageId} );
|
||||
} # 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;
|
||||
__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):());
|
||||
|
||||
sub HupHandler {
|
||||
# This idea at this time is to just exit, freeing up the memory.
|
||||
# zmfilter.pl will be respawned by zmdc.
|
||||
|
@ -236,6 +237,7 @@ sub getFilters {
|
|||
$sql .= ' `Background` = 1 AND';
|
||||
}
|
||||
$sql .= '( `AutoArchive` = 1
|
||||
or `AutoUnarchive` = 1
|
||||
or `AutoVideo` = 1
|
||||
or `AutoUpload` = 1
|
||||
or `AutoEmail` = 1
|
||||
|
@ -282,6 +284,7 @@ sub checkFilter {
|
|||
join(', ',
|
||||
($filter->{AutoDelete}?'delete':()),
|
||||
($filter->{AutoArchive}?'archive':()),
|
||||
($filter->{AutoUnarchive}?'unarchive':()),
|
||||
($filter->{AutoVideo}?'video':()),
|
||||
($filter->{AutoUpload}?'upload':()),
|
||||
($filter->{AutoEmail}?'email':()),
|
||||
|
@ -299,7 +302,7 @@ sub checkFilter {
|
|||
last if $zm_terminate;
|
||||
my $Event = new ZoneMinder::Event($$event{Id}, $event);
|
||||
|
||||
Debug("Checking event $Event->{Id}");
|
||||
Debug('Checking event '.$Event->{Id});
|
||||
my $delete_ok = !undef;
|
||||
$dbh->ping();
|
||||
if ( $filter->{AutoArchive} ) {
|
||||
|
@ -311,6 +314,15 @@ sub checkFilter {
|
|||
my $res = $sth->execute($Event->{Id})
|
||||
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 ( !$Event->{Videoed} ) {
|
||||
$delete_ok = undef if !generateVideo($filter, $Event);
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
//#define USE_PREPARED_SQL 1
|
||||
|
||||
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;
|
||||
|
||||
|
@ -104,9 +105,11 @@ Event::Event(
|
|||
);
|
||||
db_mutex.lock();
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't insert event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||
db_mutex.unlock();
|
||||
Error("Can't insert event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||
return;
|
||||
} else {
|
||||
Debug(2, "Created new event with %s", sql);
|
||||
}
|
||||
id = mysql_insert_id(&dbconn);
|
||||
|
||||
|
@ -202,8 +205,8 @@ Event::Event(
|
|||
video_name = stringtf("%" PRIu64 "-%s", id, "video.mp4");
|
||||
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||
db_mutex.unlock();
|
||||
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||
return;
|
||||
}
|
||||
video_file = path + "/" + video_name;
|
||||
|
@ -501,8 +504,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) {
|
||||
static char sql[ZM_SQL_LGE_BUFSIZ];
|
||||
strncpy(sql, "INSERT INTO `Frames` (`EventId`, `FrameId`, `TimeStamp`, `Delta`) VALUES ", sizeof(sql));
|
||||
char *frame_insert_values = (char *)&frame_insert_sql + 90; // 90 == strlen(frame_insert_sql);
|
||||
//static char sql[ZM_SQL_LGE_BUFSIZ];
|
||||
//strncpy(sql, "INSERT INTO `Frames` (`EventId`, `FrameId`, `TimeStamp`, `Delta`) VALUES ", sizeof(sql));
|
||||
int frameCount = 0;
|
||||
for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) {
|
||||
if ( timestamps[i]->tv_sec <= 0 ) {
|
||||
|
@ -541,21 +545,24 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
|
|||
delta_time.sec = 0;
|
||||
}
|
||||
|
||||
int sql_len = strlen(sql);
|
||||
snprintf(sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ",
|
||||
frame_insert_values += snprintf(frame_insert_values,
|
||||
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);
|
||||
|
||||
frameCount++;
|
||||
} // end foreach frame
|
||||
|
||||
if ( frameCount ) {
|
||||
Debug(1, "Adding %d/%d frames to DB", frameCount, n_frames);
|
||||
*(sql+strlen(sql)-2) = '\0';
|
||||
*(frame_insert_values-1) = '\0';
|
||||
db_mutex.lock();
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), sql);
|
||||
}
|
||||
int rc = mysql_query(&dbconn, frame_insert_sql);
|
||||
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;
|
||||
} else {
|
||||
Debug(1, "No valid pre-capture frames to add");
|
||||
|
@ -563,16 +570,15 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
|
|||
} // void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, struct timeval **timestamps)
|
||||
|
||||
void Event::WriteDbFrames() {
|
||||
static char sql[ZM_SQL_LGE_BUFSIZ];
|
||||
char * sql_ptr = (char *)&sql;
|
||||
sql_ptr += snprintf(sql, sizeof(sql),
|
||||
"INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) VALUES "
|
||||
);
|
||||
char *frame_insert_values_ptr = (char *)&frame_insert_sql + 90; // 90 == strlen(frame_insert_sql);
|
||||
while ( frame_data.size() ) {
|
||||
Frame *frame = frame_data.front();
|
||||
frame_data.pop();
|
||||
sql_ptr += snprintf(sql_ptr, sizeof(sql)-(sql_ptr-(char *)&sql), "( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d ), ",
|
||||
id, frame->frame_id, frame_type_names[frame->type],
|
||||
frame_insert_values_ptr += snprintf(frame_insert_values_ptr,
|
||||
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->delta.positive?"":"-",
|
||||
frame->delta.sec,
|
||||
|
@ -580,14 +586,17 @@ void Event::WriteDbFrames() {
|
|||
frame->score);
|
||||
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();
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
int rc = mysql_query(&dbconn, frame_insert_sql);
|
||||
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;
|
||||
} else {
|
||||
Debug(1, "INSERT FRAMES: sql was %s", frame_insert_sql);
|
||||
}
|
||||
db_mutex.unlock();
|
||||
} // end void Event::WriteDbFrames()
|
||||
|
||||
// Subtract an offset time from frames deltas to match with video start time
|
||||
|
@ -668,6 +677,8 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
|||
|
||||
struct DeltaTimeval delta_time;
|
||||
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);
|
||||
|
||||
bool db_frame = ( frame_type != BULK ) || (frames==1) || ((frames%config.bulk_frame_interval)==0) ;
|
||||
if ( db_frame ) {
|
||||
|
@ -675,16 +686,12 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
|||
|
||||
// The idea is to write out 1/sec
|
||||
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
|
||||
if ( write_to_db || ( monitor->get_fps() && (frame_data.size() > monitor->get_fps())) ) {
|
||||
Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f",
|
||||
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 > analysis fps %f or BULK",
|
||||
frame_data.size(), write_to_db, monitor->get_fps());
|
||||
WriteDbFrames();
|
||||
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),
|
||||
"UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
|
||||
( delta_time.positive?"":"-" ),
|
||||
|
|
|
@ -117,6 +117,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
|
||||
snprintf(sql, sizeof(sql),
|
||||
"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, "
|
||||
"`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->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]);
|
||||
event_data->start_time = atoi(dbrow[3]);
|
||||
event_data->duration = dbrow[4] ? atof(dbrow[4]) : 0.0;
|
||||
strncpy(event_data->video_file, dbrow[5], sizeof(event_data->video_file)-1);
|
||||
std::string scheme_str = std::string(dbrow[6]);
|
||||
event_data->end_time = dbrow[4] ? atoi(dbrow[4]) : 0;
|
||||
event_data->duration = dbrow[5] ? atof(dbrow[5]) : 0.0;
|
||||
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" ) {
|
||||
event_data->scheme = Storage::DEEP;
|
||||
} else if ( scheme_str == "Medium" ) {
|
||||
|
@ -160,8 +162,8 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
} else {
|
||||
event_data->scheme = Storage::SHALLOW;
|
||||
}
|
||||
event_data->SaveJPEGs = dbrow[7] == nullptr ? 0 : atoi(dbrow[7]);
|
||||
event_data->Orientation = (Monitor::Orientation)(dbrow[8] == nullptr ? 0 : atoi(dbrow[8]));
|
||||
event_data->SaveJPEGs = dbrow[8] == nullptr ? 0 : atoi(dbrow[8]);
|
||||
event_data->Orientation = (Monitor::Orientation)(dbrow[9] == nullptr ? 0 : atoi(dbrow[9]));
|
||||
mysql_free_result(result);
|
||||
|
||||
if ( !monitor ) {
|
||||
|
@ -223,8 +225,6 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
}
|
||||
|
||||
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` "
|
||||
"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
|
||||
);
|
||||
}
|
||||
// Incomplete events might not have any frame data
|
||||
event_data->last_frame_id = last_id;
|
||||
|
||||
if ( mysql_errno(&dbconn) ) {
|
||||
Error("Can't fetch row: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
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");
|
||||
}
|
||||
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());
|
||||
if ( ffmpeg_input )
|
||||
delete ffmpeg_input;
|
||||
|
||||
ffmpeg_input = new FFmpeg_Input();
|
||||
if ( 0 > ffmpeg_input->Open(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 ( replay_rate > 0 )
|
||||
curr_stream_time = event_data->frames[0].timestamp;
|
||||
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",
|
||||
event_data->event_id, event_data->frame_count, event_data->duration);
|
||||
Debug(2, "Event:%" PRIu64 ", Frames:%ld, Last Frame ID(%ld, Duration: %.2f",
|
||||
event_data->event_id, event_data->frame_count, event_data->last_frame_id, event_data->duration);
|
||||
|
||||
return true;
|
||||
} // bool EventStream::loadEventData( int event_id )
|
||||
|
@ -341,12 +345,12 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
if (
|
||||
(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");
|
||||
curr_frame_id = 1;
|
||||
} 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"),
|
||||
curr_frame_id, event_data->frame_count );
|
||||
}
|
||||
|
@ -359,6 +363,13 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
paused = false;
|
||||
}
|
||||
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;
|
||||
case CMD_STOP :
|
||||
Debug(1, "Got STOP command");
|
||||
|
@ -394,7 +405,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
paused = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
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;
|
||||
Debug(1, "Got SLOWFWD command new frame id %d", curr_frame_id);
|
||||
break;
|
||||
|
@ -411,6 +422,8 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
paused = false;
|
||||
// Set play rate
|
||||
switch ( replay_rate ) {
|
||||
case -1 * ZM_RATE_BASE :
|
||||
replay_rate = -2 * ZM_RATE_BASE;
|
||||
case -2 * ZM_RATE_BASE :
|
||||
replay_rate = -5 * ZM_RATE_BASE;
|
||||
break;
|
||||
|
@ -425,7 +438,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
replay_rate = -50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
replay_rate = -2 * ZM_RATE_BASE;
|
||||
replay_rate = -1 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -489,14 +502,14 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
if ( replay_rate >= 0 )
|
||||
curr_frame_id = 0;
|
||||
else
|
||||
curr_frame_id = event_data->frame_count+1;
|
||||
curr_frame_id = event_data->last_frame_id+1;
|
||||
paused = false;
|
||||
forceEventChange = true;
|
||||
break;
|
||||
case CMD_NEXT :
|
||||
Debug(1, "Got NEXT command");
|
||||
if ( replay_rate >= 0 )
|
||||
curr_frame_id = event_data->frame_count+1;
|
||||
curr_frame_id = event_data->last_frame_id+1;
|
||||
else
|
||||
curr_frame_id = 0;
|
||||
paused = false;
|
||||
|
@ -505,9 +518,33 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
case CMD_SEEK :
|
||||
{
|
||||
// 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);
|
||||
Debug(1, "Got SEEK command, to %d (new cfid: %d)", offset, curr_frame_id);
|
||||
|
||||
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];
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -524,19 +561,22 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
|
||||
struct {
|
||||
uint64_t event_id;
|
||||
int progress;
|
||||
double duration;
|
||||
double progress;
|
||||
int rate;
|
||||
int zoom;
|
||||
bool paused;
|
||||
} status_data;
|
||||
|
||||
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.zoom = zoom;
|
||||
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.duration,
|
||||
status_data.paused,
|
||||
status_data.progress,
|
||||
status_data.rate,
|
||||
|
@ -568,7 +608,14 @@ bool EventStream::checkEventLoaded() {
|
|||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||
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),
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
|
@ -581,6 +628,7 @@ bool EventStream::checkEventLoaded() {
|
|||
|
||||
// Event change required.
|
||||
if ( forceEventChange || ( (mode != MODE_SINGLE) && (mode != MODE_NONE) ) ) {
|
||||
Debug(1, "Checking for next event %s", sql);
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
|
@ -591,6 +639,9 @@ bool EventStream::checkEventLoaded() {
|
|||
Error("Can't use query result: %s", mysql_error(&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);
|
||||
|
||||
if ( mysql_errno(&dbconn)) {
|
||||
|
@ -605,7 +656,7 @@ bool EventStream::checkEventLoaded() {
|
|||
loadEventData(event_id);
|
||||
|
||||
if ( replay_rate < 0 ) // rewind
|
||||
curr_frame_id = event_data->frame_count;
|
||||
curr_frame_id = event_data->last_frame_id;
|
||||
else
|
||||
curr_frame_id = 1;
|
||||
Debug(2, "New frame id = %d", curr_frame_id);
|
||||
|
@ -626,7 +677,7 @@ bool EventStream::checkEventLoaded() {
|
|||
if ( curr_frame_id <= 0 )
|
||||
curr_frame_id = 1;
|
||||
else
|
||||
curr_frame_id = event_data->frame_count;
|
||||
curr_frame_id = event_data->last_frame_id;
|
||||
paused = true;
|
||||
}
|
||||
return false;
|
||||
|
@ -683,9 +734,6 @@ bool EventStream::sendFrame(int delta_us) {
|
|||
#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];
|
||||
|
||||
|
@ -748,6 +796,9 @@ bool EventStream::sendFrame(int delta_us) {
|
|||
}
|
||||
|
||||
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 ) {
|
||||
case STREAM_JPEG :
|
||||
|
@ -776,7 +827,7 @@ bool EventStream::sendFrame(int delta_us) {
|
|||
|
||||
} // end if stream MPEG or other
|
||||
|
||||
fputs("\r\n\r\n", stdout);
|
||||
fputs("\r\n", stdout);
|
||||
fflush(stdout);
|
||||
last_frame_sent = TV_2_FLOAT(now);
|
||||
return true;
|
||||
|
@ -795,13 +846,11 @@ void EventStream::runStream() {
|
|||
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);
|
||||
gettimeofday(&start, nullptr);
|
||||
uint64_t start_usec = start.tv_sec * 1000000 + start.tv_usec;
|
||||
uint64_t last_frame_offset = 0;
|
||||
|
||||
bool in_event = true;
|
||||
double time_to_event = 0;
|
||||
|
||||
while ( !zm_terminate ) {
|
||||
|
@ -843,8 +892,8 @@ void EventStream::runStream() {
|
|||
send_frame = true;
|
||||
} else if ( !send_frame ) {
|
||||
// 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;
|
||||
if ( actual_delta_time > MAX_STREAM_DELAY ) {
|
||||
double time_since_last_send = TV_2_FLOAT(now) - last_frame_sent;
|
||||
if ( time_since_last_send > MAX_STREAM_DELAY ) {
|
||||
// Send keepalive
|
||||
Debug(2, "Sending keepalive frame");
|
||||
send_frame = true;
|
||||
|
@ -852,21 +901,19 @@ void EventStream::runStream() {
|
|||
} // end if streaming stepping or doing nothing
|
||||
|
||||
// time_to_event > 0 means that we are not in the event
|
||||
if ( time_to_event > 0 ) {
|
||||
double actual_delta_time = 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);
|
||||
// > 1 second
|
||||
if ( actual_delta_time > 1 ) {
|
||||
Debug(1, "Sending time to next event frame");
|
||||
if ( ( time_to_event > 0 ) and ( mode == MODE_ALL ) ) {
|
||||
double time_since_last_send = 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);
|
||||
if ( time_since_last_send > 1 /* second */ ) {
|
||||
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) )
|
||||
zm_terminate = true;
|
||||
} else {
|
||||
Debug(1, "Not Sending time to next event frame because actual delta time is %f", actual_delta_time);
|
||||
send_frame = false; // In case keepalive was set
|
||||
}
|
||||
//else
|
||||
//{
|
||||
|
||||
// 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 * 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
|
||||
// curr_frame_id starts at 1 though, so we might skip the first frame?
|
||||
curr_frame_id += step;
|
||||
} // end if !paused
|
||||
|
||||
// Detects when we hit end of event and will load the next event or previous event
|
||||
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",
|
||||
replay_rate, time_to_event, curr_stream_time, event_data->frames[event_data->frame_count-1].timestamp);
|
||||
} // end if forward or reverse
|
||||
|
||||
} // end if checkEventLoaded
|
||||
} // end if !paused
|
||||
} // end while ! zm_terminate
|
||||
#if HAVE_LIBAVCODEC
|
||||
if ( type == STREAM_MPEG )
|
||||
|
@ -1010,6 +1056,7 @@ void EventStream::runStream() {
|
|||
|
||||
bool EventStream::send_file(const char * filepath) {
|
||||
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
||||
int rc;
|
||||
|
||||
int img_buffer_size = 0;
|
||||
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));
|
||||
return false;
|
||||
}
|
||||
bool size_sent = false;
|
||||
|
||||
#if HAVE_SENDFILE
|
||||
static struct stat filestat;
|
||||
if ( fstat(fileno(fdj), &filestat) < 0 ) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Error("Failed getting information about file %s: %s", filepath, strerror(errno));
|
||||
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) ) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
size_sent = true;
|
||||
|
||||
if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) {
|
||||
rc = zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size);
|
||||
if ( rc == (int)filestat.st_size ) {
|
||||
// Success
|
||||
fclose(fdj); /* Close the file handle */
|
||||
return true;
|
||||
}
|
||||
Warning("Unable to send raw frame %u: %s rc %d", curr_frame_id, strerror(errno), rc);
|
||||
#endif
|
||||
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 */
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
if ( !img_buffer_size ) {
|
||||
Info("Unable to read raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(fdj); /* Close the file handle */
|
||||
return true;
|
||||
return send_buffer(img_buffer, img_buffer_size);
|
||||
} // end bool EventStream::send_file(const char * filepath)
|
||||
|
||||
bool EventStream::send_buffer(uint8_t* buffer, int size) {
|
||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", size);
|
||||
if ( fwrite(buffer, size, 1, stdout) != 1 ) {
|
||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", size) ) {
|
||||
Info("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 true;
|
||||
|
|
|
@ -54,11 +54,13 @@ class EventStream : public StreamBase {
|
|||
uint64_t event_id;
|
||||
unsigned int monitor_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 end_time;
|
||||
double duration;
|
||||
char path[PATH_MAX];
|
||||
int n_frames;
|
||||
int n_frames; // # of frame rows returned from database
|
||||
FrameData *frames;
|
||||
char video_file[PATH_MAX];
|
||||
Storage::Schemes scheme;
|
||||
|
@ -74,7 +76,7 @@ class EventStream : public StreamBase {
|
|||
StreamMode mode;
|
||||
bool forceEventChange;
|
||||
|
||||
int curr_frame_id;
|
||||
unsigned long curr_frame_id;
|
||||
double curr_stream_time;
|
||||
bool send_frame;
|
||||
struct timeval start; // clock time when started the event
|
||||
|
|
|
@ -770,6 +770,7 @@ int FfmpegCamera::CaptureAndRecord(
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ( (packet.pts != AV_NOPTS_VALUE) && (packet.pts < -100000) ) {
|
||||
// Ignore packets that have crazy negative pts.
|
||||
// They aren't supposed to happen.
|
||||
|
@ -788,6 +789,7 @@ int FfmpegCamera::CaptureAndRecord(
|
|||
}
|
||||
// If we get a good frame, decrease the error count.. We could zero it...
|
||||
if ( error_count > 0 ) error_count -= 1;
|
||||
#endif
|
||||
|
||||
int keyframe = packet.flags & AV_PKT_FLAG_KEY;
|
||||
bytes += packet.size;
|
||||
|
|
|
@ -17,7 +17,7 @@ FFmpeg_Input::~FFmpeg_Input() {
|
|||
if ( streams ) {
|
||||
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
|
||||
avcodec_close(streams[i].context);
|
||||
streams[i].context = nullptr;
|
||||
avcodec_free_context(&streams[i].context);
|
||||
}
|
||||
delete[] streams;
|
||||
streams = nullptr;
|
||||
|
@ -221,6 +221,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
|
||||
get_frame(stream_id);
|
||||
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
|
||||
|
||||
last_seek_request = seek_target;
|
||||
|
|
|
@ -1850,7 +1850,7 @@ void Image::Delta( const Image &image, Image* targetimage) const {
|
|||
#endif
|
||||
}
|
||||
|
||||
const Coord Image::centreCoord( const char *text ) const {
|
||||
const Coord Image::centreCoord( const char *text, int size=1 ) const {
|
||||
int index = 0;
|
||||
int line_no = 0;
|
||||
int text_len = strlen(text);
|
||||
|
@ -1869,8 +1869,8 @@ const Coord Image::centreCoord( const char *text ) const {
|
|||
line = text+index;
|
||||
line_no++;
|
||||
}
|
||||
int x = (width - (max_line_len * ZM_CHAR_WIDTH) ) / 2;
|
||||
int y = (height - (line_no * LINE_HEIGHT) ) / 2;
|
||||
int x = (width - (max_line_len * ZM_CHAR_WIDTH * size) ) / 2;
|
||||
int y = (height - (line_no * LINE_HEIGHT * size) ) / 2;
|
||||
return Coord(x, y);
|
||||
}
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ public:
|
|||
//Image *Delta( const Image &image ) const;
|
||||
void Delta( const Image &image, Image* targetimage) const;
|
||||
|
||||
const Coord centreCoord( const char *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 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 );
|
||||
|
|
|
@ -497,6 +497,8 @@ Monitor::Monitor(
|
|||
shared_data->last_read_time = 0;
|
||||
shared_data->alarm_x = -1;
|
||||
shared_data->alarm_y = -1;
|
||||
} else {
|
||||
shared_data = nullptr;
|
||||
}
|
||||
|
||||
start_time = last_fps_time = time( 0 );
|
||||
|
@ -1448,18 +1450,19 @@ bool Monitor::Analyse() {
|
|||
int new_motion_score = DetectMotion(*snap_image, zoneSet);
|
||||
|
||||
Debug(3,
|
||||
"After motion detection, last_motion_score(%d), new motion score(%d)",
|
||||
last_motion_score, new_motion_score
|
||||
"After motion detection, score(%d), last_motion_score(%d), new motion score(%d)",
|
||||
score, last_motion_score, new_motion_score
|
||||
);
|
||||
last_motion_score = new_motion_score;
|
||||
}
|
||||
if ( last_motion_score ) {
|
||||
score += last_motion_score;
|
||||
if ( !event ) {
|
||||
// cause is calculated every frame,
|
||||
//if ( !event ) {
|
||||
if ( cause.length() )
|
||||
cause += ", ";
|
||||
cause += MOTION_CAUSE;
|
||||
}
|
||||
//}
|
||||
noteSetMap[MOTION_CAUSE] = zoneSet;
|
||||
} // end if motion_score
|
||||
//shared_data->active = signal; // unneccessary active gets set on signal change
|
||||
|
@ -1559,7 +1562,7 @@ bool Monitor::Analyse() {
|
|||
alarm_cause = alarm_cause + "," + std::string(zones[i]->Label());
|
||||
}
|
||||
}
|
||||
if ( !alarm_cause.empty() ) alarm_cause[0] = ' ';
|
||||
if ( !alarm_cause.empty() ) alarm_cause[0] = ' '; // replace leading , with a space
|
||||
alarm_cause = cause + alarm_cause;
|
||||
strncpy(shared_data->alarm_cause, alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1);
|
||||
Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s",
|
||||
|
@ -1631,6 +1634,13 @@ bool Monitor::Analyse() {
|
|||
}
|
||||
}
|
||||
event->AddFrames(pre_event_images, images, timestamps);
|
||||
} else if ( alarm_frame_count > 1 ) {
|
||||
int temp_alarm_frame_count = alarm_frame_count;
|
||||
while ( --temp_alarm_frame_count ) {
|
||||
Debug(1, "Adding previous frame due to alarm_frame_count %d", pre_index);
|
||||
event->AddFrame(image_buffer[pre_index].image, *image_buffer[pre_index].timestamp, 0, nullptr);
|
||||
pre_index = (pre_index + 1)%image_buffer_count;
|
||||
}
|
||||
} // end if pre_event_images
|
||||
|
||||
if ( ( alarm_frame_count > 1 ) && Event::PreAlarmCount() ) {
|
||||
|
@ -1668,6 +1678,8 @@ bool Monitor::Analyse() {
|
|||
} else {
|
||||
shared_data->state = state = 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);
|
||||
}
|
||||
} // end if ALARM or ALERT
|
||||
|
||||
|
@ -2108,7 +2120,6 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) {
|
|||
} else {
|
||||
v4l_captures_per_frame = config.captures_per_frame;
|
||||
}
|
||||
Debug(1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame);
|
||||
col++;
|
||||
|
||||
std::string protocol = dbrow[col] ? dbrow[col] : ""; col++;
|
||||
|
@ -2398,10 +2409,13 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) {
|
|||
0
|
||||
);
|
||||
camera->setMonitor(monitor);
|
||||
int n_zones = 0;
|
||||
if ( load_zones ) {
|
||||
Zone **zones = 0;
|
||||
int n_zones = Zone::Load(monitor, zones);
|
||||
n_zones = Zone::Load(monitor, zones);
|
||||
monitor->AddZones(n_zones, zones);
|
||||
monitor->AddPrivacyBitmask(zones);
|
||||
}
|
||||
Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones);
|
||||
return monitor;
|
||||
} // end Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose)
|
||||
|
|
|
@ -505,6 +505,8 @@ public:
|
|||
inline time_t getStartupTime() const { return shared_data->startup_time; }
|
||||
inline void setStartupTime( time_t p_time ) { shared_data->startup_time = p_time; }
|
||||
|
||||
int LabelSize() { return label_size; }
|
||||
|
||||
void actionReload();
|
||||
void actionEnable();
|
||||
void actionDisable();
|
||||
|
|
|
@ -39,7 +39,7 @@ StreamBase::~StreamBase() {
|
|||
closeComms();
|
||||
if ( 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);
|
||||
|
||||
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 ) {
|
||||
image.Scale(scale);
|
||||
|
|
|
@ -116,7 +116,7 @@ protected:
|
|||
public:
|
||||
StreamBase():
|
||||
monitor_id(0),
|
||||
monitor(0),
|
||||
monitor(nullptr),
|
||||
type(DEFAULT_TYPE),
|
||||
format(""),
|
||||
replay_rate(DEFAULT_RATE),
|
||||
|
|
|
@ -229,63 +229,31 @@ void hwcaps_detect() {
|
|||
neonversion = 0;
|
||||
sse_version = 0;
|
||||
#if (defined(__i386__) || defined(__x86_64__))
|
||||
/* x86 or x86-64 processor */
|
||||
uint32_t r_edx, r_ecx, r_ebx;
|
||||
__builtin_cpu_init();
|
||||
|
||||
#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 */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with SSE");
|
||||
} else {
|
||||
|
|
|
@ -126,6 +126,7 @@ void Zone::Setup(
|
|||
|
||||
Zone::~Zone() {
|
||||
delete[] label;
|
||||
if ( image )
|
||||
delete image;
|
||||
delete pg_image;
|
||||
delete[] ranges;
|
||||
|
@ -158,6 +159,7 @@ void Zone::SetScore(unsigned int nScore) {
|
|||
} // end void Zone::SetScore(unsigned int nScore)
|
||||
|
||||
void Zone::SetAlarmImage(const Image* srcImage) {
|
||||
if ( image )
|
||||
delete image;
|
||||
image = new Image(*srcImage);
|
||||
} // end void Zone::SetAlarmImage( const Image* srcImage )
|
||||
|
@ -205,6 +207,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( image )
|
||||
delete image;
|
||||
// Get the difference 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
|
||||
delete diff_image;
|
||||
} else {
|
||||
delete image;
|
||||
image = 0;
|
||||
}
|
||||
diff_image = nullptr;
|
||||
} // end if ( (type < PRECLUSIVE) && (check_method >= BLOBS) && (monitor->GetOptSaveJPEGs() > 1)
|
||||
|
||||
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);
|
||||
}
|
||||
} // end if score
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ function probe( &$url_bits ) {
|
|||
|
||||
$cam_list_html = file_get_contents('http://'.$url_bits['host'].':5000/monitoring/');
|
||||
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(
|
||||
'/<a href="http:\/\/([.[:digit:]]+):([[:digit:]]+)\/\?action=stream" target="_blank">([^<]+)<\/a>/',
|
||||
$cam_list_html, $cam_list );
|
||||
ZM\Logger::Debug(print_r($cam_list,true));
|
||||
ZM\Debug(print_r($cam_list,true));
|
||||
}
|
||||
if ( $matches_count ) {
|
||||
for( $index = 0; $index < $matches_count; $index ++ ) {
|
||||
|
@ -33,7 +33,7 @@ function probe( &$url_bits ) {
|
|||
if ( ! isset($new_stream['scheme'] ) )
|
||||
$new_stream['scheme'] = 'http';
|
||||
$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 {
|
||||
ZM\Info('No matches');
|
||||
|
|
|
@ -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
|
||||
ini_set('display_errors', '0');
|
||||
|
||||
if ( empty($_REQUEST['eids']) ) {
|
||||
ajaxError('No event id(s) supplied');
|
||||
$message = '';
|
||||
$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') ) {
|
||||
} // end if canView('Events')
|
||||
if ( empty($_REQUEST['eids']) ) {
|
||||
if ( isset($_REQUEST['task']) && $_REQUEST['task'] != "query" ) $message = 'No event id(s) supplied';
|
||||
} else {
|
||||
$eids = $_REQUEST['eids'];
|
||||
}
|
||||
|
||||
if ( canEdit('Events') ) {
|
||||
$message = array();
|
||||
if ( $message ) {
|
||||
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 '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(
|
||||
'UPDATE Events SET Archived = ? WHERE Id = ?',
|
||||
array($archiveVal, $eid)
|
||||
);
|
||||
break;
|
||||
case 'delete' :
|
||||
}
|
||||
|
||||
function deleteRequest($eid) {
|
||||
$message = array();
|
||||
$event = new ZM\Event($eid);
|
||||
if ( !$event->Id() ) {
|
||||
$message[] = array($eid=>'Event not found.');
|
||||
|
@ -31,11 +110,105 @@ if ( canEdit('Events') ) {
|
|||
} else {
|
||||
$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;
|
||||
}
|
||||
?>
|
||||
|
|
542
web/ajax/log.php
542
web/ajax/log.php
|
@ -1,111 +1,112 @@
|
|||
<?php
|
||||
ini_set('display_errors', '0');
|
||||
global $Servers;
|
||||
|
||||
# Moved up here because it is used in several spots.
|
||||
# These are the valid columns that you can filter on.
|
||||
$filterFields = array('Component', 'ServerId', 'Pid', 'Level', 'File', 'Line');
|
||||
if ( !canView('System') ) {
|
||||
ajaxError('Insufficient permissions to view log entries');
|
||||
return;
|
||||
}
|
||||
|
||||
function buildLogQuery($action) {
|
||||
global $filterFields;
|
||||
// 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';
|
||||
|
||||
$minTime = isset($_REQUEST['minTime']) ? $_REQUEST['minTime'] : NULL;
|
||||
$maxTime = isset($_REQUEST['maxTime']) ? $_REQUEST['maxTime'] : NULL;
|
||||
// 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_integer($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
||||
ZM\Error('Invalid value for limit ' . $_REQUEST['limit']);
|
||||
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) {
|
||||
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
|
||||
} else {
|
||||
$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';
|
||||
$where = array();
|
||||
$values = array();
|
||||
if ( $minTime ) {
|
||||
$where[] = 'TimeKey > ?';
|
||||
$values[] = $minTime;
|
||||
} elseif ( $maxTime ) {
|
||||
$where[] = 'TimeKey < ?';
|
||||
$values[] = $maxTime;
|
||||
}
|
||||
$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 ( $filter as $field=>$value ) {
|
||||
if ( !in_array($field, $filterFields) ) {
|
||||
ZM\Error("'$field' is not in valid filter fields " . print_r($filterField, true));
|
||||
foreach ( $advsearch as $col=>$text ) {
|
||||
if ( !in_array($col, array_merge($columns, $col_alt)) ) {
|
||||
ZM\Error("'$col' is not a sortable column name");
|
||||
continue;
|
||||
}
|
||||
if ( $field == 'Level' ) {
|
||||
$where[] = $field.' <= ?';
|
||||
$values[] = $value;
|
||||
$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 {
|
||||
$where[] = $field.' = ?';
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
if ( count($where) )
|
||||
$sql.= ' WHERE '.join(' AND ', $where);
|
||||
$sql .= ' ORDER BY '.$sortField.' '.$sortOrder.' LIMIT '.$limit;
|
||||
|
||||
return array('sql'=>$sql, 'values'=>$values);
|
||||
} # function buildLogQuery($action)
|
||||
|
||||
switch ( $_REQUEST['task'] ) {
|
||||
case 'create' :
|
||||
{
|
||||
// Silently ignore bogus requests
|
||||
if ( !empty($_POST['level']) && !empty($_POST['message']) ) {
|
||||
ZM\logInit(array('id'=>'web_js'));
|
||||
|
||||
$string = $_POST['message'];
|
||||
|
||||
$file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : '';
|
||||
if ( !empty($_POST['line']) ) {
|
||||
$line = validInt($_POST['line']);
|
||||
} else {
|
||||
$line = NULL;
|
||||
$data['total'] = $data['totalNotFiltered'];
|
||||
}
|
||||
|
||||
$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_by_Id = array();
|
||||
|
@ -114,353 +115,18 @@ switch ( $_REQUEST['task'] ) {
|
|||
$servers_by_Id[$server->Id()] = $server;
|
||||
}
|
||||
|
||||
$logs = array();
|
||||
$options = array();
|
||||
$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);
|
||||
|
||||
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']);
|
||||
$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
|
||||
ob_start();
|
||||
@$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>
|
|
@ -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>
|
|
@ -30,14 +30,73 @@ global $CLANG;
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<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 class="modal-footer">
|
||||
<form name="logoutForm" id="logoutForm" method="post" action="?">
|
||||
<form name="logoutForm" id="logoutForm" method="post" action="?view=logout">
|
||||
<?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="logout"/>
|
||||
<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; ?>
|
||||
<button type="button" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
|
||||
|
|
|
@ -1,27 +1,6 @@
|
|||
<?php
|
||||
//
|
||||
// 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') ) return;
|
||||
|
||||
if ( !canView('Control') ) {
|
||||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
$monitor = ZM\Monitor::find_one(array('Id'=>$_REQUEST['mid']));
|
||||
|
||||
$zmuCommand = getZmuCommand(' -m '.escapeshellarg($_REQUEST['mid']).' -B -C -H -O');
|
||||
|
@ -35,17 +14,22 @@ if ( $zmuOutput ) {
|
|||
$monitor->Colour($colour);
|
||||
}
|
||||
|
||||
$focusWindow = true;
|
||||
|
||||
xhtmlHeaders(__FILE__, validHtmlStr($monitor->Name()).' - '.translate('Settings'));
|
||||
?>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="header">
|
||||
<h2><?php echo validHtmlStr($monitor->Name()) ?> - <?php echo translate('Settings') ?></h2>
|
||||
<div class="modal" id="settingsModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<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 id="content">
|
||||
<form name="contentForm" id="contentForm" method="post" action="?">
|
||||
<div class="modal-body">
|
||||
<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="action" value="settings"/>
|
||||
<input type="hidden" name="mid" value="<?php echo validInt($_REQUEST['mid']) ?>"/>
|
||||
|
@ -69,11 +53,12 @@ xhtmlHeaders(__FILE__, validHtmlStr($monitor->Name()).' - '.translate('Settings'
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="contentButtons">
|
||||
<button type="submit" value="Save"<?php echo canView('Control') ? '' : ' disabled="disabled"' ?>><?php echo translate('Save') ?></button>
|
||||
<button type="button" value="Close" data-on-click="closeWindow"/><?php echo translate('Close') ?></button>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<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>
|
||||
</form>
|
||||
</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;
|
||||
}
|
||||
|
||||
|
@ -411,55 +411,64 @@ function getNearEvents() {
|
|||
global $user, $sortColumn, $sortOrder;
|
||||
|
||||
$eventId = $_REQUEST['id'];
|
||||
$NearEvents = array( 'EventId'=>$eventId );
|
||||
|
||||
$event = dbFetchOne('SELECT * FROM Events WHERE Id=?', NULL, array($eventId));
|
||||
if ( !$event ) return $NearEvents;
|
||||
|
||||
parseFilter($_REQUEST['filter']);
|
||||
$filter = ZM\Filter::parse($_REQUEST['filter']);
|
||||
parseSort();
|
||||
|
||||
if ( $user['MonitorIds'] )
|
||||
$midSql = ' AND MonitorId IN ('.join( ',', preg_split( '/["\'\s]*,["\'\s]*/', $user['MonitorIds'] ) ).')';
|
||||
else
|
||||
$midSql = '';
|
||||
if ( $user['MonitorIds'] ) {
|
||||
$filter = $filter->addTerm(array('cnj'=>'and', 'attr'=>'MonitorId', 'op'=>'IN', 'val'=>$user['MonitorIds']));
|
||||
}
|
||||
|
||||
# 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' ) {
|
||||
$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']].'\' AND ('.$filter->sql().') AND E.Id<'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'DESC':'ASC');
|
||||
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
|
||||
$sql .= ', E.Id DESC';
|
||||
}
|
||||
$sql .= ' LIMIT 1';
|
||||
$result = dbQuery($sql);
|
||||
if ( !$result ) {
|
||||
ZM\Error("Failed to load previous event using $sql");
|
||||
return $NearEvents;
|
||||
}
|
||||
|
||||
$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']]."' AND (".$filter->sql().') AND E.Id>'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'ASC':'DESC');
|
||||
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
|
||||
$sql .= ', E.Id ASC';
|
||||
}
|
||||
$sql .= ' LIMIT 1';
|
||||
$result = dbQuery($sql);
|
||||
if ( !$result ) {
|
||||
ZM\Error("Failed to load next event using $sql");
|
||||
return $NearEvents;
|
||||
}
|
||||
$nextEvent = dbFetchNext($result);
|
||||
|
||||
$result = array( 'EventId'=>$eventId );
|
||||
if ( $prevEvent ) {
|
||||
$result['PrevEventId'] = $prevEvent['Id'];
|
||||
$result['PrevEventStartTime'] = $prevEvent['StartTime'];
|
||||
$result['PrevEventDefVideoPath'] = getEventDefaultVideoPath($prevEvent['Id']);
|
||||
$NearEvents['PrevEventId'] = $prevEvent['Id'];
|
||||
$NearEvents['PrevEventStartTime'] = $prevEvent['StartTime'];
|
||||
$NearEvents['PrevEventDefVideoPath'] = getEventDefaultVideoPath($prevEvent['Id']);
|
||||
} else {
|
||||
$result['PrevEventId'] = $result['PrevEventStartTime'] = $result['PrevEventDefVideoPath'] = 0;
|
||||
$NearEvents['PrevEventId'] = $NearEvents['PrevEventStartTime'] = $NearEvents['PrevEventDefVideoPath'] = 0;
|
||||
}
|
||||
if ( $nextEvent ) {
|
||||
$result['NextEventId'] = $nextEvent['Id'];
|
||||
$result['NextEventStartTime'] = $nextEvent['StartTime'];
|
||||
$result['NextEventDefVideoPath'] = getEventDefaultVideoPath($nextEvent['Id']);
|
||||
$NearEvents['NextEventId'] = $nextEvent['Id'];
|
||||
$NearEvents['NextEventStartTime'] = $nextEvent['StartTime'];
|
||||
$NearEvents['NextEventDefVideoPath'] = getEventDefaultVideoPath($nextEvent['Id']);
|
||||
} 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'] ) {
|
||||
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);
|
||||
break;
|
||||
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']);
|
||||
break;
|
||||
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']);
|
||||
break;
|
||||
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']);
|
||||
break;
|
||||
case CMD_SEEK :
|
||||
ZM\Logger::Debug('Seeking to '.$_REQUEST['offset']);
|
||||
$msg = pack('lcN', MSG_CMD, $_REQUEST['command'], $_REQUEST['offset']);
|
||||
# Pack int two 32 bit integers instead of trying to deal with floats
|
||||
$msg = pack('lcNN', MSG_CMD, $_REQUEST['command'],
|
||||
intval($_REQUEST['offset']),
|
||||
1000000*( $_REQUEST['offset']-intval($_REQUEST['offset'])));
|
||||
break;
|
||||
default :
|
||||
ZM\Logger::Debug('Sending command ' . $_REQUEST['command']);
|
||||
ZM\Debug('Sending command ' . $_REQUEST['command']);
|
||||
$msg = pack('lc', MSG_CMD, $_REQUEST['command']);
|
||||
break;
|
||||
}
|
||||
|
@ -65,7 +67,7 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
|||
// WHY? We will just send another one...
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -124,20 +126,20 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
|||
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
|
||||
if ( isset($_REQUEST['auth']) and ($_REQUEST['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 {
|
||||
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));
|
||||
break;
|
||||
case MSG_DATA_EVENT :
|
||||
if ( version_compare( phpversion(), '5.6.0', '<') ) {
|
||||
ZM\Logger::Debug('Using old unpack methods to handle 64bit event id');
|
||||
$data = unpack('ltype/ieventlow/ieventhigh/iprogress/irate/izoom/Cpaused', $msg);
|
||||
ZM\Debug('Using old unpack methods to handle 64bit event id');
|
||||
$data = unpack('ltype/ieventlow/ieventhigh/dduration/dprogress/irate/izoom/Cpaused', $msg);
|
||||
$data['event'] = $data['eventhigh'] << 32 | $data['eventlow'];
|
||||
} 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['zoom'] = round($data['zoom']/SCALE_BASE, 1);
|
||||
|
@ -154,7 +156,7 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
|||
}
|
||||
sem_release($semaphore);
|
||||
} else {
|
||||
ZM\Logger::Debug('Couldn\'t get semaphore');
|
||||
ZM\Debug('Couldn\'t get semaphore');
|
||||
ajaxResponse(array());
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ class AppController extends Controller {
|
|||
if ( ! is_session_started() )
|
||||
zm_session_start();
|
||||
|
||||
ZM\Logger::Debug(print_r($_SESSION, true));
|
||||
ZM\Debug(print_r($_SESSION, true));
|
||||
$user = userFromSession();
|
||||
session_write_close();
|
||||
}
|
||||
|
|
|
@ -50,10 +50,10 @@ class HostController extends AppController {
|
|||
$cred_depr = [];
|
||||
|
||||
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
|
||||
} else {
|
||||
ZM\Logger::Debug('Only generating access token');
|
||||
ZM\Debug('Only generating access token');
|
||||
$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['append_password'] = $cred_depr[1];
|
||||
} 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];
|
||||
|
@ -203,7 +203,7 @@ class HostController extends AppController {
|
|||
|
||||
if ( $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}'");
|
||||
} else {
|
||||
$monitors = $this->Monitor->find('all', array(
|
||||
|
|
|
@ -178,7 +178,7 @@ class MonitorsController extends AppController {
|
|||
)
|
||||
) {
|
||||
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');
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ class MonitorsController extends AppController {
|
|||
}
|
||||
|
||||
$shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
|
||||
ZM\Logger::Debug("Command $shellcmd");
|
||||
ZM\Debug("Command $shellcmd");
|
||||
$status = exec($shellcmd);
|
||||
$status_text .= $status."\n";
|
||||
}
|
||||
|
|
|
@ -133,10 +133,10 @@ class Event extends AppModel {
|
|||
if ( file_exists($this->Path().'/'.$event['DefaultVideo']) ) {
|
||||
return 1;
|
||||
} 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 {
|
||||
ZM\Logger::Debug('No DefaultVideo in Event' . $this->Event);
|
||||
ZM\Debug('No DefaultVideo in Event' . $this->Event);
|
||||
return 0;
|
||||
}
|
||||
} // 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)
|
||||
*
|
||||
* @version v1.18.0
|
||||
* @version v1.17.1
|
||||
* @homepage https://bootstrap-table.com
|
||||
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
||||
* @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)
|
||||
*
|
||||
* @version v1.18.0
|
||||
* @version v1.17.1
|
||||
* @homepage https://bootstrap-table.com
|
||||
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
||||
* @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 snapshot image will be generated during capturing
|
||||
if ( file_exists($this->Path().'/snapshot.jpg') ) {
|
||||
Logger::Debug("snapshot exists");
|
||||
Debug("snapshot exists");
|
||||
$frame = null;
|
||||
} else {
|
||||
# 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) ) {
|
||||
# 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);
|
||||
}
|
||||
|
||||
if ( ( !$frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
|
||||
# No frame specified, so look for a snapshot to use
|
||||
$captImage = 'snapshot.jpg';
|
||||
Logger::Debug('Frame not specified, using snapshot');
|
||||
Debug('Frame not specified, using snapshot');
|
||||
$frame = array('FrameId'=>'snapshot', 'Type'=>'', 'Delta'=>0);
|
||||
} else {
|
||||
$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 -ss '. $frame['Delta'] .' -i '.$videoPath.' -frames:v 1 '.$eventPath.'/'.$captImage;
|
||||
Logger::Debug('Running '.$command);
|
||||
Debug('Running '.$command);
|
||||
$output = array();
|
||||
$retval = 0;
|
||||
exec($command, $output, $retval);
|
||||
Logger::Debug("Retval: $retval, output: " . implode("\n", $output));
|
||||
Debug("Retval: $retval, output: " . implode("\n", $output));
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
Logger::Debug("sending command to $url");
|
||||
Debug("sending command to $url");
|
||||
// use key 'http' even if you send the request to https://...
|
||||
$options = array(
|
||||
'http' => array(
|
||||
|
@ -545,7 +545,7 @@ class Event extends ZM_Object {
|
|||
Error("Error restarting zmc using $url");
|
||||
}
|
||||
$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'];
|
||||
} catch ( Exception $e ) {
|
||||
Error("Except $e thrown trying to get event data");
|
||||
|
@ -577,7 +577,7 @@ class Event extends ZM_Object {
|
|||
return;
|
||||
}
|
||||
}
|
||||
Logger::Debug("sending command to $url");
|
||||
Debug("sending command to $url");
|
||||
// use key 'http' even if you send the request to https://...
|
||||
$options = array(
|
||||
'http' => array(
|
||||
|
@ -593,7 +593,7 @@ class Event extends ZM_Object {
|
|||
Error("Error restarting zmc using $url");
|
||||
}
|
||||
$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'];
|
||||
} catch ( Exception $e ) {
|
||||
Error("Except $e thrown trying to get event data");
|
||||
|
|
|
@ -16,6 +16,7 @@ class Filter extends ZM_Object {
|
|||
'EmailBody' => '',
|
||||
'AutoDelete' => 0,
|
||||
'AutoArchive' => 0,
|
||||
'AutoUnarchive' => 0,
|
||||
'AutoVideo' => 0,
|
||||
'AutoUpload' => 0,
|
||||
'AutoMessage' => 0,
|
||||
|
@ -39,6 +40,7 @@ class Filter extends ZM_Object {
|
|||
|
||||
public function sql() {
|
||||
if ( ! isset($this->_sql) ) {
|
||||
$this->_sql = '';
|
||||
foreach ( $this->FilterTerms() as $term ) {
|
||||
#if ( ! ($term->is_pre_sql() or $term->is_post_sql()) ) {
|
||||
$this->_sql .= $term->sql();
|
||||
|
@ -52,15 +54,20 @@ class Filter extends ZM_Object {
|
|||
|
||||
public function querystring($separator='&') {
|
||||
if ( (! isset($this->_querystring)) or ( $separator != '&' ) ) {
|
||||
$this->_querystring = '';
|
||||
foreach ( $this->FilterTerms() as $term ) {
|
||||
$this->_querystring .= $term->querystring($separator);
|
||||
} # end foreach term
|
||||
if ( $this->Id() ) {
|
||||
$this->_querystring .= $separator.'filter[Id]='.$this->Id();
|
||||
}
|
||||
}
|
||||
return $this->_querystring;
|
||||
}
|
||||
|
||||
public function hidden_fields() {
|
||||
if ( ! isset($this->_hidden_fields) ) {
|
||||
$this->_hidden_fields = '';
|
||||
foreach ( $this->FilterTerms() as $term ) {
|
||||
$this->_hidden_fields .= $term->hidden_fields();
|
||||
} # end foreach term
|
||||
|
@ -137,6 +144,13 @@ class Filter extends ZM_Object {
|
|||
if ( func_num_args( ) ) {
|
||||
$this->{'Query'} = func_get_arg(0);
|
||||
$this->{'Query_json'} = jsonEncode($this->{'Query'});
|
||||
# We have altered the query so need to reset all the calculated results.
|
||||
unset($this->_querystring);
|
||||
unset($this->_sql);
|
||||
unset($this->_hidden_fields);
|
||||
unset($this->_pre_sql_conditions);
|
||||
unset($this->_post_sql_conditions);
|
||||
unset($this->_Terms);
|
||||
}
|
||||
if ( !property_exists($this, 'Query') ) {
|
||||
if ( property_exists($this, 'Query_json') and $this->{'Query_json'} ) {
|
||||
|
@ -226,7 +240,7 @@ class Filter extends ZM_Object {
|
|||
|
||||
if ( (!defined('ZM_SERVER_ID')) or (!$Server->Id()) or (ZM_SERVER_ID==$Server->Id()) ) {
|
||||
# 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');
|
||||
} else {
|
||||
# Remote case
|
||||
|
@ -243,7 +257,7 @@ class Filter extends ZM_Object {
|
|||
}
|
||||
}
|
||||
$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();
|
||||
if ( defined('ZM_ENABLE_CSRF_MAGIC') ) {
|
||||
require_once( 'includes/csrf/csrf-magic.php' );
|
||||
|
@ -274,7 +288,7 @@ class Filter extends ZM_Object {
|
|||
public function execute() {
|
||||
$command = ZM_PATH_BIN.'/zmfilter.pl --filter_id='.escapeshellarg($this->Id());
|
||||
$result = exec($command, $output, $status);
|
||||
Logger::Debug("$command status:$status output:".implode("\n", $output));
|
||||
Debug("$command status:$status output:".implode("\n", $output));
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
@ -615,6 +629,25 @@ class Filter extends ZM_Object {
|
|||
return array_pop($exprStack);
|
||||
} # end function tree
|
||||
|
||||
} # end class Filter
|
||||
function addTerm($term=false, $position=null) {
|
||||
|
||||
$terms = $this->terms();
|
||||
|
||||
if ( (!isset($position)) or ($position > count($terms)) )
|
||||
$position = count($terms);
|
||||
else if ( $position < 0 )
|
||||
$position = 0;
|
||||
|
||||
if ( $term && ($position == 0) ) {
|
||||
# if only 1 term, don't need AND or OR
|
||||
unset($term['cnj']);
|
||||
}
|
||||
|
||||
array_splice($terms, $position, 0, array($term ? $term : array()));
|
||||
$this->terms($terms);
|
||||
|
||||
return $this;
|
||||
} # end function addTerm
|
||||
|
||||
} # end class Filter
|
||||
?>
|
||||
|
|
|
@ -185,7 +185,7 @@ class FilterTerm {
|
|||
}
|
||||
return ' IS NOT ';
|
||||
default:
|
||||
ZM\Warning('Invalid operator in filter: ' . print_r($this->op, true));
|
||||
Warning('Invalid operator in filter: ' . print_r($this->op, true));
|
||||
} // end switch op
|
||||
} # end public function sql_operator
|
||||
|
||||
|
@ -329,14 +329,14 @@ class FilterTerm {
|
|||
public function test($event=null) {
|
||||
if ( !isset($event) ) {
|
||||
# Is a Pre Condition
|
||||
Logger::Debug("Testing " . $this->attr);
|
||||
Debug("Testing " . $this->attr);
|
||||
if ( $this->attr == 'DiskPercent' ) {
|
||||
# The logic on this is really ugly. We are going to treat it as an OR
|
||||
foreach ( $this->filter->get_StorageAreas() as $storage ) {
|
||||
$string_to_eval = 'return $storage->disk_usage_percent() '.$this->op.' '.$this->val.';';
|
||||
try {
|
||||
$ret = eval($string_to_eval);
|
||||
Logger::Debug("Evalled $string_to_eval = $ret");
|
||||
Debug("Evalled $string_to_eval = $ret");
|
||||
if ( $ret )
|
||||
return true;
|
||||
} catch ( Throwable $t ) {
|
||||
|
@ -348,7 +348,7 @@ class FilterTerm {
|
|||
$string_to_eval = 'return getLoad() '.$this->op.' '.$this->val.';';
|
||||
try {
|
||||
$ret = eval($string_to_eval);
|
||||
Logger::Debug("Evaled $string_to_eval = $ret");
|
||||
Debug("Evaled $string_to_eval = $ret");
|
||||
if ( $ret )
|
||||
return true;
|
||||
} catch ( Throwable $t ) {
|
||||
|
@ -374,7 +374,7 @@ class FilterTerm {
|
|||
$string_to_eval = 'return $event->Storage()->disk_usage_percent() '.$this->op.' '.$this->val.';';
|
||||
try {
|
||||
$ret = eval($string_to_eval);
|
||||
Logger::Debug("Evalled $string_to_eval = $ret");
|
||||
Debug("Evalled $string_to_eval = $ret");
|
||||
if ( $ret )
|
||||
return true;
|
||||
} catch ( Throwable $t ) {
|
||||
|
@ -385,7 +385,7 @@ class FilterTerm {
|
|||
$string_to_eval = 'return $event->Storage()->disk_usage_blocks() '.$this->op.' '.$this->val.';';
|
||||
try {
|
||||
$ret = eval($string_to_eval);
|
||||
Logger::Debug("Evalled $string_to_eval = $ret");
|
||||
Debug("Evalled $string_to_eval = $ret");
|
||||
if ( $ret )
|
||||
return true;
|
||||
} catch ( Throwable $t ) {
|
||||
|
|
|
@ -181,7 +181,7 @@ class Monitor extends ZM_Object {
|
|||
FROM `Monitor_Status` WHERE `MonitorId`=?';
|
||||
$row = dbFetchOne($sql, NULL, array($this->{'Id'}));
|
||||
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 ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
|
@ -293,7 +293,7 @@ class Monitor extends ZM_Object {
|
|||
}
|
||||
|
||||
function zmcControl( $mode=false ) {
|
||||
if ( ! $this->{'Id'} ) {
|
||||
if ( !(property_exists($this,'Id') and $this->{'Id'}) ) {
|
||||
Warning('Attempt to control a monitor with no Id');
|
||||
return;
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ class Monitor extends ZM_Object {
|
|||
return;
|
||||
}
|
||||
}
|
||||
Logger::Debug('sending command to '.$url);
|
||||
Debug('sending command to '.$url);
|
||||
|
||||
$context = stream_context_create();
|
||||
try {
|
||||
|
@ -346,7 +346,7 @@ class Monitor extends ZM_Object {
|
|||
} // end function zmcControl
|
||||
|
||||
function zmaControl($mode=false) {
|
||||
if ( !$this->{'Id'} ) {
|
||||
if ( ! (property_exists($this, 'Id') and $this->{'Id'}) ) {
|
||||
Warning('Attempt to control a monitor with no Id');
|
||||
return;
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ class Monitor extends ZM_Object {
|
|||
return;
|
||||
}
|
||||
}
|
||||
Logger::Debug("sending command to $url");
|
||||
Debug("sending command to $url");
|
||||
|
||||
$context = stream_context_create();
|
||||
try {
|
||||
|
@ -538,7 +538,7 @@ class Monitor extends ZM_Object {
|
|||
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) {
|
||||
# These are special as we now run zmcontrol as a daemon through zmdc.
|
||||
$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'}) ) ) ) {
|
||||
daemonControl($command, 'zmcontrol.pl', '--id '.$this->{'Id'});
|
||||
return;
|
||||
|
@ -552,10 +552,10 @@ class Monitor extends ZM_Object {
|
|||
|
||||
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) {
|
||||
# Local
|
||||
Logger::Debug('Trying to send options ' . print_r($options, true));
|
||||
Debug('Trying to send options ' . print_r($options, true));
|
||||
|
||||
$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.
|
||||
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
|
||||
if ( $socket < 0 ) {
|
||||
|
@ -589,7 +589,7 @@ class Monitor extends ZM_Object {
|
|||
$url .= '?user='.$_SESSION['username'];
|
||||
}
|
||||
}
|
||||
Logger::Debug("sending command to $url");
|
||||
Debug("sending command to $url");
|
||||
|
||||
$context = stream_context_create();
|
||||
try {
|
||||
|
|
|
@ -94,7 +94,7 @@ class Storage extends ZM_Object {
|
|||
}
|
||||
$used = $this->disk_used_space();
|
||||
$usage = round(($used / $total) * 100);
|
||||
//Logger::Debug("Used $usage = round( ( $used / $total ) * 100 )");
|
||||
//Debug("Used $usage = round( ( $used / $total ) * 100 )");
|
||||
return $usage;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,6 @@ if ( $action == 'control' ) {
|
|||
|
||||
$ctrlCommand = buildControlCommand($monitor);
|
||||
$monitor->sendControlCommand($ctrlCommand);
|
||||
$view = 'none';
|
||||
$redirect = $_SERVER['HTTP_REFERER'];
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -28,15 +28,15 @@ if ( $action == 'device' ) {
|
|||
if ( !empty($_REQUEST['command']) ) {
|
||||
setDeviceStatusX10($_REQUEST['key'], $_REQUEST['command']);
|
||||
} else if ( isset($_REQUEST['newDevice']) ) {
|
||||
if ( isset($_REQUEST['did']) ) {
|
||||
if ( isset($_REQUEST['did']) && $_REQUEST['did'] ) {
|
||||
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']) );
|
||||
}
|
||||
$refreshParent = true;
|
||||
$view = 'none';
|
||||
$redirect = '?view=devices';
|
||||
}
|
||||
} else {
|
||||
ZM\Error('Unknown action in device');
|
||||
|
|
|
@ -32,7 +32,7 @@ if ( !canEdit('Events') ) {
|
|||
if ( $action == 'archive' ) {
|
||||
$dbConn->beginTransaction();
|
||||
$eids = getAffectedIds('eids');
|
||||
ZM\Logger::Debug("E IDS" . print_r($eids, true));
|
||||
ZM\Debug("E IDS" . print_r($eids, true));
|
||||
foreach ( $eids as $markEid ) {
|
||||
dbQuery('UPDATE Events SET Archived=? WHERE Id=?', array(1, $markEid));
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ if ( $action == 'archive' ) {
|
|||
} else if ( $action == 'unarchive' ) {
|
||||
$dbConn->beginTransaction();
|
||||
$eids = getAffectedIds('eids');
|
||||
ZM\Logger::Debug("E IDS" . print_r($eids, true));
|
||||
ZM\Debug("E IDS" . print_r($eids, true));
|
||||
foreach ( $eids as $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']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1;
|
||||
$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 ( $filter->Background() )
|
||||
|
|
|
@ -32,7 +32,7 @@ if ( !canEdit('Monitors', $mid) ) {
|
|||
|
||||
if ( $action == 'function' ) {
|
||||
$monitor = new ZM\Monitor($mid);
|
||||
if ( !$monitor ) {
|
||||
if ( !$monitor->Id() ) {
|
||||
ZM\Error("Monitor not found with Id=$mid");
|
||||
return;
|
||||
}
|
||||
|
@ -46,14 +46,14 @@ if ( $action == 'function' ) {
|
|||
$monitor->save(array('Function'=>$newFunction, 'Enabled'=>$newEnabled));
|
||||
|
||||
if ( daemonCheck() && ($monitor->Type() != 'WebSite') ) {
|
||||
zmaControl($monitor, 'stop');
|
||||
zmcControl($monitor, ($newFunction != 'None') ? 'restart' : 'stop');
|
||||
$monitor->zmaControl('stop');
|
||||
$monitor->zmcControl(($newFunction != 'None') ? 'restart' : 'stop');
|
||||
if ( $newFunction != 'None' && $newFunction != 'NoDect' )
|
||||
zmaControl($monitor, 'start');
|
||||
$monitor->zmaControl('start');
|
||||
}
|
||||
} else {
|
||||
ZM\Logger::Debug('No change to function, not doing anything.');
|
||||
ZM\Debug('No change to function, not doing anything.');
|
||||
}
|
||||
} // end if action
|
||||
$view = 'console';
|
||||
$redirect = '?view=console';
|
||||
?>
|
||||
|
|
|
@ -22,9 +22,8 @@
|
|||
if ( $action == 'logout' ) {
|
||||
userLogout();
|
||||
$view = 'login';
|
||||
ZM\Logger::Debug("User: " . print_r($user,true));
|
||||
} 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' ) {
|
||||
$_REQUEST['newMonitor']['ServerId'] = dbFetchOne(
|
||||
'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') ) {
|
||||
$_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;
|
||||
} 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)
|
||||
|
||||
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);
|
||||
|
||||
|
||||
if ( isset($_REQUEST['newUser']['Password']) ) {
|
||||
if ( function_exists('password_hash') ) {
|
||||
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
|
||||
|
@ -67,9 +66,7 @@ if ( $action == 'Save' ) {
|
|||
} else {
|
||||
dbQuery('INSERT INTO Users SET '.implode(', ', $changes));
|
||||
}
|
||||
$refreshParent = true;
|
||||
}
|
||||
$view = 'none';
|
||||
} # end if changes
|
||||
} else if ( ZM_USER_SELF_EDIT and ( $_REQUEST['uid'] == $user['Id'] ) ) {
|
||||
$uid = $user['Id'];
|
||||
|
||||
|
@ -100,9 +97,7 @@ if ( $action == 'Save' ) {
|
|||
zm_session_start();
|
||||
generateAuthHash(ZM_AUTH_HASH_IPS, true);
|
||||
session_write_close();
|
||||
$refreshParent = true;
|
||||
}
|
||||
$view = 'none';
|
||||
}
|
||||
} // end if $action == user
|
||||
?>
|
||||
|
|
|
@ -70,9 +70,8 @@ if ( !empty($_REQUEST['mid']) && canEdit('Monitors', $_REQUEST['mid']) ) {
|
|||
if ( ($_REQUEST['newZone']['Type'] == 'Privacy') && $monitor->Controllable() ) {
|
||||
$monitor->sendControlCommand('quit');
|
||||
}
|
||||
$refreshParent = true;
|
||||
} // end if changes
|
||||
$view = 'none';
|
||||
$redirect = $_SERVER['HTTP_REFERER'];
|
||||
} // end if action
|
||||
} // 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
|
||||
// Starting MY SQL 4.1, mysql concats a '*' in front of its password hash
|
||||
// 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)));
|
||||
$password_correct = ($user['Password'] == $input_password_hash);
|
||||
break;
|
||||
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']);
|
||||
break;
|
||||
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
|
||||
// for every wrong password entered. This will only be invoked for passwords zmupdate.pl has
|
||||
// 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);
|
||||
$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);
|
||||
break;
|
||||
default:
|
||||
|
@ -130,7 +130,7 @@ function validateToken($token, $allowed_token_type='access') {
|
|||
return array(false, 'Incorrect token type');
|
||||
}
|
||||
} 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'];
|
||||
|
@ -210,7 +210,7 @@ function generateAuthHash($useRemoteAddr, $force=false) {
|
|||
} else {
|
||||
$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);
|
||||
$_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
|
||||
$_SESSION['AuthHashGeneratedAt'] = $time;
|
||||
|
@ -248,14 +248,14 @@ function userFromSession() {
|
|||
if ( isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) )
|
||||
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
|
||||
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 {
|
||||
# Need to refresh permissions and validate that the user still exists
|
||||
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
|
||||
$user = dbFetchOne($sql, NULL, array($_SESSION['username']));
|
||||
}
|
||||
} else {
|
||||
ZM\Logger::Debug('No username in session');
|
||||
ZM\Debug('No username in session');
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
|
|
@ -193,21 +193,21 @@ function csrf_check($fatal = true) {
|
|||
$tokens = '';
|
||||
do {
|
||||
if (!isset($_POST[$name])) {
|
||||
#Logger::Debug("POST[$name] is not set");
|
||||
#Debug("POST[$name] is not set");
|
||||
break;
|
||||
#} 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
|
||||
// schemes are volatile.
|
||||
$tokens = $_POST[$name];
|
||||
if (!csrf_check_tokens($tokens)) {
|
||||
#Logger::Debug("Failed checking tokens");
|
||||
#Debug("Failed checking tokens");
|
||||
break;
|
||||
|
||||
#} else {
|
||||
#Logger::Debug("Token passed");
|
||||
#Debug("Token passed");
|
||||
}
|
||||
$ok = true;
|
||||
} 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.
|
||||
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>";
|
||||
ZM\Logger::Debug("Failed csrf check");
|
||||
ZM\Debug("Failed csrf check");
|
||||
}
|
||||
echo "<p>Debug: $tokens</p></body></html>
|
||||
";
|
||||
|
@ -318,27 +318,27 @@ function csrf_check_tokens($tokens) {
|
|||
* Checks if a token is valid.
|
||||
*/
|
||||
function csrf_check_token($token) {
|
||||
#Logger::Debug("Checking CSRF token $token");
|
||||
#Debug("Checking CSRF token $token");
|
||||
if (strpos($token, ':') === false) {
|
||||
#Logger::Debug("Checking CSRF token $token bad because no :");
|
||||
#Debug("Checking CSRF token $token bad because no :");
|
||||
return false;
|
||||
}
|
||||
list($type, $value) = explode(':', $token, 2);
|
||||
if (strpos($value, ',') === false) {
|
||||
#Logger::Debug("Checking CSRF token $token bad because no ,");
|
||||
#Debug("Checking CSRF token $token bad because no ,");
|
||||
return false;
|
||||
}
|
||||
list($x, $time) = explode(',', $token, 2);
|
||||
if ($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;
|
||||
}
|
||||
}
|
||||
switch ($type) {
|
||||
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);
|
||||
}
|
||||
case 'cookie':
|
||||
|
@ -348,10 +348,10 @@ return false;
|
|||
return $value === csrf_hash($_COOKIE[$n], $time);
|
||||
case 'key':
|
||||
if (!$GLOBALS['csrf']['key']) {
|
||||
Logger::Debug("Checking key: no key set" );
|
||||
Debug("Checking key: no key set" );
|
||||
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);
|
||||
// We could disable these 'weaker' checks if 'key' was set, but
|
||||
// that doesn't make me feel good then about the cookie-based
|
||||
|
|
|
@ -105,7 +105,7 @@ function dbLog($sql, $update=false) {
|
|||
global $dbLogLevel;
|
||||
$noExecute = $update && ($dbLogLevel >= DB_LOG_DEBUG);
|
||||
if ( $dbLogLevel > DB_LOG_OFF )
|
||||
ZM\Logger::Debug( "SQL-LOG: $sql".($noExecute?' (not executed)':'') );
|
||||
ZM\Debug( "SQL-LOG: $sql".($noExecute?' (not executed)':'') );
|
||||
return( $noExecute );
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ function dbQuery($sql, $params=NULL) {
|
|||
}
|
||||
} else {
|
||||
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);
|
||||
if ( ! $result ) {
|
||||
|
@ -155,7 +155,7 @@ function dbQuery($sql, $params=NULL) {
|
|||
}
|
||||
}
|
||||
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) {
|
||||
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.
|
||||
# ICON: Might not be true. multi-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-Headers: x-requested-with,x-request');
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ function CORSHeaders() {
|
|||
preg_match('/^(https?:\/\/)?'.preg_quote($Server->Name(),'/').'/i', $_SERVER['HTTP_ORIGIN'])
|
||||
) {
|
||||
$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-Headers: x-requested-with,x-request');
|
||||
break;
|
||||
|
@ -392,7 +392,7 @@ function getEventDefaultVideoPath($event) {
|
|||
}
|
||||
|
||||
function deletePath( $path ) {
|
||||
ZM\Logger::Debug('Deleting '.$path);
|
||||
ZM\Debug('Deleting '.$path);
|
||||
if ( is_dir($path) ) {
|
||||
system(escapeshellcmd('rm -rf '.$path));
|
||||
} else if ( file_exists($path) ) {
|
||||
|
@ -424,6 +424,9 @@ function deleteEvent($event) {
|
|||
} # 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='') {
|
||||
$string = '';
|
||||
if ( $condition ) {
|
||||
|
@ -443,50 +446,6 @@ function makeHelpLink($ohndx) {
|
|||
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='') {
|
||||
$string = '<button type="button" data-on-click-this="'.$buttonValue.'"';
|
||||
$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) {
|
||||
|
@ -540,11 +499,10 @@ function htmlOptions($options, $values) {
|
|||
$options_html .= '<option value="'.htmlspecialchars($value, ENT_COMPAT | ENT_HTML401, ini_get('default_charset'), false).'"'.
|
||||
($selected?' selected="selected"':'').
|
||||
($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
|
||||
if ( $values and ! $has_selected ) {
|
||||
ZM\Warning('Specified value '.$values.' not in contents: '.print_r($options, true));
|
||||
if ( $values and ((!is_array($values)) or count($values) ) and ! $has_selected ) {
|
||||
ZM\Warning('Specified value '.print_r($values, true).' not in contents: '.print_r($options, true));
|
||||
}
|
||||
return $options_html;
|
||||
} # end function htmlOptions
|
||||
|
@ -582,7 +540,7 @@ function buildSelect($name, $contents, $behaviours=false) {
|
|||
$behaviourText .= ' '.$event.'="'.$action.'"';
|
||||
}
|
||||
} 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 .= ' 2>/dev/null >&- <&- >/dev/null';
|
||||
ZM\Logger::Debug('daemonControl '.$string);
|
||||
ZM\Debug('daemonControl '.$string);
|
||||
exec($string);
|
||||
}
|
||||
|
||||
|
@ -973,7 +931,7 @@ function createVideo($event, $format, $rate, $scale, $overwrite=false) {
|
|||
$command .= ' -o';
|
||||
$command = escapeshellcmd($command);
|
||||
$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);
|
||||
}
|
||||
|
||||
|
@ -1048,12 +1006,15 @@ function parseSort($saveToSession=false, $querySep='&') {
|
|||
$sortColumn = 'E.StartTime';
|
||||
break;
|
||||
case 'StartDateTime' :
|
||||
// Fix for systems with EVENT_SORT_ORDER set to erroneous StartDateTime.
|
||||
$_REQUEST['sort_field'] = 'StartTime';
|
||||
$sortColumn = 'E.StartTime';
|
||||
break;
|
||||
case 'EndTime' :
|
||||
$sortColumn = 'E.EndTime';
|
||||
break;
|
||||
case 'EndDateTime' :
|
||||
$_REQUEST['sort_field'] = 'EndTime';
|
||||
$sortColumn = 'E.EndTime';
|
||||
break;
|
||||
case 'Length' :
|
||||
|
@ -1676,17 +1637,17 @@ function coordsToPoints($coords) {
|
|||
function limitPoints(&$points, $min_x, $min_y, $max_x, $max_y) {
|
||||
foreach ( $points as &$point ) {
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
} // end foreach point
|
||||
|
@ -2111,7 +2072,7 @@ function getStreamHTML($monitor, $options = array()) {
|
|||
if ( $scale < $options['scale'] )
|
||||
$options['scale'] = $scale;
|
||||
} else {
|
||||
Warning('Invalid value for width: '.$options['width']);
|
||||
ZM\Warning('Invalid value for width: '.$options['width']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2211,7 +2172,7 @@ function check_timezone() {
|
|||
'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
|
||||
#Mysql timezone offset determine to be: $mysql_tzoffset
|
||||
#");
|
||||
|
@ -2450,4 +2411,11 @@ function zm_random_bytes($length = 32) {
|
|||
}
|
||||
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;
|
||||
|
||||
//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() {
|
||||
|
@ -199,9 +199,6 @@ class Logger {
|
|||
return self::$instance;
|
||||
}
|
||||
|
||||
public static function Debug( $string ) {
|
||||
Logger::fetch()->logPrint( Logger::DEBUG, $string );
|
||||
}
|
||||
|
||||
public function id( $id=NULL ) {
|
||||
if ( isset($id) && $this->id != $id ) {
|
||||
|
@ -459,6 +456,10 @@ function Dump( &$var, $label='VAR' ) {
|
|||
Logger::fetch()->logPrint( Logger::DEBUG, ob_get_clean() );
|
||||
}
|
||||
|
||||
function Debug( $string ) {
|
||||
Logger::fetch()->logPrint( Logger::DEBUG, $string );
|
||||
}
|
||||
|
||||
function Info( $string ) {
|
||||
Logger::fetch()->logPrint( Logger::INFO, $string );
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ function zm_session_start() {
|
|||
}
|
||||
|
||||
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['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
|
||||
|
@ -37,7 +37,7 @@ function zm_session_start() {
|
|||
session_start();
|
||||
} else if ( !empty($_SESSION['generated_at']) ) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -87,4 +87,71 @@ function zm_session_clear() {
|
|||
session_write_close();
|
||||
session_start();
|
||||
} // 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
|
||||
$now = time();
|
||||
$old = $now - $max;
|
||||
ZM\Debug('doing session gc ' . $now . '-' . $max. '='.$old);
|
||||
$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() ) {
|
||||
ob_start();
|
||||
phpinfo(INFO_VARIABLES);
|
||||
ZM\Logger::Debug(ob_get_contents());
|
||||
ZM\Debug(ob_get_contents());
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ define('ZM_BASE_URL', '');
|
|||
|
||||
require_once('includes/functions.php');
|
||||
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
|
||||
CORSHeaders();
|
||||
return;
|
||||
|
@ -183,6 +183,9 @@ $user = null;
|
|||
if ( isset($_REQUEST['view']) )
|
||||
$view = detaintPath($_REQUEST['view']);
|
||||
|
||||
if ( isset($_REQUEST['redirect']) )
|
||||
$redirect = '?view='.detaintPath($_REQUEST['redirect']);
|
||||
|
||||
# Add CSP Headers
|
||||
$cspNonce = bin2hex(zm_random_bytes(16));
|
||||
|
||||
|
@ -218,7 +221,7 @@ if ( (!$view and !$request) or ($view == 'console') ) {
|
|||
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 (
|
||||
ZM_ENABLE_CSRF_MAGIC &&
|
||||
( $action != 'login' ) &&
|
||||
|
@ -229,14 +232,14 @@ if (
|
|||
( $view != 'archive' ) // returns data
|
||||
) {
|
||||
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();
|
||||
}
|
||||
|
||||
# Need to include actions because it does auth
|
||||
if ( $action and !$request ) {
|
||||
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');
|
||||
} else {
|
||||
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');
|
||||
exit;
|
||||
}
|
||||
ZM\Logger::Debug('Redirecting to login');
|
||||
ZM\Debug('Redirecting to login');
|
||||
$view = 'none';
|
||||
$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login';
|
||||
if ( ! $request ) {
|
||||
|
@ -268,7 +271,7 @@ if ( ZM_OPT_USE_AUTH and (!isset($user)) and ($view != 'login') and ($view != 'n
|
|||
|
||||
|
||||
if ( $redirect ) {
|
||||
ZM\Logger::Debug("Redirecting to $redirect");
|
||||
ZM\Debug("Redirecting to $redirect");
|
||||
header('Location: '.$redirect);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -72,14 +72,10 @@ function MonitorStream(monitorData) {
|
|||
|
||||
this.onclick = function(evt) {
|
||||
var el = evt.currentTarget;
|
||||
var tag = 'watch';
|
||||
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 name = 'zmWatch'+id;
|
||||
evt.preventDefault();
|
||||
createPopup(url, name, tag, width, height);
|
||||
window.location.assign(url);
|
||||
};
|
||||
|
||||
this.setup_onclick = function() {
|
||||
|
|
|
@ -989,7 +989,7 @@ $OLANG = array(
|
|||
|
||||
// 'LANG_DEFAULT' => array(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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"
|
||||
// ),
|
||||
);
|
||||
|
||||
|
|
|
@ -262,6 +262,7 @@ $SLANG = array(
|
|||
'ConfiguredFor' => 'Configured for',
|
||||
'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?',
|
||||
'ConfirmDeleteTitle' => 'Delete Confirmation',
|
||||
'ConfirmPassword' => 'Confirm Password',
|
||||
|
@ -366,6 +367,7 @@ $SLANG = array(
|
|||
'Ffmpeg' => 'Ffmpeg',
|
||||
'File' => 'File',
|
||||
'FilterArchiveEvents' => 'Archive all matches',
|
||||
'FilterUnarchiveEvents' => 'Unarchive all matches',
|
||||
'FilterUpdateDiskSpace' => 'Update used disk space',
|
||||
'FilterDeleteEvents' => 'Delete all matches',
|
||||
'FilterCopyEvents' => 'Copy all matches',
|
||||
|
@ -1073,7 +1075,7 @@ $OLANG = array(
|
|||
|
||||
// 'LANG_DEFAULT' => array(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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(
|
||||
// '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
|
||||
// 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_CTYPE, 'cn_ZH' ); //Character class settings 4.3.0 and after
|
||||
setlocale( LC_TIME, 'cn_ZH' ); //Date and time formatting 4.3.0 and after
|
||||
setlocale( LC_ALL, 'zh_CN' ); //All locale settings 4.3.0 and after
|
||||
setlocale( LC_CTYPE, 'zh_CN' ); //Character class settings 4.3.0 and after
|
||||
setlocale( LC_TIME, 'zh_CN' ); //Date and time formatting 4.3.0 and after
|
||||
|
||||
// Simple String Replacements
|
||||
$SLANG = array(
|
||||
|
@ -989,7 +989,7 @@ $OLANG = array(
|
|||
|
||||
// 'LANG_DEFAULT' => array(
|
||||
// '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;
|
||||
line-height: 130%;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#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 {
|
||||
background-color:#ffcccc;
|
||||
font-weight: bold;
|
||||
|
@ -32,20 +16,3 @@ tr.log-dbg td {
|
|||
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 {
|
||||
float: left;
|
||||
margin: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
@ -19,15 +19,23 @@
|
|||
//
|
||||
|
||||
$rates = array(
|
||||
'10000' => '100x',
|
||||
'5000' => '50x',
|
||||
'2500' => '25x',
|
||||
'1000' => '10x',
|
||||
'400' => '4x',
|
||||
'200' => '2x',
|
||||
'100' => translate('Real'),
|
||||
'50' => '1/2x',
|
||||
'25' => '1/4x',
|
||||
-5000 => '-50x',
|
||||
-2500 => '-25x',
|
||||
-1000 => '-10x',
|
||||
-500 => '-5x',
|
||||
-200 => '-2x',
|
||||
-100 => '-1x',
|
||||
-50 => '-1/2x',
|
||||
-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(
|
||||
|
|
|
@ -176,7 +176,7 @@ function controlPresets($monitor, $cmds) {
|
|||
}
|
||||
if ( canEdit('Monitors') && $control->CanSetPresets() ) {
|
||||
?>
|
||||
<button type="button" class="ptzTextBtn popup-link" value="Set" data-url="?view=controlpreset&mid=<?php echo $monitor->Id() ?>" data-window-name="zmPreset" data-window-tag="preset"><?php echo translate('Set') ?></button>
|
||||
<button type="button" class="ptzTextBtn" value="Set" data-toggle="modal" data-target="#ctrlPresetModal"><?php echo translate('Set') ?></button>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -897,7 +897,7 @@ function exportEvents(
|
|||
ZM\Error("Can't create exports dir at '$export_dir'");
|
||||
return false;
|
||||
}
|
||||
ZM\Logger::Debug("Successfully created dir '$export_dir'");
|
||||
ZM\Debug("Successfully created dir '$export_dir'");
|
||||
chmod($export_dir, 0700);
|
||||
if ( !chdir($export_dir) ) {
|
||||
ZM\Error("Can't chdir to $export_dir");
|
||||
|
@ -925,7 +925,7 @@ function exportEvents(
|
|||
#continue;
|
||||
$cmd = 'cp -as '.$event->Path().'/'.$file.' '.$export_dir.'/'.$event->Id().'/'.$file. ' 2>&1';
|
||||
exec($cmd, $output, $return);
|
||||
ZM\Logger::Debug($cmd.' return code: '.$return.' output: '.print_r($output,true));
|
||||
ZM\Debug($cmd.' return code: '.$return.' output: '.print_r($output,true));
|
||||
} # end foreach event_exportFile
|
||||
} # end foreach event
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@ function getZMVersionHTML() {
|
|||
$class = 'text-danger';
|
||||
$tt_text = translate('RunLocalUpdate');
|
||||
$content = 'v'.ZM_VERSION.PHP_EOL;
|
||||
} else if ( verNum( ZM_DYN_LAST_VERSION ) <= verNum( ZM_VERSION ) ) { // No update needed
|
||||
} else if ( verNum( ZM_DYN_LAST_VERSION ) <= verNum( ZM_VERSION ) || !ZM_CHECK_FOR_UPDATES || ZM_DYN_NEXT_REMINDER > time() ) { // No update needed
|
||||
$class = ''; // Don't change the text color under normal conditions
|
||||
$tt_text = translate('UpdateNotNecessary');
|
||||
$content = 'v'.ZM_VERSION.PHP_EOL;
|
||||
|
@ -737,7 +737,7 @@ function getAcctCircleHTML($skin, $user=null) {
|
|||
if ( ZM_OPT_USE_AUTH and $user ) {
|
||||
$result .= '<p id="getAcctCircleHTML" class="navbar-text mr-2">'.PHP_EOL;
|
||||
$result .= makeLink('#', '<i class="material-icons">account_circle</i> '. $user['Username'],
|
||||
(ZM_AUTH_TYPE == 'builtin'), 'data-toggle="modal" data-target="#modalLogout" data-backdrop="false"' ).PHP_EOL;
|
||||
(ZM_AUTH_TYPE == 'builtin'), 'id="logoutButton" data-toggle="modal" data-target="#modalLogout" data-backdrop="false"' ).PHP_EOL;
|
||||
$result .= '</p>'.PHP_EOL;
|
||||
}
|
||||
|
||||
|
@ -756,9 +756,9 @@ function getStatusBtnHTML($status) {
|
|||
//$result .= '</li>'.PHP_EOL;
|
||||
|
||||
if ( ZM_SYSTEM_SHUTDOWN ) {
|
||||
$result .= '<p class="navbar-text">'.PHP_EOL;
|
||||
$result .= makePopupLink('?view=shutdown', 'zmShutdown', 'shutdown', '<i class="material-icons md-18">power_settings_new</i>' ).PHP_EOL;
|
||||
$result .= '</p>'.PHP_EOL;
|
||||
$result .= '<div class="navbar-text pr-2 align-self-center">'.PHP_EOL;
|
||||
$result .= '<button class="btn btn-outline" data-on-click="getShutdownModal" data-toggle="tooltip" data-placement="top" title="' .translate("Shutdown"). '" ><i class="material-icons md-18">power_settings_new</i></button>'.PHP_EOL;
|
||||
$result .= '</div>'.PHP_EOL;
|
||||
}
|
||||
|
||||
} else if ( canView('System') ) {
|
||||
|
@ -790,6 +790,7 @@ function getStatsTableHTML($eid, $fid, $row='') {
|
|||
$stats = dbFetchAll( $sql, NULL, array( $eid, $fid ) );
|
||||
|
||||
$result .= '<table id="contentStatsTable' .$row. '"'.PHP_EOL;
|
||||
$result .= 'data-locale="' .i18n(). '"'.PHP_EOL;
|
||||
$result .= 'data-toggle="table"'.PHP_EOL;
|
||||
$result .= 'data-toolbar="#toolbar"'.PHP_EOL;
|
||||
$result .= 'class="table-sm table-borderless contentStatsTable"'.PHP_EOL;
|
||||
|
@ -875,6 +876,7 @@ function xhtmlFooter() {
|
|||
<script src="skins/<?php echo $skin; ?>/js/bootstrap.min.js"></script>
|
||||
<?php echo output_script_if_exists(array(
|
||||
'js/bootstrap-table.min.js',
|
||||
'js/bootstrap-table-locale-all.min.js',
|
||||
'js/tableExport.min.js',
|
||||
'js/bootstrap-table-export.min.js',
|
||||
'js/bootstrap-table-page-jump-to.min.js',
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue