diff --git a/CHANGELOG.md b/CHANGELOG.md index dc69f2f89..ddf9320cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,99 +1,129 @@ # Change Log -## [Unreleased](https://github.com/ZoneMinder/ZoneMinder/tree/HEAD) - -[Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.28.1...HEAD) - -**Closed issues:** - -- Zoneminder Signal Loss event [\#964](https://github.com/ZoneMinder/ZoneMinder/issues/964) -- Default scale other than actual skews image [\#963](https://github.com/ZoneMinder/ZoneMinder/issues/963) -- Monitor configured with ffmpeg shows last part of URL instead of hostname in overview [\#950](https://github.com/ZoneMinder/ZoneMinder/issues/950) -- please update bundled CakePHP [\#945](https://github.com/ZoneMinder/ZoneMinder/issues/945) -- Montage shows only feed from the first camera [\#940](https://github.com/ZoneMinder/ZoneMinder/issues/940) -- zmtrigger: minor message format correction [\#939](https://github.com/ZoneMinder/ZoneMinder/issues/939) -- error starting zoneminder after latest upgrade [\#935](https://github.com/ZoneMinder/ZoneMinder/issues/935) -- Error "Attempt to directly assign buffer from an undersized buffer of size" [\#932](https://github.com/ZoneMinder/ZoneMinder/issues/932) -- External access to snapshots of cameras [\#929](https://github.com/ZoneMinder/ZoneMinder/issues/929) -- virtualbox - zoneminder shows only six cams [\#927](https://github.com/ZoneMinder/ZoneMinder/issues/927) -- zm\_update-1.28.99.sql not executable [\#924](https://github.com/ZoneMinder/ZoneMinder/issues/924) -- m [\#922](https://github.com/ZoneMinder/ZoneMinder/issues/922) -- loop recording [\#914](https://github.com/ZoneMinder/ZoneMinder/issues/914) -- Implement Passive Source Type for Cams that Support Event Uploading [\#912](https://github.com/ZoneMinder/ZoneMinder/issues/912) -- incorrect encoding of Russian language [\#907](https://github.com/ZoneMinder/ZoneMinder/issues/907) -- Can't compile Zoneminder v1.28.1 [\#904](https://github.com/ZoneMinder/ZoneMinder/issues/904) -- Add isRunning field to States [\#898](https://github.com/ZoneMinder/ZoneMinder/issues/898) -- updated 9831W control script [\#893](https://github.com/ZoneMinder/ZoneMinder/issues/893) -- 404 error on Ubuntu 14.04 install [\#889](https://github.com/ZoneMinder/ZoneMinder/issues/889) -- Video Smear - Vertical Striping [\#888](https://github.com/ZoneMinder/ZoneMinder/issues/888) -- Zoneminder mobile theme broken. [\#887](https://github.com/ZoneMinder/ZoneMinder/issues/887) -- cgi-bin -\> symlink on zms not work for me \(Gentoo/SystemD\) [\#878](https://github.com/ZoneMinder/ZoneMinder/issues/878) -- Replay Event Stuck [\#869](https://github.com/ZoneMinder/ZoneMinder/issues/869) -- cant add or edit monitor [\#868](https://github.com/ZoneMinder/ZoneMinder/issues/868) -- Odd window size differences when viewing frame alarm image between Chrome & FF [\#865](https://github.com/ZoneMinder/ZoneMinder/issues/865) -- On ubuntu 14.04 zoneminder 1.28.1 alarm never terminate!! [\#852](https://github.com/ZoneMinder/ZoneMinder/issues/852) -- X-10 configuration not working ZM V1.28.1 [\#848](https://github.com/ZoneMinder/ZoneMinder/issues/848) -- Global symbol requires explicit package name... [\#846](https://github.com/ZoneMinder/ZoneMinder/issues/846) -- Adapt to changes in Ubuntu 15.04 [\#840](https://github.com/ZoneMinder/ZoneMinder/issues/840) -- After initial setup, unable to start again [\#839](https://github.com/ZoneMinder/ZoneMinder/issues/839) -- FFMPEG path finding error \(formerly: Are you switching to a totally CMake based build?\) [\#835](https://github.com/ZoneMinder/ZoneMinder/issues/835) -- Purchase a Raspberry Pi 2 + PiCam for ZoneMinder development \[$114\] [\#832](https://github.com/ZoneMinder/ZoneMinder/issues/832) -- Can't Login Web getting a Loop [\#831](https://github.com/ZoneMinder/ZoneMinder/issues/831) -- Missing function drop down values \(db issue?\) [\#828](https://github.com/ZoneMinder/ZoneMinder/issues/828) -- curl using HEAD instead of GET for http requests results in 404 on some servers [\#827](https://github.com/ZoneMinder/ZoneMinder/issues/827) -- Empty string if missing index in lang files [\#819](https://github.com/ZoneMinder/ZoneMinder/issues/819) -- fix for RTSP streaming over UDP [\#811](https://github.com/ZoneMinder/ZoneMinder/issues/811) -- bundled CakePHP overhead [\#810](https://github.com/ZoneMinder/ZoneMinder/issues/810) -- PHP session locks serialize access to all scripts causing UI hangs [\#806](https://github.com/ZoneMinder/ZoneMinder/issues/806) -- How do I add authentication to ZM APIs? [\#797](https://github.com/ZoneMinder/ZoneMinder/issues/797) -- Add man page for zmsystemctl.pl [\#788](https://github.com/ZoneMinder/ZoneMinder/issues/788) -- man pages please; improve --help option [\#787](https://github.com/ZoneMinder/ZoneMinder/issues/787) -- ZM\_CONTENTDIR issues [\#786](https://github.com/ZoneMinder/ZoneMinder/issues/786) -- please update bundled jQuery [\#785](https://github.com/ZoneMinder/ZoneMinder/issues/785) -- please update bundled Mootools [\#784](https://github.com/ZoneMinder/ZoneMinder/issues/784) -- duplicated files in `cgi-bin` [\#777](https://github.com/ZoneMinder/ZoneMinder/issues/777) -- FTBFS on kFreeBSD [\#771](https://github.com/ZoneMinder/ZoneMinder/issues/771) -- CMake: incorrect installation of Perl modules \[patch\] [\#769](https://github.com/ZoneMinder/ZoneMinder/issues/769) -- Issue when viewing events when users are restricted to limited cameras [\#766](https://github.com/ZoneMinder/ZoneMinder/issues/766) -- zmupdate.pl: ignores ZM\_SERVER\_HOST in zm.conf [\#765](https://github.com/ZoneMinder/ZoneMinder/issues/765) -- Remote Zoneminder installations [\#764](https://github.com/ZoneMinder/ZoneMinder/issues/764) -- source code mess [\#760](https://github.com/ZoneMinder/ZoneMinder/issues/760) -- bttv crashing zoneminder rpm [\#755](https://github.com/ZoneMinder/ZoneMinder/issues/755) -- Make Uninstall no longer removes Perl modules [\#753](https://github.com/ZoneMinder/ZoneMinder/issues/753) -- Playback video problem in v1.26.5 [\#752](https://github.com/ZoneMinder/ZoneMinder/issues/752) -- Integrate Make Movie Branch [\#747](https://github.com/ZoneMinder/ZoneMinder/issues/747) -- FI8620 ERR Error while decoding frame [\#741](https://github.com/ZoneMinder/ZoneMinder/issues/741) -- \[Critical\] 1.28.0 to 1.28.1 seems to have lost ability for RTSP Authentication [\#738](https://github.com/ZoneMinder/ZoneMinder/issues/738) -- Disabling cambozola in options doesn't actually disable? [\#735](https://github.com/ZoneMinder/ZoneMinder/issues/735) -- FI9821W v2 shows blue screen [\#734](https://github.com/ZoneMinder/ZoneMinder/issues/734) -- Configure script checking for netpbm [\#731](https://github.com/ZoneMinder/ZoneMinder/issues/731) -- Missing dependency for killall in rpm package [\#727](https://github.com/ZoneMinder/ZoneMinder/issues/727) -- Build with ZM\_TARGET\_DISTRO=el7 fails to start under systemd [\#724](https://github.com/ZoneMinder/ZoneMinder/issues/724) -- Issue with event page for users with restricted monitors [\#717](https://github.com/ZoneMinder/ZoneMinder/issues/717) -- Unrecognised content type 'video/x-ms-asf' [\#716](https://github.com/ZoneMinder/ZoneMinder/issues/716) -- Flat skin stopped working [\#715](https://github.com/ZoneMinder/ZoneMinder/issues/715) -- Zone edit dots are gone [\#712](https://github.com/ZoneMinder/ZoneMinder/issues/712) -- zm\_rtsp Use of avformat\_free\_context not version checked [\#710](https://github.com/ZoneMinder/ZoneMinder/issues/710) -- Unable to generate video, check /usr/share/zoneminder/events/1/15/02/15/20/10/00/ffmpeg.log for details [\#705](https://github.com/ZoneMinder/ZoneMinder/issues/705) -- Axis M5014 PTZ Control [\#703](https://github.com/ZoneMinder/ZoneMinder/issues/703) -- 2nd network port breaks 'Probe' in 1.28 on Ubuntu 14.04LTS? [\#698](https://github.com/ZoneMinder/ZoneMinder/issues/698) -- ZM's Develop actually [\#697](https://github.com/ZoneMinder/ZoneMinder/issues/697) -- Release 1.28.1 [\#693](https://github.com/ZoneMinder/ZoneMinder/issues/693) -- Image disappears \(flickers\) in monitor and event playback [\#689](https://github.com/ZoneMinder/ZoneMinder/issues/689) -- Multiple issues.. [\#688](https://github.com/ZoneMinder/ZoneMinder/issues/688) -- short PHP open tags paragraph on zoneminder.com Troubleshooting page [\#684](https://github.com/ZoneMinder/ZoneMinder/issues/684) -- The monitorprobe.php code does not work in FreeBSD [\#683](https://github.com/ZoneMinder/ZoneMinder/issues/683) -- ZoneMinder problem [\#680](https://github.com/ZoneMinder/ZoneMinder/issues/680) -- CMAKE ZM\_PERL\_SUBPREFIX Slash Issue [\#677](https://github.com/ZoneMinder/ZoneMinder/issues/677) -- Centos 6.5 crashes [\#619](https://github.com/ZoneMinder/ZoneMinder/issues/619) -- ZMS crashes after "Attempt to directly assign buffer from an undersized buffer of size" error [\#586](https://github.com/ZoneMinder/ZoneMinder/issues/586) -- hi all, i'm under Linux Gentoo with systemd - ZM v1.27.99.0 [\#511](https://github.com/ZoneMinder/ZoneMinder/issues/511) -- Event export with ZM\_USE\_DEEP\_STORAGE option set [\#506](https://github.com/ZoneMinder/ZoneMinder/issues/506) -- Streaming not working on Chrome when authentication is ON [\#328](https://github.com/ZoneMinder/ZoneMinder/issues/328) -- Can add a simple send mail function? [\#311](https://github.com/ZoneMinder/ZoneMinder/issues/311) +## [v1.29.0](https://github.com/ZoneMinder/ZoneMinder/tree/v1.29.0) (2016-02-03) +[Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.29.0-rc2...v1.29.0) **Merged pull requests:** +- 1253 zms quit cmd [\#1254](https://github.com/ZoneMinder/ZoneMinder/pull/1254) ([pliablepixels](https://github.com/pliablepixels)) +- Add Debug/Info lines reporting multi-server status [\#1252](https://github.com/ZoneMinder/ZoneMinder/pull/1252) ([connortechnology](https://github.com/connortechnology)) +- Do debian package mods [\#1244](https://github.com/ZoneMinder/ZoneMinder/pull/1244) ([pliablepixels](https://github.com/pliablepixels)) +- zmtrigger - process off+time delay condition [\#1240](https://github.com/ZoneMinder/ZoneMinder/pull/1240) ([knnniggett](https://github.com/knnniggett)) +- Multi server [\#1233](https://github.com/ZoneMinder/ZoneMinder/pull/1233) ([connortechnology](https://github.com/connortechnology)) +- remove Google open Sans external import [\#1232](https://github.com/ZoneMinder/ZoneMinder/pull/1232) ([connortechnology](https://github.com/connortechnology)) +- PTZ - Added autostop to Down command on FI8918W [\#1189](https://github.com/ZoneMinder/ZoneMinder/pull/1189) ([marcolino7](https://github.com/marcolino7)) + +## [v1.29.0-rc2](https://github.com/ZoneMinder/ZoneMinder/tree/v1.29.0-rc2) (2016-01-05) +[Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.29.0-rc1...v1.29.0-rc2) + +**Merged pull requests:** + +- Multi server [\#1223](https://github.com/ZoneMinder/ZoneMinder/pull/1223) ([connortechnology](https://github.com/connortechnology)) +- Multi server [\#1222](https://github.com/ZoneMinder/ZoneMinder/pull/1222) ([connortechnology](https://github.com/connortechnology)) +- Multi server [\#1217](https://github.com/ZoneMinder/ZoneMinder/pull/1217) ([connortechnology](https://github.com/connortechnology)) +- Multi server [\#1215](https://github.com/ZoneMinder/ZoneMinder/pull/1215) ([connortechnology](https://github.com/connortechnology)) +- Change log updates [\#1172](https://github.com/ZoneMinder/ZoneMinder/pull/1172) ([SteveGilvarry](https://github.com/SteveGilvarry)) + +## [v1.29.0-rc1](https://github.com/ZoneMinder/ZoneMinder/tree/v1.29.0-rc1) (2016-01-01) +[Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.28.1...v1.29.0-rc1) + +**Merged pull requests:** + +- Bump version to 1.29.0 [\#1213](https://github.com/ZoneMinder/ZoneMinder/pull/1213) ([knnniggett](https://github.com/knnniggett)) +- Missing rtd theme [\#1202](https://github.com/ZoneMinder/ZoneMinder/pull/1202) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- Skip directories that have non-digits in them [\#1201](https://github.com/ZoneMinder/ZoneMinder/pull/1201) ([connortechnology](https://github.com/connortechnology)) +- updated mobile app info [\#1200](https://github.com/ZoneMinder/ZoneMinder/pull/1200) ([pliablepixels](https://github.com/pliablepixels)) +- Api more security [\#1196](https://github.com/ZoneMinder/ZoneMinder/pull/1196) ([pliablepixels](https://github.com/pliablepixels)) +- Documentation [\#1194](https://github.com/ZoneMinder/ZoneMinder/pull/1194) ([pliablepixels](https://github.com/pliablepixels)) +- Documentation updated for ubuntu [\#1193](https://github.com/ZoneMinder/ZoneMinder/pull/1193) ([pliablepixels](https://github.com/pliablepixels)) +- Fixes \#1179 Libvlc Live555 Segmentation Fault [\#1190](https://github.com/ZoneMinder/ZoneMinder/pull/1190) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- Add code to detect the change in REALM from older to newer firmware [\#1184](https://github.com/ZoneMinder/ZoneMinder/pull/1184) ([connortechnology](https://github.com/connortechnology)) +- add a 1/8th scale option, which is useful for 1920x1080 streams [\#1182](https://github.com/ZoneMinder/ZoneMinder/pull/1182) ([connortechnology](https://github.com/connortechnology)) +- Zms socket lock [\#1180](https://github.com/ZoneMinder/ZoneMinder/pull/1180) ([connortechnology](https://github.com/connortechnology)) +- Check for the presence of CrudControllerTrait.php instead of .git [\#1178](https://github.com/ZoneMinder/ZoneMinder/pull/1178) ([knnniggett](https://github.com/knnniggett)) +- Partial fix for \#1167 [\#1176](https://github.com/ZoneMinder/ZoneMinder/pull/1176) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- Error on missing submodules [\#1173](https://github.com/ZoneMinder/ZoneMinder/pull/1173) ([knnniggett](https://github.com/knnniggett)) +- fix mem alloc fault in zm\_monitor.cpp [\#1168](https://github.com/ZoneMinder/ZoneMinder/pull/1168) ([knnniggett](https://github.com/knnniggett)) +- compat for php 5.4 [\#1164](https://github.com/ZoneMinder/ZoneMinder/pull/1164) ([abishai](https://github.com/abishai)) +- remove comment at end of line [\#1157](https://github.com/ZoneMinder/ZoneMinder/pull/1157) ([connortechnology](https://github.com/connortechnology)) +- Reorder RTSPDescribe to avoid -wreorder warnings [\#1147](https://github.com/ZoneMinder/ZoneMinder/pull/1147) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- Update to \#1137 for backward compatibility. [\#1142](https://github.com/ZoneMinder/ZoneMinder/pull/1142) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- Update Travis to ffmpeg 2.8.1 for testing [\#1139](https://github.com/ZoneMinder/ZoneMinder/pull/1139) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- Replace deprecated FFmpeg API [\#1137](https://github.com/ZoneMinder/ZoneMinder/pull/1137) ([onlyjob](https://github.com/onlyjob)) +- added prev/next event ids [\#1136](https://github.com/ZoneMinder/ZoneMinder/pull/1136) ([pliablepixels](https://github.com/pliablepixels)) +- Install nph-zms with FILES so it is listed in install\_manifest.txt [\#1124](https://github.com/ZoneMinder/ZoneMinder/pull/1124) ([baffo32](https://github.com/baffo32)) +- Stray semicolon causes SQL error [\#1123](https://github.com/ZoneMinder/ZoneMinder/pull/1123) ([baffo32](https://github.com/baffo32)) +- Use relative URL's instead of absolute [\#1121](https://github.com/ZoneMinder/ZoneMinder/pull/1121) ([knnniggett](https://github.com/knnniggett)) +- Update version check URL [\#1120](https://github.com/ZoneMinder/ZoneMinder/pull/1120) ([kylejohnson](https://github.com/kylejohnson)) +- Add index to frames [\#1116](https://github.com/ZoneMinder/ZoneMinder/pull/1116) ([kylejohnson](https://github.com/kylejohnson)) +- Fatal if content dirs are unwritable [\#1113](https://github.com/ZoneMinder/ZoneMinder/pull/1113) ([baffo32](https://github.com/baffo32)) +- Fatal error if date.timezone is unset [\#1111](https://github.com/ZoneMinder/ZoneMinder/pull/1111) ([baffo32](https://github.com/baffo32)) +- Fix faulty zm.conf.new install line [\#1107](https://github.com/ZoneMinder/ZoneMinder/pull/1107) ([baffo32](https://github.com/baffo32)) +- Update preinst [\#1103](https://github.com/ZoneMinder/ZoneMinder/pull/1103) ([seebaer1976](https://github.com/seebaer1976)) +- Update apache.conf [\#1102](https://github.com/ZoneMinder/ZoneMinder/pull/1102) ([seebaer1976](https://github.com/seebaer1976)) +- Update rules [\#1101](https://github.com/ZoneMinder/ZoneMinder/pull/1101) ([seebaer1976](https://github.com/seebaer1976)) +- Update links [\#1100](https://github.com/ZoneMinder/ZoneMinder/pull/1100) ([seebaer1976](https://github.com/seebaer1976)) +- Update preinst [\#1099](https://github.com/ZoneMinder/ZoneMinder/pull/1099) ([seebaer1976](https://github.com/seebaer1976)) +- Fix zmaudit [\#1095](https://github.com/ZoneMinder/ZoneMinder/pull/1095) ([connortechnology](https://github.com/connortechnology)) +- fixed version compare logic [\#1094](https://github.com/ZoneMinder/ZoneMinder/pull/1094) ([pliablepixels](https://github.com/pliablepixels)) +- Don't install zm.conf if it already exists [\#1090](https://github.com/ZoneMinder/ZoneMinder/pull/1090) ([connortechnology](https://github.com/connortechnology)) +- change types and move things around to remove compile warnings [\#1089](https://github.com/ZoneMinder/ZoneMinder/pull/1089) ([connortechnology](https://github.com/connortechnology)) +- Tz [\#1084](https://github.com/ZoneMinder/ZoneMinder/pull/1084) ([connortechnology](https://github.com/connortechnology)) +- fixed orange display for monitor mode [\#1083](https://github.com/ZoneMinder/ZoneMinder/pull/1083) ([pliablepixels](https://github.com/pliablepixels)) +- use deleteAll\(\) vs. delete\(\) when deleting an Event's Frames [\#1080](https://github.com/ZoneMinder/ZoneMinder/pull/1080) ([kylejohnson](https://github.com/kylejohnson)) +- Added control script for SunEyes SP-P1802SWPTZ [\#1079](https://github.com/ZoneMinder/ZoneMinder/pull/1079) ([bofhdk](https://github.com/bofhdk)) +- Use the 3.0 branch of crud, compatible with cakephp 2.x [\#1078](https://github.com/ZoneMinder/ZoneMinder/pull/1078) ([kylejohnson](https://github.com/kylejohnson)) +- 663 frames primary key [\#1075](https://github.com/ZoneMinder/ZoneMinder/pull/1075) ([kylejohnson](https://github.com/kylejohnson)) +- Delete fixes for Events [\#1073](https://github.com/ZoneMinder/ZoneMinder/pull/1073) ([pliablepixels](https://github.com/pliablepixels)) +- restart monitor when edited via APIs [\#1070](https://github.com/ZoneMinder/ZoneMinder/pull/1070) ([pliablepixels](https://github.com/pliablepixels)) +- add debug statements for when LastWriteTime is not defined. [\#1067](https://github.com/ZoneMinder/ZoneMinder/pull/1067) ([connortechnology](https://github.com/connortechnology)) +- fixed recaptcha showing up pre DB update [\#1066](https://github.com/ZoneMinder/ZoneMinder/pull/1066) ([pliablepixels](https://github.com/pliablepixels)) +- fixed security instructions for curl [\#1062](https://github.com/ZoneMinder/ZoneMinder/pull/1062) ([pliablepixels](https://github.com/pliablepixels)) +- header typo corrections [\#1058](https://github.com/ZoneMinder/ZoneMinder/pull/1058) ([onlyjob](https://github.com/onlyjob)) +- quick fix for \#1055: make sure our mmap fd is \> 2 [\#1057](https://github.com/ZoneMinder/ZoneMinder/pull/1057) ([connortechnology](https://github.com/connortechnology)) +- Fix sgfault caused by the privacy mask stuff [\#1056](https://github.com/ZoneMinder/ZoneMinder/pull/1056) ([connortechnology](https://github.com/connortechnology)) +- link to cambozola pacakge, rather than download during build [\#1054](https://github.com/ZoneMinder/ZoneMinder/pull/1054) ([knnniggett](https://github.com/knnniggett)) +- redhat rpm packaging modifications [\#1052](https://github.com/ZoneMinder/ZoneMinder/pull/1052) ([knnniggett](https://github.com/knnniggett)) +- remove core.php, modify core.php.default [\#1049](https://github.com/ZoneMinder/ZoneMinder/pull/1049) ([knnniggett](https://github.com/knnniggett)) +- Google recaptcha [\#1048](https://github.com/ZoneMinder/ZoneMinder/pull/1048) ([pliablepixels](https://github.com/pliablepixels)) +- enable/disable RTSP Describe Header [\#1045](https://github.com/ZoneMinder/ZoneMinder/pull/1045) ([knnniggett](https://github.com/knnniggett)) +- Add Documentation for Privacy zones [\#1044](https://github.com/ZoneMinder/ZoneMinder/pull/1044) ([schrorg](https://github.com/schrorg)) +- added note about potential Perl and PHP time translation conflict wit… [\#1043](https://github.com/ZoneMinder/ZoneMinder/pull/1043) ([pliablepixels](https://github.com/pliablepixels)) +- Multi server [\#1040](https://github.com/ZoneMinder/ZoneMinder/pull/1040) ([connortechnology](https://github.com/connortechnology)) +- 1038 fixing state mgmt 1030 is active fix [\#1039](https://github.com/ZoneMinder/ZoneMinder/pull/1039) ([pliablepixels](https://github.com/pliablepixels)) +- Grey color for disabled buttons [\#1037](https://github.com/ZoneMinder/ZoneMinder/pull/1037) ([pliablepixels](https://github.com/pliablepixels)) +- Update filterevents.rst [\#1035](https://github.com/ZoneMinder/ZoneMinder/pull/1035) ([tikismoke](https://github.com/tikismoke)) +- add warning and help text for maxfps fields [\#1033](https://github.com/ZoneMinder/ZoneMinder/pull/1033) ([knnniggett](https://github.com/knnniggett)) +- update doc [\#1032](https://github.com/ZoneMinder/ZoneMinder/pull/1032) ([tikismoke](https://github.com/tikismoke)) +- Remove full path from Logger filename [\#1029](https://github.com/ZoneMinder/ZoneMinder/pull/1029) ([knnniggett](https://github.com/knnniggett)) +- Typo in README.md [\#1027](https://github.com/ZoneMinder/ZoneMinder/pull/1027) ([tikismoke](https://github.com/tikismoke)) +- Add new zone type - privacy zones [\#1026](https://github.com/ZoneMinder/ZoneMinder/pull/1026) ([schrorg](https://github.com/schrorg)) +- Send login activity to the zoneminder event log [\#1021](https://github.com/ZoneMinder/ZoneMinder/pull/1021) ([knnniggett](https://github.com/knnniggett)) +- Small dark CSS fixes in frames and timeline view [\#1019](https://github.com/ZoneMinder/ZoneMinder/pull/1019) ([schrorg](https://github.com/schrorg)) +- New User Permission "Groups" [\#1018](https://github.com/ZoneMinder/ZoneMinder/pull/1018) ([knnniggett](https://github.com/knnniggett)) +- 1013 document migration [\#1017](https://github.com/ZoneMinder/ZoneMinder/pull/1017) ([pliablepixels](https://github.com/pliablepixels)) +- Fix issue with score values less than 0 [\#1016](https://github.com/ZoneMinder/ZoneMinder/pull/1016) ([knnniggett](https://github.com/knnniggett)) +- Explained a caveat with using relative times [\#1012](https://github.com/ZoneMinder/ZoneMinder/pull/1012) ([pliablepixels](https://github.com/pliablepixels)) +- Included logic to not enforce authentication in API layer if ZM auth is off [\#1008](https://github.com/ZoneMinder/ZoneMinder/pull/1008) ([pliablepixels](https://github.com/pliablepixels)) +- Update to ffmpeg 2.7.2 in travis build [\#1007](https://github.com/ZoneMinder/ZoneMinder/pull/1007) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- I was using the wrong field to check for portal authentication [\#1006](https://github.com/ZoneMinder/ZoneMinder/pull/1006) ([pliablepixels](https://github.com/pliablepixels)) +- Demote user auth info message to debug [\#1003](https://github.com/ZoneMinder/ZoneMinder/pull/1003) ([Linwood-F](https://github.com/Linwood-F)) +- Add scale as optional feature to image.php [\#1001](https://github.com/ZoneMinder/ZoneMinder/pull/1001) ([Linwood-F](https://github.com/Linwood-F)) +- 995 events count per api \(bumps up \# of events reported per API call\) [\#996](https://github.com/ZoneMinder/ZoneMinder/pull/996) ([pliablepixels](https://github.com/pliablepixels)) +- APIs will be served only if user is logged into the ZM portal [\#994](https://github.com/ZoneMinder/ZoneMinder/pull/994) ([pliablepixels](https://github.com/pliablepixels)) +- Add option to make TimeStamp larger [\#992](https://github.com/ZoneMinder/ZoneMinder/pull/992) ([schrorg](https://github.com/schrorg)) +- Implemented \#989 \(highlight current row in tables\) for dark CSS [\#990](https://github.com/ZoneMinder/ZoneMinder/pull/990) ([schrorg](https://github.com/schrorg)) +- CSS\[skins/classic\]: highlight current row in tables. [\#989](https://github.com/ZoneMinder/ZoneMinder/pull/989) ([onlyjob](https://github.com/onlyjob)) +- quiet error when no Servers in Servers table [\#986](https://github.com/ZoneMinder/ZoneMinder/pull/986) ([connortechnology](https://github.com/connortechnology)) +- fix \#948 1 [\#985](https://github.com/ZoneMinder/ZoneMinder/pull/985) ([connortechnology](https://github.com/connortechnology)) +- Remove shared data warning for purpose query only [\#984](https://github.com/ZoneMinder/ZoneMinder/pull/984) ([Linwood-F](https://github.com/Linwood-F)) +- Change from info to debug [\#983](https://github.com/ZoneMinder/ZoneMinder/pull/983) ([Linwood-F](https://github.com/Linwood-F)) +- Fix image dimensions check [\#980](https://github.com/ZoneMinder/ZoneMinder/pull/980) ([connortechnology](https://github.com/connortechnology)) +- Apache.conf modifications [\#968](https://github.com/ZoneMinder/ZoneMinder/pull/968) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- Dark CSS for classic theme [\#967](https://github.com/ZoneMinder/ZoneMinder/pull/967) ([schrorg](https://github.com/schrorg)) +- Auto generated changelog [\#966](https://github.com/ZoneMinder/ZoneMinder/pull/966) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- 959 add exif date time to images [\#962](https://github.com/ZoneMinder/ZoneMinder/pull/962) ([Linwood-F](https://github.com/Linwood-F)) +- Add analysis interval parameter to monitors settings [\#956](https://github.com/ZoneMinder/ZoneMinder/pull/956) ([manupap1](https://github.com/manupap1)) - Fixed Configs API to return all values [\#955](https://github.com/ZoneMinder/ZoneMinder/pull/955) ([pliablepixels](https://github.com/pliablepixels)) - Change encoding of german language file to UTF-8 [\#952](https://github.com/ZoneMinder/ZoneMinder/pull/952) ([schrorg](https://github.com/schrorg)) - Show correct part of URL \(hostname\) for ffmpeg sources in console [\#951](https://github.com/ZoneMinder/ZoneMinder/pull/951) ([schrorg](https://github.com/schrorg)) @@ -125,17 +155,12 @@ - Generate man pages for perl scripts & C Binaries in the bin folder [\#896](https://github.com/ZoneMinder/ZoneMinder/pull/896) ([knnniggett](https://github.com/knnniggett)) - 893 foscam 9831 w and other foscams [\#895](https://github.com/ZoneMinder/ZoneMinder/pull/895) ([pliablepixels](https://github.com/pliablepixels)) - 893 foscam 9831 w and other foscams [\#894](https://github.com/ZoneMinder/ZoneMinder/pull/894) ([pliablepixels](https://github.com/pliablepixels)) -- improve debugging for analysis check and restart if can't read shared data [\#892](https://github.com/ZoneMinder/ZoneMinder/pull/892) ([connortechnology](https://github.com/connortechnology)) - Zmwatch cleanup2 [\#891](https://github.com/ZoneMinder/ZoneMinder/pull/891) ([connortechnology](https://github.com/connortechnology)) - reverse the if statement to reduce indenting [\#890](https://github.com/ZoneMinder/ZoneMinder/pull/890) ([connortechnology](https://github.com/connortechnology)) - Updated API document [\#886](https://github.com/ZoneMinder/ZoneMinder/pull/886) ([pliablepixels](https://github.com/pliablepixels)) - Use avconv as alternative to ffmpeg executable [\#884](https://github.com/ZoneMinder/ZoneMinder/pull/884) ([SteveGilvarry](https://github.com/SteveGilvarry)) - 881 bootstrap loading config [\#883](https://github.com/ZoneMinder/ZoneMinder/pull/883) ([pliablepixels](https://github.com/pliablepixels)) - Merged Angular UI branch API to master [\#882](https://github.com/ZoneMinder/ZoneMinder/pull/882) ([pliablepixels](https://github.com/pliablepixels)) -- h264 GUI translate fixes [\#880](https://github.com/ZoneMinder/ZoneMinder/pull/880) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- Merging Master to feature-h264-videostorage [\#879](https://github.com/ZoneMinder/ZoneMinder/pull/879) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- 799 api improvements [\#877](https://github.com/ZoneMinder/ZoneMinder/pull/877) ([pliablepixels](https://github.com/pliablepixels)) -- Fixed daemonStatus API to return string returned by ZMC in addition t… [\#876](https://github.com/ZoneMinder/ZoneMinder/pull/876) ([pliablepixels](https://github.com/pliablepixels)) - Add version to the startup log line [\#875](https://github.com/ZoneMinder/ZoneMinder/pull/875) ([connortechnology](https://github.com/connortechnology)) - German translation update [\#874](https://github.com/ZoneMinder/ZoneMinder/pull/874) ([seeebek](https://github.com/seeebek)) - reduce the wait to 2/10ths instead of a whole second [\#873](https://github.com/ZoneMinder/ZoneMinder/pull/873) ([connortechnology](https://github.com/connortechnology)) @@ -186,8 +211,6 @@ - POD: zmupdate.pl converted to "pod2usage" [\#763](https://github.com/ZoneMinder/ZoneMinder/pull/763) ([onlyjob](https://github.com/onlyjob)) - build: fix FTBFS with format-hardening \(please review\) [\#761](https://github.com/ZoneMinder/ZoneMinder/pull/761) ([onlyjob](https://github.com/onlyjob)) - fixing POD errors [\#759](https://github.com/ZoneMinder/ZoneMinder/pull/759) ([onlyjob](https://github.com/onlyjob)) -- Fixed a missing bracket post merge and also SQL\_values now used for Even... [\#750](https://github.com/ZoneMinder/ZoneMinder/pull/750) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- Keeping h264 updated. [\#749](https://github.com/ZoneMinder/ZoneMinder/pull/749) ([SteveGilvarry](https://github.com/SteveGilvarry)) - Ignore autogenerated files in git [\#746](https://github.com/ZoneMinder/ZoneMinder/pull/746) ([manupap1](https://github.com/manupap1)) - when auth is needed, try command again before dying. [\#739](https://github.com/ZoneMinder/ZoneMinder/pull/739) ([connortechnology](https://github.com/connortechnology)) - remove NETPBM dependency from autotools [\#737](https://github.com/ZoneMinder/ZoneMinder/pull/737) ([knnniggett](https://github.com/knnniggett)) @@ -205,8 +228,6 @@ - Check to make sure that skin and css are valid. [\#713](https://github.com/ZoneMinder/ZoneMinder/pull/713) ([connortechnology](https://github.com/connortechnology)) - Fixes \#710 Added libavformat version check around free context functions [\#711](https://github.com/ZoneMinder/ZoneMinder/pull/711) ([SteveGilvarry](https://github.com/SteveGilvarry)) - try harder to find arp. [\#709](https://github.com/ZoneMinder/ZoneMinder/pull/709) ([connortechnology](https://github.com/connortechnology)) -- Merging Video and feature-h264-videostorage update [\#707](https://github.com/ZoneMinder/ZoneMinder/pull/707) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- Update Version.txt to 1.28.1 [\#706](https://github.com/ZoneMinder/ZoneMinder/pull/706) ([SteveGilvarry](https://github.com/SteveGilvarry)) - Make el6 and el7 build process a little more automated [\#704](https://github.com/ZoneMinder/ZoneMinder/pull/704) ([clipo1979](https://github.com/clipo1979)) - small improvements: [\#702](https://github.com/ZoneMinder/ZoneMinder/pull/702) ([connortechnology](https://github.com/connortechnology)) - Centos 7 rpm packaging [\#700](https://github.com/ZoneMinder/ZoneMinder/pull/700) ([knnniggett](https://github.com/knnniggett)) @@ -217,76 +238,6 @@ ## [v1.28.1](https://github.com/ZoneMinder/ZoneMinder/tree/v1.28.1) (2015-02-05) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.28.0...v1.28.1) -**Implemented enhancements:** - -- Implement unit testing [\#266](https://github.com/ZoneMinder/ZoneMinder/issues/266) -- Replace PHP short tags [\#11](https://github.com/ZoneMinder/ZoneMinder/issues/11) - -**Fixed bugs:** - -- Streaming an Event as MPEG fails. [\#686](https://github.com/ZoneMinder/ZoneMinder/issues/686) -- Zoneminder Web UI No Longer Refreshes After Change [\#534](https://github.com/ZoneMinder/ZoneMinder/issues/534) -- Monster log messages [\#491](https://github.com/ZoneMinder/ZoneMinder/issues/491) -- zmu fails silently when it cannot read zm.conf [\#339](https://github.com/ZoneMinder/ZoneMinder/issues/339) -- Errors on Monitors page during first view [\#175](https://github.com/ZoneMinder/ZoneMinder/issues/175) -- Logs screen overflows when too much text in message column [\#138](https://github.com/ZoneMinder/ZoneMinder/issues/138) -- When filtering in the Events view, filter options are lost between pages [\#25](https://github.com/ZoneMinder/ZoneMinder/issues/25) - -**Closed issues:** - -- Gentoo Systemd ZM V1.28.0- New old bug with PATH\_SOCK and PATH\_SWAP [\#681](https://github.com/ZoneMinder/ZoneMinder/issues/681) -- PDO\_MYSQL the only PHP driver needed? [\#679](https://github.com/ZoneMinder/ZoneMinder/issues/679) -- Unable to probe local cameras, status is '127' [\#673](https://github.com/ZoneMinder/ZoneMinder/issues/673) -- zmc won't start automatically + Can't open memory map file [\#669](https://github.com/ZoneMinder/ZoneMinder/issues/669) -- Fake camera support [\#659](https://github.com/ZoneMinder/ZoneMinder/issues/659) -- Horrible error message when pressing probe [\#658](https://github.com/ZoneMinder/ZoneMinder/issues/658) -- socket\_sendto\( /var/run/zm/zms-256303s.sock \) failed: No such file or directory [\#656](https://github.com/ZoneMinder/ZoneMinder/issues/656) -- update feature should be removed or easily disabled [\#655](https://github.com/ZoneMinder/ZoneMinder/issues/655) -- zmfilter.pl crashes when processing background filter with no terms [\#652](https://github.com/ZoneMinder/ZoneMinder/issues/652) -- Use of undefined constants ZM\_SKIN\_DEFAULT and ZM\_CSS\_DEFAULT in index.php [\#650](https://github.com/ZoneMinder/ZoneMinder/issues/650) -- Improper track URL handling in zm\_rtsp.cpp [\#644](https://github.com/ZoneMinder/ZoneMinder/issues/644) -- Cannot install on jessie when running systemd [\#642](https://github.com/ZoneMinder/ZoneMinder/issues/642) -- Version detection [\#626](https://github.com/ZoneMinder/ZoneMinder/issues/626) -- some trash in debian package [\#625](https://github.com/ZoneMinder/ZoneMinder/issues/625) -- signed integers awesome [\#624](https://github.com/ZoneMinder/ZoneMinder/issues/624) -- cmake does not honor SYSCONFDIR [\#623](https://github.com/ZoneMinder/ZoneMinder/issues/623) -- PTZ Control Icons have disappeared [\#622](https://github.com/ZoneMinder/ZoneMinder/issues/622) -- RTSP Improvements [\#612](https://github.com/ZoneMinder/ZoneMinder/issues/612) -- CCTV Camera to IP converter [\#603](https://github.com/ZoneMinder/ZoneMinder/issues/603) -- mjpg streamer installations on fedora 20 [\#600](https://github.com/ZoneMinder/ZoneMinder/issues/600) -- Changing the skin in the options SHOULD be permanent. [\#598](https://github.com/ZoneMinder/ZoneMinder/issues/598) -- Zoneminder requires SElinux disabled on RHEL & derivatives. [\#593](https://github.com/ZoneMinder/ZoneMinder/issues/593) -- Editing control settings on a monitor should probably try to kill any running zmcontrol [\#590](https://github.com/ZoneMinder/ZoneMinder/issues/590) -- 1.28 missing dependency on debian jessie [\#581](https://github.com/ZoneMinder/ZoneMinder/issues/581) -- LibVLC MJPEG stream slows down [\#571](https://github.com/ZoneMinder/ZoneMinder/issues/571) -- %EV% in EMAIL\_BODY in E-mail options send still video [\#569](https://github.com/ZoneMinder/ZoneMinder/issues/569) -- Add documentation for EMAIL\_BODY variables [\#568](https://github.com/ZoneMinder/ZoneMinder/issues/568) -- 3S PTZ [\#566](https://github.com/ZoneMinder/ZoneMinder/issues/566) -- Live view wrong socket name [\#563](https://github.com/ZoneMinder/ZoneMinder/issues/563) -- V4L1 Support removal? [\#558](https://github.com/ZoneMinder/ZoneMinder/issues/558) -- feature-h264-videostorage compile errors [\#553](https://github.com/ZoneMinder/ZoneMinder/issues/553) -- zmc -m 1 crashed, signal 6 [\#540](https://github.com/ZoneMinder/ZoneMinder/issues/540) -- Attempt to assign buffer from a NULL pointer [\#538](https://github.com/ZoneMinder/ZoneMinder/issues/538) -- Please recommend ffmpeg settings for best video quality [\#536](https://github.com/ZoneMinder/ZoneMinder/issues/536) -- Modect Mode\(Active\) - How to revert from alarm to idle [\#509](https://github.com/ZoneMinder/ZoneMinder/issues/509) -- Update v1.27.99.0. [\#503](https://github.com/ZoneMinder/ZoneMinder/issues/503) -- Docker Container Broken [\#498](https://github.com/ZoneMinder/ZoneMinder/issues/498) -- Nordmark IP camera [\#483](https://github.com/ZoneMinder/ZoneMinder/issues/483) -- Release v1.28.0 [\#467](https://github.com/ZoneMinder/ZoneMinder/issues/467) -- Let's make a new website [\#446](https://github.com/ZoneMinder/ZoneMinder/issues/446) -- Zoneminder, Onvif CPU and RTSP capture [\#431](https://github.com/ZoneMinder/ZoneMinder/issues/431) -- Right memory settings to capture 1080p cameras [\#425](https://github.com/ZoneMinder/ZoneMinder/issues/425) -- Startup problem on Ubuntu [\#424](https://github.com/ZoneMinder/ZoneMinder/issues/424) -- Feature Request: Support for digest authentication over RTSP [\#399](https://github.com/ZoneMinder/ZoneMinder/issues/399) -- Install Zm V1.27.0 on Linux Gentoo x64 \(systemd\) [\#396](https://github.com/ZoneMinder/ZoneMinder/issues/396) -- Missing Dependencies [\#368](https://github.com/ZoneMinder/ZoneMinder/issues/368) -- Error "‘AVOutputFormat’ does not name a type AVOutputFormat \*of;" [\#340](https://github.com/ZoneMinder/ZoneMinder/issues/340) -- Add the ability to force RTSP over TCP in ffmpeg cameras. [\#323](https://github.com/ZoneMinder/ZoneMinder/issues/323) -- limited maximum path length for the device path prevents use of some by-id names [\#301](https://github.com/ZoneMinder/ZoneMinder/issues/301) -- Stream acquired via RTSP/FFMPEG won't recover from connection loss - "Unable to read packet from stream 0" [\#299](https://github.com/ZoneMinder/ZoneMinder/issues/299) -- Invalid response status 501: Method Not Implemented [\#298](https://github.com/ZoneMinder/ZoneMinder/issues/298) -- Invalid SOS parameters for sequential JPEG [\#279](https://github.com/ZoneMinder/ZoneMinder/issues/279) - **Merged pull requests:** - fix content-type parsing when there are options on it [\#692](https://github.com/ZoneMinder/ZoneMinder/pull/692) ([connortechnology](https://github.com/connortechnology)) @@ -315,11 +266,8 @@ - Output to stderror when zmu can't read zm.conf [\#627](https://github.com/ZoneMinder/ZoneMinder/pull/627) ([knnniggett](https://github.com/knnniggett)) - Add missing dependency to policykit-1 [\#621](https://github.com/ZoneMinder/ZoneMinder/pull/621) ([manupap1](https://github.com/manupap1)) - Replace PHP Short Open Tags - Fixes \#11 [\#620](https://github.com/ZoneMinder/ZoneMinder/pull/620) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- Video Highlander [\#618](https://github.com/ZoneMinder/ZoneMinder/pull/618) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- Merge Master to feature-h264-videostorage [\#616](https://github.com/ZoneMinder/ZoneMinder/pull/616) ([SteveGilvarry](https://github.com/SteveGilvarry)) - Rtsp [\#615](https://github.com/ZoneMinder/ZoneMinder/pull/615) ([knnniggett](https://github.com/knnniggett)) - Merge flat css to classic [\#614](https://github.com/ZoneMinder/ZoneMinder/pull/614) ([connortechnology](https://github.com/connortechnology)) -- feature-h264-videostorage mp4 container [\#613](https://github.com/ZoneMinder/ZoneMinder/pull/613) ([SteveGilvarry](https://github.com/SteveGilvarry)) - echo the URL to the RTSP device during the OPTIONS directive [\#608](https://github.com/ZoneMinder/ZoneMinder/pull/608) ([knnniggett](https://github.com/knnniggett)) - Fix some memory leaks in zma [\#607](https://github.com/ZoneMinder/ZoneMinder/pull/607) ([manupap1](https://github.com/manupap1)) - Fix a mismatched free in zmc binary [\#606](https://github.com/ZoneMinder/ZoneMinder/pull/606) ([manupap1](https://github.com/manupap1)) @@ -346,91 +294,16 @@ - Fixed bug in rtsp streaming caused by a bad string concatenation [\#557](https://github.com/ZoneMinder/ZoneMinder/pull/557) ([manupap1](https://github.com/manupap1)) - Add a stringVector join function for future use [\#556](https://github.com/ZoneMinder/ZoneMinder/pull/556) ([connortechnology](https://github.com/connortechnology)) - Fixed bug in rtsp streaming caused by a signed - unsigned conversion. [\#555](https://github.com/ZoneMinder/ZoneMinder/pull/555) ([manupap1](https://github.com/manupap1)) -- Keeping branch current, and fixing libvlc compile issues [\#554](https://github.com/ZoneMinder/ZoneMinder/pull/554) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- Bumped version being found by zmupdate.pl [\#551](https://github.com/ZoneMinder/ZoneMinder/pull/551) ([SteveGilvarry](https://github.com/SteveGilvarry)) - Update Ubuntu install instructions [\#550](https://github.com/ZoneMinder/ZoneMinder/pull/550) ([SteveGilvarry](https://github.com/SteveGilvarry)) - Ignore more files and initial travis framework [\#544](https://github.com/ZoneMinder/ZoneMinder/pull/544) ([kylejohnson](https://github.com/kylejohnson)) - Update Travis to ffmpeg 2.4.2 [\#539](https://github.com/ZoneMinder/ZoneMinder/pull/539) ([SteveGilvarry](https://github.com/SteveGilvarry)) - Add libvlc to Travis [\#535](https://github.com/ZoneMinder/ZoneMinder/pull/535) ([knnniggett](https://github.com/knnniggett)) -- Merge master to feature-h264-videostorage and restore web GUI [\#532](https://github.com/ZoneMinder/ZoneMinder/pull/532) ([SteveGilvarry](https://github.com/SteveGilvarry)) - 351-Rebase Attempt for ffmpeg stability fixes [\#531](https://github.com/ZoneMinder/ZoneMinder/pull/531) ([SteveGilvarry](https://github.com/SteveGilvarry)) +- 478 Basic ONVIF Support [\#479](https://github.com/ZoneMinder/ZoneMinder/pull/479) ([altaroca](https://github.com/altaroca)) ## [v1.28.0](https://github.com/ZoneMinder/ZoneMinder/tree/v1.28.0) (2014-10-18) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.27.0...v1.28.0) -**Implemented enhancements:** - -- Migrate completely to C++ [\#265](https://github.com/ZoneMinder/ZoneMinder/issues/265) -- All of the Config table shouldn't be written in Configure::write [\#192](https://github.com/ZoneMinder/ZoneMinder/issues/192) -- Translation stuff done, please pull in and test... [\#72](https://github.com/ZoneMinder/ZoneMinder/issues/72) - -**Fixed bugs:** - -- zms crashes due to monitor not running. [\#468](https://github.com/ZoneMinder/ZoneMinder/issues/468) -- Flat Skins Export Functions missing $ [\#455](https://github.com/ZoneMinder/ZoneMinder/issues/455) -- unexpected } in console.php [\#354](https://github.com/ZoneMinder/ZoneMinder/issues/354) -- incomplete path to arp in zoneminder/skins/classic/views/monitorprobe.php causes probe code 127 failures [\#271](https://github.com/ZoneMinder/ZoneMinder/issues/271) -- Minor errors when either OPT\_MAIL, OPT\_MESSAGE, or OPT\_UPLOAD are not set [\#34](https://github.com/ZoneMinder/ZoneMinder/issues/34) - -**Closed issues:** - -- Travis Build failing due to build issues with ffmpeg master [\#520](https://github.com/ZoneMinder/ZoneMinder/issues/520) -- 'zmfilter.pl' exited abnormally, exit status 9 [\#516](https://github.com/ZoneMinder/ZoneMinder/issues/516) -- Get the script on alarm feature working [\#515](https://github.com/ZoneMinder/ZoneMinder/issues/515) -- cmake installation on Arch Linux creates extraneous lib/perl5/... and share/man/... directories [\#514](https://github.com/ZoneMinder/ZoneMinder/issues/514) -- ZM Gui Stopped SU Syntax Error [\#512](https://github.com/ZoneMinder/ZoneMinder/issues/512) -- Error using log filter [\#504](https://github.com/ZoneMinder/ZoneMinder/issues/504) -- fps drop in latest snapshot 1.27.99 [\#495](https://github.com/ZoneMinder/ZoneMinder/issues/495) -- mysql missing field error after update [\#494](https://github.com/ZoneMinder/ZoneMinder/issues/494) -- Emails not including video when I add %EV% [\#487](https://github.com/ZoneMinder/ZoneMinder/issues/487) -- Cameras don't show remotely [\#484](https://github.com/ZoneMinder/ZoneMinder/issues/484) -- ZM Gui Stopped SU Syntax Error [\#482](https://github.com/ZoneMinder/ZoneMinder/issues/482) -- Airlink101 AIC500 mjpeg stream [\#481](https://github.com/ZoneMinder/ZoneMinder/issues/481) -- When a monitor's size is changed, the zone does not resize with it. [\#477](https://github.com/ZoneMinder/ZoneMinder/issues/477) -- .. [\#472](https://github.com/ZoneMinder/ZoneMinder/issues/472) -- Just A Note When Compiling [\#471](https://github.com/ZoneMinder/ZoneMinder/issues/471) -- firefox on windows not load all monitors in montage view [\#470](https://github.com/ZoneMinder/ZoneMinder/issues/470) -- Default to FLAT Skin [\#466](https://github.com/ZoneMinder/ZoneMinder/issues/466) -- zmlinkcontent.sh chown and chmod on symlink instead of content directory [\#463](https://github.com/ZoneMinder/ZoneMinder/issues/463) -- Cannot compile Zoneminder on CentOS 6.4 [\#461](https://github.com/ZoneMinder/ZoneMinder/issues/461) -- Video is not attached to e-mail anymore \(zm 1.27\) [\#460](https://github.com/ZoneMinder/ZoneMinder/issues/460) -- \[Video Branch\] Unknown column 'SaveJPEGs' in 'field list' [\#453](https://github.com/ZoneMinder/ZoneMinder/issues/453) -- Log Ajax loading oldest to newest [\#450](https://github.com/ZoneMinder/ZoneMinder/issues/450) -- '@' in password of a remote camera makes things go wrong [\#443](https://github.com/ZoneMinder/ZoneMinder/issues/443) -- Current code segfaults [\#439](https://github.com/ZoneMinder/ZoneMinder/issues/439) -- Crashing under Arch Linux [\#437](https://github.com/ZoneMinder/ZoneMinder/issues/437) -- Email Montage view on schedule [\#436](https://github.com/ZoneMinder/ZoneMinder/issues/436) -- \[question\] vmware image for latest ZM [\#428](https://github.com/ZoneMinder/ZoneMinder/issues/428) -- Cannot Compile [\#423](https://github.com/ZoneMinder/ZoneMinder/issues/423) -- seg in nph-zms/loadEventData atoi [\#417](https://github.com/ZoneMinder/ZoneMinder/issues/417) -- ffmpeg problem [\#414](https://github.com/ZoneMinder/ZoneMinder/issues/414) -- Minor fixes \(?\) for zmtrigger and mobile skin [\#410](https://github.com/ZoneMinder/ZoneMinder/issues/410) -- Misleading Config Dump [\#402](https://github.com/ZoneMinder/ZoneMinder/issues/402) -- Call to undefined function fixdevices\(\) [\#401](https://github.com/ZoneMinder/ZoneMinder/issues/401) -- Option to execute arbitrary script for each event. \[$100 awarded\] [\#400](https://github.com/ZoneMinder/ZoneMinder/issues/400) -- Zoneminder without Analysation [\#398](https://github.com/ZoneMinder/ZoneMinder/issues/398) -- Viewing 31 monitors in montage [\#379](https://github.com/ZoneMinder/ZoneMinder/issues/379) -- flat theme usability / Layout issues [\#378](https://github.com/ZoneMinder/ZoneMinder/issues/378) -- Undefined index: filter in /usr/share/zoneminder/skins/zmc/views/filter.php [\#369](https://github.com/ZoneMinder/ZoneMinder/issues/369) -- docker install not working [\#366](https://github.com/ZoneMinder/ZoneMinder/issues/366) -- Events are not being reported to table on main index page [\#364](https://github.com/ZoneMinder/ZoneMinder/issues/364) -- PatternFly for design commanality and improved user experience [\#363](https://github.com/ZoneMinder/ZoneMinder/issues/363) -- Radio buttons rendering in events replay in flat skin [\#356](https://github.com/ZoneMinder/ZoneMinder/issues/356) -- Pick a git branching strategy [\#350](https://github.com/ZoneMinder/ZoneMinder/issues/350) -- Compile directive ZM\_CGIDIR is not interpreted correctly [\#347](https://github.com/ZoneMinder/ZoneMinder/issues/347) -- 736516 - FTBFS: zm\_image.cpp:2991:165: error: \_\_attribute\_\_\(\(\_\_target\_\_\("sse2"\)\)\) is invalid [\#345](https://github.com/ZoneMinder/ZoneMinder/issues/345) -- zmcamtool isn't installed [\#344](https://github.com/ZoneMinder/ZoneMinder/issues/344) -- Overload Frame Ignore Count has no function [\#337](https://github.com/ZoneMinder/ZoneMinder/issues/337) -- preclusive zones calculated twice [\#336](https://github.com/ZoneMinder/ZoneMinder/issues/336) -- Build issue - In function `matroska\_decode\_buffer' [\#335](https://github.com/ZoneMinder/ZoneMinder/issues/335) -- High Load with Low CPU usage [\#326](https://github.com/ZoneMinder/ZoneMinder/issues/326) -- AUTH\_TYPE=remote not working in 1.26.4 [\#324](https://github.com/ZoneMinder/ZoneMinder/issues/324) -- Filter / Purge And Delete not running [\#321](https://github.com/ZoneMinder/ZoneMinder/issues/321) -- /root/zoneminder\_1.26.4-1\_amd64.deb not created [\#260](https://github.com/ZoneMinder/ZoneMinder/issues/260) -- 721161 - depends on ffmpeg which is going away [\#100](https://github.com/ZoneMinder/ZoneMinder/issues/100) -- 694131 - FTBFS against libav 9 [\#98](https://github.com/ZoneMinder/ZoneMinder/issues/98) -- Request: Better API/Remote control [\#23](https://github.com/ZoneMinder/ZoneMinder/issues/23) - **Merged pull requests:** - fixes ftbs with no ffmpeg support [\#530](https://github.com/ZoneMinder/ZoneMinder/pull/530) ([knnniggett](https://github.com/knnniggett)) @@ -450,7 +323,6 @@ - Fixes errors when opening Filters \(issue \#34\) [\#457](https://github.com/ZoneMinder/ZoneMinder/pull/457) ([knnniggett](https://github.com/knnniggett)) - Fixed missing $ on ARRAY\(event\[id\]\). Fixes \#455 [\#456](https://github.com/ZoneMinder/ZoneMinder/pull/456) ([SteveGilvarry](https://github.com/SteveGilvarry)) - Wrap sort order. Fixes \#450 [\#451](https://github.com/ZoneMinder/ZoneMinder/pull/451) ([SteveGilvarry](https://github.com/SteveGilvarry)) -- Update downloads.html [\#448](https://github.com/ZoneMinder/ZoneMinder/pull/448) ([barjac](https://github.com/barjac)) - scripts: BusyBox compatibility [\#445](https://github.com/ZoneMinder/ZoneMinder/pull/445) ([clandmeter](https://github.com/clandmeter)) - Fixed issue DateTime handling in filter queries that broke timeline view... [\#442](https://github.com/ZoneMinder/ZoneMinder/pull/442) ([Tim-Craig](https://github.com/Tim-Craig)) - Cleaning up the Contribution section of the README [\#440](https://github.com/ZoneMinder/ZoneMinder/pull/440) ([kylejohnson](https://github.com/kylejohnson)) @@ -502,49 +374,8 @@ ## [v1.27.0](https://github.com/ZoneMinder/ZoneMinder/tree/v1.27.0) (2014-03-15) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26.5...v1.27.0) -**Implemented enhancements:** - -- Change help text of source "Maximum FPS" and "Alarm Maximum FPS" to note that this should only be used on analog cameras [\#273](https://github.com/ZoneMinder/ZoneMinder/issues/273) -- Make zmpkg.pl 'better' [\#272](https://github.com/ZoneMinder/ZoneMinder/issues/272) -- Enhance security by creating SELinux policies. [\#248](https://github.com/ZoneMinder/ZoneMinder/issues/248) -- Update wiki page \(please?\) [\#91](https://github.com/ZoneMinder/ZoneMinder/issues/91) -- Better ffmpeg Version Checking [\#31](https://github.com/ZoneMinder/ZoneMinder/issues/31) -- Proposed: Enable purgewhenfull filter by default [\#332](https://github.com/ZoneMinder/ZoneMinder/issues/332) -- Exportable Camera Configs [\#86](https://github.com/ZoneMinder/ZoneMinder/issues/86) - -**Fixed bugs:** - -- Vivotek cameras, ultra slow FPS. [\#204](https://github.com/ZoneMinder/ZoneMinder/issues/204) -- Script to remove auto-generated files [\#112](https://github.com/ZoneMinder/ZoneMinder/issues/112) -- zm\_mpeg no longer uses correct ffmpeg API's [\#83](https://github.com/ZoneMinder/ZoneMinder/issues/83) -- Not all options in Monitors/add.ctp are saved to the database [\#13](https://github.com/ZoneMinder/ZoneMinder/issues/13) -- Flat skin needs window widths fixed [\#331](https://github.com/ZoneMinder/ZoneMinder/issues/331) -- Configuration gets broken in database after crash [\#239](https://github.com/ZoneMinder/ZoneMinder/issues/239) -- zmc crashes after a few minutes of usage in 1.26.4 [\#237](https://github.com/ZoneMinder/ZoneMinder/issues/237) - -**Closed issues:** - -- Apache using private /tmp space [\#307](https://github.com/ZoneMinder/ZoneMinder/issues/307) -- zmtrigger.pl crashes, which keeps Monitors in alarm state. [\#295](https://github.com/ZoneMinder/ZoneMinder/issues/295) -- SQL-ERR using Timeline after executing Filter matching on string with whitespace [\#291](https://github.com/ZoneMinder/ZoneMinder/issues/291) -- zm\_signal.cpp crashing signal 11 \(Segmentation fault\) [\#288](https://github.com/ZoneMinder/ZoneMinder/issues/288) -- Zoneminder no longer builds when using -DZM\_NO\_FFMPEG=ON [\#285](https://github.com/ZoneMinder/ZoneMinder/issues/285) -- Can't to use chinese [\#278](https://github.com/ZoneMinder/ZoneMinder/issues/278) -- jquery is embedded inside export\_functions.php [\#274](https://github.com/ZoneMinder/ZoneMinder/issues/274) -- Implement live streaming of H264 camera streams [\#176](https://github.com/ZoneMinder/ZoneMinder/issues/176) -- Support non-embedded password challenge [\#33](https://github.com/ZoneMinder/ZoneMinder/issues/33) -- libvlc source type not working in Ubuntu 12.04.3 [\#330](https://github.com/ZoneMinder/ZoneMinder/issues/330) -- zmupdate.pl InnoDB conversion silent failure [\#320](https://github.com/ZoneMinder/ZoneMinder/issues/320) -- Release v1.27.0 \[$100 awarded\] [\#315](https://github.com/ZoneMinder/ZoneMinder/issues/315) -- Default skin is flat, can't switch to classic. ?skin doesn't help [\#313](https://github.com/ZoneMinder/ZoneMinder/issues/313) -- make failure [\#304](https://github.com/ZoneMinder/ZoneMinder/issues/304) -- Fix 'remote' AUTH\_TYPE [\#296](https://github.com/ZoneMinder/ZoneMinder/issues/296) -- Use libcurl for http\(s\) authentication with remote cameras \[$400 awarded\] [\#238](https://github.com/ZoneMinder/ZoneMinder/issues/238) - **Merged pull requests:** -- Release 1.27 [\#341](https://github.com/ZoneMinder/ZoneMinder/pull/341) ([kylejohnson](https://github.com/kylejohnson)) -- Fix popup sizes in flat skins. Fixes \#331 [\#334](https://github.com/ZoneMinder/ZoneMinder/pull/334) ([kylejohnson](https://github.com/kylejohnson)) - zmcamtool.pl - import and export ptz camera controls & camera presets [\#318](https://github.com/ZoneMinder/ZoneMinder/pull/318) ([kylejohnson](https://github.com/kylejohnson)) - Example script to react to monitor alarms [\#317](https://github.com/ZoneMinder/ZoneMinder/pull/317) ([kylejohnson](https://github.com/kylejohnson)) - Change comments for many Camera subclasses [\#316](https://github.com/ZoneMinder/ZoneMinder/pull/316) ([nereocystis](https://github.com/nereocystis)) @@ -572,34 +403,12 @@ ## [v1.26.5](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26.5) (2013-12-16) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26.4...v1.26.5) -**Implemented enhancements:** - -- ZoneMinder domain / website / email [\#225](https://github.com/ZoneMinder/ZoneMinder/issues/225) - -**Fixed bugs:** - -- Post shmget problem due to \*code\* not shmmax/shmall [\#226](https://github.com/ZoneMinder/ZoneMinder/issues/226) -- SQL error when "pre event image count" \>150 or so due to insufficient ZM\_SQL\_LGE\_BUFSIZ [\#222](https://github.com/ZoneMinder/ZoneMinder/issues/222) -- 'asm' operand has impossible constraints [\#219](https://github.com/ZoneMinder/ZoneMinder/issues/219) -- ipv6 support [\#210](https://github.com/ZoneMinder/ZoneMinder/issues/210) -- RTSP decoding errors in 1.26.4 \[$450 awarded\] [\#221](https://github.com/ZoneMinder/ZoneMinder/issues/221) -- The Prev "\<+" button does not work [\#32](https://github.com/ZoneMinder/ZoneMinder/issues/32) - -**Closed issues:** - -- Strict subs error? [\#262](https://github.com/ZoneMinder/ZoneMinder/issues/262) -- PHP depreciating [\#229](https://github.com/ZoneMinder/ZoneMinder/issues/229) -- Add a feature to monitor camera\(s\) availability [\#228](https://github.com/ZoneMinder/ZoneMinder/issues/228) -- Release 1.26.4 [\#202](https://github.com/ZoneMinder/ZoneMinder/issues/202) -- 631969 - 2 problems with options screen [\#106](https://github.com/ZoneMinder/ZoneMinder/issues/106) -- 657620 - Path issues for js scripts [\#102](https://github.com/ZoneMinder/ZoneMinder/issues/102) -- Support http digest authentication for IP camera access [\#30](https://github.com/ZoneMinder/ZoneMinder/issues/30) - **Merged pull requests:** - Add reference to zm\_update-1.26.5.sql in Makefile.am [\#269](https://github.com/ZoneMinder/ZoneMinder/pull/269) ([knnniggett](https://github.com/knnniggett)) - Detection Support for WansView Cams [\#268](https://github.com/ZoneMinder/ZoneMinder/pull/268) ([Phhere](https://github.com/Phhere)) - use proper DBI parameter passing to improve security [\#264](https://github.com/ZoneMinder/ZoneMinder/pull/264) ([connortechnology](https://github.com/connortechnology)) +- Fix RTSP decoding errors in 1.26.4 \(addresses \#221\) [\#259](https://github.com/ZoneMinder/ZoneMinder/pull/259) ([ebarnard](https://github.com/ebarnard)) - Network Detection Support for Wansview [\#257](https://github.com/ZoneMinder/ZoneMinder/pull/257) ([Phhere](https://github.com/Phhere)) - Fix checkJsonError messages [\#256](https://github.com/ZoneMinder/ZoneMinder/pull/256) ([Phhere](https://github.com/Phhere)) - Update README.md [\#255](https://github.com/ZoneMinder/ZoneMinder/pull/255) ([zdanek](https://github.com/zdanek)) @@ -608,16 +417,9 @@ - Fix shared memory errors on centos 6.4 [\#250](https://github.com/ZoneMinder/ZoneMinder/pull/250) ([insidenothing](https://github.com/insidenothing)) - Update zoneminder.service [\#246](https://github.com/ZoneMinder/ZoneMinder/pull/246) ([dtmf](https://github.com/dtmf)) - remove extra stuff that I don't think we need because we are the source. Opinions? [\#240](https://github.com/ZoneMinder/ZoneMinder/pull/240) ([connortechnology](https://github.com/connortechnology)) -- Re-Add ZM\_PATH\_DATA [\#236](https://github.com/ZoneMinder/ZoneMinder/pull/236) ([knnniggett](https://github.com/knnniggett)) - Cast content\_length to signed int for error-check comparison [\#232](https://github.com/ZoneMinder/ZoneMinder/pull/232) ([josephevans](https://github.com/josephevans)) - Apply INSERTs in Event::AddFrames in batches to fix issue \#222 [\#223](https://github.com/ZoneMinder/ZoneMinder/pull/223) ([fastolfe](https://github.com/fastolfe)) -- Updates to the zones view and edit pages [\#220](https://github.com/ZoneMinder/ZoneMinder/pull/220) ([kylejohnson](https://github.com/kylejohnson)) - ffmpeg detection improvements [\#218](https://github.com/ZoneMinder/ZoneMinder/pull/218) ([mastertheknife](https://github.com/mastertheknife)) -- cmake support files for redhat/centos distros [\#217](https://github.com/ZoneMinder/ZoneMinder/pull/217) ([knnniggett](https://github.com/knnniggett)) -- Create ZM\_TARGET\_DISTRO [\#216](https://github.com/ZoneMinder/ZoneMinder/pull/216) ([knnniggett](https://github.com/knnniggett)) -- We need a toggle for x10 support [\#215](https://github.com/ZoneMinder/ZoneMinder/pull/215) ([knnniggett](https://github.com/knnniggett)) -- Cmake support files for fedora distro [\#214](https://github.com/ZoneMinder/ZoneMinder/pull/214) ([knnniggett](https://github.com/knnniggett)) -- Initial zone editing in html5 canvas [\#213](https://github.com/ZoneMinder/ZoneMinder/pull/213) ([kylejohnson](https://github.com/kylejohnson)) - ZoneMinder Dutch Translation updates by Alco \(a.k. nightcrawler\) [\#211](https://github.com/ZoneMinder/ZoneMinder/pull/211) ([kylejohnson](https://github.com/kylejohnson)) - Change Prev Button functionality [\#207](https://github.com/ZoneMinder/ZoneMinder/pull/207) ([knnniggett](https://github.com/knnniggett)) - Delete PATH\_BUILD and TIME\_BUILD from zm.conf and fix ZM\_DB\_TYPE [\#243](https://github.com/ZoneMinder/ZoneMinder/pull/243) ([mastertheknife](https://github.com/mastertheknife)) @@ -628,42 +430,6 @@ ## [v1.26.4](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26.4) (2013-10-08) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26.3...v1.26.4) -**Implemented enhancements:** - -- Configuration options should be handled in the model, not the controller [\#191](https://github.com/ZoneMinder/ZoneMinder/issues/191) -- Travis CI automatic building [\#168](https://github.com/ZoneMinder/ZoneMinder/issues/168) -- Switch h264 feature branch to track the modern branch [\#167](https://github.com/ZoneMinder/ZoneMinder/issues/167) -- Add redhat specific files to source tree [\#115](https://github.com/ZoneMinder/ZoneMinder/issues/115) -- Performing count\(\) in SQL is slower than in PHP [\#2](https://github.com/ZoneMinder/ZoneMinder/issues/2) - -**Fixed bugs:** - -- New WebUI displays horizontal scroll bar with 100% width [\#169](https://github.com/ZoneMinder/ZoneMinder/issues/169) -- syntax error, unexpected $end on line 16 in LiveStreamHelper.php [\#147](https://github.com/ZoneMinder/ZoneMinder/issues/147) -- Readme.fedora contains incorrect references [\#145](https://github.com/ZoneMinder/ZoneMinder/issues/145) -- Bandwidth cookie issues [\#143](https://github.com/ZoneMinder/ZoneMinder/issues/143) -- Monitor image invalid when monitor not enabled [\#140](https://github.com/ZoneMinder/ZoneMinder/issues/140) -- Monitor image size too small [\#139](https://github.com/ZoneMinder/ZoneMinder/issues/139) - -**Closed issues:** - -- MJPEG without cambozola.jar on modern browsers \(including Linux ones\) [\#198](https://github.com/ZoneMinder/ZoneMinder/issues/198) -- Ability to hide all 'controls' and menus [\#171](https://github.com/ZoneMinder/ZoneMinder/issues/171) -- strace on zma gives "timer\_gettime...\(..\).. = -1 EINVAL \(Invalid argument\)" [\#170](https://github.com/ZoneMinder/ZoneMinder/issues/170) -- Add ability to zms \(or use the segmenter\) to play back h264 video either directly or transcoded [\#166](https://github.com/ZoneMinder/ZoneMinder/issues/166) -- I can delete multiple events at once. [\#137](https://github.com/ZoneMinder/ZoneMinder/issues/137) -- I can view logs [\#135](https://github.com/ZoneMinder/ZoneMinder/issues/135) -- I can update system config / options [\#134](https://github.com/ZoneMinder/ZoneMinder/issues/134) -- I can change the order of monitors [\#132](https://github.com/ZoneMinder/ZoneMinder/issues/132) -- When a new version is available, I am alerted [\#130](https://github.com/ZoneMinder/ZoneMinder/issues/130) -- Bandwidth is updated on the UI after chaning it [\#129](https://github.com/ZoneMinder/ZoneMinder/issues/129) -- I can change the bandwidth [\#128](https://github.com/ZoneMinder/ZoneMinder/issues/128) -- I can delete events [\#126](https://github.com/ZoneMinder/ZoneMinder/issues/126) -- I can view monitor streams individually [\#125](https://github.com/ZoneMinder/ZoneMinder/issues/125) -- 667428 - ftbfs with GCC-4.7 [\#99](https://github.com/ZoneMinder/ZoneMinder/issues/99) -- 707411 - FTBFS: zm\_local\_camera.cpp:742:49: error: invalid conversion from '\_\_u32 {aka unsigned int}' to 'v4l2\_buf\_type' [\#97](https://github.com/ZoneMinder/ZoneMinder/issues/97) -- Change in monitor setup requested. [\#19](https://github.com/ZoneMinder/ZoneMinder/issues/19) - **Merged pull requests:** - Change frameserver warnings to debug level 2 [\#205](https://github.com/ZoneMinder/ZoneMinder/pull/205) ([knnniggett](https://github.com/knnniggett)) @@ -671,26 +437,13 @@ - Signal improvements and fixes [\#201](https://github.com/ZoneMinder/ZoneMinder/pull/201) ([mastertheknife](https://github.com/mastertheknife)) - Create ZM\_PATH\_DATA and point zmupdate to ZM\_PATH\_DATA/db [\#200](https://github.com/ZoneMinder/ZoneMinder/pull/200) ([knnniggett](https://github.com/knnniggett)) - remove ${CMAKE\_CURRENT\_SOURCE\_DIR} from add\_custom\_target [\#199](https://github.com/ZoneMinder/ZoneMinder/pull/199) ([knnniggett](https://github.com/knnniggett)) -- Updated cmake for the modern WebUI branch [\#196](https://github.com/ZoneMinder/ZoneMinder/pull/196) ([mastertheknife](https://github.com/mastertheknife)) - Added missing word in readme [\#194](https://github.com/ZoneMinder/ZoneMinder/pull/194) ([WDKevin](https://github.com/WDKevin)) -- Moved writing of configure options from Controller to Model. Fixes \#191. [\#193](https://github.com/ZoneMinder/ZoneMinder/pull/193) ([kylejohnson](https://github.com/kylejohnson)) -- Moved zmBandwidth option from cookie to Configure:: option. Might fix \#175 [\#190](https://github.com/ZoneMinder/ZoneMinder/pull/190) ([kylejohnson](https://github.com/kylejohnson)) -- Moved the Config tabs to the sidebar [\#185](https://github.com/ZoneMinder/ZoneMinder/pull/185) ([kylejohnson](https://github.com/kylejohnson)) -- Added datetime picker support and implemented on events sidebar [\#179](https://github.com/ZoneMinder/ZoneMinder/pull/179) ([WDKevin](https://github.com/WDKevin)) - Add cmake to ZoneMinder [\#178](https://github.com/ZoneMinder/ZoneMinder/pull/178) ([mastertheknife](https://github.com/mastertheknife)) -- Fixes the fixed-width container bug in bootstrap [\#177](https://github.com/ZoneMinder/ZoneMinder/pull/177) ([WDKevin](https://github.com/WDKevin)) - Rtsp updates [\#174](https://github.com/ZoneMinder/ZoneMinder/pull/174) ([POKKAHOH](https://github.com/POKKAHOH)) -- Minor patches to support older ffmpeg under distro's like Ubuntu 12.04 [\#173](https://github.com/ZoneMinder/ZoneMinder/pull/173) ([chetan-prime](https://github.com/chetan-prime)) - Solution for Issue \#170 [\#172](https://github.com/ZoneMinder/ZoneMinder/pull/172) ([raulcaj](https://github.com/raulcaj)) - Fixing debian build files including automated database setup [\#164](https://github.com/ZoneMinder/ZoneMinder/pull/164) ([jaydio](https://github.com/jaydio)) - Add fedora rpm development files to zoneminder source tree [\#163](https://github.com/ZoneMinder/ZoneMinder/pull/163) ([knnniggett](https://github.com/knnniggett)) - Improve Chrome browser support & log streaming events [\#162](https://github.com/ZoneMinder/ZoneMinder/pull/162) ([knnniggett](https://github.com/knnniggett)) -- Merge master into modern to keep changes up to date [\#161](https://github.com/ZoneMinder/ZoneMinder/pull/161) ([chriswiggins](https://github.com/chriswiggins)) -- Checks for updates every 5 minutes and notifies the user when there is one [\#158](https://github.com/ZoneMinder/ZoneMinder/pull/158) ([WDKevin](https://github.com/WDKevin)) -- Dynamic monitor resizing [\#157](https://github.com/ZoneMinder/ZoneMinder/pull/157) ([chriswiggins](https://github.com/chriswiggins)) -- Delete multiple events at once [\#156](https://github.com/ZoneMinder/ZoneMinder/pull/156) ([WDKevin](https://github.com/WDKevin)) -- Added missing jquery-2.0.1.min.map file [\#155](https://github.com/ZoneMinder/ZoneMinder/pull/155) ([WDKevin](https://github.com/WDKevin)) -- Add support to change order of monitors [\#154](https://github.com/ZoneMinder/ZoneMinder/pull/154) ([WDKevin](https://github.com/WDKevin)) - Can't seem to catch a break tonight. Moving debian files into correct folder [\#149](https://github.com/ZoneMinder/ZoneMinder/pull/149) ([knnniggett](https://github.com/knnniggett)) - Move debian folder under distros [\#148](https://github.com/ZoneMinder/ZoneMinder/pull/148) ([knnniggett](https://github.com/knnniggett)) - Removing the redhat folder from the root for real this time [\#141](https://github.com/ZoneMinder/ZoneMinder/pull/141) ([knnniggett](https://github.com/knnniggett)) @@ -702,11 +455,6 @@ ## [v1.26.3](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26.3) (2013-09-10) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26.2...v1.26.3) -**Fixed bugs:** - -- syntax error near unexpected token `5.6.0' [\#118](https://github.com/ZoneMinder/ZoneMinder/issues/118) -- Must modify zmupdate whenever the zm release number is incremented [\#114](https://github.com/ZoneMinder/ZoneMinder/issues/114) - **Merged pull requests:** - Add 1.26.1 and 1.26.2 releases to zmupdate [\#116](https://github.com/ZoneMinder/ZoneMinder/pull/116) ([knnniggett](https://github.com/knnniggett)) @@ -714,19 +462,6 @@ ## [v1.26.2](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26.2) (2013-09-06) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26.1...v1.26.2) -**Implemented enhancements:** - -- Update zmupdate to look at the github repo for the latest version [\#109](https://github.com/ZoneMinder/ZoneMinder/issues/109) - -**Fixed bugs:** - -- 666980 - hash authentication broken in update [\#105](https://github.com/ZoneMinder/ZoneMinder/issues/105) - -**Closed issues:** - -- 1.26.1 didn't get bumped from 1.26.0 [\#113](https://github.com/ZoneMinder/ZoneMinder/issues/113) -- Migrate FAQ from ZoneMinder Wiki to GitHub Wiki [\#110](https://github.com/ZoneMinder/ZoneMinder/issues/110) - **Merged pull requests:** - Use GitHub repo for version check [\#111](https://github.com/ZoneMinder/ZoneMinder/pull/111) ([chriswiggins](https://github.com/chriswiggins)) @@ -734,85 +469,18 @@ ## [v1.26.1](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26.1) (2013-09-06) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26.0...v1.26.1) -**Fixed bugs:** - -- Make and configure files are not in v1.26.0 [\#107](https://github.com/ZoneMinder/ZoneMinder/issues/107) - ## [v1.26.0](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26.0) (2013-09-05) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26-beta.3...v1.26.0) -**Closed issues:** - -- AM is deprecated in automake-1.13 onwards [\#94](https://github.com/ZoneMinder/ZoneMinder/issues/94) -- CVE-2013-0232 [\#93](https://github.com/ZoneMinder/ZoneMinder/issues/93) -- \[CRITICAL\] zms crashes with hashed authentication [\#88](https://github.com/ZoneMinder/ZoneMinder/issues/88) - -**Merged pull requests:** - -- Fix "Can't stat : No such file or directory" message [\#95](https://github.com/ZoneMinder/ZoneMinder/pull/95) ([knnniggett](https://github.com/knnniggett)) -- Update getBrowser\(\) to match IE10 [\#92](https://github.com/ZoneMinder/ZoneMinder/pull/92) ([knnniggett](https://github.com/knnniggett)) -- Update zmupdate.pl.in to give option to convert to InnoDB tables [\#84](https://github.com/ZoneMinder/ZoneMinder/pull/84) ([knnniggett](https://github.com/knnniggett)) - ## [v1.26-beta.3](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26-beta.3) (2013-08-28) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26-beta.2...v1.26-beta.3) -**Fixed bugs:** - -- libjpeg turbo errors during make [\#52](https://github.com/ZoneMinder/ZoneMinder/issues/52) - -**Closed issues:** - -- configure.ac checking for libavcore incorrectly [\#64](https://github.com/ZoneMinder/ZoneMinder/issues/64) - -**Merged pull requests:** - -- Fix for Issue \#88 - ZMS crashing [\#90](https://github.com/ZoneMinder/ZoneMinder/pull/90) ([knnniggett](https://github.com/knnniggett)) -- Fixed typo [\#89](https://github.com/ZoneMinder/ZoneMinder/pull/89) ([knnniggett](https://github.com/knnniggett)) -- edit zmupdate function in init script [\#87](https://github.com/ZoneMinder/ZoneMinder/pull/87) ([knnniggett](https://github.com/knnniggett)) -- Add PTZ control files and camera presets for specific ptz cameras. [\#85](https://github.com/ZoneMinder/ZoneMinder/pull/85) ([knnniggett](https://github.com/knnniggett)) -- Update Makefile.am [\#81](https://github.com/ZoneMinder/ZoneMinder/pull/81) ([knnniggett](https://github.com/knnniggett)) -- Suppresses erroneous Corrupt Jpeg messages sent from the jpeg library [\#80](https://github.com/ZoneMinder/ZoneMinder/pull/80) ([knnniggett](https://github.com/knnniggett)) -- Added frameserver patch from Zoneminder Wiki [\#79](https://github.com/ZoneMinder/ZoneMinder/pull/79) ([knnniggett](https://github.com/knnniggett)) -- Don't check for gnutls-openssl on systems with older gnutls [\#78](https://github.com/ZoneMinder/ZoneMinder/pull/78) ([knnniggett](https://github.com/knnniggett)) -- Change default dB Engine from MyISAM to InnoDB [\#77](https://github.com/ZoneMinder/ZoneMinder/pull/77) ([knnniggett](https://github.com/knnniggett)) -- Added build notes for CentOS & RHEL [\#76](https://github.com/ZoneMinder/ZoneMinder/pull/76) ([knnniggett](https://github.com/knnniggett)) - ## [v1.26-beta.2](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26-beta.2) (2013-08-15) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.26-beta.1...v1.26-beta.2) -**Implemented enhancements:** - -- Updated Hungarian translation [\#35](https://github.com/ZoneMinder/ZoneMinder/issues/35) - -**Fixed bugs:** - -- 1.26 Beta does not install SkyIPCam7xx.pm Control Script [\#38](https://github.com/ZoneMinder/ZoneMinder/issues/38) - -**Closed issues:** - -- Store video in a \*video\* format [\#40](https://github.com/ZoneMinder/ZoneMinder/issues/40) - -**Merged pull requests:** - -- Update hu\_hu.php [\#37](https://github.com/ZoneMinder/ZoneMinder/pull/37) ([nagyrobi](https://github.com/nagyrobi)) - ## [v1.26-beta.1](https://github.com/ZoneMinder/ZoneMinder/tree/v1.26-beta.1) (2013-08-13) [Full Changelog](https://github.com/ZoneMinder/ZoneMinder/compare/v1.25...v1.26-beta.1) -**Implemented enhancements:** - -- Scripts should only be loaded on the pages they're needed [\#15](https://github.com/ZoneMinder/ZoneMinder/issues/15) - -**Fixed bugs:** - -- Control Types always none using source Ffmpeg [\#16](https://github.com/ZoneMinder/ZoneMinder/issues/16) -- No PTZ control option when adding a new monitor [\#4](https://github.com/ZoneMinder/ZoneMinder/issues/4) -- Monitors/index.ctp Undefined offset error [\#1](https://github.com/ZoneMinder/ZoneMinder/issues/1) - -**Closed issues:** - -- Please Add my code for 0-23Hour 0n/off Zone Operation [\#24](https://github.com/ZoneMinder/ZoneMinder/issues/24) - ## [v1.25](https://github.com/ZoneMinder/ZoneMinder/tree/v1.25) (2013-04-12) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7298f31f3..0a1385a25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # cmake_minimum_required (VERSION 2.6) project (zoneminder) -set(zoneminder_VERSION "1.28.109") +set(zoneminder_VERSION "1.29.0") # make API version a minor of ZM version set(zoneminder_API_VERSION "${zoneminder_VERSION}.1") diff --git a/configure.ac b/configure.ac index c0840355b..fcdacdd6c 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ # For instructions on building with cmake, please see INSTALL # AC_PREREQ(2.59) -AC_INIT(zm,1.28.109,[http://www.zoneminder.com/forums/ - Please check FAQ first],zoneminder,http://www.zoneminder.com/downloads.html) +AC_INIT(zm,1.29.0,[http://www.zoneminder.com/forums/ - Please check FAQ first],zoneminder,http://www.zoneminder.com/downloads.html) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/zm.h) AC_CONFIG_HEADERS(config.h) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 53bfa1fa8..044fec234 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -269,6 +269,7 @@ DROP TABLE IF EXISTS `Logs`; CREATE TABLE `Logs` ( `TimeKey` decimal(16,6) NOT NULL, `Component` varchar(32) NOT NULL, + `ServerId` int(10) unsigned, `Pid` smallint(6) DEFAULT NULL, `Level` tinyint(3) NOT NULL, `Code` char(3) NOT NULL, @@ -412,6 +413,7 @@ INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1'); DROP TABLE IF EXISTS `Servers`; CREATE TABLE `Servers` ( `Id` int(10) unsigned NOT NULL auto_increment, + `Hostname` TEXT, `Name` varchar(64) NOT NULL default '', `State_Id` int(10) unsigned, PRIMARY KEY (`Id`) diff --git a/db/zm_update-1.28.110.sql b/db/zm_update-1.28.110.sql new file mode 100644 index 000000000..a9fe04633 --- /dev/null +++ b/db/zm_update-1.28.110.sql @@ -0,0 +1,21 @@ +-- +-- This updates a 1.28.106 database to 1.28.107 +-- + +-- +-- Update Frame table to have a PrimaryKey of ID, insetad of a Composite Primary Key +-- Used primarially for compatibility with CakePHP +-- +SET @s = (SELECT IF( + (SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'Logs' + AND table_schema = DATABASE() + AND column_name = 'ServerId' + ) > 0, +"SELECT 'Column ServerId already exists in Logs'", +"ALTER TABLE `Logs` ADD COLUMN `ServerId` int(10) unsigned AFTER Component" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/db/zm_update-1.29.0.sql b/db/zm_update-1.29.0.sql new file mode 100644 index 000000000..5d17651a3 --- /dev/null +++ b/db/zm_update-1.29.0.sql @@ -0,0 +1,5 @@ +-- +-- This updates a 1.28.110 database to 1.29.0 +-- +-- No changes required +-- diff --git a/distros/debian_cmake/changelog b/distros/debian_cmake/changelog index 0edaefce7..46f1e2bd9 100644 --- a/distros/debian_cmake/changelog +++ b/distros/debian_cmake/changelog @@ -1,3 +1,21 @@ +zoneminder (1.28.108-nmu2015100101) wheezy; urgency=low + + * + + -- Isaac Connor Thu, 01 Oct 2015 18:20:29 +0000 + +zoneminder (1.28.107-nmu2015092401) wheezy; urgency=low + + * + + -- Isaac Connor Thu, 24 Sep 2015 14:15:46 +0000 + +zoneminder (1.28.1+106-nmu2015091001) wheezy; urgency=low + + * + + -- Isaac Connor Thu, 10 Sep 2015 18:03:43 +0000 + zoneminder (1.28.0-0.1) wheezy; urgency=low * Use CMake instead of Autotools to simplify diff --git a/distros/debian_cmake/install b/distros/debian_cmake/install index 9e8953409..97c5f7a03 100644 --- a/distros/debian_cmake/install +++ b/distros/debian_cmake/install @@ -1,7 +1,8 @@ usr/bin -usr/lib/cgi-bin +usr/lib/zoneminder/cgi-bin usr/share/man usr/share/perl5/ZoneMinder usr/share/perl5/ZoneMinder.pm -usr/share/zoneminder +usr/share/zoneminder/db +usr/share/zoneminder/www etc/zm diff --git a/distros/debian_cmake/links b/distros/debian_cmake/links index 9715ee428..5560a100a 100644 --- a/distros/debian_cmake/links +++ b/distros/debian_cmake/links @@ -1,4 +1,3 @@ var/cache/zoneminder/events usr/share/zoneminder/events var/cache/zoneminder/images usr/share/zoneminder/images var/cache/zoneminder/temp usr/share/zoneminder/temp -usr/lib/cgi-bin usr/share/zoneminder/cgi-bin diff --git a/distros/debian_cmake/rules b/distros/debian_cmake/rules index aa0501ab1..4bdc7cb0c 100755 --- a/distros/debian_cmake/rules +++ b/distros/debian_cmake/rules @@ -17,9 +17,9 @@ override_dh_auto_configure: -DZM_SOCKDIR=/var/run/zm \ -DZM_TMPDIR=/var/tmp/zm \ -DZM_LOGDIR=/var/log/zm \ - -DZM_WEBDIR=/usr/share/zoneminder \ + -DZM_WEBDIR=/usr/share/zoneminder/www \ -DZM_CONTENTDIR=/var/cache/zoneminder \ - -DZM_CGIDIR=/usr/lib/cgi-bin \ + -DZM_CGIDIR=/usr/lib/zoneminder/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ -DCMAKE_INSTALL_SYSCONFDIR=etc/zm diff --git a/distros/fedora/README.Fedora b/distros/fedora/README.Fedora index 85088d868..0f88a9a16 100644 --- a/distros/fedora/README.Fedora +++ b/distros/fedora/README.Fedora @@ -44,12 +44,10 @@ New installs set during the previous step, you will need to create the ZoneMinder database and configure a database account for ZoneMinder to use: - mysql -u root -p < /usr/share/zoneminder/db/zm_create.sql - mysql -u root -p - mysql> grant all - on zm.* to 'zmuser'@localhost identified by 'zmpass'; - mysql> exit; - mysqladmin -u root -p reload + mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql + mysql -uroot -p -e "grant all on zm.* to \ + 'zmuser'@localhost identified by 'zmpass';" + mysqladmin -uroot -p reload The database account credentials, zmuser/zmpass, are arbitrary. Set them to anything that suits your envinroment. @@ -125,9 +123,7 @@ Upgrades have increased. Verify the zmuser database account has been granted all permission to the ZoneMinder database: - mysql -u root -p - mysql> show grants for zmuser@localhost; - mysql> exit; + mysql -uroot -p -e "show grants for zmuser@localhost;" See step 2 of the Installation section to add missing permissions. diff --git a/distros/fedora/zoneminder.f22.spec b/distros/fedora/zoneminder.f22.spec index 8e98f3693..9beef6319 100644 --- a/distros/fedora/zoneminder.f22.spec +++ b/distros/fedora/zoneminder.f22.spec @@ -10,7 +10,7 @@ %define _without_x10 1 Name: zoneminder -Version: 1.28.1 +Version: 1.29.0 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons @@ -65,7 +65,7 @@ too much degradation of performance. %setup -q -n ZoneMinder-%{version} # Change the following default values -./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin/zm/nph-zms +./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin-zm/nph-zms ./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes ./utils/zmeditconfigdata.sh ZM_PATH_SWAP /dev/shm ./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR /var/spool/zoneminder-upload @@ -138,7 +138,7 @@ fi %files %defattr(-,root,root,-) -%doc AUTHORS COPYING README.md distros/fedora/README.Fedora distros/fedora/jscalendar-doc +%doc AUTHORS COPYING README.md distros/fedora/README.Fedora distros/fedora/README.https distros/fedora/jscalendar-doc %config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf %config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf %config(noreplace) /etc/tmpfiles.d/zoneminder.conf diff --git a/distros/fedora/zoneminder.f23.spec b/distros/fedora/zoneminder.f23.spec index 97f0e73ac..14b653117 100644 --- a/distros/fedora/zoneminder.f23.spec +++ b/distros/fedora/zoneminder.f23.spec @@ -38,7 +38,7 @@ BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel BuildRequires: httpd polkit-devel %{!?_without_ffmpeg:BuildRequires: ffmpeg} -Requires: httpd php php-gd php-mysql cambozola polkit net-tools psmisc +Requires: httpd php php-gd php-mysql cambozola polkit net-tools psmisc mod_ssl Requires: libjpeg-turbo vlc-core libcurl Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) Requires: perl(DBD::mysql) perl(Archive::Tar) perl(Archive::Zip) @@ -65,7 +65,7 @@ too much degradation of performance. %setup -q -n ZoneMinder-%{version} # Change the following default values -./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin/zm/nph-zms +./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin-zm/nph-zms ./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes ./utils/zmeditconfigdata.sh ZM_PATH_SWAP /dev/shm ./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR /var/spool/zoneminder-upload @@ -138,7 +138,7 @@ fi %files %defattr(-,root,root,-) -%doc AUTHORS COPYING README.md distros/fedora/README.Fedora distros/fedora/jscalendar-doc +%doc AUTHORS COPYING README.md distros/fedora/README.Fedora distros/fedora/README.https distros/fedora/jscalendar-doc %config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf %config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf %config(noreplace) /etc/tmpfiles.d/zoneminder.conf diff --git a/distros/redhat/README.CentOS b/distros/redhat/README.CentOS index e6e53bbc6..f0e627c90 100644 --- a/distros/redhat/README.CentOS +++ b/distros/redhat/README.CentOS @@ -30,12 +30,9 @@ New installs will need to create the ZoneMinder database and configure a database account for ZoneMinder to use: - mysql -uroot -p - mysql> create database zm; - mysql> grant all - on zm.* to 'zmuser'@localhost identified by 'zmpass'; - mysql> exit; mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql + mysql -uroot -p -e "grant all on zm.* to \ + 'zmuser'@localhost identified by 'zmpass';" mysqladmin -uroot -p reload The database account credentials, zmuser/zmpass, are arbitrary. Set them to @@ -117,9 +114,7 @@ New installs have increased. Verify the zmuser database account has been granted all permission to the ZoneMinder database: - mysql -u root -p - mysql> show grants for zmuser@localhost; - mysql> exit; + mysql -uroot -p -e "show grants for zmuser@localhost;" See step 2 of the Installation section to add missing permissions. diff --git a/distros/redhat/README.Centos7 b/distros/redhat/README.Centos7 index 451f4290b..f4566b01c 100644 --- a/distros/redhat/README.Centos7 +++ b/distros/redhat/README.Centos7 @@ -32,12 +32,10 @@ New installs will need to create the ZoneMinder database and configure a database account for ZoneMinder to use: - mysql -u root -p < /usr/share/zoneminder/db/zm_create.sql - mysql -u root -p - mysql> grant all - on zm.* to 'zmuser'@localhost identified by 'zmpass'; - mysql> exit; - mysqladmin -u root -p reload + mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql + mysql -uroot -p -e "grant all on zm.* to \ + 'zmuser'@localhost identified by 'zmpass';" + mysqladmin -uroot -p reload The database account credentials, zmuser/zmpass, are arbitrary. Set them to anything that suits your envinroment. @@ -112,9 +110,7 @@ Upgrades have increased. Verify the zmuser database account has been granted all permission to the ZoneMinder database: - mysql -u root -p - mysql> show grants for zmuser@localhost; - mysql> exit; + mysql -uroot -p -e "show grants for zmuser@localhost;" See step 2 of the Installation section to add missing permissions. diff --git a/distros/redhat/zoneminder.el6.spec b/distros/redhat/zoneminder.el6.spec index 890d7bece..82406d431 100644 --- a/distros/redhat/zoneminder.el6.spec +++ b/distros/redhat/zoneminder.el6.spec @@ -4,7 +4,7 @@ %define zmgid_final apache Name: zoneminder -Version: 1.28.1 +Version: 1.29.0 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons @@ -130,7 +130,7 @@ rm -rf %{_docdir}/%{name}-%{version} %files %defattr(-,root,root,-) -%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.CentOS distros/redhat/jscalendar-doc +%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.CentOS distros/redhat/README.https distros/redhat/jscalendar-doc %doc distros/redhat/local_zoneminder.te %config %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm.conf %config(noreplace) %attr(644,root,root) %{_sysconfdir}/httpd/conf.d/zoneminder.conf diff --git a/distros/redhat/zoneminder.el7.spec b/distros/redhat/zoneminder.el7.spec index 6ed7510b0..c350553b3 100644 --- a/distros/redhat/zoneminder.el7.spec +++ b/distros/redhat/zoneminder.el7.spec @@ -6,7 +6,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.28.1 +Version: 1.29.0 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons @@ -137,7 +137,7 @@ fi %files %defattr(-,root,root,-) -%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc +%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.Centos7 distros/redhat/README.https distros/redhat/jscalendar-doc %doc distros/redhat/local_zoneminder.te %config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf %config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf diff --git a/distros/ubuntu1204/apache.conf b/distros/ubuntu1204/apache.conf index 965c67f86..262db423f 100644 --- a/distros/ubuntu1204/apache.conf +++ b/distros/ubuntu1204/apache.conf @@ -1,9 +1,21 @@ Alias /zm /usr/share/zoneminder/www - - php_flag register_globals off - Options Indexes FollowSymLinks - - DirectoryIndex index.php - - + + + Options +ExecCGI + AllowOverride All + AddHandler fcgid-script .php + FCGIWrapper /usr/bin/php5-cgi + Order allow,deny + Allow from all + + + + + php_flag register_globals off + Options Indexes FollowSymLinks + + DirectoryIndex index.php + + + diff --git a/distros/ubuntu1504_cmake/control b/distros/ubuntu1504_cmake/control index c2098f179..65e11fac9 100644 --- a/distros/ubuntu1504_cmake/control +++ b/distros/ubuntu1504_cmake/control @@ -104,7 +104,7 @@ Package: zoneminder-doc Section: doc Architecture: all Multi-Arch: foreign -Depends: ${misc:Depends}, ${sphinxdoc:Depends} +Depends: ${misc:Depends}, ${sphinxdoc:Depends}, python-sphinx-rtd-theme | python3-sphinx-rtd-theme Suggests: www-browser Description: ZoneMinder documentation ZoneMinder is intended for use in single or multi-camera video security diff --git a/distros/ubuntu1504_cmake/zoneminder.logrotate b/distros/ubuntu1504_cmake/zoneminder.logrotate index ac7ce0795..18fc6b0a0 100644 --- a/distros/ubuntu1504_cmake/zoneminder.logrotate +++ b/distros/ubuntu1504_cmake/zoneminder.logrotate @@ -1,10 +1,10 @@ -/var/log/zm/*log { +/var/log/zm/*.log { missingok notifempty sharedscripts postrotate /usr/bin/zmpkg.pl logrot >>/dev/null 2>&1 || : endscript - weekly - rotate 3 + daily + rotate 7 } diff --git a/distros/ubuntu1504_cmake/zoneminder.postinst b/distros/ubuntu1504_cmake/zoneminder.postinst index 4d2da7331..82b256e6b 100644 --- a/distros/ubuntu1504_cmake/zoneminder.postinst +++ b/distros/ubuntu1504_cmake/zoneminder.postinst @@ -2,6 +2,8 @@ set -e +. /etc/zm/zm.conf + if [ "$1" = "configure" ]; then chown www-data:root /var/log/zm chown www-data:www-data /var/lib/zm @@ -15,9 +17,13 @@ if [ "$1" = "configure" ]; then # Ensure zoneminder is stopped deb-systemd-invoke stop zoneminder.service || exit $? - echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql - # Run the ZoneMinder update tool - zmupdate.pl --nointeractive + if [ "$ZM_DB_HOST" = "localhost" ]; then + echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + # Run the ZoneMinder update tool + zmupdate.pl --nointeractive + else + echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)" + fi; fi diff --git a/distros/ubuntu1504_cmake/zoneminder.service b/distros/ubuntu1504_cmake/zoneminder.service index d5b326d59..e3575c039 100644 --- a/distros/ubuntu1504_cmake/zoneminder.service +++ b/distros/ubuntu1504_cmake/zoneminder.service @@ -4,7 +4,8 @@ [Unit] Description=ZoneMinder CCTV recording and surveillance system After=network.target mysql.service -Requires=mysql.service +# Remarked out so that it will start ZM on machines that don't have mysql installed +#Requires=mysql.service [Service] #User=www-data diff --git a/docs/conf.py b/docs/conf.py index 109161b24..9bda5df7b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -101,8 +101,8 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -#html_theme = 'default' -html_theme = 'sphinx_rtd_theme' +html_theme = 'default' +#html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/installationguide/images/zm-multiserver.png b/docs/installationguide/images/zm-multiserver.png new file mode 100644 index 000000000..360b612a8 Binary files /dev/null and b/docs/installationguide/images/zm-multiserver.png differ diff --git a/docs/installationguide/images/zm-multiserver.xml b/docs/installationguide/images/zm-multiserver.xml new file mode 100644 index 000000000..c829e1a94 --- /dev/null +++ b/docs/installationguide/images/zm-multiserver.xml @@ -0,0 +1 @@ +7Vvfb+I4F/1rkHYfFpEEQnlsmXZ2pXZUqaPd/fZlZIib+JsQs44pZf76uU6uEydOgELoUgkeELn+fc/JuddO6HnTxetnQZbRAw9o3HMHwWvP+9Rz3SvfhW9l2OSGsTfKDaFgQW5ySsMT+0HROEDrigU0rVSUnMeSLavGOU8SOpcVGxGCr6vVnnlcHXVJQj1iaXiak9i2/sUCGeGyXL+0/05ZGOmRHX+Sl8zI/Hso+CrB8Xqu95x98uIF0X1lC/VuwYeCc+hG/Vq8Tmms/Kh9lHvjrqW0mKSgCU5kRwMHUXgh8QpX+g9P6ANLAirA/rACF//2RMVLdvmFyjUX3+HXV77kMQ83PdePYaibGRT7ofqVd5jKjXZdtniqRnSgeB0xSZ+WZK5K18AVsEVyEWNxKgX/TqfQtwBLAnMB4zOL45op4oL94IkkuiFMUDLA6zpmYQI2yVXPz1AFyeRcFZMzHYQ+U80pkjUzocM+U76gUsA6B1jqISORyB52sC5ZMR5jlchgxFgzmSATw6LnEiD4gRi14OWOLbweSALkW6gF7cYC1qjsBzicoF/nMBBwwXb4ggWBGqYRYQ61n2O+BksE9Sg0MLFR0AguiWRcdeWCA2Fm0AVLQnVdXgHvwKCKVXM9R7ipBgPfn067gdgZDCsYu+MrC+QR3jkmxg7e88dBjJ0YEN+zBO65C7jdgKtRKsAd9xHLHfCimB4Fr2aSARsNINLgJRcy4iFPSHxbWsF7WkGVbwx8aRJcq+BWIgmWO8AXq/6fSrlBGMhKcgVWMcI9z9yt+ml1a8pXIoM6cxzGcElESLHeCAVJLWKr9wWNgQEv1XDa5MmsKayKqFa6wpKzRKZGz4/KYIhyTZUdDMwlKnmPza2dQa31EMO6Hj53A7aqgV2scS/8J+jDjvB/ZfJvZe57Pl7+L7scT/DykQoG01M3ddb4XRnjoYyeIWFGflXia4Sx6g8neOPuQ7ADeKHdYqj+n5DxcjDdX3+xOGNwwJRzkMpp9rG0H0r8qyvnxoOSUJCAAW61IKDNn5iADDoX60SBX3SmM99MsiOyVJNZvEK7ZdRP8tQw7c9WAMEhY9Q0H7Nk72ZpUFhl0zPoyqD1jbYha0GlMfyguxqy4jcHDb8qEOBMO+vTCV7XIWOEzDOo8SS5UBuWCznOkBzDyTuSowjKtnDk+WLAXnTCOI2Vd6HuL183S5Xd/dqUVOYWGNdoaVGsLT9r3oVp6z2Z0fiRpwzBnXEp+QIqxLWCIg+1EtMz5vZyfgJuOTVyTeztZpG9VLabnXALifzfJSswY7OJujbbqOt6o5NnMNrWXQazPyD23tBGyMrwUpi9rNnM+6h2RpJVN1LCaoLY6rad7jB3Vw2M1ba35X12Lj9sUeMdufzOjootoe4o50QXmwJfy8IWWNUZYnGihWac4D4CU5yMkpnusTxwbBKeSTU/9jT1TOFpCmqF8aiUp4nneWBS689Wo+Xd/3eljkuBmN7dnQcf05SHrzJd0ieZW8JePsAl7u0d99Lcp7VTHKXXO4JhQfvd0dBg3aSJdDoEHkM6HWm33YUGDPuBe1Mc/zdlr820afB9K7StZIhIkOm90uyApFERkes4Mp6O+wzUIe2rpyIZkkdhpbPi6oZ5bCfFQ/SviaQ+xznuCHUPPT3bMInuc8cYborwYztwWxjdP2LWRxpO8CzirRGzdcrdR0zd8xsDxGAwnSqpqAeITwTiIkntCGHFA2tTdcywb4hDl13ZUdHpW4opQPc7NHgKXM2U9La+skVrelqkjcdpnb3//3BaN3QgaWtKtTvXuvpIB+8OWqd8gt3B9kf0WrAuWrB/ptq1Bng+hsxCA2wCnyxvdVyk4keWgNGwnjucSgLqIx0sAa1T7l4C7IdDFwk4MwkYTqqvFbyzBOBpzUeWAP/ddjz1kQ7e8bROuXsJsB8CXiTgzCTAr78a+J4SoJ9KNOyIZ3rD+McjVJiSBRXE3nru91Cw6OtCtb2oNl8JJjff5rnTO3mBbTSqbj2KR8AGzTQTO3/crDu+vIB6yncUXa/+jqL99OVkL6DqN5ovL6CeCNyR9Xbx6V5Ahcvy7wR52lH+P8O7/Qk= \ No newline at end of file diff --git a/docs/installationguide/index.rst b/docs/installationguide/index.rst index 58a8f4b21..be0df2c06 100644 --- a/docs/installationguide/index.rst +++ b/docs/installationguide/index.rst @@ -10,3 +10,4 @@ Contents: debian fedora centos + multiserver diff --git a/docs/installationguide/multiserver.rst b/docs/installationguide/multiserver.rst new file mode 100644 index 000000000..e9ebefac2 --- /dev/null +++ b/docs/installationguide/multiserver.rst @@ -0,0 +1,55 @@ +Multi-Server Install +==================== + +It is possible to run multiple ZoneMinder servers and manage them from a single interface. To achieve this each zoneminder server is connected to a single shared database server and shares file storage for event data. + +.. image:: images/zm-multiserver.png + +Topology Design Notes +--------------------- + +1. Device symbols represent separate logical functions, not necessarily separate hardware. For example, the Database Server and a ZoneMinder Server, can reside on the same physical hardware. + +2. Configure each ZoneMinder Server to use the same, remote Database Server (Green). + +3. The Storage Server (Red) represents shared storage, accessible by all ZoneMinder Servers, mounted under each server’s events folder. + +4. Create at least two networks for best performance. Dedicate a Storage LAN for communication with the Storage and Database Servers. Make use of multipath and jumbo frames if possible. Keep all other traffic off the Storage LAN! Dedicate the second LAN, called the Video LAN in the diagram, for all other traffic. + +New installs +------------ + +1. Follow the normal instructions for your distro for installing ZoneMinder onto all the ZoneMinder servers in the normal fashion. Only a single database will be needed either as standalone, or on one of the ZoneMinder Servers. + +2. On each ZoneMinder server, edit zm.conf. Find the ZM_DB_HOST variable and set it to the name or ip address of your Database Server. Find the ZM_SERVER_HOST and enter a name for this ZoneMinder server. Use a name easily recognizable by you. This name is not used by ZoneMinder for dns or any other form of network conectivity. + +3. Copy the file /usr/share/zoneminder/db/zm_create.sql from one of the ZoneMinder Servers to the machine targeted as the Database Server. + +4. Install mysql/mariadb server onto the Database Server. + +5. It is advised to run "mysql_secure_installation" to help secure the server. + +6. Using the password for the root account set during the previous step, create the ZoneMinder database and configure a database account for ZoneMinder to use: + +:: + + mysql -u root -p < zm_create.sql + mysql -uroot -p -e "grant all on zm.* to 'zmuser'@localhost identified by 'zmpass';" + mysqladmin -u root -p reload + +The database account credentials, zmuser/zmpass, are arbitrary. Set them to anything that suits your environment. +Note that these commands are just an example and might not be secure enough for your environment. + +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. + +NOTE: The location of this folder varies by distro. This folder is often found under "/var/lib/zoneminder/events" for RedHat based distros and "/var/cache/zoneminder/events" for Debain based distros. This folder is NOT a Symbolic Link! + +10. Open your browser and point it to the web console on any of the ZoneMinder Servers (they will all be the same). Open Options, click the Servers tab,and populate this screen with all of your ZoneMinder Servers. Each server has a field for its name and its hostname. The name is what you used for ZM_SERVER_HOST in step 2. The hostname is the network name or ip address ZoneMinder should use. + +11. When creating a new Monitor, remember to select the server the camera will be assigned to from the Server drop down box. diff --git a/docs/userguide/definemonitor.rst b/docs/userguide/definemonitor.rst index c2006eed9..d69b44425 100644 --- a/docs/userguide/definemonitor.rst +++ b/docs/userguide/definemonitor.rst @@ -21,6 +21,9 @@ Monitor Tab Name The name for your monitor. This should be made up of alphanumeric characters (a-z,A-Z,0-9) and hyphen (-) and underscore(_) only. Whitespace is not allowed. +Server + Multi-Server implementation allows the ability to define multiple ZoneMinder servers sharing a single database. When servers are configured this setting allows you nominate the server for each monitor. + Source Type This determines whether the camera is a local one attached to a physical video or USB port on your machine, a remote network camera or an image source that is represented by a file (for instance periodically downloaded from a alternate location). Choosing one or the other affects which set of options are shown in the Source tab. diff --git a/docs/userguide/mobile.rst b/docs/userguide/mobile.rst index fe8d6e418..b6feb805d 100644 --- a/docs/userguide/mobile.rst +++ b/docs/userguide/mobile.rst @@ -3,16 +3,17 @@ Mobile Devices Here are some options for using ZoneMinder on Mobile devices: -Using the existing web console -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* You can directly use the ZoneMinder interface by launching a browser and going to the ZoneMinder server just like you do on the Desktop -* ZoneMinder also has a "mobile skin" that offers limited functionality (not all views are present in this skin). You can point your mobile browser to ``http://yourzoneminderip/zm/index.php?skin=mobile`` and bookmark it - Third party mobile clients ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * zmNinja (`source code `__, needs APIs to be installed to work) - * Currently in free beta testing for iOS and Android. Will be in app/play store as soon as ZM 1.29 is launched -* zmView (limited, free) and zmView Pro (more features, paid) - `website `__ + * Available in App Store and Play Store - `website `__ +* zmView (limited, free) and zmView Pro (more features, paid) + * Available in App Store and Play Store, relies on ZM skins `website `__ + +Using the existing web console +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* You can directly use the ZoneMinder interface by launching a browser and going to the ZoneMinder server just like you do on the Desktop +* ZoneMinder also has a "mobile skin" that offers limited functionality (not all views are present in this skin). You can point your mobile browser to ``http://yourzoneminderip/zm/index.php?skin=mobile`` and bookmark it. **Note however that 1.29 is the last release that will support the mobile skin. It's use is deprecated** Discontinued clients ^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/userguide/options/images/Options_Servers.png b/docs/userguide/options/images/Options_Servers.png new file mode 100644 index 000000000..2ca47edba Binary files /dev/null and b/docs/userguide/options/images/Options_Servers.png differ diff --git a/docs/userguide/options/options_servers.rst b/docs/userguide/options/options_servers.rst new file mode 100644 index 000000000..4736c305a --- /dev/null +++ b/docs/userguide/options/options_servers.rst @@ -0,0 +1,12 @@ +Options - Servers +--------------- + +.. image:: images/Options_Servers.png + +Servers tab is used for setting up multiple ZoneMinder servers sharing the same database and using a shared file share for all event data. To add a new server use the Add Server button. All that is required is a Name for the Server and Hostname. + +To delete a server mark that server and click the Delete button. + +Please note that all servers must have a functional web UI as the live view must come from the monitor's host server. + +On each server, you will have to edit /etc/zm/zm.conf and set either ZM_SERVER_NAME= diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index e38d151c0..0c5a82a30 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -102,6 +102,20 @@ BEGIN } $sth->finish(); #$dbh->disconnect(); + + if ( ! exists $Config{ZM_SERVER_ID} ) { + $Config{ZM_SERVER_ID} = undef; + $sth = $dbh->prepare_cached( 'SELECT * FROM Servers WHERE Name=?' ); + if ( $Config{ZM_SERVER_NAME} ) { + $res = $sth->execute( $Config{ZM_SERVER_NAME} ); + my $result = $sth->fetchrow_hashref(); + $Config{ZM_SERVER_ID} = $$result{Id}; + } elsif ( $Config{ZM_SERVER_HOST} ) { + $res = $sth->execute( $Config{ZM_SERVER_HOST} ); + my $result = $sth->fetchrow_hashref(); + $Config{ZM_SERVER_ID} = $$result{Id}; + } + } } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 7fff3d62e..9a065f8cf 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -357,7 +357,23 @@ our @options = type => $types{boolean}, category => "system", }, - # PP - Google reCaptcha settings + { + name => "ZM_OPT_USE_API", + default => "yes", + description => "Enable ZoneMinder APIs", + help => qqq(" + ZoneMinder now features a new API using which 3rd party + applications can interact with ZoneMinder data. It is + STRONGLY recommended that you enable authentication along + with APIs. Note that the APIs return sensitive data like + Monitor access details which are configured as JSON objects. + Which is why we recommend you enabling authentication, especially + if you are exposing your ZM instance on the Internet. + "), + type => $types{boolean}, + category => "system", + }, +# PP - Google reCaptcha settings { name => "ZM_OPT_USE_GOOG_RECAPTCHA", default => "no", @@ -410,6 +426,7 @@ our @options = type => $types {string}, category => "system", }, + { name => "ZM_DIR_EVENTS", diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm index 835f2943b..c9997526d 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm @@ -173,6 +173,7 @@ sub moveConDown Debug( "Move Down" ); my $cmd = "decoder_control.cgi?command=2"; $self->sendCmd( $cmd ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); } #Left Arrow diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Server.pm b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm new file mode 100644 index 000000000..df8f2fb10 --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm @@ -0,0 +1,161 @@ +# ========================================================================== +# +# ZoneMinder Server Module, $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ========================================================================== +# +# This module contains the common definitions and functions used by the rest +# of the ZoneMinder scripts +# +package ZoneMinder::Server; + +use 5.006; +use strict; +use warnings; + +require Exporter; +require ZoneMinder::Base; + +our @ISA = qw(Exporter ZoneMinder::Base); + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. + +# This allows declaration use ZoneMinder ':all'; +# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK +# will save memory. +our %EXPORT_TAGS = ( + 'functions' => [ qw( + ) ] +); +push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; + +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); + +our @EXPORT = qw(); + +our $VERSION = $ZoneMinder::Base::VERSION; + +# ========================================================================== +# +# General Utility Functions +# +# ========================================================================== + +use ZoneMinder::Config qw(:all); +use ZoneMinder::Logger qw(:all); +use ZoneMinder::Database qw(:all); + +use POSIX; + +sub new { + my ( $parent, $id, $data ) = @_; + + my $self = {}; + bless $self, $parent; + if ( ( $$self{Id} = $id ) or $data ) { +#$log->debug("loading $parent $id") if $debug or DEBUG_ALL; + $self->load( $data ); + } + return $self; +} # end sub new + +sub load { + my ( $self, $data ) = @_; + my $type = ref $self; + if ( ! $data ) { +#$log->debug("Object::load Loading from db $type"); + $data = $ZoneMinder::Database::dbh->selectrow_hashref( 'SELECT * FROM Servers WHERE Id=?', {}, $$self{Id} ); + if ( ! $data ) { + if ( $ZoneMinder::Database::dbh->errstr ) { + Error( "Failure to load Server record for $$self{id}: Reason: " . $ZoneMinder::Database::dbh->errstr ); + } # end if + } # end if + } # end if ! $data + if ( $data and %$data ) { + @$self{keys %$data} = values %$data; + } # end if +} # end sub load + +sub Name { + if ( @_ > 1 ) { + $_[0]{Name} = $_[1]; + } + return $_[0]{Name}; +} # end sub Name + +sub Hostname { + if ( @_ > 1 ) { + $_[0]{Hostname} = $_[1]; + } + return $_[0]{Hostname}; +} # end sub Hostname + +1; +__END__ +# Below is stub documentation for your module. You'd better edit it! + +=head1 NAME + +ZoneMinder::Database - Perl extension for blah blah blah + +=head1 SYNOPSIS + + use ZoneMinder::Server; + blah blah blah + +=head1 DESCRIPTION + +Stub documentation for ZoneMinder, created by h2xs. It looks like the +author of the extension was negligent enough to leave the stub +unedited. + +Blah blah blah. + +=head2 EXPORT + +None by default. + + + +=head1 SEE ALSO + +Mention other useful documentation such as the documentation of +related modules or operating system documentation (such as man pages +in UNIX), or any relevant external documentation such as RFCs or +standards. + +If you have a mailing list set up for your module, mention it here. + +If you have a web site set up for your module, mention it here. + +=head1 AUTHOR + +Philip Coombes, Ephilip.coombes@zoneminder.comE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2001-2008 Philip Coombes + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.8.3 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index bdd92524b..1e01628b8 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -178,6 +178,8 @@ MAIN: while( $loop ) { my $fs_monitors; foreach my $monitor ( glob("[0-9]*") ) { + # Thie glob above gives all files starting with a digit. So a monitor with a name starting with a digit will be in this list. + next if $monitor =~ /\D/; Debug( "Found filesystem monitor '$monitor'" ); my $fs_events = $fs_monitors->{$monitor} = {}; ( my $monitor_dir ) = ( $monitor =~ /^(.*)$/ ); # De-taint diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 54f372262..d98d31809 100755 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -349,6 +349,10 @@ sub getFilters my ( $temp_attr_name ) = $filter_expr->{terms}[$i]->{attr} =~ /^Monitor(.+)$/; $db_filter->{Sql} .= "M.".$temp_attr_name; } + elsif ( $filter_expr->{terms}[$i]->{attr} eq 'ServerId' ) + { + $db_filter->{Sql} .= "M.ServerId"; + } elsif ( $filter_expr->{terms}[$i]->{attr} eq 'DateTime' ) { $db_filter->{Sql} .= "E.StartTime"; @@ -392,6 +396,13 @@ sub getFilters { $value = "'$temp_value'"; } + elsif ( $filter_expr->{terms}[$i]->{attr} eq 'ServerId' ) { + if ( $temp_value eq 'ZM_SERVER_ID' ) { + $value = "'$Config{ZM_SERVER_ID}'"; + } else { + $value = "'$temp_value'"; + } + } elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name' || $filter_expr->{terms}[$i]->{attr} eq 'Cause' || $filter_expr->{terms}[$i]->{attr} eq 'Notes' diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 8170d534c..183f8084c 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -121,10 +121,10 @@ my $retval = 0; if ( $command eq "state" ) { Info( "Updating DB: $state->{Name}\n" ); - my $sql = "select * from Monitors order by Id asc"; + my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=? ORDER BY Id ASC' : 'SELECT * FROM Monitors ORDER BY Id ASC'; my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() + my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: () ) or Fatal( "Can't execute: ".$sth->errstr() ); while( my $monitor = $sth->fetchrow_hashref() ) { @@ -226,10 +226,11 @@ if ( $command =~ /^(?:start|restart)$/ ) zmMemTidy(); runCommand( "zmdc.pl startup" ); - my $sql = "select * from Monitors"; + Info( "Starting up services" . ( $Config{ZM_SERVER_ID} ? " for server $Config{ZM_SERVER_ID}\n" : "\n" ) ); + my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'SELECT * FROM Monitors'; my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() + my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () ) or Fatal( "Can't execute: ".$sth->errstr() ); while( my $monitor = $sth->fetchrow_hashref() ) { diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index bf7c4ad13..55166a492 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -433,11 +433,12 @@ sub loadMonitors my %new_monitors = (); my $sql = "SELECT * FROM Monitors - WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )" + WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )". + ( $Config{ZM_SERVER_ID} ? 'AND ServerId=?' : '' ) ; my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() + my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () ) or Fatal( "Can't execute: ".$sth->errstr() ); while( my $monitor = $sth->fetchrow_hashref() ) { @@ -503,22 +504,11 @@ sub handleMessage Info( "Set monitor to $state\n" ); if ( $delay ) { - my $action_time = time()+$delay; my $action_text = $id."|".( ($state eq "enable") ? "disable" : "enable" - ) - ; - my $action_array = $actions{$action_time}; - if ( !$action_array ) - { - $action_array = $actions{$action_time} = []; - } - push( @$action_array, { connection=>$connection, - message=>$action_text - } - ); - Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); + ); + handleDelay($delay, $connection, $action_text); } } elsif ( $action =~ /^(on|off)(?:[ \+](\d+))?$/ ) @@ -533,43 +523,33 @@ sub handleMessage zmTriggerEventOn( $monitor, $score, $cause, $text ); zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); Info( "Trigger '$trigger' '$cause'\n" ); + if ( $delay ) + { + my $action_text = $id."|cancel"; + handleDelay($delay, $connection, $action_text); + } } elsif ( $trigger eq "off" ) { - my $last_event = zmGetLastEvent( $monitor ); - zmTriggerEventOff( $monitor ); - zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); - Info( "Trigger '$trigger'\n" ); - # Wait til it's finished - while( zmInAlarm( $monitor ) - && ($last_event == zmGetLastEvent( $monitor )) - ) + if ( $delay ) { - # Tenth of a second - usleep( 100000 ); - } + my $action_text = $id."|off|0|".$cause."|".$text; + handleDelay($delay, $connection, $action_text); + } else { + my $last_event = zmGetLastEvent( $monitor ); + zmTriggerEventOff( $monitor ); + zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); + Info( "Trigger '$trigger'\n" ); + # Wait til it's finished + while( zmInAlarm( $monitor ) + && ($last_event == zmGetLastEvent( $monitor )) + ) + { + # Tenth of a second + usleep( 100000 ); + } zmTriggerEventCancel( $monitor ); - } - else - { - Info( "Trigger '$trigger'\n" ); - zmTriggerEventCancel( $monitor ); - } - if ( $delay ) - { - my $action_time = time()+$delay; - #my $action_text = $id."|cancel|0|".$cause."|".$text; - my $action_text = $id."|cancel"; - my $action_array = $actions{$action_time}; - if ( !$action_array ) - { - $action_array = $actions{$action_time} = []; } - push( @$action_array, { connection=>$connection, - message=>$action_text - } - ); - Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); } } elsif( $action eq "cancel" ) @@ -589,5 +569,23 @@ sub handleMessage } } # end sub handleMessage +sub handleDelay +{ + my $delay = shift; + my $connection = shift; + my $action_text = shift; + + my $action_time = time()+$delay; + my $action_array = $actions{$action_time}; + if ( !$action_array ) + { + $action_array = $actions{$action_time} = []; + } + push( @$action_array, { connection=>$connection, + message=>$action_text + } + ); + Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); +} 1; __END__ diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index ee7e1b60d..5e0767487 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -74,14 +74,14 @@ sleep( START_DELAY ); my $dbh = zmDbConnect(); -my $sql = "select * from Monitors"; +my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'SELECT * FROM Monitors'; my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); while( 1 ) { my $now = time(); - my $res = $sth->execute() + my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () ) or Fatal( "Can't execute: ".$sth->errstr() ); while( my $monitor = $sth->fetchrow_hashref() ) { diff --git a/src/zm_config.cpp b/src/zm_config.cpp index a25f7a39a..8d293906c 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -25,6 +25,8 @@ #include #include +#include "zm_utils.h" + void zmLoadConfig() { FILE *cfg; @@ -91,17 +93,53 @@ void zmLoadConfig() staticConfig.DB_PASS = std::string(val_ptr); else if ( strcasecmp( name_ptr, "ZM_PATH_WEB" ) == 0 ) staticConfig.PATH_WEB = std::string(val_ptr); + else if ( strcasecmp( name_ptr, "ZM_SERVER_HOST" ) == 0 ) + staticConfig.SERVER_NAME = std::string(val_ptr); + else if ( strcasecmp( name_ptr, "ZM_SERVER_NAME" ) == 0 ) + staticConfig.SERVER_NAME = std::string(val_ptr); + else if ( strcasecmp( name_ptr, "ZM_SERVER_ID" ) == 0 ) + staticConfig.SERVER_ID = atoi(val_ptr); else { // We ignore this now as there may be more parameters than the // c/c++ binaries are bothered about // Warning( "Invalid parameter '%s' in %s", name_ptr, ZM_CONFIG ); } - } - fclose( cfg); + } // end foreach line of the config + fclose( cfg ); zmDbConnect(); config.Load(); config.Assign(); + + // Populate the server config entries + if ( ! staticConfig.SERVER_ID ) { + if ( ! staticConfig.SERVER_NAME.empty() ) { + + Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() ); + std::string sql = stringtf("SELECT Id FROM Servers WHERE Name='%s'", staticConfig.SERVER_NAME.c_str() ); + if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { + staticConfig.SERVER_ID = atoi(dbrow[0]); + } else { + Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() ); + } + + } // end if has SERVER_NAME + } else if ( staticConfig.SERVER_NAME.empty() ) { + Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID ); + std::string sql = stringtf("SELECT Name FROM Servers WHERE Id='%d'", staticConfig.SERVER_ID ); + + if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { + staticConfig.SERVER_NAME = std::string(dbrow[0]); + } else { + Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID ); + } + + } + if ( ! staticConfig.SERVER_ID ) { + Info( "No Server ID or Name specified in config. Not using Multi-Server Mode." ); + } else { + Info( "Server is %d: using Multi-Server Mode.", staticConfig.SERVER_ID ); + } } StaticConfig staticConfig; diff --git a/src/zm_config.h.in b/src/zm_config.h.in index 1df1edf16..83aa19210 100644 --- a/src/zm_config.h.in +++ b/src/zm_config.h.in @@ -65,6 +65,8 @@ struct StaticConfig std::string DB_USER; std::string DB_PASS; std::string PATH_WEB; + std::string SERVER_NAME; + unsigned int SERVER_ID; }; extern StaticConfig staticConfig; diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 0065488f5..a342ca14b 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -95,7 +95,7 @@ MYSQL_RES * zmDbFetch( const char * query ) { return result; } // end MYSQL_RES * zmDbFetch( const char * query ); -MYSQL_ROW zmDBFetchOne( const char *query ) { +MYSQL_ROW zmDbFetchOne( const char *query ) { MYSQL_RES *result = zmDbFetch( query ); int n_rows = mysql_num_rows( result ); if ( n_rows != 1 ) { @@ -104,6 +104,7 @@ MYSQL_ROW zmDBFetchOne( const char *query ) { } MYSQL_ROW dbrow = mysql_fetch_row( result ); + mysql_free_result( result ); if ( ! dbrow ) { Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) ); return NULL; diff --git a/src/zm_db.h b/src/zm_db.h index de1a81340..6ec1b5e4e 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -33,7 +33,7 @@ void zmDbConnect(); void zmDbClose(); MYSQL_RES * zmDbFetch( const char *query ); -MYSQL_ROW zmDBFetchOne( const char *query ); +MYSQL_ROW zmDbFetchOne( const char *query ); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 41b0bd36a..2d405ded6 100755 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -1211,6 +1211,11 @@ void EventStream::processCommand( const CmdMsg *msg ) Debug( 1, "Got QUERY command, sending STATUS" ); break; } + case CMD_QUIT : + { + Info ("User initiated exit - CMD_QUIT"); + break; + } default : { // Do nothing, for now @@ -1248,6 +1253,9 @@ void EventStream::processCommand( const CmdMsg *msg ) exit( -1 ); } } + // quit after sending a status, if this was a quit request + if ((MsgCommand)msg->msg_data[0]==CMD_QUIT) + exit(0); updateFrameRate( (double)event_data->frame_count/event_data->duration ); } diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 91c2ff63b..f9f62efb1 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -603,7 +603,8 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co char escapedString[(strlen(syslogStart)*2)+1]; mysql_real_escape_string( &mDbConnection, escapedString, syslogStart, strlen(syslogStart) ); - snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), tid, level, classString, escapedString, file, line ); + + snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); if ( mysql_query( &mDbConnection, sql ) ) { databaseLevel( NOLOG ); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index bcec9956f..39924f77d 100755 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -270,6 +270,7 @@ bool Monitor::MonitorLink::hasAlarmed() Monitor::Monitor( int p_id, const char *p_name, + const unsigned int p_server_id, int p_function, bool p_enabled, const char *p_linked_monitors, @@ -306,6 +307,7 @@ Monitor::Monitor( int p_n_zones, Zone *p_zones[] ) : id( p_id ), + server_id( p_server_id ), function( (Function)p_function ), enabled( p_enabled ), width( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Height():p_camera->Width() ), @@ -2082,25 +2084,20 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) #if ZM_HAS_V4L int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ) { - static char sql[ZM_SQL_MED_BUFSIZ]; - if ( !device[0] ) - { - strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local' order by Device, Channel", sizeof(sql) ); + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'"; + if ( device[0] ) { + sql += " AND Device='"; + sql += device; + sql += "'"; } - else - { - snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local' and Device = '%s' order by Channel", device ); - } - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); } + Debug( 1, "Loading Local Monitors with %s", sql.c_str() ); - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) - { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + MYSQL_RES *result = zmDbFetch( sql.c_str() ); + if ( !result ) { + Error( "Can't load local monitors: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); } int n_monitors = mysql_num_rows( result ); @@ -2113,6 +2110,7 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose int id = atoi(dbrow[col]); col++; const char *name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; int function = atoi(dbrow[col]); col++; int enabled = atoi(dbrow[col]); col++; const char *linked_monitors = dbrow[col]; col++; @@ -2217,6 +2215,7 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); monitors[i] = new Monitor( id, name, + server_id, function, enabled, linked_monitors, @@ -2273,24 +2272,18 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose ) { - static char sql[ZM_SQL_MED_BUFSIZ]; - if ( !protocol ) - { - strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'", sizeof(sql) ); - } - else - { - snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote' and Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path ); - } - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'"; + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); } - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) - { + if ( protocol ) { + sql += stringtf(" AND Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path ); + } + + Debug( 1, "Loading Remote Monitors with %s", sql.c_str() ); + MYSQL_RES *result = zmDbFetch( sql.c_str() ); + if ( !result ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); } @@ -2304,6 +2297,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c int id = atoi(dbrow[col]); col++; std::string name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; int function = atoi(dbrow[col]); col++; int enabled = atoi(dbrow[col]); col++; const char *linked_monitors = dbrow[col]; col++; @@ -2407,6 +2401,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c monitors[i] = new Monitor( id, name.c_str(), + server_id, function, enabled, linked_monitors, @@ -2463,22 +2458,17 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - static char sql[ZM_SQL_MED_BUFSIZ]; - if ( !file[0] ) - { - strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'", sizeof(sql) ); + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'"; + if ( file[0] ) { + sql += " AND Path='"; + sql += file; + sql += "'"; } - else - { - snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File' and Path = '%s'", file ); + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); } - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - - MYSQL_RES *result = mysql_store_result( &dbconn ); + Debug( 1, "Loading File Monitors with %s", sql.c_str() ); + MYSQL_RES *result = zmDbFetch( sql.c_str() ); if ( !result ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); @@ -2494,6 +2484,7 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu int id = atoi(dbrow[col]); col++; const char *name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; int function = atoi(dbrow[col]); col++; int enabled = atoi(dbrow[col]); col++; const char *linked_monitors = dbrow[col]; col++; @@ -2561,6 +2552,7 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu monitors[i] = new Monitor( id, name, + server_id, function, enabled, linked_monitors, @@ -2617,27 +2609,22 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu #if HAVE_LIBAVFORMAT int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - static char sql[ZM_SQL_MED_BUFSIZ]; - if ( !file[0] ) - { - strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'", sizeof(sql) ); + std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'"; + if ( file[0] ) { + sql += " AND Path = '"; + sql += file; + sql += "'"; } - else - { - snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg' and Path = '%s'", file ); + if ( staticConfig.SERVER_ID ) { + sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); } - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + Debug( 1, "Loading FFMPEG Monitors with %s", sql.c_str() ); + MYSQL_RES *result = zmDbFetch( sql.c_str() ); + if ( ! result ) { + Error( "Cannot load FfmpegMonitors" ); exit( mysql_errno( &dbconn ) ); } - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) - { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } int n_monitors = mysql_num_rows( result ); Debug( 1, "Got %d monitors", n_monitors ); delete[] monitors; @@ -2648,6 +2635,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose int id = atoi(dbrow[col]); col++; const char *name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; int function = atoi(dbrow[col]); col++; int enabled = atoi(dbrow[col]); col++; const char *linked_monitors = dbrow[col]; col++; @@ -2719,6 +2707,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose monitors[i] = new Monitor( id, name, + server_id, function, enabled, linked_monitors, @@ -2773,338 +2762,320 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose } #endif // HAVE_LIBAVFORMAT -Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) +Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { - static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id, Name, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", id ); - if ( mysql_query( &dbconn, sql ) ) - { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } + std::string sql = stringtf( "select Id, Name, ServerId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id ); - MYSQL_RES *result = mysql_store_result( &dbconn ); - if ( !result ) - { + MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ); + if ( ! dbrow ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); } - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); Monitor *monitor = 0; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) - { - int col = 0; + unsigned int col = 0; - int id = atoi(dbrow[col]); col++; - std::string name = dbrow[col]; col++; - std::string type = dbrow[col]; col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - std::string linked_monitors = dbrow[col]; col++; + unsigned int id = atoi(dbrow[col]); col++; + std::string name = dbrow[col]; col++; + unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + std::string type = dbrow[col]; col++; + int function = atoi(dbrow[col]); col++; + int enabled = atoi(dbrow[col]); col++; + std::string linked_monitors = dbrow[col]; col++; - std::string device = dbrow[col]; col++; - int channel = atoi(dbrow[col]); col++; - int format = atoi(dbrow[col]); col++; + std::string device = dbrow[col]; col++; + int channel = atoi(dbrow[col]); col++; + int format = atoi(dbrow[col]); col++; - bool v4l_multi_buffer = config.v4l_multi_buffer; - if ( dbrow[col] ) { - if (*dbrow[col] == '0' ) { - v4l_multi_buffer = false; - } else if ( *dbrow[col] == '1' ) { - v4l_multi_buffer = true; - } + bool v4l_multi_buffer = config.v4l_multi_buffer; + if ( dbrow[col] ) { + if (*dbrow[col] == '0' ) { + v4l_multi_buffer = false; + } else if ( *dbrow[col] == '1' ) { + v4l_multi_buffer = true; } - col++; + } + col++; - int v4l_captures_per_frame = 0; - if ( dbrow[col] ) { - v4l_captures_per_frame = atoi(dbrow[col]); - } else { - v4l_captures_per_frame = config.captures_per_frame; - } + int v4l_captures_per_frame = 0; + if ( dbrow[col] ) { + v4l_captures_per_frame = atoi(dbrow[col]); + } else { + v4l_captures_per_frame = config.captures_per_frame; + } Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); - col++; + col++; - std::string protocol = dbrow[col]; col++; - std::string method = dbrow[col]; col++; - std::string host = dbrow[col]; col++; - std::string port = dbrow[col]; col++; - std::string path = dbrow[col]; col++; - std::string options = dbrow[col]; col++; - std::string user = dbrow[col]; col++; - std::string pass = dbrow[col]; col++; + std::string protocol = dbrow[col]; col++; + std::string method = dbrow[col]; col++; + std::string host = dbrow[col]; col++; + std::string port = dbrow[col]; col++; + std::string path = dbrow[col]; col++; + std::string options = dbrow[col]; col++; + std::string user = dbrow[col]; col++; + std::string pass = dbrow[col]; col++; - int width = atoi(dbrow[col]); col++; - int height = atoi(dbrow[col]); col++; - int colours = atoi(dbrow[col]); col++; - int palette = atoi(dbrow[col]); col++; - Orientation orientation = (Orientation)atoi(dbrow[col]); col++; - unsigned int deinterlacing = atoi(dbrow[col]); col++; - bool rtsp_describe = (*dbrow[col] != '0'); col++; - int savejpegs = atoi(dbrow[col]); col++; - int videowriter = atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col]; col++; + int width = atoi(dbrow[col]); col++; + int height = atoi(dbrow[col]); col++; + int colours = atoi(dbrow[col]); col++; + int palette = atoi(dbrow[col]); col++; + Orientation orientation = (Orientation)atoi(dbrow[col]); col++; + unsigned int deinterlacing = atoi(dbrow[col]); col++; + bool rtsp_describe = (*dbrow[col] != '0'); col++; + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; - int brightness = atoi(dbrow[col]); col++; - int contrast = atoi(dbrow[col]); col++; - int hue = atoi(dbrow[col]); col++; - int colour = atoi(dbrow[col]); col++; + int brightness = atoi(dbrow[col]); col++; + int contrast = atoi(dbrow[col]); col++; + int hue = atoi(dbrow[col]); col++; + int colour = atoi(dbrow[col]); col++; - std::string event_prefix = dbrow[col]; col++; - std::string label_format = dbrow[col]; col++; + std::string event_prefix = dbrow[col]; col++; + std::string label_format = dbrow[col]; col++; - int label_x = atoi(dbrow[col]); col++; - int label_y = atoi(dbrow[col]); col++; - int label_size = atoi(dbrow[col]); col++; + int label_x = atoi(dbrow[col]); col++; + int label_y = atoi(dbrow[col]); col++; + int label_size = atoi(dbrow[col]); col++; - int image_buffer_count = atoi(dbrow[col]); col++; - int warmup_count = atoi(dbrow[col]); col++; - int pre_event_count = atoi(dbrow[col]); col++; - int post_event_count = atoi(dbrow[col]); col++; - int stream_replay_buffer = atoi(dbrow[col]); col++; - int alarm_frame_count = atoi(dbrow[col]); col++; - int section_length = atoi(dbrow[col]); col++; - int frame_skip = atoi(dbrow[col]); col++; - int motion_frame_skip = atoi(dbrow[col]); col++; - double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; - unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); - int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; - int fps_report_interval = atoi(dbrow[col]); col++; - int ref_blend_perc = atoi(dbrow[col]); col++; - int alarm_ref_blend_perc = atoi(dbrow[col]); col++; - int track_motion = atoi(dbrow[col]); col++; + int image_buffer_count = atoi(dbrow[col]); col++; + int warmup_count = atoi(dbrow[col]); col++; + int pre_event_count = atoi(dbrow[col]); col++; + int post_event_count = atoi(dbrow[col]); col++; + int stream_replay_buffer = atoi(dbrow[col]); col++; + int alarm_frame_count = atoi(dbrow[col]); col++; + int section_length = atoi(dbrow[col]); col++; + int frame_skip = atoi(dbrow[col]); col++; + int motion_frame_skip = atoi(dbrow[col]); col++; + double analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; + unsigned int analysis_update_delay = strtoul(dbrow[col++], NULL, 0); + int capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + int fps_report_interval = atoi(dbrow[col]); col++; + int ref_blend_perc = atoi(dbrow[col]); col++; + int alarm_ref_blend_perc = atoi(dbrow[col]); col++; + int track_motion = atoi(dbrow[col]); col++; - int signal_check_colour; - if ( dbrow[col][0] == '#' ) - signal_check_colour = strtol(dbrow[col]+1,0,16); - else - signal_check_colour = strtol(dbrow[col],0,16); - col++; - bool embed_exif = (*dbrow[col] != '0'); col++; + int signal_check_colour; + if ( dbrow[col][0] == '#' ) + signal_check_colour = strtol(dbrow[col]+1,0,16); + else + signal_check_colour = strtol(dbrow[col],0,16); + col++; + bool embed_exif = (*dbrow[col] != '0'); col++; - int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); - int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); + int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width); + int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height); - int extras = (deinterlacing>>24)&0xff; + int extras = (deinterlacing>>24)&0xff; - Camera *camera = 0; - if ( type == "Local" ) - { -#if ZM_HAS_V4L - camera = new LocalCamera( - id, - device.c_str(), - channel, - format, - v4l_multi_buffer, - v4l_captures_per_frame, - method, - cam_width, - cam_height, - colours, - palette, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - extras - ); -#else // ZM_HAS_V4L - Fatal( "You must have video4linux libraries and headers installed to use local analog or USB cameras for monitor %d", id ); -#endif // ZM_HAS_V4L - } - else if ( type == "Remote" ) - { - if ( protocol == "http" ) - { - camera = new RemoteCameraHttp( - id, - method.c_str(), - host.c_str(), - port.c_str(), - path.c_str(), - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); - } - else if ( protocol == "rtsp" ) - { -#if HAVE_LIBAVFORMAT - camera = new RemoteCameraRtsp( - id, - method.c_str(), - host.c_str(), - port.c_str(), - path.c_str(), - cam_width, - cam_height, - rtsp_describe, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); -#else // HAVE_LIBAVFORMAT - Fatal( "You must have ffmpeg libraries installed to use remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); -#endif // HAVE_LIBAVFORMAT - } - else - { - Fatal( "Unexpected remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); - } - } - else if ( type == "File" ) - { - camera = new FileCamera( - id, - path.c_str(), - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); - } - else if ( type == "Ffmpeg" ) - { -#if HAVE_LIBAVFORMAT - camera = new FfmpegCamera( - id, - path.c_str(), - method, - options, - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); -#else // HAVE_LIBAVFORMAT - Fatal( "You must have ffmpeg libraries installed to use ffmpeg cameras for monitor %d", id ); -#endif // HAVE_LIBAVFORMAT - } - else if (type == "Libvlc") - { -#if HAVE_LIBVLC - camera = new LibvlcCamera( - id, - path.c_str(), - method, - options, - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); -#else // HAVE_LIBVLC - Fatal( "You must have vlc libraries installed to use vlc cameras for monitor %d", id ); -#endif // HAVE_LIBVLC - } - else if ( type == "cURL" ) - { -#if HAVE_LIBCURL - camera = new cURLCamera( - id, - path.c_str(), - user.c_str(), - pass.c_str(), - cam_width, - cam_height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE - ); -#else // HAVE_LIBCURL - Fatal( "You must have libcurl installed to use ffmpeg cameras for monitor %d", id ); -#endif // HAVE_LIBCURL - } - else - { - Fatal( "Bogus monitor type '%s' for monitor %d", type.c_str(), id ); - } - monitor = new Monitor( - id, - name.c_str(), - function, - enabled, - linked_monitors.c_str(), - camera, - orientation, - deinterlacing, - savejpegs, - videowriter, - encoderparams, - event_prefix.c_str(), - label_format.c_str(), - Coord( label_x, label_y ), - label_size, - image_buffer_count, - warmup_count, - pre_event_count, - post_event_count, - stream_replay_buffer, - alarm_frame_count, - section_length, - frame_skip, - motion_frame_skip, - analysis_fps, - analysis_update_delay, - capture_delay, - alarm_capture_delay, - fps_report_interval, - ref_blend_perc, - alarm_ref_blend_perc, - track_motion, - signal_check_colour, - embed_exif, - purpose, - 0, - 0 - - ); - - int n_zones = 0; - if ( load_zones ) - { - Zone **zones = 0; - n_zones = Zone::Load( monitor, zones ); - monitor->AddZones( n_zones, zones ); - monitor->AddPrivacyBitmask( zones ); - } - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name.c_str(), n_zones ); - } - if ( mysql_errno( &dbconn ) ) + Camera *camera = 0; + if ( type == "Local" ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); +#if ZM_HAS_V4L + camera = new LocalCamera( + id, + device.c_str(), + channel, + format, + v4l_multi_buffer, + v4l_captures_per_frame, + method, + cam_width, + cam_height, + colours, + palette, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + extras + ); +#else // ZM_HAS_V4L + Fatal( "You must have video4linux libraries and headers installed to use local analog or USB cameras for monitor %d", id ); +#endif // ZM_HAS_V4L } - // Yadda yadda - mysql_free_result( result ); + else if ( type == "Remote" ) + { + if ( protocol == "http" ) + { + camera = new RemoteCameraHttp( + id, + method.c_str(), + host.c_str(), + port.c_str(), + path.c_str(), + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE + ); + } + else if ( protocol == "rtsp" ) + { +#if HAVE_LIBAVFORMAT + camera = new RemoteCameraRtsp( + id, + method.c_str(), + host.c_str(), + port.c_str(), + path.c_str(), + cam_width, + cam_height, + rtsp_describe, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE + ); +#else // HAVE_LIBAVFORMAT + Fatal( "You must have ffmpeg libraries installed to use remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); +#endif // HAVE_LIBAVFORMAT + } + else + { + Fatal( "Unexpected remote camera protocol '%s' for monitor %d", protocol.c_str(), id ); + } + } + else if ( type == "File" ) + { + camera = new FileCamera( + id, + path.c_str(), + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE + ); + } + else if ( type == "Ffmpeg" ) + { +#if HAVE_LIBAVFORMAT + camera = new FfmpegCamera( + id, + path.c_str(), + method, + options, + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE + ); +#else // HAVE_LIBAVFORMAT + Fatal( "You must have ffmpeg libraries installed to use ffmpeg cameras for monitor %d", id ); +#endif // HAVE_LIBAVFORMAT + } + else if (type == "Libvlc") + { +#if HAVE_LIBVLC + camera = new LibvlcCamera( + id, + path.c_str(), + method, + options, + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE + ); +#else // HAVE_LIBVLC + Fatal( "You must have vlc libraries installed to use vlc cameras for monitor %d", id ); +#endif // HAVE_LIBVLC + } + else if ( type == "cURL" ) + { +#if HAVE_LIBCURL + camera = new cURLCamera( + id, + path.c_str(), + user.c_str(), + pass.c_str(), + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE + ); +#else // HAVE_LIBCURL + Fatal( "You must have libcurl installed to use ffmpeg cameras for monitor %d", id ); +#endif // HAVE_LIBCURL + } + else + { + Fatal( "Bogus monitor type '%s' for monitor %d", type.c_str(), id ); + } + monitor = new Monitor( + id, + name.c_str(), + server_id, + function, + enabled, + linked_monitors.c_str(), + camera, + orientation, + deinterlacing, + savejpegs, + videowriter, + encoderparams, + event_prefix.c_str(), + label_format.c_str(), + Coord( label_x, label_y ), + label_size, + image_buffer_count, + warmup_count, + pre_event_count, + post_event_count, + stream_replay_buffer, + alarm_frame_count, + section_length, + frame_skip, + motion_frame_skip, + analysis_fps, + analysis_update_delay, + capture_delay, + alarm_capture_delay, + fps_report_interval, + ref_blend_perc, + alarm_ref_blend_perc, + track_motion, + signal_check_colour, + embed_exif, + purpose, + 0, + 0 + ); + + int n_zones = 0; + if ( load_zones ) + { + Zone **zones = 0; + n_zones = Zone::Load( monitor, zones ); + monitor->AddZones( n_zones, zones ); + monitor->AddPrivacyBitmask( zones ); + } + Debug( 1, "Loaded monitor %d(%s), %d zones", id, name.c_str(), n_zones ); return( monitor ); } @@ -3112,17 +3083,17 @@ int Monitor::Capture() { static int FirstCapture = 1; int captureResult; - + int index = image_count%image_buffer_count; Image* capture_image = image_buffer[index].image; - + if ( (deinterlacing & 0xff) == 4) { if ( FirstCapture != 1 ) { /* Copy the next image into the shared memory */ capture_image->CopyBuffer(*(next_buffer.image)); } - /* Capture a new next image */ + /* Capture a new next image */ //Check if FFMPEG camera if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()){ @@ -3167,18 +3138,18 @@ int Monitor::Capture() if ( captureResult == 1 ) { - /* Deinterlacing */ - if ( (deinterlacing & 0xff) == 1 ) { - capture_image->Deinterlace_Discard(); - } else if ( (deinterlacing & 0xff) == 2 ) { - capture_image->Deinterlace_Linear(); - } else if ( (deinterlacing & 0xff) == 3 ) { - capture_image->Deinterlace_Blend(); - } else if ( (deinterlacing & 0xff) == 4 ) { - capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); - } else if ( (deinterlacing & 0xff) == 5 ) { - capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); - } + /* Deinterlacing */ + if ( (deinterlacing & 0xff) == 1 ) { + capture_image->Deinterlace_Discard(); + } else if ( (deinterlacing & 0xff) == 2 ) { + capture_image->Deinterlace_Linear(); + } else if ( (deinterlacing & 0xff) == 3 ) { + capture_image->Deinterlace_Blend(); + } else if ( (deinterlacing & 0xff) == 4 ) { + capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); + } else if ( (deinterlacing & 0xff) == 5 ) { + capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + } if ( orientation != ROTATE_0 ) @@ -3211,7 +3182,7 @@ int Monitor::Capture() if ( capture_image->Size() > camera->ImageSize() ) { - Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); + Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); return( -1 ); } @@ -3591,7 +3562,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z } if (zone->CheckExtendAlarmCount()) { alarm=true; - zone->SetAlarm(); + zone->SetAlarm(); } else { zone->ClearAlarm(); } @@ -4043,6 +4014,11 @@ void MonitorStream::processCommand( const CmdMsg *msg ) Debug( 1, "Got SCALE command, to %d", scale ); break; } + case CMD_QUIT : + { + Info ("User initiated exit - CMD_QUIT"); + break; + } case CMD_QUERY : { Debug( 1, "Got QUERY command, sending STATUS" ); @@ -4108,6 +4084,10 @@ void MonitorStream::processCommand( const CmdMsg *msg ) } } + // quit after sending a status, if this was a quit request + if ((MsgCommand)msg->msg_data[0]==CMD_QUIT) + exit(0); + updateFrameRate( monitor->GetFPS() ); } @@ -4558,7 +4538,7 @@ void MonitorStream::runStream() } } } - if ( swap_path ) free( swap_path ); + if ( swap_path ) free( swap_path ); closeComms(); } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index c7e45ccfb..9c59a112e 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -226,6 +226,7 @@ protected: // These are read from the DB and thereafter remain unchanged unsigned int id; char name[64]; + unsigned int server_id; Function function; // What the monitor is doing bool enabled; // Whether the monitor is enabled or asleep unsigned int width; // Normally the same as the camera, but not if partly rotated @@ -331,7 +332,7 @@ protected: public: // OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info. //bool OurCheckAlarms( Zone *zone, const Image *pImage ); - Monitor( int p_id, const char *p_name, int p_function, bool p_enabled, const char *p_linked_monitors, Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, int p_savejpegs, int p_videowriter, std::string p_encoderparams, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, int label_size, int p_image_buffer_count, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_stream_replay_buffer, int p_alarm_frame_count, int p_section_length, int p_frame_skip, int p_motion_frame_skip, double p_analysis_fps, unsigned int p_analysis_update_delay, int p_capture_delay, int p_alarm_capture_delay, int p_fps_report_interval, int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, Rgb p_signal_check_colour, bool p_embed_exif, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0 ); + Monitor( int p_id, const char *p_name, unsigned int p_server_id, int p_function, bool p_enabled, const char *p_linked_monitors, Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, int p_savejpegs, int p_videowriter, std::string p_encoderparams, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, int label_size, int p_image_buffer_count, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_stream_replay_buffer, int p_alarm_frame_count, int p_section_length, int p_frame_skip, int p_motion_frame_skip, double p_analysis_fps, unsigned int p_analysis_update_delay, int p_capture_delay, int p_alarm_capture_delay, int p_fps_report_interval, int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, Rgb p_signal_check_colour, bool p_embed_exif, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0 ); ~Monitor(); void AddZones( int p_n_zones, Zone *p_zones[] ); @@ -457,7 +458,7 @@ public: #if HAVE_LIBAVFORMAT static int LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ); #endif // HAVE_LIBAVFORMAT - static Monitor *Load( int id, bool load_zones, Purpose purpose ); + static Monitor *Load( unsigned int id, bool load_zones, Purpose purpose ); //void writeStreamImage( Image *image, struct timeval *timestamp, int scale, int mag, int x, int y ); //void StreamImages( int scale=100, int maxfps=10, time_t ttl=0, int msq_id=0 ); //void StreamImagesRaw( int scale=100, int maxfps=10, time_t ttl=0 ); diff --git a/src/zm_stream.h b/src/zm_stream.h index 9936688a8..4f6442725 100644 --- a/src/zm_stream.h +++ b/src/zm_stream.h @@ -57,7 +57,7 @@ protected: } DataMsg; typedef enum { MSG_CMD=1, MSG_DATA_WATCH, MSG_DATA_EVENT } MsgType; - typedef enum { CMD_NONE=0, CMD_PAUSE, CMD_PLAY, CMD_STOP, CMD_FASTFWD, CMD_SLOWFWD, CMD_SLOWREV, CMD_FASTREV, CMD_ZOOMIN, CMD_ZOOMOUT, CMD_PAN, CMD_SCALE, CMD_PREV, CMD_NEXT, CMD_SEEK, CMD_VARPLAY, CMD_GET_IMAGE, CMD_QUERY=99 } MsgCommand; + typedef enum { CMD_NONE=0, CMD_PAUSE, CMD_PLAY, CMD_STOP, CMD_FASTFWD, CMD_SLOWFWD, CMD_SLOWREV, CMD_FASTREV, CMD_ZOOMIN, CMD_ZOOMOUT, CMD_PAN, CMD_SCALE, CMD_PREV, CMD_NEXT, CMD_SEEK, CMD_VARPLAY, CMD_GET_IMAGE, CMD_QUIT, CMD_QUERY=99 } MsgCommand; protected: Monitor *monitor; diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index b7a97a0a6..2ce506421 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -1,18 +1,45 @@ #!/bin/bash + +if [ "$1" == "clean" ]; then + +read -p "Do you really want to delete existing packages? [y/N]" +[[ $REPLY == [yY] ]] && { rm -fr zoneminder*.build zoneminder*.changes zoneminder*.deb; echo "Existing package files deleted"; } || { echo "Packages have NOT been deleted"; } +exit; + +fi + + DATE=`date -R` DISTRO=$1 SNAPSHOT=$2 +if [ "$SNAPSHOT" == "stable" ]; then +SNAPSHOT=""; +fi; + + TYPE=$3 if [ "$TYPE" == "" ]; then TYPE="source"; fi; +BRANCH=$4 + if [ ! -d 'zoneminder_release' ]; then -git clone https://github.com/ZoneMinder/ZoneMinder.git zoneminder_release + git clone https://github.com/ZoneMinder/ZoneMinder.git zoneminder_release +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 ../ fi; VERSION=`cat zoneminder_release/version` if [ $VERSION == "" ]; then -exit 1; + exit 1; fi; echo "Doing $TYPE release zoneminder_$VERSION-$DISTRO-$SNAPSHOT"; mv zoneminder_release zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig @@ -20,9 +47,9 @@ cd zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig git submodule init git submodule update --init --recursive if [ $DISTRO == "trusty" ]; then -cp -r distros/ubuntu1204_cmake debian +ln -sf distros/ubuntu1204_cmake debian else -cp -r distros/ubuntu1504_cmake debian +ln -sf distros/ubuntu1504_cmake debian fi; cat < debian/changelog @@ -33,15 +60,26 @@ zoneminder ($VERSION-$DISTRO-$SNAPSHOT) $DISTRO; urgency=medium -- Isaac Connor $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 +#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 if [ $TYPE == "binary" ]; then -debuild -k52C7377E + debuild else -debuild -S -sa -k52C7377E + if [ $TYPE == "local" ]; then + debuild -i -us -uc -b + else + debuild -S -sa + fi; fi; + cd ../ -rm -fr zoneminder_$VERSION-$DISTRO-$SNAPSHOT.orig + +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!" + + + diff --git a/version b/version index a960d2a6d..5e57fb895 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.28.109 +1.29.0 diff --git a/web/ajax/control.php b/web/ajax/control.php index 7e2625b70..abdc8c8ef 100644 --- a/web/ajax/control.php +++ b/web/ajax/control.php @@ -1,5 +1,6 @@ Id().'.sock'; if ( @socket_connect( $socket, $sock_file ) ) { $options = array(); @@ -36,7 +37,7 @@ if ( canView( 'Control', $_REQUEST['id'] ) ) } else { - $ctrlCommand .= " --id=".$monitor['Id']; + $ctrlCommand .= " --id=".$monitor->Id(); // Can't connect so use script $ctrlStatus = ''; diff --git a/web/ajax/log.php b/web/ajax/log.php index 3decbd124..a250c952d 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -31,6 +31,13 @@ switch ( $_REQUEST['task'] ) if ( !canView( 'System' ) ) ajaxError( 'Insufficient permissions to view log entries' ); + $servers = Server::find_all(); + $servers_by_Id = array(); + # There is probably a better way to do this. + foreach ( $servers as $server ) { + $servers_by_Id[$server->Id()] = $server; + } + $minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL; $maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL; $limit = isset($_POST['limit'])?$_POST['limit']:100; @@ -38,7 +45,7 @@ switch ( $_REQUEST['task'] ) $sortField = isset($_POST['sortField'])?$_POST['sortField']:'TimeKey'; $sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc'; - $filterFields = array( 'Component', 'Pid', 'Level', 'File', 'Line' ); + $filterFields = array( 'Component', 'ServerId', 'Pid', 'Level', 'File', 'Line' ); $total = dbFetchOne( "SELECT count(*) AS Total FROM Logs", 'Total' ); $sql = 'SELECT * FROM Logs'; @@ -66,6 +73,7 @@ switch ( $_REQUEST['task'] ) $logs = array(); foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) { $log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] ); + $log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : ''; $logs[] = $log; } $options = array(); @@ -96,6 +104,12 @@ switch ( $_REQUEST['task'] ) else $options[$field][$value] = "DB".$value; } + elseif ( $field == 'ServerId' ) + { + foreach( dbFetchAll( $sql, $field, array_values($fieldValues) ) as $value ) + $options['ServerId'][$value] = ( $value and isset($servers_by_Id[$value]) ) ? $servers_by_Id[$value]->Name() : ''; + + } else { foreach( dbFetchAll( $sql, $field, array_values( $fieldValues ) ) as $value ) @@ -136,6 +150,13 @@ switch ( $_REQUEST['task'] ) $sortField = isset($_POST['sortField'])?$_POST['sortField']:'TimeKey'; $sortOrder = isset($_POST['sortOrder'])?$_POST['sortOrder']:'asc'; + $servers = Server::find_all(); + $servers_by_Id = array(); + # There is probably a better way to do this. + foreach ( $servers as $server ) { + $servers_by_Id[$server->Id()] = $server; + } + $sql = "select * from Logs"; $where = array(); $values = array(); @@ -195,6 +216,7 @@ switch ( $_REQUEST['task'] ) foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) { $log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] ); + $log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : ''; $logs[] = $log; } switch( $format ) @@ -212,10 +234,20 @@ switch ( $_REQUEST['task'] ) } case 'tsv' : { - fprintf( $exportFP, translate('DateTime')."\t".translate('Component')."\t".translate('Pid')."\t".translate('Level')."\t".translate('Message')."\t".translate('File')."\t".translate('Line')."\n" ); + # This line doesn't need fprintf, it could use fwrite + fprintf( $exportFP, join( "\t", + translate('DateTime'), + translate('Component'), + translate('Server'), + translate('Pid'), + translate('Level'), + translate('Message'), + translate('File'), + translate('Line') + )."\n" ); foreach ( $logs as $log ) { - fprintf( $exportFP, "%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); + fprintf( $exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); } break; } @@ -265,7 +297,7 @@ tr.log-dbg td {

'.count($logs).' '.translate('Logs').'

- + ' ); foreach ( $logs as $log ) { @@ -275,7 +307,7 @@ tr.log-dbg td { elseif ( $classLevel > Logger::DEBUG ) $classLevel = Logger::DEBUG; $logClass = 'log-'.strtolower(Logger::$codes[$classLevel]); - fprintf( $exportFP, " \n", $logClass, $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); + fprintf( $exportFP, " \n", $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); } fwrite( $exportFP, ' @@ -298,7 +330,7 @@ tr.log-dbg td { ' ); fwrite( $exportFP, ' - '.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' + '.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' ' ); @@ -308,12 +340,13 @@ tr.log-dbg td { " %s %s + %s %d %s %s %d - \n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); + \n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); } fwrite( $exportFP, ' diff --git a/web/api/app/Controller/AppController.php b/web/api/app/Controller/AppController.php index 1d85115e8..5b39597b3 100644 --- a/web/api/app/Controller/AppController.php +++ b/web/api/app/Controller/AppController.php @@ -34,7 +34,7 @@ class AppController extends Controller { use CrudControllerTrait; public $components = [ - 'Session', // PP - We are going to use SessionHelper to check PHP session vars + 'Session', // We are going to use SessionHelper to check PHP session vars 'RequestHandler', 'Crud.Crud' => [ 'actions' => [ @@ -49,7 +49,7 @@ class AppController extends Controller { ] ]; - //PP - Global beforeFilter function + // Global beforeFilter function //Zoneminder sets the username session variable // to the logged in user. If this variable is set // then you are logged in @@ -58,14 +58,62 @@ class AppController extends Controller { // Also checking to do this only if ZM_OPT_USE_AUTH is on public function beforeFilter() { $this->loadModel('Config'); + + $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_API')); + $config = $this->Config->find('first', $options); + $zmOptApi = $config['Config']['Value']; + + if ($zmOptApi !='1') + { + throw new UnauthorizedException(__('API Disabled')); + return; + } + $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')); $config = $this->Config->find('first', $options); $zmOptAuth = $config['Config']['Value']; if (!$this->Session->Read('user.Username') && ($zmOptAuth=='1')) { - throw new NotFoundException(__('Not Authenticated')); + throw new UnauthorizedException(__('Not Authenticated')); return; } + else + { + $this->loadModel('User'); + $loggedinUser = $this->Session->Read('user.Username'); + $isEnabled = $this->Session->Read('user.Enabled'); + // this will likely never happen as if its + // not enabled, login will fail and Not Auth will be returned + // however, keeping this here for now + if ($isEnabled != "1" && $zmOptAuth=="1") + { + throw new UnauthorizedException(__('User is not enabled')); + return; + } + + if ($zmOptAuth=='1') + { + $options = array ('conditions' => array ('User.Username' => $loggedinUser)); + $userMonitors = $this->User->find('first', $options); + $this->Session->Write('allowedMonitors',$userMonitors['User']['MonitorIds']); + $this->Session->Write('streamPermission',$userMonitors['User']['Stream']); + $this->Session->Write('eventPermission',$userMonitors['User']['Events']); + $this->Session->Write('controlPermission',$userMonitors['User']['Control']); + $this->Session->Write('systemPermission',$userMonitors['User']['System']); + $this->Session->Write('monitorPermission',$userMonitors['User']['Monitors']); + } + else // if auth is not on, you can do everything + { + //$userMonitors = $this->User->find('first', $options); + $this->Session->Write('allowedMonitors',''); + $this->Session->Write('streamPermission','View'); + $this->Session->Write('eventPermission','Edit'); + $this->Session->Write('controlPermission','Edit'); + $this->Session->Write('systemPermission','Edit'); + $this->Session->Write('monitorPermission','Edit'); + } + } + } diff --git a/web/api/app/Controller/Component/ImageComponent.php b/web/api/app/Controller/Component/ImageComponent.php index 68a254031..f8ed7a533 100644 --- a/web/api/app/Controller/Component/ImageComponent.php +++ b/web/api/app/Controller/Component/ImageComponent.php @@ -48,7 +48,7 @@ class ImageComponent extends Component { $imageFile = $config['ZM_DIR_EVENTS']."/".$imagePath; //$thumbFile = ZM_DIR_EVENTS."/".$thumbPath; $thumbFile = $thumbPath; - // PP: This segment of code results in errors when trying to get Events API + // This segment of code results in errors when trying to get Events API // This actually seems to be generating images for the angular UI web view // and should not be a part of the API anyway // I've commented it so events APIs continue to work diff --git a/web/api/app/Controller/ConfigsController.php b/web/api/app/Controller/ConfigsController.php index e70978246..48f50ae8e 100644 --- a/web/api/app/Controller/ConfigsController.php +++ b/web/api/app/Controller/ConfigsController.php @@ -15,7 +15,7 @@ class ConfigsController extends AppController { public $components = array('RequestHandler'); /** - * PP - resolves the issue of not returning all config parameters + * resolves the issue of not returning all config parameters * refer https://github.com/ZoneMinder/ZoneMinder/issues/953 * index method * diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 988c19110..ef569cd7b 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -14,6 +14,17 @@ class EventsController extends AppController { */ public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator'); +public function beforeFilter() { + parent::beforeFilter(); + $canView = $this->Session->Read('eventPermission'); + if ($canView =='None') + { + throw new UnauthorizedException(__('Insufficient Privileges')); + return; + } + +} + /** * index method * @@ -22,6 +33,18 @@ class EventsController extends AppController { */ public function index() { $this->Event->recursive = -1; + + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); + + if (!empty($allowedMonitors)) + { + $mon_options = array('Event.MonitorId' => $allowedMonitors); + } + else + { + $mon_options=''; + } + if ($this->request->params['named']) { $this->FilterComponent = $this->Components->load('Filter'); @@ -39,7 +62,7 @@ class EventsController extends AppController { $this->Paginator->settings = array( // https://github.com/ZoneMinder/ZoneMinder/issues/995 // 'limit' => $limit['ZM_WEB_EVENTS_PER_PAGE'], - // PP - 25 events per page which is what the above + // 25 events per page which is what the above // default is, is way too low for an API // changing this to 100 so we don't kill ZM // with many event APIs. In future, we can @@ -49,14 +72,14 @@ class EventsController extends AppController { 'limit' => '100', 'order' => array('StartTime', 'MaxScore'), 'paramType' => 'querystring', - 'conditions' => $conditions + 'conditions' => array (array($conditions, $mon_options)) ); $events = $this->Paginator->paginate('Event'); // For each event, get its thumbnail data (path, width, height) foreach ($events as $key => $value) { - // PP - $thumbData = $this->createThumbnail($value['Event']['Id']); - $thumbData =""; + //$thumbData = $this->createThumbnail($value['Event']['Id']); + $thumbData = ""; $events[$key]['thumbData'] = $thumbData; } @@ -71,41 +94,55 @@ class EventsController extends AppController { * @param string $id * @return void */ - public function view($id = null) { - $this->loadModel('Config'); - $configs = $this->Config->find('list', array( - 'fields' => array('Name', 'Value'), - 'conditions' => array('Name' => array('ZM_DIR_EVENTS')) - )); + public function view($id = null) +{ + $this->loadModel('Config'); + $configs = $this->Config->find('list', array( + 'fields' => array('Name', 'Value'), + 'conditions' => array('Name' => array('ZM_DIR_EVENTS')) + )); - $this->Event->recursive = 1; - if (!$this->Event->exists($id)) { - throw new NotFoundException(__('Invalid event')); - } - $options = array('conditions' => array('Event.' . $this->Event->primaryKey => $id)); - $event = $this->Event->find('first', $options); + $this->Event->recursive = 1; + if (!$this->Event->exists($id)) { + throw new NotFoundException(__('Invalid event')); + } - $path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/'; - $event['Event']['BasePath'] = $path; + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); - # Get the previous and next events for any monitor - $this->Event->id = $id; + if (!empty($allowedMonitors)) + { + $mon_options = array('Event.MonitorId' => $allowedMonitors); + } + else + { + $mon_options=''; + } + + $options = array('conditions' => array(array('Event.' . $this->Event->primaryKey => $id), $mon_options)); + $event = $this->Event->find('first', $options); + + $path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/'; + $event['Event']['BasePath'] = $path; + + # Get the previous and next events for any monitor + $this->Event->id = $id; $event_neighbors = $this->Event->find('neighbors'); - $event['Event']['Next'] = $event_neighbors['next']['Event']['Id']; - $event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id']; + $event['Event']['Next'] = $event_neighbors['next']['Event']['Id']; + $event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id']; - # Also get the previous and next events for the same monitor - $event_monitor_neighbors = $this->Event->find('neighbors', array( + # Also get the previous and next events for the same monitor + $event_monitor_neighbors = $this->Event->find('neighbors', array( 'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId']) - )); - $event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id']; - $event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id']; + )); + $event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id']; + $event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id']; + + $this->set(array( + 'event' => $event, + '_serialize' => array('event') + )); + } - $this->set(array( - 'event' => $event, - '_serialize' => array('event') - )); - } /** * add method @@ -113,6 +150,13 @@ class EventsController extends AppController { * @return void */ public function add() { + + if ($this->Session->Read('eventPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + if ($this->request->is('post')) { $this->Event->create(); if ($this->Event->save($this->request->data)) { @@ -131,6 +175,13 @@ class EventsController extends AppController { * @return void */ public function edit($id = null) { + + if ($this->Session->Read('eventPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + $this->Event->id = $id; if (!$this->Event->exists($id)) { @@ -157,15 +208,19 @@ class EventsController extends AppController { * @return void */ public function delete($id = null) { + if ($this->Session->Read('eventPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } $this->Event->id = $id; if (!$this->Event->exists()) { throw new NotFoundException(__('Invalid event')); } $this->request->allowMethod('post', 'delete'); if ($this->Event->delete()) { - // PP - lets make sure the frame table entry is removed too - $this->loadModel('Frame'); - $this->Frame->delete(); + //$this->loadModel('Frame'); + //$this->Event->Frame->delete(); return $this->flash(__('The event has been deleted.'), array('action' => 'index')); } else { return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index')); diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index ee5ecd30f..57b210a7e 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -101,7 +101,10 @@ class HostController extends AppController { function getVersion() { $version = Configure::read('ZM_VERSION'); - $apiversion = Configure::read('ZM_API_VERSION'); + // not going to use the ZM_API_VERSION + // requires recompilation and dependency on ZM upgrade + //$apiversion = Configure::read('ZM_API_VERSION'); + $apiversion = '1.0'; $this->set(array( 'version' => $version, diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index 3aeb31aa8..9ab7461f9 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -16,6 +16,19 @@ class MonitorsController extends AppController { */ public $components = array('Paginator', 'RequestHandler'); + +public function beforeFilter() { + parent::beforeFilter(); + $canView = $this->Session->Read('monitorPermission'); + if ($canView =='None') + { + throw new UnauthorizedException(__('Insufficient Privileges')); + return; + } + +} + + /** * index method * @@ -23,7 +36,17 @@ class MonitorsController extends AppController { */ public function index() { $this->Monitor->recursive = 0; - $monitors = $this->Monitor->find('all'); + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); + + if (!empty($allowedMonitors)) + { + $options = array('conditions'=>array('Monitor.Id'=> $allowedMonitors)); + } + else + { + $options=''; + } + $monitors = $this->Monitor->find('all',$options); $this->set(array( 'monitors' => $monitors, '_serialize' => array('monitors') @@ -42,7 +65,21 @@ class MonitorsController extends AppController { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - $options = array('conditions' => array('Monitor.' . $this->Monitor->primaryKey => $id)); + $allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY); + if (!empty($allowedMonitors)) + { + $restricted = array('Monitor.' . $this->Monitor->primaryKey => $allowedMonitors); + } + else + { + $restricted = ''; + } + + $options = array('conditions' => array( + array('Monitor.' . $this->Monitor->primaryKey => $id), + $restricted + ) + ); $monitor = $this->Monitor->find('first', $options); $this->set(array( 'monitor' => $monitor, @@ -57,6 +94,13 @@ class MonitorsController extends AppController { */ public function add() { if ($this->request->is('post')) { + + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthotizedException(__('Insufficient privileges')); + return; + } + $this->Monitor->create(); if ($this->Monitor->save($this->request->data)) { $this->daemonControl($this->Monitor->id, 'start', $this->request->data); @@ -78,7 +122,11 @@ class MonitorsController extends AppController { if (!$this->Monitor->exists($id)) { throw new NotFoundException(__('Invalid monitor')); } - + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } if ($this->Monitor->save($this->request->data)) { $message = 'Saved'; } else { @@ -89,9 +137,8 @@ class MonitorsController extends AppController { 'message' => $message, '_serialize' => array('message') )); - // PP - restart this monitor after change - $this->daemonControl($this->Monitor->id, 'restart', $this->request->data); - + // - restart this monitor after change + $this->daemonControl($this->Monitor->id, 'restart', $this->request->data); } /** @@ -106,6 +153,11 @@ class MonitorsController extends AppController { if (!$this->Monitor->exists()) { throw new NotFoundException(__('Invalid monitor')); } + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } $this->request->allowMethod('post', 'delete'); $this->daemonControl($this->Monitor->id, 'stop'); diff --git a/web/api/app/Model/User.php b/web/api/app/Model/User.php new file mode 100644 index 000000000..8ef18d131 --- /dev/null +++ b/web/api/app/Model/User.php @@ -0,0 +1,31 @@ + $v) { + $this->{$k} = $v; + } + if ( $this->{'Controllable'} ) { + $s = dbFetchOne( 'SELECT * FROM Controls WHERE Id=?', NULL, array( $this->{'ControlId'} ) ); + foreach ($s as $k => $v) { + if ( $k == 'Id' ) { + continue; + } + $this->{$k} = $v; + } + } + + } else { + Error("No row for Monitor " . $IdOrRow ); + } + } // end function __construct + public function Server() { + return new Server( $this->{'ServerId'} ); + } + public function __call( $fn, array $args){ + if(isset($this->{$fn})){ + return $this->{$fn}; + #array_unshift($args, $this); + #call_user_func_array( $this->{$fn}, $args); + } + } + public function getStreamSrc( $args, $querySep='&' ) { + if ( isset($this->{'ServerId'}) and $this->{'ServerId'} ) { + $Server = new Server( $this->{'ServerId'} ); + $streamSrc = ZM_BASE_PROTOCOL.'://'.$Server->Hostname().ZM_PATH_ZMS; + } else { + $streamSrc = ZM_BASE_URL.ZM_PATH_ZMS; + } + + $args[] = "monitor=".$this->{'Id'}; + + if ( ZM_OPT_USE_AUTH ) { + if ( ZM_AUTH_RELAY == "hashed" ) { + $args[] = "auth=".generateAuthHash( ZM_AUTH_HASH_IPS ); + } elseif ( ZM_AUTH_RELAY == "plain" ) { + $args[] = "user=".$_SESSION['username']; + $args[] = "pass=".$_SESSION['password']; + } elseif ( ZM_AUTH_RELAY == "none" ) { + $args[] = "user=".$_SESSION['username']; + } + } + if ( !in_array( "mode=single", $args ) && !empty($GLOBALS['connkey']) ) { + $args[] = "connkey=".$GLOBALS['connkey']; + } + if ( ZM_RAND_STREAM ) { + $args[] = "rand=".time(); + } + + if ( count($args) ) { + $streamSrc .= "?".join( $querySep, $args ); + } + + return( $streamSrc ); + } // end function etStreamSrc +} +?> diff --git a/web/includes/Server.php b/web/includes/Server.php new file mode 100644 index 000000000..e8402809c --- /dev/null +++ b/web/includes/Server.php @@ -0,0 +1,57 @@ + $v) { + $this->{$k} = $v; + } + } else { + $this->{'Name'} = ''; + $this->{'Hostname'} = ''; + } + } + public static function find_all() { + $servers = array(); + $result = dbQuery( 'SELECT * FROM Servers ORDER BY Name'); + $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Server' ); + foreach ( $results as $row => $server_obj ) { + $servers[] = $server_obj; + } + return $servers; + } + + public function Url() { + if ( $this->Id() ) { + return ZM_BASE_PROTOCOL . '://'. $this->Hostname(); + } else { + return ''; + } + } + public function Hostname() { + if ( isset( $this->{'Hostname'} ) and ( $this->{'Hostname'} != '' ) ) { + return $this->{'Hostname'}; + } + 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); + } + } +} +?> diff --git a/web/includes/actions.php b/web/includes/actions.php index 6d94bafb2..7de7a8238 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -246,13 +246,14 @@ if ( !empty($action) ) if ( !empty($_REQUEST['mid']) && canView( 'Control', $_REQUEST['mid'] ) ) { require_once( 'control_functions.php' ); + require_once( 'Monitor.php' ); $mid = validInt($_REQUEST['mid']); if ( $action == "control" ) { - $monitor = dbFetchOne( "select C.*,M.* from Monitors as M inner join Controls as C on (M.ControlId = C.Id) where M.Id = ?", NULL, array($mid) ); + $monitor = new Monitor( $mid ); $ctrlCommand = buildControlCommand( $monitor ); - sendControlCommand( $monitor['Id'], $ctrlCommand ); + sendControlCommand( $monitor->Id(), $ctrlCommand ); } elseif ( $action == "settings" ) { @@ -768,7 +769,7 @@ if ( !empty($action) ) { if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'server' ) ) { - if ( $action == "save" ) { + if ( $action == "Save" ) { if ( !empty($_REQUEST['id']) ) $dbServer = dbFetchOne( "SELECT * FROM Servers WHERE Id=?", NULL, array($_REQUEST['id']) ); else @@ -792,6 +793,8 @@ if ( !empty($action) ) dbQuery( "DELETE FROM Servers WHERE Id=?", array($Id) ); } $refreshParent = true; + } else { + Error( "Unknown action $action in saving Server" ); } } else if ( $action == "version" && isset($_REQUEST['option']) ) diff --git a/web/includes/config.php.in b/web/includes/config.php.in index 4378ef1ec..466e195f2 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -167,4 +167,25 @@ function loadConfig( $defineConsts=true ) //print_r( $configCats ); } +require_once( 'logger.php' ); +// For Human-readability, user ZM_SERVER in zm.conf, and convert it here to a ZM_SERVER_ID +if ( ! defined('ZM_SERVER_ID') ) { + if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) { + $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_NAME)); + if ( ! $server_id ) { + Error("ZM_SERVER_NAME set to " . ZM_SERVER_NAME . " in config, but not found in Servers table."); + } else { + define( 'ZM_SERVER_ID', $server_id ); + } + } else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) { + $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_HOST)); + if ( ! $server_id ) { + Error("ZM_SERVER_HOST set to " . ZM_SERVER_HOST . " in config, but not found in Servers table."); + } else { + define( 'ZM_SERVER_ID', $server_id ); + } + } +} + + ?> diff --git a/web/includes/control_functions.php b/web/includes/control_functions.php index dcb829296..dfbc8cb3e 100644 --- a/web/includes/control_functions.php +++ b/web/includes/control_functions.php @@ -20,9 +20,9 @@ function buildControlCommand( $monitor ) case 'focus' : { $factor = $_REQUEST['yge']/100; - if ( $monitor['HasFocusSpeed'] ) + if ( $monitor->HasFocusSpeed() ) { - $speed = intval(round($monitor['MinFocusSpeed']+(($monitor['MaxFocusSpeed']-$monitor['MinFocusSpeed'])*$factor))); + $speed = intval(round($monitor->MinFocusSpeed()+(($monitor->MaxFocusSpeed()-$monitor->MinFocusSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -30,15 +30,15 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinFocusStep']+(($monitor['MaxFocusStep']-$monitor['MinFocusStep'])*$factor))); + $step = intval(round($monitor->MinFocusStep()+(($monitor->MaxFocusStep()-$monitor->MinFocusStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } case 'Con' : { - if ( $monitor['AutoStopTimeout'] ) + if ( $monitor->AutoStopTimeout() ) { - $slowSpeed = intval(round($monitor['MinFocusSpeed']+(($monitor['MaxFocusSpeed']-$monitor['MinFocusSpeed'])*$slow))); + $slowSpeed = intval(round($monitor->MinFocusSpeed()+(($monitor->MaxFocusSpeed()-$monitor->MinFocusSpeed())*$slow))); if ( $speed < $slowSpeed ) { $ctrlCommand .= " --autostop"; @@ -52,9 +52,9 @@ function buildControlCommand( $monitor ) case 'zoom' : { $factor = $_REQUEST['yge']/100; - if ( $monitor['HasZoomSpeed'] ) + if ( $monitor->HasZoomSpeed() ) { - $speed = intval(round($monitor['MinZoomSpeed']+(($monitor['MaxZoomSpeed']-$monitor['MinZoomSpeed'])*$factor))); + $speed = intval(round($monitor->MinZoomSpeed()+(($monitor->MaxZoomSpeed()-$monitor->MinZoomSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -62,15 +62,15 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinZoomStep']+(($monitor['MaxZoomStep']-$monitor['MinZoomStep'])*$factor))); + $step = intval(round($monitor->MinZoomStep()+(($monitor->MaxZoomStep()-$monitor->MinZoomStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } case 'Con' : { - if ( $monitor['AutoStopTimeout'] ) + if ( $monitor->AutoStopTimeout() ) { - $slowSpeed = intval(round($monitor['MinZoomSpeed']+(($monitor['MaxZoomSpeed']-$monitor['MinZoomSpeed'])*$slow))); + $slowSpeed = intval(round($monitor->MinZoomSpeed()+(($monitor->MaxZoomSpeed()-$monitor->MinZoomSpeed())*$slow))); if ( $speed < $slowSpeed ) { $ctrlCommand .= " --autostop"; @@ -84,9 +84,9 @@ function buildControlCommand( $monitor ) case 'iris' : { $factor = $_REQUEST['yge']/100; - if ( $monitor['HasIrisSpeed'] ) + if ( $monitor->HasIrisSpeed() ) { - $speed = intval(round($monitor['MinIrisSpeed']+(($monitor['MaxIrisSpeed']-$monitor['MinIrisSpeed'])*$factor))); + $speed = intval(round($monitor->MinIrisSpeed()+(($monitor->MaxIrisSpeed()-$monitor->MinIrisSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -94,7 +94,7 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinIrisStep']+(($monitor['MaxIrisStep']-$monitor['MinIrisStep'])*$factor))); + $step = intval(round($monitor->MinIrisStep()+(($monitor->MaxIrisStep()-$monitor->MinIrisStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } @@ -104,9 +104,9 @@ function buildControlCommand( $monitor ) case 'white' : { $factor = $_REQUEST['yge']/100; - if ( $monitor['HasWhiteSpeed'] ) + if ( $monitor->HasWhiteSpeed() ) { - $speed = intval(round($monitor['MinWhiteSpeed']+(($monitor['MaxWhiteSpeed']-$monitor['MinWhiteSpeed'])*$factor))); + $speed = intval(round($monitor->MinWhiteSpeed()+(($monitor->MaxWhiteSpeed()-$monitor->MinWhiteSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -114,7 +114,7 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinWhiteStep']+(($monitor['MaxWhiteStep']-$monitor['MinWhiteStep'])*$factor))); + $step = intval(round($monitor->MinWhiteStep()+(($monitor->MaxWhiteStep()-$monitor->MinWhiteStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } @@ -124,9 +124,9 @@ function buildControlCommand( $monitor ) case 'gain' : { $factor = $_REQUEST['yge']/100; - if ( $monitor['HasGainSpeed'] ) + if ( $monitor->HasGainSpeed() ) { - $speed = intval(round($monitor['MinGainSpeed']+(($monitor['MaxGainSpeed']-$monitor['MinGainSpeed'])*$factor))); + $speed = intval(round($monitor->MinGainSpeed()+(($monitor->MaxGainSpeed()-$monitor->MinGainSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -134,7 +134,7 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinGainStep']+(($monitor['MaxGainStep']-$monitor['MinGainStep'])*$factor))); + $step = intval(round($monitor->MinGainStep()+(($monitor->MaxGainStep()-$monitor->MinGainStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } @@ -146,7 +146,7 @@ function buildControlCommand( $monitor ) $xFactor = empty($_REQUEST['xge'])?0:$_REQUEST['xge']/100; $yFactor = empty($_REQUEST['yge'])?0:$_REQUEST['yge']/100; - if ( $monitor['Orientation'] != '0' ) + if ( $monitor->Orientation() != '0' ) { $conversions = array( '90' => array( @@ -200,48 +200,48 @@ function buildControlCommand( $monitor ) 'DownRight' => 'UpRight', ), ); - $new_dirn = $conversions[$monitor['Orientation']][$dirn]; + $new_dirn = $conversions[$monitor->Orientation()][$dirn]; $_REQUEST['control'] = preg_replace( "/_$dirn\$/", "_$new_dirn", $_REQUEST['control'] ); $dirn = $new_dirn; } - if ( $monitor['HasPanSpeed'] && $xFactor ) + if ( $monitor->HasPanSpeed() && $xFactor ) { - if ( $monitor['HasTurboPan'] ) + if ( $monitor->HasTurboPan() ) { if ( $xFactor >= $turbo ) { - $panSpeed = $monitor['TurboPanSpeed']; + $panSpeed = $monitor->TurboPanSpeed(); } else { $xFactor = $xFactor/$turbo; - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } } else { - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } $ctrlCommand .= " --panspeed=".$panSpeed; } - if ( $monitor['HasTiltSpeed'] && $yFactor ) + if ( $monitor->HasTiltSpeed() && $yFactor ) { - if ( $monitor['HasTurboTilt'] ) + if ( $monitor->HasTurboTilt() ) { if ( $yFactor >= $turbo ) { - $tiltSpeed = $monitor['TurboTiltSpeed']; + $tiltSpeed = $monitor->TurboTiltSpeed(); } else { $yFactor = $yFactor/$turbo; - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } } else { - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } $ctrlCommand .= " --tiltspeed=".$tiltSpeed; } @@ -252,22 +252,22 @@ function buildControlCommand( $monitor ) { if ( preg_match( '/(Left|Right)$/', $dirn ) ) { - $panStep = intval(round($monitor['MinPanStep']+(($monitor['MaxPanStep']-$monitor['MinPanStep'])*$xFactor))); + $panStep = intval(round($monitor->MinPanStep()+(($monitor->MaxPanStep()-$monitor->MinPanStep())*$xFactor))); $ctrlCommand .= " --panstep=".$panStep; } if ( preg_match( '/^(Up|Down)/', $dirn ) ) { - $tiltStep = intval(round($monitor['MinTiltStep']+(($monitor['MaxTiltStep']-$monitor['MinTiltStep'])*$yFactor))); + $tiltStep = intval(round($monitor->MinTiltStep()+(($monitor->MaxTiltStep()-$monitor->MinTiltStep())*$yFactor))); $ctrlCommand .= " --tiltstep=".$tiltStep; } break; } case 'Con' : { - if ( $monitor['AutoStopTimeout'] ) + if ( $monitor->AutoStopTimeout() ) { - $slowPanSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$slow))); - $slowTiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$slow))); + $slowPanSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$slow))); + $slowTiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$slow))); if ( (!isset($panSpeed) || ($panSpeed < $slowPanSpeed)) && (!isset($tiltSpeed) || ($tiltSpeed < $slowTiltSpeed)) ) { $ctrlCommand .= " --autostop"; @@ -286,22 +286,22 @@ function buildControlCommand( $monitor ) { $x = deScale( $_REQUEST['x'], $_REQUEST['scale'] ); $y = deScale( $_REQUEST['y'], $_REQUEST['scale'] ); - switch ( $monitor['Orientation'] ) + switch ( $monitor->Orientation() ) { case '0' : case '180' : case 'hori' : case 'vert' : - $width = $monitor['Width']; - $height = $monitor['Height']; + $width = $monitor->Width(); + $height = $monitor->Height(); break; case '90' : case '270' : - $width = $monitor['Height']; - $height = $monitor['Width']; + $width = $monitor->Height(); + $height = $monitor->Width(); break; } - switch ( $monitor['Orientation'] ) + switch ( $monitor->Orientation() ) { case '90' : $tempY = $y; @@ -332,12 +332,12 @@ function buildControlCommand( $monitor ) $x = deScale( $_REQUEST['x'], $_REQUEST['scale'] ); $y = deScale( $_REQUEST['y'], $_REQUEST['scale'] ); - $halfWidth = $monitor['Width'] / 2; - $halfHeight = $monitor['Height'] / 2; + $halfWidth = $monitor->Width() / 2; + $halfHeight = $monitor->Height() / 2; $xFactor = ($x - $halfWidth)/$halfWidth; $yFactor = ($y - $halfHeight)/$halfHeight; - switch ( $monitor['Orientation'] ) + switch ( $monitor->Orientation() ) { case '90' : $tempYFactor = $y; @@ -396,52 +396,52 @@ function buildControlCommand( $monitor ) $xFactor = abs($xFactor); $yFactor = abs($yFactor); - if ( $monitor['HasPanSpeed'] && $xFactor ) + if ( $monitor->HasPanSpeed() && $xFactor ) { - if ( $monitor['HasTurboPan'] ) + if ( $monitor->HasTurboPan() ) { if ( $xFactor >= $turbo ) { - $panSpeed = $monitor['TurboPanSpeed']; + $panSpeed = $monitor->TurboPanSpeed(); } else { $xFactor = $xFactor/$turbo; - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } } else { - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } } - if ( $monitor['HasTiltSpeed'] && $yFactor ) + if ( $monitor->HasTiltSpeed() && $yFactor ) { - if ( $monitor['HasTurboTilt'] ) + if ( $monitor->HasTurboTilt() ) { if ( $yFactor >= $turbo ) { - $tiltSpeed = $monitor['TurboTiltSpeed']; + $tiltSpeed = $monitor->TurboTiltSpeed(); } else { $yFactor = $yFactor/$turbo; - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } } else { - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } } if ( preg_match( '/(Left|Right)$/', $dirn ) ) { - $panStep = intval(round($monitor['MinPanStep']+(($monitor['MaxPanStep']-$monitor['MinPanStep'])*$xFactor))); + $panStep = intval(round($monitor->MinPanStep()+(($monitor->MaxPanStep()-$monitor->MinPanStep())*$xFactor))); $ctrlCommand .= " --panstep=".$panStep." --panspeed=".$panSpeed; } if ( preg_match( '/^(Up|Down)/', $dirn ) ) { - $tiltStep = intval(round($monitor['MinTiltStep']+(($monitor['MaxTiltStep']-$monitor['MinTiltStep'])*$yFactor))); + $tiltStep = intval(round($monitor->MinTiltStep()+(($monitor->MaxTiltStep()-$monitor->MinTiltStep())*$yFactor))); $ctrlCommand .= " --tiltstep=".$tiltStep." --tiltspeed=".$tiltSpeed; } } @@ -451,12 +451,12 @@ function buildControlCommand( $monitor ) $x = deScale( $_REQUEST['x'], $_REQUEST['scale'] ); $y = deScale( $_REQUEST['y'], $_REQUEST['scale'] ); - $halfWidth = $monitor['Width'] / 2; - $halfHeight = $monitor['Height'] / 2; + $halfWidth = $monitor->Width() / 2; + $halfHeight = $monitor->Height() / 2; $xFactor = ($x - $halfWidth)/$halfWidth; $yFactor = ($y - $halfHeight)/$halfHeight; - switch ( $monitor['Orientation'] ) + switch ( $monitor->Orientation() ) { case '90' : $tempYFactor = $y; @@ -515,42 +515,42 @@ function buildControlCommand( $monitor ) $xFactor = abs($xFactor); $yFactor = abs($yFactor); - if ( $monitor['HasPanSpeed'] && $xFactor ) + if ( $monitor->HasPanSpeed() && $xFactor ) { - if ( $monitor['HasTurboPan'] ) + if ( $monitor->HasTurboPan() ) { if ( $xFactor >= $turbo ) { - $panSpeed = $monitor['TurboPanSpeed']; + $panSpeed = $monitor->TurboPanSpeed(); } else { $xFactor = $xFactor/$turbo; - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } } else { - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } } - if ( $monitor['HasTiltSpeed'] && $yFactor ) + if ( $monitor->HasTiltSpeed() && $yFactor ) { - if ( $monitor['HasTurboTilt'] ) + if ( $monitor->HasTurboTilt() ) { if ( $yFactor >= $turbo ) { - $tiltSpeed = $monitor['TurboTiltSpeed']; + $tiltSpeed = $monitor->TurboTiltSpeed(); } else { $yFactor = $yFactor/$turbo; - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } } else { - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } } if ( preg_match( '/(Left|Right)$/', $dirn ) ) @@ -561,10 +561,10 @@ function buildControlCommand( $monitor ) { $ctrlCommand .= " --tiltspeed=".$tiltSpeed; } - if ( $monitor['AutoStopTimeout'] ) + if ( $monitor->AutoStopTimeout() ) { - $slowPanSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$slow))); - $slowTiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$slow))); + $slowPanSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$slow))); + $slowTiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$slow))); if ( (!isset($panSpeed) || ($panSpeed < $slowPanSpeed)) && (!isset($tiltSpeed) || ($tiltSpeed < $slowTiltSpeed)) ) { $ctrlCommand .= " --autostop"; @@ -603,9 +603,9 @@ function buildControlCommand( $monitor ) break; } } - if ( $monitor['HasFocusSpeed'] ) + if ( $monitor->HasFocusSpeed() ) { - $speed = intval(round($monitor['MinFocusSpeed']+(($monitor['MaxFocusSpeed']-$monitor['MinFocusSpeed'])*$factor))); + $speed = intval(round($monitor->MinFocusSpeed()+(($monitor->MaxFocusSpeed()-$monitor->MinFocusSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -613,15 +613,15 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinFocusStep']+(($monitor['MaxFocusStep']-$monitor['MinFocusStep'])*$factor))); + $step = intval(round($monitor->MinFocusStep()+(($monitor->MaxFocusStep()-$monitor->MinFocusStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } case 'Con' : { - if ( $monitor['AutoStopTimeout'] ) + if ( $monitor->AutoStopTimeout() ) { - $slowSpeed = intval(round($monitor['MinFocusSpeed']+(($monitor['MaxFocusSpeed']-$monitor['MinFocusSpeed'])*$slow))); + $slowSpeed = intval(round($monitor->MinFocusSpeed()+(($monitor->MaxFocusSpeed()-$monitor->MinFocusSpeed())*$slow))); if ( $speed < $slowSpeed ) { $ctrlCommand .= " --autostop"; @@ -647,9 +647,9 @@ function buildControlCommand( $monitor ) break; } } - if ( $monitor['HasZoomSpeed'] ) + if ( $monitor->HasZoomSpeed() ) { - $speed = intval(round($monitor['MinZoomSpeed']+(($monitor['MaxZoomSpeed']-$monitor['MinZoomSpeed'])*$factor))); + $speed = intval(round($monitor->MinZoomSpeed()+(($monitor->MaxZoomSpeed()-$monitor->MinZoomSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -657,15 +657,15 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinZoomStep']+(($monitor['MaxZoomStep']-$monitor['MinZoomStep'])*$factor))); + $step = intval(round($monitor->MinZoomStep()+(($monitor->MaxZoomStep()-$monitor->MinZoomStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } case 'Con' : { - if ( $monitor['AutoStopTimeout'] ) + if ( $monitor->AutoStopTimeout() ) { - $slowSpeed = intval(round($monitor['MinZoomSpeed']+(($monitor['MaxZoomSpeed']-$monitor['MinZoomSpeed'])*$slow))); + $slowSpeed = intval(round($monitor->MinZoomSpeed()+(($monitor->MaxZoomSpeed()-$monitor->MinZoomSpeed())*$slow))); if ( $speed < $slowSpeed ) { $ctrlCommand .= " --autostop"; @@ -691,9 +691,9 @@ function buildControlCommand( $monitor ) break; } } - if ( $monitor['HasIrisSpeed'] ) + if ( $monitor->HasIrisSpeed() ) { - $speed = intval(round($monitor['MinIrisSpeed']+(($monitor['MaxIrisSpeed']-$monitor['MinIrisSpeed'])*$factor))); + $speed = intval(round($monitor->MinIrisSpeed()+(($monitor->MaxIrisSpeed()-$monitor->MinIrisSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -701,7 +701,7 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinIrisStep']+(($monitor['MaxIrisStep']-$monitor['MinIrisStep'])*$factor))); + $step = intval(round($monitor->MinIrisStep()+(($monitor->MaxIrisStep()-$monitor->MinIrisStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } @@ -723,9 +723,9 @@ function buildControlCommand( $monitor ) break; } } - if ( $monitor['HasWhiteSpeed'] ) + if ( $monitor->HasWhiteSpeed() ) { - $speed = intval(round($monitor['MinWhiteSpeed']+(($monitor['MaxWhiteSpeed']-$monitor['MinWhiteSpeed'])*$factor))); + $speed = intval(round($monitor->MinWhiteSpeed()+(($monitor->MaxWhiteSpeed()-$monitor->MinWhiteSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -733,7 +733,7 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinWhiteStep']+(($monitor['MaxWhiteStep']-$monitor['MinWhiteStep'])*$factor))); + $step = intval(round($monitor->MinWhiteStep()+(($monitor->MaxWhiteStep()-$monitor->MinWhiteStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } @@ -755,9 +755,9 @@ function buildControlCommand( $monitor ) break; } } - if ( $monitor['HasGainSpeed'] ) + if ( $monitor->HasGainSpeed() ) { - $speed = intval(round($monitor['MinGainSpeed']+(($monitor['MaxGainSpeed']-$monitor['MinGainSpeed'])*$factor))); + $speed = intval(round($monitor->MinGainSpeed()+(($monitor->MaxGainSpeed()-$monitor->MinGainSpeed())*$factor))); $ctrlCommand .= " --speed=".$speed; } switch( $mode ) @@ -765,7 +765,7 @@ function buildControlCommand( $monitor ) case 'Abs' : case 'Rel' : { - $step = intval(round($monitor['MinGainStep']+(($monitor['MaxGainStep']-$monitor['MinGainStep'])*$factor))); + $step = intval(round($monitor->MinGainStep()+(($monitor->MaxGainStep()-$monitor->MinGainStep())*$factor))); $ctrlCommand .= " --step=".$step; break; } @@ -794,7 +794,7 @@ function buildControlCommand( $monitor ) $xFactor = ($x+1)/$short_x; } - if ( $monitor['Orientation'] != '0' ) + if ( $monitor->Orientation() != '0' ) { $conversions = array( '90' => array( @@ -848,48 +848,48 @@ function buildControlCommand( $monitor ) 'DownRight' => 'UpRight', ), ); - $new_dirn = $conversions[$monitor['Orientation']][$dirn]; + $new_dirn = $conversions[$monitor->Orientation()][$dirn]; $_REQUEST['control'] = preg_replace( "/_$dirn\$/", "_$new_dirn", $_REQUEST['control'] ); $dirn = $new_dirn; } - if ( $monitor['HasPanSpeed'] && $xFactor ) + if ( $monitor->HasPanSpeed() && $xFactor ) { - if ( $monitor['HasTurboPan'] ) + if ( $monitor->HasTurboPan() ) { if ( $xFactor >= $turbo ) { - $panSpeed = $monitor['TurboPanSpeed']; + $panSpeed = $monitor->TurboPanSpeed(); } else { $xFactor = $xFactor/$turbo; - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } } else { - $panSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$xFactor))); + $panSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$xFactor))); } $ctrlCommand .= " --panspeed=".$panSpeed; } - if ( $monitor['HasTiltSpeed'] && $yFactor ) + if ( $monitor->HasTiltSpeed() && $yFactor ) { - if ( $monitor['HasTurboTilt'] ) + if ( $monitor->HasTurboTilt() ) { if ( $yFactor >= $turbo ) { - $tiltSpeed = $monitor['TurboTiltSpeed']; + $tiltSpeed = $monitor->TurboTiltSpeed(); } else { $yFactor = $yFactor/$turbo; - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } } else { - $tiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$yFactor))); + $tiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$yFactor))); } $ctrlCommand .= " --tiltspeed=".$tiltSpeed; } @@ -900,22 +900,22 @@ function buildControlCommand( $monitor ) { if ( preg_match( '/(Left|Right)$/', $dirn ) ) { - $panStep = intval(round($monitor['MinPanStep']+(($monitor['MaxPanStep']-$monitor['MinPanStep'])*$xFactor))); + $panStep = intval(round($monitor->MinPanStep()+(($monitor->MaxPanStep()-$monitor->MinPanStep())*$xFactor))); $ctrlCommand .= " --panstep=".$panStep; } if ( preg_match( '/^(Up|Down)/', $dirn ) ) { - $tiltStep = intval(round($monitor['MinTiltStep']+(($monitor['MaxTiltStep']-$monitor['MinTiltStep'])*$yFactor))); + $tiltStep = intval(round($monitor->MinTiltStep()+(($monitor->MaxTiltStep()-$monitor->MinTiltStep())*$yFactor))); $ctrlCommand .= " --tiltstep=".$tiltStep; } break; } case 'Con' : { - if ( $monitor['AutoStopTimeout'] ) + if ( $monitor->AutoStopTimeout() ) { - $slowPanSpeed = intval(round($monitor['MinPanSpeed']+(($monitor['MaxPanSpeed']-$monitor['MinPanSpeed'])*$slow))); - $slowTiltSpeed = intval(round($monitor['MinTiltSpeed']+(($monitor['MaxTiltSpeed']-$monitor['MinTiltSpeed'])*$slow))); + $slowPanSpeed = intval(round($monitor->MinPanSpeed()+(($monitor->MaxPanSpeed()-$monitor->MinPanSpeed())*$slow))); + $slowTiltSpeed = intval(round($monitor->MinTiltSpeed()+(($monitor->MaxTiltSpeed()-$monitor->MinTiltSpeed())*$slow))); if ( (!isset($panSpeed) || ($panSpeed < $slowPanSpeed)) && (!isset($tiltSpeed) || ($tiltSpeed < $slowTiltSpeed)) ) { $ctrlCommand .= " --autostop"; @@ -943,12 +943,12 @@ function buildControlCommand( $monitor ) if ( canEdit( 'Control' ) ) { $preset = validInt($_REQUEST['preset']); $newLabel = validJsStr($_REQUEST['newLabel']); - $row = dbFetchOne( 'SELECT * FROM ControlPresets WHERE MonitorId = ? AND Preset = ?', NULL, array( $monitor['Id'], $preset ) ); + $row = dbFetchOne( 'SELECT * FROM ControlPresets WHERE MonitorId = ? AND Preset = ?', NULL, array( $monitor->Id(), $preset ) ); if ( $newLabel != $row['Label'] ) { if ( $newLabel ) { - dbQuery( 'REPLACE INTO ControlPresets ( MonitorId, Preset, Label ) VALUES ( ?, ?, ? )', array( $monitor['Id'], $preset, $newLabel ) ); + dbQuery( 'REPLACE INTO ControlPresets ( MonitorId, Preset, Label ) VALUES ( ?, ?, ? )', array( $monitor->Id(), $preset, $newLabel ) ); } else { - dbQuery( 'DELETE FROM ControlPresets WHERE MonitorId = ? AND Preset = ?', array( $monitor['Id'], $preset ) ); + dbQuery( 'DELETE FROM ControlPresets WHERE MonitorId = ? AND Preset = ?', array( $monitor->Id(), $preset ) ); } } $ctrlCommand .= " --preset=".$preset; diff --git a/web/includes/functions.php b/web/includes/functions.php index 5be2730bd..2b879689d 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -94,6 +94,30 @@ function noCacheHeaders() header("Pragma: no-cache"); // HTTP/1.0 } +function CORSHeaders() { + if ( isset( $_SERVER['HTTP_ORIGIN'] ) ) { + + # The following is left for future reference/use. + $valid = false; + $servers = dbFetchAll( 'SELECT * FROM Servers' ); + if ( sizeof($servers) <= 1 ) { + # Only need CORSHeaders in the event that there are multiple servers in use. + return; + } + foreach( dbFetchAll( 'SELECT * FROM Servers' ) as $row ) { + $Server = new Server( $row ); + if ( $_SERVER['HTTP_ORIGIN'] == $Server->Url() ) { + $valid = true; + header("Access-Control-Allow-Origin: " . $Server->Url() ); + header("Access-Control-Allow-Headers: x-requested-with,x-request"); + } + } + if ( ! $valid ) { + Warning( $_SERVER['HTTP_ORIGIN'] . " is not found in servers list." ); + } + } +} + function getAuthUser( $auth ) { if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == "hashed" && !empty($auth) ) diff --git a/web/index.php b/web/index.php index 98df13e61..72e6dc8c0 100644 --- a/web/index.php +++ b/web/index.php @@ -48,6 +48,7 @@ if ( false ) require_once( 'includes/config.php' ); require_once( 'includes/logger.php' ); +require_once( 'includes/Server.php' ); if ( isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' ) { @@ -136,6 +137,9 @@ else require_once( 'includes/lang.php' ); require_once( 'includes/functions.php' ); +# Add Cross domain access headers +CORSHeaders(); + // Check for valid content dirs if ( !is_writable(ZM_DIR_EVENTS) || !is_writable(ZM_DIR_IMAGES) ) { diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index feef1864d..3b1ec9ef3 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -87,6 +87,7 @@ $SLANG = array( 'Actual' => 'Actual', 'AddNewControl' => 'Add New Control', 'AddNewMonitor' => 'Add New Monitor', + 'AddNewServer' => 'Add New Server', 'AddNewUser' => 'Add New User', 'AddNewZone' => 'Add New Zone', 'Alarm' => 'Alarm', @@ -124,6 +125,8 @@ $SLANG = array( 'AttrMaxScore' => 'Max. Score', 'AttrMonitorId' => 'Monitor Id', 'AttrMonitorName' => 'Monitor Name', + 'AttrServerId' => 'Server Id', + 'AttrServerName' => 'Server Name', 'AttrName' => 'Name', 'AttrNotes' => 'Notes', 'AttrSystemLoad' => 'System Load', @@ -383,6 +386,7 @@ $SLANG = array( 'HighBW' => 'High B/W', 'High' => 'High', 'Home' => 'Home', + 'Hostname' => 'Hostname', 'Hour' => 'Hour', 'Hue' => 'Hue', 'Id' => 'Id', diff --git a/web/skins/classic/css/flat/skin.css b/web/skins/classic/css/flat/skin.css index 6a871c416..3a7ee575e 100644 --- a/web/skins/classic/css/flat/skin.css +++ b/web/skins/classic/css/flat/skin.css @@ -21,8 +21,6 @@ * Primary look and feel styles */ -@import url("https://fonts.googleapis.com/css?family=Open+Sans:200,200italic,300,300italic,400,400italic,600,600italic,700"); - body { font-family: "Open Sans", Verdana, Arial, Helvetica, sans-serif; font-size: 16px; diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index b09a53138..0c8c31fe4 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -30,13 +30,13 @@ function getControlCommands( $monitor ) $cmds['PresetGoto'] = "presetGoto"; $cmds['PresetHome'] = "presetHome"; - if ( !empty($monitor['CanZoom']) ) + if ( !empty($monitor->CanZoom) ) { - if ( $monitor['CanZoomCon'] ) + if ( $monitor->CanZoomCon() ) $cmds['ZoomRoot'] = "zoomCon"; - elseif ( $monitor['CanZoomRel'] ) + elseif ( $monitor->CanZoomRel() ) $cmds['ZoomRoot'] = "zoomRel"; - elseif ( $monitor['CanZoomAbs'] ) + elseif ( $monitor->CanZoomAbs() ) $cmds['ZoomRoot'] = "zoomAbs"; $cmds['ZoomTele'] = $cmds['ZoomRoot']."Tele"; $cmds['ZoomWide'] = $cmds['ZoomRoot']."Wide"; @@ -45,13 +45,13 @@ function getControlCommands( $monitor ) $cmds['ZoomMan'] = "zoomMan"; } - if ( !empty($monitor['CanFocus']) ) + if ( !empty($monitor->CanFocus) ) { - if ( $monitor['CanFocusCon'] ) + if ( $monitor->CanFocusCon() ) $cmds['FocusRoot'] = "focusCon"; - elseif ( $monitor['CanFocusRel'] ) + elseif ( $monitor->CanFocusRel() ) $cmds['FocusRoot'] = "focusRel"; - elseif ( $monitor['CanFocusAbs'] ) + elseif ( $monitor->CanFocusAbs() ) $cmds['FocusRoot'] = "focusAbs"; $cmds['FocusFar'] = $cmds['FocusRoot']."Far"; $cmds['FocusNear'] = $cmds['FocusRoot']."Near"; @@ -60,13 +60,13 @@ function getControlCommands( $monitor ) $cmds['FocusMan'] = "focusMan"; } - if ( !empty($monitor['CanIris']) ) + if ( !empty($monitor->CanIris) ) { - if ( $monitor['CanIrisCon'] ) + if ( $monitor->CanIrisCon() ) $cmds['IrisRoot'] = "irisCon"; - elseif ( $monitor['CanIrisRel'] ) + elseif ( $monitor->CanIrisRel() ) $cmds['IrisRoot'] = "irisRel"; - elseif ( $monitor['CanIrisAbs'] ) + elseif ( $monitor->CanIrisAbs() ) $cmds['IrisRoot'] = "irisAbs"; $cmds['IrisOpen'] = $cmds['IrisRoot']."Open"; $cmds['IrisClose'] = $cmds['IrisRoot']."Close"; @@ -75,13 +75,13 @@ function getControlCommands( $monitor ) $cmds['IrisMan'] = "irisMan"; } - if ( !empty($monitor['CanWhite']) ) + if ( !empty($monitor->CanWhite) ) { - if ( $monitor['CanWhiteCon'] ) + if ( $monitor->CanWhiteCon() ) $cmds['WhiteRoot'] = "whiteCon"; - elseif ( $monitor['CanWhiteRel'] ) + elseif ( $monitor->CanWhiteRel() ) $cmds['WhiteRoot'] = "whiteRel"; - elseif ( $monitor['CanWhiteAbs'] ) + elseif ( $monitor->CanWhiteAbs() ) $cmds['WhiteRoot'] = "whiteAbs"; $cmds['WhiteIn'] = $cmds['WhiteRoot']."In"; $cmds['WhiteOut'] = $cmds['WhiteRoot']."Out"; @@ -89,13 +89,13 @@ function getControlCommands( $monitor ) $cmds['WhiteMan'] = "whiteMan"; } - if ( !empty($monitor['CanGain']) ) + if ( !empty($monitor->CanGain) ) { - if ( $monitor['CanGainCon'] ) + if ( $monitor->CanGainCon() ) $cmds['GainRoot'] = "gainCon"; - elseif ( $monitor['CanGainRel'] ) + elseif ( $monitor->CanGainRel() ) $cmds['GainRoot'] = "gainRel"; - elseif ( $monitor['CanGainAbs'] ) + elseif ( $monitor->CanGainAbs() ) $cmds['GainRoot'] = "gainAbs"; $cmds['GainUp'] = $cmds['GainRoot']."Up"; $cmds['GainDown'] = $cmds['GainRoot']."Down"; @@ -103,19 +103,19 @@ function getControlCommands( $monitor ) $cmds['GainMan'] = "gainMan"; } - if ( !empty($monitor['CanMove']) ) + if ( !empty($monitor->CanMove) ) { - if ( $monitor['CanMoveCon'] ) + if ( $monitor->CanMoveCon() ) { $cmds['MoveRoot'] = "moveCon"; $cmds['Center'] = "moveStop"; } - elseif ( $monitor['CanMoveRel'] ) + elseif ( $monitor->CanMoveRel() ) { $cmds['MoveRoot'] = "moveRel"; $cmds['Center'] = $cmds['PresetHome']; } - elseif ( $monitor['CanMoveAbs'] ) + elseif ( $monitor->CanMoveAbs() ) { $cmds['MoveRoot'] = "moveAbs"; $cmds['Center'] = $cmds['PresetHome']; @@ -142,11 +142,11 @@ function controlFocus( $monitor, $cmds )
-
onclick="controlCmd('')">
+
CanFocusCon() ) { ?> onclick="controlCmd('')">
CanAutoFocus() ) { ?> @@ -168,11 +168,11 @@ function controlZoom( $monitor, $cmds )
-
onclick="controlCmd('')">
+
CanZoomCon() ) { ?> onclick="controlCmd('')">
CanAutoZoom() ) { ?> @@ -193,11 +193,11 @@ function controlIris( $monitor, $cmds )
-
onclick="controlCmd('')">
+
CanIrisCon() ) { ?> onclick="controlCmd('')">
CanAutoIris() ) { ?> @@ -219,11 +219,11 @@ function controlWhite( $monitor, $cmds )
-
onclick="controlCmd('')">
+
CanWhiteCon() ) { ?> onclick="controlCmd('')">
CanAutoWhite() ) { ?> @@ -246,9 +246,9 @@ function controlPanTilt( $monitor, $cmds )
CanPan; + $hasTilt = $monitor->CanTilt; + $hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag; ?>
@@ -271,14 +271,14 @@ function controlPresets( $monitor, $cmds ) define( "MAX_PRESETS", "12" ); - $sql = "select * from ControlPresets where MonitorId = '".$monitor['Id']."'"; + $sql = 'select * from ControlPresets where MonitorId = ?'; $labels = array(); - foreach( dbFetchAll( $sql ) as $row ) + foreach( dbFetchAll( $sql, NULL, array( $monitor->Id() ) ) as $row ) { $labels[$row['Preset']] = $row['Label']; } - $presetBreak = (int)(($monitor['NumPresets']+1)/((int)(($monitor['NumPresets']-1)/MAX_PRESETS)+1)); + $presetBreak = (int)(($monitor->NumPresets+1)/((int)(($monitor->NumPresets-1)/MAX_PRESETS)+1)); ob_start(); ?> @@ -286,7 +286,7 @@ function controlPresets( $monitor, $cmds )
NumPresets; $i++ ) { ?>" value="" onclick="controlCmd('');"/>
HasHomePreset() ) { ?> CanSetPresets() ) { ?> - + @@ -327,19 +327,19 @@ function controlPower( $monitor, $cmds )
CanWake() ) { ?> CanSleep() ) { ?> CanReset() ) { ?> @@ -359,22 +359,22 @@ function ptzControls( $monitor ) ?>
CanFocus() ) echo controlFocus( $monitor, $cmds ); - if ( $monitor['CanZoom'] ) + if ( $monitor->CanZoom() ) echo controlZoom( $monitor, $cmds ); - if ( $monitor['CanIris'] ) + if ( $monitor->CanIris() ) echo controlIris( $monitor, $cmds ); - if ( $monitor['CanWhite'] ) + if ( $monitor->CanWhite() ) echo controlWhite( $monitor, $cmds ); - if ( $monitor['CanMove'] || ( $monitor['CanWake'] || $monitor['CanSleep'] || $monitor['CanReset'] ) ) + if ( $monitor->CanMove() || ( $monitor->CanWake() || $monitor->CanSleep() || $monitor->CanReset() ) ) { ?>
CanMove() ) echo controlPanTilt( $monitor, $cmds ); - if ( $monitor['CanWake'] || $monitor['CanSleep'] || $monitor['CanReset'] ) + if ( $monitor->CanWake() || $monitor->CanSleep() || $monitor->CanReset() ) echo controlPower( $monitor, $cmds ); ?>
@@ -383,7 +383,7 @@ function ptzControls( $monitor ) ?>
HasPresets() ) echo controlPresets( $monitor, $cmds ); return( ob_get_clean() ); } diff --git a/web/skins/classic/js/dark.js b/web/skins/classic/js/dark.js index f8867feda..e99980f61 100644 --- a/web/skins/classic/js/dark.js +++ b/web/skins/classic/js/dark.js @@ -47,7 +47,7 @@ var popupSizes = { 'image': { 'addWidth': 48, 'addHeight': 80 }, 'log': { 'width': 1080, 'height': 720 }, 'login': { 'width': 720, 'height': 480 }, - 'logout': { 'width': 260, 'height': 100 }, + 'logout': { 'width': 260, 'height': 150 }, 'monitor': { 'width': 525, 'height': 700 }, 'monitorpreset':{ 'width': 440, 'height': 200 }, 'monitorprobe': { 'width': 500, 'height': 240 }, diff --git a/web/skins/classic/js/flat.js b/web/skins/classic/js/flat.js index 6d5a89bf7..8b821f816 100644 --- a/web/skins/classic/js/flat.js +++ b/web/skins/classic/js/flat.js @@ -47,8 +47,8 @@ var popupSizes = { 'image': { 'addWidth': 48, 'addHeight': 80 }, 'log': { 'width': 1080, 'height': 720 }, 'login': { 'width': 720, 'height': 480 }, - 'logout': { 'width': 260, 'height': 100 }, - 'monitor': { 'width': 525, 'height': 700 }, + 'logout': { 'width': 260, 'height': 150 }, + 'monitor': { 'width': 550, 'height': 700 }, 'monitorpreset':{ 'width': 440, 'height': 200 }, 'monitorprobe': { 'width': 500, 'height': 240 }, 'monitorselect':{ 'width': 160, 'height': 200 }, diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 647ae132c..1029e9562 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -18,6 +18,9 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // +require_once('includes/Server.php'); +$servers = Server::find_all(); + $eventCounts = array( array( "title" => translate('Events'), @@ -235,6 +238,9 @@ else
+ + + - + + + diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 1c7c6e270..870d873df 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -84,6 +84,8 @@ $attrTypes = array( 'DiskPercent' => translate('AttrDiskPercent'), 'DiskBlocks' => translate('AttrDiskBlocks'), 'SystemLoad' => translate('AttrSystemLoad'), + 'ServerId' => translate('AttrServerId'), + 'ServerName' => translate('AttrServerName'), ); $opTypes = array( '=' => translate('OpEq'), diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js index e804d18f8..e6f7fa30e 100644 --- a/web/skins/classic/views/js/log.js +++ b/web/skins/classic/views/js/log.js @@ -22,7 +22,7 @@ var logTimeout = maxSampleTime; var firstLoad = true; var initialDisplayLimit = 200; var sortReversed = false; -var filterFields = [ 'Component', 'Pid', 'Level', 'File', 'Line']; +var filterFields = [ 'Component', 'ServerId', 'Pid', 'Level', 'File', 'Line']; var options = {}; function buildFetchParms( parms ) @@ -68,7 +68,7 @@ function logResponse( respObj ) maxLogTime = log.TimeKey; if ( !minLogTime || log.TimeKey < minLogTime ) minLogTime = log.TimeKey; - var row = logTable.push( [ { content: log.DateTime, properties: { style: 'white-space: nowrap' }}, log.Component, log.Pid, log.Code, log.Message, log.File, log.Line ] ); + var row = logTable.push( [ { content: log.DateTime, properties: { style: 'white-space: nowrap' }}, log.Component, log.Server, log.Pid, log.Code, log.Message, log.File, log.Line ] ); delete log.Message; row.tr.store( 'log', log ); if ( log.Level <= -3 ) @@ -163,6 +163,12 @@ function filterLog() function( field ) { var selector = $('filter['+field+']'); + if ( ! selector ) { + if ( window.console && window.console.log ) { + window.console.log("No selector found for " + field ); + } + return; + } var value = selector.get('value'); if ( value ) filter[field] = value; @@ -244,6 +250,12 @@ function updateFilterSelectors() function( values, key ) { var selector = $('filter['+key+']'); + if ( ! selector ) { + if ( window.console && window.console.log ) { + window.console.log("No selector found for " + key ); + } + return; + } selector.options.length = 1; if ( key == 'Level' ) { @@ -253,6 +265,15 @@ function updateFilterSelectors() selector.options[selector.options.length] = new Option( value, label ); } ); + } + else if ( key == 'ServerId' ) + { + Object.each(values, + function( value, label ) + { + selector.options[selector.options.length] = new Option( value, label ); + } + ); } else { diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index 655f993ff..80f652fd5 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -31,7 +31,12 @@ var monitorData = new Array(); foreach ( $monitors as $monitor ) { ?> -monitorData[monitorData.length] = { 'id': , 'connKey': , 'width': ,'height': }; +monitorData[monitorData.length] = { + 'id': Id() ?>, + 'connKey': connKey() ?>, + 'width': Width() ?>, + 'height':Height() ?> +}; diff --git a/web/skins/classic/views/js/server.js b/web/skins/classic/views/js/server.js new file mode 100644 index 000000000..70063d1de --- /dev/null +++ b/web/skins/classic/views/js/server.js @@ -0,0 +1,14 @@ +function validateForm( form, newServer ) +{ + var errors = new Array(); + if ( !form.elements['newServer[Name]'].value ) + { + errors[errors.length] = "You must supply a name"; + } + if ( errors.length ) + { + alert( errors.join( "\n" ) ); + return( false ); + } + return( true ); +} diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index dc3f63d43..9c39c897a 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -100,7 +100,7 @@ function setAlarmState( currentAlarmState ) } var streamCmdParms = "view=request&request=stream&connkey="+connKey; -var streamCmdReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStreamCmdResponse } ); +var streamCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStreamCmdResponse } ); var streamCmdTimer = null; var streamStatus; @@ -348,7 +348,7 @@ function streamCmdQuery() } var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate"; -var statusCmdReq = new Request.JSON( { url: thisUrl, method: 'post', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } ); +var statusCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } ); var statusCmdTimer = null; function getStatusCmdResponse( respObj, respText ) @@ -377,7 +377,7 @@ function statusCmdQuery() } var alarmCmdParms = "view=request&request=alarm&id="+monitorId; -var alarmCmdReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getAlarmCmdResponse, onTimeout: streamCmdQuery } ); +var alarmCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getAlarmCmdResponse, onTimeout: streamCmdQuery } ); var alarmCmdFirst = true; function getAlarmCmdResponse( respObj, respText ) diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index f33983d9f..c5e7e316c 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -44,9 +44,11 @@ var showMode = "'; var maxDisplayEvents = ; -var monitorId = ; -var monitorWidth = ; -var monitorHeight = ; + +var monitorId = Id() ?>; +var monitorWidth = Width() ?>; +var monitorHeight = Height() ?>; +var monitorUrl = 'Server()->Url() ) ?>'; var scale = ; @@ -61,11 +63,11 @@ var canStreamNative = ; var canPlayPauseAudio = Browser.ie; - +CanMoveMap() ) { ?> var imageControlMode = "moveMap"; - +CanMoveRel() ) { ?> var imageControlMode = "movePseudoMap"; - +CanMoveCon() ) { ?> var imageControlMode = "moveConMap"; var imageControlMode = null; diff --git a/web/skins/classic/views/log.php b/web/skins/classic/views/log.php index 06e3d9a68..50ba58d42 100644 --- a/web/skins/classic/views/log.php +++ b/web/skins/classic/views/log.php @@ -54,6 +54,7 @@ xhtmlHeaders(__FILE__, translate('SystemLog') );
- + @@ -67,6 +68,7 @@ xhtmlHeaders(__FILE__, translate('SystemLog') );
+ diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index a5615bec1..bd06aa49a 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -18,6 +18,8 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // +require_once( 'includes/Server.php'); + if ( !canView( 'Monitors' ) ) { $view = "error"; @@ -41,6 +43,7 @@ if ( isset($_REQUEST['tab']) ) else $tab = "general"; + $Server = null; if ( defined( 'ZM_SERVER_ID' ) ) { $Server = dbFetchOne( 'SELECT * FROM Servers WHERE Id=?', NULL, array( ZM_SERVER_ID ) ); } @@ -672,8 +675,12 @@ switch ( $tab ) diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index d9f92805a..fc86ad64b 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -24,6 +24,8 @@ if ( !canView( 'Stream' ) ) return; } +require_once( 'includes/Monitor.php' ); + $groupSql = ""; if ( !empty($_REQUEST['group']) ) { @@ -64,7 +66,7 @@ foreach( dbFetchAll( $sql ) as $row ) $row['scaleWidth'] = $scaleWidth; $row['scaleHeight'] = $scaleHeight; $row['connKey'] = generateConnKey(); - $monitors[] = $row; + $monitors[] = new Monitor( $row ); } $focusWindow = true; @@ -107,29 +109,29 @@ if ( $showControl ) connKey(); // Minor hack if ( !isset( $scale ) ) - $scale = reScale( SCALE_BASE, $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); + $scale = reScale( SCALE_BASE, $monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE ); ?> -
-
-
+
+
+
getStreamSrc( array( "mode=mpeg", "scale=".$scale, "bitrate=".ZM_WEB_VIDEO_BITRATE, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "format=".ZM_MPEG_LIVE_FORMAT ) ); + outputVideoStream( "liveStream".$monitor->Id(), $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), ZM_MPEG_LIVE_FORMAT ); } else { - $streamSrc = getStreamSrc( array( "mode=jpeg", "monitor=".$monitor['Id'], "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS ) ); + $streamSrc = $monitor->getStreamSrc( array( "mode=jpeg", "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS ) ); if ( canStreamNative() ) { - outputImageStream( "liveStream".$monitor['Id'], $streamSrc, reScale( $monitor['Width'], $scale ), reScale( $monitor['Height'], $scale ), validHtmlStr($monitor['Name']) ); + outputImageStream( "liveStream".$monitor->Id(), $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), validHtmlStr($monitor->Name()) ); } else { - outputHelperStream( "liveStream".$monitor['Id'], $streamSrc, reScale( $monitor['Width'], $scale ), reScale( $monitor['Height'], $scale ) ); + outputHelperStream( "liveStream".$monitor->Id(), $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ) ); } } ?> @@ -138,7 +140,7 @@ else if ( !ZM_WEB_COMPACT_MONTAGE ) { ?> -
 -  fps
+
 -  fps
diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 7b24eafa7..9c3b4a418 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -221,13 +221,15 @@ elseif ( $tab == "users" )
+ - + + diff --git a/web/skins/classic/views/server.php b/web/skins/classic/views/server.php index fa57a7e97..83df0501e 100644 --- a/web/skins/classic/views/server.php +++ b/web/skins/classic/views/server.php @@ -32,6 +32,7 @@ if ( $_REQUEST['id'] ) { } else { $newServer = array(); $newServer['Name'] = translate('NewServer'); + $newServer['Hostname'] = ''; } $focusWindow = true; @@ -51,14 +52,19 @@ xhtmlHeaders(__FILE__, translate('Server')." - ".$newServer['Name'] );
'.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').'
'.translate('DateTime').''.translate('Component').''.translate('Server').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').'
%s%s%d%s%s%s%s
%s%s%s%d%s%s%s%s
+ @@ -305,6 +311,12 @@ foreach( $displayMonitors as $monitor ) ?> '.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?>Name(); + ?> '.$monitor['Device'].' ('.$monitor['Channel'].')', canEdit( 'Monitors' ) ) ?>
'None'); + $result = dbQuery( 'SELECT * FROM Servers ORDER BY Name'); + $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Server' ); + foreach ( $results as $row => $server_obj ) { + $servers[$server_obj->Id] = $server_obj->Name(); + } ?>
disabled="disabled"/>
- + + + + +
- - + + +
diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index 8a955840f..102ae41ac 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -18,61 +18,67 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // +require_once('includes/Monitor.php'); + if ( !canView( 'Stream' ) ) { $view = "error"; return; } -if ( ! visibleMonitor( $_REQUEST['mid'] ) ) { + +// This is for input sanitation +$mid = intval( $_REQUEST['mid'] ); +if ( ! visibleMonitor( $mid ) ) { $view = "error"; return; } $sql = 'SELECT C.*, M.* FROM Monitors AS M LEFT JOIN Controls AS C ON (M.ControlId = C.Id ) WHERE M.Id = ?'; -$monitor = dbFetchOne( $sql, NULL, array( $_REQUEST['mid'] ) ); +$monitor = new Monitor( $mid ); +#dbFetchOne( $sql, NULL, array( $_REQUEST['mid'] ) ); if ( isset($_REQUEST['showControls']) ) $showControls = validInt($_REQUEST['showControls']); else - $showControls = (canView( 'Control' ) && ($monitor['DefaultView'] == 'Control')); + $showControls = (canView( 'Control' ) && ($monitor->DefaultView() == 'Control')); -$showPtzControls = ( ZM_OPT_CONTROL && $monitor['Controllable'] && canView( 'Control' ) ); +$showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView( 'Control' ) ); if ( isset( $_REQUEST['scale'] ) ) $scale = validInt($_REQUEST['scale']); else - $scale = reScale( SCALE_BASE, $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); + $scale = reScale( SCALE_BASE, $monitor->DefaultScale, ZM_WEB_DEFAULT_SCALE ); $connkey = generateConnKey(); if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { $streamMode = "mpeg"; - $streamSrc = getStreamSrc( array( "mode=".$streamMode, "monitor=".$monitor['Id'], "scale=".$scale, "bitrate=".ZM_WEB_VIDEO_BITRATE, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "format=".ZM_MPEG_LIVE_FORMAT ) ); + $streamSrc = $monitor->getStreamSrc( array( "mode=".$streamMode, "scale=".$scale, "bitrate=".ZM_WEB_VIDEO_BITRATE, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "format=".ZM_MPEG_LIVE_FORMAT ) ); } elseif ( canStream() ) { $streamMode = "jpeg"; - $streamSrc = getStreamSrc( array( "mode=".$streamMode, "monitor=".$monitor['Id'], "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "buffer=".$monitor['StreamReplayBuffer'] ) ); + $streamSrc = $monitor->getStreamSrc( array( "mode=".$streamMode, "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "buffer=".$monitor->StreamReplayBuffer() ) ); } else { $streamMode = "single"; - $streamSrc = getStreamSrc( array( "mode=".$streamMode, "monitor=".$monitor['Id'], "scale=".$scale ) ); + $streamSrc = $monitor->getStreamSrc( array( "mode=".$streamMode, "scale=".$scale ) ); Info( "The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser."); } -$showDvrControls = ( $streamMode == 'jpeg' && $monitor['StreamReplayBuffer'] != 0 ); +$showDvrControls = ( $streamMode == 'jpeg' && $monitor->StreamReplayBuffer() != 0 ); noCacheHeaders(); -xhtmlHeaders( __FILE__, $monitor['Name']." - ".translate('Feed') ); +xhtmlHeaders( __FILE__, $monitor->Name()." - ".translate('Feed') ); ?>