Merge remote-tracking branch 'origin/master' into bootstrap-skin

This commit is contained in:
Kyle Johnson 2014-11-15 21:47:01 +00:00
commit 1fc26c01ac
55 changed files with 2018 additions and 248 deletions

View File

@ -224,7 +224,11 @@ else(GCRYPT_LIBRARIES)
endif(GCRYPT_LIBRARIES)
# gnutls (using find_library and find_path)
find_library(GNUTLS_LIBRARIES gnutls)
find_library(GNUTLS_LIBRARIES gnutls-openssl)
if(NOT GNUTLS_LIBRARIES)
find_library(GNUTLS_LIBRARIES gnutls)
endif(NOT GNUTLS_LIBRARIES)
if(GNUTLS_LIBRARIES)
set(HAVE_LIBGNUTLS 1)
list(APPEND ZM_BIN_LIBS "${GNUTLS_LIBRARIES}")

View File

@ -105,29 +105,39 @@ root@host:~# gdebi /root/zoneminder_1.26.4-1_amd64.deb;
Additional repositories must be added before one can build zoneminder on CentOS or RHEL:
1. RepoForge (formerly RPMForge) http://repoforge.org/use/
1. Zmrepo [ZoneMinder WiKi](http://www.zoneminder.com/wiki/index.php/CentOS#Zmrepo_-_A_ZoneMinder_repository_for_RPM_based_distros)
2. EPEL https://fedoraproject.org/wiki/EPEL
3. Optional RPMFusion: http://rpmfusion.org/ [SEE NOTE]
[NOTE]<br>
The RPMFusion repo contains significantly newer versions of ffmpeg and vlc. This leads to significantly better camera support. However, the RPMFusion repo contains packages that conflict with the other two repos. In order to resolve this, one must also install the yum priorities pacakge and use that to prioritize your repos in the following order:
3. RPMFusion: http://rpmfusion.org/
When adding third party repositories, it is highly recommended that the user also install and configure yum priorities as documented in the [CentOS WiKi](http://wiki.centos.org/PackageManagement/Yum/Priorities)
Prioritize the repositories:
1. Base
2. RPMFusion
3. EPEL
4. RPMForge
For instructions on yum priorities, visit this page:
http://wiki.centos.org/PackageManagement/Yum/Priorities
2. EPEL
3. RPMFusion
4. Zmrepo
Once your repos are in order, install the following:
```bash
sudo yum install automake bzip2-devel ffmpeg ffmpeg-devel gnutls-devel httpd libjpeg-turbo libjpeg-turbo-devel mysql-devel mysql-server pcre-devel \
sudo yum install cmake bzip2-devel ffmpeg ffmpeg-devel gnutls-devel httpd libjpeg-turbo libjpeg-turbo-devel mysql-devel mysql-server pcre-devel \
perl-Archive-Tar perl-Archive-Zip perl-Convert-BinHex perl-Date-Manip perl-DBD-MySQL perl-DBI perl-Device-SerialPort perl-Email-Date-Format perl-IO-stringy \
perl-IO-Zlib perl-MailTools perl-MIME-Lite perl-MIME-tools perl-MIME-Types perl-Module-Load perl-Package-Constants perl-Sys-Mmap perl-Time-HiRes \
perl-TimeDate perl-YAML-Syck php php-cli php-mysql x264 vlc-devel vlc-core libcurl libcurl-devel
perl-TimeDate perl-YAML-Syck perl-X10 perl-URI-Encode php php-cli php-mysql x264 vlc-devel vlc-core \
libcurl libcurl-devel polkit-devel git
```
To build from the master branch:
```bash
git clone https://github.com/ZoneMinder/ZoneMinder.git
cd ZoneMinder
cmake .
make
sudo make install
```
IMPORTANT: Don't forget the trailing "." when calling cmake
#### Docker
Docker is a system to run applications inside isolated containers. ZoneMinder, and the ZM webserver, will run using the
@ -159,4 +169,14 @@ the following steps.
6. Create new Pull Request
7. The team will then review, discuss and hopefully merge your changes.
### Package Maintainters
Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source.
For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script:
```bash
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
```
Note that zmeditconfigdata.sh is intended to be called, from the root build folder, prior to running cmake or configure.
[![Analytics](https://ga-beacon.appspot.com/UA-15147273-6/ZoneMinder/README.md)](https://github.com/igrigorik/ga-beacon)

View File

@ -557,7 +557,7 @@ INSERT INTO Controls VALUES (NULL,'Foscam FI9821W','Ffmpeg','FI9821W_Y2k',1,0,1,
INSERT INTO Controls VALUES (NULL,'Loftek Sentinel','Remote','LoftekSentinel',0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,255,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,6,1,1,0,0,0,1,10,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
INSERT INTO Controls VALUES (NULL,'Toshiba IK-WB11A','Remote','Toshiba_IK_WB11A',0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,10,0,1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
INSERT INTO Controls VALUES (NULL,'WanscamPT','Remote','Wanscam',1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,16,0,0,0,0,0,1,16,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
INSERT INTO Controls VALUES (NULL,'3S Domo N5071', 'Remote', '3S', 0, 0, 1, 1, 0, 1, 1, 0, 0, 9999, 0, 9999, 0, 0, 0, 1, 1, 1, 1, 0, 0, 9999, 20, 9999, 0, 0, 0, 1, 1, 1, 1, 0, 0, 9999, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 64, 1, 0, 1, 1, 0, 0, 0, 0, 1, -180, 180, 40, 100, 1, 40, 100, 0, 0, 1, -180, 180, 40, 100, 1, 40, 100, 0, 0, 0, 0);
--
-- Add some monitor preset values
--

7
distros/debian/install Normal file
View File

@ -0,0 +1,7 @@
usr/bin
usr/lib/cgi-bin
usr/share/man
usr/share/perl5/ZoneMinder
usr/share/perl5/ZoneMinder.pm
usr/share/zoneminder
etc/zm

4
distros/debian/links Normal file
View File

@ -0,0 +1,4 @@
var/cache/zoneminder/events usr/share/zoneminder/events
var/cache/zoneminder/images usr/share/zoneminder/images
var/cache/zoneminder/temp usr/share/zoneminder/temp
usr/lib/cgi-bin usr/share/zoneminder/cgi-bin

View File

@ -0,0 +1,51 @@
zoneminder for Debian
---------------------
There is one manual step to get the web interface working.
You need to link /etc/zm/apache.conf to /etc/apache2/conf.d/zoneminder.conf,
then reload the apache config (i.e. /etc/init.d/apache2 reload)
Changing the location for images and events
-------------------------------------------
Zoneminder, in its upstream form, stores data in /usr/share/zoneminder/. This
package modifies that by changing /usr/share/zoneminder/images and
/usr/share/zoneminder/events to symlinks to directories under
/var/cache/zoneminder.
There are numerous places these could be put and ways to do it. But, at the
moment, if you change this, an upgrade will fail with a warning about these
locations having changed (the reason for this was that previously, an upgrade
would silently revert the changes and cause event loss - refer
bug #608793).
If you do want to change the location, here are a couple of suggestions.
These lines would mount /dev/sdX1 to /video_storage, and then 'link' /video_storage
to the locations that ZoneMinder expects them to be at.
/dev/sdX1 /video_storage ext4 defaults 0 2
/video_storage/zoneminder/images /var/cache/zoneminder/images none bind 0 2
/video_storage/zoneminder/events /var/cache/zoneminder/events none bind 0 2
or if you have a separate partition for each:
/dev/sdX1 /var/cache/zoneminder/images ext4 defaults 0 2
/dev/sdX2 /var/cache/zoneminder/events ext4 defaults 0 2
-- Peter Howard <pjh@northern-ridge.com.au>, Sun, 16 Jan 2010 01:35:51 +1100
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,9 @@
Alias /zm /usr/share/zoneminder
<Directory /usr/share/zoneminder>
php_flag register_globals off
Options Indexes FollowSymLinks
<IfModule mod_dir.c>
DirectoryIndex index.php
</IfModule>
</Directory>

View File

@ -0,0 +1,29 @@
zoneminder (1.28.0-0.1) wheezy; urgency=low
* Use CMake instead of Autotools to simplify
debian/rules and have less build-depends.
* Some lintian love in debian/{control,copyright}
and perl ZoneMinder modules.
* Don't purge database if we use a remote
MySQL server.
-- Cosme Domínguez Díaz <cosme.ddiaz@gmail.com> Sun, 09 Nov 2014 02:20:20 +0100
zoneminder (1.28.0-wheezy) wheezy; urgency=medium
* Release
-- Isaac Connor <iconnor@connortechnology.com> Fri, 17 Oct 2014 09:27:22 -0400
zoneminder (1.27.99+1-testing-SNAPSHOT2014072901) testing; urgency=medium
* improve error messages
* Make zmupdate re-run the most recent patch so that people running the daily builds get their db updates
-- Isaac Connor <iconnor@connortechnology.com> Tue, 29 Jul 2014 14:50:20 -0400
zoneminder (1.27.0+1-testing-v4ltomonitor-1) testing; urgency=high
* Snapshot release -
-- Isaac Connor <iconnor@connortechnology.com> Wed, 09 Jul 2014 21:35:29 -0400

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,40 @@
Source: zoneminder
Section: net
Priority: optional
Maintainer: Isaac Connor <iconnor@connortechnology.com>
Build-Depends: debhelper (>= 9), cmake, libphp-serialization-perl, libgnutls-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev, libpcre3-dev, libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libsys-mmap-perl, libav-tools, libnetpbm10-dev, libavdevice-dev, libdevice-serialport-perl, libarchive-zip-perl, libmime-lite-perl, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev, libpolkit-gobject-1-dev
Standards-Version: 3.9.4
Package: zoneminder
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2 | httpd, libapache2-mod-php5 | libapache2-mod-fcgid | php5-fpm, php5-mysqlnd | php5-mysql, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client | mysql-client, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, libav-tools, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, netpbm, libavdevice53, libjpeg8, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0
Recommends: mysql-server | mariadb-server
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: zoneminder-dbg
Architecture: any
Priority: extra
Section: debug
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
Description: debugging syumbols for zoneminder.
ZoneMinder is a 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.

View File

@ -0,0 +1,57 @@
Copyright:
Copyright 2002 Philip Coombes <philip.coombes@zoneminder.com>
License:
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
On Debian GNU/Linux systems, the text of the GPL can be found in
/usr/share/common-licenses/GPL.
/usr/share/zoneminder/api/lib/Cake/*:
Copyright:
Copyright (c) 2005-2013, Cake Software Foundation, Inc.
License:
CakePHP(tm) : The Rapid Development PHP Framework (http://cakephp.org)
The MIT License
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.
Cake Software Foundation, Inc.
1785 E. Sahara Avenue,
Suite 490-204
Las Vegas, Nevada 89104,
United States of America.

View File

@ -0,0 +1,5 @@
var/log/zm
var/lib/zm
var/cache/zoneminder/events
var/cache/zoneminder/images
var/cache/zoneminder/temp

View File

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

View File

@ -0,0 +1,87 @@
#!/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
### END INIT INFO
# description: Control ZoneMinder as a Service
# chkconfig: 2345 20 20
# Source function library.
#. /etc/rc.d/init.d/functions
prog=ZoneMinder
ZM_PATH_BIN="/usr/bin"
RUNDIR=/var/run/zm
TMPDIR=/tmp/zm
command="$ZM_PATH_BIN/zmpkg.pl"
start() {
echo -n "Starting $prog: "
mkdir -p $RUNDIR $TMPDIR && chown www-data:www-data $RUNDIR $TMPDIR
$command start
RETVAL=$?
[ $RETVAL = 0 ] && echo success || 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 || 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,7 @@
usr/bin
usr/lib/cgi-bin
usr/share/man
usr/share/perl5/ZoneMinder
usr/share/perl5/ZoneMinder.pm
usr/share/zoneminder
etc/zm

View File

@ -0,0 +1,4 @@
var/cache/zoneminder/events usr/share/zoneminder/events
var/cache/zoneminder/images usr/share/zoneminder/images
var/cache/zoneminder/temp usr/share/zoneminder/temp
usr/lib/cgi-bin usr/share/zoneminder/cgi-bin

View File

@ -0,0 +1,53 @@
#! /bin/sh
set -e
if [ "$1" = "configure" ]; 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
echo 'grant lock tables, alter,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
invoke-rc.d zoneminder stop || true
zmupdate.pl --nointeractive
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
chown www-data:www-data /var/log/zm
chown www-data:www-data /var/lib/zm/
if [ -z "$2" ]; then
chown www-data:www-data -R /var/cache/zoneminder
fi
fi
# Ensure zoneminder is stopped...
if [ -x "/etc/init.d/zoneminder" ]; then
if invoke-rc.d zoneminder status ; then
invoke-rc.d zoneminder stop || exit $?
fi
fi
if [ "$1" = "configure" ]; then
if [ -z "$2" ]; then
chown www-data:www-data /var/log/zm
chown www-data:www-data /var/lib/zm/
chown www-data:www-data -R /var/cache/zoneminder
else
chown www-data:www-data /var/log/zm
zmupdate.pl
fi
fi
#DEBHELPER#

View File

@ -0,0 +1,11 @@
#! /bin/sh
set -e
if [ "$1" = "purge" ]; then
if [ -e "/etc/init.d/mysql" ]; then
echo 'delete from user where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
echo 'delete from db where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f drop zm
fi
fi
#DEBHELPER#

View File

@ -0,0 +1,32 @@
#!/bin/sh
set -e
abort=false
if [ -L /usr/share/zoneminder/events ]; then
l=$(readlink /usr/share/zoneminder/events)
if [ "$l" != "/var/cache/zoneminder/events" ]; then
abort=true
fi
fi
if [ -L /usr/share/zoneminder/images ]; then
l=$(readlink /usr/share/zoneminder/images )
if [ "$l" != "/var/cache/zoneminder/images" ]; then
abort=true
fi
fi
if [ "$abort" = "true" ]; then
cat >&2 << EOF
Aborting installation of zoneminder due to non-default symlinks in
/usr/share/zoneminder for the images and/or events directory, which could
result in loss of data. Please move your data in each of these directories to
/var/cache/zoneminder before installing zoneminder from the package.
EOF
exit 1
fi
#DEBHELPER#
exit 0

42
distros/debian_cmake/rules Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export CFLAGS = -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -pipe
export CXXFLAGS = -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -pipe
INSTDIR = debian/tmp
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_SKIP_RPATH=ON \
-DCMAKE_VERBOSE_MAKEFILE=OFF \
-DCMAKE_COLOR_MAKEFILE=ON \
-DZM_RUNDIR=/var/run/zm \
-DZM_SOCKDIR=/var/run/zm \
-DZM_TMPDIR=/var/tmp/zm \
-DZM_LOGDIR=/var/log/zm \
-DZM_WEBDIR=/usr/share/zoneminder \
-DZM_CONTENTDIR=/var/cache/zoneminder \
-DZM_CGIDIR=/usr/lib/cgi-bin \
-DZM_WEB_USER=www-data \
-DZM_WEB_GROUP=www-data \
-DZM_PERL_SUBPREFIX=/share/perl5 \
-DCMAKE_INSTALL_SYSCONFDIR=etc/zm
override_dh_auto_install:
dh_auto_install --buildsystem=cmake
install -D -m 0644 debian/apache.conf $(INSTDIR)/etc/zm/apache.conf
rm $(INSTDIR)/usr/share/zoneminder/api/lib/Cake/LICENSE.txt
rm $(INSTDIR)/usr/share/zoneminder/api/.gitignore
rm -r $(INSTDIR)/usr/share/zoneminder/api/lib/Cake/Test
override_dh_auto_test:
# do not run tests...
override_dh_strip:
dh_strip --dbg-package=zoneminder-dbg
%:
dh $@ --buildsystem=cmake --parallel

View File

@ -0,0 +1,3 @@
version=3
http://www.zoneminder.com/downloads.html \
.*/ZoneMinder-(.*).tar.gz

View File

@ -22,8 +22,6 @@ URL: http://www.zoneminder.com/
#Source: https://github.com/ZoneMinder/ZoneMinder/archive/v%{version}.tar.gz
Source: ZoneMinder-%{version}.tar.gz
Patch1: zoneminder-1.28.0-defaults.patch
BuildRequires: cmake gnutls-devel systemd-units bzip2-devel
BuildRequires: community-mysql-devel pcre-devel libjpeg-turbo-devel
BuildRequires: perl(Archive::Tar) perl(Archive::Zip)
@ -66,7 +64,13 @@ too much degradation of performance.
%prep
%setup -q -n ZoneMinder-%{version}
%patch1 -p0 -b .defaults
# Change the following default values
./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin/zm/nph-zms
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
./utils/zmeditconfigdata.sh ZM_PATH_SWAP /dev/shm
./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR /var/spool/zoneminder-upload
./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes
%build
%cmake \

View File

@ -17,8 +17,6 @@ URL: http://www.zoneminder.com/
#Source0: https://github.com/ZoneMinder/ZoneMinder/archive/v%{version}.tar.gz
Source0: ZoneMinder-%{version}.tar.gz
Patch1: zoneminder-1.28.0-defaults.patch
BuildRequires: cmake gnutls-devel bzip2-devel
BuildRequires: mysql-devel pcre-devel libjpeg-turbo-devel
BuildRequires: perl(Archive::Tar) perl(Archive::Zip)
@ -63,7 +61,12 @@ too much degradation of performance.
%prep
%setup -q -n ZoneMinder-%{version}
%patch1 -p0 -b .defaults
# Change the following default values
./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin/zm/nph-zms
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
./utils/zmeditconfigdata.sh ZM_PATH_SWAP /dev/shm
./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR /var/spool/zoneminder-upload
./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes
%build
# Have to override CMAKE_INSTALL_LIBDIR for cmake < 2.8.7 due to this bug:

View File

@ -7,7 +7,7 @@ Standards-Version: 3.9.2
Package: zoneminder
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2, libapache2-mod-php5 | libapache2-mod-fcgid, php5, php5-mysql|php5-mysqlnd, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client|mysql-client, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, ffmpeg | libav-tools, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, netpbm, libavdevice53, libjpeg8, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7 | libvlccore8, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0, liburi-encode-perl
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2, libapache2-mod-php5 | libapache2-mod-fcgid, php5, php5-mysql|php5-mysqlnd, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client|mysql-client, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, ffmpeg | libav-tools, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, netpbm, libavdevice53 | libavdevice55, libjpeg8, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7 | libvlccore8, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0, liburi-encode-perl
Recommends: mysql-server|mariadb-server
Description: A video camera security and surveillance solution
ZoneMinder is intended for use in single or multi-camera video security

View File

@ -3,14 +3,10 @@ Ubuntu
PPA Install
-----------
Follow these instructions to install current release version on Ubuntu 13.04 or under.:
Follow these instructions to install current release version on Ubuntu.:
sudo apt-add-repository ppa:iconnor/zoneminder
Or Ubuntu 14.10 you will need to install the Snapshot PPA from the master branch instead.:
sudo apt-add-repository ppa:iconnor/zoneminder-master
Once you have updated the repository then update and install the package.:
sudo apt-get update

View File

@ -11,7 +11,7 @@ User=@WEB_USER@
Type=forking
ExecStart=@BINDIR@/zmpkg.pl start
ExecReload=@BINDIR@/zmpkg.pl restart
ExecStop=/bin/bash -c '[[ "$(@BINDIR@/pgrep zmdc.pl)" > 0 ]] && @BINDIR@/zmpkg.pl stop'
ExecStop=@BINDIR@/zmpkg.pl stop
PIDFile="@ZM_RUNDIR@/zm.pid"
[Install]

View File

@ -442,6 +442,15 @@ our @options =
type => $types{string},
category => "images",
},
{
name => "ZM_FFMPEG_OPEN_TIMEOUT",
default => "10",
description => "Timeout in seconds when opening a stream.",
help => "When Ffmpeg is opening a stream, it can take a long time before failing; certain circumstances even seem to be able to lock indefinitely. This option allows you to set a maximum time in seconds to pass before closing the stream and trying to reopen it again.",
requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ],
type => $types{integer},
category => "images",
},
{
name => "ZM_LOG_LEVEL_SYSLOG",
default => "0",

View File

@ -0,0 +1,606 @@
# ==========================================================================
#
# ZoneMinder 3S API Control Protocol Module, $Date: 2014-11-12 08:00:00 +0300 (Tue, 21 Jun 2011) $, $Revision: 1 $
# Copyright (C) 2014 Juan Manuel Castro
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ==========================================================================
#
# This module contains the implementation of the 3S camera control
# protocol
#Model: N5071
#Hardware Version: 00
#Firmware Version: V1.03_STD-1
#Firmware Build Time: Jun 19 2012 15:28:17
package ZoneMinder::Control::3S;
use 5.006;
use strict;
use warnings;
require ZoneMinder::Base;
require ZoneMinder::Control;
our @ISA = qw(ZoneMinder::Control);
our $VERSION = $ZoneMinder::Base::VERSION;
# ==========================================================================
#
# 3S Control Protocol
#
# ==========================================================================
use ZoneMinder::Logger qw(:all);
use ZoneMinder::Config qw(:all);
use Time::HiRes qw( usleep );
sub new
{
my $class = shift;
my $id = shift;
my $self = ZoneMinder::Control->new( $id );
bless( $self, $class );
srand( time() );
return $self;
}
our $AUTOLOAD;
sub AUTOLOAD
{
my $self = shift;
my $class = ref($self) || croak( "$self not object" );
my $name = $AUTOLOAD;
$name =~ s/.*://;
if ( exists($self->{$name}) )
{
return( $self->{$name} );
}
Fatal( "Can't access $name member of object of class $class" );
}
sub open
{
my $self = shift;
$self->loadMonitor();
use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new;
#$self->{ua}->agent( "ZoneMinder Control Agent/".ZM_VERSION );
$self->{ua}->agent( "ZoneMinder Control Agent/" . ZoneMinder::Base::ZM_VERSION );
$self->{state} = 'open';
}
sub close
{
my $self = shift;
$self->{state} = 'closed';
}
sub printMsg
{
my $self = shift;
my $msg = shift;
my $msg_len = length($msg);
Debug( $msg."[".$msg_len."]" );
}
sub sendCmd
{
my $self = shift;
my $cmd = shift;
my $result = undef;
printMsg( $cmd, "Tx" );
#print("http://".$self->{Monitor}->{ControlAddress}."/$cmd");
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
my $res = $self->{ua}->request($req);
if ( $res->is_success )
{
$result = !undef;
}
else
{
Error( "Error check failed: '".$res->status_line()."'" );
}
return( $result );
}
sub cameraReset
{
my $self = shift;
Debug( "Camera Reset" );
my $cmd = "/restart.cgi";
$self->sendCmd( $cmd );
}
#Custom#
#Move X or Y Axis
sub Up
{
my $self = shift;
Debug( "Move Up" );
my $cmd = "/ptz.cgi?move=up";
$self->sendCmd( $cmd );
}
sub Down
{
my $self = shift;
Debug( "Move Down" );
my $cmd = "/ptz.cgi?move=down";
$self->sendCmd( $cmd );
}
sub Left
{
my $self = shift;
Debug( "Move Left" );
my $cmd = "/ptz.cgi?move=left";
$self->sendCmd( $cmd );
}
sub Right
{
my $self = shift;
Debug( "Move Right" );
my $cmd = "/ptz.cgi?move=right";
$self->sendCmd( $cmd );
}
##Zoom
sub Tele
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Zoom Tele" );
my $cmd = "/ptz.cgi?rzoom=$step";
$self->sendCmd( $cmd );
}
sub Wide
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Zoom Wide" );
my $cmd = "/ptz.cgi?rzoom=-$step";
$self->sendCmd( $cmd );
}
#Move X and Y Axis
sub UpRight
{
my $self = shift;
Debug( "Move Up/Right" );
my $cmd = "/ptz.cgi?move=upright";
$self->sendCmd( $cmd );
}
sub UpLeft
{
my $self = shift;
Debug( "Move Up/Left" );
my $cmd = "/ptz.cgi?move=upleft";
$self->sendCmd( $cmd );
}
sub DownRight
{
my $self = shift;
Debug( "Move Down/Right" );
my $cmd = "/ptz.cgi?move=downright";
$self->sendCmd( $cmd );
}
sub DownLeft
{
my $self = shift;
Debug( "Move Down/Left" );
my $cmd = "/ptz.cgi?move=downleft";
$self->sendCmd( $cmd );
}
#Foco
sub focusAuto
{
my $self = shift;
Debug( "Focus Auto" );
my $cmd = "/ptz.cgi?Autofocus=on";
$self->sendCmd( $cmd );
}
sub focusMan
{
my $self = shift;
Debug( "Focus Manual" );
my $cmd = "/ptz.cgi?Autofocus=off";
$self->sendCmd( $cmd );
}
sub Near
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Focus Near" );
my $cmd = "/ptz.cgi?rfocus=-$step";
$self->sendCmd( $cmd );
}
sub Far
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Focus Far" );
my $cmd = "/ptz.cgi?rfocus=$step";
$self->sendCmd( $cmd );
}
#Iris
sub Open
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Iris Open" );
my $cmd = "/ptz.cgi?riris=$step";
$self->sendCmd( $cmd );
}
sub Close
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Iris Close" );
my $cmd = "/ptz.cgi?riris=-$step";
$self->sendCmd( $cmd );
}
#Custom#
sub moveConUp
{
my $self = shift;
Debug( "Move Up" );
my $cmd = "/ptz.cgi?move=up";
$self->sendCmd( $cmd );
}
sub moveConDown
{
my $self = shift;
Debug( "Move Down" );
my $cmd = "/ptz.cgi?move=down";
$self->sendCmd( $cmd );
}
sub moveConLeft
{
my $self = shift;
Debug( "Move Left" );
my $cmd = "/ptz.cgi?move=left";
$self->sendCmd( $cmd );
}
sub moveConRight
{
my $self = shift;
Debug( "Move Right" );
my $cmd = "/ptz.cgi?move=right";
$self->sendCmd( $cmd );
}
sub moveConUpRight
{
my $self = shift;
Debug( "Move Up/Right" );
my $cmd = "/ptz.cgi?move=upright";
$self->sendCmd( $cmd );
}
sub moveConUpLeft
{
my $self = shift;
Debug( "Move Up/Left" );
my $cmd = "/ptz.cgi?move=upleft";
$self->sendCmd( $cmd );
}
sub moveConDownRight
{
my $self = shift;
Debug( "Move Down/Right" );
my $cmd = "/ptz.cgi?move=downright";
$self->sendCmd( $cmd );
}
sub moveConDownLeft
{
my $self = shift;
Debug( "Move Down/Left" );
my $cmd = "/ptz.cgi?move=downleft";
$self->sendCmd( $cmd );
}
sub moveRelUp
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'tiltstep' );
Debug( "Step Up $step" );
my $cmd = "/ptz.cgi?tilt=$step";
$self->sendCmd( $cmd );
}
sub moveRelDown
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'tiltstep' );
Debug( "Step Down $step" );
my $cmd = "/ptz.cgi?tilt=-$step";
$self->sendCmd( $cmd );
}
sub moveRelLeft
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'panstep' );
Debug( "Step Left $step" );
my $cmd = "/ptz.cgi?pan=-$step";
$self->sendCmd( $cmd );
}
sub moveRelRight
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'panstep' );
Debug( "Step Right $step" );
my $cmd = "/ptz.cgi?pan=$step";
$self->sendCmd( $cmd );
}
sub moveRelUpRight
{
my $self = shift;
my $params = shift;
my $panstep = $self->getParam( $params, 'panstep' );
my $tiltstep = $self->getParam( $params, 'tiltstep' );
Debug( "Step Up/Right $tiltstep/$panstep" );
my $cmd = "/ptz.cgi?pan=$panstep&tilt=$tiltstep";
$self->sendCmd( $cmd );
}
sub moveRelUpLeft
{
my $self = shift;
my $params = shift;
my $panstep = $self->getParam( $params, 'panstep' );
my $tiltstep = $self->getParam( $params, 'tiltstep' );
Debug( "Step Up/Left $tiltstep/$panstep" );
my $cmd = "/ptz.cgi?pan=-$panstep&tilt=$tiltstep";
$self->sendCmd( $cmd );
}
sub moveRelDownRight
{
my $self = shift;
my $params = shift;
my $panstep = $self->getParam( $params, 'panstep' );
my $tiltstep = $self->getParam( $params, 'tiltstep' );
Debug( "Step Down/Right $tiltstep/$panstep" );
my $cmd = "/ptz.cgi?pan=$panstep&tilt=-$tiltstep";
$self->sendCmd( $cmd );
}
sub moveRelDownLeft
{
my $self = shift;
my $params = shift;
my $panstep = $self->getParam( $params, 'panstep' );
my $tiltstep = $self->getParam( $params, 'tiltstep' );
Debug( "Step Down/Left $tiltstep/$panstep" );
my $cmd = "/ptz.cgi?pan=-$panstep&tilt=-$tiltstep";
$self->sendCmd( $cmd );
}
sub zoomRelTele
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Zoom Tele" );
my $cmd = "/ptz.cgi?rzoom=$step";
$self->sendCmd( $cmd );
}
sub zoomRelWide
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Zoom Wide" );
my $cmd = "/ptz.cgi?rzoom=-$step";
$self->sendCmd( $cmd );
}
sub focusRelNear
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Focus Near" );
my $cmd = "/ptz.cgi?rfocus=-$step";
$self->sendCmd( $cmd );
}
sub focusRelFar
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Focus Far" );
my $cmd = "/ptz.cgi?rfocus=$step";
$self->sendCmd( $cmd );
}
sub focusAuto
{
my $self = shift;
Debug( "Focus Auto" );
my $cmd = "/ptz.cgi?Autofocus=on";
$self->sendCmd( $cmd );
}
sub focusMan
{
my $self = shift;
Debug( "Focus Manual" );
my $cmd = "/ptz.cgi?Autofocus=off";
$self->sendCmd( $cmd );
}
sub irisRelOpen
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Iris Open" );
my $cmd = "/ptz.cgi?riris=$step";
$self->sendCmd( $cmd );
}
sub irisRelClose
{
my $self = shift;
my $params = shift;
my $step = $self->getParam( $params, 'step' );
Debug( "Iris Close" );
my $cmd = "/ptz.cgi?riris=-$step";
$self->sendCmd( $cmd );
}
sub irisAuto
{
my $self = shift;
Debug( "Iris Auto" );
my $cmd = "/ptz.cgi?autoiris=on";
$self->sendCmd( $cmd );
}
sub irisMan
{
my $self = shift;
Debug( "Iris Manual" );
my $cmd = "/ptz.cgi?autoiris=off";
$self->sendCmd( $cmd );
}
sub presetClear
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
Debug( "Clear Preset $preset" );
my $cmd = "/ptz.cgi?removeserverpresetno=$preset";
$self->sendCmd( $cmd );
}
sub presetGoto
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
Debug( "Goto Preset $preset" );
my $cmd = "/ptz.cgi?gotoserverpresetno=$preset";
$self->sendCmd( $cmd );
}
sub presetHome
{
my $self = shift;
Debug( "Home Preset" );
my $cmd = "/ptz.cgi?move=home";
$self->sendCmd( $cmd );
}
1;
__END__
# Below is stub documentation for your module. You'd better edit it!
=head1 NAME
ZoneMinder::Database - Perl extension for blah blah blah
=head1 SYNOPSIS
use ZoneMinder::Database;
blah blah blah
=head1 DESCRIPTION
Stub documentation for ZoneMinder, created by h2xs. It looks like the
author of the extension was negligent enough to leave the stub
unedited.
Blah blah blah.
=head2 EXPORT
None by default.
=head1 SEE ALSO
Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.
If you have a mailing list set up for your module, mention it here.
If you have a web site set up for your module, mention it here.
=head1 AUTHOR
Juan Manuel Castro, E<lt>juanmanuel.castro@gmail.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2014 Juan Manuel Castro
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.3 or,
at your option, any later version of Perl 5 you may have available.
=cut

View File

@ -87,7 +87,7 @@ sub write()
my $nbytes = syswrite( $self->{handle}, $buffer );
if ( !defined( $nbytes) || $nbytes < length($buffer) )
{
Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".$nbytes.": $!\n" );
Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".($nbytes?$nbytes:'undefined').": $!\n" );
return( undef );
}
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
@ -106,11 +106,11 @@ __END__
=head1 NAME
ZoneMinder::Database - Perl extension for blah blah blah
ZoneMinder::Trigger::Channel::Handle - Perl extension for blah blah blah
=head1 SYNOPSIS
use ZoneMinder::Database;
use ZoneMinder::Trigger::Channel::Handle;
blah blah blah
=head1 DESCRIPTION

View File

@ -151,7 +151,7 @@ public:
{
if ( mSize == 0 )
mHead = mTail = mStorage;
else if ( level >= 1 )
else if ( level )
{
if ( (mHead-mStorage) > mSize )
{
@ -159,12 +159,6 @@ public:
mHead = mStorage;
mTail = mHead + mSize;
}
else if ( level >= 2 )
{
memmove( mStorage, mHead, mSize );
mHead = mStorage;
mTail = mHead + mSize;
}
}
}
}

View File

@ -23,6 +23,10 @@
#include "zm_ffmpeg_camera.h"
#ifndef AV_ERROR_MAX_STRING_SIZE
#define AV_ERROR_MAX_STRING_SIZE 64
#endif
FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) :
Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ),
mPath( p_path ),
@ -41,6 +45,10 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
mRawFrame = NULL;
mFrame = NULL;
frameCount = 0;
mIsOpening = false;
mCanCapture = false;
mOpenStart = 0;
mReopenThread = 0;
#if HAVE_LIBSWSCALE
mConvertContext = NULL;
@ -63,31 +71,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
FfmpegCamera::~FfmpegCamera()
{
av_freep( &mFrame );
av_freep( &mRawFrame );
#if HAVE_LIBSWSCALE
if ( mConvertContext )
{
sws_freeContext( mConvertContext );
mConvertContext = NULL;
}
#endif
if ( mCodecContext )
{
avcodec_close( mCodecContext );
mCodecContext = NULL; // Freed by av_close_input_file
}
if ( mFormatContext )
{
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0)
avformat_close_input( &mFormatContext );
#else
av_close_input_file( mFormatContext );
#endif
mFormatContext = NULL;
}
CloseFfmpeg();
if ( capture )
{
@ -112,116 +96,11 @@ void FfmpegCamera::Terminate()
int FfmpegCamera::PrimeCapture()
{
Info( "Priming capture from %s", mPath.c_str() );
// Open the input, not necessarily a file
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) !=0 )
#else
// Handle options
AVDictionary *opts = 0;
StringVector opVect = split(Options(), ",");
// Set transport method as specified by method field, rtpUni is default
if ( Method() == "rtpMulti" )
opVect.push_back("rtsp_transport=udp_multicast");
else if ( Method() == "rtpRtsp" )
opVect.push_back("rtsp_transport=tcp");
else if ( Method() == "rtpRtspHttp" )
opVect.push_back("rtsp_transport=http");
Debug(2, "Number of Options: %d",opVect.size());
for (size_t i=0; i<opVect.size(); i++)
{
StringVector parts = split(opVect[i],"=");
if (parts.size() > 1) {
parts[0] = trimSpaces(parts[0]);
parts[1] = trimSpaces(parts[1]);
if ( av_dict_set(&opts, parts[0].c_str(), parts[1].c_str(), 0) == 0 ) {
Debug(2, "set option %d '%s' to '%s'", i, parts[0].c_str(), parts[1].c_str());
}
else
{
Warning( "Error trying to set option %d '%s' to '%s'", i, parts[0].c_str(), parts[1].c_str() );
}
}
if (OpenFfmpeg() != 0){
ReopenFfmpeg();
}
if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) !=0 )
#endif
Fatal( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) );
// Locate stream info from input
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
if ( av_find_stream_info( mFormatContext ) < 0 )
#else
if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 )
#endif
Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) );
// Find first video stream present
mVideoStreamId = -1;
for (unsigned int i=0; i < mFormatContext->nb_streams; i++ )
{
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1)
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
#else
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
#endif
{
mVideoStreamId = i;
break;
}
}
if ( mVideoStreamId == -1 )
Fatal( "Unable to locate video stream in %s", mPath.c_str() );
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
// Try and get the codec from the codec context
if ( (mCodec = avcodec_find_decoder( mCodecContext->codec_id )) == NULL )
Fatal( "Can't find codec for video stream from %s", mPath.c_str() );
// Open the codec
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0)
if ( avcodec_open( mCodecContext, mCodec ) < 0 )
#else
if ( avcodec_open2( mCodecContext, mCodec, 0 ) < 0 )
#endif
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
// Allocate space for the native video frame
mRawFrame = avcodec_alloc_frame();
// Allocate space for the converted video frame
mFrame = avcodec_alloc_frame();
if(mRawFrame == NULL || mFrame == NULL)
Fatal( "Unable to allocate frame for %s", mPath.c_str() );
int pSize = avpicture_get_size( imagePixFormat, width, height );
if( (unsigned int)pSize != imagesize) {
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
}
#if HAVE_LIBSWSCALE
#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 8, 0)
if(!sws_isSupportedInput(mCodecContext->pix_fmt)) {
Fatal("swscale does not support the codec format: %c%c%c%c",(mCodecContext->pix_fmt)&0xff,((mCodecContext->pix_fmt>>8)&0xff),((mCodecContext->pix_fmt>>16)&0xff),((mCodecContext->pix_fmt>>24)&0xff));
}
if(!sws_isSupportedOutput(imagePixFormat)) {
Fatal("swscale does not support the target format: %c%c%c%c",(imagePixFormat)&0xff,((imagePixFormat>>8)&0xff),((imagePixFormat>>16)&0xff),((imagePixFormat>>24)&0xff));
}
#endif
#else // HAVE_LIBSWSCALE
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
#endif // HAVE_LIBSWSCALE
return( 0 );
return 0;
}
int FfmpegCamera::PreCapture()
@ -232,6 +111,24 @@ int FfmpegCamera::PreCapture()
int FfmpegCamera::Capture( Image &image )
{
if (!mCanCapture){
return -1;
}
// If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread.
if (mReopenThread != 0) {
void *retval = 0;
int ret;
ret = pthread_tryjoin_np(mReopenThread, &retval);
if (ret != 0){
Error("Could not join reopen thread.");
}
Info( "Successfully reopened stream." );
mReopenThread = 0;
}
AVPacket packet;
uint8_t* directbuffer;
@ -248,7 +145,20 @@ int FfmpegCamera::Capture( Image &image )
int avResult = av_read_frame( mFormatContext, &packet );
if ( avResult < 0 )
{
Error( "Unable to read packet from stream %d: error %d", packet.stream_index, avResult );
char errbuf[AV_ERROR_MAX_STRING_SIZE];
av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE);
if (
// Check if EOF.
(avResult == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
// Check for Connection failure.
(avResult == -110)
)
{
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf);
ReopenFfmpeg();
}
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf );
return( -1 );
}
Debug( 5, "Got packet from stream %d", packet.stream_index );
@ -300,4 +210,235 @@ int FfmpegCamera::PostCapture()
return( 0 );
}
int FfmpegCamera::OpenFfmpeg() {
Debug ( 2, "OpenFfmpeg called." );
mOpenStart = time(NULL);
mIsOpening = true;
// Open the input, not necessarily a file
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
Debug ( 1, "Calling av_open_input_file" );
if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) !=0 )
#else
// Handle options
AVDictionary *opts = 0;
StringVector opVect = split(Options(), ",");
// Set transport method as specified by method field, rtpUni is default
if ( Method() == "rtpMulti" )
opVect.push_back("rtsp_transport=udp_multicast");
else if ( Method() == "rtpRtsp" )
opVect.push_back("rtsp_transport=tcp");
else if ( Method() == "rtpRtspHttp" )
opVect.push_back("rtsp_transport=http");
Debug(2, "Number of Options: %d",opVect.size());
for (size_t i=0; i<opVect.size(); i++)
{
StringVector parts = split(opVect[i],"=");
if (parts.size() > 1) {
parts[0] = trimSpaces(parts[0]);
parts[1] = trimSpaces(parts[1]);
if ( av_dict_set(&opts, parts[0].c_str(), parts[1].c_str(), 0) == 0 ) {
Debug(2, "set option %d '%s' to '%s'", i, parts[0].c_str(), parts[1].c_str());
}
else
{
Warning( "Error trying to set option %d '%s' to '%s'", i, parts[0].c_str(), parts[1].c_str() );
}
}
}
Debug ( 1, "Calling avformat_open_input" );
mFormatContext = avformat_alloc_context( );
mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback;
mFormatContext->interrupt_callback.opaque = this;
if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) !=0 )
#endif
{
mIsOpening = false;
Error( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) );
return -1;
}
mIsOpening = false;
Debug ( 1, "Opened input" );
// Locate stream info from avformat_open_input
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
Debug ( 1, "Calling av_find_stream_info" );
if ( av_find_stream_info( mFormatContext ) < 0 )
#else
Debug ( 1, "Calling avformat_find_stream_info" );
if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 )
#endif
Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) );
Debug ( 1, "Got stream info" );
// Find first video stream present
mVideoStreamId = -1;
for (unsigned int i=0; i < mFormatContext->nb_streams; i++ )
{
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1)
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
#else
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
#endif
{
mVideoStreamId = i;
break;
}
}
if ( mVideoStreamId == -1 )
Fatal( "Unable to locate video stream in %s", mPath.c_str() );
Debug ( 1, "Found video stream" );
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
// Try and get the codec from the codec context
if ( (mCodec = avcodec_find_decoder( mCodecContext->codec_id )) == NULL )
Fatal( "Can't find codec for video stream from %s", mPath.c_str() );
Debug ( 1, "Found decoder" );
// Open the codec
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0)
Debug ( 1, "Calling avcodec_open" );
if ( avcodec_open( mCodecContext, mCodec ) < 0 )
#else
Debug ( 1, "Calling avcodec_open2" );
if ( avcodec_open2( mCodecContext, mCodec, 0 ) < 0 )
#endif
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
Debug ( 1, "Opened codec" );
// Allocate space for the native video frame
mRawFrame = avcodec_alloc_frame();
// Allocate space for the converted video frame
mFrame = avcodec_alloc_frame();
if(mRawFrame == NULL || mFrame == NULL)
Fatal( "Unable to allocate frame for %s", mPath.c_str() );
Debug ( 1, "Allocated frames" );
int pSize = avpicture_get_size( imagePixFormat, width, height );
if( (unsigned int)pSize != imagesize) {
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
}
Debug ( 1, "Validated imagesize" );
#if HAVE_LIBSWSCALE
Debug ( 1, "Calling sws_isSupportedInput" );
if(!sws_isSupportedInput(mCodecContext->pix_fmt)) {
Fatal("swscale does not support the codec format: %c%c%c%c",(mCodecContext->pix_fmt)&0xff,((mCodecContext->pix_fmt>>8)&0xff),((mCodecContext->pix_fmt>>16)&0xff),((mCodecContext->pix_fmt>>24)&0xff));
}
if(!sws_isSupportedOutput(imagePixFormat)) {
Fatal("swscale does not support the target format: %c%c%c%c",(imagePixFormat)&0xff,((imagePixFormat>>8)&0xff),((imagePixFormat>>16)&0xff),((imagePixFormat>>24)&0xff));
}
#else // HAVE_LIBSWSCALE
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
#endif // HAVE_LIBSWSCALE
mCanCapture = true;
return 0;
}
int FfmpegCamera::ReopenFfmpeg() {
Debug(2, "ReopenFfmpeg called.");
mCanCapture = false;
if (pthread_create( &mReopenThread, NULL, ReopenFfmpegThreadCallback, (void*) this) != 0){
// Log a fatal error and exit the process.
Fatal( "ReopenFfmpeg failed to create worker thread." );
}
return 0;
}
int FfmpegCamera::CloseFfmpeg(){
Debug(2, "CloseFfmpeg called.");
mCanCapture = false;
av_freep( &mFrame );
av_freep( &mRawFrame );
#if HAVE_LIBSWSCALE
if ( mConvertContext )
{
sws_freeContext( mConvertContext );
mConvertContext = NULL;
}
#endif
if ( mCodecContext )
{
avcodec_close( mCodecContext );
mCodecContext = NULL; // Freed by av_close_input_file
}
if ( mFormatContext )
{
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
av_close_input_file( mFormatContext );
#else
avformat_close_input( &mFormatContext );
#endif
mFormatContext = NULL;
}
return 0;
}
int FfmpegCamera::FfmpegInterruptCallback(void *ctx)
{
FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx);
if (camera->mIsOpening){
int now = time(NULL);
if ((now - camera->mOpenStart) > config.ffmpeg_open_timeout) {
Error ( "Open video took more than %d seconds.", config.ffmpeg_open_timeout );
return 1;
}
}
return 0;
}
void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){
if (ctx == NULL) return NULL;
FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx);
while (1){
// Close current stream.
camera->CloseFfmpeg();
// Sleep if neccessary to not reconnect too fast.
int wait = config.ffmpeg_open_timeout - (time(NULL) - camera->mOpenStart);
wait = wait < 0 ? 0 : wait;
if (wait > 0){
Debug( 1, "Sleeping %d seconds before reopening stream.", wait );
sleep(wait);
}
if (camera->OpenFfmpeg() == 0){
return NULL;
}
}
}
#endif // HAVE_LIBAVFORMAT

View File

@ -47,6 +47,16 @@ protected:
AVFrame *mRawFrame;
AVFrame *mFrame;
PixelFormat imagePixFormat;
int OpenFfmpeg();
int ReopenFfmpeg();
int CloseFfmpeg();
static int FfmpegInterruptCallback(void *ctx);
static void* ReopenFfmpegThreadCallback(void *ctx);
bool mIsOpening;
bool mCanCapture;
int mOpenStart;
pthread_t mReopenThread;
#endif // HAVE_LIBAVFORMAT
#if HAVE_LIBSWSCALE

View File

@ -129,10 +129,10 @@ int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen )
}
}
int paddedLen = 4+2+item->len+1; // Add null byte
paddedLen = (((paddedLen-1)/4)+1)*4;
paddedLen = (((paddedLen-1)/4)+1)*4; // Round to nearest multiple of 4
Debug( 5, "RTCP PL:%d", paddedLen );
sdesPtr += paddedLen;
contentLen -= paddedLen;
contentLen = ( paddedLen <= contentLen ) ? ( contentLen - paddedLen ) : 0;
}
}
break;
@ -175,13 +175,13 @@ int RtpCtrlThread::generateRr( const unsigned char *packet, ssize_t packetLen )
mRtpSource.updateRtcpStats();
Debug( 5, "Ssrc = %d", mRtspThread.getSsrc() );
Debug( 5, "Ssrc = %d", mRtspThread.getSsrc()+1 );
Debug( 5, "Ssrc_1 = %d", mRtpSource.getSsrc() );
Debug( 5, "Last Seq = %d", mRtpSource.getMaxSeq() );
Debug( 5, "Jitter = %d", mRtpSource.getJitter() );
Debug( 5, "Last SR = %d", mRtpSource.getLastSrTimestamp() );
rtcpPacket->body.rr.ssrcN = htonl(mRtspThread.getSsrc());
rtcpPacket->body.rr.ssrcN = htonl(mRtspThread.getSsrc()+1);
rtcpPacket->body.rr.rr[0].ssrcN = htonl(mRtpSource.getSsrc());
rtcpPacket->body.rr.rr[0].lost = mRtpSource.getLostPackets();
rtcpPacket->body.rr.rr[0].fraction = mRtpSource.getLostFraction();
@ -208,7 +208,7 @@ int RtpCtrlThread::generateSdes( const unsigned char *packet, ssize_t packetLen
rtcpPacket->header.count = 1;
rtcpPacket->header.lenN = htons(wordLen-1);
rtcpPacket->body.sdes.srcN = htonl(mRtpSource.getSsrc());
rtcpPacket->body.sdes.srcN = htonl(mRtpSource.getSsrc()+1);
rtcpPacket->body.sdes.item[0].type = RTCP_SDES_CNAME;
rtcpPacket->body.sdes.item[0].len = cname.size();
memcpy( rtcpPacket->body.sdes.item[0].data, cname.data(), cname.size() );

View File

@ -348,9 +348,23 @@ int RtspThread::run()
std::string localHost = "";
int localPorts[2] = { 0, 0 };
//message = "OPTIONS * RTSP/1.0\r\n";
//sendCommand( message );
//recvResponse( response );
// Request supported RTSP commands by the server
message = "OPTIONS * RTSP/1.0\r\n";
if ( !sendCommand( message ) )
return( -1 );
if ( !recvResponse( response ) )
return( -1 );
char publicLine[256] = "";
StringVector lines = split( response, "\r\n" );
for ( size_t i = 0; i < lines.size(); i++ )
sscanf( lines[i].c_str(), "Public: %[^\r\n]\r\n", publicLine );
// Check if the server supports the GET_PARAMETER command
// If yes, it is likely that the server will request this command as a keepalive message
bool sendKeepalive = false;
if ( publicLine[0] && strstr(publicLine, "GET_PARAMETER") )
sendKeepalive = true;
message = "DESCRIBE "+mUrl+" RTSP/1.0\r\n";
bool res;
@ -414,7 +428,16 @@ int RtspThread::run()
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
#endif
{
trackUrl += "/"+mediaDesc->getControlUrl();
// Check if control Url is absolute or relative
std::string controlUrl = mediaDesc->getControlUrl();
if (std::equal(trackUrl.begin(), trackUrl.end(), controlUrl.begin()))
{
trackUrl = controlUrl;
}
else
{
trackUrl += "/" + controlUrl;
}
rtpClock = mediaDesc->getClock();
codecId = mFormatContext->streams[i]->codec->codec_id;
// Hackery pokery
@ -457,7 +480,7 @@ int RtspThread::run()
if ( !recvResponse( response ) )
return( -1 );
StringVector lines = split( response, "\r\n" );
lines = split( response, "\r\n" );
char *session = 0;
int timeout = 0;
char transport[256] = "";
@ -570,6 +593,9 @@ int RtspThread::run()
Debug( 2, "RTSP Seq is %d", seq );
Debug( 2, "RTSP Rtptime is %ld", rtpTime );
time_t lastKeepalive = time(NULL);
message = "GET_PARAMETER "+mUrl+" RTSP/1.0\r\nSession: "+session+"\r\n";
switch( mMethod )
{
case RTP_UNICAST :
@ -584,6 +610,13 @@ int RtspThread::run()
while( !mStop )
{
// Send a keepalive message if the server supports this feature and we are close to the timeout expiration
if ( sendKeepalive && (timeout > 0) && ((time(NULL)-lastKeepalive) > (timeout-5)) )
{
if ( !sendCommand( message ) )
return( -1 );
lastKeepalive = time(NULL);
}
usleep( 100000 );
}
#if 0
@ -629,7 +662,6 @@ int RtspThread::run()
select.addReader( &mRtspSocket );
Buffer buffer( ZM_NETWORK_BUFSIZ );
time_t lastKeepalive = time(NULL);
std::string keepaliveMessage = "OPTIONS * RTSP/1.0\r\n";
std::string keepaliveResponse = "RTSP/1.0 200 OK\r\n";
while ( !mStop && select.wait() >= 0 )
@ -719,7 +751,9 @@ int RtspThread::run()
}
}
}
if ( (timeout > 0) && ((time(NULL)-lastKeepalive) > (timeout-5)) )
// Send a keepalive message if the server supports this feature and we are close to the timeout expiration
// FIXME: Is this really necessary when using tcp ?
if ( sendKeepalive && (timeout > 0) && ((time(NULL)-lastKeepalive) > (timeout-5)) )
{
if ( !sendCommand( message ) )
return( -1 );
@ -734,11 +768,10 @@ int RtspThread::run()
if ( !recvResponse( response ) )
return( -1 );
#endif
// Send a teardown message but don't expect a response as this may not be implemented on the server when using TCP
message = "TEARDOWN "+mUrl+" RTSP/1.0\r\nSession: "+session+"\r\n";
if ( !sendCommand( message ) )
return( -1 );
if ( !recvResponse( response ) )
return( -1 );
delete mSources[ssrc];
mSources.clear();
@ -757,6 +790,13 @@ int RtspThread::run()
while( !mStop )
{
// Send a keepalive message if the server supports this feature and we are close to the timeout expiration
if ( sendKeepalive && (timeout > 0) && ((time(NULL)-lastKeepalive) > (timeout-5)) )
{
if ( !sendCommand( message ) )
return( -1 );
lastKeepalive = time(NULL);
}
usleep( 100000 );
}
#if 0

View File

@ -126,6 +126,17 @@ StringVector split( const std::string &string, const std::string chars, int limi
return( stringVector );
}
const std::string join(const StringVector v, const char * delim ) {
std::stringstream ss;
for(size_t i = 0; i < v.size(); ++i) {
if(i != 0)
ss << ",";
ss << v[i];
}
return ss.str();
}
const std::string base64Encode( const std::string &inString )
{
static char base64_table[64] = { '\0' };

View File

@ -23,6 +23,7 @@
#include <time.h>
#include <sys/time.h>
#include <string>
#include <sstream>
#include <vector>
typedef std::vector<std::string> StringVector;
@ -36,6 +37,7 @@ const std::string stringtf( const std::string &format, ... );
bool startsWith( const std::string &haystack, const std::string &needle );
StringVector split( const std::string &string, const std::string chars, int limit=0 );
const std::string join( const StringVector, const char * );
const std::string base64Encode( const std::string &inString );

100
utils/zmeditconfigdata.sh Executable file
View File

@ -0,0 +1,100 @@
#!/bin/bash
# This script allows the package maintainer to change the default value
# of any variable specified in ConfigData.pm without writing a patch.
# Run this script from your build folder, before running configure or cmake.
usage()
{
cat <<EOF
USAGE:
$0 VARIABLE DEFAULT [CONFIGDATA DIRECTORY]
Replace the default value, DEFAULT, of the specified ZoneMinder
variable, VARIABLE, located in ConfigData.pm.in.
Default folder for ConfigData is ./scripts/ZoneMinder/lib/ZoneMinder
Specify CONFIGDATA DIRETORY to override.
Run this script from your build folder, before running configure or cmake.
EXAMPLE:
zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
WARNING:
The user supplied value for DEFAULT is not checked for sanity. For example,
changing ZM_LANG_DEFAULT to "pony" will cause bad things to happen!
EOF
}
if [ -z "$1" ] || [ -z "$2" ]; then
usage
exit 0
fi
# Check to see if this script has access to all the commands it needs
for CMD in set echo printf grep sed ; do
type $CMD &> /dev/null
if [ $? -ne 0 ]; then
echo
echo "ERROR: The script cannot find the required command \"${CMD}\"."
echo
exit 1
fi
done
escape()
{
escaped=""
local temp="$(printf %q "$1")"
escaped="$(echo $temp | sed 's/\//\\\//g')"
}
# Assign variables once they are properly escaped
escape $1
variable=$escaped
escape $2
default=$escaped
# Set the path to ConfigData
if [ -n "$3" ]; then
configdata="$3/ConfigData.pm.in"
else
configdata="./scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in"
fi
# Check to make sure we can find ConfigData
if [ ! -e "$configdata" ]; then
echo "CONFIGDATA FILE NOT FOUND: $configdata"
exit 1
fi
# Now that we've found ConfidData, verify the supplied variable
# is defined inside the ConfigData file.
if [ -z "$(grep $variable $configdata)" ]; then
echo "ZONEMINDER VARIABLE NOT FOUND: $variable"
exit 1
fi
# Update the supplied variable with the new default value.
# Don't stare too closely. You will burn your eyes out.
sed -i '/.*'${variable}'.*/{
$!{ N
s/\(.*'${variable}'.*\n.*\)\"\(.*\)\"/\1\"'${default}'\"/
t yes
P
D
:yes
}
}' $configdata
if [ "$?" != "0" ]; then
echo "SED RETURNED FAILURE"
exit 1
fi

View File

@ -10,7 +10,8 @@ switch ( $_REQUEST['task'] )
logInit( array( 'id' => "web_js" ) );
$string = $_POST['message'];
$file = preg_replace( '/\w+:\/\/\w+\//', '', $_POST['file'] );
$file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/\w+\//', '', $_POST['file'] ) : '';
if ( !empty( $_POST['line'] ) )
$line = $_POST['line'];
else

View File

@ -0,0 +1,80 @@
<?php
App::uses('Component', 'Controller');
class ConfigParserComponent extends Component {
public function parseHints($hint) {
$string = "";
$hints = explode('|', $hint);
foreach ($hints as $hint) {
$string .= "<option value=\"$hint\">$hint</option>";
}
return $string;
}
public function getLabel($name) {
$width = 'col-md-4';
$string = '<div class="form-group">';
$string .= '<label for="%s" class="control-label %s">%s</label>';
$label = sprintf($string, $name, $width, $name);
$label .= '<div class="col-md-6">';
return $label;
}
public function getInput($name, $type, $id) {
if ($type == 'checkbox') {
$string = '<input id="%s" type="checkbox" ng-change="updateConfig(\'%s\', \'%s\')" ng-model="myModel.configData[\'%s\']" ng-true-value="1" ng-false-value="0"><span class="form-control-feedback"></span></div>';
} elseif ($type == 'text') {
$string = '<input id="%s" type="text" ng-change="updateConfig(\'%s\', \'%s\')" ng-model="myModel.configData[\'%s\']" class="form-control"><span class="form-control-feedback"></span></div>';
} elseif ($type == 'textarea') {
$string = '<textarea id="%s" ng-change="updateConfig(\'%s\', \'%s\')" class="form-control" rows="3" ng-model="myModel.configData[\'%s\']"></textarea><span class="form-control-feedback"></span></div>';
} elseif ($type == 'select') {
$string = '<select id="%s" ng-change="updateConfig(\'%s\', \'%s\')" class="form-control" ng-model="myModel.configData[\'%s\']">';
}
$input = sprintf($string, $name, $id, $name, $name);
return $input;
}
public function parseOptions($configs) {
$category = $configs[0]['Config']['Category'];
$string = "";
foreach ($configs as $option) {
$type = $option['Config']['Type'];
$name = $option['Config']['Name'];
$value = $option['Config']['Value'];
$hint = $option['Config']['Hint'];
$id = $option['Config']['Id'];
$string .= $this->getLabel($name);
switch ($type) {
case "boolean":
$string .= $this->getInput($name, 'checkbox', $id);
break;
case "text":
$string .= $this->getInput($name, 'textarea', $id);
break;
case "string":
if (strpos($hint, '|') === FALSE) {
$string .= $this->getInput($name, 'text', $id);
} else {
$string .= $this->getInput($name, 'select', $id);
$string .= $this->parseHints($hint);
$string .= '</select> <span class="form-control-feedback"></span> </div>';
}
break;
default:
$string .= $this->getInput($name, 'text', $id);
}
$string .= "</div><!-- End .form-group -->\n";
}
return $string;
}
}
?>

View File

@ -88,4 +88,50 @@ class ConfigsController extends AppController {
} else {
return $this->flash(__('The config could not be deleted. Please, try again.'), array('action' => 'index'));
}
}}
}
/**
* categories method
*
* Either return a list of distinct categories
* Or all configs under a certain category
*/
public function categories($category = null) {
if ($category != null) {
if (!$this->Config->find('first', array( 'conditions' => array('Config.Category' => $category)))) {
throw new NotFoundException(__('Invalid Config Category'));
}
$config = $this->Config->find('all', array(
'conditions' => array('Config.Category' => $category),
'recursive' => 0
));
$this->set(array(
'config' => $config,
'_serialize' => array('config')
));
} else {
$categories = $this->Config->find('all', array(
'fields' => array('DISTINCT Config.Category'),
'conditions' => array('Config.Category !=' => 'hidden'),
'recursive' => 0
));
$this->set(array(
'categories' => $categories,
'_serialize' => array('categories')
));
}
}
public function keyValue() {
$keyValues = $this->Config->find('list', array(
'fields' => array('Config.Name', 'Config.Value')
));
$this->set(array(
'keyValues' => $keyValues,
'_serialize' => array('keyValues')
));
}
}

View File

@ -0,0 +1,96 @@
<?php
App::uses('AppController', 'Controller');
/**
* Logs Controller
*
* @property Log $Log
* @property PaginatorComponent $Paginator
*/
class LogsController extends AppController {
/**
* Components
*
* @var array
*/
public $components = array('Paginator');
/**
* index method
*
* @return void
*/
public function index() {
$this->Log->recursive = 0;
$this->set('logs', $this->Paginator->paginate());
}
/**
* view method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function view($id = null) {
if (!$this->Log->exists($id)) {
throw new NotFoundException(__('Invalid log'));
}
$options = array('conditions' => array('Log.' . $this->Log->primaryKey => $id));
$this->set('log', $this->Log->find('first', $options));
}
/**
* add method
*
* @return void
*/
public function add() {
if ($this->request->is('post')) {
$this->Log->create();
if ($this->Log->save($this->request->data)) {
return $this->flash(__('The log has been saved.'), array('action' => 'index'));
}
}
}
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
if (!$this->Log->exists($id)) {
throw new NotFoundException(__('Invalid log'));
}
if ($this->request->is(array('post', 'put'))) {
if ($this->Log->save($this->request->data)) {
return $this->flash(__('The log has been saved.'), array('action' => 'index'));
}
} else {
$options = array('conditions' => array('Log.' . $this->Log->primaryKey => $id));
$this->request->data = $this->Log->find('first', $options);
}
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
$this->Log->id = $id;
if (!$this->Log->exists()) {
throw new NotFoundException(__('Invalid log'));
}
$this->request->allowMethod('post', 'delete');
if ($this->Log->delete()) {
return $this->flash(__('The log has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The log could not be deleted. Please, try again.'), array('action' => 'index'));
}
}}

View File

@ -108,4 +108,21 @@ class MonitorsController extends AppController {
} else {
return $this->flash(__('The monitor could not be deleted. Please, try again.'), array('action' => 'index'));
}
}}
}
public function sourceTypes() {
$sourceTypes = $this->Monitor->query("describe Monitors Type;");
preg_match('/^enum\((.*)\)$/', $sourceTypes[0]['COLUMNS']['Type'], $matches);
foreach( explode(',', $matches[1]) as $value ) {
$enum[] = trim( $value, "'" );
}
$this->set(array(
'sourceTypes' => $enum,
'_serialize' => array('sourceTypes')
));
}
}

23
web/api/app/Model/Log.php Normal file
View File

@ -0,0 +1,23 @@
<?php
App::uses('AppModel', 'Model');
/**
* Log Model
*
*/
class Log extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Logs';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'TimeKey';
}

View File

@ -0,0 +1 @@
echo json_encode($config);

View File

@ -0,0 +1,23 @@
<div class="logs form">
<?php echo $this->Form->create('Log'); ?>
<fieldset>
<legend><?php echo __('Add Log'); ?></legend>
<?php
echo $this->Form->input('Component');
echo $this->Form->input('Pid');
echo $this->Form->input('Level');
echo $this->Form->input('Code');
echo $this->Form->input('Message');
echo $this->Form->input('File');
echo $this->Form->input('Line');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
<div class="actions">
<h3><?php echo __('Actions'); ?></h3>
<ul>
<li><?php echo $this->Html->link(__('List Logs'), array('action' => 'index')); ?></li>
</ul>
</div>

View File

@ -0,0 +1,25 @@
<div class="logs form">
<?php echo $this->Form->create('Log'); ?>
<fieldset>
<legend><?php echo __('Edit Log'); ?></legend>
<?php
echo $this->Form->input('TimeKey');
echo $this->Form->input('Component');
echo $this->Form->input('Pid');
echo $this->Form->input('Level');
echo $this->Form->input('Code');
echo $this->Form->input('Message');
echo $this->Form->input('File');
echo $this->Form->input('Line');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
<div class="actions">
<h3><?php echo __('Actions'); ?></h3>
<ul>
<li><?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('Log.TimeKey')), null, __('Are you sure you want to delete # %s?', $this->Form->value('Log.TimeKey'))); ?></li>
<li><?php echo $this->Html->link(__('List Logs'), array('action' => 'index')); ?></li>
</ul>
</div>

View File

@ -0,0 +1,52 @@
<div class="logs index">
<h2><?php echo __('Logs'); ?></h2>
<table cellpadding="0" cellspacing="0">
<tr>
<th><?php echo $this->Paginator->sort('TimeKey'); ?></th>
<th><?php echo $this->Paginator->sort('Component'); ?></th>
<th><?php echo $this->Paginator->sort('Pid'); ?></th>
<th><?php echo $this->Paginator->sort('Level'); ?></th>
<th><?php echo $this->Paginator->sort('Code'); ?></th>
<th><?php echo $this->Paginator->sort('Message'); ?></th>
<th><?php echo $this->Paginator->sort('File'); ?></th>
<th><?php echo $this->Paginator->sort('Line'); ?></th>
<th class="actions"><?php echo __('Actions'); ?></th>
</tr>
<?php foreach ($logs as $log): ?>
<tr>
<td><?php echo h($log['Log']['TimeKey']); ?>&nbsp;</td>
<td><?php echo h($log['Log']['Component']); ?>&nbsp;</td>
<td><?php echo h($log['Log']['Pid']); ?>&nbsp;</td>
<td><?php echo h($log['Log']['Level']); ?>&nbsp;</td>
<td><?php echo h($log['Log']['Code']); ?>&nbsp;</td>
<td><?php echo h($log['Log']['Message']); ?>&nbsp;</td>
<td><?php echo h($log['Log']['File']); ?>&nbsp;</td>
<td><?php echo h($log['Log']['Line']); ?>&nbsp;</td>
<td class="actions">
<?php echo $this->Html->link(__('View'), array('action' => 'view', $log['Log']['TimeKey'])); ?>
<?php echo $this->Html->link(__('Edit'), array('action' => 'edit', $log['Log']['TimeKey'])); ?>
<?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $log['Log']['TimeKey']), array(), __('Are you sure you want to delete # %s?', $log['Log']['TimeKey'])); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
<p>
<?php
echo $this->Paginator->counter(array(
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
));
?> </p>
<div class="paging">
<?php
echo $this->Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
echo $this->Paginator->numbers(array('separator' => ''));
echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
?>
</div>
</div>
<div class="actions">
<h3><?php echo __('Actions'); ?></h3>
<ul>
<li><?php echo $this->Html->link(__('New Log'), array('action' => 'add')); ?></li>
</ul>
</div>

View File

@ -0,0 +1,54 @@
<div class="logs view">
<h2><?php echo __('Log'); ?></h2>
<dl>
<dt><?php echo __('TimeKey'); ?></dt>
<dd>
<?php echo h($log['Log']['TimeKey']); ?>
&nbsp;
</dd>
<dt><?php echo __('Component'); ?></dt>
<dd>
<?php echo h($log['Log']['Component']); ?>
&nbsp;
</dd>
<dt><?php echo __('Pid'); ?></dt>
<dd>
<?php echo h($log['Log']['Pid']); ?>
&nbsp;
</dd>
<dt><?php echo __('Level'); ?></dt>
<dd>
<?php echo h($log['Log']['Level']); ?>
&nbsp;
</dd>
<dt><?php echo __('Code'); ?></dt>
<dd>
<?php echo h($log['Log']['Code']); ?>
&nbsp;
</dd>
<dt><?php echo __('Message'); ?></dt>
<dd>
<?php echo h($log['Log']['Message']); ?>
&nbsp;
</dd>
<dt><?php echo __('File'); ?></dt>
<dd>
<?php echo h($log['Log']['File']); ?>
&nbsp;
</dd>
<dt><?php echo __('Line'); ?></dt>
<dd>
<?php echo h($log['Log']['Line']); ?>
&nbsp;
</dd>
</dl>
</div>
<div class="actions">
<h3><?php echo __('Actions'); ?></h3>
<ul>
<li><?php echo $this->Html->link(__('Edit Log'), array('action' => 'edit', $log['Log']['TimeKey'])); ?> </li>
<li><?php echo $this->Form->postLink(__('Delete Log'), array('action' => 'delete', $log['Log']['TimeKey']), null, __('Are you sure you want to delete # %s?', $log['Log']['TimeKey'])); ?> </li>
<li><?php echo $this->Html->link(__('List Logs'), array('action' => 'index')); ?> </li>
<li><?php echo $this->Html->link(__('New Log'), array('action' => 'add')); ?> </li>
</ul>
</div>

View File

@ -654,21 +654,14 @@ if ( !empty($action) )
}
// System view actions
if ( canView( 'System' ) )
{
if ( $action == "setgroup" )
{
if ( !empty($_REQUEST['gid']) )
{
setcookie( "zmGroup", validInt($_REQUEST['gid']), time()+3600*24*30*12*10 );
}
else
{
setcookie( "zmGroup", "", time()-3600*24*2 );
}
$refreshParent = true;
}
}
if ( $action == "setgroup" ) {
if ( !empty($_REQUEST['gid']) ) {
setcookie( "zmGroup", validInt($_REQUEST['gid']), time()+3600*24*30*12*10 );
} else {
setcookie( "zmGroup", "", time()-3600*24*2 );
}
$refreshParent = true;
}
// System edit actions
if ( canEdit( 'System' ) )
@ -861,13 +854,10 @@ if ( !empty($action) )
}
elseif ( $action == "group" )
{
if ( !empty($_REQUEST['gid']) )
{
dbQuery( "update Groups set Name=?, MonitorIds=? WHERE Id=?", array($_REQUEST['newGroup']['Name'], join(',',$_REQUEST['newGroup']['MonitorIds']), $_REQUEST['gid']) );
}
else
{
dbQuery( "insert into Groups set Name=?, MonitorIds=?", array( $_REQUEST['newGroup']['Name'], join(',',$_REQUEST['newGroup']['MonitorIds'])) );
if ( !empty($_POST['gid']) ) {
dbQuery( "UPDATE Groups SET Name=?, MonitorIds=? WHERE Id=?", array($_POST['newGroup']['Name'], $_POST['newGroup']['MonitorIds'], $_POST['gid']) );
} else {
dbQuery( "INSERT INTO Groups SET Name=?, MonitorIds=?", array( $_POST['newGroup']['Name'], empty($_POST['newGroup']['MonitorIds']) ? array() : $_POST['newGroup']['MonitorIds'] ) );
}
$refreshParent = true;
$view = 'none';

View File

@ -57,8 +57,10 @@ function logReport( level, message, file, line )
requestParms += "&level="+level+"&message="+encodeURIComponent(message);
if ( file )
requestParms += "&file="+file;
else
else if ( location.search ) {
//location.search is the querystring part, so ?blah=blah but there is almost never any value to this
requestParms += "&file="+location.search;
}
if ( line )
requestParms += "&line="+line;
debugReq.send( requestParms );

View File

@ -190,7 +190,7 @@ xhtmlHeaders( __FILE__, $SLANG['Console'] );
<h3 id="systemStats"><?= $SLANG['Load'] ?>: <?= getLoad() ?> / <?= $SLANG['Disk'] ?>: <?= getDiskPercent() ?>%</h3>
<h2 id="title"><a href="http://www.zoneminder.com" target="ZoneMinder">ZoneMinder</a> <?= $SLANG['Console'] ?> - <?= makePopupLink( '?view=state', 'zmState', 'state', $status, canEdit( 'System' ) ) ?> - <?= makePopupLink( '?view=version', 'zmVersion', 'version', '<span class="'.$versionClass.'">v'.ZM_VERSION.'</span>', canEdit( 'System' ) ) ?></h2>
<div class="clear"></div>
<div id="monitorSummary"><?= makePopupLink( '?view=groups', 'zmGroups', 'groups', sprintf( $CLANG['MonitorCount'], count($displayMonitors), zmVlang( $VLANG['Monitor'], count($displayMonitors) ) ).($group?' ('.$group['Name'].')':''), canView( 'System' ) ); ?></div>
<div id="monitorSummary"><?= makePopupLink( '?view=groups', 'zmGroups', 'groups', 'Group: ' . ($group?' ('.$group['Name'].')':'All').': '. sprintf( $CLANG['MonitorCount'], count($displayMonitors), zmVlang( $VLANG['Monitor'], count($displayMonitors) ) ) ); ?></div>
<?php
if ( ZM_OPT_X10 && canView( 'Devices' ) )
{

View File

@ -18,11 +18,6 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
if ( !canView( 'System' ) )
{
$view = "error";
return;
}
$sql = "select * from Groups order by Name";
$groups = array();
@ -66,18 +61,13 @@ xhtmlHeaders(__FILE__, $SLANG['Groups'] );
<td class="colIds"><?= $SLANG['All'] ?></td>
<td class="colSelect"><input type="radio" name="gid" value="0"<?= !$selected?' checked="checked"':'' ?> onclick="configureButtons( this );"/></td>
</tr>
<?php
foreach ( $groups as $group )
{
?>
<?php foreach ( $groups as $group ) { ?>
<tr>
<td class="colName"><?= validHtmlStr($group['Name']) ?></td>
<td class="colIds"><?= monitorIdsToNames( $group['MonitorIds'], 30 ) ?></td>
<td class="colSelect"><input type="radio" name="gid" value="<?= $group['Id'] ?>"<?= $group['selected']?' checked="checked"':'' ?> onclick="configureButtons( this );"/></td>
</tr>
<?php
}
?>
<?php } ?>
</tbody>
</table>
<div id="contentButtons">

View File

@ -306,8 +306,5 @@ if ( focusWindow )
{
windowToFront();
}
<<<<<<< HEAD
=======
>>>>>>> release-1.28
window.addEvent( 'domready', checkSize);

View File

@ -73,7 +73,7 @@ $status = $running?$SLANG['Running']:$SLANG['Stopped'];
$group = NULL;
if ( ! empty($_COOKIE['zmGroup']) ) {
if ( $group = dbFetchOne( 'SELECT * FROM Groups WHERE Id = ?', NULL, array($_COOKIE['zmGroup']) ) )
if ( $group = dbFetchOne( 'select * from Groups where Id = ?', NULL, array($_COOKIE['zmGroup'])) )
$groupIds = array_flip(explode( ',', $group['MonitorIds'] ));
}
@ -85,7 +85,7 @@ $cycleCount = 0;
$minSequence = 0;
$maxSequence = 1;
$seqIdList = array();
$monitors = dbFetchAll( 'SELECT * FROM Monitors ORDER BY Sequence ASC' );
$monitors = dbFetchAll( "select * from Monitors order by Sequence asc" );
$displayMonitors = array();
for ( $i = 0; $i < count($monitors); $i++ )
{
@ -108,7 +108,7 @@ for ( $i = 0; $i < count($monitors); $i++ )
}
$monitors[$i]['zmc'] = zmcStatus( $monitors[$i] );
$monitors[$i]['zma'] = zmaStatus( $monitors[$i] );
$monitors[$i]['ZoneCount'] = dbFetchOne( 'SELECT count(Id) AS ZoneCount FROM Zones WHERE MonitorId = ?', 'ZoneCount', array( $monitors[$i]['Id'] ) );
$monitors[$i]['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitors[$i]['Id']) );
$counts = array();
for ( $j = 0; $j < count($eventCounts); $j++ )
{
@ -117,8 +117,8 @@ for ( $i = 0; $i < count($monitors); $i++ )
$counts[] = "count(if(1".$filter['sql'].",1,NULL)) as EventCount$j";
$monitors[$i]['eventCounts'][$j]['filter'] = $filter;
}
$sql = 'SELECT '.join($counts,', ').' FROM Events AS E WHERE MonitorId = ?';
$counts = dbFetchOne( $sql, NULL, array( $monitors[$i]['Id'] ) );
$sql = "select ".join($counts,", ")." from Events as E where MonitorId = ?";
$counts = dbFetchOne( $sql, NULL, array($monitors[$i]['Id']) );
if ( $monitors[$i]['Function'] != 'None' )
{
$cycleCount++;
@ -190,7 +190,7 @@ xhtmlHeaders( __FILE__, $SLANG['Console'] );
<h3 id="systemStats"><?= $SLANG['Load'] ?>: <?= getLoad() ?> / <?= $SLANG['Disk'] ?>: <?= getDiskPercent() ?>%</h3>
<h2 id="title"><a href="http://www.zoneminder.com" target="ZoneMinder">ZoneMinder</a> <?= $SLANG['Console'] ?> - <?= makePopupLink( '?view=state', 'zmState', 'state', $status, canEdit( 'System' ) ) ?> - <?= makePopupLink( '?view=version', 'zmVersion', 'version', '<span class="'.$versionClass.'">v'.ZM_VERSION.'</span>', canEdit( 'System' ) ) ?></h2>
<div class="clear"></div>
<div id="monitorSummary"><?= makePopupLink( '?view=groups', 'zmGroups', 'groups', sprintf( $CLANG['MonitorCount'], count($displayMonitors), zmVlang( $VLANG['Monitor'], count($displayMonitors) ) ).($group?' ('.$group['Name'].')':''), canView( 'System' ) ); ?></div>
<div id="monitorSummary"><?= makePopupLink( '?view=groups', 'zmGroups', 'groups', 'Group: ' . ($group?' ('.$group['Name'].')':'All').': '. sprintf( $CLANG['MonitorCount'], count($displayMonitors), zmVlang( $VLANG['Monitor'], count($displayMonitors) ) ) ); ?></div>
<?php
if ( ZM_OPT_X10 && canView( 'Devices' ) )
{
@ -226,7 +226,7 @@ else
{
?><?= $SLANG['ConfiguredFor'] ?><?php
}
?>&nbsp;<?= makePopupLink( '?view=bandwidth', 'zmBandwidth', 'bandwidth', $bwArray[$_COOKIE['zmBandwidth']], ($user && $user['MaxBandwidth'] != 'low' ) ) ?> <?= $SLANG['Bandwidth'] ?></h3>
?>&nbsp;<?= makePopupLink( '?view=bandwidth', 'zmBandwidth', 'bandwidth', $bwArray[$_COOKIE['zmBandwidth']], ($user && $user['MaxBandwidth'] != 'low' ) ) ?> <?= $SLANG['BandwidthHead'] ?></h3>
</div>
<div id="content">
<table id="consoleTable" cellspacing="0">
@ -302,7 +302,7 @@ foreach( $displayMonitors as $monitor )
$scale = max( reScale( SCALE_BASE, $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
?>
<td class="colName"><?= makePopupLink( '?view=watch&amp;mid='.$monitor['Id'], 'zmWatch'.$monitor['Id'], array( 'watch', reScale( $monitor['Width'], $scale ), reScale( $monitor['Height'], $scale ) ), $monitor['Name'], $running && ($monitor['Function'] != 'None') && canView( 'Stream' ) ) ?></td>
<td class="colFunction"><?= makePopupLink( '?view=function&amp;mid='.$monitor['Id'], 'zmFunction', 'function', '<span class="'.$fclass.'">'.$monitor['Function'].( empty($monitor['Enabled']) ? ', disabled' : '' ).'</span>', canEdit( 'Monitors' ) ) ?></td>
<td class="colFunction"><?= makePopupLink( '?view=function&amp;mid='.$monitor['Id'], 'zmFunction', 'function', '<span class="'.$fclass.'">'.$SLANG['Fn'.$monitor['Function']].( empty($monitor['Enabled']) ? ', disabled' : '' ) .'</span>', canEdit( 'Monitors' ) ) ?></td>
<?php if ( $monitor['Type'] == "Local" ) { ?>
<td class="colSource"><?= makePopupLink( '?view=monitor&amp;mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', '<span class="'.$dclass.'">'.$monitor['Device'].' ('.$monitor['Channel'].')</span>', canEdit( 'Monitors' ) ) ?></td>
<?php } elseif ( $monitor['Type'] == "Remote" ) { ?>

View File

@ -18,11 +18,6 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
if ( !canView( 'System' ) )
{
$view = "error";
return;
}
$sql = "select * from Groups order by Name";
$groups = array();
@ -66,18 +61,13 @@ xhtmlHeaders(__FILE__, $SLANG['Groups'] );
<td class="colIds"><?= $SLANG['All'] ?></td>
<td class="colSelect"><input type="radio" name="gid" value="0"<?= !$selected?' checked="checked"':'' ?> onclick="configureButtons( this );"/></td>
</tr>
<?php
foreach ( $groups as $group )
{
?>
<?php foreach ( $groups as $group ) { ?>
<tr>
<td class="colName"><?= validHtmlStr($group['Name']) ?></td>
<td class="colIds"><?= monitorIdsToNames( $group['MonitorIds'], 30 ) ?></td>
<td class="colSelect"><input type="radio" name="gid" value="<?= $group['Id'] ?>"<?= $group['selected']?' checked="checked"':'' ?> onclick="configureButtons( this );"/></td>
</tr>
<?php
}
?>
<?php } ?>
</tbody>
</table>
<div id="contentButtons">