Merge branch 'release-1.34' of github.com:ZoneMinder/zoneminder into release-1.34

This commit is contained in:
Isaac Connor 2020-09-16 15:30:05 -04:00
commit 17369e73e2
133 changed files with 2600 additions and 1247 deletions

4
.github/stale.yml vendored
View File

@ -1,10 +1,10 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
daysUntilStale: 180
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
daysUntilClose: 30
# Issues with these labels will never be considered stale
exemptLabels:

View File

@ -875,7 +875,6 @@ configure_file(zmlinkcontent.sh.in "${CMAKE_CURRENT_BINARY_DIR}/zmlinkcontent.sh
# Create a target for man pages
include(Pod2Man)
ADD_MANPAGE_TARGET()
# Process subdirectories

View File

@ -53,8 +53,7 @@ MACRO(POD2MAN PODFILE MANFILE SECTION MANPAGE_DEST_PREFIX)
SET(MANPAGE_TARGET "man-${MANFILE}")
ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
ADD_DEPENDENCIES(man ${MANPAGE_TARGET})
ADD_CUSTOM_TARGET(${MANPAGE_TARGET} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
INSTALL(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz

View File

@ -46,3 +46,6 @@ ZM_PATH_SWAP=@ZM_TMPDIR@
# Full path to optional arp binary
# ZoneMinder will find the arp binary automatically on most systems
ZM_PATH_ARP="@ZM_PATH_ARP@"
#Full path to shutdown binary
ZM_PATH_SHUTDOWN="@ZM_PATH_SHUTDOWN@"

View File

@ -476,7 +476,7 @@ CREATE TABLE `Monitors` (
`Hue` mediumint(7) NOT NULL default '-1',
`Colour` mediumint(7) NOT NULL default '-1',
`EventPrefix` varchar(32) NOT NULL default 'Event-',
`LabelFormat` varchar(64) default '%N - %y/%m/%d %H:%M:%S',
`LabelFormat` varchar(64),
`LabelX` smallint(5) unsigned NOT NULL default '0',
`LabelY` smallint(5) unsigned NOT NULL default '0',
`LabelSize` smallint(5) unsigned NOT NULL DEFAULT '1',

2
db/zm_update-1.34.20.sql Normal file
View File

@ -0,0 +1,2 @@
/* This was done in 1.31.0 but zm_create.sql.in wasn't updated to match. */
ALTER TABLE Monitors MODIFY LinkedMonitors varchar(255);

10
distros/beowulf/NEWS Normal file
View File

@ -0,0 +1,10 @@
zoneminder (1.28.1-1) unstable; urgency=low
This version is no longer automatically initialize or upgrade database.
See README.Debian for details.
Changed installation paths (please correct your web server configuration):
/usr/share/zoneminder --> /usr/share/zoneminder/www
/usr/lib/cgi-bin --> /usr/lib/zoneminder/cgi-bin
-- Dmitry Smirnov <onlyjob@debian.org> Tue, 31 Mar 2015 15:12:17 +1100

View File

@ -0,0 +1,130 @@
Zoneminder for Debian
---------------------
Initializing database
---------------------
pv /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf
OR
cat /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf
echo 'grant lock tables,alter,create,index,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";'\
| sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql
Hint: generate secure password with `pwgen` and update "/etc/zm/zm.conf"
accordingly.
The following command can help to ensure that zoneminder can read its
configuration file:
chgrp -c www-data /etc/zm/zm.conf
Upgrading database
------------------
The database is updated automatically on installation. You should not need to take this step.
Assuming that database is on "localhost" then the following command can be
used to upgrade "zm" database:
zmupdate.pl
Additional permissions may be required to perform upgrade:
echo 'grant lock tables, create, alter on zm.* to 'zmuser'@localhost identified by "zmpass";'\
| sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql
The following command prints the current version of zoneminder database:
echo 'select Value from Config where Name = "ZM_DYN_CURR_VERSION";' \
| sudo mysql --defaults-file=/etc/mysql/debian.cnf --skip-column-names zm
Enabling service
----------------
By default Zoneminder service is not automatically started and needs to be
manually enabled once database is configured:
sudo systemctl enable zoneminder.service
Web server set-up
-----------------
There are few manual steps to get the web interface working:
## Apache2
Apache can be configured as folder "/zm" using sample .conf:
sudo a2enconf zoneminder
Alternatively Apache web site configuration template can be used to setup
zoneminder as "http://zoneminder":
sudo cp -v /usr/share/doc/zoneminder/examples/apache.conf /etc/apache2/sites-available/
sudo a2ensite zoneminder.conf
Common configuration steps for Apache2:
sudo a2enmod cgi
sudo service apache2 reload
## nginx / fcgiwrap
Nginx needs "php-fpm" package to support PHP and "fcgiwrap" package
for binary "cgi-bin" applications:
sudo apt-get install php-fpm fcgiwrap
To enable a URL alias that makes Zoneminder available from
http://yourserver/zm
the following line is to be added to "server" section of a web site
configuration:
include /usr/share/doc/zoneminder/examples/nginx.conf;
For "default" web site it would be sufficient to include the above
statement to the file
/etc/nginx/sites-enabled/default
To avoid problems with feeds from multiple cameras "fcgiwrap" should be
configured to start at least as many processes as there are cameras.
It can be done by adjusting DAEMON_OPTS in "/etc/default/fcgiwrap".
Systemd users may be affected by the following bug:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=792705
## Note:
When Zoneminder web site is running it may be necessary to set
Options/Paths/PATH_ZMS to "/zm/cgi-bin/nph-zms" or according to chosen web
site configuration.
Changing the location for images and events
-------------------------------------------
ZoneMinder is now able to be configured to use an alternative location for storing
events and images at compile time. This package makes use of that, so symlinks in
/usr/share/zoneminder/www are no longer necessary.
Access to /dev/video*
---------------------
For cameras which require access to /dev/video*, zoneminder may need the
www-data user added to the video group in order to see those cameras:
adduser www-data video
Note that all web applications running on the zoneminder server will then have
access to all video devices on the system.
-- Vagrant Cascadian <vagrant@debian.org> Sun, 27 Mar 2011 13:06:56 -0700

View File

@ -0,0 +1,12 @@
## Separate substantial /usr/share into its own arch-all package.
## Decide how to handle database updates.
* Consider possibility that database may be on another machine (#469239).
* Consider dbconfig-common? Probably not (what if database is not on localhost?).
### Run `zmupdate.pl` from service control scripts (init.d, service) on start?
Automatic upgrade will break "one DB, many zoneminders" setup (unimportant?).

View File

@ -0,0 +1,3 @@
zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low
*
-- Isaac Connor <iconnor@connortechnology.com> Fri, 23 Feb 2018 14:15:59 -0500

3
distros/beowulf/clean Normal file
View File

@ -0,0 +1,3 @@
.gitattributes
web/api/.gitattributes
web/api/.gitignore

1
distros/beowulf/compat Normal file
View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,57 @@
# Remember to enable cgi mod (i.e. "a2enmod cgi").
ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin"
<Directory "/usr/lib/zoneminder/cgi-bin">
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AllowOverride All
Require all granted
</Directory>
# Order matters. This alias must come first.
Alias /zm/cache /var/cache/zoneminder/cache
<Directory /var/cache/zoneminder/cache>
Options -Indexes +FollowSymLinks
AllowOverride None
<IfModule mod_authz_core.c>
# Apache 2.4
Require all granted
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order deny,allow
Allow from all
</IfModule>
</Directory>
Alias /zm /usr/share/zoneminder/www
<Directory /usr/share/zoneminder/www>
Options -Indexes +FollowSymLinks
<IfModule mod_dir.c>
DirectoryIndex index.php
</IfModule>
</Directory>
# For better visibility, the following directives have been migrated from the
# default .htaccess files included with the CakePHP project.
# Parameters not set here are inherited from the parent directive above.
<Directory "/usr/share/zoneminder/www/api">
RewriteEngine on
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app">
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app/webroot">
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
RewriteBase /zm/api
</Directory>

166
distros/beowulf/control Normal file
View File

@ -0,0 +1,166 @@
Source: zoneminder
Section: net
Priority: optional
Maintainer: Isaac Connor <isaac@zoneminder.com>
Uploaders: Isaac Connor <isaac@zoneminder.com>
Build-Depends: debhelper, sphinx-doc, dh-linktree, dh-apache2
,cmake
,libx264-dev, libmp4v2-dev
,libavdevice-dev
,libavcodec-dev
,libavformat-dev
,libavutil-dev
,libswresample-dev
,libswscale-dev
,ffmpeg
,net-tools
,libbz2-dev
,libgcrypt20-dev
,libcurl4-gnutls-dev
,libturbojpeg0-dev
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
,libpcre3-dev
,libpolkit-gobject-1-dev
,libv4l-dev [!hurd-any]
,libvlc-dev
,libdate-manip-perl
,libdbd-mysql-perl
,libphp-serialization-perl
,libsys-mmap-perl [!hurd-any]
,libwww-perl
,libdata-uuid-perl
,libssl-dev
,libcrypt-eksblowfish-perl
,libdata-entropy-perl
# Unbundled (dh_linktree):
,libjs-jquery
,libjs-mootools
Standards-Version: 3.9.8
Homepage: http://www.zoneminder.com/
Vcs-Browser: http://anonscm.debian.org/cgit/collab-maint/zoneminder.git
Vcs-Git: git://anonscm.debian.org/collab-maint/zoneminder.git
Package: zoneminder
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,javascript-common
,libmp4v2-2, libx264-155
,libswscale5
,libswresample3
,ffmpeg
,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
,libdbd-mysql-perl
,libphp-serialization-perl
,libmodule-load-conditional-perl
,libnet-sftp-foreign-perl
,libarchive-zip-perl
,libdbd-mysql-perl
,libdevice-serialport-perl
,libimage-info-perl
,libjson-maybexs-perl
,libsys-mmap-perl [!hurd-any]
,liburi-encode-perl
,libwww-perl, liburi-perl
,libdata-dump-perl
,libdatetime-perl
,libclass-std-fast-perl
,libsoap-wsdl-perl
,libio-socket-multicast-perl
,libdigest-sha-perl
,libsys-cpu-perl, libsys-meminfo-perl
,libdata-uuid-perl
,libnumber-bytes-human-perl
,libfile-slurp-perl
,mysql-client | mariadb-client | virtual-mysql-client
,perl-modules
,php-mysql, php-gd, php-apcu, php-apc | php-apcu-bc, php-json
,policykit-1
,rsyslog | system-log-daemon
,zip
,libpcre3
,libcrypt-eksblowfish-perl
,libdata-entropy-perl
Recommends: ${misc:Recommends}
,libapache2-mod-php | php-fpm
,mysql-server | mariadb-server | virtual-mysql-server
,zoneminder-doc (>= ${source:Version})
,ffmpeg
Suggests: fcgiwrap, logrotate
Description: video camera security and surveillance solution
ZoneMinder is intended for use in single or multi-camera video security
applications, including commercial or home CCTV, theft prevention and child
or family member or home monitoring and other care scenarios. It
supports capture, analysis, recording, and monitoring of video data coming
from one or more video or network cameras attached to a Linux system.
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
cameras using a variety of protocols. It is suitable for use as a home
video security system and for commercial or professional video security
and surveillance. It can also be integrated into a home automation system
via X.10 or other protocols.
#Package: libzoneminder-perl
#Section: perl
#Architecture: all
#Multi-Arch: foreign
#Depends: ${misc:Depends}, ${perl:Depends}
# ,libarchive-zip-perl
# ,libdbd-mysql-perl
# ,libdevice-serialport-perl
# ,libimage-info-perl
# ,libjson-maybexs-perl
# ,libsys-mmap-perl [!hurd-any]
# ,liburi-encode-perl
# ,libwww-perl
#Description: ZoneMinder Perl libraries
# ZoneMinder is intended for use in single or multi-camera video security
# applications, including commercial or home CCTV, theft prevention and child
# or family member or home monitoring and other care scenarios. It
# supports capture, analysis, recording, and monitoring of video data coming
# from one or more video or network cameras attached to a Linux system.
# ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
# cameras using a variety of protocols. It is suitable for use as a home
# video security system and for commercial or professional video security
# and surveillance. It can also be integrated into a home automation system
# via X.10 or other protocols.
# .
# This package provides ZoneMinder Perl libraries; it can be used to
# write custom interfaces as well.
Package: zoneminder-doc
Section: doc
Architecture: all
Multi-Arch: foreign
Depends: ${misc:Depends}, ${sphinxdoc:Depends}, python-sphinx-rtd-theme | python3-sphinx-rtd-theme
Suggests: www-browser
Description: ZoneMinder documentation
ZoneMinder is intended for use in single or multi-camera video security
applications, including commercial or home CCTV, theft prevention and child
or family member or home monitoring and other care scenarios. It
supports capture, analysis, recording, and monitoring of video data coming
from one or more video or network cameras attached to a Linux system.
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
cameras using a variety of protocols. It is suitable for use as a home
video security system and for commercial or professional video security
and surveillance. It can also be integrated into a home automation system
via X.10 or other protocols.
.
This package provides ZoneMinder documentation in HTML format.
Package: zoneminder-dbg
Section: debug
Priority: extra
Architecture: any
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
Description: Zoneminder -- debugging symbols
ZoneMinder is intended for use in single or multi-camera video security
applications, including commercial or home CCTV, theft prevention and child
or family member or home monitoring and other care scenarios. It
supports capture, analysis, recording, and monitoring of video data coming
from one or more video or network cameras attached to a Linux system.
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
cameras using a variety of protocols. It is suitable for use as a home
video security system and for commercial or professional video security
and surveillance. It can also be integrated into a home automation system
via X.10 or other protocols.
.
This package provides debugging symbols

174
distros/beowulf/copyright Normal file
View File

@ -0,0 +1,174 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ZoneMinder
Upstream-Contact: Philip Coombes <philip.coombes@zoneminder.com>
Source: https://github.com/ZoneMinder/ZoneMinder
Comment:
This package was originally debianized by matrix <matrix@cecilia>
on Mon, 7 Mar 2005 02:07:57 -0500.
It was re-done for submission to the Debian project by Peter Howard
<pjh@northern-ridge.com.au> on Fri, 8 Dec 2006 10:19:43 +1100
Files-Excluded:
web/skins/*/js/jquery-*
web/tools/mootools/*-yc.js
Files: *
Copyright: 2001-2014 Philip Coombes <philip.coombes@zoneminder.com>
2008 Brian Rudy <brudyNO@SPAMpraecogito.com>
2014 Vincent Giovannone
2013 Tim Craig <timcraigNO@SPAMsonic.net>
2003-2008 Corey DeLasaux
2001-2010 Chris Kistner
License: GPL-2+
Files: distros/*
Copyright: 2001-2008 Philip Coombes <philip.coombes@zoneminder.com>
2014 Isaac Connor <iconnor@connortechnology.com>
2005 Serg Oskin
License: GPL-2+
Files: web/skins/*/js/jquery-*
Copyright: 2010 John Resig
2010 The Dojo Foundation
License: GPL-2 or Expat
Comment:
Dual licensed under the MIT or GPL Version 2 licenses.
http://jquery.org/license
.
Includes Sizzle.js http://sizzlejs.com/
Released under the MIT, BSD, and GPL Licenses.
Files: web/tools/mootools/*.js
Copyright: 2009 Marcelo Jorge Vieira (metal) <metal@alucinados.com>
2006-2010 Valerio Proietti (http://mad4milk.net/)
License: Expat
Files: web/api/*
Copyright: 2005-2013 Cake Software Foundation, Inc. (http://cakefoundation.org)
License: Expat
Files:
cmake/Modules/CheckPrototypeDefinition*.cmake
cmake/Modules/FindGLIB2.cmake
cmake/Modules/FindPolkit.cmake
cmake/Modules/GNUInstallDirs.cmake
Copyright:
2005-2011 Kitware, Inc.
2010-2011 Andreas Schneider <asn@cryptomilk.org>
2009 Dario Freddi <drf@kde.org>
2008 Laurent Montel, <montel@kde.org>
2011 Nikita Krupen'ko <krnekit@gmail.com>
License: BSD-3-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
.
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
* The names of Kitware, Inc., the Insight Consortium, or the names of
any consortium members, or of any contributors, may not be used to
endorse or promote products derived from this software without
specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Files: cmake/Modules/FindPerlModules.cmake
Copyright: 2012 Iowa State University
License: Boost-1.0
Boost Software License - Version 1.0 - August 17th, 2003
.
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
.
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
Files: debian/*
Copyright: 2015 Dmitry Smirnov <onlyjob@debian.org>
2007-2014 Peter Howard <pjh@northern-ridge.com.au>
2010-2012 Vagrant Cascadian <vagrant@debian.org>
2001-2008 Philip Coombes <philip.coombes@zoneminder.com>
License: GPL-2+
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
License: GPL-2+
This package 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 package 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 package; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
.
The complete text of the GNU General Public License version 2
can be found in "/usr/share/common-licenses/GPL-2".
License: GPL-2
This package 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; version 2 of the License.
.
This package 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 package; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
.
The complete text of the GNU General Public License version 2
can be found in "/usr/share/common-licenses/GPL-2".

View File

@ -0,0 +1,32 @@
location /zm/cgi-bin {
gzip off;
alias /usr/lib/zoneminder/cgi-bin;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
}
location /zm {
# if ($scheme ~ ^http:){
# rewrite ^(.*)$ https://$host$1 permanent;
# }
gzip off;
alias /usr/share/zoneminder/www;
index index.php;
location ~ \.php$ {
if (!-f $request_filename) { return 404; }
expires epoch;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
location ~ \.(jpg|jpeg|gif|png|ico)$ {
access_log off;
expires 33d;
}
}

7
distros/beowulf/gbp.conf Normal file
View File

@ -0,0 +1,7 @@
[dch]
id-length = 0
[import-orig]
pristine-tar = False
merge = False

View File

@ -0,0 +1,2 @@
usr/share/man/man3
usr/share/perl5

View File

87
distros/beowulf/rules Executable file
View File

@ -0,0 +1,87 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
export DEB_LDFLAGS_MAINT_APPEND += -Wl,--as-needed
ifeq ($(DEB_BUILD_ARCH_OS),hurd)
ARGS:= -DZM_NO_MMAP=ON
endif
%:
dh $@ --parallel --buildsystem=cmake --builddirectory=dbuild \
--with sphinxdoc,apache2,linktree
override_dh_auto_configure:
dh_auto_configure -- $(ARGS) \
-DCMAKE_VERBOSE_MAKEFILE=ON \
-DCMAKE_BUILD_TYPE=Release \
-DZM_CONFIG_DIR="/etc/zm" \
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
-DZM_RUNDIR="/run/zm" \
-DZM_SOCKDIR="/run/zm" \
-DZM_TMPDIR="/tmp/zm" \
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
-DZM_CACHEDIR="/var/cache/zoneminder/cache" \
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
-DZM_PATH_SHUTDOWN="/sbin/shutdown" \
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
override_dh_clean:
dh_clean $(MANPAGES1)
$(RM) -r docs/_build
build-indep:
#$(MAKE) -C docs text
$(MAKE) -C docs html
MANPAGES1 = dbuild/scripts/zmupdate.pl.1
$(MANPAGES1):
# generate man page(s):
pod2man -s1 --stderr --utf8 $(patsubst %.1, %, $@) $@
## reproducible build:
LAST_CHANGE=$(shell dpkg-parsechangelog -S Date)
BUILD_DATE=$(shell LC_ALL=C date -u "+%B %d, %Y" -d "$(LAST_CHANGE)")
override_dh_installman: $(MANPAGES1)
$(MAKE) -C docs man SPHINXOPTS="-D today=\"$(BUILD_DATE)\""
dh_installman --language=C $(MANPAGES1)
override_dh_auto_install:
dh_auto_install --destdir=$(CURDIR)/debian/tmp
# remove worthless files:
$(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*/*/.packlist
$(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*.in
# remove empty directories:
find $(CURDIR)/debian/tmp/usr -type d -empty -delete -printf 'removed %p\n'
# remove extra-license-file:
$(RM) -v $(CURDIR)/debian/tmp/usr/share/zoneminder/www/api/lib/Cake/LICENSE.txt
override_dh_fixperms:
dh_fixperms
#
# As requested by the Debian Webapps Policy Manual §3.2.1
chown root:www-data $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
chmod 640 $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
override_dh_strip:
[ -d "$(CURDIR)/debian/zoneminder-dbg" ] \
&& dh_strip --dbg-package=zoneminder-dbg \
|| dh_strip
#%:
# dh $@ --parallel --buildsystem=autoconf --with autoreconf
#
#override_dh_auto_configure:
# dh_auto_configure -- \
# --sysconfdir=/etc/zm \
# --with-mysql=/usr \
# --with-webdir=/usr/share/zoneminder \
# --with-ffmpeg=/usr \
# --with-cgidir=/usr/lib/cgi-bin \
# --with-webuser=www-data \
# --with-webgroup=www-data \
# --enable-mmap=yes

View File

@ -0,0 +1 @@
3.0 (quilt)

View File

@ -0,0 +1,9 @@
## Actually sources are there: "*-nc.js".
source-is-missing web/tools/mootools/mootools-*-yc.js
## We're using "libjs-jquery" instead.
source-is-missing web/skins/*/js/jquery-1.4.2.min.js
## Acknowledged, will repack eventually.
source-contains-prebuilt-javascript-object web/tools/mootools/mootools-*-yc.js
source-contains-prebuilt-javascript-object web/skins/*/js/jquery-1.4.2.min.js

View File

@ -0,0 +1,8 @@
Document: zoneminder-doc
Title: Zoneminder documentation
Abstract: This document describes how to use Zoneminder.
Section: System/Administration
Format: HTML
Index: /usr/share/doc/zoneminder-doc/html/index.html
Files: /usr/share/doc/zoneminder-doc/html/*

View File

@ -0,0 +1 @@
docs/_build/html usr/share/doc/zoneminder-doc/

View File

@ -0,0 +1,2 @@
## Convenience symlink:
/usr/share/doc/zoneminder-doc/html /usr/share/doc/zoneminder/html

View File

@ -0,0 +1 @@
conf debian/conf/apache2/zoneminder.conf nginx

View File

@ -0,0 +1,5 @@
Unless bug is specific to Debian please consider reporting it directly to
upstream developer(s):
https://github.com/ZoneMinder/ZoneMinder/issues

View File

@ -0,0 +1,9 @@
var/log/zm
var/lib/zm
var/cache/zoneminder/events
var/cache/zoneminder/images
var/cache/zoneminder/temp
var/cache/zoneminder/cache
usr/share/zoneminder/db
etc/zm/
etc/zm/conf.d

View File

@ -0,0 +1 @@
README.md

View File

@ -0,0 +1,2 @@
debian/examples/*
dbuild/misc/apache.conf

View File

@ -0,0 +1,91 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: zoneminder
# Required-Start: $network $remote_fs $syslog
# Required-Stop: $network $remote_fs $syslog
# Should-Start: mysql
# Should-Stop: mysql
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Control ZoneMinder as a Service
# Description: ZoneMinder CCTV recording and surveillance system
### END INIT INFO
# chkconfig: 2345 20 20
# Source function library.
. /lib/lsb/init-functions
prog=ZoneMinder
ZM_PATH_BIN="/usr/bin"
RUNDIR="/run/zm"
TMPDIR="/tmp/zm"
command="$ZM_PATH_BIN/zmpkg.pl"
start() {
echo -n "Starting $prog: "
export TZ=:/etc/localtime
mkdir -p "$RUNDIR" && chown www-data:www-data "$RUNDIR"
mkdir -p "$TMPDIR" && chown www-data:www-data "$TMPDIR"
$command start
RETVAL=$?
[ $RETVAL = 0 ] && echo success
[ $RETVAL != 0 ] && echo failure
echo
[ $RETVAL = 0 ] && touch /var/lock/zm
return $RETVAL
}
stop() {
echo -n "Stopping $prog: "
#
# Why is this status check being done?
# as $command stop returns 1 if zoneminder
# is stopped, which will result in
# this returning 1, which will stuff
# dpkg when it tries to stop zoneminder before
# uninstalling . . .
#
result=`$command status`
if [ ! "$result" = "running" ]; then
echo "Zoneminder already stopped"
echo
RETVAL=0
else
$command stop
RETVAL=$?
[ $RETVAL = 0 ] && echo success
[ $RETVAL != 0 ] && echo failure
echo
[ $RETVAL = 0 ] && rm -f /var/lock/zm
fi
}
status() {
result=`$command status`
if [ "$result" = "running" ]; then
echo "ZoneMinder is running"
RETVAL=0
else
echo "ZoneMinder is stopped"
RETVAL=1
fi
}
case "$1" in
'start')
start
;;
'stop')
stop
;;
'restart' | 'force-reload')
stop
start
;;
'status')
status
;;
*)
echo "Usage: $0 { start | stop | restart | status }"
RETVAL=1
;;
esac
exit $RETVAL

View File

@ -0,0 +1,11 @@
etc/zm/zm.conf
etc/zm/conf.d/*
usr/bin
usr/lib/zoneminder
usr/share/polkit-1
usr/share/zoneminder/db
usr/share/zoneminder/www
# libzoneminder-perl files:
usr/share/man/man3
usr/share/perl5

View File

@ -0,0 +1 @@
/var/tmp /usr/share/zoneminder/www/api/app/tmp

View File

@ -0,0 +1,14 @@
## cakephp
#replace /usr/share/php/Cake /usr/share/zoneminder/www/api/lib/Cake
## libjs-mootools
replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core.js
replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core-1.3.2-nc.js
replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core-1.3.2-yc.js
replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more.js
replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more-1.3.2.1-nc.js
replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more-1.3.2.1-yc.js
## libjs-jquery
replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/classic/js/jquery-1.4.2.min.js
replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/flat/js/jquery-1.4.2.min.js

View File

@ -0,0 +1,14 @@
# Depends: policykit-1
unusual-interpreter usr/bin/zmsystemctl.pl #!/usr/bin/pkexec
# Intentionally not others-readable, #637685.
non-standard-file-perm etc/zm/zm.conf 0640 != 0644
# Bundled Cake PHP framework, not intended for direct execution:
script-not-executable usr/share/zoneminder/www/api/*
# Annoying but seems to be too much troubles to fix; should be fixed upstream:
script-with-language-extension usr/bin/*.pl
# dh-linktree:
package-contains-broken-symlink usr/share/zoneminder/www/api/lib/Cake/*

View File

@ -0,0 +1,13 @@
/var/log/zm/*.log {
missingok
notifempty
sharedscripts
delaycompress
compress
postrotate
/usr/bin/zmpkg.pl logrot >>/dev/null 2>&1 || :
endscript
daily
rotate 7
maxage 7
}

View File

@ -0,0 +1 @@
rm_conffile /etc/zm/apache.conf 1.28.1-5~

View File

@ -0,0 +1 @@
docs/_build/man/*.1

View File

@ -0,0 +1,66 @@
#! /bin/sh
set -e
if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf
for i in /etc/zm/conf.d/*.conf; do
. $i
done;
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
chown www-data:root /var/log/zm
chown www-data:www-data /var/lib/zm
if [ -z "$2" ]; then
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
fi
# Do this every time the package is installed or upgraded
# Ensure zoneminder is stopped
invoke-rc.d zoneminder stop || true
if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/etc/init.d/mysql" ]; then
#
# Get mysql started if it isn't
#
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
invoke-rc.d mysql start
fi
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
# test if database if already present...
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
if [ $? -ne 0 ]; then
echo "Error creating db."
exit 1;
fi
# This creates the user.
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}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else
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}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
# Add any new PTZ control configurations to the database (will not overwrite)
zmcamtool.pl --import >/dev/null 2>&1
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo 'mysql not found, assuming remote server.'
fi
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
fi
echo "Done Updating, starting ZoneMinder"
invoke-rc.d zoneminder start || true
fi
#DEBHELPER#

View File

@ -0,0 +1,14 @@
#! /bin/sh
set -e
if [ "$1" = "purge" ]; then
echo "
Reminder: to completely remove \"zoneminder\" it may be necessary
* to delete database using the following sample command:
sudo mysqladmin --defaults-file=/etc/mysql/debian.cnf -f drop zm
* to delete remaining data files in "/var/cache/zoneminder".
"
fi
#DEBHELPER#

View File

@ -0,0 +1,11 @@
#!/bin/sh
set -e
## Remove obsolete symlink which is in the way of dh_apache2:
ol="/etc/apache2/conf-available/zoneminder.conf"
if [ -h "${ol}" ]; then
[ "$(readlink ${ol})" = "/etc/zm/apache.conf" ] && rm -f "${ol}"
fi
#DEBHELPER#

View File

@ -0,0 +1,4 @@
d /run/zm 0755 www-data www-data
d /tmp/zm 0755 www-data www-data
d /var/tmp/zm 0755 www-data www-data
d /var/cache/zoneminder/cache 0755 www-data www-data

View File

@ -28,7 +28,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.34.14
Version: 1.34.20
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons

View File

@ -1,3 +1,3 @@
zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low
*
-- Isaac Connor <iconnor@connortechnology.com> Fri, 23 Feb 2018 14:15:59 -0500
zoneminder (1.35.6~20200825.27-xenial) xenial; urgency=low
*
-- Isaac Connor <isaac@zoneminder.com> Tue, 25 Aug 2020 09:28:18 -0400

View File

@ -29,7 +29,7 @@ configure_file(zm.in "${CMAKE_CURRENT_BINARY_DIR}/zm" @ONLY)
#configure_file(zmeventdump.in zmeventdump @ONLY)
# Generate man files for the perl scripts destined for the bin folder
file(GLOB perlscripts "*.pl")
file(GLOB perlscripts "${CMAKE_CURRENT_BINARY_DIR}/*.pl")
FOREACH(PERLSCRIPT ${perlscripts})
get_filename_component(PERLSCRIPTNAME ${PERLSCRIPT} NAME)
POD2MAN(${PERLSCRIPT} zoneminder-${PERLSCRIPTNAME} 8 ${ZM_MANPAGE_DEST_PREFIX})

View File

@ -69,9 +69,9 @@ sub sendCmd {
my $result = undef;
printMsg($cmd, 'Tx');
$self->printMsg($cmd, 'Tx');
my $req = HTTP::Request->new( POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi" );
my $req = HTTP::Request->new(POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi");
$req->content($cmd);
my $res = $self->{ua}->request($req);

View File

@ -143,10 +143,10 @@ sub PutCmd {
} else {
Info('Missing username and password in Control Address.');
}
Fatal($res->status_line);
Error($res->status_line);
}
} else {
Fatal($res->status_line);
Error($res->status_line);
}
} # end unless res->is_success
} # end sub putCmd

View File

@ -49,9 +49,9 @@ my %options;
GetOptions(
'id=i' =>\$id,
'command=s' =>\$options{command},
'xcoord=i' =>\$options{xcoord},
'ycoord=i' =>\$options{ycoord},
'speed=i' =>\$options{speed},
'xcoord=f' =>\$options{xcoord},
'ycoord=f' =>\$options{ycoord},
'speed=f' =>\$options{speed},
'step=i' =>\$options{step},
'panspeed=i' =>\$options{panspeed},
'tiltspeed=i' =>\$options{tiltspeed},

View File

@ -160,7 +160,7 @@ if ( !$server_up ) {
use ZoneMinder::Server qw(CpuLoad);
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr());
Error('Failed Updating status of Server record to Not Running for Id='.$Config{ZM_SERVER_ID}.': '.$dbh->errstr());
}
}
# Server is not up. Some commands can still be handled
@ -173,7 +173,7 @@ if ( !$server_up ) {
print("stopped\n");
exit();
} elsif ( $command ne 'startup' ) {
print('Unable to connect to server using socket at ' . SOCK_FILE . "\n");
print('Unable to connect to server using socket at '.SOCK_FILE."\n");
exit(-1);
}
@ -189,10 +189,10 @@ if ( !$server_up ) {
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
my $attempts = 0;
while( !connect(CLIENT, $saddr) ) {
while ( !connect(CLIENT, $saddr) ) {
$attempts++;
Debug('Waiting for zmdc.pl server process at '.SOCK_FILE.", attempt $attempts");
Fatal("Can't connect: $!") if $attempts > MAX_CONNECT_DELAY;
Debug('Waiting for zmdc.pl server process at '.SOCK_FILE.', attempt '.$attempts);
Fatal('Can\'t connect to zmdc.pl server process at '.SOCK_FILE.': '.$!) if $attempts > MAX_CONNECT_DELAY;
usleep(200000);
} # end while
} elsif ( defined($cpid) ) {
@ -255,13 +255,13 @@ sub run {
close($PID);
} else {
# Log not initialized at this point so use die instead
die "Can't open pid file at ".ZM_PID."\n";
die 'Can\'t open pid file at '.ZM_PID."\n";
}
my $fd = 0;
# This also closes dbh and CLIENT and SERVER
while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
while ( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
POSIX::close($fd++);
}
@ -301,13 +301,14 @@ sub run {
my $timeout = 1;
my $secs_count = 0;
while( !$zm_terminate ) {
while ( !$zm_terminate ) {
if ( $Config{ZM_SERVER_ID} ) {
if ( ! ( $secs_count % 60 ) ) {
while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) {
Warning("Not connected to db ($dbh)".($dbh?' ping('.$dbh->ping().')':''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting');
$dbh = zmDbConnect();
sleep 10 if !$dbh;
}
last if $zm_terminate;

View File

@ -48,6 +48,49 @@ while( 1 ) {
$dbh->do('DELETE FROM Events_Week WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 week)') or Error($dbh->errstr());
$dbh->do('DELETE FROM Events_Month WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 month)') or Error($dbh->errstr());
# Prune the Logs table if required
if ( $Config{ZM_LOG_DATABASE_LIMIT} ) {
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) {
# Number of rows
my $selectLogRowCountSql = 'SELECT count(*) AS `Rows` FROM `Logs`';
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
or Fatal("Can't prepare '$selectLogRowCountSql': ".$dbh->errstr());
my $res = $selectLogRowCountSth->execute()
or Fatal("Can't execute: ".$selectLogRowCountSth->errstr());
my $row = $selectLogRowCountSth->fetchrow_hashref();
my $logRows = $row->{Rows};
if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) {
my $deleteLogByRowsSql = 'DELETE low_priority FROM `Logs` ORDER BY `TimeKey` ASC LIMIT ?';
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
or Fatal("Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr());
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
or Fatal("Can't execute: ".$deleteLogByRowsSth->errstr());
if ( $deleteLogByRowsSth->rows() ) {
Debug('Deleted '.$deleteLogByRowsSth->rows().' log table entries by count');
}
}
} else {
# Time of record
# 7 days is invalid. We need to remove the s
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^(.*)s$/ ) {
$Config{ZM_LOG_DATABASE_LIMIT} = $1;
}
my $deleted_rows;
do {
my $deleteLogByTimeSql =
'DELETE FROM `Logs`
WHERE `TimeKey` < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 100';
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
or Fatal("Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr());
my $res = $deleteLogByTimeSth->execute()
or Fatal("Can't execute: ".$deleteLogByTimeSth->errstr());
$deleted_rows = $deleteLogByTimeSth->rows();
Debug("Deleted $deleted_rows log table entries by time");
} while ( $deleted_rows );
}
} # end if ZM_LOG_DATABASE_LIMIT
sleep($Config{ZM_STATS_UPDATE_INTERVAL});
} # end while (1)

View File

@ -119,7 +119,6 @@ if ( !$monitor->{CanMoveMap} ) {
}
}
Debug("Found monitor for id '$monitor'");
exit(-1) if !zmMemVerify($monitor);
sub Suspend {

View File

@ -121,6 +121,8 @@ GetOptions(
my $dbh = zmDbConnect(undef, { mysql_multi_statements=>1 } );
$Config{ZM_DB_USER} = $dbUser;
$Config{ZM_DB_PASS} = $dbPass;
# we escape dbpass with single quotes so that $ in the password has no effect, but dbpass could have a ' in it.
$dbPass =~ s/'/\\'/g;
if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version) ) {
if ( $Config{ZM_DYN_DB_VERSION} ) {
@ -384,21 +386,22 @@ if ( $version ) {
my $command = 'mysqldump';
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
$command .= " -S".$portOrSocket;
$command .= ' -S'.$portOrSocket;
} else {
$command .= " -h".$host." -P".$portOrSocket;
$command .= ' -h'.$host.' -P'.$portOrSocket;
}
} else {
$command .= " -h".$host;
$command .= ' -h'.$host;
}
if ( $dbUser ) {
$command .= ' -u'.$dbUser;
$command .= ' -p"'.$dbPass.'"' if $dbPass;
$command .= ' -p\''.$dbPass.'\'' if $dbPass;
}
my $backup = "@ZM_TMPDIR@/".$Config{ZM_DB_NAME}."-".$version.".dump";
$command .= " --add-drop-table --databases ".$Config{ZM_DB_NAME}." > ".$backup;
print( "Creating backup to $backup. This may take several minutes.\n" );
print( "Executing '$command'\n" ) if ( logDebugging() );
my $backup = '@ZM_TMPDIR@/'.$Config{ZM_DB_NAME}.'-'.$version.'.dump';
$command .= ' --add-drop-table --databases '.$Config{ZM_DB_NAME}.' > '.$backup;
print("Creating backup to $backup. This may take several minutes.\n");
($command) = $command =~ /(.*)/; # detaint
print("Executing '$command'\n") if logDebugging();
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() ) {
@ -969,7 +972,7 @@ sub patchDB {
my $dbh = shift;
my $version = shift;
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ) if $Config{ZM_DB_HOST};
my $command = 'mysql';
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
@ -977,12 +980,12 @@ sub patchDB {
} else {
$command .= ' -h'.$host.' -P'.$portOrSocket;
}
} else {
} elsif ( $host ) {
$command .= ' -h'.$host;
}
if ( $dbUser ) {
$command .= ' -u'.$dbUser;
$command .= ' -p"'.$dbPass.'"' if $dbPass;
$command .= ' -p\''.$dbPass.'\'' if $dbPass;
}
$command .= ' '.$Config{ZM_DB_NAME}.' < ';
if ( $updateDir ) {

View File

@ -48,11 +48,12 @@ Camera::Camera(
record_audio(p_record_audio),
bytes(0)
{
linesize = width * colours;
pixels = width * height;
imagesize = pixels * colours;
imagesize = height * linesize;
Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",
monitor_id, width, height, colours, subpixelorder, capture);
Debug(2, "New camera id: %d width: %d line size: %d height: %d colours: %d subpixelorder: %d capture: %d",
monitor_id, width, linesize, height, colours, subpixelorder, capture);
monitor = NULL;
}

View File

@ -41,6 +41,7 @@ protected:
Monitor * monitor; // Null on instantiation, set as soon as possible.
SourceType type;
unsigned int width;
unsigned int linesize;
unsigned int height;
unsigned int colours;
unsigned int subpixelorder;
@ -69,6 +70,7 @@ public:
bool IsLibvlc() const { return type == LIBVLC_SRC; }
bool IscURL() const { return type == CURL_SRC; }
unsigned int Width() const { return width; }
unsigned int LineSize() const { return linesize; }
unsigned int Height() const { return height; }
unsigned int Colours() const { return colours; }
unsigned int SubpixelOrder() const { return subpixelorder; }

View File

@ -206,7 +206,12 @@ Event::Event(
/* X264 MP4 video writer */
if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) {
#if ZM_HAVE_VIDEOWRITER_X264MP4
videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams());
videowriter = new X264MP4Writer(video_file,
monitor->Width(),
monitor->Height(),
monitor->Colours(),
monitor->SubpixelOrder(),
monitor->GetOptEncoderParamsVec());
#else
Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)");
#endif

View File

@ -807,29 +807,38 @@ Debug(1, "Loading image");
if ( send_raw ) {
#if HAVE_SENDFILE
fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size);
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size) ) {
fclose(fdj); /* Close the file handle */
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
return false;
}
if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) {
/* sendfile() failed, use standard way instead */
img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj );
img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj);
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
fclose(fdj); /* Close the file handle */
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
return false;
}
}
#else
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
if (
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) )
||
( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 )
) {
fclose(fdj); /* Close the file handle */
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
return false;
}
#endif
fclose(fdj); /* Close the file handle */
} else {
Debug(3, "Content length: %d", img_buffer_size);
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
if (
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) )
||
( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) ) {
Error("Unable to send stream frame: %s", strerror(errno));
return false;
}

View File

@ -40,6 +40,7 @@ extern "C" {
#include <libavutil/mathematics.h>
#include <libavutil/avstring.h>
#include "libavutil/audio_fifo.h"
#include "libavutil/imgutils.h"
/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)

View File

@ -63,31 +63,31 @@ static enum AVPixelFormat get_hw_format(
}
#if !LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0)
static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) {
enum AVPixelFormat fmt;
switch (type) {
enum AVPixelFormat fmt;
switch (type) {
case AV_HWDEVICE_TYPE_VAAPI:
fmt = AV_PIX_FMT_VAAPI;
break;
fmt = AV_PIX_FMT_VAAPI;
break;
case AV_HWDEVICE_TYPE_DXVA2:
fmt = AV_PIX_FMT_DXVA2_VLD;
break;
fmt = AV_PIX_FMT_DXVA2_VLD;
break;
case AV_HWDEVICE_TYPE_D3D11VA:
fmt = AV_PIX_FMT_D3D11;
break;
fmt = AV_PIX_FMT_D3D11;
break;
case AV_HWDEVICE_TYPE_VDPAU:
fmt = AV_PIX_FMT_VDPAU;
break;
fmt = AV_PIX_FMT_VDPAU;
break;
case AV_HWDEVICE_TYPE_CUDA:
fmt = AV_PIX_FMT_CUDA;
break;
fmt = AV_PIX_FMT_CUDA;
break;
case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
fmt = AV_PIX_FMT_VIDEOTOOLBOX;
break;
fmt = AV_PIX_FMT_VIDEOTOOLBOX;
break;
default:
fmt = AV_PIX_FMT_NONE;
break;
}
return fmt;
fmt = AV_PIX_FMT_NONE;
break;
}
return fmt;
}
#endif
#endif
@ -174,6 +174,20 @@ FfmpegCamera::FfmpegCamera(
} else {
Panic("Unexpected colours: %d", colours);
}
// sws_scale needs 32bit aligned width and an extra 16 bytes padding, so recalculate imagesize, which was width*height*bytes_per_pixel
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
alignment = 32;
imagesize = av_image_get_buffer_size(imagePixFormat, width, height, alignment);
// av_image_get_linesize isn't aligned, so we have to do that.
linesize = FFALIGN(av_image_get_linesize(imagePixFormat, width, 0), alignment);
#else
alignment = 1;
linesize = FFALIGN(av_image_get_linesize(imagePixFormat, width, 0), alignment);
imagesize = avpicture_get_size(imagePixFormat, width, height);
#endif
Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, imagesize);
} // FfmpegCamera::FfmpegCamera
FfmpegCamera::~FfmpegCamera() {
@ -194,12 +208,12 @@ void FfmpegCamera::Terminate() {
int FfmpegCamera::PrimeCapture() {
if ( mCanCapture ) {
Info("Priming capture from %s, Closing", mPath.c_str());
Debug(1, "Priming capture from %s, Closing", mPath.c_str());
Close();
}
mVideoStreamId = -1;
mAudioStreamId = -1;
Info("Priming capture from %s", mPath.c_str());
Debug(1, "Priming capture from %s", mPath.c_str());
return OpenFfmpeg();
}
@ -608,16 +622,6 @@ int FfmpegCamera::OpenFfmpeg() {
mFrame->width = width;
mFrame->height = height;
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
int pSize = av_image_get_buffer_size(imagePixFormat, width, height, 1);
#else
int pSize = avpicture_get_size(imagePixFormat, width, height);
#endif
if ( (unsigned int)pSize != imagesize ) {
Error("Image size mismatch. Required: %d Available: %d", pSize, imagesize);
return -1;
}
#if HAVE_LIBSWSCALE
if ( !sws_isSupportedInput(mVideoCodecContext->pix_fmt) ) {
@ -976,10 +980,12 @@ int FfmpegCamera::CaptureAndRecord(
return -1;
}
#if HAVE_LIBAVUTIL_HWCONTEXT_H
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
if ( (ret == AVERROR_INVALIDDATA ) && (hw_pix_fmt != AV_PIX_FMT_NONE) ) {
use_hwaccel = false;
return -1;
}
#endif
#endif
}
zm_av_packet_unref(&packet);
@ -1087,11 +1093,18 @@ int FfmpegCamera::transfer_to_image(
int size = av_image_fill_arrays(
output_frame->data, output_frame->linesize,
directbuffer, imagePixFormat, width, height,
(AV_PIX_FMT_RGBA == imagePixFormat ? 32 : 1)
alignment
);
if ( size < 0 ) {
Error("Problem setting up data pointers into image %s",
av_make_error_string(size).c_str());
} else {
Debug(4, "av_image_fill_array %dx%d alignment: %d = %d, buffer size is %d",
width, height, alignment, size, image.Size());
}
Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, imagesize);
if ( linesize != (unsigned int)output_frame->linesize[0] ) {
Error("Bad linesize expected %d got %d", linesize, output_frame->linesize[0]);
}
#else
avpicture_fill((AVPicture *)output_frame, directbuffer,

View File

@ -45,6 +45,8 @@ class FfmpegCamera : public Camera {
std::string hwaccel_device;
int frameCount;
int alignment; /* ffmpeg wants line sizes to be 32bit aligned. Especially 4.3+ */
#if HAVE_LIBAVFORMAT
AVFormatContext *mFormatContext;

View File

@ -19,7 +19,7 @@ FFmpeg_Input::~FFmpeg_Input() {
avcodec_close(streams[i].context);
streams[i].context = NULL;
}
delete streams;
delete[] streams;
streams = NULL;
}
if ( frame ) {

File diff suppressed because it is too large Load Diff

View File

@ -152,9 +152,11 @@ protected:
static struct zm_error_mgr jpg_err;
unsigned int width;
unsigned int linesize;
unsigned int height;
unsigned int pixels;
unsigned int colours;
unsigned int padding;
unsigned int size;
unsigned int subpixelorder;
unsigned long allocation;
@ -165,15 +167,18 @@ protected:
public:
Image();
explicit Image( const char *filename );
Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0);
explicit Image(const char *filename);
Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
explicit Image( const Image &p_image );
explicit Image( const AVFrame *frame );
~Image();
static void Initialise();
static void Deinitialise();
inline unsigned int Width() const { return width; }
inline unsigned int LineSize() const { return linesize; }
inline unsigned int Height() const { return height; }
inline unsigned int Pixels() const { return pixels; }
inline unsigned int Colours() const { return colours; }
@ -182,7 +187,7 @@ public:
/* Internal buffer should not be modified from functions outside of this class */
inline const uint8_t* Buffer() const { return buffer; }
inline const uint8_t* Buffer( unsigned int x, unsigned int y= 0 ) const { return &buffer[colours*((y*width)+x)]; }
inline const uint8_t* Buffer( unsigned int x, unsigned int y= 0 ) const { return &buffer[(y*linesize)+x]; }
/* Request writeable buffer */
uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder);
@ -193,21 +198,34 @@ public:
if ( !holdbuffer )
DumpImgBuffer();
width = height = colours = size = pixels = subpixelorder = 0;
width = linesize = height = colours = size = pixels = subpixelorder = 0;
}
void Assign( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size);
void Assign( const Image &image );
void AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype);
void Assign(
unsigned int p_width,
unsigned int p_height,
unsigned int p_colours,
unsigned int p_subpixelorder,
const uint8_t* new_buffer,
const size_t buffer_size);
void Assign(const Image &image);
void AssignDirect(
const unsigned int p_width,
const unsigned int p_height,
const unsigned int p_colours,
const unsigned int p_subpixelorder,
uint8_t *new_buffer,
const size_t buffer_size,
const int p_buffertype);
inline void CopyBuffer( const Image &image ) {
inline void CopyBuffer(const Image &image) {
Assign(image);
}
inline Image &operator=( const Image &image ) {
inline Image &operator=(const Image &image) {
Assign(image);
return *this;
}
inline Image &operator=( const unsigned char *new_buffer ) {
inline Image &operator=(const unsigned char *new_buffer) {
(*fptr_imgbufcpy)(buffer, new_buffer, size);
return *this;
}

View File

@ -504,7 +504,7 @@ LocalCamera::LocalCamera(
subpixelorder = ZM_SUBPIX_ORDER_NONE;
} else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8 ) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
if ( config.cpu_extensions && sseversion >= 35 ) {
if ( config.cpu_extensions && sse_version >= 35 ) {
conversion_fptr = &ssse3_convert_yuyv_gray8;
Debug(2,"Using SSSE3 YUYV->grayscale fast conversion");
} else {
@ -616,7 +616,7 @@ LocalCamera::LocalCamera(
}
} else if ( (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_GRAY8 ) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
if ( config.cpu_extensions && sseversion >= 35 ) {
if ( config.cpu_extensions && sse_version >= 35 ) {
conversion_fptr = &ssse3_convert_yuyv_gray8;
Debug(2,"Using SSSE3 YUYV->grayscale fast conversion");
} else {

View File

@ -131,12 +131,12 @@ Monitor::MonitorLink::~MonitorLink() {
}
bool Monitor::MonitorLink::connect() {
if ( !last_connect_time || (time( 0 ) - last_connect_time) > 60 ) {
if ( !last_connect_time || (time( 0 ) - last_connect_time) > ZM_MAX_RESTART_DELAY ) {
last_connect_time = time( 0 );
mem_size = sizeof(SharedData) + sizeof(TriggerData);
Debug( 1, "link.mem.size=%d", mem_size );
Debug(1, "link.mem.size=%d", mem_size);
#if ZM_MEM_MAPPED
map_fd = open( mem_file, O_RDWR, (mode_t)0600 );
if ( map_fd < 0 ) {
@ -379,6 +379,7 @@ Monitor::Monitor(
strncpy(event_prefix, p_event_prefix, sizeof(event_prefix)-1);
strncpy(label_format, p_label_format, sizeof(label_format)-1);
Debug(1, "encoder params %s", encoderparams.c_str());
// Change \n to actual line feeds
char *token_ptr = label_format;
@ -531,6 +532,7 @@ Monitor::Monitor(
shared_data->last_write_index, shared_data->last_write_time );
sleep(1);
}
ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(),
image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize());
adaptive_skip = true;
@ -605,7 +607,7 @@ bool Monitor::connect() {
if ( mem_ptr == MAP_FAILED )
Fatal("Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno);
if ( mem_ptr == NULL ) {
Error("mmap gave a null address:");
Error("mmap gave a NULL address:");
} else {
Debug(3, "mmapped to %p", mem_ptr);
}
@ -1406,9 +1408,6 @@ bool Monitor::Analyse() {
score += trigger_data->trigger_score;
Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score);
if ( !event ) {
// How could it have a length already?
//if ( cause.length() )
//cause += ", ";
cause += trigger_data->trigger_cause;
}
Event::StringSet noteSet;
@ -1488,6 +1487,7 @@ bool Monitor::Analyse() {
score += 50;
}
} else {
Debug(1, "Linked monitor %d %d is not connected. Connecting.", i, linked_monitors[i]->Id());
linked_monitors[i]->connect();
}
} // end foreach linked_monit
@ -1502,7 +1502,7 @@ bool Monitor::Analyse() {
if ( section_length
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length )
&& ( (event_close_mode != CLOSE_TIME) || ! ( timestamp->tv_sec % section_length ) )
&& ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) )
) {
Info("%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d",
name, image_count, event->Id(),
@ -1515,7 +1515,6 @@ bool Monitor::Analyse() {
} // end if event
if ( !event ) {
// Create event
event = new Event(this, *timestamp, "Continuous", noteSetMap, videoRecording);
shared_data->last_event = event->Id();
@ -1529,7 +1528,6 @@ bool Monitor::Analyse() {
if ( state == IDLE ) {
shared_data->state = state = TAPE;
}
} // end if ! event
} // end if function == RECORD || function == MOCORD)
} // end if !signal_change && signal
@ -1542,7 +1540,7 @@ bool Monitor::Analyse() {
&& (event_close_mode == CLOSE_ALARM)
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= min_section_length )
) {
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
name, image_count, event->Id());
closeEvent();
} else if ( event ) {
@ -1553,7 +1551,6 @@ bool Monitor::Analyse() {
);
}
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
shared_data->state = state = ALARM;
// lets construct alarm cause. It will contain cause + names of zones alarmed
std::string alarm_cause = "";
for ( int i=0; i < n_zones; i++ ) {
@ -1638,6 +1635,7 @@ bool Monitor::Analyse() {
event->SavePreAlarmFrames();
}
}
shared_data->state = state = ALARM;
} else if ( state != PREALARM ) {
Info("%s: %03d - Gone into prealarm state", name, image_count);
shared_data->state = state = PREALARM;
@ -1697,17 +1695,10 @@ bool Monitor::Analyse() {
} // end if zone is alarmed
} // end foreach zone
if ( got_anal_image ) {
if ( state == PREALARM )
Event::AddPreAlarmFrame(snap_image, *timestamp, score, &alarm_image);
else
event->AddFrame(snap_image, *timestamp, score, &alarm_image);
} else {
if ( state == PREALARM )
Event::AddPreAlarmFrame(snap_image, *timestamp, score);
else
event->AddFrame(snap_image, *timestamp, score);
}
if ( state == PREALARM )
Event::AddPreAlarmFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
else
event->AddFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
} else {
// Not doing alarm frame storage
if ( state == PREALARM ) {
@ -1743,7 +1734,6 @@ bool Monitor::Analyse() {
//set up video store data
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
video_store_data->recording = event->StartTime();
}
} // end if event
@ -2498,7 +2488,7 @@ int Monitor::Capture() {
if ( capture_image->Size() > camera->ImageSize() ) {
Error("Captured image %d does not match expected size %d check width, height and colour depth",
capture_image->Size(),camera->ImageSize() );
capture_image->Size(), camera->ImageSize() );
return -1;
}

View File

@ -220,7 +220,7 @@ protected:
}
inline bool isConnected() const {
return( connected );
return connected && shared_data->valid;
}
inline time_t getLastConnectTime() const {
return( last_connect_time );
@ -463,7 +463,8 @@ public:
int GetOptSaveJPEGs() const { return savejpegs; }
VideoWriter GetOptVideoWriter() const { return videowriter; }
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return &encoderparamsvec; }
const std::vector<EncoderParameter_t>* GetOptEncoderParamsVec() const { return &encoderparamsvec; }
const std::string GetOptEncoderParams() const { return encoderparams; }
uint64_t GetVideoWriterEventId() const { return video_store_data->current_event; }
void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; }
struct timeval GetVideoWriterStartTime() const { return video_store_data->recording; }

View File

@ -329,8 +329,11 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
gettimeofday(&frameStartTime, NULL);
fputs("--ZoneMinderFrame\r\nContent-Type: image/jpeg\r\n", stdout);
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
if (
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size))
||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
) {
if ( !zm_terminate )
Warning("Unable to send stream frame: %s", strerror(errno));
return false;
@ -385,7 +388,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
gettimeofday(&frameStartTime, NULL);
fputs("--ZoneMinderFrame\r\n", stdout);
switch( type ) {
switch ( type ) {
case STREAM_JPEG :
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
fputs("Content-Type: image/jpeg\r\n", stdout);
@ -410,8 +413,11 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
Error("Unexpected frame type %d", type);
return false;
}
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
if (
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size))
||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
) {
if ( !zm_terminate ) {
// If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate
Warning("Unable to send stream frame: %s", strerror(errno));

View File

@ -618,8 +618,8 @@ int RemoteCameraHttp::GetResponse() {
static char *content_type_header;
static char *boundary_header;
static char *authenticate_header;
static char subcontent_length_header[32];
static char subcontent_type_header[64];
static char subcontent_length_header[33];
static char subcontent_type_header[65];
static char http_version[16];
static char status_code[16];
@ -892,25 +892,37 @@ int RemoteCameraHttp::GetResponse() {
}
}
Debug( 6, "%d: %s", subheader_len, subheader_ptr );
Debug(6, "%d: %s", subheader_len, subheader_ptr);
if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) ) {
if ( (crlf = mempbrk(subheader_ptr, "\r\n", subheader_len)) ) {
//subheaders[n_subheaders++] = subheader_ptr;
n_subheaders++;
if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) ) {
if ( !boundary_header && (strncasecmp(subheader_ptr, content_boundary, content_boundary_len) == 0) ) {
boundary_header = subheader_ptr;
Debug( 4, "Got boundary subheader '%s'", subheader_ptr );
} else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) ) {
strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) );
*(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0';
Debug( 4, "Got content length subheader '%s'", subcontent_length_header );
Debug(4, "Got boundary subheader '%s'", subheader_ptr);
} else if (
!subcontent_length_header[0]
&&
(strncasecmp(subheader_ptr, content_length_match, content_length_match_len) == 0)
) {
strncpy(
subcontent_length_header,
subheader_ptr+content_length_match_len,
sizeof(subcontent_length_header)-1
);
*(subcontent_length_header+strcspn(subcontent_length_header, "\r\n")) = '\0';
Debug(4, "Got content length subheader '%s'", subcontent_length_header);
} else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) ) {
strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) );
*(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0';
Debug( 4, "Got content type subheader '%s'", subcontent_type_header );
strncpy(
subcontent_type_header,
subheader_ptr+content_type_match_len,
sizeof(subcontent_type_header)-1
);
*(subcontent_type_header+strcspn(subcontent_type_header, "\r\n")) = '\0';
Debug(4, "Got content type subheader '%s'", subcontent_type_header);
} else {
Debug( 6, "Got ignored subheader '%s' found", subheader_ptr );
Debug(6, "Got ignored subheader '%s' found", subheader_ptr);
}
subheader_ptr = crlf;
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );

View File

@ -35,7 +35,7 @@
#include <curl/curl.h>
#endif
unsigned int sseversion = 0;
unsigned int sse_version = 0;
unsigned int neonversion = 0;
std::string trimSet(std::string str, std::string trimset) {
@ -44,12 +44,9 @@ std::string trimSet(std::string str, std::string trimset) {
size_t endpos = str.find_last_not_of(trimset); // Find the first character position from reverse af
// if all spaces or empty return an empty string
if(( std::string::npos == startpos ) || ( std::string::npos == endpos))
{
if ( ( std::string::npos == startpos ) || ( std::string::npos == endpos ) )
return std::string("");
}
else
return str.substr( startpos, endpos-startpos+1 );
return str.substr(startpos, endpos-startpos+1);
}
std::string trimSpaces(const std::string &str) {
@ -57,48 +54,46 @@ std::string trimSpaces(const std::string &str) {
}
std::string replaceAll(std::string str, std::string from, std::string to) {
if(from.empty())
if ( from.empty() )
return str;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
while ( (start_pos = str.find(from, start_pos)) != std::string::npos ) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
return str;
}
const std::string stringtf( const char *format, ... )
{
const std::string stringtf( const char *format, ... ) {
va_list ap;
char tempBuffer[8192];
std::string tempString;
va_start(ap, format );
vsnprintf( tempBuffer, sizeof(tempBuffer), format , ap );
va_start(ap, format);
vsnprintf(tempBuffer, sizeof(tempBuffer), format , ap);
va_end(ap);
tempString = tempBuffer;
return( tempString );
return tempString;
}
const std::string stringtf( const std::string format, ... )
{
const std::string stringtf(const std::string format, ...) {
va_list ap;
char tempBuffer[8192];
std::string tempString;
va_start(ap, format );
vsnprintf( tempBuffer, sizeof(tempBuffer), format.c_str() , ap );
va_start(ap, format);
vsnprintf(tempBuffer, sizeof(tempBuffer), format.c_str(), ap);
va_end(ap);
tempString = tempBuffer;
return( tempString );
return tempString;
}
bool startsWith(const std::string &haystack, const std::string &needle) {
return( haystack.substr(0, needle.length()) == needle );
return ( haystack.substr(0, needle.length()) == needle );
}
StringVector split(const std::string &string, const std::string &chars, int limit) {
@ -145,8 +140,7 @@ const std::string join(const StringVector &v, const char * delim=",") {
const std::string base64Encode(const std::string &inString) {
static char base64_table[64] = { '\0' };
if ( !base64_table[0] )
{
if ( !base64_table[0] ) {
int i = 0;
for ( char c = 'A'; c <= 'Z'; c++ )
base64_table[i++] = c;
@ -159,59 +153,52 @@ const std::string base64Encode(const std::string &inString) {
}
std::string outString;
outString.reserve( 2 * inString.size() );
outString.reserve(2 * inString.size());
const char *inPtr = inString.c_str();
while( *inPtr )
{
while ( *inPtr ) {
unsigned char selection = *inPtr >> 2;
unsigned char remainder = (*inPtr++ & 0x03) << 4;
outString += base64_table[selection];
if ( *inPtr )
{
if ( *inPtr ) {
selection = remainder | (*inPtr >> 4);
remainder = (*inPtr++ & 0x0f) << 2;
outString += base64_table[selection];
if ( *inPtr )
{
if ( *inPtr ) {
selection = remainder | (*inPtr >> 6);
outString += base64_table[selection];
selection = (*inPtr++ & 0x3f);
outString += base64_table[selection];
}
else
{
} else {
outString += base64_table[remainder];
outString += '=';
}
}
else
{
} else {
outString += base64_table[remainder];
outString += '=';
outString += '=';
}
}
return( outString );
return outString;
}
int split(const char* string, const char delim, std::vector<std::string>& items) {
if(string == NULL)
if ( string == NULL )
return -1;
if(string[0] == 0)
if ( string[0] == 0 )
return -2;
std::string str(string);
while(true) {
while ( true ) {
size_t pos = str.find(delim);
items.push_back(str.substr(0, pos));
str.erase(0, pos+1);
if(pos == std::string::npos)
if ( pos == std::string::npos )
break;
}
@ -219,16 +206,16 @@ int split(const char* string, const char delim, std::vector<std::string>& items)
}
int pairsplit(const char* string, const char delim, std::string& name, std::string& value) {
if(string == NULL)
if ( string == NULL )
return -1;
if(string[0] == 0)
if ( string[0] == 0 )
return -2;
std::string str(string);
size_t pos = str.find(delim);
if(pos == std::string::npos || pos == 0 || pos >= str.length())
if ( pos == std::string::npos || pos == 0 || pos >= str.length() )
return -3;
name = str.substr(0, pos);
@ -240,7 +227,7 @@ int pairsplit(const char* string, const char delim, std::string& name, std::stri
/* Detect special hardware features, such as SIMD instruction sets */
void hwcaps_detect() {
neonversion = 0;
sseversion = 0;
sse_version = 0;
#if (defined(__i386__) || defined(__x86_64__))
/* x86 or x86-64 processor */
uint32_t r_edx, r_ecx, r_ebx;
@ -277,33 +264,33 @@ void hwcaps_detect() {
);
#endif
if (r_ebx & 0x00000020) {
sseversion = 52; /* AVX2 */
Debug(1,"Detected a x86\\x86-64 processor with AVX2");
} else if (r_ecx & 0x10000000) {
sseversion = 51; /* AVX */
Debug(1,"Detected a x86\\x86-64 processor with AVX");
} else if (r_ecx & 0x00100000) {
sseversion = 42; /* SSE4.2 */
Debug(1,"Detected a x86\\x86-64 processor with SSE4.2");
} else if (r_ecx & 0x00080000) {
sseversion = 41; /* SSE4.1 */
Debug(1,"Detected a x86\\x86-64 processor with SSE4.1");
} else if (r_ecx & 0x00000200) {
sseversion = 35; /* SSSE3 */
if ( r_ebx & 0x00000020 ) {
sse_version = 52; /* AVX2 */
Debug(1, "Detected a x86\\x86-64 processor with AVX2");
} else if ( r_ecx & 0x10000000 ) {
sse_version = 51; /* AVX */
Debug(1, "Detected a x86\\x86-64 processor with AVX");
} else if ( r_ecx & 0x00100000 ) {
sse_version = 42; /* SSE4.2 */
Debug(1, "Detected a x86\\x86-64 processor with SSE4.2");
} else if ( r_ecx & 0x00080000 ) {
sse_version = 41; /* SSE4.1 */
Debug(1, "Detected a x86\\x86-64 processor with SSE4.1");
} else if ( r_ecx & 0x00000200 ) {
sse_version = 35; /* SSSE3 */
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
} else if (r_ecx & 0x00000001) {
sseversion = 30; /* SSE3 */
Debug(1,"Detected a x86\\x86-64 processor with SSE3");
} else if (r_edx & 0x04000000) {
sseversion = 20; /* SSE2 */
Debug(1,"Detected a x86\\x86-64 processor with SSE2");
} else if (r_edx & 0x02000000) {
sseversion = 10; /* SSE */
Debug(1,"Detected a x86\\x86-64 processor with SSE");
} else if ( r_ecx & 0x00000001 ) {
sse_version = 30; /* SSE3 */
Debug(1, "Detected a x86\\x86-64 processor with SSE3");
} else if ( r_edx & 0x04000000 ) {
sse_version = 20; /* SSE2 */
Debug(1, "Detected a x86\\x86-64 processor with SSE2");
} else if ( r_edx & 0x02000000 ) {
sse_version = 10; /* SSE */
Debug(1, "Detected a x86\\x86-64 processor with SSE");
} else {
sseversion = 0;
Debug(1,"Detected a x86\\x86-64 processor");
sse_version = 0;
Debug(1, "Detected a x86\\x86-64 processor");
}
#elif defined(__arm__)
// ARM processor in 32bit mode

View File

@ -59,7 +59,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes);
void timespec_diff(struct timespec *start, struct timespec *end, struct timespec *diff);
void hwcaps_detect();
extern unsigned int sseversion;
extern unsigned int sse_version;
extern unsigned int neonversion;
char *timeval_to_string( struct timeval tv );

View File

@ -37,11 +37,12 @@ VideoStore::VideoStore(
const char *format_in,
AVStream *p_video_in_stream,
AVStream *p_audio_in_stream,
Monitor *monitor
Monitor *p_monitor
) {
video_in_stream = p_video_in_stream;
audio_in_stream = p_audio_in_stream;
monitor = p_monitor;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
//video_in_ctx = avcodec_alloc_context3(NULL);
@ -213,11 +214,18 @@ VideoStore::VideoStore(
}
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
#if 0
# This is commented out because we are only doing passthrough right now
/* I'm not entirely sure that this is a good idea. We may have to do it someday but really only when transcoding
* * think what I was trying to achieve here was to have zm_dump_codecpar output nice info
* */
#if 0
AVDictionary *opts = 0;
ret = av_dict_parse_string(&opts, monitor->GetOptEncoderParams().c_str(), "=", ",", 0);
if ( ret < 0 ) {
Warning("Could not parse ffmpeg encoder options '%s'", monitor->GetOptEncoderParams().c_str());
}
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
Warning("Can't open video codec (%s) %s",
video_out_codec->name,
@ -404,21 +412,39 @@ bool VideoStore::open() {
}
zm_dump_stream_format(oc, 0, 0, 1);
if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1);
if ( audio_out_stream ) zm_dump_stream_format(oc, 1, 0, 1);
AVDictionary *opts = NULL;
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
// Shiboleth reports that this may break seeking in mp4 before it downloads
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
// av_dict_set(&opts, "movflags",
// "frag_keyframe+empty_moov+default_base_moof", 0);
std::string option_string = monitor->GetOptEncoderParams();
ret = av_dict_parse_string(&opts, option_string.c_str(), "=", ",\n", 0);
if ( ret < 0 ) {
Warning("Could not parse ffmpeg output options '%s'", option_string.c_str());
}
const AVDictionaryEntry *movflags_entry = av_dict_get(opts, "movflags", NULL, AV_DICT_MATCH_CASE);
if ( !movflags_entry ) {
Debug(1, "setting movflags to frag_keyframe+empty_moov");
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
// Shiboleth reports that this may break seeking in mp4 before it downloads
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
// av_dict_set(&opts, "movflags",
// "frag_keyframe+empty_moov+default_base_moof", 0);
} else {
Debug(1, "using movflags %s", movflags_entry->value);
}
if ( (ret = avformat_write_header(oc, &opts)) < 0 ) {
// if ((ret = avformat_write_header(oc, &opts)) < 0) {
Warning("Unable to set movflags to frag_custom+dash+delay_moov");
/* Write the stream header, if any. */
Warning("Unable to set movflags trying with defaults.");
ret = avformat_write_header(oc, NULL);
} else if (av_dict_count(opts) != 0) {
Warning("some options not set");
} else if ( av_dict_count(opts) != 0 ) {
Info("some options not used, turn on debugging for a list.");
AVDictionaryEntry *e = NULL;
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Debug(1, "Encoder Option %s=>%s", e->key, e->value);
if ( !e->value ) {
av_dict_set(&opts, e->key, NULL, 0);
}
}
}
if ( opts ) av_dict_free(&opts);
if ( ret < 0 ) {

View File

@ -19,7 +19,6 @@ extern "C" {
class VideoStore {
private:
AVOutputFormat *out_format;
AVFormatContext *oc;
@ -30,6 +29,7 @@ private:
AVStream *video_in_stream;
AVStream *audio_in_stream;
Monitor *monitor;
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
AVPacket opkt;

View File

@ -227,7 +227,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
Debug(4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y);
/* if(config.cpu_extensions && sseversion >= 20) {
/* if(config.cpu_extensions && sse_version >= 20) {
sse2_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);
} else {
std_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);

View File

@ -259,7 +259,8 @@ int main(int argc, char *argv[]) {
Debug(1, "Failed to prime capture of initial monitor");
}
prime_capture_log_count ++;
sleep(10);
if ( !zm_terminate )
sleep(10);
continue;
}

View File

@ -80,7 +80,7 @@ fi;
if [ "$DISTROS" == "" ]; then
if [ "$RELEASE" != "" ]; then
DISTROS="xenial,bionic,disco,eoan,focal,trusty"
DISTROS="xenial,bionic,focal,trusty"
else
DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
fi;
@ -220,14 +220,19 @@ IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
fi;
# Generate Changlog
if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]; then
if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]
then
cp -Rpd distros/ubuntu1204 debian
else
if [ "$DISTRO" == "wheezy" ]; then
cp -Rpd distros/debian debian
else
cp -Rpd distros/ubuntu1604 debian
fi;
elif [ "$DISTRO" == "wheezy" ]
then
cp -Rpd distros/debian debian
elif [ "$DISTRO" == "beowulf" ]
then
cp -Rpd distros/beowulf debian
else
cp -Rpd distros/ubuntu1604 debian
fi;
if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then

View File

@ -37,7 +37,7 @@ echo "Target subfolder set to $targetfolder"
echo
echo "Running \$(rsync -v -e 'ssh -vvv' build/*.{rpm,deb,dsc,tar.xz,buildinfo,changes} zmrepo@zmrepo.zoneminder.com:${targetfolder}/ 2>&1)"
rsync -v --ignore-missing-args --exclude 'external-repo.noarch.rpm' -e 'ssh -vvv' build/*.{rpm,deb,dsc,tar.xz,buildinfo,changes} zmrepo@zmrepo.zoneminder.com:${targetfolder}/ 2>&1
rsync -v --ignore-missing-args --exclude 'external-repo.noarch.rpm' -e 'ssh -v' build/*.{rpm,deb,dsc,tar.xz,buildinfo,changes} zmrepo@zmrepo.zoneminder.com:${targetfolder}/ 2>&1
if [ "$?" -eq 0 ]; then
echo
echo "Files copied successfully."

View File

@ -1 +1 @@
1.34.14
1.34.20

View File

@ -19,7 +19,7 @@ $statusData = array(
'limit' => 1,
'elements' => array(
'MonitorCount' => array( 'sql' => 'count(*)' ),
'ActiveMonitorCount' => array( 'sql' => 'count(if(Function != \'None\',1,NULL))' ),
'ActiveMonitorCount' => array( 'sql' => 'count(if(`Function` != \'None\',1,NULL))' ),
'State' => array( 'func' => 'daemonCheck()?'.translate('Running').':'.translate('Stopped') ),
'Load' => array( 'func' => 'getLoad()' ),
'Disk' => array( 'func' => 'getDiskPercent()' ),
@ -211,17 +211,17 @@ function collectData() {
$values = array();
$elements = &$entitySpec['elements'];
$lc_elements = array_change_key_case( $elements );
$lc_elements = array_change_key_case($elements);
$id = false;
if ( isset($_REQUEST['id']) )
if ( !is_array($_REQUEST['id']) )
$id = array( validJsStr($_REQUEST['id']) );
else
$id = array_values( $_REQUEST['id'] );
$id = array_values($_REQUEST['id']);
if ( !isset($_REQUEST['element']) )
$_REQUEST['element'] = array_keys( $elements );
$_REQUEST['element'] = array_keys($elements);
else if ( !is_array($_REQUEST['element']) )
$_REQUEST['element'] = array( validJsStr($_REQUEST['element']) );
@ -235,18 +235,18 @@ function collectData() {
foreach ( $_REQUEST['element'] as $element ) {
if ( !($elementData = $lc_elements[strtolower($element)]) )
ajaxError( 'Bad '.validJsStr($_REQUEST['entity']).' element '.$element );
ajaxError('Bad '.validJsStr($_REQUEST['entity']).' element '.$element);
if ( isset($elementData['func']) )
$data[$element] = eval( 'return( '.$elementData['func'].' );' );
$data[$element] = eval('return( '.$elementData['func'].' );');
else if ( isset($elementData['postFunc']) )
$postFuncs[$element] = $elementData['postFunc'];
else if ( isset($elementData['zmu']) )
$data[$element] = exec( escapeshellcmd( getZmuCommand( ' '.$elementData['zmu'] ) ) );
$data[$element] = exec(escapeshellcmd(getZmuCommand(' '.$elementData['zmu'])));
else {
if ( isset($elementData['sql']) )
$fieldSql[] = $elementData['sql'].' as '.$element;
else
$fieldSql[] = $element;
$fieldSql[] = '`'.$element.'`';
if ( isset($elementData['table']) && isset($elementData['join']) ) {
$joinSql[] = 'left join '.$elementData['table'].' on '.$elementData['join'];
}
@ -285,7 +285,7 @@ function collectData() {
preg_match('/^(\w+)\s*(ASC|DESC)?( NULLS FIRST)?$/i', $sort_field, $matches);
if ( count($matches) ) {
if ( in_array($matches[1], $fieldSql) ) {
if ( in_array($matches[1], $fieldSql) or in_array('`'.$matches[1].'`', $fieldSql) ) {
$sql .= $matches[1];
} else {
ZM\Error('Sort field ' . $matches[1] . ' not in SQL Fields');
@ -296,7 +296,7 @@ function collectData() {
$sql .= ' '.strtoupper($matches[3]);
}
} else {
ZM\Error("Sort field didn't match regexp $sort_field");
ZM\Error('Sort field didn\'t match regexp '.$sort_field);
}
} # end foreach sort field
} # end if has sort
@ -310,7 +310,7 @@ function collectData() {
if ( !empty( $limit ) )
$sql .= ' limit '.$limit_offset.$limit;
if ( isset($limit) && $limit == 1 ) {
if ( $sqlData = dbFetchOne( $sql, NULL, $values ) ) {
if ( $sqlData = dbFetchOne($sql, NULL, $values) ) {
foreach ( $postFuncs as $element=>$func )
$sqlData[$element] = eval( 'return( '.$func.'( $sqlData ) );' );
$data = array_merge( $data, $sqlData );

View File

@ -102,21 +102,21 @@ CakeLog::config('debug', array(
'engine' => 'File',
'types' => array('notice', 'info', 'debug'),
'file' => 'cake_debug',
'path' => '@ZM_LOGDIR@/'
'path' => '@ZM_LOGDIR@/'
));
CakeLog::config('error', array(
'engine' => 'File',
'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'cake_error',
'path' => '@ZM_LOGDIR@/'
'path' => '@ZM_LOGDIR@/'
));
CakeLog::config('custom_path', array(
'engine' => 'File',
'path' => '@ZM_LOGDIR@/'
'engine' => 'File',
'path' => '@ZM_LOGDIR@/'
));
Configure::write('ZM_CONFIG', '@ZM_CONFIG@');
Configure::write('ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@');
Configure::write('ZM_CONFIG', '@ZM_CONFIG@');
Configure::write('ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@');
Configure::write('ZM_VERSION', '@VERSION@');
Configure::write('ZM_API_VERSION', '@API_VERSION@');
@ -128,27 +128,3 @@ global $configvals;
foreach( $configvals as $key => $value) {
Configure::write($key, $value);
}
if ( 0 ) {
// No longer needed, but I want to keep the code for reference
//
// For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID
if ( ! defined('ZM_SERVER_ID') ) {
App::uses('ClassRegistry', 'Utility');
$ServerModel = ClassRegistry::init('Server');
if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) {
$Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_NAME) ) );
if ( ! $Server ) {
Error('Invalid Multi-Server configration detected. ZM_SERVER_NAME set to ' . ZM_SERVER_NAME . ' in zm.conf, but no corresponding entry found in Servers table.');
} else {
define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
}
} else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) {
$Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_HOST) ) );
if ( ! $Server ) {
Error('Invalid Multi-Server configration detected. ZM_SERVER_HOST set to ' . ZM_SERVER_HOST . ' in zm.conf, but no corresponding entry found in Servers table.');
} else {
define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
}
}
}
}

View File

@ -434,14 +434,11 @@ class EventsController extends AppController {
// Find the max Frame for this Event. Error out otherwise.
$this->loadModel('Frame');
if (! $frame = $this->Frame->find('first', array(
$frame = $this->Frame->find('first', array(
'conditions' => array(
'EventId' => $event['Event']['Id'],
'Score' => $event['Event']['MaxScore']
)
))) {
throw new NotFoundException(__('Can not find Frame for Event ' . $event['Event']['Id']));
}
return $frame['Frame']['Id'];
'EventId' => $event['Event']['Id'],
'Score' => $event['Event']['MaxScore']
)));
return empty($frame)?null:$frame['Frame']['Id'];
}
} // end class EventsController

View File

@ -14,6 +14,18 @@ class UsersController extends AppController {
*/
public $components = array('RequestHandler', 'Paginator');
public function beforeFilter() {
parent::beforeFilter();
global $user;
# We already tested for auth in appController, so we just need to test for specific permission
$canView = (!$user) || ($user['System'] != 'None');
if ( !$canView ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
*
@ -23,6 +35,12 @@ class UsersController extends AppController {
public function index() {
$this->User->recursive = 0;
global $user;
# We should actually be able to list our own user, but I'm not bothering at this time.
if ( $user['System'] == 'None' ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
$users = $this->Paginator->paginate('User');
$this->set(compact('users'));
@ -36,16 +54,20 @@ class UsersController extends AppController {
* @return void
*/
public function view($id = null) {
$this->loadModel('Config');
$configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'),
'conditions' => array('Name' => array('ZM_DIR_EVENTS'))
));
$this->User->recursive = 1;
if (!$this->User->exists($id)) {
global $user;
# We can view ourselves
$canView = ($user['System'] != 'None') or ($user['Id'] == $id);
if ( !$canView ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
if ( !$this->User->exists($id) ) {
throw new NotFoundException(__('Invalid user'));
}
$options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
$user = $this->User->find('first', $options);
@ -61,9 +83,16 @@ class UsersController extends AppController {
* @return void
*/
public function add() {
if ($this->request->is('post')) {
if ( $this->request->is('post') ) {
global $user;
if ( $user['System'] != 'Edit' ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
$this->User->create();
if ($this->User->save($this->request->data)) {
if ( $this->User->save($this->request->data) ) {
return $this->flash(__('The user has been saved.'), array('action' => 'index'));
}
$this->Session->setFlash(
@ -82,20 +111,29 @@ class UsersController extends AppController {
public function edit($id = null) {
$this->User->id = $id;
if (!$this->User->exists($id)) {
global $user;
$canEdit = ($user['System'] == 'Edit') or (($user['Id'] == $id) and ZM_USER_SELF_EDIT);
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
if ( !$this->User->exists($id) ) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->User->save($this->request->data)) {
if ( $this->request->is('post') || $this->request->is('put') ) {
if ( $this->User->save($this->request->data) ) {
$message = 'Saved';
} else {
$message = 'Error';
}
} else {
$this->request->data = $this->User->read(null, $id);
unset($this->request->data['User']['password']);
}
# What is this doing? Resetting the request data? I understand clearing the password field
# but generally I feel like the request data should be read only
$this->request->data = $this->User->read(null, $id);
unset($this->request->data['User']['Password']);
}
$this->set(array(
'message' => $message,
@ -112,11 +150,18 @@ class UsersController extends AppController {
*/
public function delete($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
global $user;
# Can't delete ourselves
if ( ($user['System'] != 'Edit') or ($user['Id'] == $id) ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
if ( !$this->User->exists() ) {
throw new NotFoundException(__('Invalid user'));
}
$this->request->allowMethod('post', 'delete');
if ($this->User->delete()) {
if ( $this->User->delete() ) {
$message = 'The user has been deleted.';
} else {
$message = 'The user could not be deleted. Please, try again.';
@ -126,47 +171,4 @@ class UsersController extends AppController {
'_serialize' => array('message')
));
}
public function beforeFilter() {
parent::beforeFilter();
$this->loadModel('Config');
$configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'),
'conditions' => array('Name' => array('ZM_OPT_USE_AUTH'))
));
if ( $configs['ZM_OPT_USE_AUTH'] ) {
$this->Auth->allow('add','logout');
} else {
$this->Auth->allow();
}
}
public function login() {
$this->loadModel('Config');
$configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'),
'conditions' => array('Name' => array('ZM_OPT_USE_AUTH'))
));
if ( ! $configs['ZM_OPT_USE_AUTH'] ) {
$this->set(array(
'message' => 'Login is not required.',
'_serialize' => array('message')
));
return;
}
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirectUrl());
}
$this->Session->setFlash(__('Invalid username or password, try again'));
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
}
} # end class UsersController

View File

@ -40,6 +40,7 @@ class ZonesController extends AppController {
'_serialize' => array('zones')
));
}
public function index() {
$this->Zone->recursive = -1;
@ -63,23 +64,43 @@ class ZonesController extends AppController {
* @return void
*/
public function add() {
if ( $this->request->is('post') ) {
global $user;
$canEdit = (!$user) || $user['Monitors'] == 'Edit';
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
if ( !$this->request->is('post') ) {
throw new BadRequestException(__('Invalid method. Should be post'));
return;
}
$this->Zone->create();
if ( $this->Zone->save($this->request->data) ) {
return $this->flash(__('The zone has been saved.'), array('action' => 'index'));
global $user;
$canEdit = (!$user) || $user['Monitors'] == 'Edit';
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
$zone = null;
$this->Zone->create();
$zone = $this->Zone->save($this->request->data);
if ( $zone ) {
require_once __DIR__ .'/../../../includes/Monitor.php';
$monitor = new ZM\Monitor($zone['Zone']['MonitorId']);
$monitor->zmaControl('restart');
$message = 'Saved';
//$zone = $this->Zone->find('first', array('conditions' => array( array('Zone.' . $this->Zone->primaryKey => $this->Zone),
} else {
$message = 'Error: ';
// if there is a validation message, use it
if ( !$this->Zone->validates() ) {
$message = $this->Zone->validationErrors;
}
}
$monitors = $this->Zone->Monitor->find('list');
$this->set(compact('monitors'));
}
$this->set(array(
'message' => $message,
'zone' => $zone,
'_serialize' => array('message','zone')
));
} // end function add()
/**
* edit method

View File

@ -3,8 +3,6 @@ App::uses('AppModel', 'Model');
/**
* User Model
*
* @property Monitor $Monitor
* @property Frame $Frame
*/
class User extends AppModel {
@ -23,6 +21,20 @@ class User extends AppModel {
)
);
function beforeFind($query) {
if ( empty($query['fields']) ) {
$schema = $this->schema();
unset($schema['Password']);
foreach (array_keys($schema) as $field) {
$query['fields'][] = $this->alias . '.' . $field;
}
return $query;
}
return parent::beforeFind($query);
}
/**
* Use table
*
@ -53,14 +65,6 @@ class User extends AppModel {
* @var array
*/
public $belongsTo = array(
/*'Monitor' => array(
'className' => 'Monitor',
'foreignKey' => 'MonitorId',
'conditions' => '',
'fields' => '',
'order' => ''
)
*/
);
/**
@ -69,21 +73,6 @@ class User extends AppModel {
* @var array
*/
public $hasMany = array(
/*
'Frame' => array(
'className' => 'Frame',
'foreignKey' => 'UserId',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
*/
);
}

View File

@ -30,6 +30,32 @@ class Zone extends AppModel {
public $recursive = -1;
/**
* Validation rules
*
* @var array
*/
public $validate = array(
'MonitorId' => array(
'rule' => 'checkMonitorId',
//array('naturalNumber'),
'message' => 'Zones must have a valid MonitorId',
'allowEmpty' => false,
'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
'Name' => array(
'required' => array(
//'on' => 'create',
'rule' => 'notBlank',
'message' => 'Zone Name must be specified for creation',
'required' => true,
),
)
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
@ -41,9 +67,17 @@ class Zone extends AppModel {
'Monitor' => array(
'className' => 'Monitor',
'foreignKey' => 'MonitorId',
'conditions' => '',
'fields' => '',
'order' => ''
//'conditions' => '',
//'fields' => '',
//'order' => ''
)
);
public function checkMonitorId($data) {
if ( !$this->Monitor->find('first', array('conditions'=>array('Id'=>$data['MonitorId']))) ) {
//$this->invalidate('MonitorId', 'Invalid Monitor Id');
return false;
}
return true;
}
}

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($zone);

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($zone);

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response'=>$message, 'zone'=>$zone));
echo $xml->asXML();

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $message, 'zone'=>$zone));
echo $xml->asXML();

View File

@ -262,13 +262,18 @@ class Event extends ZM_Object {
return $streamSrc;
} // end function getStreamSrc
# The new='' is to so that if we pass null, we reset the value of DiskSpace.
# '' is not a valid DiskSpace so that tells us that nothing was passed whereas null (unknown) is.
function DiskSpace( $new='' ) {
if ( is_null($new) or ( $new != '' ) ) {
$this->{'DiskSpace'} = $new;
}
if ( (!property_exists($this, 'DiskSpace')) or (null === $this->{'DiskSpace'}) ) {
$this->{'DiskSpace'} = folder_size($this->Path());
dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'}));
if ( $this->{'EndTime'} ) {
# Finished events shouldn't grow in size much so we can commit it to the db.
dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'}));
}
}
return $this->{'DiskSpace'};
}
@ -380,54 +385,54 @@ class Event extends ZM_Object {
$Event = $this;
$eventPath = $Event->Path();
if ( $frame and ! is_array($frame) ) {
if ( $frame and !is_array($frame) ) {
# Must be an Id
Logger::Debug("Assuming that $frame is an Id");
$frame = array( 'FrameId'=>$frame, 'Type'=>'', 'Delta'=>0 );
$frame = array('FrameId'=>$frame, 'Type'=>'', 'Delta'=>0);
}
if ( ( ! $frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
if ( ( !$frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
# No frame specified, so look for a snapshot to use
$captImage = 'snapshot.jpg';
Logger::Debug("Frame not specified, using snapshot");
$frame = array('FrameId'=>'snapshot', 'Type'=>'','Delta'=>0);
Logger::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'] );
$captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId']);
if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
$captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId'] );
if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
$captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId']);
if ( !file_exists($eventPath.'/'.$captImage) ) {
# Generate the frame JPG
if ( $Event->DefaultVideo() ) {
$videoPath = $eventPath.'/'.$Event->DefaultVideo();
if ( ! file_exists( $videoPath ) ) {
Error("Event claims to have a video file, but it does not seem to exist at $videoPath" );
if ( !file_exists($videoPath) ) {
Error('Event claims to have a video file, but it does not seem to exist at '.$videoPath);
return '';
}
#$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" );
Logger::Debug('Running '.$command);
$output = array();
$retval = 0;
exec( $command, $output, $retval );
exec($command, $output, $retval);
Logger::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() );
Error('Can\'t create frame images from video because there is no video file for event '.$Event->Id().' at ' .$Event->Path());
}
} // end if capture file exists
} // end if analyze file exists
} // end if frame or snapshot
$captPath = $eventPath.'/'.$captImage;
if ( ! file_exists($captPath) ) {
Error("Capture file does not exist at $captPath");
if ( !file_exists($captPath) ) {
Error('Capture file does not exist at '.$captPath);
}
$analImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyse.jpg', $frame['FrameId']);
$analPath = $eventPath.'/'.$analImage;
$alarmFrame = $frame['Type']=='Alarm';
$alarmFrame = $frame['Type'] == 'Alarm';
$hasAnalImage = $alarmFrame && file_exists($analPath) && filesize($analPath);
$isAnalImage = $hasAnalImage && !$captureOnly;
@ -443,8 +448,8 @@ class Event extends ZM_Object {
$fraction = sprintf('%.3f', $scale/SCALE_BASE);
$scale = (int)round($scale);
$thumbCaptPath = preg_replace( '/\.jpg$/', "-$scale.jpg", $captPath );
$thumbAnalPath = preg_replace( '/\.jpg$/', "-$scale.jpg", $analPath );
$thumbCaptPath = preg_replace('/\.jpg$/', "-$scale.jpg", $captPath);
$thumbAnalPath = preg_replace('/\.jpg$/', "-$scale.jpg", $analPath);
if ( $isAnalImage ) {
$imagePath = $analPath;
@ -457,7 +462,7 @@ class Event extends ZM_Object {
$thumbFile = $thumbPath;
if ( $overwrite || ! file_exists($thumbFile) || ! filesize($thumbFile) ) {
// Get new dimensions
list( $imageWidth, $imageHeight ) = getimagesize($imagePath);
list($imageWidth, $imageHeight) = getimagesize($imagePath);
$thumbWidth = $imageWidth * $fraction;
$thumbHeight = $imageHeight * $fraction;
@ -484,7 +489,7 @@ class Event extends ZM_Object {
);
return $imageData;
}
} # getImageSrc
public function link_to($text=null) {
if ( !$text )

View File

@ -19,9 +19,9 @@ class Group extends ZM_Object {
public function delete() {
if ( property_exists($this, 'Id') ) {
dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}));
dbQuery('UPDATE Groups SET ParentId=NULL WHERE ParentId=?', array($this->{'Id'}));
dbQuery('DELETE FROM Groups WHERE Id=?', array($this->{'Id'}));
dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($this->{'Id'}));
dbQuery('UPDATE `Groups` SET `ParentId`=NULL WHERE `ParentId`=?', array($this->{'Id'}));
dbQuery('DELETE FROM `Groups` WHERE Id=?', array($this->{'Id'}));
if ( isset($_COOKIE['zmGroup']) ) {
if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) {
unset($_COOKIE['zmGroup']);
@ -47,7 +47,7 @@ class Group extends ZM_Object {
public function MonitorIds( ) {
if ( ! property_exists($this, 'MonitorIds') ) {
$this->{'MonitorIds'} = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}));
$this->{'MonitorIds'} = dbFetchAll('SELECT `MonitorId` FROM `Groups_Monitors` WHERE `GroupId`=?', 'MonitorId', array($this->{'Id'}));
}
return $this->{'MonitorIds'};
}
@ -65,7 +65,7 @@ class Group extends ZM_Object {
session_write_close();
}
return htmlSelect( 'GroupId[]', Group::get_dropdown_options(), isset($_SESSION['GroupId'])?$_SESSION['GroupId']:null, array(
return htmlSelect('GroupId[]', Group::get_dropdown_options(), isset($_SESSION['GroupId'])?$_SESSION['GroupId']:null, array(
'data-on-change' => 'submitThisForm',
'class'=>'chosen',
'multiple'=>'multiple',

View File

@ -201,6 +201,11 @@ class Monitor extends ZM_Object {
if ( ZM_RAND_STREAM ) {
$args['rand'] = time();
}
foreach ( array('scale') as $int_arg ) {
if ( isset($args[$int_arg]) and (!is_numeric($args[$int_arg]) or !$args[$int_arg] ) ) {
unset($args[$int_arg]);
}
}
$streamSrc .= '?'.http_build_query($args, '', $querySep);
@ -293,12 +298,12 @@ class Monitor extends ZM_Object {
return;
}
}
Logger::Debug("sending command to $url");
Logger::Debug('sending command to '.$url);
$context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
if ( $result === FALSE ) { /* Handle error */
Error("Error restarting zmc using $url");
}
} catch ( Exception $e ) {
@ -310,14 +315,15 @@ class Monitor extends ZM_Object {
} // end function zmcControl
function zmaControl($mode=false) {
if ( ! $this->{'Id'} ) {
if ( !$this->{'Id'} ) {
Warning('Attempt to control a monitor with no Id');
return;
}
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) {
if ( $this->{'Function'} == 'None' || $this->{'Function'} == 'Monitor' || $mode == 'stop' ) {
if ( ZM_OPT_CONTROL ) {
if ( ZM_OPT_CONTROL && $this->Controllable() && $this->TrackMotion() &&
( $this->{'Function'} == 'Modect' || $this->{'Function'} == 'Mocord' ) ) {
daemonControl('stop', 'zmtrack.pl', '-m '.$this->{'Id'});
}
daemonControl('stop', 'zma', '-m '.$this->{'Id'});
@ -340,7 +346,7 @@ class Monitor extends ZM_Object {
} else if ( $this->ServerId() ) {
$Server = $this->Server();
$url = ZM_BASE_PROTOCOL . '://'.$Server->Hostname().'/zm/api/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zma.json';
$url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zma.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
@ -354,10 +360,10 @@ class Monitor extends ZM_Object {
}
Logger::Debug("sending command to $url");
$context = stream_context_create();
$context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
if ( $result === FALSE ) { /* Handle error */
Error("Error restarting zma using $url");
}
} catch ( Exception $e ) {
@ -490,12 +496,11 @@ class Monitor extends ZM_Object {
foreach ( explode(' ', $command) as $option ) {
if ( preg_match('/--([^=]+)(?:=(.+))?/', $option, $matches) ) {
$options[$matches[1]] = $matches[2]?$matches[2]:1;
} else if ( $option != '' and $option != 'quit' ) {
} else if ( $option != '' and $option != 'quit' and $option != 'start' and $option != 'stop' ) {
Warning("Ignored command for zmcontrol $option in $command");
}
}
if ( !count($options) ) {
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'}));
@ -539,7 +544,7 @@ class Monitor extends ZM_Object {
} else if ( $this->ServerId() ) {
$Server = $this->Server();
$url = ZM_BASE_PROTOCOL . '://'.$Server->Hostname().'/zm/api/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json';
$url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);

View File

@ -306,7 +306,7 @@ class ZM_Object {
$fields = array_keys($fields);
if ( $this->Id() ) {
$sql = 'UPDATE '.$table.' SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?';
$sql = 'UPDATE `'.$table.'` SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?';
$values = array_map(function($field){ return $this->{$field};}, $fields);
$values[] = $this->{'Id'};
if ( dbQuery($sql, $values) )
@ -314,8 +314,8 @@ class ZM_Object {
} else {
unset($fields['Id']);
$sql = 'INSERT INTO '.$table.
' ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)).
$sql = 'INSERT INTO `'.$table.
'` ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)).
') VALUES ('.
implode(', ', array_map(function($field){return '?';}, $fields)).')';
@ -331,7 +331,7 @@ class ZM_Object {
public function delete() {
$class = get_class($this);
$table = $class::$table;
dbQuery("DELETE FROM $table WHERE Id=?", array($this->{'Id'}));
dbQuery("DELETE FROM `$table` WHERE Id=?", array($this->{'Id'}));
if ( isset($object_cache[$class]) and isset($object_cache[$class][$this->{'Id'}]) )
unset($object_cache[$class][$this->{'Id'}]);
}

View File

@ -85,8 +85,6 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
// We update the request id so that the newly saved filter is auto-selected
$_REQUEST['Id'] = $filter->Id();
}
if ( $filter->Background() )
$filter->control('start');
if ( $action == 'execute' ) {
$filter->execute();
@ -94,6 +92,8 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
$filter->delete();
$view = 'events';
} else if ( $filter->Background() ) {
$filter->control('start');
}
} else if ( $action == 'control' ) {

View File

@ -18,27 +18,36 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( $action == 'user' ) {
if ( $action == 'Save' ) {
if ( canEdit('System') ) {
if ( !empty($_REQUEST['uid']) )
if ( !empty($_REQUEST['uid']) ) {
$dbUser = dbFetchOne('SELECT * FROM Users WHERE Id=?', NULL, array($_REQUEST['uid']));
else
} else {
$dbUser = array();
}
$types = array();
if ( isset($_REQUEST['newUser']['MonitorIds']) and is_array($_REQUEST['newUser']['MonitorIds']) )
$_REQUEST['newUser']['MonitorIds'] = implode(',', $_REQUEST['newUser']['MonitorIds']);
if ( !$_REQUEST['newUser']['Password'] )
unset($_REQUEST['newUser']['Password']);
$changes = getFormChanges($dbUser, $_REQUEST['newUser'], $types);
if ( function_exists('password_hash') ) {
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
} else {
$pass_hash = ' PASSWORD('.dbEscape($_REQUEST['newUser']['Password']).') ';
ZM\Info('Cannot use bcrypt as you are using PHP < 5.3');
}
if ( $_REQUEST['newUser']['Password'] ) {
$changes['Password'] = 'Password = '.$pass_hash;
} else {
unset($changes['Password']);
if ( isset($_REQUEST['newUser']['Password']) ) {
if ( function_exists('password_hash') ) {
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
} else {
$pass_hash = ' PASSWORD('.dbEscape($_REQUEST['newUser']['Password']).') ';
ZM\Info('Cannot use bcrypt as you are using PHP < 5.3');
}
if ( $_REQUEST['newUser']['Password'] ) {
$changes['Password'] = 'Password = '.$pass_hash;
} else {
unset($changes['Password']);
}
}
if ( count($changes) ) {

View File

@ -260,6 +260,22 @@ function userFromSession() {
return $user;
}
function get_auth_relay() {
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
return 'auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
} else if ( ZM_AUTH_RELAY == 'plain' ) {
// password probably needs to be escaped
return 'username='.$_SESSION['username'].'&password='.urlencode($_SESSION['password']);
} else if ( ZM_AUTH_RELAY == 'none' ) {
return 'username='.$_SESSION['username'];
} else {
ZM\Error('Unknown value for ZM_AUTH_RELAY ' . ZM_AUTH_RELAY);
}
}
return '';
} // end function get_auth_relay
if ( ZM_OPT_USE_AUTH ) {
if ( !empty($_REQUEST['token']) ) {
// we only need to get the username here

View File

@ -389,7 +389,7 @@ function csrf_conf($key, $val) {
*/
function csrf_start() {
if ($GLOBALS['csrf']['auto-session'] && !session_id()) {
session_start();
zm_session_start();
}
}

View File

@ -25,20 +25,26 @@ define('DB_LOG_DEBUG', 2);
$GLOBALS['dbLogLevel'] = DB_LOG_OFF;
$GLOBALS['dbConn'] = false;
require_once('logger.php');
function dbConnect() {
global $dbConn;
if ( strpos(ZM_DB_HOST, ':') ) {
// Host variable may carry a port or socket.
list($host, $portOrSocket) = explode(':', ZM_DB_HOST, 2);
if ( ctype_digit($portOrSocket) ) {
$socket = ':host='.$host . ';port='.$portOrSocket;
$socket = '';
if ( ZM_DB_HOST ) {
if ( strpos(ZM_DB_HOST, ':') ) {
// Host variable may carry a port or socket.
list($host, $portOrSocket) = explode(':', ZM_DB_HOST, 2);
if ( ctype_digit($portOrSocket) ) {
$socket = ':host='.$host . ';port='.$portOrSocket.';';
} else {
$socket = ':unix_socket='.$portOrSocket.';';
}
} else {
$socket = ':unix_socket='.$portOrSocket;
$socket = ':host='.ZM_DB_HOST.';';
}
} else {
$socket = ':host='.ZM_DB_HOST;
$socket = ':host=localhost;';
}
try {
@ -49,9 +55,9 @@ function dbConnect() {
PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY,
PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT,
);
$dbConn = new PDO(ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions);
$dbConn = new PDO(ZM_DB_TYPE.$socket.'dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions);
} else {
$dbConn = new PDO(ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS);
$dbConn = new PDO(ZM_DB_TYPE.$socket.'dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS);
}
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
@ -61,9 +67,12 @@ function dbConnect() {
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
$dbConn = null;
}
}
return $dbConn;
} // end function dbConnect
dbConnect();
if ( !dbConnect() ) {
ZM\Fatal("Failed db connection to $socket");
}
function dbDisconnect() {
global $dbConn;

View File

@ -40,7 +40,7 @@ function CSPHeaders($view, $nonce) {
if ( ! $Servers )
$Servers = ZM\Server::find();
$additionalScriptSrc = implode(' ', array_map(function($S){return $S->Url();}, $Servers));
$additionalScriptSrc = implode(' ', array_map(function($S){return $S->Hostname();}, $Servers));
switch ($view) {
case 'login': {
if (defined('ZM_OPT_USE_GOOG_RECAPTCHA')
@ -840,9 +840,15 @@ function daemonStatus($daemon, $args=false) {
initDaemonStatus();
$string = $daemon;
if ( $args )
$string .= ' ' . $args;
return( strpos($daemon_status, "'$string' running") !== false );
if ( $args ) {
if ( is_array($args) ) {
$string .= join(' ', $args);
ZM\Warning("daemonStatus args: $string");
} else {
$string .= ' ' . $args;
}
}
return ( strpos($daemon_status, "'$string' running") !== false );
}
function zmcStatus($monitor) {
@ -1484,15 +1490,15 @@ function getLoad() {
function getDiskPercent($path = ZM_DIR_EVENTS) {
$total = disk_total_space($path);
if ( $total === false ) {
Error('disk_total_space returned false. Verify the web account user has access to ' . $path);
ZM\Error('disk_total_space returned false. Verify the web account user has access to ' . $path);
return 0;
} elseif ( $total == 0 ) {
Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path);
ZM\Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path);
return 100;
}
$free = disk_free_space($path);
if ( $free === false ) {
Error('disk_free_space returned false. Verify the web account user has access to ' . $path);
ZM\Error('disk_free_space returned false. Verify the web account user has access to ' . $path);
}
$space = round((($total - $free) / $total) * 100);
return $space;
@ -2048,7 +2054,7 @@ function logState() {
if ( $count['Level'] <= ZM\Logger::PANIC )
$count['Level'] = ZM\Logger::FATAL;
if ( !($levelCount = $levelCounts[$count['Level']]) ) {
Error('Unexpected Log level '.$count['Level']);
ZM\Error('Unexpected Log level '.$count['Level']);
next;
}
if ( $levelCount[1] && $count['LevelCount'] >= $levelCount[1] ) {
@ -2075,18 +2081,23 @@ function isVector(&$array) {
function checkJsonError($value) {
if ( function_exists('json_last_error') ) {
$value = var_export($value,true);
switch( json_last_error() ) {
$value = var_export($value, true);
switch ( json_last_error() ) {
case JSON_ERROR_DEPTH :
ZM\Fatal("Unable to decode JSON string '$value', maximum stack depth exceeded");
ZM\Error("Unable to decode JSON string '$value', maximum stack depth exceeded");
break;
case JSON_ERROR_CTRL_CHAR :
ZM\Fatal("Unable to decode JSON string '$value', unexpected control character found");
ZM\Error("Unable to decode JSON string '$value', unexpected control character found");
break;
case JSON_ERROR_STATE_MISMATCH :
ZM\Fatal("Unable to decode JSON string '$value', invalid or malformed JSON");
ZM\Error("Unable to decode JSON string '$value', invalid or malformed JSON");
break;
case JSON_ERROR_SYNTAX :
ZM\Fatal("Unable to decode JSON string '$value', syntax error");
ZM\Error("Unable to decode JSON string '$value', syntax error");
break;
default :
ZM\Fatal("Unable to decode JSON string '$value', unexpected error ".json_last_error());
ZM\Error("Unable to decode JSON string '$value', unexpected error ".json_last_error());
break;
case JSON_ERROR_NONE:
break;
}
@ -2290,7 +2301,8 @@ function validHtmlStr($input) {
function getStreamHTML($monitor, $options = array()) {
if ( isset($options['scale']) ) {
if ( $options['scale'] != 'auto' && $options['scale'] != '0' ) {
if ( $options['scale'] != 'auto' && $options['scale'] != '0' and $options['scale'] != '' ) {
ZM\Logger::Debug("Setting dimensions from scale:".$options['scale']);
$options['width'] = reScale($monitor->ViewWidth(), $options['scale']).'px';
$options['height'] = reScale($monitor->ViewHeight(), $options['scale']).'px';
} else {

View File

@ -87,6 +87,7 @@ $SLANG = array(
'Actual' => 'Actual',
'AddNewControl' => 'Add New Control',
'AddNewMonitor' => 'Add',
'AddMonitorDisabled' => 'Your user is not allowed to add a new monitor',
'AddNewServer' => 'Add New Server',
'AddNewStorage' => 'Add New Storage',
'AddNewUser' => 'Add New User',
@ -983,6 +984,18 @@ $OLANG = array(
"loglevel=debug" Set verbosity of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)
'
),
'OPTIONS_ENCODER_PARAMETERS' => array(
'Help' => '
Parameters passed to the encoding codec. name=value separated by either , or newline.~~
For example to changing quality, use the crf option. 1 is best, 51 is worst 23 is default.~~
~~
crf=23~~
~~
You might want to alter the movflags value to support different behaviours. Some people have troubles viewing videos due to the frag_keyframe option, but that option is supposed to allow viewing of incomplete events. See
[https://ffmpeg.org/ffmpeg-formats.html](https://ffmpeg.org/ffmpeg-formats.html)
for more information. ZoneMinder\'s default is frag_keyframe,empty_moov~~
',
),
'OPTIONS_DECODERHWACCELNAME' => array(
'Help' => '
This is equivalent to the ffmpeg -hwaccel command line option. With intel graphics support, use "vaapi". For NVIDIA cuda support use "cuda". To check for support, run ffmpeg -hwaccels on the command line.'

View File

@ -509,7 +509,7 @@ th.table-th-sort-rev span.table-th-sort-span {
}
#content {
width: 96%;
width: 100%;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;

View File

@ -11,10 +11,30 @@
textarea,
input[name="newMonitor[Name]"],
input[name="newMonitor[LabelFormat]"],
input[name="newMonitor[ControlDevice]"],
input[name="newMonitor[ControlAddress]"] {
width: 100%;
}
input[name="newMonitor[AnalysisFPSLimit]"],
input[name="newMonitor[MaxFPS]"],
input[name="newMonitor[AlarmMaxFPS]"],
input[name="newMonitor[V4LCapturesPerFrame]"]{
width: 60px;
}
input[name="newMonitor[Port]"],
input[name="newMonitor[Refresh]"],
input[name="newMonitor[LabelX]"],
input[name="newMonitor[LabelY]"],
input[name="newMonitor[ImageBufferCount]"],
input[name="newMonitor[WarmupCount]"],
input[name="newMonitor[PreEventCount]"],
input[name="newMonitor[PostEventCount]"],
input[name="newMonitor[StreamReplayBuffer]"],
input[name="newMonitor[AlarmFrameCount]"],
input[name="newMonitor[AutoStopTimeout]"],
input[name="newMonitor[TrackDelay]"],
input[name="newMonitor[ReturnDelay]"],
input[name="newMonitor[Width]"],
input[name="newMonitor[Height]"] {
width: 80px;

Some files were not shown because too many files have changed in this diff Show More