Merge branch 'master' into feature-h264-videostorage

This commit is contained in:
Isaac Connor 2017-05-15 21:52:58 -04:00
commit d3115219d2
157 changed files with 3876 additions and 3753 deletions

4
.eslintignore Normal file
View File

@ -0,0 +1,4 @@
web/api/lib
web/skins/classic/js/jquery-1.11.3.js
web/skins/classic/js/jquery.js
web/tools/mootools

29
.eslintrc.js Normal file
View File

@ -0,0 +1,29 @@
"use strict";
module.exports = {
"env": {
"browser": true,
},
"extends": ["google"],
"rules": {
"brace-style": "off",
"camelcase": "off",
"comma-dangle": "off",
"key-spacing": "off",
"max-len": "off",
"new-cap": ["error", {
capIsNewExceptions: ["Error", "Warning", "Debug", "Polygon_calcArea", "Play", "Stop"],
newIsCapExceptionPattern: "^Asset\.."
}],
"no-array-constructor": "off",
"no-caller": "off",
"no-new-object": "off",
"no-unused-vars": "off",
"no-var": "off",
"object-curly-spacing": "off",
"prefer-rest-params": "off",
"quotes": "off",
"require-jsdoc": "off",
"spaced-comment": "off",
},
};

View File

@ -2,50 +2,52 @@ language: cpp
sudo: required
dist: trusty
notifications:
irc: "chat.freenode.net#zoneminder-dev"
irc: chat.freenode.net#zoneminder-dev
branches:
except:
- modern
- modern
cache: ccache
addons:
sauce_connect:
username: "zoneminder"
access_key: "046ec7c1-c598-4e7e-949a-f86e725d1722"
ssh_known_hosts: zmrepo.zoneminder.com
apt:
sources:
- sourceline: ppa:iconnor/zoneminder
- key_url: http://keyserver.ubuntu.com:11371/pks/lookup?op=get&search=0x4D0BF748776FFB04
packages:
- gdebi
- yum-utils
- patch
- git
- curl
- sshfs
env:
global:
- LD_LIBRARY_PATH="/usr/local/lib:/opt/libjpeg-turbo/lib:$LD_LIBRARY_PATH"
- DEB_HOST_GNU_TYPE=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
- DEB_BUILD_GNU_TYPE=$(dpkg-architecture -qDEB_BUILD_GNU_TYPE)
- CFLAGS="-DZM_FFMPEG_CVS -DHAVE_LIBCRYPTO -I/usr/local/include"
- CXXFLAGS="$CFLAGS"
matrix:
- ZM_BUILDMETHOD=cmake
- OS=el DIST=6
- OS=el DIST=7
- OS=fedora DIST=24
- OS=fedora DIST=25
- OS=ubuntu DIST=trusty
- OS=ubuntu DIST=xenial
- OS=ubuntu DIST=trusty ARCH=i386
- OS=ubuntu DIST=xenial ARCH=i386
compiler:
- gcc
- clang
- gcc
services:
- mysql
before_install:
- sudo apt-get update -qq
- sudo apt-get install -y libpolkit-gobject-1-dev zlib1g-dev apache2 php5 php5-mysql build-essential libmysqlclient-dev libssl-dev libbz2-dev libpcre3-dev libdbi-perl libarchive-zip-perl libdate-manip-perl libdevice-serialport-perl libmime-perl libwww-perl libdbd-mysql-perl libsys-mmap-perl yasm automake autoconf cmake libjpeg-turbo8-dev apache2-mpm-prefork libapache2-mod-php5 php5-cli libtheora-dev libvorbis-dev libvpx-dev libx264-dev libvlccore-dev libvlc-dev
install:
- git clone -b n3.0 --depth=1 git://source.ffmpeg.org/ffmpeg.git
- cd ffmpeg
- ./configure --enable-shared --enable-swscale --enable-gpl --enable-libx264 --enable-libvpx --enable-libvorbis --enable-libtheora
- make -j `grep processor /proc/cpuinfo|wc -l`
- sudo make install
- sudo make install-libs
before_script:
- cd $TRAVIS_BUILD_DIR
- mysql -uroot -e "CREATE DATABASE IF NOT EXISTS zm"
- mysql -uroot -e "GRANT ALL ON zm.* TO 'zmuser'@'localhost' IDENTIFIED BY 'zmpass'";
- mysql -uroot -e "FLUSH PRIVILEGES"
- mysql
- docker
script:
- if [ "$ZM_BUILDMETHOD" = "cmake" ]; then cmake -DZM_ONVIF=OFF -DCMAKE_INSTALL_PREFIX="/usr"; fi
- make
- sudo make install
- if [ "$ZM_BUILDMETHOD" = "cmake" ]; then sudo ./zmlinkcontent.sh; fi
- mysql -uzmuser -pzmpass < db/zm_create.sql
- mysql -uzmuser -pzmpass zm < db/test.monitor.sql
- sudo zmpkg.pl start
- sudo zmfilter.pl -f purgewhenfull
- utils/packpack/startpackpack.sh
before_deploy:
- openssl aes-256-cbc -K $encrypted_62a62750aa73_key -iv $encrypted_62a62750aa73_iv -in ./utils/packpack/deploy_rsa.enc -out /tmp/deploy_rsa -d
- eval "$(ssh-agent -s)"
- chmod 600 /tmp/deploy_rsa
- ssh-add /tmp/deploy_rsa
deploy:
provider: script
skip_cleanup: true
script: utils/packpack/rsync_xfer.sh
on:
branch: master

View File

@ -66,6 +66,24 @@ set(CMAKE_CXX_FLAGS_DEBUG "-Wall -D__STDC_CONSTANT_MACROS -g")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
# GCC below 6.0 doesn't support __target__("fpu=neon") attribute, required for compiling ARM Neon code, otherwise compilation fails.
# Must use -mfpu=neon compiler flag instead, but only do that for processors that support neon, otherwise strip the neon code alltogether,
# because passing -fmpu=neon is unsafe to processors that don't support neon
IF(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
EXEC_PROGRAM(grep ARGS " neon " "/proc/cpuinfo" OUTPUT_VARIABLE neonoutput RETURN_VALUE neonresult)
IF(neonresult EQUAL 0)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfpu=neon")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpu=neon")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mfpu=neon")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -mfpu=neon")
ELSE(neonresult EQUAL 0)
add_definitions(-DZM_STRIP_NEON=1)
message(STATUS "ARM Neon is not available on this processor. Neon functions will be absent")
ENDIF(neonresult EQUAL 0)
ENDIF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
ENDIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
# Modules that we need:
include (GNUInstallDirs)
include (CheckIncludeFile)
@ -85,7 +103,8 @@ mark_as_advanced(
ZM_PERL_MM_PARMS
ZM_PERL_SEARCH_PATH
ZM_TARGET_DISTRO
ZM_CONFIG_DIR)
ZM_CONFIG_DIR
ZM_SYSTEMD)
set(ZM_RUNDIR "/var/run/zm" CACHE PATH
"Location of transient process files, default: /var/run/zm")
@ -148,6 +167,8 @@ set(ZM_PERL_SEARCH_PATH "" CACHE PATH
installed outside Perl's default search path.")
set(ZM_TARGET_DISTRO "" CACHE STRING
"Build ZoneMinder for a specific distribution. Currently, valid names are: fc24, fc25, el6, el7, OS13, FreeBSD")
set(ZM_SYSTEMD "OFF" CACHE BOOL
"Set to ON to force building ZM with systemd support. default: OFF")
# Reassign some variables if a target distro has been specified
if((ZM_TARGET_DISTRO STREQUAL "fc24") OR (ZM_TARGET_DISTRO STREQUAL "fc25"))
@ -205,6 +226,11 @@ include_directories("${CMAKE_BINARY_DIR}")
# This is required to enable searching in lib64 (if exists), do not change
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
# Set the systemd flag if systemd is autodetected or ZM_SYSTEMD has been set
if(ZM_SYSTEMD OR (IS_DIRECTORY /usr/lib/systemd/system) OR (IS_DIRECTORY /lib/systemd/system))
set(WITH_SYSTEMD 1)
endif(ZM_SYSTEMD OR (IS_DIRECTORY /usr/lib/systemd/system) OR (IS_DIRECTORY /lib/systemd/system))
# System checks
check_include_file("libv4l1-videodev.h" HAVE_LIBV4L1_VIDEODEV_H)
if(NOT HAVE_LIBV4L1_VIDEODEV_H)
@ -386,13 +412,13 @@ find_library(MYSQLCLIENT_LIBRARIES mysqlclient PATH_SUFFIXES mysql)
if(MYSQLCLIENT_LIBRARIES)
set(HAVE_LIBMYSQLCLIENT 1)
list(APPEND ZM_BIN_LIBS "${MYSQLCLIENT_LIBRARIES}")
find_path(MYSQLCLIENT_INCLUDE_DIR mysql/mysql.h)
find_path(MYSQLCLIENT_INCLUDE_DIR mysql.h PATH_SUFFIXES mysql)
if(MYSQLCLIENT_INCLUDE_DIR)
include_directories("${MYSQLCLIENT_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${MYSQLCLIENT_INCLUDE_DIR}")
endif(MYSQLCLIENT_INCLUDE_DIR)
mark_as_advanced(FORCE MYSQLCLIENT_LIBRARIES MYSQLCLIENT_INCLUDE_DIR)
check_include_file("mysql/mysql.h" HAVE_MYSQL_H)
check_include_file("mysql.h" HAVE_MYSQL_H)
if(NOT HAVE_MYSQL_H)
message(FATAL_ERROR
"ZoneMinder requires MySQL headers - check that MySQL development packages are installed")
@ -712,12 +738,14 @@ endif(NOT ZM_WEB_GROUP)
message(STATUS "Using web user: ${ZM_WEB_USER}")
message(STATUS "Using web group: ${ZM_WEB_GROUP}")
# Check for polkit
find_package(Polkit)
if(NOT POLKIT_FOUND)
message(FATAL_ERROR
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
endif(NOT POLKIT_FOUND)
if(WITH_SYSTEMD)
# Check for polkit
find_package(Polkit)
if(NOT POLKIT_FOUND)
message(FATAL_ERROR
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
endif(NOT POLKIT_FOUND)
endif(WITH_SYSTEMD)
# Some variables that zm expects
set(ZM_PID "${ZM_RUNDIR}/zm.pid")
@ -786,7 +814,15 @@ else(zmconfgen_result EQUAL 0)
endif(zmconfgen_result EQUAL 0)
# Install zm.conf
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" DESTINATION "${ZM_CONFIG_DIR}")
install(CODE "
if (NOT EXISTS \"${ZM_CONFIG_DIR}/zm.conf\")
file(INSTALL \"${CMAKE_CURRENT_BINARY_DIR}/zm.conf\" DESTINATION \"${ZM_CONFIG_DIR}\")
else (NOT EXISTS \"${ZM_CONFIG_DIR}/zm.conf\")
file(RENAME \"${CMAKE_CURRENT_BINARY_DIR}/zm.conf\" \"${CMAKE_CURRENT_BINARY_DIR}/zm.conf.new\")
file(INSTALL \"${CMAKE_CURRENT_BINARY_DIR}/zm.conf.new\" DESTINATION \"${ZM_CONFIG_DIR}\")
endif()
")
# Uninstall target
configure_file(
@ -802,3 +838,4 @@ if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif(CCACHE_FOUND)

View File

@ -10,7 +10,7 @@ RUN apt-get update && \
libdbi-perl libarchive-zip-perl libdate-manip-perl libdevice-serialport-perl libmime-perl libpcre3 \
libwww-perl libdbd-mysql-perl libsys-mmap-perl yasm cmake libjpeg-turbo8-dev \
libjpeg-turbo8 libtheora-dev libvorbis-dev libvpx-dev libx264-dev libmp4v2-dev libav-tools mysql-client \
apache2 php php-mysql libapache2-mod-php php-cli openssh-server \
apache2 php php-mysql libapache2-mod-php php-cli \
mysql-server libvlc-dev libvlc5 libvlccore-dev libvlccore8 vlc-data libcurl4-openssl-dev \
libavformat-dev libswscale-dev libavutil-dev libavcodec-dev libavfilter-dev \
libavresample-dev libavdevice-dev libpostproc-dev libv4l-dev libtool libnetpbm10-dev \
@ -43,10 +43,10 @@ ADD utils/docker/start.sh /tmp/start.sh
RUN chown -R www-data:www-data /usr/local/share/zoneminder/
# Adding apache virtual hosts file
ADD utils/docker/apache-vhost /etc/apache2/sites-available/000-default.conf
ADD utils/docker/phpdate.ini /etc/php/7.0/apache2/conf.d/25-phpdate.ini
RUN cp misc/apache.conf /etc/apache2/sites-available/000-default.conf
ADD utils/docker/phpdate.ini /etc/php5/apache2/conf.d/25-phpdate.ini
# Expose http ports
# Expose http port
EXPOSE 80
# Initial database and apache setup:

74
code_of_conduct.md Normal file
View File

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

5
db/zm_update-1.30.3.sql Normal file
View File

@ -0,0 +1,5 @@
--
-- This updates a 1.30.2 database to 1.30.3
--
-- No changes required
--

5
db/zm_update-1.30.4.sql Normal file
View File

@ -0,0 +1,5 @@
--
-- This updates a 1.30.3 database to 1.30.4
--
-- No changes required
--

1
distros/fedora Symbolic link
View File

@ -0,0 +1 @@
redhat

View File

@ -1,3 +0,0 @@
Fedora rpm build files have been merged with redhat.
See /distros/redhat.

View File

@ -51,6 +51,7 @@ file(MAKE_DIRECTORY sock swap zoneminder zoneminder-upload events images temp)
# Install the empty folders
install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(DIRECTORY zoneminder DESTINATION /var/log DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(DIRECTORY zoneminder DESTINATION /var/run DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

View File

@ -157,7 +157,9 @@ Upgrades
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
5. Now start zoneminder:
5. Now restart nginx and php-fpm then start and zoneminder:
sudo systemctl restart nginx
sudo systemctl restart php-fpm
sudo systemctl start zoneminder

View File

@ -151,7 +151,8 @@ Upgrades
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
5. Now start zoneminder:
5. Now restart the web server then start zoneminder:
sudo systemctl restart httpd
sudo systemctl start zoneminder

View File

@ -150,7 +150,8 @@ Upgrades
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
5. Now start zoneminder:
5. Now restart the web server then start zoneminder:
sudo service httpd restart
sudo service zoneminder start

View File

@ -142,7 +142,9 @@ Upgrades
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
5. Now start zoneminder:
5. Now restart the web server then start zoneminder:
sudo systemctl restart httpd
sudo systemctl start zoneminder

View File

@ -23,3 +23,7 @@ here are a couple of considerations you may want to take.
directives found in /etc/httpd/conf.d/zoneminder.conf. You should also
comment out the HTTP -> HTTPS Rewrite rule.
3. Install a fully signed certificate from letsencrypt. See the Letsencrypt
site for more information. https://letsencrypt.org/
This service is totally free!

View File

@ -17,6 +17,11 @@
# This will tell zoneminder's cmake process we are building against a known distro
%global zmtargetdistro %{?rhel:el%{rhel}}%{!?rhel:fc%{fedora}}
# Fedora >= 25 needs apcu backwards compatibility module
%if 0%{?fedora} >= 25
%global with_apcu_bc 1
%endif
# Include files for SysV init or systemd
%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7
%global with_init_systemd 1
@ -28,7 +33,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.30.2
Version: 1.30.4
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons
@ -39,12 +44,13 @@ Group: System Environment/Daemons
License: GPLv2+ and LGPLv2+ and MIT
URL: http://www.zoneminder.com/
Source0: https://github.com/ZoneMinder/ZoneMinder/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz
Source1: https://github.com/FriendsOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz
%{?with_init_systemd:BuildRequires: systemd-devel}
%{?with_init_systemd:BuildRequires: mariadb-devel}
%{?with_init_systemd:BuildRequires: perl-podlators}
%{?with_init_systemd:BuildRequires: polkit-devel}
%{?with_init_sysv:BuildRequires: mysql-devel}
%{?el6:BuildRequires: epel-rpm-macros}
BuildRequires: cmake >= 2.8.7
@ -76,7 +82,6 @@ BuildRequires: vlc-devel
BuildRequires: libcurl-devel
BuildRequires: libv4l-devel
BuildRequires: ffmpeg-devel
BuildRequires: polkit-devel
%{?with_nginx:Requires: nginx}
%{?with_nginx:Requires: fcgiwrap}
@ -86,6 +91,8 @@ BuildRequires: polkit-devel
Requires: php-mysqli
Requires: php-common
Requires: php-gd
Requires: php-pecl-apcu
%{?with_apcu_bc:Requires: php-pecl-apcu-bc}
Requires: cambozola
Requires: net-tools
Requires: psmisc
@ -130,10 +137,9 @@ designed to support as many cameras as you can attach to your computer without
too much degradation of performance.
%prep
%autosetup
%autosetup -a 1
rmdir ./web/api/app/Plugin/Crud
mv -f crud-%{crud_version} ./web/api/app/Plugin/Crud
%autosetup -p 1 -a 1 -n ZoneMinder-%{version}
%{__rm} -rf ./web/api/app/Plugin/Crud
%{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud
# Change the following default values
./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin-zm/nph-zms
@ -285,6 +291,8 @@ rm -rf %{_docdir}/%{name}-%{version}
%if 0%{?with_init_systemd}
%{_tmpfilesdir}/zoneminder.conf
%{_unitdir}/zoneminder.service
%{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy
%{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules
%endif
%if 0%{?with_init_sysv}
@ -297,7 +305,6 @@ rm -rf %{_docdir}/%{name}-%{version}
%{_bindir}/zmc
%{_bindir}/zmcontrol.pl
%{_bindir}/zmdc.pl
%{_bindir}/zmf
%{_bindir}/zmfilter.pl
%{_bindir}/zmpkg.pl
%{_bindir}/zmtrack.pl
@ -322,9 +329,6 @@ rm -rf %{_docdir}/%{name}-%{version}
%{_libexecdir}/zoneminder/
%{_datadir}/zoneminder/
%{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy
%{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/events
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/images
@ -333,11 +337,22 @@ rm -rf %{_docdir}/%{name}-%{version}
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/temp
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/log/zoneminder
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/spool/zoneminder-upload
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %ghost %{_localstatedir}/run/zoneminder
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder
%changelog
* Tue May 09 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.4-1
- modify autosetup macro parameters
- modify requirements for php-pecl-acpu-bc package
- 1.30.4 release
* Tue May 02 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.3-1
- 1.30.3 release
* Thu Mar 30 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.2-2
- 1.30.2 release
* Wed Feb 08 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.2-1
- Bump version for 1.30.2 release
- Bump version for 1.30.2 release candidate 1
* Wed Dec 28 2016 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.1-2
- Changes from rpmfusion #4393

View File

@ -54,7 +54,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,libdata-uuid-perl
,mysql-client | virtual-mysql-client
,perl-modules
,php5-mysql, php5-gd
,php5-mysql, php5-gd, php5-apcu, php-apc
,policykit-1
,rsyslog | system-log-daemon
,zip

View File

@ -1,2 +1,3 @@
d /var/run/zm 0755 www-data www-data
d /tmp/zm 0755 www-data www-data
d /var/tmp/zm 0755 www-data www-data

View File

@ -65,7 +65,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,libdata-uuid-perl
,mysql-client | virtual-mysql-client
,perl-modules
,php5-mysql | php-mysql, php5-gd | php-gd
,php5-mysql | php-mysql, php5-gd | php-gd, php-apcu, php-apcu-bc | php-gd
,policykit-1
,rsyslog | system-log-daemon
,zip

View File

@ -1,3 +1,4 @@
/var/cache/zoneminder/events /usr/share/zoneminder/www/events
/var/cache/zoneminder/images /usr/share/zoneminder/www/images
/var/cache/zoneminder/temp /usr/share/zoneminder/www/temp
/var/tmp /usr/share/zoneminder/www/api/app/tmp

View File

@ -1,2 +1,3 @@
d /var/run/zm 0755 www-data www-data
d /tmp/zm 0755 www-data www-data
d /var/run/zm 0755 www-data www-data
d /tmp/zm 0755 www-data www-data
d /var/tmp/zm 0755 www-data www-data

View File

@ -309,7 +309,7 @@ The main causes are.
* Capture frame rates. Unless there's a compelling reason in your case there is often little benefit in running cameras at 25fps when 5-10fps would often get you results just as good. Try changing your monitor settings to limit your cameras to lower frame rates. You can still configure ZM to ignore these limits and capture as fast as possible when motion is detected.
* Run function. Obviously running in Record or Mocord modes or in Modect with lots of events generates a lot of DB and file activity and so CPU and load will increase.
* Basic default detection zones. By default when a camera is added one detection zone is added which covers the whole image with a default set of parameters. If your camera covers a view in which various regions are unlikely to generate a valid alarm (ie the sky) then I would experiment with reducing the zone sizes or adding inactive zones to blank out areas you don't want to monitor. Additionally the actual settings of the zone themselves may not be optimal. When doing motion detection the number of changed pixels above a threshold is examined, then this is filter, then contiguous regions are calculated to see if an alarm is generated. If any maximum or minimum threshold is exceeded according to your zone settings at any time the calculation stops. If your settings always result in the calculations going through to the last stage before being failed then additional CPU time is used unnecessarily. Make sure your maximum and minimumzone thresholds are set to sensible values and experiment by switching RECORD_EVENT_STATS on and seeing what the actual values of alarmed pixels etc are during sample events.
* Optimise your settings. After you've got some settings you're happy with then switching off RECORD_EVENT_STATS will prevent the statistics being written to the database which saves some time. Other settings which might make a difference are ZM_FAST_RGB_DIFFS, ZM_OPT_FRAME_SERVER and the JPEG_xxx_QUALITY ones.
* Optimise your settings. After you've got some settings you're happy with then switching off RECORD_EVENT_STATS will prevent the statistics being written to the database which saves some time. Other settings which might make a difference are ZM_FAST_RGB_DIFFS and the JPEG_xxx_QUALITY ones.
I'm sure there are other things which might make a difference such as what else you have running on the box and memory sizes (make sure there's no swapping going on). Also speed of disk etc will make some difference during event capture and also if you are watching the whole time then you may have a bunch of zms processes running also.

View File

@ -42,8 +42,6 @@ Note that these commands are just an example and might not be secure enough for
7. If you have chosen to change the ZoneMinder database account credentials to something other than zmuser/zmpass, you must now update zm.conf on each ZoneMinder Server. Change ZM_DB_USER and ZM_DB_PASS to the values you created in the previous step.
Additionally, you must also edit /usr/share/zoneminder/www/api/app/Config/database.php in a similar manner on each ZoneMinder Server. Scroll down and change login and password to the values you created in the previous step.
8. All ZoneMinders Servers must share a common events folder. This can be done in any manner supported by the underlying operating system. From the Storage Server, share/export a folder to be used for ZoneMinder events.
9. From each ZoneMinder Server, mount the shared events folder on the Storage Server to the events folder on the local ZoneMinder Server.

View File

@ -169,8 +169,6 @@ Now clone the ZoneMinder git repository:
cd
git clone https://github.com/ZoneMinder/ZoneMinder
cd ZoneMinder
git submodule init
git submodule update
This will create a sub-folder called ZoneMinder, which will contain the latest development.
@ -180,21 +178,21 @@ We want to turn this into a tarball, but first we need to figure out what to nam
ls ~/rpmbuild/SOURCES
The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From one folder above the local ZoneMinder git repository, execute the following:
The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From the root folder of the local ZoneMinder git repository, execute the following:
::
mv ZoneMinder ZoneMinder-1.28.1
tar -cvzf ~/rpmbuild/SOURCES/ZoneMinder-1.28.1.tar.gz ZoneMinder-1.28.1/*
git archive --prefix=ZoneMinder-1.28.1/ -o ~/rpmbuild/SOURCES/zoneminder-1.28.1.tar.gz HEAD
The trailing "/\*" leaves off the hidden dot "." file and folders from the git repo, which is what we want.
Note that we are overwriting the original tarball. If you wish to keep the original tarball then create a copy prior to creating the new tarball.
Now build a new src.rpm:
From the root of the local ZoneMinder git repo, execute the following:
::
rpmbuild -bs --nodeps ~/rpmbuild/SPECS/zoneminder.el7.spec
rpmbuild -bs --nodeps distros/redhat/zoneminder.spec
Notice we used the rpm specfile that is part of the latest master branch you just downloaded, rather than the one that may be in your ~/rpmbbuild/SOURCES folder.
This step will overwrite the SRPM you originally downloaded, so you may want to back it up prior to completing this step. Note that the name of the specfile will vary slightly depending on the target distro.

View File

@ -287,19 +287,19 @@ To build the latest master snapshot:
::
./do_debian_package.sh `lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'` `date +%Y%m%d`01 local master
./do_debian_package.sh --snapshot=NOW --branch=master --type=local
To build the latest stable release:
::
./do_debian_package.sh `lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'` `date +%Y%m%d`01 local stable
./do_debian_package.sh --snapshot=stable --type=local
Note that the ``lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'``
part simply extracts your distribution name - like "vivid", "trusty" etc. You
can always replace it by your distro name if you know it. As far as the script
Note that the distribution will be guessed using ``lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'``
which simply extracts your distribution name - like "vivid", "trusty" etc. You
can always specify it using --distro=your distro name if you know it. As far as the script
goes, it checks if your distro is "trusty" in which case it pulls in pre-systemd
release configurations and if its not "trusty" it assumes its based on systemd
and pulls in systemd related config files.
@ -358,24 +358,6 @@ Changed Default DB User
^^^^^^^^^^^^^^^^^^^^^^^
If you have changed your DB login/password from zmuser/zmpass, you need to
update these values in zm.conf and the API's database.php file.
update these values in zm.conf.
1. Edit zm.conf to change ZM_DB_USER and ZM_DB_PASS to the values you used.
2. Edit databse.php which can be found in the web server folder zoneminder/www/api/app/Config
There is a class there called DATABASE_CONFIG -
change the $default array to reflect your new details. Example:
::
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'mynewDBusername',
'password' => 'mynewDBpassword'
'database' => 'zm',
'prefix' => '',
//'encoding' => 'utf8',
);

View File

@ -29,7 +29,7 @@ Here is what the filter window looks like
events later and also make sure archived events don't get deleted, for example
* Email details of all matches: Sends an email to the configured address with details about the event.
The email can be customized as per TBD
* Execute command on all matches: Allows you to execute any arbitrary command on the matched events
* Execute command on all matches: Allows you to execute any arbitrary command on the matched events. You can use replacement tokens as subsequent arguents to the command, the last argument will be the absolute path to the event, preceeded by replacement arguents. eg: /usr/bin/script.sh %MN% will excecute as /usr/bin/script.sh MonitorName /path/to/event.
* Delete all matches: Deletes all the matched events
* *E*: Use 'Submit' to 'test' your matching conditions. This will just match and show you what filters match. Use 'Execute' to actually execute the action after matching your conditions. Use 'Save' to save the filter for future use and 'Reset' to clear your settings

View File

@ -33,10 +33,6 @@ RUN_AUDIT - The zmaudit daemon exists to check that the saved information in the
AUDIT_CHECK_INTERVAL - The zmaudit daemon exists to check that the saved information in the database and on the filesystem match and are consistent with each other. If an error occurs or if you are using 'fast deletes' it may be that database records are deleted but files remain. In this case, and similar, zmaudit will remove redundant information to synchronise the two data stores. The default check interval of 900 seconds (15 minutes) is fine for most systems however if you have a very large number of events the process of scanning the database and filesystem may take a long time and impact performance. In this case you may prefer to make this interval much larger to reduce the impact on your system. This option determines how often these checks are performed.
OPT_FRAME_SERVER - In some circumstances it is possible for a slow disk to take so long writing images to disk that it causes the analysis daemon to fall behind especially during high frame rate events. Setting this option to yes enables a frame server daemon (zmf) which will be sent the images from the analysis daemon and will do the actual writing of images itself freeing up the analysis daemon to get on with other things. Should this transmission fail or other permanent or transient error occur, this function will fall back to the analysis daemon.
FRAME_SOCKET_SIZE - For large captured images it is possible for the writes from the analysis daemon to the frame server to fail as the amount to be written exceeds the default buffer size. While the images are then written by the analysis daemon so no data is lost, it defeats the object of the frame server daemon in the first place. You can use this option to indicate that a larger buffer size should be used. Note that you may have to change the existing maximum socket buffer size on your system via sysctl (or in /proc/sys/net/core/wmem_max) to allow this new size to be set. Alternatively you can change the default buffer size on your system in the same way in which case that will be used with no change necessary in this option
OPT_CONTROL - ZoneMinder includes limited support for controllable cameras. A number of sample protocols are included and others can easily be added. If you wish to control your cameras via ZoneMinder then select this option otherwise if you only have static cameras or use other control methods then leave this option off.
OPT_TRIGGERS - ZoneMinder can interact with external systems which prompt or cancel alarms. This is done via the zmtrigger.pl script. This option indicates whether you want to use these external triggers. Most people will say no here.

View File

@ -12,7 +12,8 @@ configure_file(zoneminder-tmpfiles.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zonemind
# Do not install the misc files by default
#install(FILES "${CMAKE_CURRENT_BINARY_DIR}/apache.conf" "${CMAKE_CURRENT_BINARY_DIR}/logrotate.conf" "${CMAKE_CURRENT_BINARY_DIR}/syslog.conf" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/misc")
# Install Policykit rules and actions into the proper folders
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.policy" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/actions")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.rules" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/rules.d")
# Install Policykit rules and actions into the proper folders only on systems with systemd
if(WITH_SYSTEMD)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.policy" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/actions")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.rules" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/rules.d")
endif(WITH_SYSTEMD)

View File

@ -5,13 +5,22 @@
# Some values may need to manually adjusted to suit your setup
#
<VirtualHost *:80>
ServerName @WEB_HOST@
ServerAdmin webmaster@localhost
DocumentRoot "@WEB_PREFIX@"
Alias /zm/ "@WEB_PREFIX@/"
<Directory "@WEB_PREFIX@">
Options -Indexes +FollowSymLinks
AllowOverride All
<IfModule mod_authz_core.c>
# Apache 2.4
Require all granted
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order deny,allow
Allow from all
</IfModule>
</Directory>
ScriptAlias /cgi-bin "@CGI_PREFIX@"

View File

@ -12,7 +12,7 @@ Type=forking
ExecStart=@BINDIR@/zmpkg.pl start
ExecReload=@BINDIR@/zmpkg.pl restart
ExecStop=@BINDIR@/zmpkg.pl stop
PIDFile="@ZM_RUNDIR@/zm.pid"
PIDFile=@ZM_RUNDIR@/zm.pid
Environment=TZ=:/etc/localtime
[Install]

View File

@ -26,9 +26,10 @@ 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 RELATIVE "${CMAKE_CURRENT_BINARY_DIR}" "*.pl")
file(GLOB perlscripts "*.pl")
FOREACH(PERLSCRIPT ${perlscripts})
POD2MAN(${CMAKE_CURRENT_SOURCE_DIR}/${PERLSCRIPT} zoneminder-${PERLSCRIPT} 8)
get_filename_component(PERLSCRIPTNAME ${PERLSCRIPT} NAME)
POD2MAN(${PERLSCRIPT} zoneminder-${PERLSCRIPTNAME} 8)
ENDFOREACH(PERLSCRIPT ${perlscripts})
# Install the perl scripts

View File

@ -345,6 +345,26 @@ our @options = (
type => $types{boolean},
category => "system",
},
{
name => "ZM_ENABLE_CSRF_MAGIC",
default => "no",
description => "Enable csrf-magic library",
help => qqq("
CSRF stands for Cross-Site Request Forgery which, under specific
circumstances, can allow an attacker to perform any task your
ZoneMinder user account has permission to perform. To accomplish
this, the attacker must write a very specific web page and get
you to navigate to it, while you are logged into the ZoneMinder
web console at the same time. Enabling ZM_ENABLE_CSRF_MAGIC will
help mitigate these kinds of attackes. Be warned this feature
is experimental and may cause problems, particularly with the API.
If you find a false positive and can document how to reproduce it,
then please report it. This feature defaults to OFF currently due to
its experimental nature.
"),
type => $types{boolean},
category => "system",
},
{
name => "ZM_OPT_USE_API",
default => "yes",
@ -2696,47 +2716,6 @@ our @options = (
type => $types{boolean},
category => "config",
},
{
name => "ZM_OPT_FRAME_SERVER",
default => "no",
description => "Should analysis farm out the writing of images to disk",
#requires => [ { name => "ZM_OPT_ADAPTIVE_SKIP", value => "yes" } ],
help => qqq("
In some circumstances it is possible for a slow disk to take so
long writing images to disk that it causes the analysis daemon
to fall behind especially during high frame rate events.
Setting this option to yes enables a frame server daemon (zmf)
which will be sent the images from the analysis daemon and will
do the actual writing of images itself freeing up the analysis
daemon to get on with other things. Should this transmission
fail or other permanent or transient error occur, this function
will fall back to the analysis daemon.
"),
type => $types{boolean},
category => "system",
},
{
name => "ZM_FRAME_SOCKET_SIZE",
default => "0",
description => "Specify the frame server socket buffer size if non-standard",
requires => [ { name => "ZM_OPT_FRAME_SERVER", value => "yes" } ],
help => qqq("
For large captured images it is possible for the writes from
the analysis daemon to the frame server to fail as the amount
to be written exceeds the default buffer size. While the images
are then written by the analysis daemon so no data is lost, it
defeats the object of the frame server daemon in the first
place. You can use this option to indicate that a larger buffer
size should be used. Note that you may have to change the
existing maximum socket buffer size on your system via sysctl
(or in /proc/sys/net/core/wmem_max) to allow this new size to
be set. Alternatively you can change the default buffer size on
your system in the same way in which case that will be used
with no change necessary in this option
"),
type => $types{integer},
category => "system",
},
{
name => "ZM_OPT_CONTROL",
default => "no",

View File

@ -215,6 +215,55 @@ sub presetHome
$self->sendCmd( 'decoder_control.cgi?command=25&' );
}
sub moveRelUp
{
my $self = shift;
Debug( "Move Up" );
$self->sendCmd( 'decoder_control.cgi?command=0&onestep=1&' );
}
#Down Arrow
sub moveRelDown
{
my $self = shift;
Debug( "Move Down" );
$self->sendCmd( 'decoder_control.cgi?command=2&onestep=1&' );
}
#Left Arrow
sub moveRelLeft
{
my $self = shift;
Debug( "Move Left" );
$self->sendCmd( 'decoder_control.cgi?command=6&onestep=1&' );
}
#Right Arrow
sub moveRelRight
{
my $self = shift;
Debug( "Move Right" );
$self->sendCmd( 'decoder_control.cgi?command=4&onestep=1&' );
}
#Go to preset
sub presetGoto
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
my $result = undef;
if ( $preset > 0 && $preset <= 32 ) {
my $command=31+(($preset-1) * 2);
Debug( "Goto Preset $preset with command $command" );
$result=$self->sendCmd( 'decoder_control.cgi?command=' . $command . '&' );
}
else {
Error( "Unsupported preset $preset : must be between 1 and 32" );
}
return $result;
}
1;
__END__

View File

@ -103,8 +103,10 @@ sub getCmdFormat {
my $suffix = "";
my $command = $prefix.$null_command.$suffix;
Debug( "Testing \"$command\"\n" );
my $output = qx($command);
my $output = qx($command 2>&1);
my $status = $? >> 8;
$output //= $!;
if ( !$status ) {
Debug( "Test ok, using format \"$prefix<command>$suffix\"\n" );
return( $prefix, $suffix );
@ -116,8 +118,10 @@ sub getCmdFormat {
$suffix = "'";
$command = $prefix.$null_command.$suffix;
Debug( "Testing \"$command\"\n" );
my $output = qx($command);
my $output = qx($command 2>&1);
my $status = $? >> 8;
$output //= $!;
if ( !$status ) {
Debug( "Test ok, using format \"$prefix<command>$suffix\"\n" );
return( $prefix, $suffix );
@ -129,8 +133,10 @@ sub getCmdFormat {
$suffix = "'";
$command = $prefix.$null_command.$suffix;
Debug( "Testing \"$command\"\n" );
$output = qx($command);
$output = qx($command 2>&1);
$status = $? >> 8;
$output //= $!;
if ( !$status ) {
Debug( "Test ok, using format \"$prefix<command>$suffix\"\n" );
return( $prefix, $suffix );

View File

@ -89,7 +89,6 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
my @daemons = (
'zmc',
'zma',
'zmf',
'zmfilter.pl',
'zmaudit.pl',
'zmtrigger.pl',

View File

@ -982,6 +982,7 @@ sub executeCommand
my $command = $filter->{AutoExecuteCmd};
$command .= " $event_path";
$command = substituteTags( $command, $filter, $event );
Info( "Executing '$command'\n" );
my $output = qx($command);

View File

@ -251,10 +251,6 @@ if ( $command =~ /^(?:start|restart)$/ )
}
if ( $monitor->{Function} ne 'Monitor' )
{
if ( $Config{ZM_OPT_FRAME_SERVER} )
{
runCommand( "zmdc.pl start zmf -m $monitor->{Id}" );
}
runCommand( "zmdc.pl start zma -m $monitor->{Id}" );
}
if ( $Config{ZM_OPT_CONTROL} )

View File

@ -12,21 +12,19 @@ add_library(zm STATIC ${ZM_BIN_SRC_FILES})
add_executable(zmc zmc.cpp)
add_executable(zma zma.cpp)
add_executable(zmu zmu.cpp)
add_executable(zmf zmf.cpp)
add_executable(zms zms.cpp)
target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zmu zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zmf zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
# Generate man files for the binaries destined for the bin folder
FOREACH(CBINARY zma zmc zmf zmu)
FOREACH(CBINARY zma zmc zmu)
POD2MAN(${CMAKE_CURRENT_SOURCE_DIR}/${CBINARY}.cpp zoneminder-${CBINARY} 8)
ENDFOREACH(CBINARY zma zmc zmf zmu)
ENDFOREACH(CBINARY zma zmc zmu)
install(TARGETS zmc zma zmu zmf RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(TARGETS zmc zma zmu RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(TARGETS zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})" )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nph-zms DESTINATION "${ZM_CGIDIR}")

View File

@ -40,10 +40,10 @@ Camera::Camera( unsigned int p_monitor_id, SourceType p_type, int p_width, int p
Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",monitor_id,width,height,colours,subpixelorder,capture);
/* Because many loops are unrolled and work on 16 colours/time or 4 pixels/time, we have to meet requirements */
if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 16) != 0) {
Fatal("Image size is not multiples of 16");
} else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 16) != 0 || (imagesize % 12) != 0)) {
Fatal("Image size is not multiples of 12 and 16");
if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0) {
Fatal("Image size is not multiples of 64");
} else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0)) {
Fatal("Image size is not multiples of 12 and 64");
}
}

View File

@ -42,8 +42,6 @@ extern "C"
#include "zm_sendfile.h"
}
#include "zmf.h"
#if HAVE_SYS_SENDFILE_H
#include <sys/sendfile.h>
#endif
@ -282,141 +280,12 @@ void Event::createNotes( std::string &notes )
int Event::sd = -1;
bool Event::OpenFrameSocket( int monitor_id )
{
if ( sd > 0 )
{
close( sd );
}
sd = socket( AF_UNIX, SOCK_STREAM, 0);
if ( sd < 0 )
{
Error( "Can't create socket: %s", strerror(errno) );
return( false );
}
int socket_buffer_size = config.frame_socket_size;
if ( socket_buffer_size > 0 )
{
if ( setsockopt( sd, SOL_SOCKET, SO_SNDBUF, &socket_buffer_size, sizeof(socket_buffer_size) ) < 0 )
{
Error( "Can't get socket buffer size to %d, error = %s", socket_buffer_size, strerror(errno) );
close( sd );
sd = -1;
return( false );
}
}
int flags;
if ( (flags = fcntl( sd, F_GETFL )) < 0 )
{
Error( "Can't get socket flags, error = %s", strerror(errno) );
close( sd );
sd = -1;
return( false );
}
flags |= O_NONBLOCK;
if ( fcntl( sd, F_SETFL, flags ) < 0 )
{
Error( "Can't set socket flags, error = %s", strerror(errno) );
close( sd );
sd = -1;
return( false );
}
char sock_path[PATH_MAX] = "";
snprintf( sock_path, sizeof(sock_path), "%s/zmf-%d.sock", config.path_socks, monitor_id );
struct sockaddr_un addr;
strncpy( addr.sun_path, sock_path, sizeof(addr.sun_path) );
addr.sun_family = AF_UNIX;
if ( connect( sd, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)+1) < 0 )
{
Warning( "Can't connect to frame server: %s", strerror(errno) );
close( sd );
sd = -1;
return( false );
}
Debug( 1, "Opened connection to frame server" );
return( true );
}
bool Event::ValidateFrameSocket( int monitor_id )
{
if ( sd < 0 )
{
return( OpenFrameSocket( monitor_id ) );
}
return( true );
}
bool Event::SendFrameImage( const Image *image, bool alarm_frame )
{
if ( !ValidateFrameSocket( monitor->Id() ) )
{
return( false );
}
static int jpg_buffer_size = 0;
static unsigned char jpg_buffer[ZM_MAX_IMAGE_SIZE];
image->EncodeJpeg( jpg_buffer, &jpg_buffer_size, (alarm_frame&&(config.jpeg_alarm_file_quality>config.jpeg_file_quality))?config.jpeg_alarm_file_quality:config.jpeg_file_quality );
static FrameHeader frame_header;
frame_header.event_id = id;
if ( config.use_deep_storage )
frame_header.event_time = start_time.tv_sec;
frame_header.frame_id = frames;
frame_header.alarm_frame = alarm_frame;
frame_header.image_length = jpg_buffer_size;
struct iovec iovecs[2];
iovecs[0].iov_base = &frame_header;
iovecs[0].iov_len = sizeof(frame_header);
iovecs[1].iov_base = jpg_buffer;
iovecs[1].iov_len = jpg_buffer_size;
ssize_t writev_size = sizeof(frame_header)+jpg_buffer_size;
ssize_t writev_result = writev( sd, iovecs, sizeof(iovecs)/sizeof(*iovecs));
if ( writev_result != writev_size )
{
if ( writev_result < 0 )
{
if ( errno == EAGAIN )
{
Warning( "Blocking write detected" );
}
else
{
Error( "Can't write frame: %s", strerror(errno) );
close( sd );
sd = -1;
}
}
else
{
Error( "Incomplete frame write: %zd of %zd bytes written", writev_result, writev_size );
close( sd );
sd = -1;
}
return( false );
}
Debug( 1, "Wrote frame image, %d bytes", jpg_buffer_size );
return( true );
}
bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame )
{
Image* ImgToWrite;
Image* ts_image = NULL;
if ( config.timestamp_on_capture ) // stash the image we plan to use in another pointer regardless if timestamped.
if ( !config.timestamp_on_capture ) // stash the image we plan to use in another pointer regardless if timestamped.
{
ts_image = new Image(*image);
monitor->TimestampImage( ts_image, &timestamp );
@ -425,11 +294,9 @@ bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char
else
ImgToWrite=image;
if ( !config.opt_frame_server || !SendFrameImage(ImgToWrite, alarm_frame) )
{
int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default
ImgToWrite->WriteJpeg( event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0}) ); // exif is only timestamp at present this switches on or off for write
}
int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default
ImgToWrite->WriteJpeg( event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0}) ); // exif is only timestamp at present this switches on or off for write
if(ts_image) delete(ts_image); // clean up if used.
return( true );
}

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,7 @@ extern imgbufcpy_fptr_t fptr_imgbufcpy;
/* Should be called from Image class functions */
inline static uint8_t* AllocBuffer(size_t p_bufsize) {
uint8_t* buffer = (uint8_t*)zm_mallocaligned(16,p_bufsize);
uint8_t* buffer = (uint8_t*)zm_mallocaligned(64,p_bufsize);
if(buffer == NULL)
Fatal("Memory allocation failed: %s",strerror(errno));
@ -264,6 +264,8 @@ public:
/* Blend functions */
void sse2_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
void std_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
void neon32_armv7_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
void neon64_armv8_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
void std_blend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
/* Delta functions */
@ -274,6 +276,16 @@ void std_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result,
void std_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void std_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void std_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon64_armv8_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon64_armv8_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon64_armv8_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon64_armv8_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon64_armv8_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void sse2_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void sse2_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void sse2_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
@ -293,6 +305,9 @@ void std_convert_argb_gray8(const uint8_t* col1, uint8_t* result, unsigned long
void std_convert_abgr_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void std_convert_yuyv_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void ssse3_convert_rgba_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void ssse3_convert_bgra_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void ssse3_convert_argb_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void ssse3_convert_abgr_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void ssse3_convert_yuyv_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void zm_convert_yuyv_rgb(const uint8_t* col1, uint8_t* result, unsigned long count);
void zm_convert_yuyv_rgba(const uint8_t* col1, uint8_t* result, unsigned long count);
@ -309,8 +324,3 @@ void std_deinterlace_4field_rgba(uint8_t* col1, uint8_t* col2, unsigned int thre
void std_deinterlace_4field_bgra(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
void std_deinterlace_4field_argb(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
void std_deinterlace_4field_abgr(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
void ssse3_deinterlace_4field_gray8(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
void ssse3_deinterlace_4field_rgba(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
void ssse3_deinterlace_4field_bgra(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
void ssse3_deinterlace_4field_argb(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
void ssse3_deinterlace_4field_abgr(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);

View File

@ -182,8 +182,8 @@ int LibvlcCamera::PrimeCapture()
mLibvlcData.bufferSize = width * height * mBpp;
// Libvlc wants 32 byte alignment for images (should in theory do this for all image lines)
mLibvlcData.buffer = (uint8_t*)zm_mallocaligned(32, mLibvlcData.bufferSize);
mLibvlcData.prevBuffer = (uint8_t*)zm_mallocaligned(32, mLibvlcData.bufferSize);
mLibvlcData.buffer = (uint8_t*)zm_mallocaligned(64, mLibvlcData.bufferSize);
mLibvlcData.prevBuffer = (uint8_t*)zm_mallocaligned(64, mLibvlcData.bufferSize);
mLibvlcData.newImage.setValueImmediate(false);

View File

@ -366,7 +366,7 @@ LocalCamera::LocalCamera(
palette = V4L2_PIX_FMT_YUYV;
} else {
if(capture) {
Info("Selected capture palette: %s (%c%c%c%c)", palette_desc, palette&0xff, (palette>>8)&0xff, (palette>>16)&0xff, (palette>>24)&0xff);
Info("Selected capture palette: %s (0x%02hhx%02hhx%02hhx%02hhx)", palette_desc, (palette>>24)&0xff, (palette>>16)&0xff, (palette>>8)&0xff, (palette)&0xff);
}
}
}
@ -427,7 +427,8 @@ LocalCamera::LocalCamera(
} else {
if( capture )
#if HAVE_LIBSWSCALE
Info("No direct match for the selected palette (%c%c%c%c) and target colorspace (%d). Format conversion is required, performance penalty expected", (capturePixFormat)&0xff,((capturePixFormat>>8)&0xff),((capturePixFormat>>16)&0xff),((capturePixFormat>>24)&0xff), colours );
Info("No direct match for the selected palette (0x%02hhx%02hhx%02hhx%02hhx) and target colorspace (%02u). Format conversion is required, performance penalty expected",
(capturePixFormat>>24)&0xff,((capturePixFormat>>16)&0xff),((capturePixFormat>>8)&0xff),((capturePixFormat)&0xff), colours);
#else
Info("No direct match for the selected palette and target colorspace. Format conversion is required, performance penalty expected");
#endif
@ -445,16 +446,18 @@ LocalCamera::LocalCamera(
subpixelorder = ZM_SUBPIX_ORDER_NONE;
imagePixFormat = AV_PIX_FMT_GRAY8;
} else {
Panic("Unexpected colours: %d",colours);
Panic("Unexpected colours: %u",colours);
}
if( capture ) {
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
if(!sws_isSupportedInput(capturePixFormat)) {
Error("swscale does not support the used capture format: %c%c%c%c",(capturePixFormat)&0xff,((capturePixFormat>>8)&0xff),((capturePixFormat>>16)&0xff),((capturePixFormat>>24)&0xff));
Error("swscale does not support the used capture format: 0x%02hhx%02hhx%02hhx%02hhx",
(capturePixFormat>>24)&0xff,((capturePixFormat>>16)&0xff),((capturePixFormat>>8)&0xff),((capturePixFormat)&0xff));
conversion_type = 2; /* Try ZM format conversions */
}
if(!sws_isSupportedOutput(imagePixFormat)) {
Error("swscale does not support the target format: %c%c%c%c",(imagePixFormat)&0xff,((imagePixFormat>>8)&0xff),((imagePixFormat>>16)&0xff),((imagePixFormat>>24)&0xff));
Error("swscale does not support the target format: 0x%02hhx%02hhx%02hhx%02hhx",
(imagePixFormat>>24)&0xff,((imagePixFormat>>16)&0xff),((imagePixFormat>>8)&0xff),((imagePixFormat)&0xff));
conversion_type = 2; /* Try ZM format conversions */
}
#endif
@ -563,7 +566,7 @@ LocalCamera::LocalCamera(
subpixelorder = ZM_SUBPIX_ORDER_NONE;
imagePixFormat = AV_PIX_FMT_GRAY8;
} else {
Panic("Unexpected colours: %d",colours);
Panic("Unexpected colours: %u",colours);
}
if( capture ) {
if(!sws_isSupportedInput(capturePixFormat)) {
@ -631,7 +634,7 @@ LocalCamera::LocalCamera(
#endif // ZM_HAS_V4L1
last_camera = this;
Debug(3,"Selected subpixelorder: %d",subpixelorder);
Debug(3,"Selected subpixelorder: %u",subpixelorder);
#if HAVE_LIBSWSCALE
/* Initialize swscale stuff */
@ -650,7 +653,7 @@ LocalCamera::LocalCamera(
int pSize = avpicture_get_size( imagePixFormat, width, height );
#endif
if( (unsigned int)pSize != imagesize) {
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
Fatal("Image size mismatch. Required: %d Available: %u",pSize,imagesize);
}
imgConversionContext = sws_getContext(width, height, capturePixFormat, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
@ -807,7 +810,7 @@ void LocalCamera::Initialise()
Debug(3,"Failed to get updated JPEG compression options: %s", strerror(errno) );
} else {
Debug(4, "JPEG quality: %d",jpeg_comp.quality);
Debug(4, "JPEG markers: %#x",jpeg_comp.jpeg_markers);
Debug(4, "JPEG markers: 0x%x",jpeg_comp.jpeg_markers);
}
}
}
@ -871,7 +874,7 @@ void LocalCamera::Initialise()
v4l2_data.buffers[i].start = mmap( NULL, vid_buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, vid_fd, vid_buf.m.offset );
if ( v4l2_data.buffers[i].start == MAP_FAILED )
Fatal( "Can't map video buffer %d (%d bytes) to memory: %s(%d)", i, vid_buf.length, strerror(errno), errno );
Fatal( "Can't map video buffer %u (%u bytes) to memory: %s(%d)", i, vid_buf.length, strerror(errno), errno );
#if HAVE_LIBSWSCALE
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
@ -1195,7 +1198,8 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
strcpy(fmt_desc[nIndex], (const char*)(fmtinfo.description));
fmt_fcc[nIndex] = fmtinfo.pixelformat;
Debug(6, "Got format: %s (%c%c%c%c) at index %d",fmt_desc[nIndex],fmt_fcc[nIndex]&0xff, (fmt_fcc[nIndex]>>8)&0xff, (fmt_fcc[nIndex]>>16)&0xff, (fmt_fcc[nIndex]>>24)&0xff ,nIndex);
Debug(6, "Got format: %s (0x%02hhx%02hhx%02hhx%02hhx) at index %d",
fmt_desc[nIndex], (fmt_fcc[nIndex]>>24)&0xff, (fmt_fcc[nIndex]>>16)&0xff, (fmt_fcc[nIndex]>>8)&0xff, (fmt_fcc[nIndex])&0xff ,nIndex);
/* Proceed to the next index */
memset(&fmtinfo, 0, sizeof(fmtinfo));
@ -1223,12 +1227,14 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
for( unsigned int i=0; i < n_preferedformats && nIndexUsed < 0; i++ ) {
for( unsigned int j=0; j < nIndex; j++ ) {
if( preferedformats[i] == fmt_fcc[j] ) {
Debug(6, "Choosing format: %s (%c%c%c%c) at index %d",fmt_desc[j],fmt_fcc[j]&0xff, (fmt_fcc[j]>>8)&0xff, (fmt_fcc[j]>>16)&0xff, (fmt_fcc[j]>>24)&0xff ,j);
Debug(6, "Choosing format: %s (0x%02hhx%02hhx%02hhx%02hhx) at index %u",
fmt_desc[j],fmt_fcc[j]&0xff, (fmt_fcc[j]>>8)&0xff, (fmt_fcc[j]>>16)&0xff, (fmt_fcc[j]>>24)&0xff ,j);
/* Found a format! */
nIndexUsed = j;
break;
} else {
Debug(6, "No match for format: %s (%c%c%c%c) at index %d",fmt_desc[j],fmt_fcc[j]&0xff, (fmt_fcc[j]>>8)&0xff, (fmt_fcc[j]>>16)&0xff, (fmt_fcc[j]>>24)&0xff ,j);
Debug(6, "No match for format: %s (0x%02hhx%02hhx%02hhx%02hhx) at index %u",
fmt_desc[j],fmt_fcc[j]&0xff, (fmt_fcc[j]>>8)&0xff, (fmt_fcc[j]>>16)&0xff, (fmt_fcc[j]>>24)&0xff ,j);
}
}
}
@ -1403,9 +1409,11 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
}
}
if ( verbose )
sprintf( output+strlen(output), " %s (%c%c%c%c)\n", format.description, format.pixelformat&0xff, (format.pixelformat>>8)&0xff, (format.pixelformat>>16)&0xff, (format.pixelformat>>24)&0xff );
sprintf( output+strlen(output), " %s (0x%02hhx%02hhx%02hhx%02hhx)\n",
format.description, (format.pixelformat>>24)&0xff, (format.pixelformat>>16)&0xff, (format.pixelformat>>8)&0xff, format.pixelformat&0xff);
else
sprintf( output+strlen(output), "%c%c%c%c/", format.pixelformat&0xff, (format.pixelformat>>8)&0xff, (format.pixelformat>>16)&0xff, (format.pixelformat>>24)&0xff );
sprintf( output+strlen(output), "0x%02hhx%02hhx%02hhx%02hhx/",
(format.pixelformat>>24)&0xff, (format.pixelformat>>16)&0xff, (format.pixelformat>>8)&0xff, (format.pixelformat)&0xff);
}
while ( formatIndex++ >= 0 );
if ( !verbose )

View File

@ -31,9 +31,9 @@
#include <signal.h>
#include <stdarg.h>
#include <errno.h>
#include <libgen.h>
#ifdef __FreeBSD__
#include <sys/thr.h>
#include <libgen.h>
#endif
bool Logger::smInitialised = false;
@ -515,8 +515,9 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
va_list argPtr;
struct timeval timeVal;
const char * const file = basename(filepath);
char *filecopy = strdup(filepath);
const char * const file = basename(filecopy);
if ( level < PANIC || level > DEBUG9 )
Panic( "Invalid logger level %d", level );
@ -631,6 +632,8 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
syslog( priority, "%s [%s]", classString, syslogStart );
}
free(filecopy);
if ( level <= FATAL )
{
if ( level <= PANIC )

View File

@ -161,7 +161,7 @@ bool Monitor::MonitorLink::connect()
return( false );
}
mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 );
if ( mem_ptr < 0 )
if ( mem_ptr < (void *)0 )
{
Debug( 3, "Can't shmat link memory: %s", strerror(errno) );
connected = false;
@ -195,7 +195,7 @@ bool Monitor::MonitorLink::disconnect()
connected = false;
#if ZM_MEM_MAPPED
if ( mem_ptr > 0 )
if ( mem_ptr > (void *)0 )
{
msync( mem_ptr, mem_size, MS_ASYNC );
munmap( mem_ptr, mem_size );
@ -406,7 +406,7 @@ Monitor::Monitor(
+ sizeof(VideoStoreData) //Information to pass back to the capture process
+ (image_buffer_count*sizeof(struct timeval))
+ (image_buffer_count*camera->ImageSize())
+ 64; /* Padding used to permit aligning the images buffer to 16 byte boundary */
+ 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */
Debug( 1, "mem.size=%d", mem_size );
mem_ptr = NULL;
@ -576,7 +576,7 @@ bool Monitor::connect() {
exit( -1 );
}
mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 );
if ( mem_ptr < 0 )
if ( mem_ptr < (void *)0 )
{
Error( "Can't shmat: %s", strerror(errno));
exit( -1 );
@ -588,10 +588,10 @@ bool Monitor::connect() {
struct timeval *shared_timestamps = (struct timeval *)((char *)video_store_data + sizeof(VideoStoreData));
unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval)));
if(((unsigned long)shared_images % 16) != 0) {
/* Align images buffer to nearest 16 byte boundary */
Debug(3,"Aligning shared memory images to the next 16 byte boundary");
shared_images = (uint8_t*)((unsigned long)shared_images + (16 - ((unsigned long)shared_images % 16)));
if(((unsigned long)shared_images % 64) != 0) {
/* Align images buffer to nearest 64 byte boundary */
Debug(3,"Aligning shared memory images to the next 64 byte boundary");
shared_images = (uint8_t*)((unsigned long)shared_images + (64 - ((unsigned long)shared_images % 64)));
}
image_buffer = new Snapshot[image_buffer_count];
for ( int i = 0; i < image_buffer_count; i++ )

View File

@ -24,8 +24,16 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#if defined(__arm__)
#include <sys/auxv.h>
#endif
#ifdef HAVE_CURL_CURL_H
#include <curl/curl.h>
#endif
unsigned int sseversion = 0;
unsigned int neonversion = 0;
std::string trimSet(std::string str, std::string trimset) {
// Trim Both leading and trailing sets
@ -234,30 +242,59 @@ int pairsplit(const char* string, const char delim, std::string& name, std::stri
return 0;
}
/* Sets sse_version */
void ssedetect() {
/* Detect special hardware features, such as SIMD instruction sets */
void hwcaps_detect() {
neonversion = 0;
sseversion = 0;
#if (defined(__i386__) || defined(__x86_64__))
/* x86 or x86-64 processor */
uint32_t r_edx, r_ecx;
uint32_t r_edx, r_ecx, r_ebx;
#ifdef __x86_64__
__asm__ __volatile__(
#if defined(__i386__)
"pushl %%ebx;\n\t"
#endif
"push %%rbx\n\t"
"mov $0x0,%%ecx\n\t"
"mov $0x7,%%eax\n\t"
"cpuid\n\t"
"push %%rbx\n\t"
"mov $0x1,%%eax\n\t"
"cpuid\n\t"
#if defined(__i386__)
"popl %%ebx;\n\t"
#endif
: "=d" (r_edx), "=c" (r_ecx)
"pop %%rax\n\t"
"pop %%rbx\n\t"
: "=d" (r_edx), "=c" (r_ecx), "=a" (r_ebx)
:
:
: "%eax"
#if !defined(__i386__)
, "%ebx"
#endif
);
if (r_ecx & 0x00000200) {
#else
__asm__ __volatile__(
"push %%ebx\n\t"
"mov $0x0,%%ecx\n\t"
"mov $0x7,%%eax\n\t"
"cpuid\n\t"
"push %%ebx\n\t"
"mov $0x1,%%eax\n\t"
"cpuid\n\t"
"pop %%eax\n\t"
"pop %%ebx\n\t"
: "=d" (r_edx), "=c" (r_ecx), "=a" (r_ebx)
:
:
);
#endif
if (r_ebx & 0x00000020) {
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 */
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
} else if (r_ecx & 0x00000001) {
@ -272,12 +309,25 @@ void ssedetect() {
} else {
sseversion = 0;
Debug(1,"Detected a x86\\x86-64 processor");
}
#elif defined(__arm__)
// ARM processor in 32bit mode
// To see if it supports NEON, we need to get that information from the kernel
unsigned long auxval = getauxval(AT_HWCAP);
if (auxval & HWCAP_ARM_NEON) {
Debug(1,"Detected ARM (AArch32) processor with Neon");
neonversion = 1;
} else {
Debug(1,"Detected ARM (AArch32) processor");
}
#elif defined(__aarch64__)
// ARM processor in 64bit mode
// Neon is mandatory, no need to check for it
neonversion = 1;
Debug(1,"Detected ARM (AArch64) processor with Neon");
#else
/* Non x86 or x86-64 processor, SSE2 is not available */
Debug(1,"Detected a non x86\\x86-64 processor");
sseversion = 0;
// Unknown processor
Debug(1,"Detected unknown processor architecture");
#endif
}
@ -345,3 +395,18 @@ void timespec_diff(struct timespec *start, struct timespec *end, struct timespec
}
}
std::string UriDecode( const std::string &encoded ) {
#ifdef HAVE_LIBCURL
CURL *curl = curl_easy_init();
int outlength;
char *cres = curl_easy_unescape(curl, encoded.c_str(), encoded.length(), &outlength);
std::string res(cres, cres + outlength);
curl_free(cres);
curl_easy_cleanup(curl);
return res;
#else
Warning("ZM Compiled without LIBCURL. UriDecoding not implemented.");
return encoded;
#endif
}

View File

@ -54,10 +54,13 @@ inline int min( int a, int b )
return( a<=b?a:b );
}
void ssedetect();
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 neonversion;
std::string UriDecode( const std::string &encoded );
#endif // ZM_UTILS_H

View File

@ -133,7 +133,7 @@ int main( int argc, char *argv[] )
logInit( log_id_string );
ssedetect();
hwcaps_detect();
Monitor *monitor = Monitor::Load( id, true, Monitor::ANALYSIS );
@ -141,11 +141,6 @@ int main( int argc, char *argv[] )
{
Info( "In mode %d/%d, warming up", monitor->GetFunction(), monitor->Enabled() );
if ( config.opt_frame_server )
{
Event::OpenFrameSocket( monitor->Id() );
}
zmSetDefaultHupHandler();
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();

View File

@ -27,7 +27,6 @@ zmc - The ZoneMinder Capture daemon
zmc -d <device_path>
zmc --device <device_path>
zmc -r <proto> -H <host> -P <port> -p <path>
zmc -f <file_path>
zmc --file <file_path>
zmc -m <monitor_id>
@ -45,7 +44,6 @@ possible, this should run at more or less constant speed.
=head1 OPTIONS
-d, --device <device_path> - For local cameras, device to access. e.g /dev/video0 etc
-r <proto> -H <host> -P <port> -p <path> - For remote cameras
-f, --file <file_path> - For local images, jpg file to access.
-m, --monitor_id - ID of the monitor to analyse
-h, --help - Display usage information
@ -83,7 +81,6 @@ void Usage()
#else
fprintf( stderr, " -d, --device <device_path> : For local cameras, device to access. E.g /dev/video0 etc\n" );
#endif
fprintf( stderr, " -r <proto> -H <host> -P <port> -p <path> : For remote cameras\n" );
fprintf( stderr, " -f, --file <file_path> : For local images, jpg file to access.\n" );
fprintf( stderr, " -m, --monitor <monitor_id> : For sources associated with a single monitor\n" );
fprintf( stderr, " -h, --help : This screen\n" );
@ -173,14 +170,14 @@ int main( int argc, char *argv[] )
int modes = ( device[0]?1:0 + host[0]?1:0 + file[0]?1:0 + (monitor_id>0?1:0) );
if ( modes > 1 )
{
fprintf( stderr, "Only one of device, host/port/path, file or monitor id allowed\n" );
fprintf( stderr, "Only one of device, file or monitor id allowed\n" );
Usage();
exit( 0 );
}
if ( modes < 1 )
{
fprintf( stderr, "One of device, host/port/path, file or monitor id must be specified\n" );
fprintf( stderr, "One of device, file or monitor id must be specified\n" );
Usage();
exit( 0 );
}
@ -209,7 +206,7 @@ int main( int argc, char *argv[] )
logInit( log_id_string );
ssedetect();
hwcaps_detect();
Monitor **monitors = 0;
int n_monitors = 0;

View File

@ -1,350 +0,0 @@
//
// ZoneMinder Image File Writer Implementation, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
/*
=head1 NAME
zmf - The ZoneMinder Frame daemon
=head1 SYNOPSIS
zmf -m <monitor_id>
zmf --monitor <monitor_id>
zmf -h
zmf --help
zmf -v
zmf --version
=head1 DESCRIPTION
This is an optional daemon that can run in concert with the Analysis daemon and
whose function it is to actually write captured frames to disk. This frees up
the Analysis daemon to do more analysis (!) and so keep up with the Capture
daemon better. If it isn't running or dies then the Analysis daemon just writes
them itself.
=head1 OPTIONS
-m, --monitor_id - ID of the monitor to use
-h, --help - Display usage information
-v, --version - Print the installed version of ZoneMinder
=cut
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <getopt.h>
#include <signal.h>
#include "zm.h"
#include "zm_db.h"
#include "zm_signal.h"
#include "zm_monitor.h"
#include "zmf.h"
int OpenSocket( int monitor_id )
{
int sd = socket( AF_UNIX, SOCK_STREAM, 0);
if ( sd < 0 )
{
Error( "Can't create socket: %s", strerror(errno) );
return( -1 );
}
char sock_path[PATH_MAX] = "";
snprintf( sock_path, sizeof(sock_path), "%s/zmf-%d.sock", config.path_socks, monitor_id );
if ( unlink( sock_path ) < 0 )
{
Warning( "Can't unlink '%s': %s", sock_path, strerror(errno) );
}
struct sockaddr_un addr;
strncpy( addr.sun_path, sock_path, sizeof(addr.sun_path) );
addr.sun_family = AF_UNIX;
if ( bind( sd, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)) < 0 )
{
Error( "Can't bind: %s", strerror(errno) );
exit( -1 );
}
if ( listen( sd, SOMAXCONN ) < 0 )
{
Error( "Can't listen: %s", strerror(errno) );
return( -1 );
}
struct sockaddr_un rem_addr;
socklen_t rem_addr_len = sizeof(rem_addr);
int new_sd = -1;
if ( (new_sd = accept( sd, (struct sockaddr *)&rem_addr, &rem_addr_len )) < 0 )
{
Error( "Can't accept: %s", strerror(errno) );
exit( -1 );
}
close( sd );
sd = new_sd;
Info( "Frame server socket open, awaiting images" );
return( sd );
}
int ReopenSocket( int &sd, int monitor_id )
{
close( sd );
return( sd = OpenSocket( monitor_id ) );
}
void Usage()
{
fprintf( stderr, "zmf -m <monitor_id>\n" );
fprintf( stderr, "Options:\n" );
fprintf( stderr, " -m, --monitor <monitor_id> : Specify which monitor to use\n" );
fprintf( stderr, " -h, --help : This screen\n" );
fprintf( stderr, " -v, --version : Report the installed version of ZoneMinder\n" );
exit( 0 );
}
int main( int argc, char *argv[] )
{
self = argv[0];
srand( getpid() * time( 0 ) );
int id = -1;
static struct option long_options[] = {
{"monitor", 1, 0, 'm'},
{"help", 0, 0, 'h'},
{"version", 0, 0, 'v'},
{0, 0, 0, 0}
};
while (1)
{
int option_index = 0;
int c = getopt_long (argc, argv, "m:h:v", long_options, &option_index);
if (c == -1)
{
break;
}
switch (c)
{
case 'm':
id = atoi(optarg);
break;
case 'h':
case '?':
Usage();
break;
case 'v':
std::cout << ZM_VERSION << "\n";
exit(0);
default:
//fprintf( stderr, "?? getopt returned character code 0%o ??\n", c );
break;
}
}
if (optind < argc)
{
fprintf( stderr, "Extraneous options, " );
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
Usage();
}
if ( id < 0 )
{
fprintf( stderr, "Bogus monitor %d\n", id );
Usage();
exit( 0 );
}
char log_id_string[16];
snprintf( log_id_string, sizeof(log_id_string), "m%d", id );
zmLoadConfig();
logInit( "zmf" );
ssedetect();
Monitor *monitor = Monitor::Load( id, false, Monitor::QUERY );
if ( !monitor )
{
fprintf( stderr, "Can't find monitor with id of %d\n", id );
exit( -1 );
}
char capt_path[PATH_MAX];
char anal_path[PATH_MAX];
snprintf( capt_path, sizeof(capt_path), "%s/%d/%%s/%%0%dd-capture.jpg", config.dir_events, monitor->Id(), config.event_image_digits );
snprintf( anal_path, sizeof(anal_path), "%s/%d/%%s/%%0%dd-analyse.jpg", config.dir_events, monitor->Id(), config.event_image_digits );
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();
sigset_t block_set;
sigemptyset( &block_set );
int sd = OpenSocket( monitor->Id() );
FrameHeader frame_header = { 0, 0, false, 0 };
//unsigned char *image_data = 0;
fd_set rfds;
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
while( 1 )
{
struct timeval temp_timeout = timeout;
FD_ZERO(&rfds);
FD_SET(sd, &rfds);
int n_found = select( sd+1, &rfds, NULL, NULL, &temp_timeout );
if( n_found == 0 )
{
Debug( 1, "Select timed out" );
continue;
}
else if ( n_found < 0)
{
Error( "Select error: %s", strerror(errno) );
ReopenSocket( sd, monitor->Id() );
continue;
}
sigprocmask( SIG_BLOCK, &block_set, 0 );
int n_bytes = read( sd, &frame_header, sizeof(frame_header) );
if ( n_bytes != sizeof(frame_header) )
{
if ( n_bytes < 0 )
{
Error( "Can't read frame header: %s", strerror(errno) );
}
else if ( n_bytes > 0 )
{
Error( "Incomplete read of frame header, %d bytes only", n_bytes );
}
else
{
Warning( "Socket closed at remote end" );
}
ReopenSocket( sd, monitor->Id() );
continue;
}
Debug( 1, "Read frame header, expecting %ld bytes of image", frame_header.image_length );
static unsigned char image_data[ZM_MAX_IMAGE_SIZE];
// Read for pipe and loop until bytes expected have been read or an error occurs
int bytes_read = 0;
do
{
n_bytes = read( sd, image_data+bytes_read, frame_header.image_length-bytes_read );
if (n_bytes < 0) break; // break on error
if (n_bytes < (int)frame_header.image_length)
{
// print some informational messages
if (bytes_read == 0)
{
Debug(4,"Image read : Short read %d bytes of %d expected bytes",n_bytes,frame_header.image_length);
}
else if (bytes_read+n_bytes == (int)frame_header.image_length)
{
Debug(5,"Image read : Read rest of short read: %d bytes read total of %d bytes",n_bytes,frame_header.image_length);
}
else
{
Debug(6,"Image read : continuing, read %d bytes (%d so far)", n_bytes, bytes_read+n_bytes);
}
}
bytes_read+= n_bytes;
} while (n_bytes>0 && (bytes_read < (ssize_t)frame_header.image_length) );
// Print errors if there was a problem
if ( n_bytes < 1 )
{
Error( "Only read %d bytes of %d\n", bytes_read, frame_header.image_length);
if ( n_bytes < 0 )
{
Error( "Can't read frame image data: %s", strerror(errno) );
}
else
{
Warning( "Socket closed at remote end" );
}
ReopenSocket( sd, monitor->Id() );
continue;
}
static char subpath[PATH_MAX] = "";
if ( config.use_deep_storage )
{
struct tm *time = localtime( &frame_header.event_time );
snprintf( subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec );
}
else
{
snprintf( subpath, sizeof(subpath), "%ld", frame_header.event_id );
}
static char path[PATH_MAX] = "";
snprintf( path, sizeof(path), frame_header.alarm_frame?anal_path:capt_path, subpath, frame_header.frame_id );
Debug( 1, "Got image, writing to %s", path );
FILE *fd = 0;
if ( (fd = fopen( path, "w" )) < 0 )
{
Error( "Can't fopen '%s': %s", path, strerror(errno) );
exit( -1 );
}
if ( 0 == fwrite( image_data, frame_header.image_length, 1, fd ) )
{
Error( "Can't fwrite image data: %s", strerror(errno) );
exit( -1 );
}
fclose( fd );
sigprocmask( SIG_UNBLOCK, &block_set, 0 );
}
logTerm();
zmDbClose();
}

View File

@ -1,32 +0,0 @@
//
// ZoneMinder Image File Write Class Interface, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#ifndef ZMFILE_H
#define ZMFILE_H
struct FrameHeader
{
unsigned long event_id;
time_t event_time;
unsigned long frame_id;
bool alarm_frame;
unsigned long image_length;
};
#endif // ZMFILE_H

View File

@ -69,8 +69,8 @@ int main( int argc, const char *argv[] )
unsigned int bitrate = 100000;
unsigned int ttl = 0;
EventStream::StreamMode replay = EventStream::MODE_SINGLE;
char username[64] = "";
char password[64] = "";
std::string username;
std::string password;
char auth[64] = "";
unsigned int connkey = 0;
unsigned int playback_buffer = 0;
@ -91,7 +91,7 @@ int main( int argc, const char *argv[] )
logInit( "zms" );
ssedetect();
hwcaps_detect();
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();
@ -164,7 +164,7 @@ int main( int argc, const char *argv[] )
{
if ( !strcmp( name, "user" ) )
{
strncpy( username, value, sizeof(username) );
username = value;
}
}
else
@ -180,11 +180,11 @@ int main( int argc, const char *argv[] )
{
if ( !strcmp( name, "user" ) )
{
strncpy( username, value, sizeof(username) );
username = UriDecode( value );
}
if ( !strcmp( name, "pass" ) )
{
strncpy( password, value, sizeof(password) );
password = UriDecode( value );
}
}
}
@ -198,9 +198,9 @@ int main( int argc, const char *argv[] )
if ( strcmp( config.auth_relay, "none" ) == 0 )
{
if ( *username )
if ( username.length() )
{
user = zmLoadUser( username );
user = zmLoadUser( username.c_str() );
}
}
else
@ -214,9 +214,9 @@ int main( int argc, const char *argv[] )
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
if ( *username && *password )
if ( username.length() && password.length() )
{
user = zmLoadUser( username, password );
user = zmLoadUser( username.c_str(), password.c_str() );
}
}
}

View File

@ -1,252 +0,0 @@
//
// ZoneMinder Streamer, $Date: 2010-10-14 23:21:00 +0200 (Thu, 14 Oct 2010) $
// Copyright (C) 2001-2010 Philip Coombes, Chris Kistner
//
// This program is based on revision 3143 of
// http://svn.zoneminder.com/svn/zm/trunk/src/zms.cpp
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
/*
=head1 NAME
zmstreamer - eyeZM video streamer
=head1 SYNOPSIS
zmstreamer -e <mode>
zmstreamer -o <format>
zmstreamer -u <buffer size>
zmstreamer -f <maximum fps>
zmstreamer -s <scale>
zmstreamer -b <bitrate in bps>
zmstreamer -m <monitor id>
zmstreamer -d <debug mode>
zmstreamer -i
zmstreamer -?
zmstreamer -h
zmstreamer -v
=head1 DESCRIPTION
*DEPRECIATED* The xml skin and all files associated with the xml skin are now
depreciated. Please use the ZoneMinder API instead.
This binary works in conjunction with the XML skin to stream video to iPhones
running the eyeZm app.
=head1 OPTIONS
-e <mode> - Specify output mode: mpeg/jpg/zip/single/raw.
-o <format> - Specify output format.
-u <buffer size> - Specify buffer size in ms.
-f <maximum fps> - Specify maximum framerate.
-s <scale> - Specify scale.
-b <bitrate in bps> - Specify bitrate.
-m <monitor id> - Specify monitor id.
-d <debug mode> - 0 = off, 1 = no streaming, 2 = with streaming.
-i, -?, -h - Display usage information
-v - Print the installed version of ZoneMinder
=cut
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "zm.h"
#include "zm_db.h"
#include "zm_user.h"
#include "zm_signal.h"
#include "zm_monitor.h"
#include "zm_stream.h"
// Possible command-line options
#define OPTIONS "e:o:u:f:s:b:m:d:i:?:h:v"
// Default ZMS values
#define ZMS_DEFAULT_DEBUG 0
#define ZMS_DEFAULT_ID 1
#define ZMS_DEFAULT_BITRATE 100000
#define ZMS_DEFAULT_SCALE 100
#define ZMS_DEFAULT_MODE "mpeg"
#define ZMS_DEFAULT_FORMAT "asf"
#define ZMS_DEFAULT_FPS 25.0
#define ZMS_DEFAULT_BUFFER 1000
int main(int argc, char** argv) {
self = argv[0];
// Set initial values to the default values
int debug = ZMS_DEFAULT_DEBUG;
int id = ZMS_DEFAULT_ID;
int bitrate = ZMS_DEFAULT_BITRATE;
int scale = ZMS_DEFAULT_SCALE;
char mode[32];
sprintf(mode, "%s", ZMS_DEFAULT_MODE);
char format[32];
sprintf(format, "%s", ZMS_DEFAULT_FORMAT);
double maxfps = ZMS_DEFAULT_FPS;
int buffer = ZMS_DEFAULT_BUFFER;
// Parse command-line options
int arg;
while ((arg = getopt(argc, argv, OPTIONS)) != -1) {
switch (arg) {
case 'e':
sprintf(mode, "%s", optarg);
break;
case 'o':
sprintf(format, "%s", optarg);
break;
case 'u':
buffer = atoi(optarg);
break;
case 'f':
maxfps = atof(optarg);
break;
case 's':
scale = atoi(optarg);
break;
case 'b':
bitrate = atoi(optarg);
break;
case 'm':
id = atoi(optarg);
break;
case 'd':
debug = atoi(optarg);
break;
case 'h':
case 'i':
case '?':
printf("-e <mode> : Specify output mode: mpeg/jpg/zip/single/raw. Default = %s\n", ZMS_DEFAULT_MODE);
printf("-o <format> : Specify output format. Default = %s\n", ZMS_DEFAULT_FORMAT);
printf("-u <buffer size> : Specify buffer size in ms. Default = %d\n", ZMS_DEFAULT_BUFFER);
printf("-f <maximum fps> : Specify maximum framerate. Default = %lf\n", ZMS_DEFAULT_FPS);
printf("-s <scale> : Specify scale. Default = %d\n", ZMS_DEFAULT_SCALE);
printf("-b <bitrate in bps> : Specify bitrate. Default = %d\n", ZMS_DEFAULT_BITRATE);
printf("-m <monitor id> : Specify monitor id. Default = %d\n", ZMS_DEFAULT_ID);
printf("-d <debug mode> : 0 = off, 1 = no streaming, 2 = with streaming. Default = 0\n");
printf("-i or -? or -h: This information\n");
printf("-v : This installed version of ZoneMinder\n");
return EXIT_SUCCESS;
case 'v':
std::cout << ZM_VERSION << "\n";
exit(0);
}
}
// Set stream type
StreamBase::StreamType streamtype;
if (!strcasecmp("raw", mode))
streamtype = MonitorStream::STREAM_RAW;
else if (!strcasecmp("mpeg", mode))
streamtype = MonitorStream::STREAM_MPEG;
else if (!strcasecmp("jpg", mode))
streamtype = MonitorStream::STREAM_JPEG;
else if (!strcasecmp("single", mode))
streamtype = MonitorStream::STREAM_SINGLE;
else if (!strcasecmp("zip", mode))
streamtype = MonitorStream::STREAM_ZIP;
else
streamtype = MonitorStream::STREAM_MPEG;
if (debug) {
// Show stream parameters
printf("Stream parameters:\n");
switch (streamtype) {
case MonitorStream::STREAM_MPEG:
printf("Output mode (-e) = %s\n", "mpeg");
printf("Output format (-o) = %s\n", format);
break;
default:
printf("Output mode (-e) = %s\n", mode);
}
printf("Buffer size (-u) = %d ms\n", buffer);
printf("Maximum FPS (-f) = %lf FPS\n", maxfps);
printf("Scale (-s) = %d%%\n", scale);
printf("Bitrate (-b) = %d bps\n", bitrate);
printf("Monitor Id (-m) = %d\n", id);
}
if (debug) {
// Set ZM debugger to print to stdout
printf("Setting up ZoneMinder debugger to print to stdout...");
setenv("ZM_DBG_PRINT", "1", 1);
printf("Done.\n");
}
// Loading ZM configurations
printf("Loading ZoneMinder configurations...");
zmLoadConfig();
printf("Done.\n");
logInit("zmstreamer");
ssedetect();
// Setting stream parameters
MonitorStream stream;
stream.setStreamScale(scale); // default = 100 (scale)
stream.setStreamReplayRate(100); // default = 100 (rate)
stream.setStreamMaxFPS(maxfps); // default = 10 (maxfps)
if (debug) stream.setStreamTTL(1);
else stream.setStreamTTL(0); // default = 0 (ttl)
stream.setStreamQueue(0); // default = 0 (connkey)
stream.setStreamBuffer(buffer); // default = 0 (buffer)
stream.setStreamStart(id); // default = 0 (monitor_id)
stream.setStreamType(streamtype);
if (streamtype == MonitorStream::STREAM_MPEG) {
#if HAVE_LIBAVCODEC
if (debug) printf("HAVE_LIBAVCODEC is set\n");
stream.setStreamFormat(format); // default = "" (format)
stream.setStreamBitrate(bitrate); // default = 100000 (bitrate)
#else
fprintf(stderr, "MPEG streaming is disabled.\nYou should configure with the --with-ffmpeg option and rebuild to use this functionality.\n");
logTerm();
zmDbClose();
return EXIT_FAILURE;
#endif
}
if (debug != 1) {
if (debug) printf("Running stream...");
// Output headers
fprintf(stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION);
time_t now = time(0);
char date_string[64];
strftime(date_string, sizeof (date_string) - 1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
fprintf(stdout, "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n");
fprintf(stdout, "Last-Modified: %s\r\n", date_string);
fprintf(stdout, "Cache-Control: no-store, no-cache, must-revalidate\r\n");
fprintf(stdout, "Cache-Control: post-check=0, pre-check=0\r\n");
fprintf(stdout, "Pragma: no-cache\r\n");
// Run stream
stream.runStream();
}
if (debug) printf("Done.\n");
logTerm();
zmDbClose();
return (EXIT_SUCCESS);
}

View File

@ -8,88 +8,272 @@ exit;
fi
for i in "$@"
do
case $i in
-b=*|--branch=*)
BRANCH="${i#*=}"
shift # past argument=value
;;
-d=*|--distro=*)
DISTRO="${i#*=}"
shift # past argument=value
;;
-i=*|--interactive=*)
INTERACTIVE="${i#*=}"
shift # past argument=value
;;
-r=*|--release=*)
RELEASE="${i#*=}"
shift
;;
-s=*|--snapshot=*)
SNAPSHOT="${i#*=}"
shift # past argument=value
;;
-t=*|--type=*)
TYPE="${i#*=}"
shift # past argument=value
;;
-u=*|--urgency=*)
URGENCY="${i#*=}"
shift # past argument=value
;;
-f=*|--fork=*)
GITHUB_FORK="${i#*=}"
shift # past argument=value
;;
-v=*|--version=*)
PACKAGE_VERSION="${i#*=}"
shift
;;
--default)
DEFAULT=YES
shift # past argument with no value
;;
*)
# unknown option
read -p "Unknown option $i, continue? (Y|n)"
[[ $REPLY == [yY] ]] && { echo "continuing..."; } || exit 1;
;;
esac
done
DATE=`date -R`
DISTRO=$1
SNAPSHOT=$2
if [ "$SNAPSHOT" == "stable" ]; then
SNAPSHOT="";
fi;
TYPE=$3
if [ "$TYPE" == "" ]; then
TYPE="source";
echo "Defaulting to source build"
TYPE="source";
fi;
BRANCH=$4
if [ "$DISTRO" == "" ]; then
DISTRO=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
echo "Defaulting to $DISTRO for distribution";
else
echo "Building for $DISTRO";
fi;
# Release is a special mode... it uploads to the release ppa and cannot have a snapshot
if [ "$RELEASE" != "" ]; then
if [ "$SNAPSHOT" != "" ]; then
echo "Releases cannot have a snapshot.... exiting."
exit 0;
fi
if [ "$GITHUB_FORK" != "" ] && [ "$GITHUB_FORK" != "ZoneMinder" ]; then
echo "Releases cannot have a fork ($GITHUB_FORK).... exiting."
exit 0;
fi
BRANCH="release-$RELEASE"
else
if [ "$GITHUB_FORK" == "" ]; then
echo "Defaulting to ZoneMinder upstream git"
GITHUB_FORK="ZoneMinder"
fi;
if [ "$SNAPSHOT" == "stable" ]; then
if [ "$BRANCH" == "" ]; then
BRANCH=$(git describe --tags $(git rev-list --tags --max-count=1));
echo "Latest stable branch is $BRANCH";
fi;
else
if [ "$BRANCH" == "" ]; then
echo "Defaulting to master branch";
BRANCH="master";
fi;
if [ "$SNAPSHOT" == "NOW" ]; then
SNAPSHOT=`date +%Y%m%d%H%M%S`;
fi;
fi;
fi
if [ ! -d 'zoneminder_release' ]; then
git clone https://github.com/ZoneMinder/ZoneMinder.git zoneminder_release
# Instead of cloning from github each time, if we have a fork lying around, update it and pull from there instead.
if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then
if [ -d "${GITHUB_FORK}_ZoneMinder.git" ]; then
echo "Using local clone ${GITHUB_FORK}_ZoneMinder.git to pull from."
cd "${GITHUB_FORK}_ZoneMinder.git"
echo "git pull..."
git pull
echo "git checkout $BRANCH"
git checkout $BRANCH
echo "git pull..."
git pull
cd ../
echo "git clone ${GITHUB_FORK}_ZoneMinder.git ${GITHUB_FORK}_zoneminder_release"
git clone "${GITHUB_FORK}_ZoneMinder.git" "${GITHUB_FORK}_zoneminder_release"
else
echo "git clone https://github.com/$GITHUB_FORK/ZoneMinder.git ${GITHUB_FORK}_zoneminder_release"
git clone "https://github.com/$GITHUB_FORK/ZoneMinder.git" "${GITHUB_FORK}_zoneminder_release"
fi
else
echo "release dir already exists. Please remove it."
exit 0;
fi;
if [ "$BRANCH" != "" ]; then
cd zoneminder_release
if [ "$BRANCH" == "stable" ]; then
BRANCH=$(git describe --tags $(git rev-list --tags --max-count=1));
echo "Latest stable branch is $BRANCH";
fi
git checkout $BRANCH
cd ../
cd "${GITHUB_FORK}_zoneminder_release"
if [ $RELEASE ]; then
git checkout $RELEASE
else
git checkout $BRANCH
fi;
VERSION=`cat zoneminder_release/version`
cd ../
VERSION=`cat ${GITHUB_FORK}_zoneminder_release/version`
if [ $VERSION == "" ]; then
exit 1;
fi;
echo "Doing $TYPE release zoneminder_$VERSION-$DISTRO-$SNAPSHOT";
mv zoneminder_release zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig
cd zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig
git submodule init
git submodule update --init --recursive
if [ $DISTRO == "trusty" ]; then
ln -sf distros/ubuntu1204 debian
else
ln -sf distros/ubuntu1604 debian
if [ "$SNAPSHOT" != "stable" ] && [ "$SNAPSHOT" != "" ]; then
VERSION="$VERSION~$SNAPSHOT";
fi;
# Auto-install all ZoneMinder's depedencies using the Debian control file
sudo apt-get install devscripts equivs
sudo mk-build-deps -ir ./debian/control
DIRECTORY="zoneminder_$VERSION";
echo "Doing $TYPE release $DIRECTORY";
mv "${GITHUB_FORK}_zoneminder_release" "$DIRECTORY.orig";
cd "$DIRECTORY.orig";
if [ -z `hostname -d` ] ; then
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`.local>"
git submodule init
git submodule update --init --recursive
if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]; then
mv distros/ubuntu1204 debian
else
if [ "$DISTRO" == "wheezy" ]; then
mv distros/debian debian
else
mv distros/ubuntu1604 debian
fi;
fi;
if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then
AUTHOR="$DEBFULLNAME <$DEBEMAIL>"
else
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`>"
if [ -z `hostname -d` ] ; then
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`.local>"
else
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`>"
fi
fi
if [ "$URGENCY" = "" ]; then
URGENCY="medium"
fi;
if [ "$SNAPSHOT" == "stable" ]; then
cat <<EOF > debian/changelog
zoneminder ($VERSION-$DISTRO-$SNAPSHOT) $DISTRO; urgency=medium
zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
* Release $VERSION
-- $AUTHOR $DATE
EOF
else
cat <<EOF > debian/changelog
zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
*
-- $AUTHOR $DATE
EOF
#rm -rf .git
#rm .gitignore
#cd ../
#tar zcf zoneminder_$VERSION-$DISTRO.orig.tar.gz zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig
#cd zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig
fi;
rm -rf .git
rm .gitignore
cd ../
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
cd $DIRECTORY.orig
if [ $TYPE == "binary" ]; then
debuild
# Auto-install all ZoneMinder's depedencies using the Debian control file
sudo apt-get install devscripts equivs
sudo mk-build-deps -ir ./debian/control
echo "Status: $?"
DEBUILD=debuild
else
if [ $TYPE == "local" ]; then
debuild -i -us -uc -b
else
debuild -S -sa
fi;
if [ $TYPE == "local" ]; then
# Auto-install all ZoneMinder's depedencies using the Debian control file
sudo apt-get install devscripts equivs
sudo mk-build-deps -ir ./debian/control
echo "Status: $?"
DEBUILD="debuild -i -us -uc -b"
else
DEBUILD="debuild -S -sa"
fi;
fi;
if [ "$DEBSIGN_KEYID" != "" ]; then
DEBUILD="$DEBUILD -k$DEBSIGN_KEYID"
fi
$DEBUILD
if [ $? -ne 0 ]; then
echo "Error status code is: $?"
echo "Build failed.";
exit $?;
fi;
cd ../
if [ "$INTERACTIVE" != "no" ]; then
read -p "Do you want to keep the checked out version of Zoneminder (incase you want to modify it later) [y/N]"
[[ $REPLY == [yY] ]] && { mv $DIRECTORY zoneminder_release; echo "The checked out copy is preserved in zoneminder_release"; } || { rm -fr $DIRECTORY; echo "The checked out copy has been deleted"; }
echo "Done!"
else
rm -fr $DIRECTORY; echo "The checked out copy has been deleted";
fi
read -p "Do you want to keep the checked out version of Zoneminder (incase you want to modify it later) [y/N]"
[[ $REPLY == [yY] ]] && { mv zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig zoneminder_release; echo "The checked out copy is preserved in zoneminder_release"; } || { rm -fr zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig; echo "The checked out copy has been deleted"; }
echo "Done!"
if [ $TYPE == "binary" ]; then
if [ "$INTERACTIVE" != "no" ]; then
echo "Not doing dput since it's a binary release. Do you want to install it? (Y/N)"
read install
if [ "$install" == "Y" ]; then
sudo dpkg -i $DIRECTORY*.deb
fi;
if [ "$DISTRO" == "jessie" ]; then
echo "Do you want to upload this binary to zmrepo? (y/N)"
read install
if [ "$install" == "Y" ]; then
scp "zoneminder_*-${VERSION}-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/"
fi;
fi;
fi;
else
SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes";
PPA="";
if [ "$RELEASE" != "" ]; then
PPA="ppa:iconnor/zoneminder";
else
if [ "$BRANCH" == "" ]; then
PPA="ppa:iconnor/zoneminder-master";
else
PPA="ppa:iconnor/zoneminder-$BRANCH";
fi;
fi;
dput="Y";
if [ "$INTERACTIVE" != "no" ]; then
echo "Ready to dput $SC to $PPA ? Y/N...";
read dput
fi
if [ "$dput" == "Y" -o "$dput" == "y" ]; then
dput $PPA $SC
fi;
fi;

View File

@ -1,14 +0,0 @@
<VirtualHost *:80>
DocumentRoot /usr/local/share/zoneminder/www
DirectoryIndex index.php
ScriptAlias /cgi-bin/ /usr/local/libexec/zoneminder/cgi-bin/
<Directory />
Require all granted
</Directory>
<Directory "/usr/local/libexec/zoneminder/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
</VirtualHost>

View File

@ -30,6 +30,9 @@ mysql -u root < db/zm_create.sql
# Add the ZoneMinder DB user
mysql -u root -e "grant insert,select,update,delete,lock tables,alter on zm.* to 'zmuser'@'localhost' identified by 'zmpass';"
# Make ZM_LOGDIR
mkdir /var/log/zm
# Activate CGI
a2enmod cgi

View File

@ -7,7 +7,8 @@ umount /dev/shm
mount -t tmpfs -o rw,nosuid,nodev,noexec,relatime,size=512M tmpfs /dev/shm
# Start MySQL
/usr/bin/mysqld_safe &
test -e /var/run/mysqld || install -m 755 -o mysql -g root -d /var/run/mysqld
su - mysql -s /bin/sh -c "/usr/bin/mysqld_safe > /dev/null 2>&1 &"
# Ensure we shut down mysql cleanly later:
trap close_mysql SIGTERM

View File

@ -1,17 +0,0 @@
--- a/packpack/pack/rpm.mk 2017-01-14 14:01:50.364217882 -0600
+++ b/packpack/pack/rpm.mk 2017-01-14 14:01:19.594985311 -0600
@@ -23,11 +23,13 @@
-e 's/Release:\([ ]*\).*/Release: $(RELEASE)%{dist}/' \
-e 's/Source0:\([ ]*\).*/Source0: $(TARBALL)/' \
-e 's/%setup .*/%setup -q -n $(PRODUCT)-$(VERSION)/' \
+ -e 's/%autosetup -n .*/%autosetup -n $(PRODUCT)-$(VERSION)/' \
-i $@.tmp
grep -F "Version: $(VERSION)" $@.tmp && \
grep -F "Release: $(RELEASE)" $@.tmp && \
grep -F "Source0: $(TARBALL)" $@.tmp && \
- grep -F "%setup -q -n $(PRODUCT)-$(VERSION)" $@.tmp || \
+ (grep -F "%setup -q -n $(PRODUCT)-$(VERSION)" $@.tmp || \
+ grep -F "%autosetup" $@.tmp) || \
(echo "Failed to patch RPM spec" && exit 1)
@ mv -f $@.tmp $@
@echo

View File

@ -1,11 +0,0 @@
--- a/packpack/pack/deb.mk 2017-01-15 16:41:32.938418279 -0600
+++ b/packpack/pack/deb.mk 2017-02-16 15:44:43.267900717 -0600
@@ -14,7 +14,7 @@
DPKG_BUILD:=$(PRODUCT)_$(DEB_VERSION)-$(RELEASE)_$(DPKG_ARCH).build
DPKG_DSC:=$(PRODUCT)_$(DEB_VERSION)-$(RELEASE).dsc
DPKG_ORIG_TARBALL:=$(PRODUCT)_$(DEB_VERSION).orig.tar.$(TARBALL_COMPRESSOR)
-DPKG_DEBIAN_TARBALL:=$(PRODUCT)_$(DEB_VERSION)-$(RELEASE).debian.tar.$(TARBALL_COMPRESSOR)
+DPKG_DEBIAN_TARBALL:=$(PRODUCT)_$(DEB_VERSION)-$(RELEASE).tar.$(TARBALL_COMPRESSOR)
# gh-7: Ubuntu/Debian should export DEBIAN_FRONTEND=noninteractive
export DEBIAN_FRONTEND=noninteractive

View File

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6tO+Kuj85uS4Z7ZmyAjmeAJbKbuv+pddPncgY/0/cSKfLbDo5f+TFM9K5AUlegcALbccUA9jt5p615KTgN0ZyGiCDcNs6/1DcDh4Nb/KgHsApVLZHZYpd7bnP5yadIqXroXw9VI2PWhUTasb97t4xvEepcsnepdfeGFegX7jyeRqucdEsZZa8kiSgU9hIdJyTeQXQQY5odYqABvR6ea7ff8iD2pdzjXIFHiA9527fXoPuUJo5rwIWOwtwstFG5xCT6ZPBgi2nECSZoRdG7zqkm2gqhAaNiR8PR5Qr0CbeYa4LWYl0v33CwLxFuyiP9AOqdFB+vF9c67do4E0yJ+heUNuOUbp3ePT1jJDOhQapAjkmyEb4A+RMNc9SEXmJh10nUiJ2zGGb9a3FyreopHfjdzKiZdk+uSV18kdG7KSiRvHep+sEK7xMepAQ3OiAprwOH2D2EoXC08TLehaeXmsOAuMGz0JvJKBXMGAow2SEa38v42PJwKsjn0qo72IjN1h/9ICgM/o+4oNHLHsu5GK1dornAt9OE6g1be1jXdij07QaSV831NiweOHqRTPpl2eglWfoyMjPuzebiyoAqb4tNBnMOk5BTaxx7ZZGXmdHyH9kKFAVj+WBkRHNlDhaMB2/QzhHUs0PRVRUexBKgog+1xnPE5gTie6NNnDB04NcDQ== zmrepo@zmrepo.zoneminder.com

Binary file not shown.

15
utils/packpack/installzm.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
# No longer needed. This was incorporated into startpackpack.sh
# Required, so that Travis marks the build as failed if any of the steps below fail
set -ev
# Install and test the zoneminder package (only) for Ubuntu Trusty
if [ ${OS} == "ubuntu" ] && [ ${DIST} == "trusty" ]; then
sudo gdebi --non-interactive build/zoneminder_*amd64.deb
sudo chmod 644 /etc/zm/zm.conf
mysql -uzmuser -pzmpass zm < db/test.monitor.sql
sudo /usr/bin/zmpkg.pl start
sudo /usr/bin/zmfilter.pl -f purgewhenfull
fi

View File

@ -0,0 +1,10 @@
--- a/packpack/pack/rpm.mk 2017-05-10 09:53:38.797616947 -0500
+++ b/packpack/pack/rpm.mk 2017-05-10 09:59:26.744409073 -0500
@@ -26,7 +26,6 @@
-e 's/Source0:\([ ]*\).*/Source0: $(TARBALL)/' \
-e 's/%setup.*/%setup -q -n $(PRODUCT)-$(VERSION)/' \
-re 's/(%autosetup.*)( -n \S*)(.*)/\1\3/' \
- -e '0,/%autosetup.*/ s/%autosetup.*/%autosetup -n $(PRODUCT)-$(VERSION)/' \
-e '/%changelog/a\* $(THEDATE) $(CHANGELOG_NAME) <$(CHANGELOG_EMAIL)> - $(VERSION)-$(RELEASE)\n\- $(CHANGELOG_TEXT)\n' \
-i $@.tmp
grep -F "Version: $(VERSION)" $@.tmp && \

50
utils/packpack/rsync_xfer.sh Executable file
View File

@ -0,0 +1,50 @@
#!/bin/bash
# Check to see if this script has access to all the commands it needs
for CMD in sshfs rsync find fusermount mkdir; do
type $CMD 2>&1 > /dev/null
if [ $? -ne 0 ]; then
echo
echo "ERROR: The script cannot find the required command \"${CMD}\"."
echo
exit 1
fi
done
# We only want to deploy packages during cron events
# See https://docs.travis-ci.com/user/cron-jobs/
if [ "${TRAVIS_EVENT_TYPE}" == "cron" ]; then
if [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then
targetfolder="debian/master/mini-dinstall/incoming"
else
targetfolder="travis"
fi
echo
echo "Target subfolder set to $targetfolder"
echo
mkdir -p ./zmrepo
ssh_mntchk="$(sshfs zmrepo@zmrepo.zoneminder.com:./ ./zmrepo -o workaround=rename,reconnect)"
if [ -z "$ssh_mntchk" ]; then
echo
echo "Remote filesystem mounted successfully."
echo "Begin transfering files..."
echo
# Don't keep packages older than 5 days
find ./zmrepo/$targetfolder/ -maxdepth 1 -type f -mtime +5 -delete
rsync -vzh --ignore-errors build/* zmrepo/$targetfolder/
fusermount -zu zmrepo
else
echo
echo "ERROR: Attempt to mount zmrepo.zoneminder.com failed!"
echo "sshfs gave the following error message:"
echo \"$ssh_mntchk\"
echo
exit 99
fi
fi

View File

@ -2,97 +2,77 @@
# packpack setup file for the ZoneMinder project
# Written by Andrew Bauer
# Check to see if this script has access to all the commands it needs
for CMD in set echo curl repoquery git ln mkdir patch rmdir; do
type $CMD 2>&1 > /dev/null
###############
# SUBROUTINES #
###############
if [ $? -ne 0 ]; then
echo
echo "ERROR: The script cannot find the required command \"${CMD}\"."
echo
exit $?
fi
done
# General sanity checks
checksanity () {
# Check to see if this script has access to all the commands it needs
for CMD in set echo curl repoquery git ln mkdir rmdir cat patch; do
type $CMD 2>&1 > /dev/null
# Verify OS & DIST environment variables have been set before calling this script
if [ -z "${OS}" ] || [ -z "${DIST}" ]; then
echo "ERROR: both OS and DIST environment variables must be set"
exit 1
fi
if [ $? -ne 0 ]; then
echo
echo "ERROR: The script cannot find the required command \"${CMD}\"."
echo
exit 1
fi
done
# Verify OS & DIST environment variables have been set before calling this script
if [ -z "${OS}" ] || [ -z "${DIST}" ]; then
echo "ERROR: both OS and DIST environment variables must be set"
exit 1
fi
if [ -z "${ARCH}" ]; then
ARCH="x86_64"
fi
if [[ "${ARCH}" != "x86_64" && "${ARCH}" != "i386" && "${ARCH}" != "armhf" ]]; then
echo
echo "ERROR: Unsupported architecture specified \"${ARCH}\"."
echo
exit 1
fi
}
# Steps common to all builds
mkdir -p build
if [ -e "packpack/Makefile" ]; then
echo "Checking packpack github repo for changes..."
git -C packpack pull origin master
else
echo "Cloning pakcpack github repo..."
git clone https://github.com/packpack/packpack.git packpack
fi
# The rpm specfile requires we download the tarball and manually move it into place
# Might as well do this for Debian as well, rather than git submodule init
CRUDVER="3.0.10"
if [ -e "build/crud-${CRUDVER}.tar.gz" ]; then
echo "Found existing Crud ${CRUDVER} tarball..."
else
echo "Retrieving Crud ${CRUDVER} submodule..."
curl -L https://github.com/FriendsOfCake/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz
if [ $? -ne 0 ]; then
echo "ERROR: Crud tarball retreival failed..."
exit $?
fi
fi
# Steps common to Redhat distros
if [ "${OS}" == "el" ] || [ "${OS}" == "fedora" ]; then
echo "Begin Redhat build..."
# %autosetup support has been merged upstream. No need to patch
#patch -p1 < utils/packpack/autosetup.patch
ln -sf distros/redhat rpm
# The rpm specfile requires the Crud submodule folder to be empty
if [ -e "web/api/app/Plugin/Crud/LICENSE.txt" ]; then
rm -rf web/api/app/Plugin/Crud
mkdir web/api/app/Plugin/Crud
fi
if [ "${OS}" == "el" ]; then
zmrepodistro=${OS}
commonprep () {
mkdir -p build
if [ -e "packpack/Makefile" ]; then
echo "Checking packpack github repo for changes..."
git -C packpack pull origin master
else
zmrepodistro="f"
echo "Cloning pakcpack github repo..."
git clone https://github.com/packpack/packpack.git packpack
fi
# Let repoquery determine the full url and filename of the zmrepo rpm we are interested in
result=`repoquery --repofrompath=zmpackpack,https://zmrepo.zoneminder.com/${zmrepodistro}/${DIST}/x86_64/ --repoid=zmpackpack --qf="%{location}" zmrepo 2> /dev/null`
# Patch packpack
patch --dry-run --silent -f -p1 < utils/packpack/packpack-rpm.patch
if [ $? -eq 0 ]; then
patch -p1 < utils/packpack/packpack-rpm.patch
fi
if [ -n "$result" ] && [ $? -eq 0 ]; then
echo "Retrieving ZMREPO rpm..."
curl $result > build/zmrepo.noarch.rpm
# The rpm specfile requires we download the tarball and manually move it into place
# Might as well do this for Debian as well, rather than git submodule init
CRUDVER="3.0.10"
if [ -e "build/crud-${CRUDVER}.tar.gz" ]; then
echo "Found existing Crud ${CRUDVER} tarball..."
else
echo "ERROR: Failed to retrieve zmrepo rpm..."
if [ $? -ne 0 ]; then
echo $?
else
echo 1
echo "Retrieving Crud ${CRUDVER} submodule..."
curl -L https://github.com/FriendsOfCake/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz
if [ $? -ne 0 ]; then
echo "ERROR: Crud tarball retreival failed..."
exit 1
fi
fi
}
echo "Starting packpack..."
packpack/packpack -f utils/packpack/redhat_package.mk redhat_package
# Steps common the Debian based distros
elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then
echo "Begin Debian build..."
# patch packpack to remove "debian" from the source tarball filename
patch --dry-run --silent -f -p1 < utils/packpack/deb.mk.patch 2>/dev/null
if [ $? -eq 0 ]; then
patch -p1 < utils/packpack/deb.mk.patch
fi
# Uncompress the Crud tarball and move it into place
# Uncompress the Crud tarball and move it into place
movecrud () {
if [ -e "web/api/app/Plugin/Crud/LICENSE.txt" ]; then
echo "Crud plugin already installed..."
else
@ -101,17 +81,151 @@ elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then
rmdir web/api/app/Plugin/Crud
mv -f crud-${CRUDVER} web/api/app/Plugin/Crud
fi
}
if [ ${DIST} == "trusty" ] || [ ${DIST} == "precise" ]; then
ln -sf distros/ubuntu1204 debian
elif [ ${DIST} == "wheezy" ]; then
ln -sf distros/debian debian
else
ln -sf distros/ubuntu1604 debian
# previsouly part of installzm.sh
# install the trusty deb and test zoneminder
installtrusty () {
# Check we've got gdebi installed
type gdebi 2>&1 > /dev/null
if [ $? -ne 0 ]; then
echo
echo "ERROR: The script cannot find the required command \"gdebi\"."
echo
exit 1
fi
# Install and test the zoneminder package (only) for Ubuntu Trusty
pkgname="build/zoneminder_${VERSION}-${RELEASE}_amd64.deb"
if [ -e $pkgname ]; then
sudo gdebi --non-interactive $pkgname
mysql -uzmuser -pzmpass zm < db/test.monitor.sql
sudo /usr/bin/zmpkg.pl start
sudo /usr/bin/zmfilter.pl -f purgewhenfull
else
echo
echo "ERROR: The script cannot find the package $pkgname"
echo "Check the Travis log for a build failure."
echo
exit 99
fi
}
# This sets the naming convention for the deb packages
setdebpkgver () {
# Set VERSION to x.xx.x+x e.g. 1.30.2+15
# the last x is number of commits since release
# Creates zoneminder packages in the format: zoneminder-{version}-{release}
zmver=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\1/p')
commitnum=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p')
export VERSION="$zmver+$commitnum"
export RELEASE="${DIST}"
echo
echo "Packpack VERSION has been set to: ${VERSION}"
echo "Packpack RELEASE has been set to: ${RELEASE}"
echo
}
################
# MAIN PROGRAM #
################
checksanity
# We don't want to build packages for all supported distros after every commit
# Only build all packages when executed via cron
# See https://docs.travis-ci.com/user/cron-jobs/
if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
commonprep
# Steps common to Redhat distros
if [ "${OS}" == "el" ] || [ "${OS}" == "fedora" ]; then
echo "Begin Redhat build..."
# Set VERSION to x.xx.x e.g. 1.30.2
# Set RELEASE to x where x is number of commits since release
# Creates zoneminder packages in the format: zoneminder-{version}-{release}
export VERSION=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\1/p')
export RELEASE=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p')
echo
echo "Packpack VERSION has been set to: ${VERSION}"
echo "Packpack RELEASE has been set to: ${RELEASE}"
echo
ln -sfT distros/redhat rpm
# The rpm specfile requires the Crud submodule folder to be empty
rm -rf web/api/app/Plugin/Crud
mkdir web/api/app/Plugin/Crud
if [ "${OS}" == "el" ]; then
zmrepodistro=${OS}
else
zmrepodistro="f"
fi
# Let repoquery determine the full url and filename of the zmrepo rpm we are interested in
result=`repoquery --repofrompath=zmpackpack,https://zmrepo.zoneminder.com/${zmrepodistro}/"${DIST}"/x86_64/ --repoid=zmpackpack --qf="%{location}" zmrepo 2> /dev/null`
if [ -n "$result" ] && [ $? -eq 0 ]; then
echo "Retrieving ZMREPO rpm..."
curl $result > build/zmrepo.noarch.rpm
else
echo "ERROR: Failed to retrieve zmrepo rpm..."
exit 1
fi
echo "Starting packpack..."
packpack/packpack -f utils/packpack/redhat_package.mk redhat_package
# Steps common to Debian based distros
elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then
echo "Begin ${OS} ${DIST} build..."
setdebpkgver
movecrud
if [ "${DIST}" == "trusty" ] || [ "${DIST}" == "precise" ]; then
ln -sfT distros/ubuntu1204 debian
elif [ "${DIST}" == "wheezy" ]; then
ln -sfT distros/debian debian
else
ln -sfT distros/ubuntu1604 debian
fi
echo "Starting packpack..."
packpack/packpack
if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then
installtrusty
fi
fi
# We were not triggered via cron so just build and test trusty
elif [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86_64" ]; then
echo "Begin Ubuntu Trusty build..."
commonprep
setdebpkgver
movecrud
ln -sfT distros/ubuntu1204 debian
echo "Starting packpack..."
packpack/packpack
# If we are running inside Travis then attempt to install the deb we just built
if [ "${TRAVIS}" == "true" ]; then
installtrusty
fi
fi
exit 0

View File

@ -1 +1 @@
1.30.2
1.30.4

View File

@ -18,6 +18,7 @@ if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/api/app/Config/core.php" DESTINATION "${ZM_WEBDIR}/api/app/Config")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/api/app/Config/database.php" DESTINATION "${ZM_WEBDIR}/api/app/Config")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/api/app/Config/bootstrap.php" DESTINATION "${ZM_WEBDIR}/api/app/Config")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/api/lib/Cake/bootstrap.php" DESTINATION "${ZM_WEBDIR}/api/lib/Cake")
endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
# Install the mootools symlinks (if its not in the source directory)

View File

@ -52,7 +52,7 @@ while ( !file_exists($remSockFile) && $max_socket_tries-- ) { //sometimes we are
}
if ( !file_exists($remSockFile) ) {
ajaxError("Socket $remSocketFile does not exist. This file is created by zms, and since it does not exist, either zms did not run, or zms exited early. Please check your zms logs and ensure that CGI is enabled in apache and check that the PATH_ZMS is set correctly. Make sure that ZM is actually recording. If you are trying to view a live stream and the capture process (zmc) is not running then zms will exit. Please go to http://zoneminder.readthedocs.io/en/latest/faq.html#why-can-t-i-see-streamed-images-when-i-can-see-stills-in-the-zone-window-etc for more information.");
ajaxError("Socket $remSockFile does not exist. This file is created by zms, and since it does not exist, either zms did not run, or zms exited early. Please check your zms logs and ensure that CGI is enabled in apache and check that the PATH_ZMS is set correctly. Make sure that ZM is actually recording. If you are trying to view a live stream and the capture process (zmc) is not running then zms will exit. Please go to http://zoneminder.readthedocs.io/en/latest/faq.html#why-can-t-i-see-streamed-images-when-i-can-see-stills-in-the-zone-window-etc for more information.");
} else {
if ( !@socket_sendto( $socket, $msg, strlen($msg), 0, $remSockFile ) ) {
ajaxError( "socket_sendto( $remSockFile ) failed: ".socket_strerror(socket_last_error()) );

View File

@ -11,5 +11,8 @@ configure_file(app/Config/database.php.default "${CMAKE_CURRENT_BINARY_DIR}/app/
# Configure core.php
configure_file(app/Config/core.php.default "${CMAKE_CURRENT_BINARY_DIR}/app/Config/core.php" @ONLY)
# Configure bootstrap.php
# Configure app/Config/bootstrap.php
configure_file(app/Config/bootstrap.php.in "${CMAKE_CURRENT_BINARY_DIR}/app/Config/bootstrap.php" @ONLY)
# Configure lib/Cake/bootstrap.php
configure_file(lib/Cake/bootstrap.php.in "${CMAKE_CURRENT_BINARY_DIR}/lib/Cake/bootstrap.php" @ONLY)

View File

@ -23,7 +23,7 @@
*/
// Setup a 'default' cache configuration for use in the application.
Cache::config('default', array('engine' => 'File'));
Cache::config('default', array('engine' => 'Apc'));
/**
* The settings below can be used to set additional paths to models, views and controllers.
@ -100,12 +100,16 @@ App::uses('CakeLog', 'Log');
CakeLog::config('debug', array(
'engine' => 'File',
'types' => array('notice', 'info', 'debug'),
'file' => 'debug',
'file' => 'cake_debug',
));
CakeLog::config('error', array(
'engine' => 'File',
'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'error',
'file' => 'cake_error',
));
CakeLog::config('custom_path', array(
'engine' => 'File',
'path' => '@ZM_LOGDIR@'
));
Configure::write('ZM_CONFIG', '@ZM_CONFIG@');

View File

@ -352,7 +352,7 @@
* Please check the comments in bootstrap.php for more info on the cache engines available
* and their settings.
*/
$engine = 'File';
$engine = 'Apc';
// In development mode, caches should expire quickly.
$duration = '+999 days';

View File

@ -88,7 +88,7 @@ class DATABASE_CONFIG {
public function __construct() {
if (strpos(ZM_DB_HOST, ':')):
$array = explode(':', ZM_DB_HOST, 2);
if (is_numeric($array[1])):
if (ctype_digit($array[1])):
$this->default['host'] = $array[0];
$this->default['port'] = $array[1];
else:

View File

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0"?>
<tags>
<tag id="1">
<name>defect</name>

View File

@ -18,6 +18,9 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
// Force Cake's temp folder = ZoneMinder's temp folder
define('TMP', '@ZM_TMPDIR@');
define('TIME_START', microtime(true));
if (!defined('E_DEPRECATED')) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

BIN
web/graphics/spinner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

View File

@ -1,51 +1,81 @@
<?php
require_once( 'database.php' );
class Storage {
public function __construct( $IdOrRow = NULL ) {
$row = NULL;
if ( $IdOrRow ) {
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
$row = dbFetchOne( 'SELECT * FROM Storage WHERE Id=?', NULL, array( $IdOrRow ) );
if ( ! $row ) {
Error("Unable to load Storage record for Id=" . $IdOrRow );
}
} elseif ( is_array( $IdOrRow ) ) {
$row = $IdOrRow;
}
}
if ( $row ) {
foreach ($row as $k => $v) {
$this->{$k} = $v;
}
} else {
$this->{'Name'} = '';
$this->{'Path'} = '';
}
public function __construct( $IdOrRow = NULL ) {
$row = NULL;
if ( $IdOrRow ) {
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
$row = dbFetchOne( 'SELECT * FROM Storage WHERE Id=?', NULL, array( $IdOrRow ) );
if ( ! $row ) {
Error("Unable to load Storage record for Id=" . $IdOrRow );
}
} elseif ( is_array( $IdOrRow ) ) {
$row = $IdOrRow;
}
}
if ( $row ) {
foreach ($row as $k => $v) {
$this->{$k} = $v;
}
} else {
$this->{'Name'} = '';
$this->{'Path'} = '';
}
}
public function Path() {
if ( isset( $this->{'Path'} ) and ( $this->{'Path'} != '' ) ) {
return $this->{'Path'};
} else if ( ! isset($this->{'Id'}) ) {
return ZM_DIR_EVENTS;
}
return $this->{'Name'};
}
public function __call( $fn, array $args= NULL){
if(isset($this->{$fn})){
return $this->{$fn};
#array_unshift($args, $this);
#call_user_func_array( $this->{$fn}, $args);
}
public function Path() {
if ( isset( $this->{'Path'} ) and ( $this->{'Path'} != '' ) ) {
return $this->{'Path'};
} else if ( ! isset($this->{'Id'}) ) {
$path = ZM_DIR_EVENTS;
if ( $path[0] != '/' ) {
$this->{'Path'} = ZM_PATH_WEB.'/'.ZM_DIR_EVENTS;
} else {
$this->{'Path'} = ZM_DIR_EVENTS;
}
return $this->{'Path'};
}
public static function find_all() {
$storage_areas = array();
$result = dbQuery( 'SELECT * FROM Storage ORDER BY Name');
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' );
foreach ( $results as $row => $obj ) {
$storage_areas[] = $obj;
}
return $storage_areas;
return $this->{'Name'};
}
public function Name() {
if ( isset( $this->{'Name'} ) and ( $this->{'Name'} != '' ) ) {
return $this->{'Name'};
} else if ( ! isset($this->{'Id'}) ) {
return 'Default';
}
return $this->{'Name'};
}
public function __call( $fn, array $args= NULL){
if(isset($this->{$fn})){
return $this->{$fn};
#array_unshift($args, $this);
#call_user_func_array( $this->{$fn}, $args);
}
}
public static function find_all() {
$storage_areas = array();
$result = dbQuery( 'SELECT * FROM Storage ORDER BY Name');
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' );
foreach ( $results as $row => $obj ) {
$storage_areas[] = $obj;
}
return $storage_areas;
}
public function disk_usage_percent() {
$path = $this->Path();
$total = disk_total_space( $path );
if ( ! $total ) {
Error("disk_total_space returned false for " . $path );
return 0;
}
$free = disk_free_space( $path );
if ( ! $free ) {
Error("disk_free_space returned false for " . $path );
}
$usage = round(($total - $free) / $total * 100);
return $usage;
}
}
?>

View File

@ -618,7 +618,7 @@ if ( !empty($action) )
{
if ( !$x10Monitor )
{
dbQuery( "insert into TriggersX10 set MonitorId = ?".implode( ", ", $x10Changes ), array( $mid ) );
dbQuery( "insert into TriggersX10 set MonitorId = ?,".implode( ", ", $x10Changes ), array( $mid ) );
}
else
{

View File

@ -0,0 +1,9 @@
Copyright (c) 2008-2013, Edward Z. Yang
All rights reserved.
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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.

View File

@ -0,0 +1,69 @@
[[ news ]]
1.0.4 released 2013-07-17
[SECURITY FIXES]
- When secret key was not explicitly set, it was not being used
by the csrf_hash() function. Thanks sparticvs for reporting.
[FEATURES]
- The default 'CSRF check failed' page now offers a handy 'Try
again' button, which resubmits the form.
[BUG FIXES]
- The fix for 1.0.3 inadvertantly turned off XMLHttpRequest
overloading for all browsers; it has now been fixed to only
apply to IE.
1.0.3 released 2012-01-31
[BUG FIXES]
- Internet Explorer 8 adds support for XMLHttpRequest.prototype,
but this support is broken for method overloading. We
explicitly disable JavaScript overloading for Internet Explorer.
Thanks Kelly Lu for reporting. <lubird@gmail.com>
- A global declaration was omitted, resulting in a variable
not being properly introduced in PHP 5.3. Thanks Whitney Beck for
reporting. <whitney.a.beck@gmail.com>
1.0.2 released 2009-03-08
[SECURITY FIXES]
- Due to a typo, csrf-magic accidentally treated the secret key
as always present. This means that there was a possible CSRF
attack against users without any cookies. No attacks in the
wild were known at the time of this release. Thanks Jakub
Vrána for reporting.
1.0.1 released 2008-11-02
[NEW FEATURES]
- Support for composite tokens; this also fixes a bug with using
IP-based tokens for users with cookies disabled.
- Native support cookie tokens; use csrf_conf('cookie', $name) to
specify the name of a cookie that the CSRF token should be
placed in. This is useful if you have a Squid cache, and need
to configure it to ignore this token.
- Tips/tricks section in README.txt.
- There is now a two hour expiration time on all tokens. This
can be modified using csrf_conf('expires', $seconds).
- ClickJacking protection using an iframe breaker. Disable with
csrf_conf('frame-breaker', false).
[BUG FIXES]
- CsrfMagic.send() incorrectly submitted GET requests twice,
once without the magic token and once with the token. Reported
by Kelly Lu <lubird@gmail.com>.

View File

@ -0,0 +1,160 @@
[[ csrf-magic ]]
Add the following line to the top of all web-accessible PHP pages. If you have
a common file included by everything, put it there.
include_once '/path/to/csrf-magic.php';
Do it, test it, then forget about it. csrf-magic is protecting you if nothing
bad happens. Read on if you run into problems.
TABLE OF CONTENTS
+ ------------------- +
1. TIPS AND TRICKS
2. AJAX
3. CONFIGURE
4. THANKS
5. FOOTNOTES
+ ------------------- +
1. TIPS AND TRICKS
* If your JavaScript and AJAX is persistently getting errors, check the
AJAX section below on how to fix.
* The CSS overlay protection makes it impossible to display your website
in frame/iframe elements. You can disable it with
csrf_conf('frame-breaker', false) in your csrf_startup() function.
* csrf-magic will start a session. To disable, use csrf_conf('auto-session',
false) in your csrf_startup() function.
* The default error message is a little user unfriendly. Write your own
function which outputs an error message and set csrf_conf('callback',
'myCallbackFunction') in your csrf_startup() function.
* Make sure csrf_conf('secret', 'ABCDEFG') has something random in it. If
the directory csrf-magic.php is in is writable, csrf-magic will generate
a secret key for you in the csrf-secret.php file.
* Remember you can use auto_prepend to include csrf-magic.php on all your
pages. You may want to create a stub file which you can include that
includes csrf-magic.php as well as performs configuration.
* The default expiration time for tokens is two hours. If you expect your
users to need longer to fill out forms, be sure to enable double
submission when the token is invalid.
2. AJAX
csrf-magic has the ability to dynamically rewrite AJAX requests which use
XMLHttpRequest. However, due to the invasiveness of this procedure, it is
not enabled by default. You can enable it by adding this code before you
include csrf-magic.php.
function csrf_startup() {
csrf_conf('rewrite-js', '/web/path/to/csrf-magic.js');
}
// include_once '/path/to/csrf-magic.php';
(Be sure to place csrf-magic.js somewhere web accessible).
The default method CSRF Magic uses to rewrite AJAX requests will
only work for browsers with support for XmlHttpRequest.prototype (this excludes
all versions of Internet Explorer). See this page for more information:
http://stackoverflow.com/questions/664315/internet-explorer-8-prototypes-and-xmlhttprequest
However, csrf-magic.js will
automatically detect and play nice with the following JavaScript frameworks:
* jQuery
* Prototype
* MooTools
* Ext
* Dojo
(Note 2013-07-16: It has been a long time since this manual support has
been updated, and some JavaScript libraries have placed their copies of XHR
in local variables in closures, which makes it difficult for us to monkey-patch
it in automatically.)
To rewrite your own JavaScript library to use csrf-magic.js, you should modify
your function that generates XMLHttpRequest to have this at the end:
return new CsrfMagic(xhrObject);
With whatever xhrObject may be. If you have literal instances of XMLHttpRequest
in your code, find and replace ''new XMLHttpRequest'' with ''new CsrfMagic''
(CsrfMagic will automatically instantiate an XMLHttpRequest object in a
cross-platform manner as necessary).
If you don't want csrf-magic monkeying around with your XMLHttpRequest object,
you can manually rewrite your AJAX code to include the variable. The important
information is stored in the global variables csrfMagicName and csrfMagicToken.
CsrfMagic.process may also be of interest, as it takes one parameter, a
querystring, and prepends the CSRF token to the value.
3. CONFIGURE
csrf-magic has some configuration options that you can set inside the
csrf_startup() function. They are described in csrf-magic.php, and you can
set them using the convenience function csrf_conf($name, $value).
For example, this is a recommended configuration:
/**
* This is a function that gets called if a csrf check fails. csrf-magic will
* then exit afterwards.
*/
function my_csrf_callback() {
echo "You're doing bad things young man!";
}
function csrf_startup() {
// While csrf-magic has a handy little heuristic for determining whether
// or not the content in the buffer is HTML or not, you should really
// give it a nudge and turn rewriting *off* when the content is
// not HTML. Implementation details will vary.
if (isset($_POST['ajax'])) csrf_conf('rewrite', false);
// This is a secret value that must be set in order to enable username
// and IP based checks. Don't show this to anyone. A secret id will
// automatically be generated for you if the directory csrf-magic.php
// is placed in is writable.
csrf_conf('secret', 'ABCDEFG123456');
// This enables JavaScript rewriting and will ensure your AJAX calls
// don't stop working.
csrf_conf('rewrite-js', '/csrf-magic.js');
// This makes csrf-magic call my_csrf_callback() before exiting when
// there is a bad csrf token. This lets me customize the error page.
csrf_conf('callback', 'my_csrf_callback');
// While this is enabled by default to boost backwards compatibility,
// for security purposes it should ideally be off. Some users can be
// NATted or have dialup addresses which rotate frequently. Cookies
// are much more reliable.
csrf_conf('allow-ip', false);
}
// Finally, include the library
include_once '/path/to/csrf-magic.php';
Configuration gets stored in the $GLOBALS['csrf'] array.
4. THANKS
My thanks to Chris Shiflett, for unintentionally inspiring the idea, as well
as telling me the original variant of the Bob and Mallory story,
and the Django CSRF Middleware authors, who thought up of this before me.
Gareth Heyes suggested using the frame-breaker option to protect against
CSS overlay attacks.

View File

@ -0,0 +1,191 @@
/**
* @file
*
* Rewrites XMLHttpRequest to automatically send CSRF token with it. In theory
* plays nice with other JavaScript libraries, needs testing though.
*/
// Here are the basic overloaded method definitions
// The wrapper must be set BEFORE onreadystatechange is written to, since
// a bug in ActiveXObject prevents us from properly testing for it.
CsrfMagic = function(real) {
// try to make it ourselves, if you didn't pass it
if (!real) try { real = new XMLHttpRequest; } catch (e) {;}
if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) {;}
if (!real) try { real = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {;}
if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP.4.0'); } catch (e) {;}
this.csrf = real;
// properties
var csrfMagic = this;
real.onreadystatechange = function() {
csrfMagic._updateProps();
return csrfMagic.onreadystatechange ? csrfMagic.onreadystatechange() : null;
};
csrfMagic._updateProps();
}
CsrfMagic.prototype = {
open: function(method, url, async, username, password) {
if (method == 'POST') this.csrf_isPost = true;
// deal with Opera bug, thanks jQuery
if (username) return this.csrf_open(method, url, async, username, password);
else return this.csrf_open(method, url, async);
},
csrf_open: function(method, url, async, username, password) {
if (username) return this.csrf.open(method, url, async, username, password);
else return this.csrf.open(method, url, async);
},
send: function(data) {
if (!this.csrf_isPost) return this.csrf_send(data);
prepend = csrfMagicName + '=' + csrfMagicToken + '&';
// XXX: Removed to eliminate 'Refused to set unsafe header "Content-length" ' errors in modern browsers
// if (this.csrf_purportedLength === undefined) {
// this.csrf_setRequestHeader("Content-length", this.csrf_purportedLength + prepend.length);
// delete this.csrf_purportedLength;
// }
delete this.csrf_isPost;
return this.csrf_send(prepend + data);
},
csrf_send: function(data) {
return this.csrf.send(data);
},
setRequestHeader: function(header, value) {
// We have to auto-set this at the end, since we don't know how long the
// nonce is when added to the data.
if (this.csrf_isPost && header == "Content-length") {
this.csrf_purportedLength = value;
return;
}
return this.csrf_setRequestHeader(header, value);
},
csrf_setRequestHeader: function(header, value) {
return this.csrf.setRequestHeader(header, value);
},
abort: function() {
return this.csrf.abort();
},
getAllResponseHeaders: function() {
return this.csrf.getAllResponseHeaders();
},
getResponseHeader: function(header) {
return this.csrf.getResponseHeader(header);
} // ,
}
// proprietary
CsrfMagic.prototype._updateProps = function() {
this.readyState = this.csrf.readyState;
if (this.readyState == 4) {
this.responseText = this.csrf.responseText;
this.responseXML = this.csrf.responseXML;
this.status = this.csrf.status;
this.statusText = this.csrf.statusText;
}
}
CsrfMagic.process = function(base) {
if(typeof base == 'object') {
base[csrfMagicName] = csrfMagicToken;
return base;
}
var prepend = csrfMagicName + '=' + csrfMagicToken;
if (base) return prepend + '&' + base;
return prepend;
}
// callback function for when everything on the page has loaded
CsrfMagic.end = function() {
// This rewrites forms AGAIN, so in case buffering didn't work this
// certainly will.
forms = document.getElementsByTagName('form');
for (var i = 0; i < forms.length; i++) {
form = forms[i];
if (form.method.toUpperCase() !== 'POST') continue;
if (form.elements[csrfMagicName]) continue;
var input = document.createElement('input');
input.setAttribute('name', csrfMagicName);
input.setAttribute('value', csrfMagicToken);
input.setAttribute('type', 'hidden');
form.appendChild(input);
}
}
// Sets things up for Mozilla/Opera/nice browsers
// We very specifically match against Internet Explorer, since they haven't
// implemented prototypes correctly yet.
if (window.XMLHttpRequest && window.XMLHttpRequest.prototype && '\v' != 'v') {
var x = XMLHttpRequest.prototype;
var c = CsrfMagic.prototype;
// Save the original functions
x.csrf_open = x.open;
x.csrf_send = x.send;
x.csrf_setRequestHeader = x.setRequestHeader;
// Notice that CsrfMagic is itself an instantiatable object, but only
// open, send and setRequestHeader are necessary as decorators.
x.open = c.open;
x.send = c.send;
x.setRequestHeader = c.setRequestHeader;
} else {
// The only way we can do this is by modifying a library you have been
// using. We support YUI, script.aculo.us, prototype, MooTools,
// jQuery, Ext and Dojo.
if (window.jQuery) {
// jQuery didn't implement a new XMLHttpRequest function, so we have
// to do this the hard way.
jQuery.csrf_ajax = jQuery.ajax;
jQuery.ajax = function( s ) {
if (s.type && s.type.toUpperCase() == 'POST') {
s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
if ( s.data && s.processData && typeof s.data != "string" ) {
s.data = jQuery.param(s.data);
}
s.data = CsrfMagic.process(s.data);
}
return jQuery.csrf_ajax( s );
}
}
if (window.Prototype) {
// This works for script.aculo.us too
Ajax.csrf_getTransport = Ajax.getTransport;
Ajax.getTransport = function() {
return new CsrfMagic(Ajax.csrf_getTransport());
}
}
if (window.MooTools) {
Browser.csrf_Request = Browser.Request;
Browser.Request = function () {
return new CsrfMagic(Browser.csrf_Request());
}
}
if (window.YAHOO) {
// old YUI API
YAHOO.util.Connect.csrf_createXhrObject = YAHOO.util.Connect.createXhrObject;
YAHOO.util.Connect.createXhrObject = function (transaction) {
obj = YAHOO.util.Connect.csrf_createXhrObject(transaction);
obj.conn = new CsrfMagic(obj.conn);
return obj;
}
}
if (window.Ext) {
// Ext can use other js libraries as loaders, so it has to come last
// Ext's implementation is pretty identical to Yahoo's, but we duplicate
// it for comprehensiveness's sake.
Ext.lib.Ajax.csrf_createXhrObject = Ext.lib.Ajax.createXhrObject;
Ext.lib.Ajax.createXhrObject = function (transaction) {
obj = Ext.lib.Ajax.csrf_createXhrObject(transaction);
obj.conn = new CsrfMagic(obj.conn);
return obj;
}
}
if (window.dojo) {
// NOTE: this doesn't work with latest dojo
dojo.csrf__xhrObj = dojo._xhrObj;
dojo._xhrObj = function () {
return new CsrfMagic(dojo.csrf__xhrObj());
}
}
}

View File

@ -0,0 +1,405 @@
<?php
/**
* @file
*
* csrf-magic is a PHP library that makes adding CSRF-protection to your
* web applications a snap. No need to modify every form or create a database
* of valid nonces; just include this file at the top of every
* web-accessible page (or even better, your common include file included
* in every page), and forget about it! (There are, of course, configuration
* options for advanced users).
*
* This library is PHP4 and PHP5 compatible.
*/
// CONFIGURATION:
/**
* By default, when you include this file csrf-magic will automatically check
* and exit if the CSRF token is invalid. This will defer executing
* csrf_check() until you're ready. You can also pass false as a parameter to
* that function, in which case the function will not exit but instead return
* a boolean false if the CSRF check failed. This allows for tighter integration
* with your system.
*/
$GLOBALS['csrf']['defer'] = true;
/**
* This is the amount of seconds you wish to allow before any token becomes
* invalid; the default is two hours, which should be more than enough for
* most websites.
*/
$GLOBALS['csrf']['expires'] = 7200;
/**
* Callback function to execute when there's the CSRF check fails and
* $fatal == true (see csrf_check). This will usually output an error message
* about the failure.
*/
$GLOBALS['csrf']['callback'] = 'csrf_callback';
/**
* Whether or not to include our JavaScript library which also rewrites
* AJAX requests on this domain. Set this to the web path. This setting only works
* with supported JavaScript libraries in Internet Explorer; see README.txt for
* a list of supported libraries.
*/
$GLOBALS['csrf']['rewrite-js'] = false;
/**
* A secret key used when hashing items. Please generate a random string and
* place it here. If you change this value, all previously generated tokens
* will become invalid.
*/
$GLOBALS['csrf']['secret'] = '';
// nota bene: library code should use csrf_get_secret() and not access
// this global directly
/**
* Set this to false to disable csrf-magic's output handler, and therefore,
* its rewriting capabilities. If you're serving non HTML content, you should
* definitely set this false.
*/
$GLOBALS['csrf']['rewrite'] = true;
/**
* Whether or not to use IP addresses when binding a user to a token. This is
* less reliable and less secure than sessions, but is useful when you need
* to give facilities to anonymous users and do not wish to maintain a database
* of valid keys.
*/
$GLOBALS['csrf']['allow-ip'] = true;
/**
* If this information is available, use the cookie by this name to determine
* whether or not to allow the request. This is a shortcut implementation
* very similar to 'key', but we randomly set the cookie ourselves.
*/
$GLOBALS['csrf']['cookie'] = '__csrf_cookie';
/**
* If this information is available, set this to a unique identifier (it
* can be an integer or a unique username) for the current "user" of this
* application. The token will then be globally valid for all of that user's
* operations, but no one else. This requires that 'secret' be set.
*/
$GLOBALS['csrf']['user'] = false;
/**
* This is an arbitrary secret value associated with the user's session. This
* will most probably be the contents of a cookie, as an attacker cannot easily
* determine this information. Warning: If the attacker knows this value, they
* can easily spoof a token. This is a generic implementation; sessions should
* work in most cases.
*
* Why would you want to use this? Lets suppose you have a squid cache for your
* website, and the presence of a session cookie bypasses it. Let's also say
* you allow anonymous users to interact with the website; submitting forms
* and AJAX. Previously, you didn't have any CSRF protection for anonymous users
* and so they never got sessions; you don't want to start using sessions either,
* otherwise you'll bypass the Squid cache. Setup a different cookie for CSRF
* tokens, and have Squid ignore that cookie for get requests, for anonymous
* users. (If you haven't guessed, this scheme was(?) used for MediaWiki).
*/
$GLOBALS['csrf']['key'] = false;
/**
* The name of the magic CSRF token that will be placed in all forms, i.e.
* the contents of <input type="hidden" name="$name" value="CSRF-TOKEN" />
*/
$GLOBALS['csrf']['input-name'] = '__csrf_magic';
/**
* Set this to false if your site must work inside of frame/iframe elements,
* but do so at your own risk: this configuration protects you against CSS
* overlay attacks that defeat tokens.
*/
$GLOBALS['csrf']['frame-breaker'] = true;
/**
* Whether or not CSRF Magic should be allowed to start a new session in order
* to determine the key.
*/
$GLOBALS['csrf']['auto-session'] = true;
/**
* Whether or not csrf-magic should produce XHTML style tags.
*/
$GLOBALS['csrf']['xhtml'] = true;
// FUNCTIONS:
// Don't edit this!
$GLOBALS['csrf']['version'] = '1.0.4';
/**
* Rewrites <form> on the fly to add CSRF tokens to them. This can also
* inject our JavaScript library.
*/
function csrf_ob_handler($buffer, $flags) {
// Even though the user told us to rewrite, we should do a quick heuristic
// to check if the page is *actually* HTML. We don't begin rewriting until
// we hit the first <html tag.
static $is_html = false;
if (!$is_html) {
// not HTML until proven otherwise
if (stripos($buffer, '<html') !== false) {
$is_html = true;
} else {
return $buffer;
}
}
$tokens = csrf_get_tokens();
$name = $GLOBALS['csrf']['input-name'];
$endslash = $GLOBALS['csrf']['xhtml'] ? ' /' : '';
$input = "<input type='hidden' name='$name' value=\"$tokens\"$endslash>";
$buffer = preg_replace('#(<form[^>]*method\s*=\s*["\']post["\'][^>]*>)#i', '$1' . $input, $buffer);
if ($GLOBALS['csrf']['frame-breaker']) {
$buffer = str_ireplace('</head>', '<script type="text/javascript">if (top != self) {top.location.href = self.location.href;}</script></head>', $buffer);
}
if ($js = $GLOBALS['csrf']['rewrite-js']) {
$buffer = str_ireplace(
'</head>',
'<script type="text/javascript">'.
'var csrfMagicToken = "'.$tokens.'";'.
'var csrfMagicName = "'.$name.'";</script>'.
'<script src="'.$js.'" type="text/javascript"></script></head>',
$buffer
);
$script = '<script type="text/javascript">CsrfMagic.end();</script>';
$buffer = str_ireplace('</body>', $script . '</body>', $buffer, $count);
if (!$count) {
$buffer .= $script;
}
}
return $buffer;
}
/**
* Checks if this is a post request, and if it is, checks if the nonce is valid.
* @param bool $fatal Whether or not to fatally error out if there is a problem.
* @return True if check passes or is not necessary, false if failure.
*/
function csrf_check($fatal = true) {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true;
csrf_start();
$name = $GLOBALS['csrf']['input-name'];
$ok = false;
$tokens = '';
do {
if (!isset($_POST[$name])) break;
// we don't regenerate a token and check it because some token creation
// schemes are volatile.
$tokens = $_POST[$name];
if (!csrf_check_tokens($tokens)) break;
$ok = true;
} while (false);
if ($fatal && !$ok) {
$callback = $GLOBALS['csrf']['callback'];
if (trim($tokens, 'A..Za..z0..9:;,') !== '') $tokens = 'hidden';
$callback($tokens);
exit;
}
return $ok;
}
/**
* Retrieves a valid token(s) for a particular context. Tokens are separated
* by semicolons.
*/
function csrf_get_tokens() {
$has_cookies = !empty($_COOKIE);
// $ip implements a composite key, which is sent if the user hasn't sent
// any cookies. It may or may not be used, depending on whether or not
// the cookies "stick"
$secret = csrf_get_secret();
if (!$has_cookies && $secret) {
// :TODO: Harden this against proxy-spoofing attacks
$IP_ADDRESS = (isset($_SERVER['IP_ADDRESS']) ? $_SERVER['IP_ADDRESS'] : $_SERVER['REMOTE_ADDR']);
$ip = ';ip:' . csrf_hash($IP_ADDRESS);
} else {
$ip = '';
}
csrf_start();
// These are "strong" algorithms that don't require per se a secret
if (session_id()) return 'sid:' . csrf_hash(session_id()) . $ip;
if ($GLOBALS['csrf']['cookie']) {
$val = csrf_generate_secret();
setcookie($GLOBALS['csrf']['cookie'], $val);
return 'cookie:' . csrf_hash($val) . $ip;
}
if ($GLOBALS['csrf']['key']) return 'key:' . csrf_hash($GLOBALS['csrf']['key']) . $ip;
// These further algorithms require a server-side secret
if (!$secret) return 'invalid';
if ($GLOBALS['csrf']['user'] !== false) {
return 'user:' . csrf_hash($GLOBALS['csrf']['user']);
}
if ($GLOBALS['csrf']['allow-ip']) {
return ltrim($ip, ';');
}
return 'invalid';
}
function csrf_flattenpost($data) {
$ret = array();
foreach($data as $n => $v) {
$ret = array_merge($ret, csrf_flattenpost2(1, $n, $v));
}
return $ret;
}
function csrf_flattenpost2($level, $key, $data) {
if(!is_array($data)) return array($key => $data);
$ret = array();
foreach($data as $n => $v) {
$nk = $level >= 1 ? $key."[$n]" : "[$n]";
$ret = array_merge($ret, csrf_flattenpost2($level+1, $nk, $v));
}
return $ret;
}
/**
* @param $tokens is safe for HTML consumption
*/
function csrf_callback($tokens) {
// (yes, $tokens is safe to echo without escaping)
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
$data = '';
foreach (csrf_flattenpost($_POST) as $key => $value) {
if ($key == $GLOBALS['csrf']['input-name']) continue;
$data .= '<input type="hidden" name="'.htmlspecialchars($key).'" value="'.htmlspecialchars($value).'" />';
}
echo "<html><head><title>CSRF check failed</title></head>
<body>
<p>CSRF check failed. Your form session may have expired, or you may not have
cookies enabled.</p>
<form method='post' action=''>$data<input type='submit' value='Try again' /></form>
<p>Debug: $tokens</p></body></html>
";
}
/**
* Checks if a composite token is valid. Outward facing code should use this
* instead of csrf_check_token()
*/
function csrf_check_tokens($tokens) {
if (is_string($tokens)) $tokens = explode(';', $tokens);
foreach ($tokens as $token) {
if (csrf_check_token($token)) return true;
}
return false;
}
/**
* Checks if a token is valid.
*/
function csrf_check_token($token) {
if (strpos($token, ':') === false) return false;
list($type, $value) = explode(':', $token, 2);
if (strpos($value, ',') === false) return false;
list($x, $time) = explode(',', $token, 2);
if ($GLOBALS['csrf']['expires']) {
if (time() > $time + $GLOBALS['csrf']['expires']) return false;
}
switch ($type) {
case 'sid':
return $value === csrf_hash(session_id(), $time);
case 'cookie':
$n = $GLOBALS['csrf']['cookie'];
if (!$n) return false;
if (!isset($_COOKIE[$n])) return false;
return $value === csrf_hash($_COOKIE[$n], $time);
case 'key':
if (!$GLOBALS['csrf']['key']) return false;
return $value === csrf_hash($GLOBALS['csrf']['key'], $time);
// We could disable these 'weaker' checks if 'key' was set, but
// that doesn't make me feel good then about the cookie-based
// implementation.
case 'user':
if (!csrf_get_secret()) return false;
if ($GLOBALS['csrf']['user'] === false) return false;
return $value === csrf_hash($GLOBALS['csrf']['user'], $time);
case 'ip':
if (!csrf_get_secret()) return false;
// do not allow IP-based checks if the username is set, or if
// the browser sent cookies
if ($GLOBALS['csrf']['user'] !== false) return false;
if (!empty($_COOKIE)) return false;
if (!$GLOBALS['csrf']['allow-ip']) return false;
$IP_ADDRESS = (isset($_SERVER['IP_ADDRESS']) ? $_SERVER['IP_ADDRESS'] : $_SERVER['REMOTE_ADDR']);
return $value === csrf_hash($IP_ADDRESS, $time);
}
return false;
}
/**
* Sets a configuration value.
*/
function csrf_conf($key, $val) {
if (!isset($GLOBALS['csrf'][$key])) {
trigger_error('No such configuration ' . $key, E_USER_WARNING);
return;
}
$GLOBALS['csrf'][$key] = $val;
}
/**
* Starts a session if we're allowed to.
*/
function csrf_start() {
if ($GLOBALS['csrf']['auto-session'] && !session_id()) {
session_start();
}
}
/**
* Retrieves the secret, and generates one if necessary.
*/
function csrf_get_secret() {
if ($GLOBALS['csrf']['secret']) return $GLOBALS['csrf']['secret'];
$dir = dirname(__FILE__);
$file = $dir . '/csrf-secret.php';
$secret = '';
if (file_exists($file)) {
include $file;
return $secret;
}
if (is_writable($dir)) {
$secret = csrf_generate_secret();
$fh = fopen($file, 'w');
fwrite($fh, '<?php $secret = "'.$secret.'";' . PHP_EOL);
fclose($fh);
return $secret;
}
return '';
}
/**
* Generates a random string as the hash of time, microtime, and mt_rand.
*/
function csrf_generate_secret($len = 32) {
$r = '';
for ($i = 0; $i < $len; $i++) {
$r .= chr(mt_rand(0, 255));
}
$r .= time() . microtime();
return sha1($r);
}
/**
* Generates a hash/expiry double. If time isn't set it will be calculated
* from the current time.
*/
function csrf_hash($value, $time = null) {
if (!$time) $time = time();
return sha1(csrf_get_secret() . $value . $time) . ',' . $time;
}
// Load user configuration
if (function_exists('csrf_startup')) csrf_startup();
// Initialize our handler
if ($GLOBALS['csrf']['rewrite']) ob_start('csrf_ob_handler');
// Perform check
if (!$GLOBALS['csrf']['defer']) csrf_check();

View File

@ -33,7 +33,7 @@ function dbConnect()
if (strpos(ZM_DB_HOST, ':')) {
// Host variable may carry a port or socket.
list($host, $portOrSocket) = explode(':', ZM_DB_HOST, 2);
if (is_numeric($portOrSocket)) {
if (ctype_digit($portOrSocket)) {
$socket = ':host='.$host . ';port='.$portOrSocket;
} else {
$socket = ':unix_socket='.$portOrSocket;

View File

@ -835,12 +835,13 @@ function packageControl( $command ) {
function daemonControl( $command, $daemon=false, $args=false ) {
$string = ZM_PATH_BIN."/zmdc.pl $command";
if ( $daemon ) {
$string .= escapeshellarg(" $daemon");
$string .= ' ' . $daemon;
if ( $args ) {
$string .= escapeshellarg(" $args");
$string .= ' ' . $args;
}
}
$string .= " 2>/dev/null >&- <&- >/dev/null";
$string = escapeshellcmd( $string );
$string .= ' 2>/dev/null >&- <&- >/dev/null';
exec( $string );
}
@ -877,21 +878,12 @@ function zmaControl( $monitor, $mode=false ) {
daemonControl( "stop", "zmtrack.pl", "-m ".$monitor['Id'] );
}
daemonControl( "stop", "zma", "-m ".$monitor['Id'] );
if ( ZM_OPT_FRAME_SERVER ) {
daemonControl( "stop", "zmf", "-m ".$monitor['Id'] );
}
} else {
if ( $mode == "restart" ) {
if ( ZM_OPT_CONTROL ) {
daemonControl( "stop", "zmtrack.pl", "-m ".$monitor['Id'] );
}
daemonControl( "stop", "zma", "-m ".$monitor['Id'] );
if ( ZM_OPT_FRAME_SERVER ) {
daemonControl( "stop", "zmf", "-m ".$monitor['Id'] );
}
}
if ( ZM_OPT_FRAME_SERVER ) {
daemonControl( "start", "zmf", "-m ".$monitor['Id'] );
}
daemonControl( "start", "zma", "-m ".$monitor['Id'] );
if ( ZM_OPT_CONTROL && $monitor['Controllable'] && $monitor['TrackMotion'] && ( $monitor['Function'] == 'Modect' || $monitor['Function'] == 'Mocord' ) ) {
@ -947,10 +939,11 @@ function zmaStatus( $monitor ) {
function daemonCheck( $daemon=false, $args=false ) {
$string = ZM_PATH_BIN."/zmdc.pl check";
if ( $daemon ) {
$string .= escapeshellarg(" $daemon");
$string .= ' ' . $daemon;
if ( $args )
$string .= escapeshellarg(" $args");
$string .= ' '. $args;
}
$string = escapeshellcmd( $string );
$result = exec( $string );
return( preg_match( '/running/', $result ) );
}
@ -2164,4 +2157,8 @@ function folder_size($dir) {
return $size;
} // end function folder_size
function csrf_startup() {
csrf_conf('rewrite-js', 'includes/csrf/csrf-magic.js');
}
?>

View File

@ -105,6 +105,7 @@ if ( ! in_array( $css, $css_skins ) ) {
}
define( "ZM_BASE_PATH", dirname( $_SERVER['REQUEST_URI'] ) );
define( "ZM_SKIN_NAME", $skin );
define( "ZM_SKIN_PATH", "skins/$skin" );
$skinBase = array(); // To allow for inheritance of skins
@ -147,6 +148,7 @@ else
require_once( 'includes/lang.php' );
require_once( 'includes/functions.php' );
require_once( 'includes/csrf/csrf-magic.php' );
# Add Cross domain access headers
CORSHeaders();
@ -169,6 +171,16 @@ if ( isset($_REQUEST['action']) )
foreach ( getSkinIncludes( 'skin.php' ) as $includeFile )
require_once $includeFile;
# The only variable we really need to set is action. The others are informal.
isset($view) || $view = NULL;
isset($request) || $request = NULL;
isset($action) || $action = NULL;
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' ) {
Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
csrf_check();
}
require_once( 'includes/actions.php' );
# If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in.

View File

@ -46,7 +46,7 @@ function logReport( level, message, file, line )
return;
if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.name )
message += ' - '+arguments.callee.caller.caller.name+'()';
message += ' - '+arguments.callee.caller.caller.name+'()';
if ( !debugReq )
{
@ -115,4 +115,4 @@ window.onerror =
function( message, url, line )
{
logReport( "ERR", message, url, line );
}
};

View File

@ -84,7 +84,7 @@ var Overlay = new Class({
showAnimation:function()
{
showOverlay();
//console.log( "Showing overlay loading" );
if ( !this.loading )
{
@ -116,7 +116,7 @@ function setupOverlays()
overlay.getElements('.overlayCloser').each(
function( closer )
{
closer.addEvent( 'click', function() { overlay.element.hide(); } )
closer.addEvent( 'click', function() { overlay.element.hide(); } );
}
);
overlay.overlayShow = function() { overlay.element.show(); };

View File

@ -1,4 +1,4 @@
<?php
<?php
//
// ZoneMinder web Polish language file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes

View File

@ -822,14 +822,6 @@ $OLANG = array(
'Prompt' => "Creaz&#259; imagini analizate cu marcaje ale mi&#351;c&#259;rii",
'Help' => "Implicit, &#238;n cazul unei alarme, ZoneMinder &#238;nregistreaz&#259; at&#226;t imaginile neprelucrate c&#226;t &#351;i cele ce au fost analizate &#351;i au zone marcate unde a fost detectat&#259; mi&#351;care. Acest lucru poate fi foarte folositor la configurarea zonelor sau &#238;n analiza evenimentelor. Acest parametru permite oprirea &#238;nregistr&#259;rii imaginilor cu zone de mi&#351;care marcate."
),
'OPT_FRAME_SERVER' => array(
'Prompt' => "Daemon-ul de analiz&#259; va scrie imaginile pe disc",
'Help' => "&#206;n unele cazuri este posibil ca viteza de scriere a unui HDD sa fie at&#226;t de mic&#259; &#238;ncat s&#259; cauzeze &#238;ncetinirea daemon-ului de analiz&#259; &#238;n special &#238;n timpul evenimentelor cu multe cadre. Activarea acestei op&#355;iuni porne&#351;te daemon-ul de cadre (zmf) care va 'primi' imaginile de la daemon-ul de analiz&#259; &#351;i le va scrie pe disc. Dac&#259; aceast&#259; transmisie e&#351;ueaz&#259; sau apar alte erori, func&#355;ia de scriere va reveni daemon-ului de analiz&#259;."
),
'FRAME_SOCKET_SIZE' => array(
'Prompt' => "Specifica&#355;i dimensiunea memoriei tampon",
'Help' => "Pentru imaginile de dimensiuni mari capturate este posibil ca scrierea lor pe disc s&#259; e&#351;ueze deoarece cantitatea de informa&#355;ie scris&#259; este mai mare dec&#226;t memoria tampon alocat&#259;. De&#351;i imaginile sunt scrise apoi de c&#259;tre daemon-ul de analiz&#259;, se distruge obiectul daemon-ului de cadre. Pute&#355;i folosi aceast&#259; op&#355;iune pentru a specifica o memorie tampon de dimensiuni mai mari. Va trebui sa modifica&#355;i dimensiunea socket-ului tampon maxim folosind 'sysctl' (sau in /proc/sys/net/core/wmem_max) pentru a permite setarea acestei noi valori. Alternativa este s&#259; schimba&#355;i m&#259;rimea implicit&#259; a memorie tampon a sistemului, caz &#238;n care modificarea acestei valori nu mai este necesar&#259;."
),
'OPT_CONTROL' => array(
'Prompt' => "Suport camere controlabile (rotire/&#238;nclinare/zoom)",
'Help' => "ZoneMinder include suport limitat pentru camere controlabile. Sunt incluse c&#226;teva protocoale mostr&#259; &#351;i pot fi ad&#259;ugate cu u&#351;urin&#355;&#259; &#351;i altele. Dac&#259; vre&#355;i s&#259; controla&#355;i camerele prin intermediul ZoneMinder selecta&#355;i aceast&#259; op&#355;iune."

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,6 @@
#scaleControl {
float: right;
}
#controls {
width: 80%;
text-align: center;

View File

@ -1,3 +1,6 @@
#scaleControl {
float: right;
}
#controls {
width: 80%;
text-align: center;

View File

@ -1,3 +1,7 @@
#scaleControl {
float: right;
}
#controls {
width: 80%;
text-align: center;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

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