diff --git a/.gitmodules b/.gitmodules index a42bd946b..eb0e282a2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "web/api/app/Plugin/Crud"] path = web/api/app/Plugin/Crud - url = https://github.com/FriendsOfCake/crud.git + url = https://github.com/ZoneMinder/crud.git branch = 3.0 [submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"] path = web/api/app/Plugin/CakePHP-Enum-Behavior - url = https://github.com/connortechnology/CakePHP-Enum-Behavior.git + url = https://github.com/ZoneMinder/CakePHP-Enum-Behavior.git diff --git a/.travis.yml b/.travis.yml index 52ba2d486..1ae0988d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,17 +23,27 @@ addons: - curl - sshfs - sed + - binfmt-support + - qemu + - qemu-user-static + - dnsutils + - traceroute +install: + - update-binfmts --enable qemu-arm + env: + global: + - SMPFLAGS=-j4 matrix: - - OS=el DIST=6 - - OS=el DIST=6 ARCH=i386 DOCKER_REPO=knnniggett/packpack - OS=el DIST=7 - - OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack - OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack + - OS=fedora DIST=28 DOCKER_REPO=knnniggett/packpack - OS=ubuntu DIST=trusty - OS=ubuntu DIST=xenial - OS=ubuntu DIST=trusty ARCH=i386 - OS=ubuntu DIST=xenial ARCH=i386 + - OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack + compiler: - gcc services: diff --git a/CMakeLists.txt b/CMakeLists.txt index 31f680923..854f14376 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,8 @@ if(NOT HOST_OS) "ZoneMinder was unable to deterimine the host OS. Please report this. Value of CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") endif(NOT HOST_OS) +set (CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # Default CLFAGS and CXXFLAGS: set(CMAKE_C_FLAGS_RELEASE "-Wall -D__STDC_CONSTANT_MACROS -O2") set(CMAKE_CXX_FLAGS_RELEASE "-Wall -D__STDC_CONSTANT_MACROS -O2") @@ -141,6 +143,8 @@ set(ZM_WEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/www" "Location of the web files, default: /${CMAKE_INSTALL_DATADIR}/zoneminder/www") set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH "Location of the cgi-bin files, default: /${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin") +set(ZM_CACHEDIR "/var/cache/zoneminder" CACHE PATH + "Location of the web server cache busting files, default: /var/cache/zoneminder") set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH "Location of dynamic content (events and images), default: /var/lib/zoneminder") set(ZM_DB_HOST "localhost" CACHE STRING @@ -205,7 +209,7 @@ set(ZM_PERL_SEARCH_PATH "" CACHE PATH where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path.") set(ZM_TARGET_DISTRO "" CACHE STRING - "Build ZoneMinder for a specific distribution. Currently, valid names are: fc24, fc25, el6, el7, OS13, FreeBSD") + "Build ZoneMinder for a specific distribution. Currently, valid names are: fc27, fc26, el7, OS13, FreeBSD") set(ZM_SYSTEMD "OFF" CACHE BOOL "Set to ON to force building ZM with systemd support. default: OFF") @@ -484,24 +488,24 @@ if(MP4V2_LIBRARIES) if(MP4V2_INCLUDE_DIR) include_directories("${MP4V2_INCLUDE_DIR}") set(CMAKE_REQUIRED_INCLUDES "${MP4V2_INCLUDE_DIR}") + check_include_file("mp4v2/mp4v2.h" HAVE_MP4V2_MP4V2_H) endif(MP4V2_INCLUDE_DIR) - check_include_file("mp4v2/mp4v2.h" HAVE_MP4V2_MP4V2_H) # mp4v2.h find_path(MP4V2_INCLUDE_DIR mp4v2.h) if(MP4V2_INCLUDE_DIR) include_directories("${MP4V2_INCLUDE_DIR}") set(CMAKE_REQUIRED_INCLUDES "${MP4V2_INCLUDE_DIR}") + check_include_file("mp4v2.h" HAVE_MP4V2_H) endif(MP4V2_INCLUDE_DIR) - check_include_file("mp4v2.h" HAVE_MP4V2_H) # mp4.h find_path(MP4V2_INCLUDE_DIR mp4.h) if(MP4V2_INCLUDE_DIR) include_directories("${MP4V2_INCLUDE_DIR}") set(CMAKE_REQUIRED_INCLUDES "${MP4V2_INCLUDE_DIR}") + check_include_file("mp4.h" HAVE_MP4_H) endif(MP4V2_INCLUDE_DIR) - check_include_file("mp4.h" HAVE_MP4_H) mark_as_advanced(FORCE MP4V2_LIBRARIES MP4V2_INCLUDE_DIR) set(optlibsfound "${optlibsfound} mp4v2") diff --git a/README.md b/README.md index 0b9a90f9c..3bdf1ffd1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ZoneMinder ========== -[![Build Status](https://travis-ci.org/ZoneMinder/ZoneMinder.png)](https://travis-ci.org/ZoneMinder/ZoneMinder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received) +[![Build Status](https://travis-ci.org/ZoneMinder/zoneminder.png)](https://travis-ci.org/ZoneMinder/zoneminder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received) All documentation for ZoneMinder is now online at https://zoneminder.readthedocs.org diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt index e1b551b1c..ed215d35f 100644 --- a/db/CMakeLists.txt +++ b/db/CMakeLists.txt @@ -2,6 +2,7 @@ # Create files from the .in files configure_file(zm_create.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" @ONLY) +configure_file(zm_update-1.31.30.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" @ONLY) # Glob all database upgrade scripts file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql") @@ -9,5 +10,12 @@ file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql") # Install the database upgrade scripts install(FILES ${dbfileslist} DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") +# install zm_update-1.31.30.sql +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") + # install zm_create.sql install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") + +# install triggers.sql +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db") + diff --git a/db/triggers.sql b/db/triggers.sql index 76097b825..2f13be435 100644 --- a/db/triggers.sql +++ b/db/triggers.sql @@ -116,39 +116,26 @@ FOR EACH ROW END; // -drop procedure if exists update_storage_stats; -create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT) - -sql security invoker - -deterministic - -begin - - update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; - -end; - -// +drop procedure if exists update_storage_stats// drop trigger if exists event_update_trigger// CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events FOR EACH ROW BEGIN - declare diff BIGINT default 0; + declare diff BIGINT default 0; - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( NEW.StorageId = OLD.StorageID ) THEN IF ( diff ) THEN - call update_storage_stats(OLD.StorageId, diff); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + diff WHERE Id = OLD.StorageId; END IF; ELSE IF ( NEW.DiskSpace ) THEN - call update_storage_stats(NEW.StorageId, NEW.DiskSpace); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + NEW.DiskSpace WHERE Id = NEW.StorageId; END IF; IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) - OLD.DiskSpace WHERE Id = OLD.StorageId; END IF; END IF; @@ -216,7 +203,7 @@ CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events FOR EACH ROW BEGIN IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) - CAST(OLD.DiskSpace AS SIGNED) WHERE Id = OLD.StorageId; END IF; DELETE FROM Events_Hour WHERE EventId=OLD.Id; DELETE FROM Events_Day WHERE EventId=OLD.Id; diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index b50c5934b..f67fc0116 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -63,7 +63,7 @@ DROP TABLE IF EXISTS `Controls`; CREATE TABLE `Controls` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', - `Type` enum('Local','Remote','Ffmpeg','Libvlc','cURL') NOT NULL default 'Local', + `Type` enum('Local','Remote','Ffmpeg','Libvlc','cURL','WebSite') NOT NULL default 'Local', `Protocol` varchar(64) default NULL, `CanWake` tinyint(3) unsigned NOT NULL default '0', `CanSleep` tinyint(3) unsigned NOT NULL default '0', @@ -182,7 +182,7 @@ CREATE TABLE `Devices` ( DROP TABLE IF EXISTS `Events`; CREATE TABLE `Events` ( - `Id` int(10) unsigned NOT NULL auto_increment, + `Id` bigint unsigned NOT NULL auto_increment, `MonitorId` int(10) unsigned NOT NULL default '0', `StorageId` smallint(5) unsigned default 0, `Name` varchar(64) NOT NULL default '', @@ -210,6 +210,7 @@ CREATE TABLE `Events` ( `Orientation` enum('0','90','180','270','hori','vert') NOT NULL default '0', `DiskSpace` bigint unsigned default NULL, `Scheme` enum('Deep','Medium','Shallow') NOT NULL default 'Medium', + `Locked` BOOLEAN NOT NULL DEFAULT False, PRIMARY KEY (`Id`), KEY `Events_MonitorId_idx` (`MonitorId`), KEY `Events_StorageId_idx` (`StorageId`), @@ -219,7 +220,7 @@ CREATE TABLE `Events` ( DROP TABLE IF EXISTS `Events_Hour`; CREATE TABLE `Events_Hour` ( - `EventId` int(10) unsigned NOT NULL, + `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, `DiskSpace` bigint unsigned default NULL, @@ -228,40 +229,9 @@ CREATE TABLE `Events_Hour` ( KEY `Events_Hour_StartTime_idx` (`StartTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; -delimiter // -DROP TRIGGER IF EXISTS Events_Hour_delete_trigger// -CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour -FOR EACH ROW BEGIN - UPDATE Monitors SET - HourEvents = COALESCE(HourEvents,1)-1, - HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS Events_Hour_update_trigger// - -CREATE TRIGGER Events_Hour_update_trigger AFTER UPDATE ON Events_Hour -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; -// -DELIMITER ; - DROP TABLE IF EXISTS `Events_Day`; CREATE TABLE `Events_Day` ( - `EventId` int(10) unsigned NOT NULL, + `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, `DiskSpace` bigint unsigned default NULL, @@ -270,40 +240,9 @@ CREATE TABLE `Events_Day` ( KEY `Events_Day_StartTime_idx` (`StartTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; -delimiter // -DROP TRIGGER IF EXISTS Events_Day_delete_trigger// -CREATE TRIGGER Events_Day_delete_trigger BEFORE DELETE ON Events_Day -FOR EACH ROW BEGIN - UPDATE Monitors SET - DayEvents = COALESCE(DayEvents,1)-1, - DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS Events_Day_update_trigger; -CREATE TRIGGER Events_Day_update_trigger AFTER UPDATE ON Events_Day -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; - // - - -DELIMITER ; DROP TABLE IF EXISTS `Events_Week`; CREATE TABLE `Events_Week` ( - `EventId` int(10) unsigned NOT NULL, + `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, `DiskSpace` bigint unsigned default NULL, @@ -312,40 +251,9 @@ CREATE TABLE `Events_Week` ( KEY `Events_Week_StartTime_idx` (`StartTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; -delimiter // -DROP TRIGGER IF EXISTS Events_Week_delete_trigger// -CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week -FOR EACH ROW BEGIN - UPDATE Monitors SET - WeekEvents = COALESCE(WeekEvents,1)-1, - WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS Events_Week_update_trigger; -CREATE TRIGGER Events_Week_update_trigger AFTER UPDATE ON Events_Week -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; - // - -DELIMITER ; - DROP TABLE IF EXISTS `Events_Month`; CREATE TABLE `Events_Month` ( - `EventId` int(10) unsigned NOT NULL, + `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `StartTime` datetime default NULL, `DiskSpace` bigint unsigned default NULL, @@ -354,177 +262,16 @@ CREATE TABLE `Events_Month` ( KEY `Events_Month_StartTime_idx` (`StartTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; -delimiter // -DROP TRIGGER IF EXISTS Events_Month_delete_trigger// -CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month -FOR EACH ROW BEGIN - UPDATE Monitors SET - MonthEvents = COALESCE(MonthEvents,1)-1, - MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - - -DROP TRIGGER IF EXISTS Events_Month_update_trigger; -CREATE TRIGGER Events_Month_update_trigger AFTER UPDATE ON Events_Month -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; - // - - -DELIMITER ; DROP TABLE IF EXISTS `Events_Archived`; CREATE TABLE `Events_Archived` ( - `EventId` int(10) unsigned NOT NULL, + `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, `DiskSpace` bigint unsigned default NULL, PRIMARY KEY (`EventId`), KEY `Events_Archived_MonitorId_idx` (`MonitorId`) ) ENGINE=@ZM_MYSQL_ENGINE@; - -drop procedure if exists update_storage_stats; - -delimiter // - -create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT) - -sql security invoker - -deterministic - -begin - - update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; - -end; - -// - -drop trigger if exists event_update_trigger// - -CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events -FOR EACH ROW -BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( NEW.StorageId = OLD.StorageID ) THEN - IF ( diff ) THEN - call update_storage_stats(OLD.StorageId, diff); - END IF; - ELSE - IF ( NEW.DiskSpace ) THEN - call update_storage_stats(NEW.StorageId, NEW.DiskSpace); - END IF; - IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); - END IF; - END IF; - - UPDATE Events_Hour SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - - IF ( NEW.Archived != OLD.Archived ) THEN - IF ( NEW.Archived ) THEN - INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); - UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=NEW.MonitorId; - ELSEIF ( OLD.Archived ) THEN - DELETE FROM Events_Archived WHERE EventId=OLD.Id; - UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)-1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; - ELSE - IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN - UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Monitors SET - ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) - WHERE Id=OLD.MonitorId; - END IF; - END IF; - ELSE IF ( NEW.Archived AND diff ) THEN - UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - END IF; - - IF ( diff ) THEN - UPDATE Monitors SET TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=OLD.MonitorId; - END IF; - -END; - -// - -delimiter ; - -DROP TRIGGER IF EXISTS event_insert_trigger; - -delimiter // -/* The assumption is that when an Event is inserted, it has no size yet, so don't bother updating the DiskSpace, just the count. - * The DiskSpace will get update in the Event Update Trigger - */ -CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events -FOR EACH ROW - BEGIN - - INSERT INTO Events_Hour (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Day (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Week (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Month (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - UPDATE Monitors SET - HourEvents = COALESCE(DayEvents,0)+1, - DayEvents = COALESCE(DayEvents,0)+1, - WeekEvents = COALESCE(DayEvents,0)+1, - MonthEvents = COALESCE(DayEvents,0)+1, - TotalEvents = COALESCE(TotalEvents,0)+1 - WHERE Id=NEW.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS event_delete_trigger// - -CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events -FOR EACH ROW -BEGIN - IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); - END IF; - DELETE FROM Events_Hour WHERE EventId=OLD.Id; - DELETE FROM Events_Day WHERE EventId=OLD.Id; - DELETE FROM Events_Week WHERE EventId=OLD.Id; - DELETE FROM Events_Month WHERE EventId=OLD.Id; - IF ( OLD.Archived ) THEN - DELETE FROM Events_Archived WHERE EventId=OLD.Id; - UPDATE Monitors SET - ArchivedEvents = COALESCE(ArchivedEvents,1) - 1, - ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0), - TotalEvents = COALESCE(TotalEvents,1) - 1, - TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; - ELSE - UPDATE Monitors SET - TotalEvents = COALESCE(TotalEvents,1)-1, - TotalEventDiskSpace=COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; - END IF; -END; - -// - -delimiter ; -- -- Table structure for table `Filters` -- @@ -557,8 +304,8 @@ CREATE TABLE `Filters` ( DROP TABLE IF EXISTS `Frames`; CREATE TABLE `Frames` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `EventId` int(10) unsigned NOT NULL default '0', + `Id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + `EventId` BIGINT UNSIGNED NOT NULL default '0', `FrameId` int(10) unsigned NOT NULL default '0', `Type` enum('Normal','Bulk','Alarm') NOT NULL default 'Normal', `TimeStamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, @@ -710,7 +457,8 @@ CREATE TABLE `Monitors` ( `Deinterlacing` int(10) unsigned NOT NULL default '0', `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' , `VideoWriter` TINYINT NOT NULL DEFAULT '0', - `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2'), + `OutputCodec` int(10) unsigned NOT NULL default 0, + `Encoder` enum('auto','h264','h264_omx','mjpeg','mpeg1','mpeg2'), `OutputContainer` enum('auto','mp4','mkv'), `EncoderParameters` TEXT, `RecordAudio` TINYINT NOT NULL DEFAULT '0', @@ -752,6 +500,7 @@ CREATE TABLE `Monitors` ( `DefaultView` enum('Events','Control') NOT NULL default 'Events', `DefaultRate` smallint(5) unsigned NOT NULL default '100', `DefaultScale` smallint(5) unsigned NOT NULL default '100', + `SignalCheckPoints` INT UNSIGNED NOT NULL default '0', `SignalCheckColour` varchar(32) NOT NULL default '#0000BE', `WebColour` varchar(32) NOT NULL default 'red', `Exif` tinyint(1) unsigned NOT NULL default '0', @@ -780,6 +529,7 @@ CREATE TABLE `Monitor_Status` ( `Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown', `CaptureFPS` DECIMAL(10,2) NOT NULL default 0, `AnalysisFPS` DECIMAL(5,2) NOT NULL default 0, + `CaptureBandwidth` INT NOT NULL default 0, PRIMARY KEY (`MonitorId`) ) ENGINE=MEMORY; -- @@ -949,40 +699,24 @@ CREATE TABLE `Zones` ( KEY `MonitorId` (`MonitorId`) ) ENGINE=@ZM_MYSQL_ENGINE@; -DELIMITER // -DROP TRIGGER IF EXISTS Zone_Insert_Trigger// -CREATE TRIGGER Zone_Insert_Trigger AFTER INSERT ON Zones -FOR EACH ROW - BEGIN - UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=NEW.MonitorId) WHERE Id=NEW.MonitorID; - END -// -DROP TRIGGER IF EXISTS Zone_Delete_Trigger// -CREATE TRIGGER Zone_Delete_Trigger AFTER DELETE ON Zones -FOR EACH ROW - BEGIN - UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=OLD.MonitorId) WHERE Id=OLD.MonitorID; - END -// - -DELIMITER ; - DROP TABLE IF EXISTS `Storage`; CREATE TABLE `Storage` ( `Id` smallint(5) unsigned NOT NULL auto_increment, `Path` varchar(64) NOT NULL default '', `Name` varchar(64) NOT NULL default '', `Type` enum('local','s3fs') NOT NULL default 'local', + `Url` varchar(255) default NULL, `DiskSpace` bigint default NULL, `Scheme` enum('Deep','Medium','Shallow') NOT NULL default 'Medium', `ServerId` int(10) unsigned, + `DoDelete` BOOLEAN NOT NULL DEFAULT true, PRIMARY KEY (`Id`) ) ENGINE=@ZM_MYSQL_ENGINE@; -- -- Create a default storage location -- -insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL, 'Medium', 0 ); +insert into Storage VALUES (NULL, '@ZM_DIR_EVENTS@', 'Default', 'local', NULL, NULL, 'Medium', 0, true ); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; @@ -1040,6 +774,10 @@ INSERT INTO `Controls` VALUES (NULL,'Keekoon','Remote','Keekoon', 0, 0, 0, 0, 0, INSERT INTO `Controls` VALUES (NULL,'HikVision','Local','',0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,1,1,1,1,0,0,0,1,1,0,0,0,0,1,1,100,0,0,1,0,0,0,0,1,1,100,1,0,0,0); INSERT INTO `Controls` VALUES (NULL,'Maginon Supra IPC','cURL','MaginonIPC',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0); INSERT INTO `Controls` VALUES (NULL,'Floureon 1080P','Ffmpeg','Floureon',0,0,0,1,0,0,0,1,1,18,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,8,0,0,1,0,0,0,0,1,1,8,0,0,0,0); +INSERT INTO `Controls` VALUES (NULL,'Reolink RLC-423','Ffmpeg','Reolink',0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,64,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0); +INSERT INTO `Controls` VALUES (NULL,'Reolink RLC-411','Ffmpeg','Reolink',0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +INSERT INTO `Controls` VALUES (NULL,'Reolink RLC-420','Ffmpeg','Reolink',0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +INSERT INTO `Controls` VALUES (NULL,'D-LINK DCS-3415','Remote','DCS3415',0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0); -- -- Add some monitor preset values @@ -1138,7 +876,7 @@ CREATE TABLE Maps ( PRIMARY KEY (`Id`) ); -DROP TABLE IF EXISTS MontageLayout; +DROP TABLE IF EXISTS MontageLayouts; CREATE TABLE MontageLayouts ( `Id` int(10) unsigned NOT NULL auto_increment, @@ -1155,11 +893,7 @@ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' ); -- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts. -<<<<<<< HEAD -source triggers.sql -======= -source @ZM_PATH_DATA@/db/triggers.sql ->>>>>>> storageareas +source @PKGDATADIR@/db/triggers.sql -- -- Apply the initial configuration -- diff --git a/db/zm_update-1.31.30.sql.in b/db/zm_update-1.31.30.sql.in new file mode 100644 index 000000000..b6746b55a --- /dev/null +++ b/db/zm_update-1.31.30.sql.in @@ -0,0 +1,20 @@ +DROP TABLE IF EXISTS `Monitor_Status`; +CREATE TABLE `Monitor_Status` ( + `MonitorId` int(10) unsigned NOT NULL, + `Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown', + `CaptureFPS` DECIMAL(10,2) NOT NULL default 0, + `AnalysisFPS` DECIMAL(5,2) NOT NULL default 0, + PRIMARY KEY (`MonitorId`) +) ENGINE=MEMORY; + +SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO'; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='@ZM_DIR_EVENTS@' + ) > 0, + "SELECT 'Default Storage Area already exists.'", + "INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','@ZM_DIR_EVENTS@','Medium',NULL)" + )); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/db/zm_update-1.31.38.sql b/db/zm_update-1.31.38.sql index 0ca0be6ea..12fd3e96d 100644 --- a/db/zm_update-1.31.38.sql +++ b/db/zm_update-1.31.38.sql @@ -176,8 +176,10 @@ BEGIN WHERE Id=OLD.MonitorId; END IF; END IF; - ELSEIF ( NEW.Archived AND diff ) THEN - UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + ELSE + IF ( NEW.Archived AND diff ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + END IF; END IF; IF ( diff ) THEN @@ -185,7 +187,6 @@ BEGIN END IF; END; - // delimiter ; diff --git a/db/zm_update-1.31.40.sql b/db/zm_update-1.31.40.sql new file mode 100644 index 000000000..37a6e260b --- /dev/null +++ b/db/zm_update-1.31.40.sql @@ -0,0 +1,27 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Storage' + AND column_name = 'Url' + ) > 0, +"SELECT 'Column Url already exists in Storage'", +"ALTER TABLE `Storage` ADD `Url` VARCHAR(255) default NULL AFTER `Type`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + + +ALTER TABLE `Monitors` MODIFY `OutputCodec` int(10) UNSIGNED NOT NULL default 0; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'Encoder' + ) > 0, +"SELECT 'Column Encoder already exists in Monitors'", +"ALTER TABLE `Monitors` ADD `Encoder` enum('auto','h264','h264_omx','mjpeg','mpeg1','mpeg2') AFTER `OutputCodec`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/db/zm_update-1.31.41.sql b/db/zm_update-1.31.41.sql new file mode 100644 index 000000000..e2b45df5b --- /dev/null +++ b/db/zm_update-1.31.41.sql @@ -0,0 +1,25 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Storage' + AND column_name = 'DoDelete' + ) > 0, +"SELECT 'Column DoDelete already exists in Storage'", +"ALTER TABLE `Storage` ADD `DoDelete` BOOLEAN NOT NULL default true AFTER `ServerId`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events' + AND column_name = 'Locked' + ) > 0, +"SELECT 'Column Locked already exists in Events'", +"ALTER TABLE `Events` ADD `Locked` BOOLEAN NOT NULL default false AFTER `Scheme`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + diff --git a/db/zm_update-1.31.42.sql b/db/zm_update-1.31.42.sql new file mode 100644 index 000000000..adb004baf --- /dev/null +++ b/db/zm_update-1.31.42.sql @@ -0,0 +1,12 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'SignalCheckPoints' + ) > 0, +"SELECT 'Column SignalCheckPoints already exists in Storage'", +"ALTER TABLE `Monitors` ADD `SignalCheckPoints` INT UNSIGNED NOT NULL default '0' AFTER `DefaultScale`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/db/zm_update-1.31.43.sql b/db/zm_update-1.31.43.sql new file mode 100644 index 000000000..d8d6eaefd --- /dev/null +++ b/db/zm_update-1.31.43.sql @@ -0,0 +1,24 @@ +-- +-- This updates a 1.31.42 database to 1.31.43 +-- +-- Add WebSite enum to Monitor.Type +-- Add Refresh column to Monitors table +-- + +ALTER TABLE `zm`.`Monitors` +CHANGE COLUMN `Type` `Type` ENUM('Local', 'Remote', 'File', 'Ffmpeg', 'Libvlc', 'cURL', 'WebSite') NOT NULL DEFAULT 'Local' ; + +SET @s = (SELECT IF( + (SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'Monitors' + AND table_schema = DATABASE() + AND column_name = 'Refresh' + ) > 0, +"SELECT 'Column Refresh exists in Monitors'", +"ALTER TABLE Monitors ADD `Refresh` int(10) unsigned default NULL" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + diff --git a/db/zm_update-1.31.44.sql b/db/zm_update-1.31.44.sql new file mode 100644 index 000000000..3c8a1525a --- /dev/null +++ b/db/zm_update-1.31.44.sql @@ -0,0 +1,12 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'CaptureBandwidth' + ) > 0, +"SELECT 'Column CaptureBandwidth already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `CaptureBandwidth` INT NOT NULL default 0 AFTER `AnalysisFPS`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/distros/debian/postinst b/distros/debian/postinst index 20f715793..3cd3fd277 100644 --- a/distros/debian/postinst +++ b/distros/debian/postinst @@ -5,6 +5,9 @@ set -e if [ "$1" = "configure" ]; then . /etc/zm/zm.conf + for i in /etc/zm/conf.d/*.conf; do + . $i + done; # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group. chown www-data:root /var/log/zm diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index 73f88f968..e42c5db61 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -14,24 +14,18 @@ if((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx")) endif((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx")) # Configure the zoneminder service files -if(ZM_TARGET_DISTRO STREQUAL "el6") - configure_file(sysvinit/zoneminder.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.sysvinit @ONLY) - configure_file(sysvinit/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) +configure_file(systemd/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) +if(ZM_WEB_USER STREQUAL "nginx") + configure_file(nginx/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) + configure_file(nginx/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) + configure_file(nginx/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) + configure_file(nginx/zoneminder.php-fpm.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.php-fpm.conf @ONLY) + configure_file(nginx/README.Fedora ${CMAKE_CURRENT_SOURCE_DIR}/readme/README.Fedora COPYONLY) +else(ZM_WEB_USER STREQUAL "nginx") + configure_file(systemd/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) -else(ZM_TARGET_DISTRO STREQUAL "el6") - configure_file(systemd/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) - if(ZM_WEB_USER STREQUAL "nginx") - configure_file(nginx/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) - configure_file(nginx/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) - configure_file(nginx/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) - configure_file(nginx/zoneminder.php-fpm.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.php-fpm.conf @ONLY) - configure_file(nginx/README.Fedora ${CMAKE_CURRENT_SOURCE_DIR}/readme/README.Fedora COPYONLY) - else(ZM_WEB_USER STREQUAL "nginx") - configure_file(systemd/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) - configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) - configure_file(systemd/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) - endif(ZM_WEB_USER STREQUAL "nginx") -endif(ZM_TARGET_DISTRO STREQUAL "el6") + configure_file(systemd/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) +endif(ZM_WEB_USER STREQUAL "nginx") # Unpack jscalendar & move files into position message(STATUS "Unpacking and Installing jscalendar...") @@ -52,6 +46,7 @@ file(MAKE_DIRECTORY sock swap zoneminder zoneminder-upload events images temp) install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder DESTINATION /var/log DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder DESTINATION /var/run DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(DIRECTORY zoneminder DESTINATION /var/cache DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) @@ -61,23 +56,18 @@ install(CODE "execute_process(COMMAND ln -sf ../../../../../../var/lib/zoneminde # Link to Cambozola install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/cambozola.jar\")") -# Install auxiliary files required to run zoneminder on CentOS +# Install auxiliary files install(FILES misc/redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY jscalendar-1.0/ DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/tools/jscalendar) +# Install zoneminder service files install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) +install(FILES zoneminder.conf DESTINATION /etc/zm/www PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) if(ZM_WEB_USER STREQUAL "nginx") - install(FILES zoneminder.conf DESTINATION /etc/nginx/default.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.php-fpm.conf DESTINATION /etc/php-fpm.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ RENAME zoneminder.conf) -else(ZM_WEB_USER STREQUAL "nginx") - install(FILES zoneminder.conf DESTINATION /etc/httpd/conf.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) endif(ZM_WEB_USER STREQUAL "nginx") -if(ZM_TARGET_DISTRO STREQUAL "el6") - install(FILES zoneminder.sysvinit DESTINATION /etc/rc.d/init.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -else(ZM_TARGET_DISTRO STREQUAL "el6") - install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) - install(FILES zoneminder.tmpfiles DESTINATION /usr/lib/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -endif(ZM_TARGET_DISTRO STREQUAL "el6") +install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) +install(FILES zoneminder.tmpfiles DESTINATION /usr/lib/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/distros/redhat/apache/zoneminder.conf.in b/distros/redhat/apache/zoneminder.conf.in index 0e546f9df..a52c1166a 100644 --- a/distros/redhat/apache/zoneminder.conf.in +++ b/distros/redhat/apache/zoneminder.conf.in @@ -9,6 +9,23 @@ RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^/?(zm)(.*) https://%{SERVER_NAME}/$1$2 [R,L] +# Order matters. This alias must come first. +Alias /zm/cache "@ZM_CACHEDIR@" + + SSLRequireSSL + Options -Indexes +MultiViews +FollowSymLinks + AllowOverride None + + # Apache 2.4 + Require all granted + + + # Apache 2.2 + Order deny,allow + Allow from all + + + Alias /zm "@ZM_WEBDIR@" # explicitly set index.php as the only directoryindex diff --git a/distros/redhat/readme/README.Fedora b/distros/redhat/readme/README.Fedora index e3cca1f8c..d0ccf8c4e 100644 --- a/distros/redhat/readme/README.Fedora +++ b/distros/redhat/readme/README.Fedora @@ -1,37 +1,19 @@ What's New ========== -1. ZoneMinder now uses a conf.d subfolder to process custom changes to - variables found in zm.conf. Changes to zm.conf will be overwritten - during an upgrade. Instead, create a file with a ".conf" extension under - the conf.d folder and make your changes there. - -2. ZoneMinder now supports recording directly to video container! This feature - is new and should be treated as experimental. Refer to the documentation - regarding how to use this feature. - -3. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to - "/cgi-bin-zm/zms". This has been to done to avoid this bug: - https://bugzilla.redhat.com/show_bug.cgi?id=973067 - - IMPORTANT: You must manually inspect the value for PATH_ZMS under Options - and verify it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result - in a broken system. You have been warned. - -4. This package uses the HTTPS protocol by default to access the web portal. - Requests using HTTP will auto-redirect to HTTPS. See README.https for - more information. - +1. See the ZoneMinder release notes for a list of new features: + https://github.com/ZoneMinder/zoneminder/releases + New installs ============ 1. Unless you are already using MariaDB server, you need to ensure that the server is configured to start during boot and properly secured by running: - sudo dnf install mariadb-server - sudo systemctl enable mariadb - sudo systemctl start mariadb.service - mysql_secure_installation + sudo dnf install mariadb-server + sudo systemctl enable mariadb + sudo systemctl start mariadb.service + mysql_secure_installation 2. Assuming the database is local and using the password for the root account set during the previous step, you will need to create the ZoneMinder @@ -50,13 +32,13 @@ New installs /etc/zm/conf.d and set your credentials there. For example, create the file /etc/zm/conf.d/zm-db-user.conf and add the following content to it: - ZM_DB_USER = {username of the sql account you want to use} - ZM_DB_PASS = {password of the sql account you want to use} + ZM_DB_USER = {username of the sql account you want to use} + ZM_DB_PASS = {password of the sql account you want to use} Once the file has been saved, set proper file & ownership permissions on it: - sudo chown root:apache *.conf - sudo chmod 640 *.conf + sudo chown root:apache *.conf + sudo chmod 640 *.conf 4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local timezone. PHP will complain loudly if this is not set, or if it is set @@ -82,34 +64,62 @@ New installs SELINUX line from "enforcing" to "disabled". This change will take effect after a reboot. -6. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your - needs. This package comes preconfigured for HTTPS using the default self - signed certificate on your system. The recommended way to complete this step - is to simply install mod_ssl: +6. Configure the web server - sudo dnf install mod_ssl + This package uses the HTTPS protocol by default to access the web portal, + using rhe default self signed certificate on your system. Requests using + HTTP will auto-redirect to HTTPS. - If this does not meet your needs, then read README.https to - learn about alternatives. When in doubt, install mod_ssl. + Inspect the web server configuration file and verify it meets your needs: + + /etc/zm/www/zoneminder.conf + + If you are running other web enabled services then you may need to edit + this file to suite. See README.https to learn about other alternatives. + + When in doubt, proceed with the default: + + sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ + sudo dnf install mod_ssl 7. Now start the web server: - sudo systemctl enable httpd - sudo systemctl start httpd + sudo systemctl enable httpd + sudo systemctl start httpd 8. Now start zoneminder: - sudo systemctl enable zoneminder - sudo systemctl start zoneminder + sudo systemctl enable zoneminder + sudo systemctl start zoneminder -9. The Fedora repos have a ZoneMinder package available, but it does not - support ffmpeg or libvlc, which many modern IP cameras require. Most users - will want to prevent the ZoneMinder package in the Fedora repos from - overwriting the ZoneMinder package in zmrepo, during a future dnf update. To - prevent that from happening you must edit /etc/yum.repos.d/fedora.repo - and /etc/yum.repos.d/fedora-updates.repo. Add the line "exclude=zoneminder*" - without the quotes under the [fedora] and [fedora-updates] blocks, - respectively. +9. Optionally configure the firewall + + All Redhat distros ship with the firewall enabled. That means you will not + be able to access the ZoneMinder web console from a remote machine until + changes are made to the firewall. + + What follows are a set of minimal commands to allow remote access to the + ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to + work. The following commands do not put any restrictions on which remote + machine(s) have access to the listed ports or services. + + sudo firewall-cmd --permanent --zone=public --add-service=http + sudo firewall-cmd --permanent --zone=public --add-service=https + sudo firewall-cmd --permanent --zone=public --add-port=3702/udp + sudo firewall-cmd --reload + + Additional changes to the firewall may be required, depending on your + security requirements and how you use the system. It is up to you to verify + these commands are sufficient. + +10. Access the ZoneMinder web console + + You may now access the ZoneMinder web console from your web browser using + an appropriate url. Here are some examples: + + http://localhost/zm (works from the local machine only) + http://{machine name}/zm (works only if dns is configured for your network) + http://{ip address}/zm Upgrades ======== @@ -131,7 +141,7 @@ Upgrades See step 2 of the Installation section to add missing permissions. 3. Verify the ZoneMinder Apache configuration file in the folder - /etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there + /etc/zm/www. You will have a file called "zoneminder.conf" and there may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file exists, inspect it and merge anything new in that file with zoneminder.conf. Verify the SSL REquirements meet your needs. Read README.https if necessary. diff --git a/distros/redhat/readme/README.Redhat6 b/distros/redhat/readme/README.Redhat6 deleted file mode 100644 index 939300d96..000000000 --- a/distros/redhat/readme/README.Redhat6 +++ /dev/null @@ -1,161 +0,0 @@ -What's New -========== - -1. ***EOL NOTICE*** - It has become increasingly difficult to maintain the ZoneMinder project such - that it remains compatible with EL6 distros. The version of php shipped with - EL6 distros and the version of ffmpeg which will build against EL6 are too - old. It is with regret that I must announce our plans to stop supporting - ZoneMinder on EL6 distros soon. Your best option is to upgrade to an EL7 - distro or another distro with newer php & ffmpeg packages. Please note that - replacing core packages, such as php, will not be supported by us. You are - on your own should you choose to go down that path. - -2. ZoneMinder now uses a conf.d subfolder to process custom changes to - variables found in zm.conf. Changes to zm.conf will be overwritten - during an upgrade. Instead, create a file with a ".conf" extension under - th2 conf.d folder and make your changes there. - -3. ZoneMinder now supports recording directly to video container! This feature - is new and should be treated as experimental. Refer to the documentation - regarding how to use this feature. - -4. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to - "/cgi-bin-zm/zms". This has been to done match the configuration of - CentOS7/Fedora and simplify the build process. - - IMPORTANT: You must manually verify the value of PATH_ZMS under Options. - Make sure it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result - in a broken system. You have been warned. - -5. This package uses the HTTPS protocol by default to access the web portal. - Requests using HTTP will auto-redirect to HTTPS. See README.https for - more information. - -6. The php package that ships with CentOS 6 does not support the new ZoneMinder - API. If you require API functionality (such as using a mobile app) then you - should consider an upgrade to CentOS 7 or use Fedora. - -New installs -============ - -1. Unless you are already using MySQL server, you need to ensure that - the server is confired to start during boot and properly secured - by running: - - sudo yum install mysql-server - sudo service mysqld start - /usr/bin/mysql_secure_installation - sudo chkconfig mysqld on - -2. Using the password for the root account set during the previous step, you - will need to create the ZoneMinder database and configure a database - account for ZoneMinder to use: - - 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 environment. - -3. If you have chosen to change the zoneminder database account credentials to - something other than zmuser/zmpass, you must now create a config file under - /etc/zm/conf.d and set your credentials there. For example, create the file - /etc/zm/conf.d/zm-db-user.conf and add the following content to it: - - ZM_DB_USER = {username of the sql account you want to use} - ZM_DB_PASS = {password of the sql account you want to use} - - Once the file has been saved, set proper file & ownership permissions on it: - - sudo chown root:apache *.conf - sudo chmod 640 *.conf - -4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local - timezone. PHP will complain loudly if this is not set, or if it is set - incorrectly, and these complaints will show up in the zoneminder logging - system as errors - - If you are not sure of the proper timezone specification to use, look at - http://php.net/date.timezone - -5. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your - needs. This package comes preconfigured for HTTPS using the default self - signed certificate on your system. The recommended way to complete this step - is to simply install mod_ssl: - - sudo yum install mod_ssl - - If this does not meet your needs, then read README.https to - learn about alternatives. When in doubt, install mod_ssl. - -6. Configure the web server to start automatically: - - sudo chkconfig httpd on - sudo service httpd start - -7. This package will automatically configure and install an SELinux policy - called local_zoneminder. A copy of this policy is in the documentation - folder. - - It is still possible to run into SELinux issues, however. If this is case, - you can disable SELinux permanently by editing the following: - - /etc/selinux/conf - - Change SELINUX line from "enforcing" to "disabled". This change will not - take effect until a reboot, however. To avoid a reboot, execute the - following from the commandline: - - sudo setenforce 0 - -8. Finally, you may start the ZoneMinder service: - - sudo service zoneminder start - - Then point your web browser to http:///zm - -Upgrades -======== - -1. Conf.d folder support has been added to ZoneMinder 1.31.0. Any custom - changes previously made to zm.conf must now be made in one or more custom - config files, created under the conf.d folder. Do this now. See - /etc/zm/conf.d/README for details. Once you recreate any custom config changes - under the conf.d folder, they will remain in place indefinitely. - -2. Verify permissions of the zmuser account. - - Over time, the database account permissions required for normal operation - have increased. Verify the zmuser database account has been granted all - permission to the ZoneMinder database: - - mysql -uroot -p -e "show grants for zmuser@localhost;" - - See step 2 of the Installation section to add missing permissions. - -3. Verify the ZoneMinder Apache configuration file in the folder - /etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there - may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file - exists, inspect it and merge anything new in that file with zoneminder.conf. - Verify the SSL REquirements meet your needs. Read README.https if necessary. - -4. Upgrade the database before starting ZoneMinder. - - Most upgrades can be performed by executing the following command: - - sudo zmupdate.pl - - Recent versions of ZoneMinder don't require any parameters added to the - zmupdate command. However, if ZoneMinder complains, you may need to call - zmupdate in the following manner: - - sudo zmupdate.pl --user=root --pass= --version= - -5. Now restart the web server then start zoneminder: - - sudo service httpd restart - sudo service zoneminder start - diff --git a/distros/redhat/readme/README.Redhat7 b/distros/redhat/readme/README.Redhat7 index d74973a72..b70e7768d 100644 --- a/distros/redhat/readme/README.Redhat7 +++ b/distros/redhat/readme/README.Redhat7 @@ -1,26 +1,8 @@ What's New ========== -1. ZoneMinder now uses a conf.d subfolder to process custom changes to - variables found in zm.conf. Changes to zm.conf will be overwritten - during an upgrade. Instead, create a file with a ".conf" extension under - the conf.d folder and make your changes there. - -2. ZoneMinder now supports recording directly to video container! This feature - is new and should be treated as experimental. Refer to the documentation - regarding how to use this feature. - -3. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to - "/cgi-bin-zm/zms". This has been to done to avoid this bug: - https://bugzilla.redhat.com/show_bug.cgi?id=973067 - - IMPORTANT: You must manually inspect the value for PATH_ZMS under Options - and verify it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result - in a broken system. You have been warned. - -4. This package uses the HTTPS protocol by default to access the web portal. - Requests using HTTP will auto-redirect to HTTPS. See README.https for - more information. +1. See the ZoneMinder release notes for a list of new features: + https://github.com/ZoneMinder/zoneminder/releases New installs ============ @@ -28,10 +10,10 @@ New installs 1. Unless you are already using MariaDB server, you need to ensure that the server is configured to start during boot and properly secured by running: - sudo yum install mariadb-server - sudo systemctl enable mariadb - sudo systemctl start mariadb.service - mysql_secure_installation + sudo yum install mariadb-server + sudo systemctl enable mariadb + sudo systemctl start mariadb.service + mysql_secure_installation 2. Using the password for the root account set during the previous step, you will need to create the ZoneMinder database and configure a database @@ -50,13 +32,13 @@ New installs /etc/zm/conf.d and set your credentials there. For example, create the file /etc/zm/conf.d/zm-db-user.conf and add the following content to it: - ZM_DB_USER = {username of the sql account you want to use} - ZM_DB_PASS = {password of the sql account you want to use} + ZM_DB_USER = {username of the sql account you want to use} + ZM_DB_PASS = {password of the sql account you want to use} Once the file has been saved, set proper file & ownership permissions on it: - sudo chown root:apache *.conf - sudo chmod 640 *.conf + sudo chown root:apache *.conf + sudo chmod 640 *.conf 4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local timezone. PHP will complain loudly if this is not set, or if it is set @@ -82,25 +64,62 @@ New installs SELINUX line from "enforcing" to "disabled". This change will take effect after a reboot. -6. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your - needs. This package comes preconfigured for HTTPS using the default self - signed certificate on your system. The recommended way to complete this step - is to simply install mod_ssl: +6. Configure the web server - sudo yum install mod_ssl + This package uses the HTTPS protocol by default to access the web portal, + using rhe default self signed certificate on your system. Requests using + HTTP will auto-redirect to HTTPS. - If this does not meet your needs, then read README.https to - learn about alternatives. When in doubt, install mod_ssl. + Inspect the web server configuration file and verify it meets your needs: + + /etc/zm/www/zoneminder.conf + + If you are running other web enabled services then you may need to edit + this file to suite. See README.https to learn about other alternatives. + + When in doubt, proceed with the default: + + sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/ + sudo dnf install mod_ssl 7. Now start the web server: - sudo systemctl enable httpd - sudo systemctl start httpd + sudo systemctl enable httpd + sudo systemctl start httpd 8. Now start zoneminder: - sudo systemctl enable zoneminder - sudo systemctl start zoneminder + sudo systemctl enable zoneminder + sudo systemctl start zoneminder + +9. Optionally configure the firewall + + All Redhat distros ship with the firewall enabled. That means you will not + be able to access the ZoneMinder web console from a remote machine until + changes are made to the firewall. + + What follows are a set of minimal commands to allow remote access to the + ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to + work. The following commands do not put any restrictions on which remote + machine(s) have access to the listed ports or services. + + sudo firewall-cmd --permanent --zone=public --add-service=http + sudo firewall-cmd --permanent --zone=public --add-service=https + sudo firewall-cmd --permanent --zone=public --add-port=3702/udp + sudo firewall-cmd --reload + + Additional changes to the firewall may be required, depending on your + security requirements and how you use the system. It is up to you to verify + these commands are sufficient. + +10. Access the ZoneMinder web console + + You may now access the ZoneMinder web console from your web browser using + an appropriate url. Here are some examples: + + http://localhost/zm (works from the local machine only) + http://{machine name}/zm (works only if dns is configured for your network) + http://{ip address}/zm Upgrades ======== @@ -122,7 +141,7 @@ Upgrades See step 2 of the Installation section to add missing permissions. 3. Verify the ZoneMinder Apache configuration file in the folder - /etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there + /etc/zm/www. You will have a file called "zoneminder.conf" and there may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file exists, inspect it and merge anything new in that file with zoneminder.conf. Verify the SSL REquirements meet your needs. Read README.https if necessary. diff --git a/distros/redhat/readme/README.https b/distros/redhat/readme/README.https index 7e4132a4a..4b02aaa0d 100644 --- a/distros/redhat/readme/README.https +++ b/distros/redhat/readme/README.https @@ -1,29 +1,26 @@ -HTTPS is now a requirement -========================== +HTTPS is now the default +======================== -This package now depends on Apache's mod_ssl package. This will automatically -be installed along with ZoneMinder. Upon installation, the mod_ssl package -will create a default, self-signed certificate. This is the certificate that -ZoneMinder will use out of the box. +By default, ZoneMinder will use the certifciate created when the mod_ssl +pacakge was installed on your system. Since the certificate is self-signed, you will get a warning from your browser the first time you access the web portal. This is normal. This is not intended to be an all encompasing solution for everyone. ZoneMinder will work just fine over HTTPS the way it is currently configured. However, -here are a couple of considerations you may want to take. +here are a couple of considerations you may want to take to improve your +experience. -1. Create your own certificate. The CentOS wiki has a guide that describes how +1. Install a fully signed certificate from letsencrypt, using certbot. See the + certbot site for more information. This free service is very easy to set up. + https://certbot.eff.org/all-instructions/ + +2. Create your own certificate. The CentOS wiki has a guide that describes how to do this: https://wiki.centos.org/HowTos/Https . Additionally, Googling - "centos certificate" reveals many articles on the subject. Note that some - third party applications, such as zmNinja, will require you to create a - certificate different than the default certificate on your machine. + "centos certificate" reveals many articles on the subject. -2. You can turn off HTTPS entirely by simply commenting out the SSLRequireSSL +3. You can turn off HTTPS entirely by simply commenting out the SSLRequireSSL directives found in /etc/httpd/conf.d/zoneminder.conf. You should also comment out the HTTP -> HTTPS Rewrite rule. -3. Install a fully signed certificate from letsencrypt. See the Letsencrypt - site for more information. https://letsencrypt.org/ - This service is totally free! - diff --git a/distros/redhat/systemd/zoneminder.tmpfiles.in b/distros/redhat/systemd/zoneminder.tmpfiles.in index f3acd0af7..de155b4cc 100644 --- a/distros/redhat/systemd/zoneminder.tmpfiles.in +++ b/distros/redhat/systemd/zoneminder.tmpfiles.in @@ -1,2 +1,5 @@ D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@ D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_CACHEDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_DIR_EVENTS@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_DIR_IMAGES@ 0755 @WEB_USER@ @WEB_GROUP@ diff --git a/distros/redhat/sysvinit/zoneminder.in b/distros/redhat/sysvinit/zoneminder.in deleted file mode 100644 index f1c6c47c6..000000000 --- a/distros/redhat/sysvinit/zoneminder.in +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/sh -# description: ZoneMinder is the top Linux video camera security and surveillance solution. ZoneMinder is intended for use in single or multi-camera video security applications.Copyright: Philip Coombes, Corey DeLasaux 2003-2008 -# chkconfig: - 99 00 -# processname: zmpkg.pl - -# Source function library. -. /etc/rc.d/init.d/functions - -prog=ZoneMinder -ZM_CONFIG="@ZM_CONFIG@" -pidfile="@ZM_RUNDIR@" -LOCKFILE=/var/lock/subsys/zm - -loadconf() -{ - if [ -f $ZM_CONFIG ]; then - . $ZM_CONFIG - else - echo "ERROR: $ZM_CONFIG not found." - return 1 - fi -} - -loadconf -command="$ZM_PATH_BIN/zmpkg.pl" - -start() -{ -# Commenting out as it is not needed. Leaving as a placeholder for future use. -# zmupdate || return $? - loadconf || return $? - #Make sure the directory for our PID folder exists or create one. - [ ! -d $pidfile ] \ - && mkdir -m 774 $pidfile \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile - #Make sure the folder for the socks file exists or create one - GetPath="select Value from Config where Name='ZM_PATH_SOCKS'" - dbHost=`echo $ZM_DB_HOST | cut -d: -f1` - dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2` - if [ "$dbPort" = "" ] - then - ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` - else - ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` - fi - [ ! -d $ZM_PATH_SOCK ] \ - && mkdir -m 774 $ZM_PATH_SOCK \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK - echo -n $"Starting $prog: " - $command start - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && touch $LOCKFILE - return $RETVAL -} - -stop() -{ - loadconf - echo -n $"Stopping $prog: " - $command stop - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && rm -f $LOCKFILE -} - -zmstatus() -{ - loadconf - result=`$command status` - if [ "$result" = "running" ]; then - echo "ZoneMinder is running" - $ZM_PATH_BIN/zmu -l - RETVAL=0 - else - echo "ZoneMinder is stopped" - RETVAL=1 - fi -} - -zmupdate() -{ - if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then - $ZM_PATH_BIN/zmupdate.pl -f - fi -} - - -case "$1" in - 'start') - start - ;; - 'stop') - stop - ;; - 'restart') - stop - start - ;; - 'condrestart') - loadconf - result=`$ZM_PATH_BIN/zmdc.pl check` - if [ "$result" = "running" ]; then - $ZM_PATH_BIN/zmdc.pl shutdown > /dev/null - rm -f $LOCKFILE - start - fi - ;; - 'status') - status httpd - status mysqld - zmstatus - ;; - *) - echo "Usage: $0 { start | stop | restart | condrestart | status }" - RETVAL=1 - ;; -esac -exit $RETVAL diff --git a/distros/redhat/sysvinit/zoneminder.logrotate.in b/distros/redhat/sysvinit/zoneminder.logrotate.in deleted file mode 100644 index daf0b908f..000000000 --- a/distros/redhat/sysvinit/zoneminder.logrotate.in +++ /dev/null @@ -1,7 +0,0 @@ -@ZM_LOGDIR@/*log -{ - weekly - notifempty - missingok - create 660 @WEB_USER@ @WEB_GROUP@ -} diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 10ce1ff0a..c52ccbad9 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -2,13 +2,13 @@ %global zmgid_final apache # Crud is configured as a git submodule -%global crud_version 3.0.10 +%global crud_version 3.1.0-zm + +# CakePHP-Enum-Behavior is configured as a git submodule +%global ceb_version 1.0-zm %if "%{zmuid_final}" == "nginx" %global with_nginx 1 -%global wwwconfdir %{_sysconfdir}/nginx/default.d -%else -%global wwwconfdir %{_sysconfdir}/httpd/conf.d %endif %global sslcert %{_sysconfdir}/pki/tls/certs/localhost.crt @@ -22,18 +22,11 @@ %global with_apcu_bc 1 %endif -# Include files for SysV init or systemd -%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7 -%global with_init_systemd 1 -%else -%global with_init_sysv 1 -%endif - %global readme_suffix %{?rhel:Redhat%{?rhel}}%{!?rhel:Fedora} %global _hardened_build 1 Name: zoneminder -Version: 1.31.1 +Version: 1.31.43 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons @@ -41,18 +34,18 @@ Group: System Environment/Daemons # Mootools is inder the MIT license: http://mootools.net/ # CakePHP is under the MIT license: https://github.com/cakephp/cakephp # Crud is under the MIT license: https://github.com/FriendsOfCake/crud +# CakePHP-Enum-Behavior is under the MIT license: https://github.com/asper/CakePHP-Enum-Behavior License: GPLv2+ and LGPLv2+ and MIT URL: http://www.zoneminder.com/ Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz -Source1: https://github.com/FriendsOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz +Source1: https://github.com/ZoneMinder/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz +Source2: https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/%{ceb_version}.tar.gz#/cakephp-enum-behavior-%{ceb_version}.tar.gz -%{?with_init_systemd:BuildRequires: systemd-devel} -%{?with_init_systemd:BuildRequires: mariadb-devel} -%{?with_init_systemd:BuildRequires: perl-podlators} -%{?with_init_systemd:BuildRequires: polkit-devel} -%{?with_init_sysv:BuildRequires: mysql-devel} -%{?el6:BuildRequires: epel-rpm-macros} +BuildRequires: systemd-devel +BuildRequires: mariadb-devel +BuildRequires: perl-podlators +BuildRequires: polkit-devel BuildRequires: cmake >= 2.8.7 BuildRequires: gnutls-devel BuildRequires: bzip2-devel @@ -82,6 +75,11 @@ BuildRequires: vlc-devel BuildRequires: libcurl-devel BuildRequires: libv4l-devel BuildRequires: ffmpeg-devel +BuildRequires: desktop-file-utils + +# Required for mp4 container support +BuildRequires: libmp4v2-devel +BuildRequires: x264-devel %{?with_nginx:Requires: nginx} %{?with_nginx:Requires: fcgiwrap} @@ -112,19 +110,10 @@ Requires: perl(LWP::Protocol::https) Requires: ca-certificates Requires: zip -%{?with_init_systemd:Requires(post): systemd} -%{?with_init_systemd:Requires(post): systemd-sysv} -%{?with_init_systemd:Requires(preun): systemd} -%{?with_init_systemd:Requires(postun): systemd} - -%{?with_init_sysv:Requires(post): /sbin/chkconfig} -%{?with_init_sysv:Requires(post): %{_bindir}/checkmodule} -%{?with_init_sysv:Requires(post): %{_bindir}/semodule_package} -%{?with_init_sysv:Requires(post): %{_sbindir}/semodule} -%{?with_init_sysv:Requires(preun): /sbin/chkconfig} -%{?with_init_sysv:Requires(preun): /sbin/service} -%{?with_init_sysv:Requires(preun): %{_sbindir}/semodule} -%{?with_init_sysv:Requires(postun): /sbin/service} +Requires(post): systemd +Requires(post): systemd-sysv +Requires(preun): systemd +Requires(postun): systemd Requires(post): %{_bindir}/gpasswd Requires(post): %{_bindir}/less @@ -143,6 +132,11 @@ too much degradation of performance. %{__rm} -rf ./web/api/app/Plugin/Crud %{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud +# The all powerful autosetup macro does not work after the second source tarball +%{__gzip} -dc %{_sourcedir}/cakephp-enum-behavior-%{ceb_version}.tar.gz | tar -xvvf - +%{__rm} -rf ./web/api/app/Plugin/CakePHP-Enum-Behavior +%{__mv} -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Behavior + # Change the following default values ./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes ./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR %{_localstatedir}/spool/zoneminder-upload @@ -163,6 +157,12 @@ too much degradation of performance. %install %make_install +desktop-file-install \ + --dir %{buildroot}%{_datadir}/applications \ + --delete-original \ + --mode 644 \ + %{buildroot}%{_datadir}/applications/zoneminder.desktop + # Remove unwanted files and folders find %{buildroot} \( -name .htaccess -or -name .editorconfig -or -name .packlist -or -name .git -or -name .gitignore -or -name .gitattributes -or -name .travis.yml \) -type f -delete > /dev/null 2>&1 || : @@ -174,24 +174,10 @@ find %{buildroot}%{_datadir}/zoneminder/www/api \( -name cake -or -name cake.php %{__ln_s} ../../../../../../../..%{_sysconfdir}/pki/tls/certs/ca-bundle.crt %{buildroot}%{_datadir}/zoneminder/www/api/lib/Cake/Config/cacert.pem %post -%if 0%{?with_init_sysv} -/sbin/chkconfig --add zoneminder -/sbin/chkconfig zoneminder on - -# Create and load zoneminder selinux policy module -echo -e "\nCreating and installing a ZoneMinder SELinux policy module. Please wait.\n" -%{_bindir}/checkmodule -M -m -o %{_docdir}/%{name}-%{version}/local_zoneminder.mod %{_docdir}/%{name}-%{version}/local_zoneminder.te > /dev/null 2>&1 || : -%{_bindir}/semodule_package -o %{_docdir}/%{name}-%{version}/local_zoneminder.pp -m %{_docdir}/%{name}-%{version}/local_zoneminder.mod > /dev/null 2>&1 || : -%{_sbindir}/semodule -i %{_docdir}/%{name}-%{version}/local_zoneminder.pp > /dev/null 2>&1 || : - -%endif - -%if 0%{?with_init_systemd} # Initial installation if [ $1 -eq 1 ] ; then %systemd_post %{name}.service fi -%endif # Upgrade from a previous version of zoneminder if [ $1 -eq 2 ] ; then @@ -245,34 +231,11 @@ EOF %endif %preun -%if 0%{?with_init_sysv} -if [ $1 -eq 0 ]; then - /sbin/service zoneminder stop > /dev/null 2>&1 || : - /sbin/chkconfig --del zoneminder - echo -e "\nRemoving ZoneMinder SELinux policy module. Please wait.\n" - %{_sbindir}/semodule -r local_zoneminder.pp -fi -%endif - -%if 0%{?with_init_systemd} %systemd_preun %{name}.service -%endif %postun -%if 0%{?with_init_sysv} -if [ $1 -ge 1 ]; then - /sbin/service zoneminder condrestart > /dev/null 2>&1 || : -fi - -# Remove the doc folder. -rm -rf %{_docdir}/%{name}-%{version} -%endif - -%if 0%{?with_init_systemd} %systemd_postun_with_restart %{name}.service -%endif -%if 0%{?with_init_systemd} %triggerun -- zoneminder < 1.25.0-4 # Save the current service runlevel info # User must manually run systemd-sysv-convert --apply zoneminder @@ -282,7 +245,6 @@ rm -rf %{_docdir}/%{name}-%{version} # Run these because the SysV package being removed won't do them /sbin/chkconfig --del zoneminder >/dev/null 2>&1 || : /bin/systemctl try-restart zoneminder.service >/dev/null 2>&1 || : -%endif %files %license COPYING @@ -300,25 +262,18 @@ rm -rf %{_docdir}/%{name}-%{version} %config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/*.conf %ghost %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/zmcustom.conf -%config(noreplace) %attr(644,root,root) %{wwwconfdir}/zoneminder.conf +%config(noreplace) %attr(644,root,root) /etc/zm/www/zoneminder.conf %config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder %if 0%{?with_nginx} %config(noreplace) %{_sysconfdir}/php-fpm.d/zoneminder.conf %endif -%if 0%{?with_init_systemd} %{_tmpfilesdir}/zoneminder.conf %{_unitdir}/zoneminder.service %{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy %{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules %{_bindir}/zmsystemctl.pl -%endif - -%if 0%{?with_init_sysv} -%doc distros/redhat/misc/local_zoneminder.te -%attr(755,root,root) %{_initrddir}/zoneminder -%endif %{_bindir}/zma %{_bindir}/zmaudit.pl @@ -337,6 +292,7 @@ rm -rf %{_docdir}/%{name}-%{version} %{_bindir}/zmtelemetry.pl %{_bindir}/zmx10.pl %{_bindir}/zmonvif-probe.pl +%{_bindir}/zmstats.pl %{perl_vendorlib}/ZoneMinder* %{perl_vendorlib}/ONVIF* @@ -347,6 +303,7 @@ rm -rf %{_docdir}/%{name}-%{version} %{_libexecdir}/zoneminder/ %{_datadir}/zoneminder/ +%{_datadir}/applications/*%{name}.desktop %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/events @@ -354,11 +311,18 @@ rm -rf %{_docdir}/%{name}-%{version} %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/sock %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/swap %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/temp +%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/cache/zoneminder %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/log/zoneminder %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/spool/zoneminder-upload %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder %changelog +* Sun Apr 22 2018 Andrew Bauer - 1.31.42-1 +- Remove support for sysvinit a.k.a. el6 +- use desktop-file-install for new zoneminder.desktop file +- add new web cache folder +- 1.31.42 development snapshot + * Tue May 09 2017 Andrew Bauer - 1.30.4-1 - modify autosetup macro parameters - modify requirements for php-pecl-acpu-bc package diff --git a/distros/ubuntu1204/conf/apache2/zoneminder.conf b/distros/ubuntu1204/conf/apache2/zoneminder.conf index 0dc312769..81e9713db 100644 --- a/distros/ubuntu1204/conf/apache2/zoneminder.conf +++ b/distros/ubuntu1204/conf/apache2/zoneminder.conf @@ -6,6 +6,12 @@ ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin" Require all granted +# Order matters. This Alias must come first +Alias /zm/cache /var/cache/zoneminder/cache + + Options -Indexes +FollowSymLinks + + Alias /zm /usr/share/zoneminder/www php_flag register_globals off @@ -15,6 +21,28 @@ Alias /zm /usr/share/zoneminder/www - - AllowOverride All +# For better visibility, the following directives have been migrated from the +# default .htaccess files included with the CakePHP project. +# Parameters not set here are inherited from the parent directive above. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api + + diff --git a/distros/ubuntu1204/control b/distros/ubuntu1204/control index ad751ef71..febcb9435 100644 --- a/distros/ubuntu1204/control +++ b/distros/ubuntu1204/control @@ -54,6 +54,8 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,liburi-encode-perl ,libwww-perl ,libdata-uuid-perl + ,libnumber-bytes-human-perl + ,libfile-slurp-perl ,mysql-client | virtual-mysql-client ,perl-modules ,php5-mysql, php5-gd, php5-apcu, php-apc diff --git a/distros/ubuntu1204/rules b/distros/ubuntu1204/rules index 0103d1c27..aed63c110 100755 --- a/distros/ubuntu1204/rules +++ b/distros/ubuntu1204/rules @@ -25,6 +25,7 @@ override_dh_auto_configure: -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ + -DZM_CACHEDIR="/var/cache/zoneminder/cache" \ -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \ diff --git a/distros/ubuntu1204/zoneminder.dirs b/distros/ubuntu1204/zoneminder.dirs index ff1ec7858..79b2c66af 100644 --- a/distros/ubuntu1204/zoneminder.dirs +++ b/distros/ubuntu1204/zoneminder.dirs @@ -3,6 +3,7 @@ var/lib/zm var/cache/zoneminder/events var/cache/zoneminder/images var/cache/zoneminder/temp +var/cache/zoneminder/cache usr/share/zoneminder/db etc/zm etc/zm/conf.d diff --git a/distros/ubuntu1204/zoneminder.postinst b/distros/ubuntu1204/zoneminder.postinst index 06b976037..ef715375b 100644 --- a/distros/ubuntu1204/zoneminder.postinst +++ b/distros/ubuntu1204/zoneminder.postinst @@ -5,6 +5,10 @@ set -e if [ "$1" = "configure" ]; then . /etc/zm/zm.conf + for i in /etc/zm/conf.d/*.conf; do + . $i + done; + # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group chown www-data:root /var/log/zm diff --git a/distros/ubuntu1604/README.Debian b/distros/ubuntu1604/README.Debian index 8182e0678..4fe3464d2 100644 --- a/distros/ubuntu1604/README.Debian +++ b/distros/ubuntu1604/README.Debian @@ -23,8 +23,7 @@ configuration file: Upgrading database ------------------ -Prior to 1.28.1 database upgrade was performed automatically. -"zoneminder" service will refuse to start with outdated database. +The database is updated automatically on installation. You should not need to take this step. Assuming that database is on "localhost" then the following command can be used to upgrade "zm" database: @@ -45,17 +44,11 @@ The following command prints the current version of zoneminder database: Enabling service ---------------- -By default Zoneminder service is not starting automatically and need to be -manually activated once database is configured: - -On systemd: +By default Zoneminder service is not automatically started and needs to be +manually enabled once database is configured: sudo systemctl enable zoneminder.service -On SysV: - - sudo update-rc.d zoneminder enable - Web server set-up ----------------- @@ -82,10 +75,10 @@ Common configuration steps for Apache2: ## nginx / fcgiwrap -Nginx needs "php5-fpm" package to support PHP and "fcgiwrap" package +Nginx needs "php-fpm" package to support PHP and "fcgiwrap" package for binary "cgi-bin" applications: - sudo apt-get install php5-fpm fcgiwrap + sudo apt-get install php-fpm fcgiwrap To enable a URL alias that makes Zoneminder available from @@ -119,32 +112,9 @@ site configuration. Changing the location for images and events ------------------------------------------- -Zoneminder, in its upstream form, stores data in /usr/share/zoneminder/. This -package modifies that by changing /usr/share/zoneminder/images and -/usr/share/zoneminder/events to symlinks to directories under -/var/cache/zoneminder. - -There are numerous places these could be put and ways to do it. But, at the -moment, if you change this, an upgrade will fail with a warning about these -locations having changed (the reason for this was that previously, an upgrade -would silently revert the changes and cause event loss - refer -bug #608793). - -If you do want to change the location, here are a couple of suggestions. -(thanks to vagrant@freegeek.org): - -These lines in fstab could allow you to bind-mount an alternate location - - /dev/sdX1 /otherdrive ext3 defaults 0 2 - /otherdrive/zoneminder/images /var/cache/zoneminder/images bind defaults 0 2 - /otherdrive/zoneminder/events /var/cache/zoneminder/events bind defaults 0 2 - - or if you have a separate partition for each: - - /dev/sdX1 /var/cache/zoneminder/images ext3 defaults 0 2 - /dev/sdX2 /var/cache/zoneminder/events ext3 defaults 0 2 - - -- Peter Howard , Sun, 16 Jan 2010 01:35:51 +1100 +ZoneMinder is now able to be configured to use an alternative location for storing +events and images at compile time. This package makes use of that, so symlinks in +/usr/share/zoneminder/www are no longer necessary. Access to /dev/video* --------------------- diff --git a/distros/ubuntu1604/changelog b/distros/ubuntu1604/changelog index 3ea02e3ea..616f75178 100644 --- a/distros/ubuntu1604/changelog +++ b/distros/ubuntu1604/changelog @@ -1,7 +1,3 @@ -zoneminder (1.31.4-vivid1) vivid; urgency=medium - - * Release 1.31.4 - - -- Isaac Connor Thu, 21 Sep 2017 09:55:31 -0700 - - +zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low + * + -- Isaac Connor Fri, 23 Feb 2018 14:15:59 -0500 diff --git a/distros/ubuntu1604/conf/apache2/zoneminder.conf b/distros/ubuntu1604/conf/apache2/zoneminder.conf index 59efc6248..a51b153a9 100644 --- a/distros/ubuntu1604/conf/apache2/zoneminder.conf +++ b/distros/ubuntu1604/conf/apache2/zoneminder.conf @@ -6,6 +6,12 @@ ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin" Require all granted +# Order matters. This alias must come first. +Alias /zm/cache /var/cache/zoneminder/cache + + Options -Indexes +FollowSymLinks + + Alias /zm /usr/share/zoneminder/www Options -Indexes +FollowSymLinks @@ -14,6 +20,27 @@ Alias /zm /usr/share/zoneminder/www - - AllowOverride All +# For better visibility, the following directives have been migrated from the +# default .htaccess files included with the CakePHP project. +# Parameters not set here are inherited from the parent directive above. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api diff --git a/distros/ubuntu1604/control b/distros/ubuntu1604/control index 347d494b4..0b934b7d2 100644 --- a/distros/ubuntu1604/control +++ b/distros/ubuntu1604/control @@ -16,7 +16,7 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa ,libcurl4-gnutls-dev ,libgnutls-openssl-dev ,libjpeg8-dev | libjpeg9-dev | libjpeg62-turbo-dev - ,libmysqlclient-dev | libmariadbclient-dev + ,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat ,libpcre3-dev ,libpolkit-gobject-1-dev ,libv4l-dev (>= 0.8.3) [!hurd-any] @@ -39,7 +39,7 @@ Package: zoneminder Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,javascript-common - ,libmp4v2-2, libx264-142|libx264-148, libswscale-ffmpeg3|libswscale4|libswscale3 + ,libmp4v2-2, libx264-142|libx264-148|libx264-152, libswscale-ffmpeg3|libswscale4|libswscale3 ,ffmpeg | libav-tools ,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl ,libdbd-mysql-perl @@ -59,9 +59,11 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,libsoap-wsdl-perl ,libio-socket-multicast-perl ,libdigest-sha-perl - ,libsys-cpu-perl, libsys-cpuload-perl, libsys-meminfo-perl + ,libsys-cpu-perl, libsys-meminfo-perl ,libdata-uuid-perl - ,mysql-client | virtual-mysql-client + ,libnumber-bytes-human-perl + ,libfile-slurp-perl + ,mysql-client | mariadb-client | virtual-mysql-client ,perl-modules ,php5-mysql | php-mysql, php5-gd | php-gd , php5-apcu | php-apcu , php-apc | php-apcu-bc ,policykit-1 @@ -70,7 +72,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,libpcre3 Recommends: ${misc:Recommends} ,libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm - ,mysql-server | virtual-mysql-server + ,mysql-server | mariadb-server | virtual-mysql-server ,zoneminder-doc (>= ${source:Version}) ,ffmpeg Suggests: fcgiwrap, logrotate diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules index 53a9a237a..f0808a8e1 100755 --- a/distros/ubuntu1604/rules +++ b/distros/ubuntu1604/rules @@ -25,6 +25,7 @@ override_dh_auto_configure: -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ + -DZM_CACHEDIR="/var/cache/zoneminder/cache" \ -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" @@ -66,9 +67,6 @@ override_dh_fixperms: chown root:www-data $(CURDIR)/debian/zoneminder/etc/zm/zm.conf chmod 640 $(CURDIR)/debian/zoneminder/etc/zm/zm.conf -override_dh_installinit: - dh_installinit --no-start - override_dh_systemd_start: dh_systemd_start --no-start diff --git a/distros/ubuntu1604/zoneminder.dirs b/distros/ubuntu1604/zoneminder.dirs index 08840aef4..6db3d5a95 100644 --- a/distros/ubuntu1604/zoneminder.dirs +++ b/distros/ubuntu1604/zoneminder.dirs @@ -3,7 +3,7 @@ var/lib/zm var/cache/zoneminder/events var/cache/zoneminder/images var/cache/zoneminder/temp +var/cache/zoneminder/cache usr/share/zoneminder/db -usr/share/zoneminder/www/cache etc/zm/ etc/zm/conf.d diff --git a/distros/ubuntu1604/zoneminder.init b/distros/ubuntu1604/zoneminder.init deleted file mode 100644 index 5cdf62165..000000000 --- a/distros/ubuntu1604/zoneminder.init +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: zoneminder -# Required-Start: $network $remote_fs $syslog -# Required-Stop: $network $remote_fs $syslog -# Should-Start: mysql -# Should-Stop: mysql -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Control ZoneMinder as a Service -# Description: ZoneMinder CCTV recording and surveillance system -### END INIT INFO -# chkconfig: 2345 20 20 - -# Source function library. -. /lib/lsb/init-functions - -prog=ZoneMinder -ZM_PATH_BIN="/usr/bin" -RUNDIR="/var/run/zm" -TMPDIR="/tmp/zm" -command="$ZM_PATH_BIN/zmpkg.pl" - -start() { - echo -n "Starting $prog: " - export TZ=:/etc/localtime - mkdir -p "$RUNDIR" && chown www-data:www-data "$RUNDIR" - mkdir -p "$TMPDIR" && chown www-data:www-data "$TMPDIR" - $command start - RETVAL=$? - [ $RETVAL = 0 ] && echo success - [ $RETVAL != 0 ] && echo failure - echo - [ $RETVAL = 0 ] && touch /var/lock/zm - return $RETVAL -} -stop() { - echo -n "Stopping $prog: " - # - # Why is this status check being done? - # as $command stop returns 1 if zoneminder - # is stopped, which will result in - # this returning 1, which will stuff - # dpkg when it tries to stop zoneminder before - # uninstalling . . . - # - result=`$command status` - if [ ! "$result" = "running" ]; then - echo "Zoneminder already stopped" - echo - RETVAL=0 - else - $command stop - RETVAL=$? - [ $RETVAL = 0 ] && echo success - [ $RETVAL != 0 ] && echo failure - echo - [ $RETVAL = 0 ] && rm -f /var/lock/zm - fi -} -status() { - result=`$command status` - if [ "$result" = "running" ]; then - echo "ZoneMinder is running" - RETVAL=0 - else - echo "ZoneMinder is stopped" - RETVAL=1 - fi -} - -case "$1" in -'start') - start - ;; -'stop') - stop - ;; -'restart' | 'force-reload') - stop - start - ;; -'status') - status - ;; -*) - echo "Usage: $0 { start | stop | restart | status }" - RETVAL=1 - ;; -esac -exit $RETVAL diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index 66d696208..98e5259c3 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -1,40 +1,65 @@ #! /bin/sh -set -e +set +e if [ "$1" = "configure" ]; then - + . /etc/zm/zm.conf - + for CONFFILE in /etc/zm/conf.d/*.conf; do + . "$CONFFILE" + done + # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group chown www-data:root /var/log/zm chown www-data:www-data /var/lib/zm if [ -z "$2" ]; then - chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* /usr/share/zoneminder/www/cache + chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* fi - if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ]; then + if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ] && [ "$(command -v a2enmod)" != "" ]; then echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi." a2enmod cgi fi if [ "$ZM_DB_HOST" = "localhost" ]; then - if [ -e "/etc/init.d/mysql" ]; then - # Do this every time the package is installed or upgraded + if [ -e "/lib/systemd/system/mysql.service" ] || [ -e "/lib/systemd/system/mariadb.service" ]; then # Ensure zoneminder is stopped deb-systemd-invoke stop zoneminder.service || exit $? - + # - # Get mysql started if it isn't + # Get mysql started if it isn't running # - if $(/etc/init.d/mysql status >/dev/null 2>&1); then + + if [ -e "/lib/systemd/system/mariadb.service" ]; then + DBSERVICE="mariadb.service" + else + DBSERVICE="mysql.service" + fi + echo "Detected db service is $DBSERVICE" + if systemctl is-failed --quiet $DBSERVICE; then + echo "$DBSERVICE is in a failed state; it will not be started." + echo "If you have already resolved the problem preventing $DBSERVICE from running," + echo "run sudo systemctl restart $DBSERVICE then run sudo dpkg-reconfigure zoneminder." + exit 1 + fi + + if ! systemctl is-active --quiet mysql.service mariadb.service; then + # Due to /etc/init.d service autogeneration, mysql.service always returns the status of mariadb.service + # However, mariadb.service will not return the status of mysql.service. + deb-systemd-invoke start $DBSERVICE + fi + + # Make sure systemctl status exit code is 0; i.e. the DB is running + if systemctl is-active --quiet "$DBSERVICE"; then mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload # test if database if already present... if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then + echo "Creating zm db" cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf # This creates the user. echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql else + echo "Updating permissions" echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi @@ -43,20 +68,20 @@ if [ "$1" = "configure" ]; then # Add any new PTZ control configurations to the database (will not overwrite) zmcamtool.pl --import >/dev/null 2>&1 - else - echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.' + echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.' fi else - echo 'mysql not found, assuming remote server.' + echo 'MySQL/MariaDB not found; assuming remote server.' fi else - echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)" + echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)." fi - echo "Done Updating, starting ZoneMinder" - deb-systemd-invoke restart zoneminder.service || exit $? + echo "Done Updating; starting ZoneMinder." + deb-systemd-invoke restart zoneminder.service + fi #DEBHELPER# diff --git a/distros/ubuntu1604/zoneminder.tmpfile b/distros/ubuntu1604/zoneminder.tmpfile index f23ca55b3..9435be2a8 100644 --- a/distros/ubuntu1604/zoneminder.tmpfile +++ b/distros/ubuntu1604/zoneminder.tmpfile @@ -1,4 +1,4 @@ d /var/run/zm 0755 www-data www-data d /tmp/zm 0755 www-data www-data d /var/tmp/zm 0755 www-data www-data -d /usr/share/zoneminder/www/cache 0755 www-data www-data +d /var/cache/zoneminder/cache 0755 www-data www-data diff --git a/docs/api.rst b/docs/api.rst index 36467525a..706748880 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -98,15 +98,15 @@ This command will add a new http monitor. :: - curl -XPOST http://server/zm/api/monitors.json -d "Monitor[Name]=Cliff-Burton \ - &Monitor[Function]=Modect \ - &Monitor[Protocol]=http \ - &Monitor[Method]=simple \ - &Monitor[Host]=usr:pass@192.168.11.20 \ - &Monitor[Port]=80 \ - &Monitor[Path]=/mjpg/video.mjpg \ - &Monitor[Width]=704 \ - &Monitor[Height]=480 \ + curl -XPOST http://server/zm/api/monitors.json -d "Monitor[Name]=Cliff-Burton\ + &Monitor[Function]=Modect\ + &Monitor[Protocol]=http\ + &Monitor[Method]=simple\ + &Monitor[Host]=usr:pass@192.168.11.20\ + &Monitor[Port]=80\ + &Monitor[Path]=/mjpg/video.mjpg\ + &Monitor[Width]=704\ + &Monitor[Height]=480\ &Monitor[Colours]=4" Edit monitor 1 @@ -304,26 +304,26 @@ Create a Zone :: - curl -XPOST http://server/zm/api/zones.json -d "Zone[Name]=Jason-Newsted \ - &Zone[MonitorId]=3 \ - &Zone[Type]=Active \ - &Zone[Units]=Percent \ - &Zone[NumCoords]=4 \ - &Zone[Coords]=0,0 639,0 639,479 0,479 \ - &Zone[AlarmRGB]=16711680 \ - &Zone[CheckMethod]=Blobs \ - &Zone[MinPixelThreshold]=25 \ - &Zone[MaxPixelThreshold]= \ - &Zone[MinAlarmPixels]=9216 \ - &Zone[MaxAlarmPixels]= \ - &Zone[FilterX]=3 \ - &Zone[FilterY]=3 \ - &Zone[MinFilterPixels]=9216 \ - &Zone[MaxFilterPixels]=230400 \ - &Zone[MinBlobPixels]=6144 \ - &Zone[MaxBlobPixels]= \ - &Zone[MinBlobs]=1 \ - &Zone[MaxBlobs]= \ + curl -XPOST http://server/zm/api/zones.json -d "Zone[Name]=Jason-Newsted\ + &Zone[MonitorId]=3\ + &Zone[Type]=Active\ + &Zone[Units]=Percent\ + &Zone[NumCoords]=4\ + &Zone[Coords]=0,0 639,0 639,479 0,479\ + &Zone[AlarmRGB]=16711680\ + &Zone[CheckMethod]=Blobs\ + &Zone[MinPixelThreshold]=25\ + &Zone[MaxPixelThreshold]=\ + &Zone[MinAlarmPixels]=9216\ + &Zone[MaxAlarmPixels]=\ + &Zone[FilterX]=3\ + &Zone[FilterY]=3\ + &Zone[MinFilterPixels]=9216\ + &Zone[MaxFilterPixels]=230400\ + &Zone[MinBlobPixels]=6144\ + &Zone[MaxBlobPixels]=\ + &Zone[MinBlobs]=1\ + &Zone[MaxBlobs]=\ &Zone[OverloadFrames]=0" PTZ Control APIs diff --git a/docs/faq.rst b/docs/faq.rst index 87421ddb9..7735ff38f 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -71,22 +71,23 @@ The 1.2 at the start is basically adding 20% on top of the calculation to accoun The math breakdown for 4 cameras running at 1280x960 capture, 50 frame buffer, 24 bit color space: :: - 1280*960 = 1,228,800 (bits) - 1,228,800 * 24 = 2,359,296,000 (bits) - 2,359,296,000 * 50 = 5,898,240,000 (bits) - 5,898,240,000 * 4 = 7,077,888,000 (bits) - 7,077,888,000 / 8 = 884,736,000 (bytes) - 884,736,000 / 1000 = 884,736 (Kilobytes) - 884,736 / 1000 = 864 (Megabytes) - 864 / 1000 = 0.9 (Gigabyte) -Around 900MB of memory. + 1280*960 = 1,228,800 (bytes) + 1,228,800 * (3 bytes for 24 bit) = 3,686,400 (bytes) + 3,686,400 * 50 = 184,320,000 (bytes) + 184,320,000 * 4 = 737,280,000 (bytes) + 737,280,000 / 1024 = 720,000 (Kilobytes) + 720,000 / 1024 = 703.125 (Megabytes) + 703.125 / 1024 = 0.686 (Gigabytes) + +Around 700MB of memory. So if you have 2GB of memory, you should be all set. Right? **Not, really**: * This is just the base memory required to capture the streams. Remember ZM is always capturing streams irrespective of whether you are actually recording or not - to make sure its image ring buffer is there with pre images when an alarm kicks in. * You also need to account for other processes not related to ZM running in your box * You also need to account for other ZM processes - for example, I noticed the audit daemon takes up a good amount of memory when it runs, DB updates also take up memory + * If you are using H264 encoding, that buffers a lot of frames in memory as well. So a good rule of thumb is to make sure you have twice the memory as the calculation above (and if you are using the ZM server for other purposes, please factor in those memory requirements as well) @@ -128,15 +129,14 @@ So, for example: :: 384x288 capture resolution, that makes: 110 592 pixels - in 24 bit color that's x24 = 2 654 208 bits per frame - by 80 frames ring buffer x80 = 212 336 640 bits per camera - by 4 cameras x4 = 849 346 560 bits. - Plus 10% overhead = 934 281 216 bits - That's 116 785 152 bytes, and - = 114 048 kB, respectively 111.38 MB. - If my shared memory is set to 134 217 728, which is exactly 128MB, + in 24 bit color that's x 3 = 331,776 bytes per frame + by 80 frames ring buffer x80 = 26,542,080 bytes per camera + by 4 cameras x4 = 106,168,320 bytes. + Plus 10% overhead = 116,785,152 bytes + Thats 114,048 kB, respectively 111.38 MB. + If my shared memory is set to 134,217,728, which is exactly 128MB, that means I shouldn't have any problem. - (Note that 1 byte = 8 bits and 1kbyte = 1024bytes, 1MB = 1024 kB) + (Note that 1kbyte = 1024bytes, 1MB = 1024 kB) If for instance you were using 24bit 640x480 then this would come to about 92Mb if you are using the default buffer size of 100. If this is too large then you can either reduce the image or buffer sizes or increase the maximum amount of shared memory available. If you are using RedHat then you can get details on how to change these settings `here `__ diff --git a/docs/installationguide/dedicateddrive.rst b/docs/installationguide/dedicateddrive.rst new file mode 100644 index 000000000..f0dfadc28 --- /dev/null +++ b/docs/installationguide/dedicateddrive.rst @@ -0,0 +1,39 @@ +Dedicated Drive, Partition, or Network Share +============================================ + +One of the first steps the end user must perform after installing ZoneMinder is to dedicate an entire partition, drive, or network share for ZoneMinder's event storage. +The reason being, ZoneMinder will, by design, fill up your hard disk, and you don't want to do that to your root volume! + +The following steps apply to ZoneMinder 1.31 or newer, running on a typical Linux system, which uses systemd. +If you are using an older version of ZoneMinder, please follow the legacy steps in the `ZoneMinder Wiki `_. + +**Step 1:** Stop ZoneMinder +:: + + sudo systemctl stop zoneminder + +**Step 2:** Mount your dedicated drive, partition, or network share to the local filesystem in any folder of your choosing. +We recommend you use systemd to manage the mount points. +Instructions on how to accomplish this can be found `here `__ and `here `__. +Note that bind mounting ZoneMinder's images folder is optional. Newer version of ZoneMinder write very little, if anything, to the images folder. +Verify the dedicated drive, partition, or network share is successfully mounted before proceeding to the next step. + +**Step 3:** Set the owner and group to that of the web server user account. Debian based distros typically use "www-data" as the web server user account while many rpm based distros use "apache". +:: + + sudo chown -R apache:apache /path/to/your/zoneminder/events/folder + sudo chown -R apache:apache /path/to/your/zoneminder/images/folder + +Recall from the previous step, the images folder is optional. + +**Step 4:** Create a config file under /etc/zm/conf.d using your favorite text editor. Name the file anything you want just as long as it ends in ".conf". +Add the following content to the file and save your changes: +:: + + ZM_DIR_EVENTS=/full/path/to/the/events/folder + ZM_DIR_IMAGES=/full/path/to/the/images/folder + +**Step 5:** Start ZoneMinder and inspect the ZoneMinder log files for errors. +:: + + sudo systemctl start zoneminder diff --git a/docs/installationguide/index.rst b/docs/installationguide/index.rst index 8b8a7c376..4e2288de6 100644 --- a/docs/installationguide/index.rst +++ b/docs/installationguide/index.rst @@ -11,3 +11,4 @@ Contents: debian redhat multiserver + dedicateddrive diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 6b558d11c..dd54ef4b2 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -1,4 +1,4 @@ -All Distros - A Simpler Way to Build ZoneMinder +All Distros - A Docker Way to Build ZoneMinder =============================================== .. contents:: @@ -27,6 +27,8 @@ Procedure - If the desired distro does not appear in either list, then unfortuantely you cannot use the procedure described here. +- If the desired distro architecture is arm, refer to `Appendix A - Enable Qemu On the Host`_ to enable qemu emulation on your amd64 host machine. + **Step 2:** Install Docker. You need to have a working installation of Docker so head over to the `Docker site `_ and get it working. Before continuing to the next step, verify you can run the Docker "Hello World" container as a normal user. To run a Docker container as a normal user, issue the following: @@ -44,7 +46,7 @@ Clone the ZoneMinder project if you have not done so already. :: - git clone https://ZoneMinder/ZoneMinder + git clone https://github.com/ZoneMinder/ZoneMinder cd ZoneMinder Alternatively, if you have already cloned the repo and wish to update it, do the following. @@ -99,7 +101,27 @@ For advanced users who really want to go out into uncharted waters, it is theore Building arm packages in this manner has not been tested by us, however. +Appendix A - Enable Qemu On the Host +------------------------------------ +If you intend to build ZoneMinder packages for arm on an amd64 host, then Debian users can following these steps to enable transparent Qemu emulation: +:: + sudo apt-get install binfmt-support qemu qemu-user-static +Verify arm emulation is enabled by issuing: + +:: + + sudo update-binfmts --enable qemu-arm + +You may get a message stating emulation for this processor is already enabled. + +More testing needs to be done for Redhat distros but it appears Fedora users can just run: + +:: + + sudo systemctl start systemd-binfmt + +TO-DO: Verify the details behind enabling qemu emulation on redhat distros. Pull requests are welcome. diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index fbbb7a5d8..12d9ed769 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -45,9 +45,7 @@ The following notes are based on real problems which have occurred by those who How to Install ZoneMinder ------------------------- -These instructions apply to all redhat distros and compatible clones, except for RHEL/CentOS 6. - -ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site `_ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site `_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline: +ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site `__ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site `_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline: :: @@ -57,13 +55,6 @@ Note that RHEL/CentOS 7 users should use yum instead of dnf. Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder. ZoneMinder will not run without completing the steps outlined in the README. -How to Install ZoneMinder on RHEL/CentOS 6 ------------------------------------------- - -We continue to encounter build problems, caused by the age of this distro. It is unforuntate, but we can see the writing on the wall. We do not have a date set, but the end of the line for this distros is near. - -Please be advised that we do not recommend any new ZoneMinder installations using CentOS 6. However, for the time being, ZoneMinder rpms will continue to be hosted at `zmrepo `_. - How to Install Nightly Development Builds ----------------------------------------- @@ -74,9 +65,9 @@ The feedback we get from those who use these development packages is extremely h How to Change from Zmrepo to RPM Fusion --------------------------------------- -As mentioned above, the place to get the latest ZoneMinder release is now `RPM Fusion `_. If you are currently using ZoneMinder release packages from Zmrepo, then the following steps will change you over to RPM Fusion: +As mentioned above, the place to get the latest ZoneMinder release is now `RPM Fusion `__. If you are currently using ZoneMinder release packages from Zmrepo, then the following steps will change you over to RPM Fusion: -- Navigate to the `RPM Fusion site `_ and enable RPM Fusion on your system +- Navigate to the `RPM Fusion site `__ and enable RPM Fusion on your system - Now issue the following from the command line: :: @@ -132,7 +123,7 @@ Your build environment is now set up. Build from SRPM *************** -To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest source rpm from our master branch then browse the `Zmrepo site `_. +To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `__. If instead you wish to rebuild the latest source rpm from our master branch then browse the `Zmrepo site `_. For this example, I'll use one of the source rpms from zmrepo: diff --git a/docs/userguide/definemonitor.rst b/docs/userguide/definemonitor.rst index 66e8928d3..8f85feb98 100644 --- a/docs/userguide/definemonitor.rst +++ b/docs/userguide/definemonitor.rst @@ -147,6 +147,23 @@ Keep aspect ratio Orientation As per local devices. +WebSite +^^^^^^^ + +This Source Type allows one to configure an arbitrary website as a non-reocrdable, fully interactive, monitor in ZoneMinder. Note that sites with self-signed certificates will not display until the end user first manually navigates to the site and accpets the unsigned certificate. Also note that some sites will set an X-Frame option in the header, which discourages their site from being displayed within a frame. ZoneMinder will detect this condition and present a warning in the log. When this occurs, the end user can choose to install a browser plugin or extension to workaround this issue. + +Website URL + Enter the full http or https url to the desired website. + +Width (pixels) + Chose a desired width in pixels that gives an acceptable appearance. This may take some expirimentation. + +Height (pixels) + Chose a desired height in pixels that gives an acceptable appearance. This may take some expirimentation. + +Web Site Refresh + If the website in question has static content, optionally enter a time period in seconds for ZoneMinder to refresh the content. + Timestamp Tab ------------- diff --git a/docs/userguide/viewmonitors.rst b/docs/userguide/viewmonitors.rst index 1c67c4a25..448b63a9d 100644 --- a/docs/userguide/viewmonitors.rst +++ b/docs/userguide/viewmonitors.rst @@ -1,7 +1,7 @@ Viewing Monitors ================ -ZoneMinder allows you to view a live feed of your configured monitors. Once can access this view by clicking on the "Name" column of any of the monitors +ZoneMinder allows you to view a live feed of your configured monitors. One can access this view by clicking on the "Name" column of any of the monitors .. image:: images/viewmonitor-main.png :width: 500px diff --git a/misc/apache.conf.in b/misc/apache.conf.in index 1344bb9b1..cb9c08667 100644 --- a/misc/apache.conf.in +++ b/misc/apache.conf.in @@ -8,6 +8,23 @@ ServerAdmin webmaster@localhost DocumentRoot "@WEB_PREFIX@" + + # Order matters. This alias must come first. + Alias /zm/cache "@ZM_CACHEDIR@" + + Options -Indexes +FollowSymLinks + AllowOverride None + + # Apache 2.4 + Require all granted + + + # Apache 2.2 + Order deny,allow + Allow from all + + + Alias /zm "@WEB_PREFIX@" Options -Indexes +FollowSymLinks @@ -38,6 +55,31 @@ + # For better visibility, the following directives have been migrated from the + # default .htaccess files included with the CakePHP project. + # Parameters not set here are inherited from the parent directive above. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api + + # Use the first option to have Apache logs written to the general log # directory, or the second to have them written to the regular Apache # directory (you may have to change the path to that used on your system) diff --git a/misc/zoneminder.desktop.in b/misc/zoneminder.desktop.in index fd7f247d8..675dc62c5 100755 --- a/misc/zoneminder.desktop.in +++ b/misc/zoneminder.desktop.in @@ -5,4 +5,3 @@ Name=ZoneMinder Comment= Icon=@PKGDATADIR@/icons/16x16/icon.xpm URL=http://localhost/zm/\r -Categories=GNOME;AudioVideo;Video;Recorder; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 00015ae24..6eb41e57e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -400,7 +400,22 @@ our @options = ( type => $types{boolean}, category => 'system', }, -# PP - Google reCaptcha settings + { + name => 'ZM_OPT_USE_EVENTNOTIFICATION', + default => 'no', + description => 'Enable 3rd party Event Notification Server', + help => q` + zmeventnotification is a 3rd party event notification server + that is used to get notifications for alarms detected by ZoneMinder + in real time. zmNinja requires this server for push notifications to + mobile phones. This option only enables the server if its already installed. + Please visit https://github.com/pliablepixels/zmeventserver for installation + instructions. + `, + type => $types{boolean}, + category => 'system', + }, + # Google reCaptcha settings { name => 'ZM_OPT_USE_GOOG_RECAPTCHA', default => 'no', @@ -424,7 +439,6 @@ our @options = ( }, { name => 'ZM_OPT_GOOG_RECAPTCHA_SITEKEY', - default => '...Insert your recaptcha site-key here...', description => 'Your recaptcha site-key', help => q`You need to generate your keys from the Google reCaptcha website. @@ -1709,26 +1723,6 @@ our @options = ( type => $types{abs_path}, category => 'config', }, - { - name => 'ZM_SIGNAL_CHECK_POINTS', - default => '10', - description => 'How many points in a captured image to check for signal loss', - help => q` - For locally attached video cameras ZoneMinder can check for - signal loss by looking at a number of random points on each - captured image. If all of these points are set to the same - fixed colour then the camera is assumed to have lost signal. - When this happens any open events are closed and a short one - frame signal loss event is generated, as is another when the - signal returns. This option defines how many points on each - image to check. Note that this is a maximum, any points found - to not have the check colour will abort any further checks so - in most cases on a couple of points will actually be checked. - Network and file based cameras are never checked. - `, - type => $types{integer}, - category => 'config', - }, { name => 'ZM_V4L_MULTI_BUFFER', default => 'yes', @@ -2952,6 +2946,23 @@ our @options = ( type => $types{boolean}, category => 'web', }, + { + name => 'ZM_WEB_XFRAME_WARN', + default => 'yes', + description => 'Warn when website X-Frame-Options is set to sameorigin', + help => q` + When creating a Web Site monitor, if the target web site has + X-Frame-Options set to sameorigin in the header, the site will + not display in ZoneMinder. This is a design feature in most modern + browsers. When this condiction has occured, ZoneMinder will write a + warning to the log file. To get around this, one can install a browser + plugin or extension to ignore X-Frame headers, and then the page will + display properly. Once the plugin or extenstion has ben installed, + the end user may choose to turn this warning off. + `, + type => $types{boolean}, + category => 'web', + }, { name => 'ZM_WEB_H_REFRESH_MAIN', default => '60', diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm index 4603645fa..efd17abcd 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm @@ -47,9 +47,9 @@ sub new { my $class = shift; my $id = shift; my $self = {}; - $self->{name} = "PelcoD"; + $self->{name} = $class; if ( !defined($id) ) { - Fatal( "No monitor defined when invoking protocol ".$self->{name} ); + Fatal('No monitor defined when invoking protocol '.$self->{name}); } $self->{id} = $id; bless( $self, $class ); @@ -61,14 +61,13 @@ sub DESTROY { sub AUTOLOAD { my $self = shift; - my $class = ref($self) || croak( "$self not object" ); + my $class = ref($self) || Fatal("$self not object"); my $name = $AUTOLOAD; $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); + if ( exists($self->{$name}) ) { + return $self->{$name}; } - croak( "Can't access $name member of object of class $class" ); + Error("Can't access $name member of object of class $class"); } sub getKey { @@ -83,7 +82,8 @@ sub open { sub close { my $self = shift; - Fatal( "No close method defined for protocol ".$self->{name} ); + $self->{state} = 'closed'; + Debug('No close method defined for protocol '.$self->{name}); } sub loadMonitor { diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm index 2ccd275ce..31e99be26 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm @@ -50,31 +50,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -88,12 +63,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm index daa39ed72..d63236c86 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm @@ -44,31 +44,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -82,12 +57,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS3415.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS3415.pm new file mode 100644 index 000000000..03561c0fd --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS3415.pm @@ -0,0 +1,189 @@ +# ========================================================================== +# +# ZoneMinder D-Link DCS-3415 IP Control Protocol Module, 2018-03-04, 0.1 +# Copyright (C) 2015-2018 Habib Kamei +# +# Modified for use with D-Link DCS-3415 IP Camera by Habib Kamei +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# ========================================================================== +# +# This module contains the implementation of the D-Link DCS-3415 device control protocol +# +#=========================================================================== + +package ZoneMinder::Control::DCS3415; + +use 5.006; +use strict; +use warnings; + +require ZoneMinder::Base; +require ZoneMinder::Control; + +our @ISA = qw(ZoneMinder::Control); + +# ========================================================================== +# +# D-Link DCS-3415 Control Protocol +# +# On ControlAddress use the format : +# USERNAME:PASSWORD@ADDRESS:PORT +# eg : admin:@10.1.2.1:80 +# zoneuser:zonepass@192.168.0.20:40000 +# +# ========================================================================== + +use ZoneMinder::Logger qw(:all); +use ZoneMinder::Config qw(:all); + +use Time::HiRes qw( usleep ); + +sub new +{ + my $class = shift; + my $id = shift; + my $self = ZoneMinder::Control->new( $id ); + bless( $self, $class ); + srand( time() ); + return $self; +} + +our $AUTOLOAD; + +sub AUTOLOAD +{ + my $self = shift; + my $class = ref( ) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + if ( exists($self->{$name}) ) + { + return( $self->{$name} ); + } + Fatal( "Can't access $name member of object of class $class" ); +} + +sub open +{ + my $self = shift; + + $self->loadMonitor(); + + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); + + $self->{state} = 'open'; +} + +sub printMsg +{ + my $self = shift; + my $msg = shift; + my $msg_len = length($msg); + + Debug( $msg."[".$msg_len."]" ); +} + +sub sendCmd +{ + my $self = shift; + my $cmd = shift; + my $result = undef; + printMsg( $cmd, "Tx" ); + + my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/cgi-bin/viewer/$cmd" ); + my $res = $self->{ua}->request($req); + + + if ( $res->is_success ) + { + $result = !undef; + } + else + { + Error( "Error check failed:'".$res->status_line()."'" ); + } + + return( $result ); +} + +#Zoom In +sub Tele +{ + my $self = shift; + Debug( "Zoom Tele" ); + my $cmd = "camctrl.cgi?channel=0&camid=1&zoom=tele"; + $self->sendCmd( $cmd ); +} + +#Zoom Out +sub Wide +{ + my $self = shift; + Debug( "Zoom Wide" ); + my $cmd = "camctrl.cgi?channel=0&camid=1&zoom=wide"; + $self->sendCmd( $cmd ); +} + +#Focus Near +sub Near +{ + my $self = shift; + Debug( "Focus Near" ); + my $cmd = "camctrl.cgi?channel=0&camid=1&focus=near"; + $self->sendCmd( $cmd ); +} + +#Focus Far +sub Far +{ + my $self = shift; + Debug( "Focus Far" ); + my $cmd = "camctrl.cgi?channel=0&camid=1&focus=far"; + $self->sendCmd( $cmd ); +} + +1; +__END__ +# Below is stub documentation for your module. You'd better edit it! +=head1 NAME +ZoneMinder::Database - Perl extension for blah blah blah +=head1 SYNOPSIS + use ZoneMinder::Database; + blah blah blah +=head1 DESCRIPTION +Stub documentation for ZoneMinder, created by h2xs. It looks like the +author of the extension was negligent enough to leave the stub +unedited. +Blah blah blah. +=head2 EXPORT +None by default. +=head1 SEE ALSO +Mention other useful documentation such as the documentation of +related modules or operating system documentation (such as man pages +in UNIX), or any relevant external documentation such as RFCs or +standards. +If you have a mailing list set up for your module, mention it here. +If you have a web site set up for your module, mention it here. +=head1 AUTHOR +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/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm index c8a77aa2c..87b7707a4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm @@ -79,31 +79,6 @@ use Time::HiRes qw( usleep ); # this script is reload at every command ,if i want the button on/off (Focus MAN) for OSD works... my $osd = "on"; -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -114,12 +89,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm index 5eb06219d..bb5146d42 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm @@ -85,31 +85,6 @@ use Time::HiRes qw( usleep ); # this script is reload at every command ,if i want the button on/off (Focus MAN) for OSD works... my $osd = "on"; -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -120,12 +95,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm index 9cf00d077..5501d4e21 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm @@ -80,12 +80,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm index 9d023320a..0159364c9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8918W.pm @@ -63,33 +63,8 @@ our $VERSION = $ZoneMinder::Base::VERSION; use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); - use Time::HiRes qw( usleep ); +use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} our $stop_command; sub open diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm index 7165fd686..921646438 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm @@ -94,12 +94,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $msg = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Floureon.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Floureon.pm index bb3504067..521409e11 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Floureon.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Floureon.pm @@ -55,31 +55,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} our $stop_command; sub open @@ -94,12 +69,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm index f9cabd5fa..8754500fa 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm @@ -53,158 +53,136 @@ use HTTP::Cookies; my $ChannelID = 1; # Usually... my $DefaultFocusSpeed = 50; # Should be between 1 and 100 my $DefaultIrisSpeed = 50; # Should be between 1 and 100 +my ($user,$pass,$host,$port); -sub new { - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD { - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} sub open { - my $self = shift; - $self->loadMonitor(); - # - # Create a UserAgent for the requests - # - $self->{UA} = LWP::UserAgent->new(); - $self->{UA}->cookie_jar( {} ); - # - # Extract the username/password host/port from ControlAddress - # - my ($user,$pass,$host,$port); - if( $self->{Monitor}{ControlAddress} =~ /^([^:]+):([^@]+)@(.+)/ ) { # user:pass@host... - $user = $1; - $pass = $2; - $host = $3; - } - elsif( $self->{Monitor}{ControlAddress} =~ /^([^@]+)@(.+)/ ) { # user@host... - $user = $1; - $host = $2; - } - else { # Just a host - $host = $self->{Monitor}{ControlAddress}; - } - # Check if it is a host and port or just a host - if( $host =~ /([^:]+):(.+)/ ) { - $host = $1; - $port = $2; - } - else { - $port = 80; - } - # Save the credentials - if( defined($user) ) { - $self->{UA}->credentials( "$host:$port", $self->{Monitor}{ControlDevice}, $user, $pass ); - } - # Save the base url - $self->{BaseURL} = "http://$host:$port"; + my $self = shift; + $self->loadMonitor(); + # + # Create a UserAgent for the requests + # + $self->{UA} = LWP::UserAgent->new(); + $self->{UA}->cookie_jar( {} ); + # + # Extract the username/password host/port from ControlAddress + # + if ( $self->{Monitor}{ControlAddress} =~ /^([^:]+):([^@]+)@(.+)/ ) { # user:pass@host... + $user = $1; + $pass = $2; + $host = $3; + } elsif ( $self->{Monitor}{ControlAddress} =~ /^([^@]+)@(.+)/ ) { # user@host... + $user = $1; + $host = $2; + } else { # Just a host + $host = $self->{Monitor}{ControlAddress}; + } + # Check if it is a host and port or just a host + if ( $host =~ /([^:]+):(.+)/ ) { + $host = $1; + $port = $2; + } else { + $port = 80; + } + # Save the credentials + if ( defined($user) ) { + $self->{UA}->credentials("$host:$port", $self->{Monitor}{ControlDevice}, $user, $pass); + } + # Save the base url + $self->{BaseURL} = "http://$host:$port"; } + sub PutCmd { - my $self = shift; - my $cmd = shift; - my $content = shift; - my $req = HTTP::Request->new(PUT => "$self->{BaseURL}/$cmd"); - if(defined($content)) { - $req->content_type("application/x-www-form-urlencoded; charset=UTF-8"); - $req->content('' . "\n" . $content); - } - my $res = $self->{UA}->request($req); - unless( $res->is_success ) { - # - # The camera timeouts connections at short intervals. When this - # happens the user agent connects again and uses the same auth tokens. - # The camera rejects this and asks for another token but the UserAgent - # just gives up. Because of this I try the request again and it should - # succeed the second time if the credentials are correct. - # - if($res->code == 401) { - $res = $self->{UA}->request($req); - unless( $res->is_success ) { - # - # It has failed authentication. The odds are - # that the user has set some paramater incorrectly - # so check the realm against the ControlDevice - # entry and send a message if different - # - my $auth = $res->headers->www_authenticate; - foreach (split(/\s*,\s*/,$auth)) { - if( $_ =~ /^realm\s*=\s*"([^"]+)"/i ) { - if( $self->{Monitor}{ControlDevice} ne $1 ) { - Info "Control Device appears to be incorrect."; - Info "Control Device should be set to \"$1\"."; - Info "Control Device currently set to \"$self->{Monitor}{ControlDevice}\"."; - } + my $self = shift; + my $cmd = shift; + my $content = shift; + my $req = HTTP::Request->new(PUT => "$self->{BaseURL}/$cmd"); + if ( defined($content) ) { + $req->content_type("application/x-www-form-urlencoded; charset=UTF-8"); + $req->content('' . "\n" . $content); + } + my $res = $self->{UA}->request($req); + unless( $res->is_success ) { + # + # The camera timeouts connections at short intervals. When this + # happens the user agent connects again and uses the same auth tokens. + # The camera rejects this and asks for another token but the UserAgent + # just gives up. Because of this I try the request again and it should + # succeed the second time if the credentials are correct. + # + if ( $res->code == 401 ) { + $res = $self->{UA}->request($req); + unless( $res->is_success ) { + # + # It has failed authentication. The odds are + # that the user has set some parameter incorrectly + # so check the realm against the ControlDevice + # entry and send a message if different + # + my $auth = $res->headers->www_authenticate; + foreach (split(/\s*,\s*/,$auth)) { + if ( $_ =~ /^realm\s*=\s*"([^"]+)"/i ) { + if ( $self->{Monitor}{ControlDevice} ne $1 ) { + Warning("Control Device appears to be incorrect. + Control Device should be set to \"$1\". + Control Device currently set to \"$self->{Monitor}{ControlDevice}\"."); + $self->{Monitor}{ControlDevice} = $1; + $self->{UA}->credentials("$host:$port", $self->{Monitor}{ControlDevice}, $user, $pass); + return PutCmd($self,$cmd,$content); } } - # - # Check for username/password - # - if( $self->{Monitor}{ControlAddress} =~ /.+:(.+)@.+/ ) { - Info "Check username/password is correct"; - } elsif ( $self->{Monitor}{ControlAddress} =~ /^[^:]+@.+/ ) { - Info "No password in Control Address. Should there be one?"; - } elsif ( $self->{Monitor}{ControlAddress} =~ /^:.+@.+/ ) { - Info "Password but no username in Control Address."; - } else { - Info "Missing username and password in Control Address."; - } - Fatal $res->status_line; } + # + # Check for username/password + # + if ( $self->{Monitor}{ControlAddress} =~ /.+:(.+)@.+/ ) { + Info("Check username/password is correct"); + } elsif ( $self->{Monitor}{ControlAddress} =~ /^[^:]+@.+/ ) { + Info("No password in Control Address. Should there be one?"); + } elsif ( $self->{Monitor}{ControlAddress} =~ /^:.+@.+/ ) { + Info("Password but no username in Control Address."); + } else { + Info("Missing username and password in Control Address."); + } + Fatal($res->status_line); } - else { - Fatal $res->status_line; - } + } else { + Fatal($res->status_line); } -} + } # end unless res->is_success +} # end sub putCmd # # The move continuous functions all call moveVector # with the direction to move in. This includes zoom # sub moveVector { - my $self = shift; - my $pandirection = shift; - my $tiltdirection = shift; - my $zoomdirection = shift; - my $params = shift; - my $command; # The ISAPI/PTZ command + my $self = shift; + my $pandirection = shift; + my $tiltdirection = shift; + my $zoomdirection = shift; + my $params = shift; + my $command; # The ISAPI/PTZ command - # Calculate autostop time - my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; - # Change from microseconds to milliseconds - $duration = int($duration/1000); - my $momentxml; - if( $duration ) { - $momentxml = "$duration"; - $command = "ISAPI/PTZCtrl/channels/$ChannelID/momentary"; - } - else { - $momentxml = ""; - $command = "ISAPI/PTZCtrl/channels/$ChannelID/continuous"; - } - # Calculate movement speeds - my $x = $pandirection * $self->getParam( $params, 'panspeed', 0 ); - my $y = $tiltdirection * $self->getParam( $params, 'tiltspeed', 0 ); - my $z = $zoomdirection * $self->getParam( $params, 'speed', 0 ); - # Create the XML - my $xml = "$x$y$z$momentxml"; - # Send it to the camera - $self->PutCmd($command,$xml); + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Change from microseconds to milliseconds + $duration = int($duration/1000); + my $momentxml; + if( $duration ) { + $momentxml = "$duration"; + $command = "ISAPI/PTZCtrl/channels/$ChannelID/momentary"; + } + else { + $momentxml = ""; + $command = "ISAPI/PTZCtrl/channels/$ChannelID/continuous"; + } + # Calculate movement speeds + my $x = $pandirection * $self->getParam( $params, 'panspeed', 0 ); + my $y = $tiltdirection * $self->getParam( $params, 'tiltspeed', 0 ); + my $z = $zoomdirection * $self->getParam( $params, 'speed', 0 ); + # Create the XML + my $xml = "$x$y$z$momentxml"; + # Send it to the camera + $self->PutCmd($command,$xml); } sub moveStop { $_[0]->moveVector( 0, 0, 0, splice(@_,1)); } sub moveConUp { $_[0]->moveVector( 0, 1, 0, splice(@_,1)); } @@ -221,191 +199,191 @@ sub zoomConWide { $_[0]->moveVector( 0, 0,-1, splice(@_,1)); } # Presets including Home set and clear # sub presetGoto { - my $self = shift; - my $params = shift; - my $preset = $self->getParam($params,'preset'); - $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/presets/$preset/goto"); + my $self = shift; + my $params = shift; + my $preset = $self->getParam($params,'preset'); + $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/presets/$preset/goto"); } sub presetSet { - my $self = shift; - my $params = shift; - my $preset = $self->getParam($params,'preset'); - my $xml = "$preset"; - $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/presets/$preset",$xml); + my $self = shift; + my $params = shift; + my $preset = $self->getParam($params,'preset'); + my $xml = "$preset"; + $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/presets/$preset",$xml); } sub presetHome { - my $self = shift; - my $params = shift; - $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/homeposition/goto"); + my $self = shift; + my $params = shift; + $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/homeposition/goto"); } # # Focus controls all call Focus with a +/- speed # sub Focus { - my $self = shift; - my $speed = shift; - my $xml = "$speed"; - $self->PutCmd("ISAPI/System/Video/inputs/channels/$ChannelID/focus",$xml); + my $self = shift; + my $speed = shift; + my $xml = "$speed"; + $self->PutCmd("ISAPI/System/Video/inputs/channels/$ChannelID/focus",$xml); } sub focusConNear { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Calculate autostop time - my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; - # Get the focus speed - my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); - $self->Focus(-$speed); - if($duration) { - usleep($duration); - $self->moveStop($params); - } + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus(-$speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } } sub Near { - my $self = shift; - my $params = shift; - $self->Focus(-$DefaultFocusSpeed); + my $self = shift; + my $params = shift; + $self->Focus(-$DefaultFocusSpeed); } sub focusAbsNear { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Get the focus speed - my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); - $self->Focus(-$speed); + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus(-$speed); } sub focusRelNear { - my $self = shift; - my $params = shift; - # Get the focus speed - my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); - $self->Focus(-$speed); + my $self = shift; + my $params = shift; + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus(-$speed); } sub focusConFar { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Calculate autostop time - my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; - # Get the focus speed - my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); - $self->Focus($speed); - if($duration) { - usleep($duration); - $self->moveStop($params); - } + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus($speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } } sub Far { - my $self = shift; - my $params = shift; - $self->Focus($DefaultFocusSpeed); + my $self = shift; + my $params = shift; + $self->Focus($DefaultFocusSpeed); } sub focusAbsFar { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Get the focus speed - my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); - $self->Focus($speed); + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus($speed); } sub focusRelFar { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Get the focus speed - my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); - $self->Focus($speed); + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus($speed); } # # Iris controls all call Iris with a +/- speed # sub Iris { - my $self = shift; - my $speed = shift; + my $self = shift; + my $speed = shift; - my $xml = "$speed"; - $self->PutCmd("ISAPI/System/Video/inputs/channels/$ChannelID/iris",$xml); + my $xml = "$speed"; + $self->PutCmd("ISAPI/System/Video/inputs/channels/$ChannelID/iris",$xml); } sub irisConClose { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Calculate autostop time - my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; - # Get the iris speed - my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); - $self->Iris(-$speed); - if($duration) { - usleep($duration); - $self->moveStop($params); - } + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris(-$speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } } sub Close { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - $self->Iris(-$DefaultIrisSpeed); + $self->Iris(-$DefaultIrisSpeed); } sub irisAbsClose { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Get the iris speed - my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); - $self->Iris(-$speed); + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris(-$speed); } sub irisRelClose { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Get the iris speed - my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); - $self->Iris(-$speed); + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris(-$speed); } sub irisConOpen { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Calculate autostop time - my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; - # Get the iris speed - my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); - $self->Iris($speed); - if($duration) { - usleep($duration); - $self->moveStop($params); - } + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris($speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } } sub Open { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - $self->Iris($DefaultIrisSpeed); + $self->Iris($DefaultIrisSpeed); } sub irisAbsOpen { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Get the iris speed - my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); - $self->Iris($speed); + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris($speed); } sub irisRelOpen { - my $self = shift; - my $params = shift; + my $self = shift; + my $params = shift; - # Get the iris speed - my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); - $self->Iris($speed); + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris($speed); } # # reset (reboot) the device # sub reset { - my $self = shift; + my $self = shift; - $self->PutCmd("ISAPI/System/reboot"); + $self->PutCmd("ISAPI/System/reboot"); } 1; - +__END__ diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/IPCC7210W.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/IPCC7210W.pm index f3ac081a5..c18b37485 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/IPCC7210W.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/IPCC7210W.pm @@ -44,31 +44,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Keekoon.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Keekoon.pm index 0fc14135d..28f95b7d3 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Keekoon.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Keekoon.pm @@ -82,33 +82,6 @@ use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref( ) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -126,12 +99,6 @@ sub open } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/LoftekSentinel.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/LoftekSentinel.pm index a5500e2b0..b0751c9af 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/LoftekSentinel.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/LoftekSentinel.pm @@ -54,33 +54,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref( ) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); - } - sub open { my $self = shift; @@ -94,12 +67,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm index bacfc77aa..dff4cb317 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm @@ -50,29 +50,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); use URI::Encode qw(); -sub new { - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD { - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -85,11 +62,6 @@ sub open { $self->{state} = 'open'; } -sub close { - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; my $msg = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm index 38ae81aa3..409c397c9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm @@ -44,31 +44,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -82,12 +57,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm index 32ac9a50c..1f74c3e26 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Ncs370.pm @@ -44,31 +44,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -82,12 +57,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Netcat.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Netcat.pm index 6aefbb6c3..e345e5eab 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Netcat.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Netcat.pm @@ -74,33 +74,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref( ) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); - } - sub open { my $self = shift; @@ -114,12 +87,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm index 070f5fb18..55292d3e4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PanasonicIP.pm @@ -44,31 +44,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -82,12 +57,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm index 68547da6f..2dc2ac95b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoD.pm @@ -46,31 +46,6 @@ use Time::HiRes qw( usleep ); use constant SYNC => 0xff; use constant COMMAND_GAP => 100000; # In ms -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -91,8 +66,7 @@ sub open $self->{state} = 'open'; } -sub close -{ +sub close { my $self = shift; $self->{state} = 'closed'; $self->{port}->close(); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm index 9c411c0cd..8cbb505ca 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm @@ -47,31 +47,6 @@ use constant STX => 0xa0; use constant ETX => 0xaf; use constant COMMAND_GAP => 100000; # In ms -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Reolink.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Reolink.pm new file mode 100644 index 000000000..370d463c3 --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Reolink.pm @@ -0,0 +1,597 @@ +# ========================================================================== +# +# ZoneMinder Reolink IP Control Protocol Module, Date: 2016-01-19 +# Converted for use with Reolink IP Camera by Chris Swertfeger +# Copyright (C) 2016 Chris Swertfeger +# +# 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 first implementation of the Reolink IP camera control +# protocol +# +package ZoneMinder::Control::Reolink; + +use 5.006; +use strict; +use warnings; + +require ZoneMinder::Base; +require ZoneMinder::Control; + +our @ISA = qw(ZoneMinder::Control); + +our %CamParams = (); + +# ========================================================================== +# +# Reolink IP Control Protocol +# This script sends ONVIF compliant commands and may work with other cameras +# that require authentication +# +# The script was developed against a RLC-423 and RLC-420. +# +# Basic preset functions are supported, but more advanced features, which make +# use of abnormally high preset numbers (ir lamp control, tours, pan speed, etc) +# may or may not work. +# +# +# On ControlAddress use the format : +# USERNAME:PASSWORD@ADDRESS:PORT +# eg : admin:pass@10.1.2.1:8899 +# admin:password@10.0.100.1:8899 +# +# Use port 8000 by default for Reolink cameras +# +# Make sure and place a value in the Auto Stop Timeout field. +# Recommend starting with a value of 1 second, and adjust accordingly. +# +# ========================================================================== + +use ZoneMinder::Logger qw(:all); +use ZoneMinder::Config qw(:all); + +use Time::HiRes qw( usleep ); + +use MIME::Base64; +use Digest::SHA; +use DateTime; + +my ($username,$password,$host,$port); + +sub open +{ + my $self = shift; + + $self->loadMonitor(); + # + # Extract the username/password host/port from ControlAddress + # + if( $self->{Monitor}{ControlAddress} =~ /^([^:]+):([^@]+)@(.+)/ ) + { # user:pass@host... + $username = $1; + $password = $2; + $host = $3; + } + elsif( $self->{Monitor}{ControlAddress} =~ /^([^@]+)@(.+)/ ) + { # user@host... + $username = $1; + $host = $2; + } + else { # Just a host + $host = $self->{Monitor}{ControlAddress}; + } + # Check if it is a host and port or just a host + if( $host =~ /([^:]+):(.+)/ ) + { + $host = $1; + $port = $2; + } + else + { + $port = 80; + } + + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); + + $self->{state} = 'open'; +} + +sub printMsg +{ + my $self = shift; + my $msg = shift; + my $msg_len = length($msg); + + Debug( $msg."[".$msg_len."]" ); +} + +sub sendCmd +{ + my $self = shift; + my $cmd = shift; + my $msg = shift; + my $content_type = shift; + my $result = undef; + + printMsg( $cmd, "Tx" ); + + my $server_endpoint = "http://".$host.":".$port."/$cmd"; + my $req = HTTP::Request->new( POST => $server_endpoint ); + $req->header('content-type' => $content_type); + $req->header('Host' => $host.":".$port); + $req->header('content-length' => length($msg)); + $req->header('accept-encoding' => 'gzip, deflate'); + $req->header('connection' => 'close'); + $req->content($msg); + + my $res = $self->{ua}->request($req); + + if ( $res->is_success ) { + $result = !undef; + } else { + Error( "After sending PTZ command, camera returned the following error:'".$res->status_line()."'" ); + } + return( $result ); +} + +sub getCamParams +{ + my $self = shift; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg = ''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $server_endpoint = "http://".$self->{Monitor}->{ControlAddress}."/onvif/imaging"; + my $req = HTTP::Request->new( POST => $server_endpoint ); + $req->header('content-type' => 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/GetImagingSettings"'); + $req->header('Host' => $host.":".$port); + $req->header('content-length' => length($msg)); + $req->header('accept-encoding' => 'gzip, deflate'); + $req->header('connection' => 'Close'); + $req->content($msg); + + my $res = $self->{ua}->request($req); + + if ( $res->is_success ) { + # We should really use an xml or soap library to parse the xml tags + my $content = $res->decoded_content; + + if ($content =~ /.*(.+)<\/tt:Brightness>.*/) { + $CamParams{$1} = $2; + } + if ($content =~ /.*(.+)<\/tt:Contrast>.*/) { + $CamParams{$1} = $2; + } + } + else + { + Error( "Unable to retrieve camera image settings:'".$res->status_line()."'" ); + } +} + +#autoStop +#This makes use of the ZoneMinder Auto Stop Timeout on the Control Tab +sub autoStop +{ + my $self = shift; + my $autostop = shift; + + if( $autostop ) { + Debug( "Auto Stop" ); + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg = ''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000truefalse'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + usleep( $autostop ); + $self->sendCmd( $cmd, $msg, $content_type ); + } +} + +# Reset the Camera +sub reset +{ + Debug( "Camera Reset" ); + my $self = shift; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $cmd = ""; + my $msg = ''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.''; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/device/wsdl/SystemReboot"'; + $self->sendCmd( $cmd, $msg, $content_type ); +} + +#Up Arrow +sub moveConUp +{ + Debug( "Move Up" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Down Arrow +sub moveConDown +{ + Debug( "Move Down" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Left Arrow +sub moveConLeft +{ + Debug( "Move Left" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Right Arrow +sub moveConRight +{ + Debug( "Move Right" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Zoom In +sub zoomConTele +{ + Debug( "Zoom Tele" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Zoom Out +sub zoomConWide +{ + Debug( "Zoom Wide" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Diagonally Up Right Arrow +#This camera does not have builtin diagonal commands so we emulate them +sub moveConUpRight +{ + Debug( "Move Diagonally Up Right" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Diagonally Down Right Arrow +#This camera does not have builtin diagonal commands so we emulate them +sub moveConDownRight +{ + Debug( "Move Diagonally Down Right" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Diagonally Up Left Arrow +#This camera does not have builtin diagonal commands so we emulate them +sub moveConUpLeft +{ + Debug( "Move Diagonally Up Left" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Diagonally Down Left Arrow +#This camera does not have builtin diagonal commands so we emulate them +sub moveConDownLeft +{ + Debug( "Move Diagonally Down Left" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); + $self->autoStop( $self->{Monitor}->{AutoStopTimeout} ); +} + +#Stop +sub moveStop +{ + Debug( "Move Stop" ); + my $self = shift; + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000truefalse'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; + $self->sendCmd( $cmd, $msg, $content_type ); +} + +#Set Camera Preset +sub presetSet +{ + my $self = shift; + my $params = shift; + my $preset = $self->getParam( $params, 'preset' ); + Debug( "Set Preset $preset" ); + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'.$preset.''; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/SetPreset"'; + $self->sendCmd( $cmd, $msg, $content_type ); +} + +#Recall Camera Preset +sub presetGoto +{ + my $self = shift; + my $params = shift; + my $preset = $self->getParam( $params, 'preset' ); + my $num = sprintf("%03d", $preset); + $num=~ tr/ /0/; + Debug( "Goto Preset $preset" ); + my $cmd = 'onvif/PTZ'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'.$num.''; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/GotoPreset"'; + $self->sendCmd( $cmd, $msg, $content_type ); +} + +#Horizontal Patrol +#To be determined if this camera supports this feature +sub horizontalPatrol +{ + Debug( "Horizontal Patrol" ); + my $self = shift; + my $cmd = ''; + my $msg =''; + my $content_type = ''; +# $self->sendCmd( $cmd, $msg, $content_type ); + Error( "PTZ Command not implemented in control script." ); +} + +#Horizontal Patrol Stop +#To be determined if this camera supports this feature +sub horizontalPatrolStop +{ + Debug( "Horizontal Patrol Stop" ); + my $self = shift; + my $cmd = ''; + my $msg =''; + my $content_type = ''; +# $self->sendCmd( $cmd, $msg, $content_type ); + Error( "PTZ Command not implemented in control script." ); +} + +# Increase Brightness +sub irisAbsOpen +{ + Debug( "Iris $CamParams{'Brightness'}" ); + my $self = shift; + my $params = shift; + $self->getCamParams() unless($CamParams{'Brightness'}); + my $step = $self->getParam( $params, 'step' ); + my $max = 100; + + $CamParams{'Brightness'} += $step; + $CamParams{'Brightness'} = $max if ($CamParams{'Brightness'} > $max); + + my $cmd = 'onvif/imaging'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'.$CamParams{'Brightness'}.'true'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"'; + $self->sendCmd( $cmd, $msg, $content_type ); +} + +# Decrease Brightness +sub irisAbsClose +{ + Debug( "Iris $CamParams{'Brightness'}" ); + my $self = shift; + my $params = shift; + $self->getCamParams() unless($CamParams{'brightness'}); + my $step = $self->getParam( $params, 'step' ); + my $min = 0; + + $CamParams{'Brightness'} -= $step; + $CamParams{'Brightness'} = $min if ($CamParams{'Brightness'} < $min); + + my $cmd = 'onvif/imaging'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'.$CamParams{'Brightness'}.'true'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"'; + $self->sendCmd( $cmd, $msg, $content_type ); +} + +# Increase Contrast +sub whiteAbsIn +{ + Debug( "Iris $CamParams{'Contrast'}" ); + my $self = shift; + my $params = shift; + $self->getCamParams() unless($CamParams{'Contrast'}); + my $step = $self->getParam( $params, 'step' ); + my $max = 100; + + $CamParams{'Contrast'} += $step; + $CamParams{'Contrast'} = $max if ($CamParams{'Contrast'} > $max); + + my $cmd = 'onvif/imaging'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'.$CamParams{'Contrast'}.'true'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"'; +} + +# Decrease Contrast +sub whiteAbsOut +{ + Debug( "Iris $CamParams{'Contrast'}" ); + my $self = shift; + my $params = shift; + $self->getCamParams() unless($CamParams{'Contrast'}); + my $step = $self->getParam( $params, 'step' ); + my $min = 0; + + $CamParams{'Contrast'} -= $step; + $CamParams{'Contrast'} = $min if ($CamParams{'Contrast'} < $min); + + my $cmd = 'onvif/imaging'; + my $nonce; + for (0..20){$nonce .= chr(int(rand(254)));} + my $mydate = DateTime->now()->iso8601().'Z'; + my $sha = Digest::SHA->new(1); + $sha->add($nonce.$mydate.$password); + my $digest = encode_base64($sha->digest,""); + my $msg =''.$username.''.$digest.''.encode_base64($nonce,"").''.$mydate.'000'.$CamParams{'Contrast'}.'true'; + my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"'; +} + +1; + diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/SPP1802SWPTZ.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/SPP1802SWPTZ.pm index 38838237b..fe89bf51e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/SPP1802SWPTZ.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/SPP1802SWPTZ.pm @@ -60,33 +60,8 @@ our $VERSION = $ZoneMinder::Base::VERSION; use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); - use Time::HiRes qw( usleep ); +use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} our $stop_command; sub open @@ -101,12 +76,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm index b3f9418ce..7175d1e84 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/SkyIPCam7xx.pm @@ -45,28 +45,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new { - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD { - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -79,11 +57,6 @@ sub open { $self->{state} = 'open'; } -sub close { - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; my $msg = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm index eb083eb60..827540dce 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm @@ -81,31 +81,6 @@ our $ADDRESS = ''; use ZoneMinder::Logger qw(:all); use ZoneMinder::Config qw(:all); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -164,12 +139,6 @@ sub open } # end if ! $res->is_success } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Toshiba_IK_WB11A.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Toshiba_IK_WB11A.pm index 562365e95..410a6c79b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Toshiba_IK_WB11A.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Toshiba_IK_WB11A.pm @@ -45,31 +45,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -83,12 +58,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm index e356c77f0..a7c406ec2 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Visca.pm @@ -46,31 +46,6 @@ use Time::HiRes qw( usleep ); use constant SYNC => 0xff; use constant COMMAND_GAP => 100000; # In ms -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm index 7ddf2dc6d..58ebe4c63 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm @@ -44,33 +44,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - Debug( "Camera New" ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - Debug( "Camera AUTOLOAD" ); - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm index 894fe970d..1e6e70410 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm @@ -70,32 +70,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -109,12 +83,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/WanscamHW0025.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/WanscamHW0025.pm index 3459c097f..036b051ed 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/WanscamHW0025.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/WanscamHW0025.pm @@ -52,31 +52,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -90,12 +65,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm index 7ac00c995..59b6cc1a6 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm @@ -44,33 +44,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - Debug( "Camera New" ); - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - Debug( "Camera AUTOLOAD" ); - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm index 8214b9f5d..ea287a42f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm @@ -49,33 +49,6 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - my $logindetails = ""; - bless( $self, $class ); - srand( time() ); - return $self; -} - -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref( ) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); -} - sub open { my $self = shift; @@ -89,12 +62,6 @@ sub open $self->{state} = 'open'; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; -} - sub printMsg { my $self = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index 19a5f8662..c39a6a73f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -77,39 +77,51 @@ sub zmDbConnect { } my $options = shift; - if ( ( ! defined( $dbh ) ) or ! $dbh->ping() ) { + if ( ( !defined($dbh) ) or ! $dbh->ping() ) { my ( $host, $portOrSocket ) = ( $ZoneMinder::Config::Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my $socket; if ( defined($portOrSocket) ) { if ( $portOrSocket =~ /^\// ) { - $socket = ";mysql_socket=".$portOrSocket; + $socket = ';mysql_socket='.$portOrSocket; } else { - $socket = ";host=".$host.";port=".$portOrSocket; + $socket = ';host='.$host.';port='.$portOrSocket; } } else { - $socket = ";host=".$Config{ZM_DB_HOST}; + $socket = ';host='.$Config{ZM_DB_HOST}; } - my $sslOptions = ""; + my $sslOptions = ''; if ( $Config{ZM_DB_SSL_CA_CERT} ) { $sslOptions = ';'.join(';', - "mysql_ssl=1", - "mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT}, - "mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY}, - "mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT} + 'mysql_ssl=1', + 'mysql_ssl_ca_file='.$Config{ZM_DB_SSL_CA_CERT}, + 'mysql_ssl_client_key='.$Config{ZM_DB_SSL_CLIENT_KEY}, + 'mysql_ssl_client_cert='.$Config{ZM_DB_SSL_CLIENT_CERT} ); } - $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} - .$socket . $sslOptions . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' ) + eval { + $dbh = DBI->connect( 'DBI:mysql:database='.$Config{ZM_DB_NAME} + .$socket . $sslOptions . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '') , $Config{ZM_DB_USER} , $Config{ZM_DB_PASS} ); - $dbh->trace( 0 ); - } - return( $dbh ); -} + }; + if ( !$dbh or $@ ) { + Error("Error reconnecting to db: errstr:$DBI::errstr error val:$@"); + } else { + $dbh->{AutoCommit} = 1; + Fatal('Can\'t set AutoCommit on in database connection') + unless $dbh->{AutoCommit}; + $dbh->{mysql_auto_reconnect} = 1; + Fatal('Can\'t set mysql_auto_reconnect on in database connection') + unless $dbh->{mysql_auto_reconnect}; + $dbh->trace( 0 ); + } # end if success connecting + } # end if ! connected + return $dbh; +} # end sub zmDbConnect sub zmDbDisconnect { if ( defined( $dbh ) ) { diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 6e882b1e5..8a9c78ada 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -35,6 +35,9 @@ require Date::Manip; require File::Find; require File::Path; require File::Copy; +require File::Slurp; +require File::Basename; +require Number::Bytes::Human; #our @ISA = qw(ZoneMinder::Object); use parent qw(ZoneMinder::Object); @@ -300,8 +303,8 @@ sub GenerateVideo { $frame_rate = $fps; } - my $width = $self->{MonitorWidth}; - my $height = $self->{MonitorHeight}; + my $width = $self->{Width}; + my $height = $self->{Height}; my $video_size = " ${width}x${height}"; if ( $scale ) { @@ -347,13 +350,17 @@ sub delete { Warning( "Can't Delete event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime} from $caller:$line\n" ); return; } + if ( ! -e $event->Storage()->Path() ) { + Warning("Not deleting event because storage path doesn't exist"); + return; + } Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime}\n" ); $ZoneMinder::Database::dbh->ping(); $ZoneMinder::Database::dbh->begin_work(); - $event->lock_and_load(); + #$event->lock_and_load(); - if ( ! $Config{ZM_OPT_FAST_DELETE} ) { + { my $sql = 'DELETE FROM Frames WHERE EventId=?'; my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql ) or Error( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() ); @@ -375,19 +382,23 @@ sub delete { $ZoneMinder::Database::dbh->commit(); return; } + } +# Do it individually to avoid locking up the table for new events + { + my $sql = 'DELETE FROM Events WHERE Id=?'; + my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql ) + or Error( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Error( "Can't execute '$sql': ".$sth->errstr() ); + $sth->finish(); + } + $ZoneMinder::Database::dbh->commit(); + if ( (! $Config{ZM_OPT_FAST_DELETE}) and $event->Storage()->DoDelete() ) { $event->delete_files( ); } else { - Debug('Not deleting frames, stats and files for speed.'); + Debug('Not deleting event files from '.$event->Path().' for speed.'); } -# Do it individually to avoid locking up the table for new events - my $sql = 'DELETE FROM Events WHERE Id=?'; - my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql ) - or Error( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) - or Error( "Can't execute '$sql': ".$sth->errstr() ); - $sth->finish(); - $ZoneMinder::Database::dbh->commit(); } # end sub delete sub delete_files { @@ -410,8 +421,34 @@ sub delete_files { if ( $event_path ) { ( $storage_path ) = ( $storage_path =~ /^(.*)$/ ); # De-taint ( $event_path ) = ( $event_path =~ /^(.*)$/ ); # De-taint + + my $deleted = 0; + if ( $$Storage{Type} eq 's3fs' ) { + my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$Storage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ ); + eval { + require Net::Amazon::S3; + my $s3 = Net::Amazon::S3->new( { + aws_access_key_id => $aws_id, + aws_secret_access_key => $aws_secret, + ( $aws_host ? ( host => $aws_host ) : () ), + }); + my $bucket = $s3->bucket($aws_bucket); + if ( ! $bucket ) { + Error("S3 bucket $bucket not found."); + die; + } + if ( $bucket->delete_key($event_path) ) { + $deleted = 1; + } else { + Error("Failed to delete from S3:".$s3->err . ": " . $s3->errstr); + } + }; + Error($@) if $@; + } + if ( ! $deleted ) { my $command = "/bin/rm -rf $storage_path/$event_path"; - ZoneMinder::General::executeShellCommand( $command ); + ZoneMinder::General::executeShellCommand( $command ); + } } if ( $event->Scheme() eq 'Deep' ) { @@ -419,7 +456,7 @@ sub delete_files { Debug("Deleting files for Event $$event{Id} from $storage_path/$link_path."); if ( $link_path ) { ( $link_path ) = ( $link_path =~ /^(.*)$/ ); # De-taint - unlink( $storage_path.'/'.$link_path ) or Error( "Unable to unlink '$storage_path/$link_path': $!" ); + unlink($storage_path.'/'.$link_path) or Error( "Unable to unlink '$storage_path/$link_path': $!" ); } } } # end sub delete_files @@ -429,7 +466,7 @@ sub Storage { $_[0]{Storage} = $_[1]; } if ( ! $_[0]{Storage} ) { - $_[0]{Storage} = new ZoneMinder::Storage( $_[0]{StorageId} ); + $_[0]{Storage} = new ZoneMinder::Storage($_[0]{StorageId}); } return $_[0]{Storage}; } @@ -482,6 +519,24 @@ sub DiskSpace { sub MoveTo { my ( $self, $NewStorage ) = @_; + my $OldStorage = $self->Storage(undef); + my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint + if ( ! -e $OldPath ) { + return "Old path $OldPath does not exist."; + } + # First determine if we can move it to the dest. + # We do this before bothering to lock the event + my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint + if ( ! $$NewStorage{Id} ) { + return "New storage does not have an id. Moving will not happen."; + } elsif ( $$NewStorage{Id} == $$self{StorageId} ) { + return "Event is already located at " . $NewPath; + } elsif ( !$NewPath ) { + return "New path ($NewPath) is empty."; + } elsif ( ! -e $NewPath ) { + return "New path $NewPath does not exist."; + } + $ZoneMinder::Database::dbh->begin_work(); $self->lock_and_load(); # data is reloaded, so need to check that the move hasn't already happened. @@ -490,25 +545,12 @@ sub MoveTo { return "Event has already been moved by someone else."; } - my $OldStorage = $self->Storage(undef); - my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint + if ( $$OldStorage{Id} != $$self{StorageId} ) { + $ZoneMinder::Database::dbh->commit(); + return "Old Storage path changed, Event has moved somewhere else."; + } $$self{Storage} = $NewStorage; - - my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint - if ( ! $$NewStorage{Id} ) { - $ZoneMinder::Database::dbh->commit(); - return "New storage does not have an id. Moving will not happen."; - } elsif ( !$NewPath ) { - $ZoneMinder::Database::dbh->commit(); - return "New path ($NewPath) is empty."; - } elsif ( ! -e $NewPath ) { - $ZoneMinder::Database::dbh->commit(); - return "New path $NewPath does not exist."; - } elsif ( ! -e $OldPath ) { - $ZoneMinder::Database::dbh->commit(); - return "Old path $OldPath does not exist."; - } ( $NewPath ) = ( $self->Path(undef) =~ /^(.*)$/ ); # De-taint if ( $NewPath eq $OldPath ) { $ZoneMinder::Database::dbh->commit(); @@ -516,34 +558,97 @@ sub MoveTo { } Debug("Moving event $$self{Id} from $OldPath to $NewPath"); + my $moved = 0; + + if ( $$NewStorage{Type} eq 's3fs' ) { + my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$NewStorage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ ); + eval { + require Net::Amazon::S3; + my $s3 = Net::Amazon::S3->new( { + aws_access_key_id => $aws_id, + aws_secret_access_key => $aws_secret, + ( $aws_host ? ( host => $aws_host ) : () ), + }); + my $bucket = $s3->bucket($aws_bucket); + if ( ! $bucket ) { + Error("S3 bucket $bucket not found."); + die; + } + + my $event_path = 'events/'.$self->RelativePath(); +Info("Making dir ectory $event_path/"); + if ( ! $bucket->add_key( $event_path.'/','' ) ) { + die "Unable to add key for $event_path/"; + } + + my @files = glob("$OldPath/*"); +Debug("Files to move @files"); + for my $file (@files) { + next if $file =~ /^\./; + ( $file ) = ( $file =~ /^(.*)$/ ); # De-taint + my $starttime = time; + Debug("Moving file $file to $NewPath"); + my $size = -s $file; + if ( ! $size ) { + Info("Not moving file with 0 size"); + } + my $file_contents = File::Slurp::read_file($file); + if ( ! $file_contents ) { + die "Loaded empty file, but it had a size. Giving up"; + } + + my $filename = $event_path.'/'.File::Basename::basename($file); + if ( ! $bucket->add_key( $filename, $file_contents ) ) { + die "Unable to add key for $filename"; + } + my $duration = time - $starttime; + Debug("PUT to S3 " . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($size/$duration) . "/sec"); + } # end foreach file. + + $moved = 1; + }; + Error($@) if $@; + die $@ if $@; + } # end if s3 + my $error = ''; - File::Path::make_path( $NewPath, {error => \my $err} ); - if ( @$err ) { - for my $diag (@$err) { - my ($file, $message) = %$diag; - next if $message eq 'File exists'; - if ($file eq '') { - $error .= "general error: $message\n"; - } else { - $error .= "problem making $file: $message\n"; + if ( ! $moved ) { + File::Path::make_path( $NewPath, {error => \my $err} ); + if ( @$err ) { + for my $diag (@$err) { + my ($file, $message) = %$diag; + next if $message eq 'File exists'; + if ($file eq '') { + $error .= "general error: $message\n"; + } else { + $error .= "problem making $file: $message\n"; + } } } - } - if ( $error ) { - $ZoneMinder::Database::dbh->commit(); - return $error; - } - my @files = glob("$OldPath/*"); - - for my $file (@files) { - next if $file =~ /^\./; - ( $file ) = ( $file =~ /^(.*)$/ ); # De-taint - Debug("Moving file $file to $NewPath"); - if ( ! File::Copy::copy( $file, $NewPath ) ) { - $error .= "Copy failed: for $file to $NewPath: $!"; - last; + if ( $error ) { + $ZoneMinder::Database::dbh->commit(); + return $error; } - } # end foreach file. + my @files = glob("$OldPath/*"); + if ( ! @files ) { + $ZoneMinder::Database::dbh->commit(); + return "No files to move."; + } + + for my $file (@files) { + next if $file =~ /^\./; + ( $file ) = ( $file =~ /^(.*)$/ ); # De-taint + my $starttime = time; + Debug("Moving file $file to $NewPath"); + my $size = -s $file; + if ( ! File::Copy::copy( $file, $NewPath ) ) { + $error .= "Copy failed: for $file to $NewPath: $!"; + last; + } + my $duration = time - $starttime; + Debug("Copied " . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . ($duration?Number::Bytes::Human::format_bytes($size/$duration):'inf') . "/sec"); + } # end foreach file. + } # end if ! moved if ( $error ) { $ZoneMinder::Database::dbh->commit(); @@ -558,8 +663,10 @@ sub MoveTo { $ZoneMinder::Database::dbh->commit(); return $error; } - $self->delete_files( $OldStorage ); +Debug("Committing"); $ZoneMinder::Database::dbh->commit(); + $self->delete_files( $OldStorage ); +Debug("Done deleting files, returning"); return $error; } # end sub MoveTo diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index cd8b76a62..1b158b2ac 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -96,7 +96,7 @@ sub find_one { sub Execute { my $self = $_[0]; - my $sql = $self->Sql(); + my $sql = $self->Sql(undef); if ( $self->{HasDiskPercent} ) { my $disk_percent = getDiskPercent( $$self{Storage} ? $$self{Storage}->Path() : () ); @@ -130,9 +130,10 @@ sub Execute { } sub Sql { - my $self = $_[0]; + my $self = shift; + $$self{Sql} = shift if @_; if ( ! $$self{Sql} ) { - my $filter_expr = ZoneMinder::General::jsonDecode( $self->{Query} ); + my $filter_expr = ZoneMinder::General::jsonDecode($self->{Query}); my $sql = 'SELECT E.*, unix_timestamp(E.StartTime) as Time, M.Name as MonitorName, @@ -159,9 +160,12 @@ sub Sql { if ( $term->{attr} =~ /^Monitor/ ) { my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/; $self->{Sql} .= 'M.'.$temp_attr_name; - } elsif ( $term->{attr} =~ /^Server/ ) { - $self->{Sql} .= 'S.'.$term->{attr}; - + } elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) { + $self->{Sql} .= 'M.ServerId'; + } elsif ( $term->{attr} eq 'StorageServerId' ) { + $self->{Sql} .= 'S.ServerId'; + } elsif ( $term->{attr} eq 'FilterServerId' ) { + $self->{Sql} .= $Config{ZM_SERVER_ID}; # StartTime options } elsif ( $term->{attr} eq 'DateTime' ) { $self->{Sql} .= 'E.StartTime'; @@ -171,7 +175,7 @@ sub Sql { $self->{Sql} .= 'to_days( E.StartTime )'; } elsif ( $term->{attr} eq 'StartDate' ) { $self->{Sql} .= 'to_days( E.StartTime )'; - } elsif ( $term->{attr} eq 'Time' ) { + } elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' ) { $self->{Sql} .= 'extract( hour_second from E.StartTime )'; } elsif ( $term->{attr} eq 'Weekday' ) { $self->{Sql} .= 'weekday( E.StartTime )'; @@ -205,9 +209,9 @@ sub Sql { ( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/; foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) { - if ( $term->{attr} =~ /^Monitor/ ) { + if ( $term->{attr} =~ /^MonitorName/ ) { $value = "'$temp_value'"; - } elsif ( $term->{attr} eq 'ServerId' ) { + } elsif ( $term->{attr} =~ /ServerId/) { Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})"); if ( $temp_value eq 'ZM_SERVER_ID' ) { $value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'"; @@ -240,7 +244,7 @@ sub Sql { } $value = "'$value'"; } - } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) { + } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) { if ( $temp_value eq 'NULL' ) { $value = $temp_value; } else { @@ -276,7 +280,13 @@ sub Sql { } elsif ( $term->{op} eq '!~' ) { $self->{Sql} .= " not regexp $value"; } elsif ( $term->{op} eq 'IS' ) { - $self->{Sql} .= " IS $value"; + if ( $value eq 'Odd' ) { + $self->{Sql} .= ' % 2 = 1'; + } elsif ( $value eq 'Even' ) { + $self->{Sql} .= ' % 2 = 0'; + } else { + $self->{Sql} .= " IS $value"; + } } elsif ( $term->{op} eq 'IS NOT' ) { $self->{Sql} .= " IS NOT $value"; } elsif ( $term->{op} eq '=[]' ) { diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 921c063cc..8dbcf8efa 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -1,4 +1,4 @@ -# ========================================================================== +############################################################################ # # ZoneMinder Logger Module, $Date$, $Revision$ # Copyright (C) 2001-2008 Philip Coombes @@ -17,7 +17,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -# ========================================================================== +############################################################################ # # This module contains the debug definitions and functions used by the rest # of the ZoneMinder scripts @@ -81,11 +81,11 @@ our @EXPORT = qw(); our $VERSION = $ZoneMinder::Base::VERSION; -# ========================================================================== +############################################################################ # # Logger Facilities # -# ========================================================================== +############################################################################ use ZoneMinder::Config qw(:all); @@ -158,6 +158,7 @@ sub new { ( $this->{fileName} = $0 ) =~ s|^.*/||; $this->{logPath} = $Config{ZM_PATH_LOGS}; $this->{logFile} = $this->{logPath}.'/'.$this->{id}.'.log'; + ($this->{logFile}) = $this->{logFile} =~ /^([\w\.\/]+)$/; $this->{trace} = 0; @@ -207,6 +208,7 @@ sub initialise( @ ) { if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) { $tempLogFile = $logFile; } + ($tempLogFile) = $tempLogFile =~ /^([\w\.\/]+)$/; my $tempLevel = INFO; my $tempTermLevel = $this->{termLevel}; @@ -427,54 +429,10 @@ sub databaseLevel { if ( $this->{databaseLevel} != $databaseLevel ) { if ( $databaseLevel > NOLOG and $this->{databaseLevel} <= NOLOG ) { if ( !$this->{dbh} ) { - my $socket; - my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); - - if ( defined($portOrSocket) ) { - if ( $portOrSocket =~ /^\// ) { - $socket = ';mysql_socket='.$portOrSocket; - } else { - $socket = ';host='.$host.';port='.$portOrSocket; - } - } else { - $socket = ';host='.$Config{ZM_DB_HOST}; - } - my $sslOptions = ''; - if ( $Config{ZM_DB_SSL_CA_CERT} ) { - $sslOptions = join(';','', - 'mysql_ssl=1', - 'mysql_ssl_ca_file='.$Config{ZM_DB_SSL_CA_CERT}, - 'mysql_ssl_client_key='.$Config{ZM_DB_SSL_CLIENT_KEY}, - 'mysql_ssl_client_cert='.$Config{ZM_DB_SSL_CLIENT_CERT} - ); - } - $this->{dbh} = DBI->connect( 'DBI:mysql:database='.$Config{ZM_DB_NAME} - .$socket.$sslOptions - , $Config{ZM_DB_USER} - , $Config{ZM_DB_PASS} - ); - if ( !$this->{dbh} ) { - $databaseLevel = NOLOG; - Error( 'Unable to write log entries to DB, can\'t connect to database ' - .$Config{ZM_DB_NAME} - .' on host ' - .$Config{ZM_DB_HOST} - ); - } else { - $this->{dbh}->{AutoCommit} = 1; - Fatal('Can\'t set AutoCommit on in database connection' ) - unless( $this->{dbh}->{AutoCommit} ); - $this->{dbh}->{mysql_auto_reconnect} = 1; - Fatal('Can\'t set mysql_auto_reconnect on in database connection' ) - unless( $this->{dbh}->{mysql_auto_reconnect} ); - $this->{dbh}->trace( 0 ); - } + $this->{dbh} = ZoneMinder::Database::zmDbConnect(); } } elsif ( $databaseLevel <= NOLOG && $this->{databaseLevel} > NOLOG ) { - if ( $this->{dbh} ) { - $this->{dbh}->disconnect(); - undef($this->{dbh}); - } + undef($this->{dbh}); } $this->{databaseLevel} = $databaseLevel; } @@ -581,28 +539,34 @@ sub logPrint { syslog($priorities{$level}, $code.' [%s]', $string); } print($LOGFILE $message) if $level <= $this->{fileLevel}; + print(STDERR $message) if $level <= $this->{termLevel}; + if ( $level <= $this->{databaseLevel} ) { - my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )'; - $this->{sth} = $this->{dbh}->prepare_cached($sql); - if ( !$this->{sth} ) { - $this->{databaseLevel} = NOLOG; - Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr()); - } else { - my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0) - , $this->{id} - , $$ - , $level - , $code - , $string - , $this->{fileName} - ); - if ( !$res ) { + if ( ( $this->{dbh} and $this->{dbh}->ping() ) or ( $this->{dbh} = ZoneMinder::Database::zmDbConnect() ) ) { + + my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )'; + $this->{sth} = $this->{dbh}->prepare_cached($sql); + if ( !$this->{sth} ) { $this->{databaseLevel} = NOLOG; - Error("Can't execute log entry '$sql': ".$this->{sth}->errstr()); + Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr()); + } else { + my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0) + , $this->{id} + , $$ + , $level + , $code + , $string + , $this->{fileName} + ); + if ( !$res ) { + $this->{databaseLevel} = NOLOG; + Error("Can't execute log entry '$sql': ".$this->{dbh}->errstr()); + } } + } else { + print(STDERR "Can't log to database: "); } } # end if doing db logging - print(STDERR $message) if $level <= $this->{termLevel}; } # end if level < effectivelevel } diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in index 2386c5d6f..2529c8786 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in @@ -147,7 +147,7 @@ our $mem_data = { last_write_index => { type=>'uint32', seq=>$mem_seq++ }, last_read_index => { type=>'uint32', seq=>$mem_seq++ }, state => { type=>'uint32', seq=>$mem_seq++ }, - last_event => { type=>'uint32', seq=>$mem_seq++ }, + last_event => { type=>'uint64', seq=>$mem_seq++ }, action => { type=>'uint32', seq=>$mem_seq++ }, brightness => { type=>'int32', seq=>$mem_seq++ }, hue => { type=>'int32', seq=>$mem_seq++ }, @@ -166,6 +166,7 @@ our $mem_data = { last_write_time => { type=>'time_t64', seq=>$mem_seq++ }, last_read_time => { type=>'time_t64', seq=>$mem_seq++ }, control_state => { type=>'uint8[256]', seq=>$mem_seq++ }, + alarm_cause => { type=>'int8[256]', seq=>$mem_seq++ }, } }, trigger_data => { type=>'TriggerData', seq=>$mem_seq++, 'contents'=> { @@ -315,6 +316,12 @@ sub zmMemRead { my $type = $mem_data->{$section}->{contents}->{$element}->{type}; my $size = $mem_data->{$section}->{contents}->{$element}->{size}; + if (!defined $offset || !defined $type || !defined $size) { + Error ("Invalid field:".$field." setting to undef and exiting zmMemRead"); + zmMemInvalidate( $monitor ); + return( undef ); + } + my $data = zmMemGet( $monitor, $offset, $size ); if ( !defined($data) ) { Error( "Unable to read '$field' from memory for monitor ".$monitor->{Id} ); @@ -820,6 +827,7 @@ colour Read/write location for the current monitor colour contrast Read/write location for the current monitor contrast alarm_x Image x co-ordinate (from left) of the centre of the last motion event, -1 if none alarm_y Image y co-ordinate (from top) of the centre of the last motion event, -1 if none +alarm_cause The current alarm event cause string along with zone names(s) alarmed trigger_data The triggered event mapped memory section size The size, in bytes of this section diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index baa77059a..8c28028a0 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -125,6 +125,7 @@ sub load { if ( $data and %$data ) { @$self{keys %$data} = values %$data; } # end if + return $data; } # end sub load sub lock_and_load { @@ -134,33 +135,34 @@ sub lock_and_load { no strict 'refs'; my $table = ${$type.'::table'}; if ( ! $table ) { - Error( 'NO table for type ' . $type ); + Error('NO table for type ' . $type); return; } # end if my $primary_key = ${$type.'::primary_key'}; if ( ! $primary_key ) { - Error( 'NO primary_key for type ' . $type ); + Error('NO primary_key for type ' . $type); return; } # end if if ( ! $$self{$primary_key} ) { my ( $caller, undef, $line ) = caller; - Error( (ref $self) . "::lock_and_load called without $primary_key from $caller:$line"); + Error("$type ::lock_and_load called without $primary_key from $caller:$line"); return; - } - #$log->debug("Object::load Loading from db $type"); - Debug("Loading $type from $table WHERE $primary_key = $$self{$primary_key}"); - my $data = $ZoneMinder::Database::dbh->selectrow_hashref( "SELECT * FROM $table WHERE $primary_key=? FOR UPDATE", {}, $$self{$primary_key} ); + + Debug("Lock and Load $type from $table WHERE $primary_key = $$self{$primary_key}"); + my $data = $ZoneMinder::Database::dbh->selectrow_hashref("SELECT * FROM $table WHERE $primary_key=? FOR UPDATE", {}, $$self{$primary_key}); if ( ! $data ) { if ( $ZoneMinder::Database::dbh->errstr ) { - Error( "Failure to load Object record for $$self{$primary_key}: Reason: " . $ZoneMinder::Database::dbh->errstr ); + Error("Failure to load Object record for $$self{$primary_key}: Reason: " . $ZoneMinder::Database::dbh->errstr); } else { - Debug("No Results Loading $type from $table WHERE $primary_key = $$self{$primary_key}"); + Debug("No Results Lock and Loading $type from $table WHERE $primary_key = $$self{$primary_key}"); } # end if } # end if if ( $data and %$data ) { @$self{keys %$data} = values %$data; + } else { + Debug("No values Lock and Loading $type from $table WHERE $primary_key = $$self{$primary_key}"); } # end if } # end sub lock_and_load diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Server.pm b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm index 9c68f5a51..1d822f9af 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Server.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Server.pm @@ -42,6 +42,7 @@ our @ISA = qw(Exporter ZoneMinder::Base); # will save memory. our %EXPORT_TAGS = ( 'functions' => [ qw( + CpuLoad ) ] ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -107,6 +108,17 @@ sub Hostname { return $_[0]{Hostname}; } # end sub Hostname +sub CpuLoad { + my $output = qx(uptime); + my @sysloads = split ', ', (split ': ', $output)[-1]; + + if (join(', ',@sysloads) =~ /(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*$/) { + return @sysloads; + } + + return (undef, undef, undef); +} # end sub CpuLoad + 1; __END__ # Below is stub documentation for your module. You'd better edit it! diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm b/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm index 8fbe5ed80..b6924c4e9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Storage.pm @@ -113,6 +113,15 @@ sub Name { return $_[0]{Name}; } # end sub Path +sub DoDelete { + my $self = shift; + $$self{DoDelete} = shift if @_; + if ( ! defined $$self{DoDelete} ) { + $$self{DoDelete} = 1; + } + return $$self{DoDelete}; +} + sub Server { my $self = shift; if ( ! $$self{Server} ) { diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 0e1faf640..80d675f05 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -63,6 +63,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my $report = 0; my $interactive = 0; my $continuous = 0; +my $level = 1; my $monitor_id = 0; my $version; my $force = 0; @@ -74,6 +75,7 @@ GetOptions( continuous =>\$continuous, force =>\$force, interactive =>\$interactive, + level =>\$level, 'monitor_id=i' =>\$monitor_id, report =>\$report, 'storage_id=i' =>\$storage_id, @@ -246,7 +248,7 @@ MAIN: while( $loop ) { { my @day_dirs = glob("$monitor_dir/[0-9][0-9]/[0-9][0-9]/[0-9][0-9]"); - Debug(qq`Checking for Deep Events under using glob("$monitor_dir/[0-9][0-9]/[0-9][0-9]/[0-9][0-9]") returned `. scalar @day_dirs . " events"); + Debug(qq`Checking for Deep Events under $$Storage{Path} using glob("$monitor_dir/[0-9][0-9]/[0-9][0-9]/[0-9][0-9]") returned `. scalar @day_dirs . ' events'); foreach my $day_dir ( @day_dirs ) { Debug( "Checking day dir $day_dir" ); ( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint @@ -294,7 +296,7 @@ MAIN: while( $loop ) { } # end foreach day dir } - Debug("Checking for Medium Scheme Events under $monitor_dir"); + Debug("Checking for Medium Scheme Events under $$Storage{Path}/$monitor_dir"); { my @event_dirs = glob("$monitor_dir/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/*"); Debug(qq`glob("$monitor_dir/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/*") returned ` . scalar @event_dirs . " entries." ); @@ -485,7 +487,9 @@ MAIN: while( $loop ) { redo MAIN; } +if ( $level > 1 ) { # Remove orphaned events (with no monitor) +# Shouldn't be possible anymore with FOREIGN KEYS in place $cleaned = 0; Debug("Checking for Orphaned Events"); my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name @@ -507,6 +511,7 @@ MAIN: while( $loop ) { } } redo MAIN if $cleaned; +} # end if level > 1 # Remove empty events (with no frames) $cleaned = 0; @@ -537,7 +542,7 @@ MAIN: while( $loop ) { $cleaned = 0; Debug("Checking for Orphaned Frames"); my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames - WHERE EventId NOT IN (SELECT Id FROM Events)'; + WHERE (SELECT COUNT(*) FROM Events WHERE Events.Id=EventId)=0'; my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() ); $res = $selectOrphanedFramesSth->execute() @@ -552,6 +557,7 @@ MAIN: while( $loop ) { } redo MAIN if $cleaned; +if ( $level > 1 ) { # Remove orphaned stats records $cleaned = 0; Debug("Checking for Orphaned Stats"); @@ -570,6 +576,7 @@ MAIN: while( $loop ) { } } redo MAIN if ( $cleaned ); +} # New audit to close any events that were left open for longer than MIN_AGE seconds my $selectUnclosedEventsSql = diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 90b0abd27..7f179db71 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -104,19 +104,23 @@ my @daemons = ( 'zmtelemetry.pl' ); +if ( $Config{ZM_OPT_USE_EVENTNOTIFICATION} ) { + push @daemons,'zmeventnotification.pl'; +} + my $command = shift @ARGV; -if( ! $command ) { - print( STDERR "No command given\n" ); +if ( !$command ) { + print(STDERR "No command given\n"); pod2usage(-exitstatus => -1); } if ( $command eq 'version' ) { print ZoneMinder::Base::ZM_VERSION."\n"; - exit( 0 ); + exit(0); } my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/; -my $daemon = shift( @ARGV ); +my $daemon = shift @ARGV; if ( $needs_daemon && ! $daemon ) { - print( STDERR "No daemon given\n" ); + print(STDERR "No daemon given\n"); pod2usage(-exitstatus => -1); } my @args; @@ -126,7 +130,7 @@ if ( $needs_daemon ) { if ( $daemon =~ /^${daemon_patt}$/ ) { $daemon = $1; } else { - print( STDERR "Invalid daemon '$daemon' specified" ); + print(STDERR "Invalid daemon '$daemon' specified"); pod2usage(-exitstatus => -1); } } @@ -137,22 +141,22 @@ foreach my $arg ( @ARGV ) { if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) { push( @args, $1 ); } else { - print( STDERR "Bogus argument '$arg' found" ); - exit( -1 ); + print(STDERR "Bogus argument '$arg' found"); + exit(-1); } } my $dbh = zmDbConnect(); -socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); +socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); -my $saddr = sockaddr_un( SOCK_FILE ); -my $server_up = connect( CLIENT, $saddr ); +my $saddr = sockaddr_un(SOCK_FILE); +my $server_up = connect(CLIENT, $saddr); -if ( ! $server_up ) { +if ( !$server_up ) { if ( $Config{ZM_SERVER_ID} ) { -use Sys::MemInfo qw(totalmem freemem totalswap freeswap); -use Sys::CpuLoad; + use Sys::MemInfo qw(totalmem freemem totalswap freeswap); + use ZoneMinder::Server qw(CpuLoad); if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, 'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr()); @@ -164,16 +168,16 @@ use Sys::CpuLoad; exit(); } if ( $command eq 'check' ) { - print( "stopped\n" ); + print("stopped\n"); exit(); } elsif ( $command ne 'startup' ) { - print( "Unable to connect to server using socket at " . SOCK_FILE . "\n" ); + print("Unable to connect to server using socket at " . SOCK_FILE . "\n"); exit( -1 ); } # The server isn't there - print( "Starting server\n" ); - close( CLIENT ); + print("Starting server\n"); + close(CLIENT); if ( my $cpid = fork() ) { # Parent process just sleep and fall through @@ -181,7 +185,7 @@ use Sys::CpuLoad; # I'm still not sure why we need to re-init the logs logInit(); - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); + socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); my $attempts = 0; while( !connect(CLIENT, $saddr) ) { $attempts++; @@ -205,7 +209,6 @@ if ( ($command eq 'check') && !$daemon ) { } # The server is there, connect to it -#print( "Writing commands\n" ); CLIENT->autoflush(); my $message = join(';', $command, ( $daemon ? $daemon : () ), @args ); print(CLIENT $message); @@ -214,9 +217,7 @@ while( my $line = ) { chomp($line); print("$line\n"); } -# And we're done! close(CLIENT); -#print( "Finished writing, bye\n" ); exit; @@ -233,54 +234,56 @@ use Socket; use IO::Handle; use Time::HiRes qw(usleep); use Sys::MemInfo qw(totalmem freemem totalswap freeswap); -use Sys::CpuLoad; +use ZoneMinder::Server qw(CpuLoad); #use Data::Dumper; -# We count 10 of these, so total timeout is this value *10. -use constant KILL_DELAY => 1; # seconds +use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sending KILL our %cmd_hash; our %pid_hash; +our %terminating_processes; +our $zm_terminate = 0; sub run { my $fd = 0; - while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) { - POSIX::close( $fd++ ); + while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) { + POSIX::close($fd++); } setpgrp(); logInit(); - dPrint( ZoneMinder::Logger::INFO, 'Server starting at ' - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + dPrint(ZoneMinder::Logger::INFO, 'Server starting at ' + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); - if ( open( my $PID, '>', ZM_PID ) ) { - print( $PID $$ ); - close( $PID ); + if ( open(my $PID, '>', ZM_PID) ) { + print($PID $$); + close($PID); } else { - Error( "Can't open pid file at " . ZM_PID ); + Error("Can't open pid file at " . ZM_PID); } - killAll( 1 ); + # Tell any existing processes to die, wait 1 second between TERM and KILL + killAll(1); - dPrint( ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE ); + dPrint(ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE); my $dbh = zmDbConnect(1); - socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); - unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if -e main::SOCK_FILE; - bind( SERVER, $saddr ) or Fatal( "Can't bind to " . main::SOCK_FILE . ": $!" ); - listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); + socket(SERVER, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); + unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if -e main::SOCK_FILE; + bind(SERVER, $saddr) or Fatal("Can't bind to " . main::SOCK_FILE . ": $!"); + listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); $SIG{CHLD} = \&reaper; - $SIG{INT} = \&shutdownAll; - $SIG{TERM} = \&shutdownAll; - $SIG{ABRT} = \&shutdownAll; + $SIG{INT} = \&shutdown_sig_handler; + $SIG{TERM} = \&shutdown_sig_handler; + $SIG{ABRT} = \&shutdown_sig_handler; $SIG{HUP} = \&logrot; my $rin = ''; - vec( $rin, fileno(SERVER), 1 ) = 1; + vec($rin, fileno(SERVER), 1) = 1; my $win = $rin; my $ein = $win; my $timeout = 1; @@ -289,17 +292,21 @@ sub run { if ( $Config{ZM_SERVER_ID} ) { require ZoneMinder::Server; - $Server = new ZoneMinder::Server( $Config{ZM_SERVER_ID} ); - dPrint( ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name} ); + $Server = new ZoneMinder::Server($Config{ZM_SERVER_ID}); + dPrint(ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name}); } - while( 1 ) { + while( !$zm_terminate ) { if ( $Config{ZM_SERVER_ID} ) { if ( ! ( $secs_count % 60 ) ) { - $dbh = zmDbConnect() if ! $dbh->ping(); - my @cpuload = Sys::CpuLoad::load(); - dPrint( ZoneMinder::Logger::DEBUG, 'Updating Server record' ); + Debug("Connecting"); + while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) { + Warning("Not connected to db ($dbh)".($dbh?" ping(".$dbh->ping().")":''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting'); + $dbh = zmDbConnect(); + } + my @cpuload = CpuLoad(); + Debug("UPdating Server record @cpuload"); if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, 'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); @@ -307,52 +314,53 @@ sub run { } $secs_count += 1; } - my $nfound = select( my $rout = $rin, undef, undef, $timeout ); + my $nfound = select(my $rout = $rin, undef, undef, $timeout); +Debug("Aftere select $nfound"); if ( $nfound > 0 ) { - if ( vec( $rout, fileno(SERVER), 1 ) ) { - my $paddr = accept( CLIENT, SERVER ); + if ( vec($rout, fileno(SERVER), 1) ) { + my $paddr = accept(CLIENT, SERVER); my $message = ; next if !$message; - my ( $command, $daemon, @args ) = split( /;/, $message ); + my ( $command, $daemon, @args ) = split(';', $message); if ( $command eq 'start' ) { - start( $daemon, @args ); + start($daemon, @args); } elsif ( $command eq 'stop' ) { - stop( $daemon, @args ); + stop($daemon, @args); } elsif ( $command eq 'restart' ) { - restart( $daemon, @args ); + restart($daemon, @args); } elsif ( $command eq 'reload' ) { - reload( $daemon, @args ); + reload($daemon, @args); } elsif ( $command eq 'startup' ) { # Do nothing, this is all we're here for - dPrint( ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n" ); + dPrint(ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n"); } elsif ( $command eq 'shutdown' ) { - shutdownAll(); + # Breka out of while loop + last; } elsif ( $command eq 'check' ) { - check( $daemon, @args ); + check($daemon, @args); } elsif ( $command eq 'status' ) { if ( $daemon ) { - status( $daemon, @args ); + status($daemon, @args); } else { status(); } } elsif ( $command eq 'logrot' ) { logrot(); } else { - dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); + dPrint(ZoneMinder::Logger::ERROR, "Invalid command '$command'\n"); } close(CLIENT); } else { - Fatal('Bogus descriptor'); + Error('Bogus descriptor'); } } elsif ( $nfound < 0 ) { if ( $! == EINTR ) { # Dead child, will be reaped #print( "Probable dead child\n" ); # See if it needs to start up again - restartPending(); } elsif ( $! == EPIPE ) { Error("Can't select: $!"); } else { @@ -360,22 +368,26 @@ sub run { } } else { #print( "Select timed out\n" ); - restartPending(); } - } - dPrint( ZoneMinder::Logger::INFO, 'Server exiting at ' + +Debug("restartPending"); + restartPending(); +Debug("check_for_processes_to_kill"); + check_for_processes_to_kill(); + + } # end while + + dPrint(ZoneMinder::Logger::INFO, 'Server exiting at ' .strftime( '%y/%m/%d %H:%M:%S', localtime() ) ."\n" ); if ( $Config{ZM_SERVER_ID} ) { $dbh = zmDbConnect() if ! $dbh->ping(); - if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID} ) ) { + if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID}) ) { Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); } } - unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE ); - unlink( ZM_PID ) or Error( 'Unable to unlink ' . ZM_PID .". Error message was: $!" ) if ( -e ZM_PID ); - exit(); + shutdownAll(); } sub cPrint { @@ -391,15 +403,15 @@ sub dPrint { print CLIENT @_ } if ( $logLevel == ZoneMinder::Logger::DEBUG ) { - Debug( @_ ); + Debug(@_); } elsif ( $logLevel == ZoneMinder::Logger::INFO ) { - Info( @_ ); + Info(@_); } elsif ( $logLevel == ZoneMinder::Logger::WARNING ) { - Warning( @_ ); + Warning(@_); } elsif ( $logLevel == ZoneMinder::Logger::ERROR ) { - Error( @_ ); + Error(@_); } elsif ( $logLevel == ZoneMinder::Logger::FATAL ) { - Fatal( @_ ); + Fatal(@_); } } @@ -407,61 +419,64 @@ sub start { my $daemon = shift; my @args = @_; - my $command = join(' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( !$process ) { # It's not running, or at least it's not been started by us $process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef }; } elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) { - dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}\n" ); - return(); + return; } my $sigset = POSIX::SigSet->new; - my $blockset = POSIX::SigSet->new( SIGCHLD ); - sigprocmask( SIG_BLOCK, $blockset, $sigset ) or Fatal( "Can't block SIGCHLD: $!" ); + my $blockset = POSIX::SigSet->new(SIGCHLD); + Debug("Blocking SIGCHLD"); + sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!"); + Debug("forking"); if ( my $cpid = fork() ) { + # This logReinit is required. Not sure why. logReinit(); $process->{pid} = $cpid; $process->{started} = time(); - delete( $process->{pending} ); + delete $process->{pending}; - dPrint( ZoneMinder::Logger::INFO, "'$command' starting at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + dPrint(ZoneMinder::Logger::INFO, "'$command' starting at " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}\n" ); $cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process; - sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" ); - } elsif ( defined($cpid ) ) { + sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!"); + Debug("unblocking child"); + } elsif ( defined($cpid) ) { # Force reconnection to the db. $dbh = zmDbConnect(1); logReinit(); - dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) ) - ."' started at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + dPrint(ZoneMinder::Logger::INFO, "'$command' started at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); if ( $daemon =~ /^${daemon_patt}$/ ) { $daemon = $Config{ZM_PATH_BIN}.'/'.$1; } else { - Fatal( "Invalid daemon '$daemon' specified" ); + Fatal("Invalid daemon '$daemon' specified"); } my @good_args; foreach my $arg ( @args ) { # Detaint arguments, if they look ok if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) { - push( @good_args, $1 ); + push @good_args, $1; } else { - Fatal( "Bogus argument '$arg' found" ); + Fatal("Bogus argument '$arg' found"); } } @@ -469,8 +484,8 @@ sub start { zmDbDisconnect(); my $fd = 0; - while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) { - POSIX::close( $fd++ ); + while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) { + POSIX::close($fd++); } # Child process @@ -479,153 +494,167 @@ sub start { $SIG{TERM} = 'DEFAULT'; $SIG{ABRT} = 'DEFAULT'; - exec( $daemon, @good_args ) or Fatal( "Can't exec: $!" ); + exec($daemon, @good_args) or Fatal("Can't exec: $!"); } else { - Fatal( "Can't fork: $!" ); + Fatal("Can't fork: $!"); } -} +} # end sub start # Sends the stop signal, without waiting around to see if the process died. sub send_stop { my ( $final, $process ) = @_; + my $sigset = POSIX::SigSet->new; + my $blockset = POSIX::SigSet->new(SIGCHLD); + sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n"; + my $command = $process->{command}; if ( $process->{pending} ) { - delete( $cmd_hash{$command} ); - dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + delete $cmd_hash{$command}; + dPrint(ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); + sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; return(); } my $pid = $process->{pid}; + if ( !$pid ) { + dPrint(ZoneMinder::Logger::ERROR, "No process with command of '$command' is running\n"); + sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; + return(); + } if ( !$pid_hash{$pid} ) { - dPrint( ZoneMinder::Logger::ERROR, "No process with command of '$command' pid $pid is running\n" ); + dPrint(ZoneMinder::Logger::ERROR, "No process with command of '$command' pid $pid is running\n"); + sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; return(); } - dPrint( ZoneMinder::Logger::INFO, "'$command' sending stop to pid $pid at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + dPrint(ZoneMinder::Logger::INFO, "'$command' sending stop to pid $pid at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); $process->{keepalive} = !$final; - kill( 'TERM', $pid ); + $process->{term_sent_at} = time if ! $process->{term_sent_at}; + $process->{pending} = 0; + $terminating_processes{$command} = $process; + + kill('TERM', $pid); + sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; return $pid; } # end sub send_stop -sub kill_until_dead { - my ( $process ) = @_; -# Now check it has actually gone away, if not kill -9 it - my $count = 0; +sub check_for_processes_to_kill { + # Turn off SIGCHLD my $sigset = POSIX::SigSet->new; my $blockset = POSIX::SigSet->new(SIGCHLD); - sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n"; - while( $process and $$process{pid} and kill( 0, $$process{pid} ) ) { - if ( $count++ > 10 ) { - dPrint( ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) - .". Sending KILL to pid $$process{pid}\n" - ); - kill( 'KILL', $$process{pid} ); - last; + sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n"; + foreach my $command ( keys %terminating_processes ) { + my $process = $cmd_hash{$command}; + if ( ! $process ) { + Debug("No process found for $command"); + delete $terminating_processes{$command}; + next; + } + if ( ! $$process{pid} ) { + Warning("Have no pid for $command."); + delete $terminating_processes{$command}; + next; + } + my $now = time; + Debug("Have process $command at pid $$process{pid} $now - $$process{term_sent_at} = " . ( $now - $$process{term_sent_at} )); + if ( $$process{term_sent_at} and ( $now - $$process{term_sent_at} > KILL_DELAY ) ) { + dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) + .' after ' . KILL_DELAY . ' seconds.' + ." Sending KILL to pid $$process{pid}\n" + ); + kill('KILL', $$process{pid}); + delete $terminating_processes{$command}; } - - # THe purpose of the signal blocking is to simplify the concurrency - sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; - sleep( KILL_DELAY ); - sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n"; } sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; -} - -sub _stop { - my ($final, $process ) = @_; - - my $pid = send_stop( $final, $process ); - return if ! $pid; - delete( $cmd_hash{$$process{command}} ); - kill_until_dead( $process ); -} +} # end sub check_for_processess_to_kill sub stop { my ( $daemon, @args ) = @_; my $command = join(' ', $daemon, @args ); my $process = $cmd_hash{$command}; if ( !$process ) { - dPrint( ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n" ); - return(); + dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'"); + return; } - _stop( 1, $process ); + send_stop(1, $process); } +# restart is the same as stop, except that we flag the processes for restarting once it dies +# One difference is that if we don't know about the process, then we start it. sub restart { - my $daemon = shift; - my @args = @_; + my ( $daemon, @args ) = @_; - my $command = $daemon; - $command .= ' '.join( ' ', ( @args ) ) if @args; - dPrint ( ZoneMinder::Logger::DEBUG, "Restarting $command\n"); + my $command = join(' ', $daemon, @args); + dPrint(ZoneMinder::Logger::DEBUG, "Restarting $command\n"); my $process = $cmd_hash{$command}; - if ( $process ) { - dPrint( ZoneMinder::Logger::DEBUG, "Have process" ); - if ( $process->{pid} ) { - dPrint( ZoneMinder::Logger::DEBUG, "Have process pid " .$process->{pid} ); - my $cpid = $process->{pid}; - if ( defined($pid_hash{$cpid}) ) { - dPrint( ZoneMinder::Logger::DEBUG, "Have process pid hash " .$process->{pid} ); - _stop( 0, $process ); - return; - } else { - dPrint( ZoneMinder::Logger::DEBUG, "Not sending stop" ); - } - } + if ( !$process ) { + dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n"); + start($daemon, @args); + return; } - start( $daemon, @args ); + # Start will be handled by the reaper + send_stop(0, $process); + return; } sub reload { my $daemon = shift; my @args = @_; - my $command = $daemon; - $command .= ' '.join( ' ', ( @args ) ) if ( @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( $process ) { if ( $process->{pid} ) { - kill( 'HUP', $process->{pid} ); + kill('HUP', $process->{pid}); } } } sub logrot { logReinit(); - foreach my $process ( values( %pid_hash ) ) { + foreach my $process ( values %pid_hash ) { if ( $process->{pid} ) { # && $process->{command} =~ /^zm.*\.pl/ ) { - kill( 'HUP', $process->{pid} ); + kill('HUP', $process->{pid}); } } } +sub shutdown_sig_handler { + $zm_terminate = 1; +} + sub reaper { my $saved_status = $!; - while ( (my $cpid = waitpid( -1, WNOHANG )) > 0 ) { + + # Wait for a child to terminate + while ( (my $cpid = waitpid(-1, WNOHANG)) > 0 ) { my $status = $?; my $process = $pid_hash{$cpid}; - delete( $pid_hash{$cpid} ); + delete $pid_hash{$cpid}; if ( !$process ) { - dPrint( ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n" ); + dPrint(ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n"); next; } + delete $terminating_processes{$$process{command}}; + delete $$process{term_sent_at}; $process->{stopped} = time(); $process->{runtime} = ($process->{stopped}-$process->{started}); - delete( $process->{pid} ); + delete $process->{pid}; my $exit_status = $status>>8; my $exit_signal = $status&0xfe; @@ -633,8 +662,8 @@ sub reaper { my $out_str = "'$process->{command}' "; if ( $exit_signal ) { + # 15 == TERM, 14 == ALARM if ( $exit_signal == 15 || $exit_signal == 14 ) { -# TERM or ALRM $out_str .= 'exited'; } else { $out_str .= 'crashed'; @@ -652,9 +681,9 @@ sub reaper { $out_str .= "\n"; if ( $exit_status == 0 ) { - Info( $out_str ); + Info($out_str); } else { - Error( $out_str ); + Error($out_str); } if ( $process->{keepalive} ) { @@ -672,49 +701,49 @@ sub reaper { $process->{delay} = $Config{ZM_MAX_RESTART_DELAY}; } } + Debug("Delay for $$process{command} is now $$process{delay}"); + } else { + delete $cmd_hash{$$process{command}}; } - } + } # end while waitpid $SIG{CHLD} = \&reaper; $! = $saved_status; + Debug("Leaving reaper"); } sub restartPending { -# Restart any pending processes - foreach my $process ( values( %cmd_hash ) ) { +# Restart any pending processes, we list them first because cmd_hash may change in foreach + my @processes = values %cmd_hash; + foreach my $process ( @processes ) { if ( $process->{pending} && $process->{pending} <= time() ) { - dPrint( ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n" ); - start( $process->{daemon}, @{$process->{args}} ); + dPrint(ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n"); + start($process->{daemon}, @{$process->{args}}); } } + Debug("done restartPending"); } sub shutdownAll { foreach my $pid ( keys %pid_hash ) { # This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here. next if ! $pid_hash{$pid}; - send_stop( 1, $pid_hash{$pid} ); + send_stop(1, $pid_hash{$pid}); } - foreach my $pid ( keys %pid_hash ) { -# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here. - next if ! $pid_hash{$pid}; - - my $process = $pid_hash{$pid}; - - kill_until_dead( $process ); - delete( $cmd_hash{$$process{command}} ); - delete( $pid_hash{$pid} ); + while ( keys %terminating_processes ) { + check_for_processes_to_kill(); + if ( %terminating_processes ) { + Debug("Still " . %terminating_processes . ' to die. sleeping'); + sleep(1); + } } -if ( 0 ) { - killAll( 5 ); -} - dPrint( ZoneMinder::Logger::INFO, "Server shutdown at " - .strftime( '%y/%m/%d %H:%M:%S', localtime() ) - ."\n" - ); - unlink( main::SOCK_FILE ) or Error( "Unable to unlink " . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE ); - unlink( ZM_PID ) or Error( "Unable to unlink " . ZM_PID .". Error message was: $!" ) if ( -e ZM_PID ); - close( CLIENT ); - close( SERVER ); + dPrint(ZoneMinder::Logger::INFO, 'Server shutdown at ' + .strftime('%y/%m/%d %H:%M:%S', localtime()) + ."\n" + ); + unlink(main::SOCK_FILE) or Error("Unable to unlink " . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE ); + unlink(ZM_PID) or Error("Unable to unlink " . ZM_PID .". Error message was: $!") if ( -e ZM_PID ); + close(CLIENT); + close(SERVER); exit(); } @@ -722,18 +751,18 @@ sub check { my $daemon = shift; my @args = @_; - my $command = join( ' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( !$process ) { - cPrint( "unknown\n" ); + cPrint("unknown\n"); } elsif ( $process->{pending} ) { - cPrint( "pending\n" ); + cPrint("pending\n"); } else { my $cpid = $process->{pid}; if ( ! $pid_hash{$cpid} ) { - cPrint( "stopped\n" ); + cPrint("stopped\n"); } else { - cPrint( "running\n" ); + cPrint("running\n"); } } } @@ -743,53 +772,54 @@ sub status { my @args = @_; if ( defined($daemon) ) { - my $command = join( ' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( ! $process ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); - return(); + dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n"); + return; } if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) ) + dPrint(ZoneMinder::Logger::DEBUG, "'$command' pending at " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{pending})) ."\n" ); } else { - my $cpid = $process->{pid}; - if ( ! $pid_hash{$cpid} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); - return(); + my $pid = $process->{pid}; + if ( ! $pid_hash{$pid} ) { + dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n"); + return; } } - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started} ) ) + dPrint(ZoneMinder::Logger::DEBUG, "'$command' running since " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}" ); } else { - foreach my $process ( values(%pid_hash) ) { + foreach my $process ( values %pid_hash ) { my $out_str = "'$process->{command}' running since " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}" ; - $out_str .= ", valid" if ( kill( 0, $process->{pid} ) ); + $out_str .= ", valid" if ( kill(0, $process->{pid}) ); $out_str .= "\n"; - dPrint( ZoneMinder::Logger::DEBUG, $out_str ); + dPrint(ZoneMinder::Logger::DEBUG, $out_str); } - foreach my $process ( values( %cmd_hash ) ) { + foreach my $process ( values %cmd_hash ) { if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " - .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) ) + dPrint(ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " + .strftime( '%y/%m/%d %H:%M:%S', localtime($process->{pending})) ."\n" ); } } # end foreach process } -} +} # end sub status sub killAll { my $delay = shift; - sleep( $delay ); + # Why sleep before sending term? + #sleep( $delay ); my $killall; if ( '@HOST_OS@' eq 'BSD' ) { $killall = 'killall -q -'; @@ -800,16 +830,15 @@ sub killAll { } foreach my $daemon ( @daemons ) { my $cmd = $killall ."TERM $daemon"; - Debug( $cmd ); - qx( $cmd ); + Debug($cmd); + qx($cmd); } - sleep( $delay ); + sleep($delay); foreach my $daemon ( @daemons ) { my $cmd = $killall."KILL $daemon"; - Debug( $cmd ); - qx( $cmd ); + Debug($cmd); + qx($cmd); } } - 1; __END__ diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 12dae98cf..fa59d91e0 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -94,7 +94,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|) : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) ; -logInit(); +logInit($filter_id?(id=>'zmfilter_'.$filter_id):()); sub HupHandler { Info("Received HUP, reloading"); &ZoneMinder::Logger::logHupHandler(); @@ -154,38 +154,38 @@ my $delay = $Config{ZM_FILTER_EXECUTE_INTERVAL}; my $event_id = 0; if ( ! EVENT_PATH ) { - Error( "No event path defined. Config was $Config{ZM_DIR_EVENTS}\n" ); + Error("No event path defined. Config was $Config{ZM_DIR_EVENTS}\n"); die; } # In future, should not be neccessary wrt StorageAreas chdir( EVENT_PATH ); -# SHould not be neccessary... but nice to get a local var. What if it fails? +# Should not be neccessary... but nice to get a local var. What if it fails? my $dbh = zmDbConnect(); if ( $filter_name ) { - Info( "Scanning for events using filter '$filter_name'\n" ); + Info("Scanning for events using filter '$filter_name'\n"); } elsif ( $filter_id ) { - Info( "Scanning for events using filter id '$filter_id'\n" ); + Info("Scanning for events using filter id '$filter_id'\n"); } else { - Info( "Scanning for events using all filters\n" ); + Info("Scanning for events using all filters\n"); } if ( ! ( $filter_name or $filter_id ) ) { - Debug("Sleeping due to start delay: " . START_DELAY . ' seconds...' ); - sleep( START_DELAY ); + Debug("Sleeping due to start delay: " . START_DELAY . ' seconds...'); + sleep(START_DELAY); } my @filters; my $last_action = 0; -while( ! $zm_terminate ) { +while( !$zm_terminate ) { my $now = time; if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} ) { - Debug( "Reloading filters\n" ); + Debug("Reloading filters\n"); $last_action = $now; - @filters = getFilters( { Name=>$filter_name, Id=>$filter_id } ); + @filters = getFilters({ Name=>$filter_name, Id=>$filter_id }); } foreach my $filter ( @filters ) { @@ -195,16 +195,16 @@ while( ! $zm_terminate ) { my ( $id ) = $$filter{Id} =~ /(\d+)/; Debug("Running concurrent filter process $proc --filter_id $$filter{Id} => $id for $$filter{Name}"); - system( qq`$proc --filter "$$filter{Name}" &` ); + system(qq`$proc --filter "$$filter{Name}" &`); } else { - checkFilter( $filter ); + checkFilter($filter); } } last if $filter_name or $filter_id or $zm_terminate; - Debug( "Sleeping for $delay seconds\n" ); - sleep( $delay ); + Debug("Sleeping for $delay seconds\n"); + sleep($delay); } sub getFilters { @@ -232,17 +232,18 @@ sub getFilters { or UpdateDiskSpace = 1 or AutoMove = 1 ) ORDER BY Name'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable to prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( @sql_values ) - or Fatal( "Unable to execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached($sql) + or Fatal("Unable to prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute(@sql_values) + or Fatal("Unable to execute '$sql': ".$dbh->errstr()); FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) { - my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter ); - Debug( "Found filter '$db_filter->{Name}'\n" ); - my $filter_sql = $filter->Sql(); + my $filter = new ZoneMinder::Filter($$db_filter{Id}, $db_filter); + Debug("Found filter '$db_filter->{Name}'"); + # The undef here is to make sure the Sql gets regenerated because the Filter object may be cached + my $filter_sql = $filter->Sql(undef); if ( ! $filter_sql ) { - Error( "Error parsing Sql. skipping filter '$db_filter->{Name}'\n" ); + Error("Error parsing Sql. skipping filter '$db_filter->{Name}'"); next FILTER; } push @filters, $filter; @@ -251,7 +252,7 @@ FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) { if ( ! @filters ) { Warning("No filter found for $sql with values(@sql_values)"); } else { - Debug( "Got " . @filters . " filters" ); + Debug("Got " . @filters . " filters"); } return @filters; @@ -282,65 +283,71 @@ sub checkFilter { foreach my $event ( @Events ) { last if $zm_terminate; - Debug( "Checking event $event->{Id}" ); + my $Event = new ZoneMinder::Event($$event{Id}, $event); + + Debug("Checking event $event->{Id}"); my $delete_ok = !undef; $dbh->ping(); if ( $filter->{AutoArchive} ) { - Info( "Archiving event $event->{Id}" ); + Info("Archiving event $event->{Id}"); # Do it individually to avoid locking up the table for new events my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?'; my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); + or Fatal("Unable to prepare '$sql': ".$dbh->errstr()); my $res = $sth->execute( $event->{Id} ) - or Error( "Unable toexecute '$sql': ".$sth->errstr() ); + or Error("Unable to execute '$sql': ".$dbh->errstr()); } if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) { if ( !$event->{Videoed} ) { - $delete_ok = undef if ( !generateVideo( $filter, $event ) ); + $delete_ok = undef if !generateVideo($filter, $event); } } if ( $Config{ZM_OPT_EMAIL} && $filter->{AutoEmail} ) { if ( !$event->{Emailed} ) { - $delete_ok = undef if ( !sendEmail( $filter, $event ) ); + $delete_ok = undef if !sendEmail($filter, $Event); } } if ( $Config{ZM_OPT_MESSAGE} && $filter->{AutoMessage} ) { if ( !$event->{Messaged} ) { - $delete_ok = undef if ( !sendMessage( $filter, $event ) ); + $delete_ok = undef if !sendMessage($filter, $event); } } if ( $Config{ZM_OPT_UPLOAD} && $filter->{AutoUpload} ) { if ( !$event->{Uploaded} ) { - $delete_ok = undef if ( !uploadArchFile( $filter, $event ) ); + $delete_ok = undef if !uploadArchFile($filter, $event); } } if ( $filter->{AutoExecute} ) { if ( !$event->{Executed} ) { - $delete_ok = undef if ( !executeCommand( $filter, $event ) ); + $delete_ok = undef if !executeCommand($filter, $event); } } if ( $filter->{AutoDelete} ) { if ( $delete_ok ) { - my $Event = new ZoneMinder::Event( $$event{Id}, $event ); $Event->delete(); } else { - Error( "Unable toto delete event $event->{Id} as previous operations failed\n" ); + Error("Unable toto delete event $event->{Id} as previous operations failed"); } } # end if AutoDelete + if ( $filter->{AutoMove} ) { - my $Event = new ZoneMinder::Event( $$event{Id}, $event ); - my $NewStorage = new ZoneMinder::Storage( $filter->{AutoMoveTo} ); - $_ = $Event->MoveTo( $NewStorage ); + my $NewStorage = new ZoneMinder::Storage($filter->{AutoMoveTo}); + $_ = $Event->MoveTo($NewStorage); Error($_) if $_; } if ( $filter->{UpdateDiskSpace} ) { - my $Event = new ZoneMinder::Event( $$event{Id}, $event ); $ZoneMinder::Database::dbh->begin_work(); $Event->lock_and_load(); my $old_diskspace = $$Event{DiskSpace}; - if ( $old_diskspace != $Event->DiskSpace(undef) ) { + my $new_diskspace = $Event->DiskSpace(undef); + + if ( + ( (!defined $old_diskspace) and defined $new_diskspace) + or + ( (defined $old_diskspace) and (defined $new_diskspace) and ( $old_diskspace != $Event->DiskSpace(undef) ) ) + ) { $Event->save(); } $ZoneMinder::Database::dbh->commit(); @@ -357,7 +364,7 @@ sub generateVideo { my $scale = $event->{DefaultScale}/100; my $format; - my @ffmpeg_formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} ); + my @ffmpeg_formats = split(/\s+/, $Config{ZM_FFMPEG_FORMATS}); my $default_video_format; my $default_phone_format; foreach my $ffmpeg_format( @ffmpeg_formats ) { @@ -391,25 +398,25 @@ sub generateVideo { chomp( $output ); my $status = $? >> 8; if ( $status || logDebugging() ) { - Debug( "Output: $output\n" ); + Debug("Output: $output\n"); } if ( $status ) { - Error( "Video generation '$command' failed with status: $status\n" ); + Error("Video generation '$command' failed with status: $status\n"); if ( wantarray() ) { return( undef, undef ); } - return( 0 ); + return 0; } else { my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) - or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached($sql) + or Fatal("Unable to prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($event->{Id}) + or Fatal("Unable toexecute '$sql': ".$dbh->errstr()); if ( wantarray() ) { return( $format, $output ); } } - return( 1 ); + return 1; } # Returns an image absolute path for given event and frame @@ -417,13 +424,14 @@ sub generateVideo { # If neither capture nor analyse image exists it will try to extract a frame from .mp4 file if exists # An empty string is returned if no one from methods above works sub generateImage { - my $event = shift; + my $Event = shift; my $frame = shift; - my $analyse = do { @_ ? shift : 0 }; # don't return analyse image by default + my $analyse = @_ ? shift : 0; # don't return analyse image by default - my $capture_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-capture.jpg', getEventPath($event), $frame->{FrameId}); - my $analyse_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-analyse.jpg', getEventPath($event), $frame->{FrameId}) if $analyse; - my $video_path = sprintf('%s/%d-video.mp4', getEventPath($event), $event->{Id}); + my $event_path = $Event->Path(); + my $capture_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-capture.jpg', $event_path, $frame->{FrameId}); + my $analyse_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-analyse.jpg', $event_path, $frame->{FrameId}) if $analyse; + my $video_path = sprintf('%s/%d-video.mp4', $event_path, $Event->{Id}); my $image_path = ''; # check if the image file exists. If the file doesn't exist and we use H264 try to extract it from .mp4 video @@ -431,8 +439,18 @@ sub generateImage { $image_path = $analyse_image_path; } elsif ( -r $capture_image_path ) { $image_path = $capture_image_path; - } elsif ( -e $video_path ) { - if ( !system('ffmpeg -y -v 0 -i '.$video_path." -vf 'select=gte(n\\,".$frame->{FrameId}."),setpts=PTS-STARTPTS' -vframes 1 -f image2 ".$capture_image_path) ) { + } elsif ( -r $video_path ) { + my $command ="ffmpeg -ss $$frame{Delta} -i '$video_path' -frames:v 1 '$capture_image_path'"; + #$command = "ffmpeg -y -v 0 -i $video_path -vf 'select=gte(n\\,$$frame{FrameId}),setpts=PTS-STARTPTS' -vframes 1 -f image2 $capture_image_path"; + my $output = qx($command); + chomp( $output ); + my $status = $? >> 8; + if ( $status || logDebugging() ) { + Debug("Output: $output\n"); + } + if ( $status ) { + Error("Failed $command status $status"); + } else { $image_path = $capture_image_path; } } @@ -445,12 +463,12 @@ sub uploadArchFile { my $event = shift; if ( ! $Config{ZM_UPLOAD_HOST} ) { - Error( 'Cannot upload archive as no upload host defined' ); + Error('Cannot upload archive as no upload host defined'); return( 0 ); } my $archFile = $event->{MonitorName}.'-'.$event->{Id}; - my $archImagePath = getEventPath( $event ) + my $archImagePath = getEventPath($event) .'/' .( ( $Config{ZM_UPLOAD_ARCH_ANALYSE} ) @@ -467,14 +485,14 @@ sub uploadArchFile { $archFile .= '.zip'; $archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile; my $zip = Archive::Zip->new(); - Info( "Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n" ); + Info("Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n"); my $status = &AZ_OK; foreach my $imageFile ( @archImageFiles ) { - Debug( "Adding $imageFile\n" ); - my $member = $zip->addFile( $imageFile ); + Debug("Adding $imageFile\n"); + my $member = $zip->addFile($imageFile); if ( !$member ) { - Error( "Unable toto add image file $imageFile to zip archive $archLocPath" ); + Error("Unable toto add image file $imageFile to zip archive $archLocPath"); $archError = 1; last; } @@ -487,10 +505,10 @@ sub uploadArchFile { $status = $zip->writeToFileNamed( $archLocPath ); if ( $archError = ($status != &AZ_OK) ) { - Error( "Zip error: $status\n " ); + Error("Zip error: $status"); } } else { - Error( "Error adding images to zip archive $archLocPath, not writing" ); + Error("Error adding images to zip archive $archLocPath, not writing"); } } elsif ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq 'tar' ) { if ( $Config{ZM_UPLOAD_ARCH_COMPRESS} ) { @@ -499,7 +517,7 @@ sub uploadArchFile { $archFile .= '.tar'; } $archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile; - Info( "Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n" ); + Info("Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n"); if ( $archError = !Archive::Tar->create_archive( $archLocPath, @@ -507,7 +525,7 @@ sub uploadArchFile { @archImageFiles ) ) { - Error( 'Tar error: '.Archive::Tar->error()."\n " ); + Error('Tar error: '.Archive::Tar->error()); } } @@ -515,7 +533,7 @@ sub uploadArchFile { return( 0 ); } else { if ( $Config{ZM_UPLOAD_PROTOCOL} eq 'ftp' ) { - Info( 'Uploading to '.$Config{ZM_UPLOAD_HOST}." using FTP\n" ); + Info('Uploading to '.$Config{ZM_UPLOAD_HOST}." using FTP"); my $ftp = Net::FTP->new( $Config{ZM_UPLOAD_HOST}, Timeout=>$Config{ZM_UPLOAD_TIMEOUT}, @@ -523,63 +541,61 @@ sub uploadArchFile { Debug=>$Config{ZM_UPLOAD_DEBUG} ); if ( !$ftp ) { - Error( "Unable tocreate FTP connection: $@" ); - return( 0 ); + Error("Unable tocreate FTP connection: $@"); + return 0; } - $ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} ) - or Error( "FTP - Unable tologin" ); + $ftp->login($Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS}) + or Error("FTP - Unable tologin"); $ftp->binary() - or Error( "FTP - Unable togo binary" ); - $ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} ) - or Error( "FTP - Unable tocwd" ) + or Error("FTP - Unable togo binary"); + $ftp->cwd($Config{ZM_UPLOAD_REM_DIR}) + or Error("FTP - Unable tocwd") if ( $Config{ZM_UPLOAD_REM_DIR} ); $ftp->put( $archLocPath ) - or Error( "FTP - Unable toupload '$archLocPath'" ); + or Error("FTP - Unable toupload '$archLocPath'"); $ftp->quit() - or Error( "FTP - Unable toquit" ); + or Error("FTP - Unable toquit"); } else { my $host = $Config{ZM_UPLOAD_HOST}; - $host .= ':'.$Config{ZM_UPLOAD_PORT} - if $Config{ZM_UPLOAD_PORT}; - Info( 'Uploading to '.$host." using SFTP\n" ); - my %sftpOptions = ( host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} ); - $sftpOptions{password} = $Config{ZM_UPLOAD_PASS} - if $Config{ZM_UPLOAD_PASS}; - $sftpOptions{port} = $Config{ZM_UPLOAD_PORT} - if $Config{ZM_UPLOAD_PORT}; - $sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT} - if $Config{ZM_UPLOAD_TIMEOUT}; + $host .= ':'.$Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT}; + Info('Uploading to '.$host." using SFTP\n"); + my %sftpOptions = ( + host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} + ($Config{ZM_UPLOAD_PASS} ? (password=>$Config{ZM_UPLOAD_PASS}) : ()), + ($Config{ZM_UPLOAD_PORT} ? (port=>$Config{ZM_UPLOAD_PORT}) : ()), + ($Config{ZM_UPLOAD_TIMEOUT} ? (timeout=>$Config{ZM_UPLOAD_TIMEOUT}) : ()), + ); my @more_ssh_args; push @more_ssh_args, '-o'=>'StrictHostKeyChecking=no' if ! $Config{ZM_UPLOAD_STRICT}; push @more_ssh_args, '-v' if $Config{ZM_UPLOAD_DEBUG}; $sftpOptions{more} = [@more_ssh_args]; - my $sftp = Net::SFTP::Foreign->new( $Config{ZM_UPLOAD_HOST}, %sftpOptions ); + my $sftp = Net::SFTP::Foreign->new($Config{ZM_UPLOAD_HOST}, %sftpOptions); if ( $sftp->error ) { - Error( "Unable tocreate SFTP connection: ".$sftp->error ); - return( 0 ); + Error("Unable tocreate SFTP connection: ".$sftp->error); + return 0; } - $sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) - or Error( "SFTP - Unable tosetcwd: ".$sftp->error ) + $sftp->setcwd($Config{ZM_UPLOAD_REM_DIR}) + or Error("SFTP - Unable to setcwd: ".$sftp->error) if $Config{ZM_UPLOAD_REM_DIR}; - $sftp->put( $archLocPath, $archFile ) - or Error( "SFTP - Unable toupload '$archLocPath': ".$sftp->error ); + $sftp->put($archLocPath, $archFile) + or Error("SFTP - Unable to upload '$archLocPath': ".$sftp->error); } - unlink( $archLocPath ); + unlink($archLocPath); my $sql = 'UPDATE Events SET Uploaded = 1 WHERE Id = ?'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) - or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached($sql) + or Fatal("Unable toprepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($event->{Id}) + or Fatal("Unable toexecute '$sql': ".$dbh->errstr()); } - return( 1 ); -} + return 1; +} # end sub uploadArchFile sub substituteTags { my $text = shift; my $filter = shift; - my $event = shift; + my $Event = shift; my $attachments_ref = shift; # First we'd better check what we need to get @@ -587,35 +603,7 @@ sub substituteTags { # monitor information? my $need_monitor = $text =~ /%(?:MET|MEH|MED|MEW|MEN|MEA)%/; - my $monitor = {}; - if ( $need_monitor ) { - my $db_now = strftime( '%Y-%m-%d %H:%M:%S', localtime() ); - my $sql = "SELECT - M.Id, - count(E.Id) as EventCount, - count(if(E.Archived,1,NULL)) - as ArchEventCount, - count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL)) - as HourEventCount, - count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL)) - as DayEventCount, - count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL)) - as WeekEventCount, - count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL)) - as MonthEventCount - FROM Monitors as M LEFT JOIN Events as E on E.MonitorId = M.Id - WHERE MonitorId = ? - GROUP BY E.MonitorId - ORDER BY Id" - ; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{MonitorId} ) - or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); - $monitor = $sth->fetchrow_hashref(); - $sth->finish(); - return() if ( !$monitor ); - } + my $Monitor = $Event->Monitor() if $need_monitor; # Do we need the image information too? my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA)%/; @@ -623,14 +611,14 @@ sub substituteTags { my $max_alarm_frame; my $max_alarm_score = 0; if ( $need_images ) { - my $sql = "SELECT * FROM Frames + my $sql = q`SELECT * FROM Frames WHERE EventId = ? AND Type = 'Alarm' - ORDER BY FrameId" - ; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) - or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); + ORDER BY FrameId`; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Unable toprepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($Event->{Id}) + or Fatal( "Unable toexecute '$sql': ".$dbh->errstr()); + my $rows = 0; while( my $frame = $sth->fetchrow_hashref() ) { if ( !$first_alarm_frame ) { $first_alarm_frame = $frame; @@ -639,72 +627,80 @@ sub substituteTags { $max_alarm_frame = $frame; $max_alarm_score = $frame->{Score}; } + $rows ++; } + Debug("Frames: rows: $rows first alarm frame: $first_alarm_frame max_alaarm_frame: $max_alarm_frame, score: $max_alarm_score"); $sth->finish(); } my $url = $Config{ZM_URL}; $text =~ s/%ZP%/$url/g; - $text =~ s/%MN%/$event->{MonitorName}/g; - $text =~ s/%MET%/$monitor->{EventCount}/g; - $text =~ s/%MEH%/$monitor->{HourEventCount}/g; - $text =~ s/%MED%/$monitor->{DayEventCount}/g; - $text =~ s/%MEW%/$monitor->{WeekEventCount}/g; - $text =~ s/%MEM%/$monitor->{MonthEventCount}/g; - $text =~ s/%MEA%/$monitor->{ArchEventCount}/g; - $text =~ s/%MP%/$url?view=watch&mid=$event->{MonitorId}/g; - $text =~ s/%MPS%/$url?view=watchfeed&mid=$event->{MonitorId}&mode=stream/g; - $text =~ s/%MPI%/$url?view=watchfeed&mid=$event->{MonitorId}&mode=still/g; - $text =~ s/%EP%/$url?view=event&mid=$event->{MonitorId}&eid=$event->{Id}/g; - $text =~ s/%EPS%/$url?view=event&mode=stream&mid=$event->{MonitorId}&eid=$event->{Id}/g; - $text =~ s/%EPI%/$url?view=event&mode=still&mid=$event->{MonitorId}&eid=$event->{Id}/g; - $text =~ s/%EI%/$event->{Id}/g; - $text =~ s/%EN%/$event->{Name}/g; - $text =~ s/%EC%/$event->{Cause}/g; - $text =~ s/%ED%/$event->{Notes}/g; - $text =~ s/%ET%/$event->{StartTime}/g; - $text =~ s/%EL%/$event->{Length}/g; - $text =~ s/%EF%/$event->{Frames}/g; - $text =~ s/%EFA%/$event->{AlarmFrames}/g; - $text =~ s/%EST%/$event->{TotScore}/g; - $text =~ s/%ESA%/$event->{AvgScore}/g; - $text =~ s/%ESM%/$event->{MaxScore}/g; + $text =~ s/%MN%/$Event->{MonitorName}/g; + $text =~ s/%MET%/$Monitor->{TotalEvents}/g; + $text =~ s/%MEH%/$Monitor->{HourEvents}/g; + $text =~ s/%MED%/$Monitor->{DayEvents}/g; + $text =~ s/%MEW%/$Monitor->{WeekEvents}/g; + $text =~ s/%MEM%/$Monitor->{MonthEvents}/g; + $text =~ s/%MEA%/$Monitor->{ArchivedEvents}/g; + $text =~ s/%MP%/$url?view=watch&mid=$Event->{MonitorId}/g; + $text =~ s/%MPS%/$url?view=watch&mid=$Event->{MonitorId}&mode=stream/g; + $text =~ s/%MPI%/$url?view=watch&mid=$Event->{MonitorId}&mode=still/g; + $text =~ s/%EP%/$url?view=event&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; + $text =~ s/%EPS%/$url?view=event&mode=stream&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; + $text =~ s/%EPI%/$url?view=event&mode=still&mid=$Event->{MonitorId}&eid=$Event->{Id}/g; + $text =~ s/%EI%/$Event->{Id}/g; + $text =~ s/%EN%/$Event->{Name}/g; + $text =~ s/%EC%/$Event->{Cause}/g; + $text =~ s/%ED%/$Event->{Notes}/g; + $text =~ s/%ET%/$Event->{StartTime}/g; + $text =~ s/%EL%/$Event->{Length}/g; + $text =~ s/%EF%/$Event->{Frames}/g; + $text =~ s/%EFA%/$Event->{AlarmFrames}/g; + $text =~ s/%EST%/$Event->{TotScore}/g; + $text =~ s/%ESA%/$Event->{AvgScore}/g; + $text =~ s/%ESM%/$Event->{MaxScore}/g; if ( $first_alarm_frame ) { - $text =~ s/%EPI1%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$first_alarm_frame->{FrameId}/g; - $text =~ s/%EPIM%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$max_alarm_frame->{FrameId}/g; + $text =~ s/%EPI1%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$first_alarm_frame->{FrameId}/g; + $text =~ s/%EPIM%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$max_alarm_frame->{FrameId}/g; if ( $attachments_ref && $text =~ s/%EI1%//g ) { - my $path = generateImage( $event, $first_alarm_frame ); + my $path = generateImage($Event, $first_alarm_frame); if ( -e $path ) { - push( @$attachments_ref, { type=>'image/jpeg', path=>$path } ); + push @$attachments_ref, { type=>'image/jpeg', path=>$path }; } } - if ( $attachments_ref && $text =~ s/%EIM%//g ) { + if ( $attachments_ref && ( $text =~ s/%EIM%//g ) ) { # Don't attach the same image twice if ( !@$attachments_ref - || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) + || ( $first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) ) { - my $path = generateImage( $event, $max_alarm_frame ); + my $path = generateImage($Event, $max_alarm_frame); if ( -e $path ) { - push( @$attachments_ref, { type=>'image/jpeg', path=>$path } ); + push @$attachments_ref, { type=>'image/jpeg', path=>$path }; + } else { + Warning("No image for EIM"); } } } if ( $attachments_ref && $text =~ s/%EI1A%//g ) { - my $path = generateImage( $event, $first_alarm_frame, 'analyse' ); + my $path = generateImage($Event, $first_alarm_frame, 'analyse'); if ( -e $path ) { - push( @$attachments_ref, { type=>'image/jpeg', path=>$path } ); + push @$attachments_ref, { type=>'image/jpeg', path=>$path }; + } else { + Warning("No image for EI1A"); } } if ( $attachments_ref && $text =~ s/%EIMA%//g ) { # Don't attach the same image twice if ( !@$attachments_ref - || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) + || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId}) ) { - my $path = generateImage( $event, $max_alarm_frame, 'analyse'); + my $path = generateImage($Event, $max_alarm_frame, 'analyse'); if ( -e $path ) { - push( @$attachments_ref, { type=>'image/jpeg', path=>$path } ); + push @$attachments_ref, { type=>'image/jpeg', path=>$path }; + } else { + Warning('No image for EIMA'); } } } @@ -712,49 +708,49 @@ sub substituteTags { if ( $attachments_ref && $Config{ZM_OPT_FFMPEG} ) { if ( $text =~ s/%EV%//g ) { - my ( $format, $path ) = generateVideo( $filter, $event ); + my ( $format, $path ) = generateVideo($filter, $Event); if ( !$format ) { - return( undef ); + return undef; } push( @$attachments_ref, { type=>"video/$format", path=>$path } ); } if ( $text =~ s/%EVM%//g ) { - my ( $format, $path ) = generateVideo( $filter, $event, 1 ); + my ( $format, $path ) = generateVideo($filter, $Event, 1); if ( !$format ) { - return( undef ); + return undef; } - push( @$attachments_ref, { type=>"video/$format", path=>$path } ); + push @$attachments_ref, { type=>"video/$format", path=>$path }; } } $text =~ s/%FN%/$filter->{Name}/g; ( my $filter_name = $filter->{Name} ) =~ s/ /+/g; - $text =~ s/%FP%/$url?view=filter&mid=$event->{MonitorId}&filter_name=$filter_name/g; + $text =~ s/%FP%/$url?view=filter&mid=$Event->{MonitorId}&filter_name=$filter_name/g; - return( $text ); + return $text; } # end subsitituteTags sub sendEmail { my $filter = shift; - my $event = shift; + my $Event = shift; if ( ! $Config{ZM_FROM_EMAIL} ) { - Error( "No 'from' email address defined, not sending email" ); - return( 0 ); + Error('No from email address defined, not sending email'); + return 0; } if ( ! $Config{ZM_EMAIL_ADDRESS} ) { - Error( 'No email address defined, not sending email' ); - return( 0 ); + Error('No email address defined, not sending email'); + return 0; } - Info( "Creating notification email\n" ); + Info('Creating notification email'); - my $subject = substituteTags( $Config{ZM_EMAIL_SUBJECT}, $filter, $event ); - return( 0 ) if ( !$subject ); + my $subject = substituteTags($Config{ZM_EMAIL_SUBJECT}, $filter, $Event); + return 0 if !$subject; my @attachments; - my $body = substituteTags( $Config{ZM_EMAIL_BODY}, $filter, $event, \@attachments ); - return( 0 ) if ( !$body ); + my $body = substituteTags($Config{ZM_EMAIL_BODY}, $filter, $Event, \@attachments); + return 0 if !$body; - Info( "Sending notification email '$subject'\n" ); + Info("Sending notification email '$subject'"); eval { if ( $Config{ZM_NEW_MAIL_MODULES} ) { @@ -772,7 +768,7 @@ sub sendEmail { ); ### Add the attachments foreach my $attachment ( @attachments ) { - Info( "Attaching '$attachment->{path}\n" ); + Info( "Attaching '$attachment->{path}'" ); $mail->attach( Path => $attachment->{path}, Type => $attachment->{type}, @@ -784,20 +780,20 @@ sub sendEmail { my $ssmtp_location = $Config{ZM_SSMTP_PATH}; if ( !$ssmtp_location ) { if ( logDebugging() ) { - Debug( "which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message\n" ); + Debug("which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message"); } $ssmtp_location = qx('which ssmtp'); } if ( !$ssmtp_location ) { - Debug( "Unable tofind ssmtp, trying MIME::Lite->send" ); - MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); + Debug('Unable tofind ssmtp, trying MIME::Lite->send'); + MIME::Lite->send('smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60); $mail->send(); } else { ### Send using SSMTP - $mail->send( 'sendmail', $ssmtp_location, $Config{ZM_EMAIL_ADDRESS} ); + $mail->send('sendmail', $ssmtp_location, $Config{ZM_EMAIL_ADDRESS}); } } else { - MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); + MIME::Lite->send('smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60); $mail->send(); } } else { @@ -810,29 +806,29 @@ sub sendEmail { ); foreach my $attachment ( @attachments ) { - Info( "Attaching '$attachment->{path}\n" ); + Info("Attaching '$attachment->{path}'"); $mail->attach( Path => $attachment->{path}, Type => $attachment->{type}, Encoding => 'base64' ); } - $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} ); + $mail->smtpsend(Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL}); } }; if ( $@ ) { - Error( "Unable tosend email: $@" ); - return( 0 ); + Error("Unable tosend email: $@"); + return 0; } else { - Info( "Notification email sent\n" ); + Info('Notification email sent'); } - my $sql = 'update Events set Emailed = 1 where Id = ?'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) - or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); + my $sql = 'UPDATE Events SET Emailed = 1 WHERE Id = ?'; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Unable toprepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($Event->{Id}) + or Fatal("Unable toexecute '$sql': ".$dbh->errstr()); - return( 1 ); + return 1; } sub sendMessage { @@ -840,28 +836,28 @@ sub sendMessage { my $event = shift; if ( ! $Config{ZM_FROM_EMAIL} ) { - Error( "No 'from' email address defined, not sending message" ); - return( 0 ); + Error('No from email address defined, not sending message'); + return 0; } if ( ! $Config{ZM_MESSAGE_ADDRESS} ) { - Error( 'No message address defined, not sending message' ); - return( 0 ); + Error('No message address defined, not sending message'); + return 0; } - Info( "Creating notification message\n" ); + Info('Creating notification message'); - my $subject = substituteTags( $Config{ZM_MESSAGE_SUBJECT}, $filter, $event ); - return( 0 ) if ( !$subject ); + my $subject = substituteTags($Config{ZM_MESSAGE_SUBJECT}, $filter, $event); + return 0 if !$subject; my @attachments; - my $body = substituteTags( $Config{ZM_MESSAGE_BODY}, $filter, $event, \@attachments ); - return( 0 ) if ( !$body ); + my $body = substituteTags($Config{ZM_MESSAGE_BODY}, $filter, $event, \@attachments); + return 0 if !$body; - Info( "Sending notification message '$subject'\n" ); + Info("Sending notification message '$subject'"); eval { if ( $Config{ZM_NEW_MAIL_MODULES} ) { ### Create the multipart container - my $mail = MIME::Lite->new ( + my $mail = MIME::Lite->new( From => $Config{ZM_FROM_EMAIL}, To => $Config{ZM_MESSAGE_ADDRESS}, Subject => $subject, @@ -874,7 +870,7 @@ sub sendMessage { ); ### Add the attachments foreach my $attachment ( @attachments ) { - Info( "Attaching '$attachment->{path}\n" ); + Info("Attaching '$attachment->{path}"); $mail->attach( Path => $attachment->{path}, Type => $attachment->{type}, @@ -886,20 +882,20 @@ sub sendMessage { my $ssmtp_location = $Config{ZM_SSMTP_PATH}; if ( !$ssmtp_location ) { if ( logDebugging() ) { - Debug( "which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message\n" ); + Debug("which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message"); } $ssmtp_location = qx('which ssmtp'); } if ( !$ssmtp_location ) { - Debug( 'Unable tofind ssmtp, trying MIME::Lite->send' ); - MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); + Debug('Unable tofind ssmtp, trying MIME::Lite->send'); + MIME::Lite->send(smtp=>$Config{ZM_EMAIL_HOST}, Timeout=>60); $mail->send(); } else { ### Send using SSMTP - $mail->send( 'sendmail', $ssmtp_location, $Config{ZM_MESSAGE_ADDRESS} ); + $mail->send('sendmail', $ssmtp_location, $Config{ZM_MESSAGE_ADDRESS}); } } else { - MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 ); + MIME::Lite->send(smtp=>$Config{ZM_EMAIL_HOST}, Timeout=>60); $mail->send(); } } else { @@ -912,59 +908,60 @@ sub sendMessage { ); foreach my $attachment ( @attachments ) { - Info( "Attaching '$attachment->{path}\n" ); + Info("Attaching '$attachment->{path}'"); $mail->attach( Path => $attachment->{path}, Type => $attachment->{type}, Encoding => 'base64' ); } - $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, + $mail->smtpsend( + Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} ); } }; if ( $@ ) { - Error( "Unable tosend email: $@" ); - return( 0 ); + Error("Unable tosend email: $@"); + return 0; } else { - Info( "Notification message sent\n" ); + Info('Notification message sent'); } - my $sql = 'update Events set Messaged = 1 where Id = ?'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) - or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); + my $sql = 'UPDATE Events SET Messaged = 1 WHERE Id = ?'; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Unable toprepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($event->{Id}) + or Fatal("Unable toexecute '$sql': ".$dbh->errstr()); - return( 1 ); + return 1; } sub executeCommand { my $filter = shift; my $event = shift; - my $event_path = getEventPath( $event ); + my $event_path = getEventPath($event); my $command = $filter->{AutoExecuteCmd}; $command .= " $event_path"; - $command = substituteTags( $command, $filter, $event ); + $command = substituteTags($command, $filter, $event); - Info( "Executing '$command'\n" ); + Info("Executing '$command'"); my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { - chomp( $output ); - Debug( "Output: $output\n" ); + chomp($output); + Debug("Output: $output"); } if ( $status ) { - Error( "Command '$command' exited with status: $status\n" ); - return( 0 ); + Error("Command '$command' exited with status: $status"); + return 0; } else { - my $sql = 'update Events set Executed = 1 where Id = ?'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() ); + my $sql = 'UPDATE Events SET Executed = 1 WHERE Id = ?'; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Unable to prepare '$sql': ".$dbh->errstr()); my $res = $sth->execute( $event->{Id} ) - or Fatal( "Unable toexecute '$sql': ".$sth->errstr() ); + or Fatal("Unable to execute '$sql': ".$dbh->errstr()); } return( 1 ); } diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 3daadbc26..70934a8ef 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -205,12 +205,13 @@ if ( $command =~ /^(?:start|restart)$/ ) { $sql = 'SELECT * FROM Monitors'; } + { my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( @values ) or Fatal( "Can't execute: ".$sth->errstr() ); while( my $monitor = $sth->fetchrow_hashref() ) { - if ( $monitor->{Function} ne 'None' ) { + if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) { if ( $monitor->{Type} eq 'Local' ) { runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); } else { @@ -226,9 +227,24 @@ if ( $command =~ /^(?:start|restart)$/ ) { } } $sth->finish(); - + } + { + my $sql = 'SELECT Id FROM Filters WHERE Background=1'; + my $sth = $dbh->prepare_cached($sql) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + if ( $sth->rows ) { + while( my $filter = $sth->fetchrow_hashref() ) { # This is now started unconditionally - runCommand('zmdc.pl start zmfilter.pl'); + runCommand("zmdc.pl start zmfilter.pl --filter_id=$$filter{Id}"); + } + } else { + runCommand('zmdc.pl start zmfilter.pl'); + } + $sth->finish(); + } + if ( $Config{ZM_RUN_AUDIT} ) { if ( $Server and exists $$Server{'zmaudit'} and ! $$Server{'zmaudit'} ) { Debug("Not running zmaudit.pl because it is turned off for this server."); @@ -253,6 +269,9 @@ if ( $command =~ /^(?:start|restart)$/ ) { if ( $Config{ZM_TELEMETRY_DATA} ) { runCommand('zmdc.pl start zmtelemetry.pl'); } + if ($Config{ZM_OPT_USE_EVENTNOTIFICATION} ) { + runCommand('zmdc.pl start zmeventnotification.pl'); + } if ( $Server and exists $$Server{'zmstats'} and ! $$Server{'zmstats'} ) { Debug("Not running zmstats.pl because it is turned off for this server."); } else { diff --git a/scripts/zmtelemetry.pl.in b/scripts/zmtelemetry.pl.in index 54521d335..c23240891 100644 --- a/scripts/zmtelemetry.pl.in +++ b/scripts/zmtelemetry.pl.in @@ -53,67 +53,70 @@ GetOptions( version => \$version ); if ( $version ) { - print( ZoneMinder::Base::ZM_VERSION . "\n"); - exit(0); + print( ZoneMinder::Base::ZM_VERSION . "\n"); + exit(0); } if ( $help ) { - pod2usage(-exitstatus => -1); + pod2usage(-exitstatus => -1); } if ( ! defined $interval ) { $interval = eval($Config{ZM_TELEMETRY_INTERVAL}); } -if ( $Config{ZM_TELEMETRY_DATA} or $force ) { - print "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n"; +if ( !($Config{ZM_TELEMETRY_DATA} or $force) ) { + print "ZoneMinder Telemetry Agent not enabled. Exiting.\n"; + exit(0); +} + +print 'ZoneMinder Telemetry Agent starting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n"; - my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD}; +my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD}; - while( 1 ) { - my $now = time(); - my $since_last_check = $now-$lastCheck; - Debug(" Last Check time (now($now) - lastCheck($lastCheck)) = $since_last_check > interval($interval) or force($force)"); - if ( $since_last_check < 0 ) { - Warning( "Seconds since last check is negative! Which means that lastCheck is in the future!" ); - next; - } - if ( ( ($now-$lastCheck) > $interval ) or $force ) { - print "Collecting data to send to ZoneMinder Telemetry server.\n"; - my $dbh = zmDbConnect(); +while( 1 ) { + my $now = time(); + my $since_last_check = $now-$lastCheck; + Debug(" Last Check time (now($now) - lastCheck($lastCheck)) = $since_last_check > interval($interval) or force($force)"); + if ( $since_last_check < 0 ) { + Warning( 'Seconds since last check is negative! Which means that lastCheck is in the future!' ); + next; + } + if ( ( ($since_last_check) > $interval ) or $force ) { + print "Collecting data to send to ZoneMinder Telemetry server.\n"; + my $dbh = zmDbConnect(); # Build the telemetry hash # We should keep *BSD systems in mind when calling system commands - my %telemetry; - $telemetry{uuid} = getUUID($dbh); - $telemetry{ip} = getIP(); - $telemetry{timestamp} = strftime( '%Y-%m-%dT%H:%M:%S%z', localtime() ); - $telemetry{monitor_count} = countQuery($dbh,'Monitors'); - $telemetry{event_count} = countQuery($dbh,'Events'); - $telemetry{architecture} = runSysCmd('uname -p'); - ($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro(); - $telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION; - $telemetry{system_memory} = totalmem(); - $telemetry{processor_count} = cpu_count(); - $telemetry{monitors} = getMonitorRef($dbh); + my %telemetry; + $telemetry{uuid} = getUUID($dbh); + $telemetry{ip} = getIP(); + $telemetry{timestamp} = strftime( '%Y-%m-%dT%H:%M:%S%z', localtime() ); + $telemetry{monitor_count} = countQuery($dbh,'Monitors'); + $telemetry{event_count} = countQuery($dbh,'Events'); + $telemetry{architecture} = runSysCmd('uname -p'); + ($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro(); + $telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION; + $telemetry{system_memory} = totalmem(); + $telemetry{processor_count} = cpu_count(); + $telemetry{monitors} = getMonitorRef($dbh); - Info( 'Sending data to ZoneMinder Telemetry server.' ); + Info('Sending data to ZoneMinder Telemetry server.'); - my $result = jsonEncode( \%telemetry ); + my $result = jsonEncode(\%telemetry); - if ( sendData($result) ) { - - my $sql = q`UPDATE Config SET Value = ? WHERE Name = 'ZM_TELEMETRY_LAST_UPLOAD'`; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $now ) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); - $Config{ZM_TELEMETRY_LAST_UPLOAD} = $now; - } - zmDbDisconnect(); - } elsif ( -t STDIN ) { - print "Update agent sleeping for 1 hour because ($now-$lastCheck=$since_last_check > $interval\n"; - } - sleep( 3600 ); - } - print 'Update agent exiting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n"; -} + if ( sendData($result) ) { + my $sql = q`UPDATE Config SET Value = ? WHERE Name = 'ZM_TELEMETRY_LAST_UPLOAD'`; + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($now) or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); + $Config{ZM_TELEMETRY_LAST_UPLOAD} = $now; + } + zmDbDisconnect(); + } elsif ( -t STDIN ) { + print "ZoneMinder Telemetry Agent sleeping for $interval seconds because ($now-$lastCheck=$since_last_check > $interval\n"; + } + $lastCheck = $now; + sleep($interval); +} # end while +print 'ZoneMinder Telemetry Agent exiting at '.strftime('%y/%m/%d %H:%M:%S', localtime())."\n"; ############### # SUBROUTINES # @@ -178,7 +181,7 @@ sub sendData { # Retrieves the UUID from the database. Creates a new UUID if one does not exist. sub getUUID { my $dbh = shift; - my $uuid= ""; + my $uuid= ''; # Verify the current UUID is valid and not nil if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne '00000000-0000-0000-0000-000000000000' )) { diff --git a/scripts/zmvideo.pl.in b/scripts/zmvideo.pl.in index 788ecde87..1f1b33acc 100644 --- a/scripts/zmvideo.pl.in +++ b/scripts/zmvideo.pl.in @@ -197,8 +197,6 @@ my $sql = " SELECT (SELECT max(Delta) FROM Frames WHERE EventId=Events.Id)-(SELE Events.*, unix_timestamp(Events.StartTime) as Time, M.Name as MonitorName, - M.Width as MonitorWidth, - M.Height as MonitorHeight, M.Palette FROM Events INNER JOIN Monitors as M on Events.MonitorId = M.Id diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index 57ffd49a6..10fd55e11 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -84,6 +84,7 @@ while( 1 ) { while( my $monitor = $sth->fetchrow_hashref() ) { my $now = time(); next if $monitor->{Function} eq 'None'; + next if $monitor->{Type} eq 'WebSite'; my $restart = 0; if ( zmMemVerify( $monitor ) ) { # Check we have got an image recently @@ -147,11 +148,11 @@ while( 1 ) { if ( !defined($image_time) ) { # Can't read from shared data $restart = 1; - Error( "Error reading shared data for $$monitor{Id} $$monitor{Name}\n"); + Error("Error reading shared data for $$monitor{Id} $$monitor{Name}\n"); } elsif ( !$image_time ) { # We can't get the last capture time so can't be sure it's died. $restart = 1; - Error( "Error getting last analyse time for $$monitor{Id} $$monitor{Name}\n"); + Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero.\n"); } else { my $max_image_delay = ( $monitor->{MaxFPS} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 838d0e3d2..2c0ffd4ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,9 @@ configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY) # Group together all the source files that are used by all the binaries (zmc, zmu, zms etc) -set(ZM_BIN_SRC_FILES zm_analysis_thread.cpp zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_ffmpeg_input.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp) +set(ZM_BIN_SRC_FILES + zm_analysis_thread.cpp + zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_ffmpeg_input.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_nvsocket.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index ce0a9bc60..43e97f26a 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -1,53 +1,68 @@ // // ZoneMinder Camera Class Implementation, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// #include "zm.h" #include "zm_camera.h" -Camera::Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_width, unsigned int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : - monitor_id( p_monitor_id ), - type( p_type ), - width( p_width), - height( p_height ), - colours( p_colours ), - subpixelorder( p_subpixelorder ), - brightness( p_brightness ), - hue( p_hue ), - colour( p_colour ), - contrast( p_contrast ), - capture( p_capture ), - record_audio( p_record_audio ), +Camera::Camera( + unsigned int p_monitor_id, + SourceType p_type, + unsigned int p_width, + unsigned int p_height, + int p_colours, + int p_subpixelorder, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio + ) : + monitor_id(p_monitor_id), + type(p_type), + width(p_width), + height(p_height), + colours(p_colours), + subpixelorder(p_subpixelorder), + brightness(p_brightness), + hue(p_hue), + colour(p_colour), + contrast(p_contrast), + capture(p_capture), + record_audio(p_record_audio), mVideoStreamId(-1), mAudioStreamId(-1), mVideoCodecContext(NULL), mAudioCodecContext(NULL), - video_stream(NULL) + video_stream(NULL), + bytes(0) { pixels = width * height; imagesize = pixels * colours; - - Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",monitor_id,width,height,colours,subpixelorder,capture); - + + Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d", + monitor_id,width,height,colours,subpixelorder,capture); + /* Because many loops are unrolled and work on 16 colours/time or 4 pixels/time, we have to meet requirements */ - if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0) { + if ( (colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0 ) { Fatal("Image size is not multiples of 64"); - } else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0)) { + } else if ( colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0) ) { Fatal("Image size is not multiples of 12 and 64"); } monitor = NULL; @@ -57,14 +72,12 @@ Camera::~Camera() { } Monitor *Camera::getMonitor() { - if ( ! monitor ) { - Warning("Loading monitor"); - monitor = Monitor::Load( monitor_id, false, Monitor::QUERY ); - } + if ( ! monitor ) + monitor = Monitor::Load(monitor_id, false, Monitor::QUERY); return monitor; -} +} -void Camera::setMonitor( Monitor *p_monitor ) { +void Camera::setMonitor(Monitor *p_monitor) { monitor = p_monitor; monitor_id = monitor->Id(); } diff --git a/src/zm_camera.h b/src/zm_camera.h index 204aa526d..292ece560 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -53,6 +53,8 @@ protected: int contrast; bool capture; bool record_audio; + unsigned int bytes; + int mVideoStreamId; int mAudioStreamId; @@ -89,10 +91,11 @@ public: bool IscURL() const { return( type == CURL_SRC ); } unsigned int Width() const { return( width ); } unsigned int Height() const { return( height ); } - unsigned int Colours() const { return( colours ); } + unsigned int Colours() const { return colours; } unsigned int SubpixelOrder() const { return( subpixelorder ); } unsigned int Pixels() const { return( pixels ); } unsigned int ImageSize() const { return( imagesize ); } + unsigned int Bytes() const { return bytes; }; virtual int Brightness( int/*p_brightness*/=-1 ) { return( -1 ); } virtual int Hue( int/*p_hue*/=-1 ) { return( -1 ); } @@ -113,6 +116,7 @@ public: virtual AVCodecContext *get_AudioCodecContext() { return NULL; }; int get_VideoStreamId() { return mVideoStreamId; }; int get_AudioStreamId() { return mAudioStreamId; }; + virtual int Close()=0; }; #endif // ZM_CAMERA_H diff --git a/src/zm_comms.h b/src/zm_comms.h index b5974771d..133c0d19f 100644 --- a/src/zm_comms.h +++ b/src/zm_comms.h @@ -194,7 +194,7 @@ public: SockAddrUnix(); SockAddrUnix( const SockAddrUnix &addr ) : SockAddr( (const struct sockaddr *)&mAddrUn ), mAddrUn( addr.mAddrUn ) { } - SockAddrUnix( const struct sockaddr_un *addr ) : SockAddr( (const struct sockaddr *)&mAddrUn ), mAddrUn( *addr ) { + explicit SockAddrUnix( const struct sockaddr_un *addr ) : SockAddr( (const struct sockaddr *)&mAddrUn ), mAddrUn( *addr ) { } bool resolve( const char *path, const char *proto ); @@ -622,9 +622,9 @@ protected: public: Select(); - Select( struct timeval timeout ); - Select( int timeout ); - Select( double timeout ); + explicit Select( struct timeval timeout ); + explicit Select( int timeout ); + explicit Select( double timeout ); void setTimeout( int timeout ); void setTimeout( double timeout ); diff --git a/src/zm_curl_camera.h b/src/zm_curl_camera.h index f3a6ce47e..5c1b84fcc 100644 --- a/src/zm_curl_camera.h +++ b/src/zm_curl_camera.h @@ -73,6 +73,7 @@ public: void Initialise(); void Terminate(); + int Close() { return 0; }; int PrimeCapture(); int PreCapture(); diff --git a/src/zm_db.cpp b/src/zm_db.cpp index fc5ee5fe0..d4a927f3b 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -23,7 +23,6 @@ #include "zm.h" #include "zm_db.h" -// From what I read, we need one of these per thread MYSQL dbconn; Mutex db_mutex; @@ -31,34 +30,37 @@ bool zmDbConnected = false; bool zmDbConnect() { // For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu - //if ( zmDbConnected ) - //return; + // But they really need to be here in order to prevent a double open of mysql + if ( zmDbConnected ) { + Warning("Calling zmDbConnect when already connected"); + return true; + } - if ( !mysql_init( &dbconn ) ) { - Error( "Can't initialise database connection: %s", mysql_error( &dbconn ) ); + if ( !mysql_init(&dbconn) ) { + Error("Can't initialise database connection: %s", mysql_error(&dbconn)); return false; } my_bool reconnect = 1; - if ( mysql_options( &dbconn, MYSQL_OPT_RECONNECT, &reconnect ) ) - Error( "Can't set database auto reconnect option: %s", mysql_error( &dbconn) ); + if ( mysql_options(&dbconn, MYSQL_OPT_RECONNECT, &reconnect) ) + Error("Can't set database auto reconnect option: %s", mysql_error(&dbconn)); if ( !staticConfig.DB_SSL_CA_CERT.empty() ) - mysql_ssl_set( &dbconn, + mysql_ssl_set(&dbconn, staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), - NULL, NULL ); - std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" ); + NULL, NULL); + std::string::size_type colonIndex = staticConfig.DB_HOST.find(":"); if ( colonIndex == std::string::npos ) { - if ( !mysql_real_connect( &dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0 ) ) { - Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); + if ( !mysql_real_connect(&dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0) ) { + Error( "Can't connect to server: %s", mysql_error(&dbconn)); return false; } } else { std::string dbHost = staticConfig.DB_HOST.substr( 0, colonIndex ); std::string dbPortOrSocket = staticConfig.DB_HOST.substr( colonIndex+1 ); if ( dbPortOrSocket[0] == '/' ) { - if ( !mysql_real_connect( &dbconn, NULL, staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, dbPortOrSocket.c_str(), 0 ) ) { - Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); + if ( !mysql_real_connect(&dbconn, NULL, staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, dbPortOrSocket.c_str(), 0) ) { + Error("Can't connect to server: %s", mysql_error(&dbconn)); return false; } } else { @@ -70,7 +72,7 @@ bool zmDbConnect() { } if ( mysql_select_db( &dbconn, staticConfig.DB_NAME.c_str() ) ) { Error( "Can't select database: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + return false; } zmDbConnected = true; return zmDbConnected; @@ -78,67 +80,72 @@ bool zmDbConnect() { void zmDbClose() { if ( zmDbConnected ) { + db_mutex.lock(); mysql_close( &dbconn ); // mysql_init() call implicitly mysql_library_init() but // mysql_close() does not call mysql_library_end() mysql_library_end(); zmDbConnected = false; + db_mutex.unlock(); } } -MYSQL_RES * zmDbFetch( const char * query ) { +MYSQL_RES * zmDbFetch(const char * query) { if ( ! zmDbConnected ) { - Error( "Not connected." ); + Error("Not connected."); return NULL; } db_mutex.lock(); - if ( mysql_query( &dbconn, query ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + if ( mysql_query(&dbconn, query) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + db_mutex.unlock(); return NULL; } - Debug( 4, "Success running query: %s", query ); - MYSQL_RES *result = mysql_store_result( &dbconn ); + Debug(4, "Success running query: %s", query); + MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { - Error( "Can't use query result: %s for query %s", mysql_error( &dbconn ), query ); - return NULL; + Error("Can't use query result: %s for query %s", mysql_error(&dbconn), query); } db_mutex.unlock(); return result; -} // end MYSQL_RES * zmDbFetch( const char * query ); +} // end MYSQL_RES * zmDbFetch(const char * query); -zmDbRow *zmDbFetchOne( const char *query ) { +zmDbRow *zmDbFetchOne(const char *query) { zmDbRow *row = new zmDbRow(); - if ( row->fetch( query ) ) { + if ( row->fetch(query) ) { return row; } delete row; return NULL; } -MYSQL_RES *zmDbRow::fetch( const char *query ) { - result_set = zmDbFetch( query ); +MYSQL_RES *zmDbRow::fetch(const char *query) { + result_set = zmDbFetch(query); if ( ! result_set ) return result_set; - int n_rows = mysql_num_rows( result_set ); + int n_rows = mysql_num_rows(result_set); if ( n_rows != 1 ) { - Error( "Bogus number of lines return from query, %d returned for query %s.", n_rows, query ); - mysql_free_result( result_set ); + Error("Bogus number of lines return from query, %d returned for query %s.", n_rows, query); + mysql_free_result(result_set); result_set = NULL; return result_set; } - row = mysql_fetch_row( result_set ); + row = mysql_fetch_row(result_set); if ( ! row ) { - mysql_free_result( result_set ); + mysql_free_result(result_set); result_set = NULL; - Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) ); + Error("Error getting row from query %s. Error is %s", query, mysql_error(&dbconn)); } else { Debug(5, "Success"); } return result_set; } + zmDbRow::~zmDbRow() { - if ( result_set ) - mysql_free_result( result_set ); + if ( result_set ) { + mysql_free_result(result_set); + result_set = NULL; + } } diff --git a/src/zm_db.h b/src/zm_db.h index 267995e70..de47a6108 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -33,6 +33,8 @@ class zmDbRow { zmDbRow( MYSQL_RES *, MYSQL_ROW *row ); ~zmDbRow(); + MYSQL_ROW mysql_row() const { return row; }; + char *operator[](unsigned int index) const { return row[index]; } diff --git a/src/zm_event.cpp b/src/zm_event.cpp index da23288ad..ee533937f 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "zm.h" #include "zm_db.h" @@ -49,10 +50,10 @@ Event::Event( const std::string &p_cause, const StringSetMap &p_noteSetMap ) : - monitor( p_monitor ), - start_time( p_start_time ), - cause( p_cause ), - noteSetMap( p_noteSetMap ) + monitor(p_monitor), + start_time(p_start_time), + cause(p_cause), + noteSetMap(p_noteSetMap) { std::string notes; @@ -66,11 +67,14 @@ Event::Event( untimedEvent = true; start_time = now; } else if ( start_time.tv_sec > now.tv_sec ) { - Error("StartTime in the future"); + Error("StartTime in the future %u.%u > %u.%u", + start_time.tv_sec, start_time.tv_usec, now.tv_sec, now.tv_usec + ); start_time = now; } Storage * storage = monitor->getStorage(); + scheme = storage->Scheme(); unsigned int state_id = 0; zmDbRow dbrow; @@ -78,8 +82,15 @@ Event::Event( state_id = atoi(dbrow[0]); } - static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d, '%s' )", + // Copy it in case opening the mp4 doesn't work we can set it to another value + save_jpegs = monitor->GetOptSaveJPEGs(); + + char sql[ZM_SQL_MED_BUFSIZ]; + snprintf(sql, sizeof(sql), + "INSERT INTO Events " + "( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme )" + " VALUES " + "( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d, '%s' )", monitor->Id(), storage->Id(), start_time.tv_sec, @@ -95,14 +106,15 @@ Event::Event( ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql ); - exit( mysql_errno( &dbconn ) ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't insert event: %s. sql was (%s)", mysql_error(&dbconn), sql); + db_mutex.unlock(); + return; } - id = mysql_insert_id( &dbconn ); + id = mysql_insert_id(&dbconn); db_mutex.unlock(); if ( untimedEvent ) { - Warning( "Event %d has zero time, setting to current", id ); + Warning("Event %d has zero time, setting to current", id); } end_time.tv_sec = 0; frames = 0; @@ -111,12 +123,10 @@ Event::Event( max_score = 0; have_video_keyframe = false; - char id_file[PATH_MAX]; - struct tm *stime = localtime( &start_time.tv_sec ); + struct tm *stime = localtime(&start_time.tv_sec); if ( storage->Scheme() == Storage::DEEP ) { - char *path_ptr = path; - path_ptr += snprintf( path_ptr, sizeof(path), "%s/%d", storage->Path(), monitor->Id() ); + path = stringtf("%s/%d", storage->Path(), monitor->Id()); int dt_parts[6]; dt_parts[0] = stime->tm_year-100; @@ -130,55 +140,54 @@ Event::Event( char time_path[PATH_MAX] = ""; char *time_path_ptr = time_path; for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) { - path_ptr += snprintf( path_ptr, sizeof(path)-(path_ptr-path), "/%02d", dt_parts[i] ); + path += stringtf("/%02d", dt_parts[i]); errno = 0; - if ( mkdir( path, 0755 ) ) { + if ( mkdir(path.c_str(), 0755) ) { // FIXME This should not be fatal. Should probably move to a different storage area. if ( errno != EEXIST ) { - Error( "Can't mkdir %s: %s", path, strerror(errno)); + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); } } if ( i == 2 ) - strncpy( date_path, path, sizeof(date_path) ); + strncpy(date_path, path.c_str(), sizeof(date_path)); else if ( i >= 3 ) - time_path_ptr += snprintf( time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i] ); + time_path_ptr += snprintf(time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i]); } // Create event id symlink - snprintf( id_file, sizeof(id_file), "%s/.%d", date_path, id ); - if ( symlink( time_path, id_file ) < 0 ) - Error( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno)); + std::string id_file = stringtf("%s/.%" PRIu64, date_path, id); + if ( symlink(time_path, id_file.c_str()) < 0 ) + Error("Can't symlink %s -> %s: %s", id_file.c_str(), path.c_str(), strerror(errno)); } else if ( storage->Scheme() == Storage::MEDIUM ) { - char *path_ptr = path; - path_ptr += snprintf( path_ptr, sizeof(path), "%s/%d/%04d-%02d-%02d", + path = stringtf("%s/%d/%04d-%02d-%02d", storage->Path(), monitor->Id(), stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday ); - if ( mkdir( path, 0755 ) ) { + if ( mkdir(path.c_str(), 0755) ) { // FIXME This should not be fatal. Should probably move to a different storage area. if ( errno != EEXIST ) - Error( "Can't mkdir %s: %s", path, strerror(errno)); + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); } - path_ptr += snprintf( path_ptr, sizeof(path), "/%d", id ); - if ( mkdir( path, 0755 ) ) { + path += stringtf("/%" PRIu64, id); + if ( mkdir(path.c_str(), 0755) ) { // FIXME This should not be fatal. Should probably move to a different storage area. if ( errno != EEXIST ) - Error( "Can't mkdir %s: %s", path, strerror(errno)); + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); } } else { // Shallow Storage - snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id ); - if ( mkdir( path, 0755 ) ) { + path = stringtf("%s/%d/%" PRIu64, storage->Path(), monitor->Id(), id); + if ( mkdir(path.c_str(), 0755) ) { if ( errno != EEXIST ) { - Error( "Can't mkdir %s: %s", path, strerror(errno)); + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); } } // Create empty id tag file - snprintf( id_file, sizeof(id_file), "%s/.%d", path, id ); - if ( FILE *id_fp = fopen( id_file, "w" ) ) - fclose( id_fp ); + std::string id_file = stringtf("%s/.%" PRIu64, path, id); + if ( FILE *id_fp = fopen(id_file.c_str(), "w") ) + fclose(id_fp); else - Error( "Can't fopen %s: %s", id_file, strerror(errno)); + Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno)); } // deep storage or not last_db_frame = 0; @@ -190,16 +199,16 @@ Event::Event( if ( monitor->GetOptVideoWriter() != 0 ) { std::string container = monitor->OutputContainer(); if ( container == "auto" || container == "" ) { - if ( monitor->OutputCodec() == "h264" ) { + if ( monitor->OutputCodec() == AV_CODEC_ID_H264 ) { container = "mp4"; } else { container = "mkv"; } } - snprintf( video_name, sizeof(video_name), "%d-%s.%s", id, "video", container.c_str() ); - snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name ); - Debug(1,"Writing video file to %s", video_file ); + snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s.%s", id, "video", container.c_str()); + snprintf(video_file, sizeof(video_file), staticConfig.video_file_format, path.c_str(), video_name); + Debug(1,"Writing video file to %s", video_file); Camera * camera = monitor->getCamera(); videoStore = new VideoStore( video_file, @@ -211,28 +220,15 @@ Event::Event( if ( ! videoStore->open() ) { delete videoStore; videoStore = NULL; - } + save_jpegs |= 1; // Turn on jpeg storage + } } } // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent ) Event::~Event() { - static char sql[ZM_SQL_MED_BUFSIZ]; - struct DeltaTimeval delta_time; - DELTA_TIMEVAL(delta_time, end_time, start_time, DT_PREC_2); - Debug(2, "start_time:%d.%d end_time%d.%d", start_time.tv_sec, start_time.tv_usec, end_time.tv_sec, end_time.tv_usec ); - if ( frames > last_db_frame ) { - Debug( 1, "Adding closing frame %d to DB", frames ); - snprintf( sql, sizeof(sql), - "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", - id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); - db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't insert frame: %s", mysql_error( &dbconn ) ); - } - db_mutex.unlock(); - } + // We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet. /* Close the video file */ if ( videoStore ) { @@ -240,15 +236,41 @@ Event::~Event() { videoStore = NULL; } - snprintf( sql, sizeof(sql), "UPDATE Events SET Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); + // Should not be static because we are multi-threaded + char sql[ZM_SQL_MED_BUFSIZ]; + struct DeltaTimeval delta_time; + DELTA_TIMEVAL(delta_time, end_time, start_time, DT_PREC_2); + Debug(2, "start_time:%d.%d end_time%d.%d", start_time.tv_sec, start_time.tv_usec, end_time.tv_sec, end_time.tv_usec); + + if ( frames > last_db_frame ) { + Debug(1, "Adding closing frame %d to DB", frames); + snprintf(sql, sizeof(sql), + "INSERT INTO Frames ( EventId, FrameId, TimeStamp, Delta ) VALUES ( %" PRIu64 ", %d, from_unixtime( %ld ), %s%ld.%02ld )", + id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec); + db_mutex.lock(); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't insert frame: %s", mysql_error(&dbconn)); + } else { + Debug(1,"Success writing last frame"); + } + db_mutex.unlock(); + } + + snprintf(sql, sizeof(sql), + "UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64, + monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't update event: %s", mysql_error( &dbconn ) ); + while ( mysql_query(&dbconn, sql) && !zm_terminate ) { + Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); + db_mutex.unlock(); + sleep(1); + db_mutex.lock(); } db_mutex.unlock(); -} // ~Event -void Event::createNotes( std::string ¬es ) { +} // Event::~Event() + +void Event::createNotes(std::string ¬es) { notes.clear(); for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); ++mapIter ) { notes += mapIter->first; @@ -262,9 +284,7 @@ void Event::createNotes( std::string ¬es ) { } } -int Event::sd = -1; - -bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame ) { +bool Event::WriteFrameImage(Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame) { int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default bool rc; @@ -273,11 +293,11 @@ Debug(3, "Writing image to %s", event_file ); if ( !config.timestamp_on_capture ) { // stash the image we plan to use in another pointer regardless if timestamped. Image *ts_image = new Image(*image); - monitor->TimestampImage( ts_image, ×tamp ); - rc = ts_image->WriteJpeg( event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0}) ); // exif is only timestamp at present this switches on or off for write + monitor->TimestampImage(ts_image, ×tamp); + rc = ts_image->WriteJpeg(event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0})); // exif is only timestamp at present this switches on or off for write delete(ts_image); } else { - rc = image->WriteJpeg( event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0}) ); // exif is only timestamp at present this switches on or off for write + rc = image->WriteJpeg(event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0})); // exif is only timestamp at present this switches on or off for write } return rc; @@ -380,31 +400,31 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) { #else static char escapedNotes[ZM_SQL_MED_BUFSIZ]; - mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() ); + mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length()); + snprintf(sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %" PRIu64, escapedNotes, id); db_mutex.lock(); - snprintf( sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %d", escapedNotes, id ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't insert event: %s", mysql_error( &dbconn ) ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't insert event: %s", mysql_error(&dbconn)); } db_mutex.unlock(); #endif - } + } // end if update } -void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps ) { +void Event::AddFrames(int n_frames, Image **images, struct timeval **timestamps) { for (int i = 0; i < n_frames; i += ZM_SQL_BATCH_SIZE) { AddFramesInternal(n_frames, i, images, timestamps); } } -void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ) { +void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, struct timeval **timestamps) { static char sql[ZM_SQL_LGE_BUFSIZ]; - strncpy( sql, "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ", sizeof(sql) ); + strncpy(sql, "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ", sizeof(sql)); int frameCount = 0; for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) { if ( timestamps[i]->tv_sec <= 0 ) { - Debug( 1, "Not adding pre-capture frame %d, zero or less than 0 timestamp", i ); + Debug(1, "Not adding pre-capture frame %d, zero or less than 0 timestamp", i); continue; } else if ( timestamps[i]->tv_sec < 0 ) { Warning( "Not adding pre-capture frame %d, negative timestamp", i ); @@ -416,10 +436,10 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st frames++; static char event_file[PATH_MAX]; - snprintf( event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames ); - if ( monitor->GetOptSaveJPEGs() & 1 ) { - Debug( 1, "Writing pre-capture frame %d", frames ); - WriteFrameImage( images[i], *(timestamps[i]), event_file ); + snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); + if ( save_jpegs & 1 ) { + Debug(1, "Writing pre-capture frame %d", frames); + WriteFrameImage(images[i], *(timestamps[i]), event_file); } else { //If this is the first frame, we should add a thumbnail to the event directory // ICON: We are working through the pre-event frames so this snapshot won't @@ -427,7 +447,7 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st // so I am changing this to 1, but we should overwrite it later with a better snapshot. if ( frames == 1 ) { std::string snapshot_file = std::string(path) + "/snapshot.jpg"; - WriteFrameImage( images[i], *(timestamps[i]), snapshot_file.c_str() ); + WriteFrameImage(images[i], *(timestamps[i]), snapshot_file.c_str()); } } @@ -441,22 +461,22 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st } int sql_len = strlen(sql); - snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %d, %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); + snprintf(sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec); frameCount++; - } + } // end foreach frame if ( frameCount ) { - Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames ); + Debug(1, "Adding %d/%d frames to DB", frameCount, n_frames); *(sql+strlen(sql)-2) = '\0'; db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't insert frames: %s, sql was (%s)", mysql_error( &dbconn ), sql ); + Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), sql); } db_mutex.unlock(); last_db_frame = frames; } else { - Debug( 1, "No valid pre-capture frames to add" ); + Debug(1, "No valid pre-capture frames to add"); } } @@ -465,8 +485,7 @@ void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { have_video_keyframe = have_video_keyframe || ( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) && packet->keyframe ); if ( videoStore ) { if ( have_video_keyframe ) { - Debug(2,"Have video keyframe, writing packet to videostore"); - videoStore->writePacket( packet ); + videoStore->writePacket(packet); } else { Debug(2, "No video keyframe yet, not writing"); } @@ -475,37 +494,39 @@ void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { Debug(2,"AddPacket but no videostore?!"); } if ( have_video_keyframe && ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) ) { - AddFrame( packet->image, *packet->timestamp, score, alarm_image ); + AddFrame(packet->image, *packet->timestamp, score, alarm_image); } // end if is video return; } -void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *alarm_image ) { +void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) { if ( !timestamp.tv_sec ) { - Debug( 1, "Not adding new frame, zero timestamp" ); + Debug(1, "Not adding new frame, zero timestamp"); return; } frames++; static char event_file[PATH_MAX]; - snprintf( event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames ); + snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); - if ( monitor->GetOptSaveJPEGs() & 1 ) { - Debug( 1, "Writing capture frame %d to %s", frames, event_file ); - if ( ! WriteFrameImage( image, timestamp, event_file ) ) { + if ( save_jpegs & 1 ) { + Debug(1, "Writing capture frame %d to %s", frames, event_file); + if ( ! WriteFrameImage(image, timestamp, event_file) ) { Error("Failed to write frame image"); } } else { //If this is the first frame, we should add a thumbnail to the event directory - if ( frames == 10 || frames == 1 ) { + // On the first frame, max_score will be zero, this effectively makes us write out a thumbnail + // for the first frame as well. + if ( score > max_score ) { std::string snapshot_file = std::string(path) + "/snapshot.jpg"; WriteFrameImage( image, timestamp, snapshot_file.c_str() ); } } struct DeltaTimeval delta_time; - DELTA_TIMEVAL( delta_time, timestamp, start_time, DT_PREC_2 ); + DELTA_TIMEVAL(delta_time, timestamp, start_time, DT_PREC_2); FrameType frame_type = score>0?ALARM:(score<0?BULK:NORMAL); // < 0 means no motion detection is being done. @@ -515,28 +536,26 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * bool db_frame = ( frame_type != BULK ) || ((frames%config.bulk_frame_interval)==0) || !frames; if ( db_frame ) { - Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type] ); + Debug(1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type]); static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) VALUES ( %d, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score ); + snprintf(sql, sizeof(sql), + "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score )" + " VALUES ( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", + id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score); db_mutex.lock(); if ( mysql_query(&dbconn, sql) ) { - Error("Can't insert frame: (%s) reason:%s", sql, mysql_error(&dbconn)); - zmDbClose(); - if ( ! zmDbConnect() ) { - Error("Unable to connect to db"); - exit(mysql_errno(&dbconn)); - } - if ( mysql_query(&dbconn, sql) ) { - Error("REALLY Can't insert frame: (%s) reason:%s", sql, mysql_error(&dbconn)); - exit(mysql_errno(&dbconn)); - } + Error("Can't insert frame: %s", mysql_error(&dbconn)); + Error("SQL was %s", sql); + db_mutex.unlock(); + return; } db_mutex.unlock(); last_db_frame = frames; // We are writing a Bulk frame if ( frame_type == BULK ) { - snprintf( sql, sizeof(sql), "update Events set Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", + snprintf(sql, sizeof(sql), + "UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %" PRIu64, ( delta_time.positive?"":"-" ), delta_time.sec, delta_time.fsec, frames, @@ -547,8 +566,11 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * id ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't update event: %s", mysql_error( &dbconn ) ); + while ( mysql_query(&dbconn, sql) && !zm_terminate ) { + Error("Can't update event: %s", mysql_error(&dbconn)); + db_mutex.unlock(); + sleep(1); + db_mutex.lock(); } db_mutex.unlock(); } @@ -565,10 +587,10 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * max_score = score; if ( alarm_image ) { - snprintf( event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames ); + snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames); - Debug( 1, "Writing analysis frame %d", frames ); - if ( monitor->GetOptSaveJPEGs() & 2 ) { + Debug(1, "Writing analysis frame %d", frames); + if ( save_jpegs & 2 ) { WriteFrameImage(alarm_image, timestamp, event_file, true); } } diff --git a/src/zm_event.h b/src/zm_event.h index b513eae99..c354d58e3 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -75,7 +75,7 @@ class Event { static int pre_alarm_count; static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES]; - unsigned int id; + uint64_t id; Monitor *monitor; struct timeval start_time; struct timeval end_time; @@ -85,15 +85,16 @@ class Event { int alarm_frames; unsigned int tot_score; unsigned int max_score; - char path[PATH_MAX]; + std::string path; VideoStore *videoStore; char video_name[64]; char video_file[PATH_MAX]; int last_db_frame; bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe. + Storage::Schemes scheme; + int save_jpegs; void createNotes( std::string ¬es ); - Storage::Schemes scheme; public: static bool OpenFrameSocket( int ); @@ -102,15 +103,15 @@ class Event { Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap ); ~Event(); - int Id() const { return( id ); } - const std::string &Cause() { return( cause ); } - int Frames() const { return( frames ); } - int AlarmFrames() const { return( alarm_frames ); } + uint64_t Id() const { return id; } + const std::string &Cause() { return cause; } + int Frames() const { return frames; } + int AlarmFrames() const { return alarm_frames; } - const struct timeval &StartTime() const { return( start_time ); } - const struct timeval &EndTime() const { return( end_time ); } - struct timeval &StartTime() { return( start_time ); } - struct timeval &EndTime() { return( end_time ); } + const struct timeval &StartTime() const { return start_time; } + const struct timeval &EndTime() const { return end_time; } + struct timeval &StartTime() { return start_time; } + struct timeval &EndTime() { return end_time; } bool SendFrameImage( const Image *image, bool alarm_frame=false ); bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false ); @@ -132,7 +133,7 @@ class Event { return( subpath ); } static const char *getSubPath( time_t *time ) { - return( Event::getSubPath( localtime( time ) ) ); + return Event::getSubPath( localtime( time ) ); } char* getEventFile(void) { @@ -141,7 +142,7 @@ class Event { public: static int PreAlarmCount() { - return( pre_alarm_count ); + return pre_alarm_count; } static void EmptyPreAlarmFrames() { if ( pre_alarm_count > 0 ) { diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index c475493fc..b8eabbd0f 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "zm.h" #include "zm_db.h" @@ -43,30 +44,30 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) { static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %d and unix_timestamp( EndTime ) > %ld order by Id asc limit 1", monitor_id, event_time ); + snprintf(sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %d AND unix_timestamp(EndTime) > %ld ORDER BY Id ASC LIMIT 1", monitor_id, event_time); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + 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 ); + MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); exit( mysql_errno( &dbconn ) ); } - MYSQL_ROW dbrow = mysql_fetch_row( result ); + MYSQL_ROW dbrow = mysql_fetch_row(result); - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + if ( mysql_errno(&dbconn) ) { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + exit( mysql_errno(&dbconn)); } - int init_event_id = atoi( dbrow[0] ); + uint64_t init_event_id = atoll(dbrow[0]); - mysql_free_result( result ); + mysql_free_result(result); - loadEventData( init_event_id ); + loadEventData(init_event_id); if ( event_time ) { curr_stream_time = event_time; @@ -84,47 +85,52 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) { Debug( 3, "Skipping %ld frames", event_data->frame_count ); } } - return( true ); + return true; } -bool EventStream::loadInitialEventData( int init_event_id, unsigned int init_frame_id ) { - loadEventData( init_event_id ); +bool EventStream::loadInitialEventData( uint64_t init_event_id, unsigned int init_frame_id ) { + loadEventData(init_event_id); if ( init_frame_id ) { - curr_stream_time = event_data->frames[init_frame_id-1].timestamp; - curr_frame_id = init_frame_id; + if ( init_frame_id >= event_data->frame_count ) { + Error("Invalid frame id specified. %d > %d", init_frame_id, event_data->frame_count ); + curr_stream_time = event_data->start_time; + } else { + curr_stream_time = event_data->frames[init_frame_id-1].timestamp; + curr_frame_id = init_frame_id; + } } else { curr_stream_time = event_data->start_time; } - return( true ); + return true; } -bool EventStream::loadEventData( int event_id ) { +bool EventStream::loadEventData(uint64_t event_id) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %d", event_id ); + snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %" PRIu64, event_id); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + 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 ); + MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } - if ( !mysql_num_rows( result ) ) { - Fatal( "Unable to load event %d, not found in DB", event_id ); + if ( !mysql_num_rows(result) ) { + Fatal("Unable to load event %d, not found in DB", event_id); } - MYSQL_ROW dbrow = mysql_fetch_row( result ); + MYSQL_ROW dbrow = mysql_fetch_row(result); - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + if ( mysql_errno(&dbconn) ) { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } delete event_data; @@ -147,50 +153,53 @@ bool EventStream::loadEventData( int event_id ) { } mysql_free_result( result ); - Storage * storage = new Storage( event_data->storage_id ); + Storage * storage = new Storage(event_data->storage_id); const char *storage_path = storage->Path(); if ( event_data->scheme == Storage::DEEP ) { - struct tm *event_time = localtime( &event_data->start_time ); + struct tm *event_time = localtime(&event_data->start_time); if ( storage_path[0] == '/' ) - snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); + snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", + storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); else - snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); + snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", + staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); } else if ( event_data->scheme == Storage::MEDIUM ) { struct tm *event_time = localtime( &event_data->start_time ); if ( storage_path[0] == '/' ) - snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%ld", + snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%" PRIu64, storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id ); else - snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%ld", + snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%" PRIu64, staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id ); } else { if ( storage_path[0] == '/' ) - snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", storage_path, event_data->monitor_id, event_data->event_id ); + snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%" PRIu64, + storage_path, event_data->monitor_id, event_data->event_id ); else - snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id ); + snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%" PRIu64, + staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id ); } delete storage; storage = NULL; updateFrameRate( (double)event_data->frame_count/event_data->duration ); - - snprintf( sql, sizeof(sql), "select FrameId, unix_timestamp( `TimeStamp` ), Delta from Frames where EventId = %d order by FrameId asc", event_id ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + snprintf(sql, sizeof(sql), "SELECT FrameId, unix_timestamp( `TimeStamp` ), Delta FROM Frames where EventId = %" PRIu64 " ORDER BY FrameId ASC", event_id); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } - result = mysql_store_result( &dbconn ); + result = mysql_store_result(&dbconn); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } - event_data->n_frames = mysql_num_rows( result ); + event_data->n_frames = mysql_num_rows(result); event_data->frames = new FrameData[event_data->frame_count]; int last_id = 0; @@ -223,7 +232,7 @@ bool EventStream::loadEventData( int event_id ) { exit( mysql_errno( &dbconn ) ); } - mysql_free_result( result ); + mysql_free_result(result); //for ( int i = 0; i < 250; i++ ) //{ //Info( "%d -> %d @ %f (%d)", i+1, event_data->frames[i].timestamp, event_data->frames[i].delta, event_data->frames[i].in_db ); @@ -231,33 +240,31 @@ bool EventStream::loadEventData( int event_id ) { if ( event_data->video_file[0] ) { char filepath[PATH_MAX]; - snprintf( filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file ); + snprintf(filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file); ffmpeg_input = new FFmpeg_Input(); if ( 0 > ffmpeg_input->Open( filepath ) ) { - Warning("Unable to open ffmpeg_input %s/%s", event_data->path, event_data->video_file ); + Warning("Unable to open ffmpeg_input %s/%s", event_data->path, event_data->video_file); delete ffmpeg_input; ffmpeg_input = NULL; } } - if ( forceEventChange || mode == MODE_ALL_GAPLESS ) { if ( replay_rate > 0 ) curr_stream_time = event_data->frames[0].timestamp; else curr_stream_time = event_data->frames[event_data->frame_count-1].timestamp; } - Debug( 2, "Event:%ld, Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration ); + Debug(2, "Event:%" PRIu64 ", Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration); - return( true ); + return true; } // bool EventStream::loadEventData( int event_id ) -void EventStream::processCommand( const CmdMsg *msg ) { - Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ); +void EventStream::processCommand(const CmdMsg *msg) { + Debug(2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0]); // Check for incoming command switch( (MsgCommand)msg->msg_data[0] ) { case CMD_PAUSE : - { Debug( 1, "Got PAUSE command" ); // Set paused flag @@ -265,12 +272,9 @@ void EventStream::processCommand( const CmdMsg *msg ) { replay_rate = ZM_RATE_BASE; last_frame_sent = TV_2_FLOAT( now ); break; - } case CMD_PLAY : - { Debug( 1, "Got PLAY command" ); if ( paused ) { - // Clear paused flag paused = false; } @@ -284,30 +288,20 @@ void EventStream::processCommand( const CmdMsg *msg ) { replay_rate = ZM_RATE_BASE; break; - } case CMD_VARPLAY : - { Debug( 1, "Got VARPLAY command" ); if ( paused ) { - // Clear paused flag paused = false; } replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768; break; - } case CMD_STOP : - { Debug( 1, "Got STOP command" ); - - // Clear paused flag paused = false; break; - } case CMD_FASTFWD : - { Debug( 1, "Got FAST FWD command" ); if ( paused ) { - // Clear paused flag paused = false; } // Set play rate @@ -330,36 +324,21 @@ void EventStream::processCommand( const CmdMsg *msg ) { break; } break; - } case CMD_SLOWFWD : - { Debug( 1, "Got SLOW FWD command" ); - // Set paused flag paused = true; - // Set play rate replay_rate = ZM_RATE_BASE; - // Set step step = 1; break; - } case CMD_SLOWREV : - { Debug( 1, "Got SLOW REV command" ); - // Set paused flag paused = true; - // Set play rate replay_rate = ZM_RATE_BASE; - // Set step step = -1; break; - } case CMD_FASTREV : - { Debug( 1, "Got FAST REV command" ); - if ( paused ) { - // Clear paused flag - paused = false; - } + paused = false; // Set play rate switch ( replay_rate ) { case -2 * ZM_RATE_BASE : @@ -380,9 +359,7 @@ void EventStream::processCommand( const CmdMsg *msg ) { break; } break; - } case CMD_ZOOMIN : - { x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; Debug( 1, "Got ZOOM IN command, to %d,%d", x, y ); @@ -406,10 +383,7 @@ void EventStream::processCommand( const CmdMsg *msg ) { } send_frame = true; break; - - } case CMD_ZOOMOUT : - { Debug( 1, "Got ZOOM OUT command" ); switch ( zoom ) { case 500: @@ -431,22 +405,16 @@ void EventStream::processCommand( const CmdMsg *msg ) { } send_frame = true; break; - } case CMD_PAN : - { x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; Debug( 1, "Got PAN command, to %d,%d", x, y ); break; - } case CMD_SCALE : - { scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; Debug( 1, "Got SCALE command, to %d", scale ); break; - } case CMD_PREV : - { Debug( 1, "Got PREV command" ); if ( replay_rate >= 0 ) curr_frame_id = 0; @@ -455,9 +423,7 @@ void EventStream::processCommand( const CmdMsg *msg ) { paused = false; forceEventChange = true; break; - } case CMD_NEXT : - { Debug( 1, "Got NEXT command" ); if ( replay_rate >= 0 ) curr_frame_id = event_data->frame_count+1; @@ -466,7 +432,6 @@ void EventStream::processCommand( const CmdMsg *msg ) { paused = false; forceEventChange = true; break; - } case CMD_SEEK : { int offset = ((unsigned char)msg->msg_data[1]<<24)|((unsigned char)msg->msg_data[2]<<16)|((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; @@ -476,35 +441,30 @@ void EventStream::processCommand( const CmdMsg *msg ) { break; } case CMD_QUERY : - { Debug( 1, "Got QUERY command, sending STATUS" ); break; - } case CMD_QUIT : - { - Info ("User initiated exit - CMD_QUIT"); + Info("User initiated exit - CMD_QUIT"); break; - } default : - { // Do nothing, for now - } + break; } struct { - int event; + uint64_t event_id; int progress; int rate; int zoom; bool paused; } status_data; - status_data.event = event_data->event_id; + status_data.event_id = event_data->event_id; status_data.progress = (int)event_data->frames[curr_frame_id-1].offset; status_data.rate = replay_rate; status_data.zoom = zoom; status_data.paused = paused; - Debug( 2, "Event:%d, Paused:%d, progress:%d Rate:%d, Zoom:%d", - status_data.event, + Debug( 2, "Event:%" PRIu64 ", Paused:%d, progress:%d Rate:%d, Zoom:%d", + status_data.event_id, status_data.paused, status_data.progress, status_data.rate, @@ -513,19 +473,19 @@ void EventStream::processCommand( const CmdMsg *msg ) { DataMsg status_msg; status_msg.msg_type = MSG_DATA_EVENT; - memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) ); - if ( sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) ) < 0 ) { + memcpy(&status_msg.msg_data, &status_data, sizeof(status_data)); + if ( sendto(sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr)) < 0 ) { //if ( errno != EAGAIN ) { - Error( "Can't sendto on sd %d: %s", sd, strerror(errno) ); - exit( -1 ); + Error("Can't sendto on sd %d: %s", sd, strerror(errno)); + exit(-1); } } // quit after sending a status, if this was a quit request - if ((MsgCommand)msg->msg_data[0]==CMD_QUIT) + if ( (MsgCommand)msg->msg_data[0]==CMD_QUIT ) exit(0); - updateFrameRate( (double)event_data->frame_count/event_data->duration ); + updateFrameRate((double)event_data->frame_count/event_data->duration); } void EventStream::checkEventLoaded() { @@ -533,10 +493,10 @@ void EventStream::checkEventLoaded() { static char sql[ZM_SQL_SML_BUFSIZ]; if ( curr_frame_id <= 0 ) { - snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id < %ld order by Id desc limit 1", event_data->monitor_id, event_data->event_id ); + snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id < %" PRIu64 " ORDER BY Id DESC LIMIT 1", event_data->monitor_id, event_data->event_id ); reload_event = true; } else if ( (unsigned int)curr_frame_id > event_data->frame_count ) { - snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id > %ld order by Id asc limit 1", event_data->monitor_id, event_data->event_id ); + snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id > %" PRIu64 " ORDER BY Id ASC LIMIT 1", event_data->monitor_id, event_data->event_id ); reload_event = true; } @@ -561,10 +521,10 @@ void EventStream::checkEventLoaded() { } if ( dbrow ) { - int event_id = atoi(dbrow[0]); - Debug( 1, "Loading new event %d", event_id ); + uint64_t event_id = atoll(dbrow[0]); + Debug( 1, "Loading new event %" PRIu64, event_id ); - loadEventData( event_id ); + loadEventData(event_id); Debug( 2, "Current frame id = %d", curr_frame_id ); if ( replay_rate < 0 ) @@ -594,14 +554,15 @@ void EventStream::checkEventLoaded() { Image * EventStream::getImage( ) { static char filepath[PATH_MAX]; - Debug( 2, "EventStream::getImage path(%s) frame(%d)", event_data->path, curr_frame_id ); - snprintf( filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id ); - Image *image = new Image( filepath ); + Debug(2, "EventStream::getImage path(%s) frame(%d)", event_data->path, curr_frame_id); + snprintf( filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id); + Debug(2, "EventStream::getImage path(%s) ", filepath, curr_frame_id); + Image *image = new Image(filepath); return image; } -bool EventStream::sendFrame( int delta_us ) { - Debug( 2, "Sending frame %d", curr_frame_id ); +bool EventStream::sendFrame(int delta_us) { + Debug(2, "Sending frame %d", curr_frame_id); static char filepath[PATH_MAX]; static struct stat filestat; @@ -626,13 +587,14 @@ bool EventStream::sendFrame( int delta_us ) { #if HAVE_LIBAVCODEC if ( type == STREAM_MPEG ) { +Debug(2,"Streaming MPEG"); Image image( filepath ); - Image *send_image = prepareImage( &image ); + Image *send_image = prepareImage(&image); if ( !vid_stream ) { - vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height() ); - fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() ); + vid_stream = new VideoStream("pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height()); + fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType()); vid_stream->OpenStream(); } /* double pts = */ vid_stream->EncodeFrame( send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_us*1000 ); @@ -648,34 +610,35 @@ bool EventStream::sendFrame( int delta_us ) { fprintf( stdout, "--ZoneMinderFrame\r\n" ); - if ( type != STREAM_JPEG ) + if ( (type != STREAM_JPEG) || (!filepath[0]) ) send_raw = false; if ( send_raw ) { - fdj = fopen( filepath, "rb" ); + fdj = fopen(filepath, "rb"); if ( !fdj ) { - Error( "Can't open %s: %s", filepath, strerror(errno) ); - return( false ); + Error("Can't open %s: %s", filepath, strerror(errno)); + return false; } #if HAVE_SENDFILE if( fstat(fileno(fdj),&filestat) < 0 ) { Error( "Failed getting information about file %s: %s", filepath, strerror(errno) ); - return( false ); + return false; } #else - img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); + img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj); #endif } else { Image *image = NULL; if ( filepath[0] ) { - image = new Image( filepath ); +Debug(1, "Loading image"); + image = new Image(filepath); } else if ( ffmpeg_input ) { // Get the frame from the mp4 input Debug(1,"Getting frame from ffmpeg"); AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id(), curr_frame_id ); if ( frame ) { - image = new Image( frame ); + image = new Image(frame); av_frame_free(&frame); } else { Error("Failed getting a frame."); @@ -686,16 +649,16 @@ bool EventStream::sendFrame( int delta_us ) { return false; } - Image *send_image = prepareImage( image ); + Image *send_image = prepareImage(image); switch( type ) { case STREAM_JPEG : - send_image->EncodeJpeg( img_buffer, &img_buffer_size ); + send_image->EncodeJpeg(img_buffer, &img_buffer_size); break; case STREAM_ZIP : #if HAVE_ZLIB_H unsigned long zip_buffer_size; - send_image->Zip( img_buffer, &zip_buffer_size ); + send_image->Zip(img_buffer, &zip_buffer_size); img_buffer_size = zip_buffer_size; break; #else @@ -716,16 +679,16 @@ bool EventStream::sendFrame( int delta_us ) { switch( type ) { case STREAM_JPEG : - fprintf( stdout, "Content-Type: image/jpeg\r\n" ); + fputs( "Content-Type: image/jpeg\r\n", stdout ); break; case STREAM_RAW : - fprintf( stdout, "Content-Type: image/x-rgb\r\n" ); + fputs( "Content-Type: image/x-rgb\r\n", stdout ); break; case STREAM_ZIP : - fprintf( stdout, "Content-Type: image/x-rgbz\r\n" ); + fputs( "Content-Type: image/x-rgbz\r\n", stdout ); break; default : - Fatal( "Unexpected frame type %d", type ); + Fatal("Unexpected frame type %d", type); break; } @@ -759,11 +722,11 @@ bool EventStream::sendFrame( int delta_us ) { } } - fprintf( stdout, "\r\n\r\n" ); - fflush( stdout ); + fputs("\r\n\r\n", stdout); + fflush(stdout); } - last_frame_sent = TV_2_FLOAT( now ); - return( true ); + last_frame_sent = TV_2_FLOAT(now); + return true; } void EventStream::runStream() { @@ -772,20 +735,19 @@ void EventStream::runStream() { checkInitialised(); - if ( type == STREAM_JPEG ) - fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); + fputs("Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n", stdout); if ( !event_data ) { - sendTextFrame( "No event data found" ); - exit( 0 ); + sendTextFrame("No event data found"); + exit(0); } - Debug(3, "frame rate is: (%f)", (double)event_data->frame_count/event_data->duration ); - updateFrameRate( (double)event_data->frame_count/event_data->duration ); + Debug(3, "frame rate is: (%f)", (double)event_data->frame_count/event_data->duration); + updateFrameRate((double)event_data->frame_count/event_data->duration); while( !zm_terminate ) { - gettimeofday( &now, NULL ); + gettimeofday(&now, NULL); unsigned int delta_us = 0; send_frame = false; @@ -818,11 +780,11 @@ void EventStream::runStream() { in_event = false; } if ( !in_event ) { - double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; + double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent; if ( actual_delta_time > 1 ) { static char frame_text[64]; - snprintf( frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event ); - if ( !sendTextFrame( frame_text ) ) + snprintf(frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event); + if ( !sendTextFrame(frame_text) ) zm_terminate = true; } //else @@ -851,16 +813,16 @@ void EventStream::runStream() { send_frame = true; } else if ( !send_frame ) { // We are paused, and doing nothing - double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; + double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent; if ( actual_delta_time > MAX_STREAM_DELAY ) { // Send keepalive - Debug( 2, "Sending keepalive frame" ); + Debug(2, "Sending keepalive frame"); send_frame = true; } } if ( send_frame ) - if ( !sendFrame( delta_us ) ) + if ( !sendFrame(delta_us) ) zm_terminate = true; curr_stream_time = frame_data->timestamp; @@ -885,3 +847,17 @@ void EventStream::runStream() { closeComms(); } +void EventStream::setStreamStart( uint64_t init_event_id, unsigned int init_frame_id=0 ) { + loadInitialEventData( init_event_id, init_frame_id ); + if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) { + Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id ); + return; + } +} +void EventStream::setStreamStart( int monitor_id, time_t event_time ) { + loadInitialEventData(monitor_id, event_time); + if ( !(monitor = Monitor::Load(event_data->monitor_id, false, Monitor::QUERY)) ) { + Fatal("Unable to load monitor id %d for streaming", monitor_id); + return; + } +} diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index 02e90f70a..067661937 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -54,7 +54,7 @@ class EventStream : public StreamBase { }; struct EventData { - unsigned long event_id; + uint64_t event_id; unsigned long monitor_id; unsigned long storage_id; unsigned long frame_count; @@ -83,8 +83,8 @@ class EventStream : public StreamBase { FFmpeg_Input *ffmpeg_input; protected: - bool loadEventData( int event_id ); - bool loadInitialEventData( int init_event_id, unsigned int init_frame_id ); + bool loadEventData( uint64_t event_id ); + bool loadInitialEventData( uint64_t init_event_id, unsigned int init_frame_id ); bool loadInitialEventData( int monitor_id, time_t event_time ); void checkEventLoaded(); @@ -110,20 +110,8 @@ class EventStream : public StreamBase { ffmpeg_input = NULL; } - void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) { - loadInitialEventData( init_event_id, init_frame_id ); - if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) { - Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id ); - return; - } - } - void setStreamStart( int monitor_id, time_t event_time ) { - loadInitialEventData( monitor_id, event_time ); - if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) { - Fatal( "Unable to load monitor id %d for streaming", monitor_id ); - return; - } - } + void setStreamStart( uint64_t init_event_id, unsigned int init_frame_id ); + void setStreamStart( int monitor_id, time_t event_time ); void setStreamMode( StreamMode p_mode ) { mode = p_mode; } diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 77e3c90aa..228062f4a 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -16,6 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "zm_ffmpeg.h" #include "zm_image.h" @@ -27,9 +28,9 @@ void FFMPEGInit() { static bool bInit = false; if ( !bInit ) { - if ( logDebugging() ) - av_log_set_level( AV_LOG_DEBUG ); - else + //if ( logDebugging() ) + //av_log_set_level( AV_LOG_DEBUG ); + //else av_log_set_level( AV_LOG_QUIET ); av_register_all(); avformat_network_init(); @@ -243,7 +244,7 @@ void zm_dump_codecpar ( const AVCodecParameters *par ) { } #endif -void zm_dump_codec ( const AVCodecContext *codec ) { +void zm_dump_codec(const AVCodecContext *codec) { Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d) format(%s)", codec->codec_type, codec->codec_id, @@ -425,7 +426,7 @@ int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet #endif # else - int frameComplete; + int frameComplete = 0; while ( !frameComplete ) { if ( (ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet )) < 0 ) { Error( "Unable to decode frame at frame: %s, continuing", @@ -436,22 +437,22 @@ int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet #endif return 1; } // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) + void dumpPacket(AVPacket *pkt, const char *text) { char b[10240]; snprintf(b, sizeof(b), - " pts: %" PRId64 ", dts: %" PRId64 - ", data: %p, size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64 + " pts: %" PRIu64 ", dts: %" PRIu64 + ", size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64 ", duration: %" #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - PRId64 + PRIu64 #else "d" #endif "\n", pkt->pts, pkt->dts, - pkt->data, pkt->size, pkt->stream_index, pkt->flags, @@ -460,3 +461,14 @@ void dumpPacket(AVPacket *pkt, const char *text) { pkt->duration); Debug(2, "%s:%d:%s: %s", __FILE__, __LINE__, text, b); } + +void zm_free_codec( AVCodecContext **ctx ) { + if ( *ctx ) { + avcodec_close(*ctx); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // We allocate and copy in newer ffmpeg, so need to free it + avcodec_free_context(ctx); +#endif + *ctx = NULL; + } // end if +} diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 7e3cf9651..ab214204d 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -300,11 +300,11 @@ void zm_dump_codecpar ( const AVCodecParameters *par ); #endif #if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) - #define zm_av_packet_unref( packet ) av_packet_unref( packet ) - #define zm_av_packet_ref( dst, src ) av_packet_ref( dst, src ) + #define zm_av_packet_unref(packet) av_packet_unref(packet) + #define zm_av_packet_ref(dst, src) av_packet_ref(dst, src) #else - #define zm_av_packet_unref( packet ) av_free_packet( packet ) -unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src ); + #define zm_av_packet_unref(packet) av_free_packet(packet) +unsigned int zm_av_packet_ref(AVPacket *dst, AVPacket *src); #endif #if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) #define zm_avcodec_decode_video( context, rawFrame, frameComplete, packet ) avcodec_decode_video2( context, rawFrame, frameComplete, packet ) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 6f4ba9f94..d5a07807a 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -1,23 +1,24 @@ // // ZoneMinder Ffmpeg Camera Class Implementation, $Date: 2009-01-16 12:18:50 +0000 (Fri, 16 Jan 2009) $, $Revision: 2713 $ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// #include "zm.h" +#include "zm_signal.h" #if HAVE_LIBAVFORMAT @@ -113,19 +114,19 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri FfmpegCamera::~FfmpegCamera() { - CloseFfmpeg(); + Close(); avformat_network_deinit(); } int FfmpegCamera::PrimeCapture() { if ( mCanCapture ) { - Info( "Priming capture from %s, CLosing", mPath.c_str() ); - CloseFfmpeg(); + Info("Priming capture from %s, Closing", mPath.c_str()); + Close(); } mVideoStreamId = -1; mAudioStreamId = -1; - Info( "Priming capture from %s", mPath.c_str() ); + Info("Priming capture from %s", mPath.c_str()); return ! OpenFfmpeg(); } @@ -134,7 +135,7 @@ int FfmpegCamera::PreCapture() { return 0; } -int FfmpegCamera::Capture( ZMPacket &zm_packet ) { +int FfmpegCamera::Capture(ZMPacket &zm_packet) { if ( ! mCanCapture ) { return -1; } @@ -143,27 +144,32 @@ int FfmpegCamera::Capture( ZMPacket &zm_packet ) { // If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread. - if ( (ret = av_read_frame( mFormatContext, &packet )) < 0 ) { + if ( (ret = av_read_frame(mFormatContext, &packet)) < 0 ) { if ( // Check if EOF. (ret == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) || // Check for Connection failure. (ret == -110) ) { - Info( "av_read_frame returned \"%s\". Reopening stream.", av_make_error_string(ret).c_str() ); - return ReopenFfmpeg(); - } - Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, av_make_error_string(ret).c_str() ); - return -1; + Info("Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, + av_make_error_string(ret).c_str() + ); + } else { + Error("Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, + av_make_error_string(ret).c_str() + ); + } + return -1; } dumpPacket(&packet, "ffmpeg_camera in"); if ( 0 && ( packet.dts < 0 ) ) { - zm_av_packet_unref( &packet ); + zm_av_packet_unref(&packet); return 0; } - zm_packet.set_packet( &packet ); - zm_av_packet_unref( &packet ); + bytes += packet.size; + zm_packet.set_packet(&packet); + zm_av_packet_unref(&packet); return 1; } // FfmpegCamera::Capture @@ -174,13 +180,12 @@ int FfmpegCamera::PostCapture() { int FfmpegCamera::OpenFfmpeg() { - Debug(2, "OpenFfmpeg called."); int ret; // Open the input, not necessarily a file #if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) - Debug ( 1, "Calling av_open_input_file" ); - if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) != 0 ) + Debug(1, "Calling av_open_input_file"); + if ( av_open_input_file(&mFormatContext, mPath.c_str(), NULL, 0, NULL) != 0 ) #else // Handle options AVDictionary *opts = NULL; @@ -200,27 +205,35 @@ int FfmpegCamera::OpenFfmpeg() { } else if ( method == "rtpRtspHttp" ) { ret = av_dict_set(&opts, "rtsp_transport", "http", 0); } else { - Warning("Unknown method (%s)", method.c_str() ); + Warning("Unknown method (%s)", method.c_str()); } if ( ret < 0 ) { Warning("Could not set rtsp_transport method '%s'\n", method.c_str()); } - Debug ( 1, "Calling avformat_alloc_context for %s", mPath.c_str() ); + Debug(1, "Calling avformat_open_input for %s", mPath.c_str()); mFormatContext = avformat_alloc_context( ); + // Speed up find_stream_info + //FIXME can speed up initial analysis but need sensible parameters... + //mFormatContext->probesize = 32; + //mFormatContext->max_analyze_duration = 32; + mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; + mFormatContext->interrupt_callback.opaque = this; - if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) != 0 ) + if ( avformat_open_input(&mFormatContext, mPath.c_str(), NULL, &opts) != 0 ) #endif { Error("Unable to open input %s due to: %s", mPath.c_str(), strerror(errno)); #if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) - av_close_input_file( mFormatContext ); + av_close_input_file(mFormatContext); #else - avformat_close_input( &mFormatContext ); + if ( mFormatContext ) { + avformat_close_input(&mFormatContext); + mFormatContext = NULL; + } #endif - mFormatContext = NULL; av_dict_free(&opts); return -1; @@ -228,7 +241,7 @@ int FfmpegCamera::OpenFfmpeg() { AVDictionaryEntry *e = NULL; while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Option %s not recognized by ffmpeg", e->key); + Warning("Option %s not recognized by ffmpeg", e->key); } av_dict_free(&opts); @@ -236,12 +249,12 @@ int FfmpegCamera::OpenFfmpeg() { Debug(1, "Opened input"); - Info( "Stream open %s, parsing streams...", mPath.c_str() ); + Info("Stream open %s, parsing streams...", mPath.c_str()); #if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0) - if ( av_find_stream_info( mFormatContext ) < 0 ) + if ( av_find_stream_info(mFormatContext) < 0 ) #else - if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 ) + if ( avformat_find_stream_info(mFormatContext, 0) < 0 ) #endif { Error("Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno)); @@ -269,7 +282,7 @@ int FfmpegCamera::OpenFfmpeg() { // if we break, then we won't find the audio stream continue; } else { - Debug(2, "Have another video stream." ); + Debug(2, "Have another video stream."); } } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -284,14 +297,14 @@ int FfmpegCamera::OpenFfmpeg() { if ( mAudioStreamId == -1 ) { mAudioStreamId = i; } else { - Debug(2, "Have another audio stream." ); + Debug(2, "Have another audio stream."); } } } // end foreach stream if ( mVideoStreamId == -1 ) - Fatal( "Unable to locate video stream in %s", mPath.c_str() ); + Fatal("Unable to locate video stream in %s", mPath.c_str()); if ( mAudioStreamId == -1 ) - Debug( 3, "Unable to locate audio stream in %s", mPath.c_str() ); + Debug(3, "Unable to locate audio stream in %s", mPath.c_str()); Debug(3, "Found video stream at index %d", mVideoStreamId); Debug(3, "Found audio stream at index %d", mAudioStreamId); @@ -318,7 +331,7 @@ int FfmpegCamera::OpenFfmpeg() { if ( ! mVideoCodec ) { // Try to open an hwaccel codec. - if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_vaapi")) == NULL ) { + if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_vaapi")) == NULL ) { Debug(1, "Failed to find decoder (h264_vaapi)" ); } else { Debug(1, "Success finding decoder (h264_vaapi)" ); @@ -326,7 +339,7 @@ int FfmpegCamera::OpenFfmpeg() { } if ( ! mVideoCodec ) { // Try to open an hwaccel codec. - if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_qsv")) == NULL ) { + if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_qsv")) == NULL ) { Debug(1, "Failed to find decoder (h264_qsv)" ); } else { Debug(1, "Success finding decoder (h264_qsv)" ); @@ -347,11 +360,11 @@ int FfmpegCamera::OpenFfmpeg() { } // end if h264 #endif if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { - if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_mmal")) == NULL ) { - Debug(1, "Failed to find decoder (h264_mmal)" ); - } else { - Debug(1, "Success finding decoder (h264_mmal)" ); - } + if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_mmal")) == NULL ) { + Debug(1, "Failed to find decoder (h264_mmal)"); + } else { + Debug(1, "Success finding decoder (h264_mmal)"); + } } if ( (!mVideoCodec) and ( (mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL ) ) { @@ -359,7 +372,7 @@ int FfmpegCamera::OpenFfmpeg() { Error("Can't find codec for video stream from %s", mPath.c_str()); return -1; } else { - Debug(1, "Video Found decoder"); + Debug(1, "Video Found decoder %s", mVideoCodec->name); zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0); // Open the codec @@ -372,15 +385,15 @@ int FfmpegCamera::OpenFfmpeg() { #endif AVDictionaryEntry *e = NULL; while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Option %s not recognized by ffmpeg", e->key); + Warning("Option %s not recognized by ffmpeg", e->key); } - Error( "Unable to open codec for video stream from %s", mPath.c_str() ); + Error("Unable to open codec for video stream from %s", mPath.c_str()); av_dict_free(&opts); return -1; } else { AVDictionaryEntry *e = NULL; if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Option %s not recognized by ffmpeg", e->key); + Warning("Option %s not recognized by ffmpeg", e->key); } av_dict_free(&opts); } @@ -393,8 +406,8 @@ int FfmpegCamera::OpenFfmpeg() { } if ( mAudioStreamId >= 0 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - mAudioCodecContext = avcodec_alloc_context3( NULL ); - avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar ); + mAudioCodecContext = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar); #else mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec; #endif @@ -405,20 +418,20 @@ int FfmpegCamera::OpenFfmpeg() { zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0); // Open the codec #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) - Debug ( 1, "Calling avcodec_open" ); + Debug(1, "Calling avcodec_open"); if ( avcodec_open(mAudioCodecContext, mAudioCodec) < 0 ) #else - Debug ( 1, "Calling avcodec_open2" ); + Debug(1, "Calling avcodec_open2"); if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 ) #endif - Fatal( "Unable to open codec for video stream from %s", mPath.c_str() ); + Fatal("Unable to open codec for video stream from %s", mPath.c_str()); } - Debug ( 1, "Opened audio codec" ); + Debug(1, "Opened audio codec"); } // end if have audio stream if ( (unsigned int)mVideoCodecContext->width != width || (unsigned int)mVideoCodecContext->height != height ) { - Warning( "Monitor dimensions are %dx%d but camera is sending %dx%d", width, height, mVideoCodecContext->width, mVideoCodecContext->height ); + Warning("Monitor dimensions are %dx%d but camera is sending %dx%d", width, height, mVideoCodecContext->width, mVideoCodecContext->height); } mCanCapture = true; @@ -426,15 +439,7 @@ int FfmpegCamera::OpenFfmpeg() { return 1; } // int FfmpegCamera::OpenFfmpeg() -int FfmpegCamera::ReopenFfmpeg() { - - Debug(2, "ReopenFfmpeg called."); - - CloseFfmpeg(); - return OpenFfmpeg(); -} - -int FfmpegCamera::CloseFfmpeg() { +int FfmpegCamera::Close() { Debug(2, "CloseFfmpeg called."); @@ -467,14 +472,20 @@ int FfmpegCamera::CloseFfmpeg() { if ( mFormatContext ) { #if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) - av_close_input_file( mFormatContext ); + av_close_input_file(mFormatContext); #else - avformat_close_input( &mFormatContext ); + avformat_close_input(&mFormatContext); #endif mFormatContext = NULL; } return 0; -} // end int FfmpegCamera::CloseFfmpeg() +} // end FfmpegCamera::Close + +int FfmpegCamera::FfmpegInterruptCallback(void *ctx) { + //FfmpegCamera* camera = reinterpret_cast(ctx); + + return zm_terminate; +} #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 828d24499..2dfd957cf 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -69,11 +69,8 @@ class FfmpegCamera : public Camera { AVPacket packet; int OpenFfmpeg(); - int ReopenFfmpeg(); - int CloseFfmpeg(); - bool mIsOpening; + int Close(); bool mCanCapture; - int mOpenStart; #endif // HAVE_LIBAVFORMAT public: @@ -97,6 +94,8 @@ class FfmpegCamera : public Camera { const std::string &Options() const { return( mOptions ); } const std::string &Method() const { return( mMethod ); } + static int FfmpegInterruptCallback(void*ctx); + int PrimeCapture(); int PreCapture(); int Capture(ZMPacket &p); @@ -114,5 +113,4 @@ class FfmpegCamera : public Camera { AVCodecContext *get_VideoCodecContext() { return mVideoCodecContext; }; AVCodecContext *get_AudioCodecContext() { return mAudioCodecContext; }; }; - #endif // ZM_FFMPEG_CAMERA_H diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 240dfff24..ad82de475 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -28,15 +28,15 @@ int FFmpeg_Input::Open( const char *filepath ) { /** Open the input file to read from it. */ if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) { - Error("Could not open input file '%s' (error '%s')\n", - filepath, av_make_error_string(error).c_str() ); + Error("Could not open input file '%s' (error '%s')", + filepath, av_make_error_string(error).c_str()); input_format_context = NULL; return error; } /** Get information on the input file (number of streams etc.). */ if ( (error = avformat_find_stream_info(input_format_context, NULL)) < 0 ) { - Error( "Could not open find stream info (error '%s')\n", + Error("Could not open find stream info (error '%s')", av_make_error_string(error).c_str() ); avformat_close_input(&input_format_context); return error; @@ -51,37 +51,37 @@ int FFmpeg_Input::Open( const char *filepath ) { video_stream_id = i; // if we break, then we won't find the audio stream } else { - Warning( "Have another video stream." ); + Warning("Have another video stream."); } - } else if ( is_audio_stream( input_format_context->streams[i] ) ) { + } else if ( is_audio_stream(input_format_context->streams[i]) ) { if ( audio_stream_id == -1 ) { audio_stream_id = i; } else { - Warning( "Have another audio stream." ); + Warning("Have another audio stream."); } } streams[i].frame_count = 0; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - streams[i].context = avcodec_alloc_context3( NULL ); - avcodec_parameters_to_context( streams[i].context, input_format_context->streams[i]->codecpar ); + streams[i].context = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(streams[i].context, input_format_context->streams[i]->codecpar); #else streams[i].context = input_format_context->streams[i]->codec; #endif if ( !(streams[i].codec = avcodec_find_decoder(streams[i].context->codec_id)) ) { - Error( "Could not find input codec\n"); + Error("Could not find input codec\n"); avformat_close_input(&input_format_context); return AVERROR_EXIT; } else { - Debug(1, "Using codec (%s) for stream %d", streams[i].codec->name, i ); + Debug(1, "Using codec (%s) for stream %d", streams[i].codec->name, i); } if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) { - Error( "Could not open input codec (error '%s')\n", - av_make_error_string(error).c_str() ); + Error("Could not open input codec (error '%s')\n", + av_make_error_string(error).c_str()); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context( &streams[i].context ); + avcodec_free_context(&streams[i].context); #endif avformat_close_input(&input_format_context); return error; @@ -89,9 +89,9 @@ int FFmpeg_Input::Open( const char *filepath ) { } // end foreach stream if ( video_stream_id == -1 ) - Error( "Unable to locate video stream in %s", filepath ); + Error("Unable to locate video stream in %s", filepath); if ( audio_stream_id == -1 ) - Debug( 3, "Unable to locate audio stream in %s", filepath ); + Debug(3, "Unable to locate audio stream in %s", filepath); return 0; } // end int FFmpeg_Input::Open( const char * filepath ) @@ -99,9 +99,9 @@ int FFmpeg_Input::Open( const char *filepath ) { int FFmpeg_Input::Close( ) { for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { if ( streams[i].context ) { - avcodec_close( streams[i].context ); + avcodec_close(streams[i].context); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context(& streams[i].context ); + avcodec_free_context(&streams[i].context); #endif streams[i].context = NULL; } @@ -109,20 +109,20 @@ int FFmpeg_Input::Close( ) { if ( input_format_context ) { #if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) - av_close_input_file( input_format_context ); + av_close_input_file(input_format_context); #else - avformat_close_input( &input_format_context ); + avformat_close_input(&input_format_context); #endif input_format_context = NULL; } return 1; } // end int FFmpeg_Input::Close() -AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) { - Debug(1, "Getting frame from stream %d, frame_number(%d)", stream_id, frame_number ); +AVFrame *FFmpeg_Input::get_frame(int stream_id, int frame_number) { + Debug(1, "Getting frame from stream %d, frame_number(%d)", stream_id, frame_number); AVPacket packet; - av_init_packet( &packet ); + av_init_packet(&packet); AVFrame *frame = zm_av_frame_alloc(); while ( frame_number >= streams[stream_id].frame_count ) { @@ -135,10 +135,10 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) { // Check for Connection failure. (ret == -110) ) { - Info( "av_read_frame returned %s.", av_make_error_string(ret).c_str() ); + Info("av_read_frame returned %s.", av_make_error_string(ret).c_str()); } else { - Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, - av_make_error_string(ret).c_str() ); + Error("Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, + av_make_error_string(ret).c_str()); } return NULL; } @@ -148,7 +148,7 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) { return NULL; } - if ( ! zm_receive_frame( streams[packet.stream_index].context, frame, packet ) ) { + if ( ! zm_receive_frame(streams[packet.stream_index].context, frame, packet) ) { Error("Unable to get frame %d, continuing", streams[packet.stream_index].frame_count); zm_av_packet_unref( &packet ); continue; @@ -157,12 +157,10 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) { streams[packet.stream_index].frame_count += 1; } - zm_av_packet_unref( &packet ); + zm_av_packet_unref(&packet); if ( frame_number == -1 ) break; } // end while frame_number > streams.frame_count return frame; -} // end AVFrame *FFmpeg_Input::get_frame - - +} // end AVFrame *FFmpeg_Input::get_frame diff --git a/src/zm_file_camera.h b/src/zm_file_camera.h index 6bf054de7..ad3d46f7b 100644 --- a/src/zm_file_camera.h +++ b/src/zm_file_camera.h @@ -58,6 +58,7 @@ public: int PreCapture(); int Capture( ZMPacket &p ); int PostCapture(); + int Close() { return 0; }; }; #endif // ZM_FILE_CAMERA_H diff --git a/src/zm_group.cpp b/src/zm_group.cpp new file mode 100644 index 000000000..7b96920b8 --- /dev/null +++ b/src/zm_group.cpp @@ -0,0 +1,69 @@ +/* + * ZoneMinder regular expression class implementation, $Date$, $Revision$ + * Copyright (C) 2001-2008 Philip Coombes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "zm.h" +#include "zm_db.h" + +#include "zm_group.h" + +#include +#include + +Group::Group() { + Warning("Instantiating default Group Object. Should not happen."); + id = 0; + parent_id = 0; + strcpy(name, "Default"); +} + +// The order of columns is: Id, ParentId, Name +Group::Group(MYSQL_ROW &dbrow) { + unsigned int index = 0; + id = atoi(dbrow[index++]); + parent_id = dbrow[index] ? atoi(dbrow[index]): 0; index++; + strncpy(name, dbrow[index++], sizeof(name)-1); +} + +/* If a zero or invalid p_id is passed, then the old default path will be assumed. */ +Group::Group(unsigned int p_id) { + id = 0; + + if ( p_id ) { + char sql[ZM_SQL_SML_BUFSIZ]; + snprintf(sql, sizeof(sql), "SELECT Id, ParentId, Name FROM Group WHERE Id=%d", p_id); + Debug(2,"Loading Group for %d using %s", p_id, sql); + zmDbRow dbrow; + if ( !dbrow.fetch(sql) ) { + Error("Unable to load group for id %d: %s", p_id, mysql_error(&dbconn)); + } else { + unsigned int index = 0; + id = atoi(dbrow[index++]); + parent_id = dbrow[index] ? atoi(dbrow[index]): 0; index++; + strncpy(name, dbrow[index++], sizeof(name)-1); + Debug(1, "Loaded Group area %d '%s'", id, this->Name()); + } + } + if ( ! id ) { + Debug(1,"No id passed to Group constructor."); + strcpy(name, "Default"); + } +} + +Group::~Group() { +} diff --git a/src/zm_group.h b/src/zm_group.h new file mode 100644 index 000000000..6adb8cd93 --- /dev/null +++ b/src/zm_group.h @@ -0,0 +1,43 @@ +/* + * ZoneMinder Group Class Interface, $Date$, $Revision$ + * Copyright (C) 2001-2008 Philip Coombes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "zm_db.h" + +#ifndef ZM_GROUP_H +#define ZM_GROUP_H + +class Group { + +protected: + unsigned int id; + unsigned int parent_id; + char name[64+1]; + +public: + Group(); + explicit Group( MYSQL_ROW &dbrow ); + explicit Group( unsigned int p_id ); + ~Group(); + + unsigned int Id() const { return id; } + unsigned int ParentId() const { return id; } + const char *Name() const { return name; } +}; + +#endif // ZM_GROUP_H diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 782e4df4c..020963a67 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -768,7 +768,7 @@ bool Image::ReadRaw( const char *filename ) { return false; } - if ( statbuf.st_size != size ) { + if ( (unsigned int)statbuf.st_size != size ) { fclose(infile); Error("Raw file size mismatch, expected %d bytes, found %ld", size, statbuf.st_size); return false; @@ -803,57 +803,51 @@ bool Image::WriteRaw( const char *filename ) const { return true; } -bool Image::ReadJpeg( const char *filename, unsigned int p_colours, unsigned int p_subpixelorder) -{ +bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int p_subpixelorder) { unsigned int new_width, new_height, new_colours, new_subpixelorder; struct jpeg_decompress_struct *cinfo = readjpg_dcinfo; - if ( !cinfo ) - { + if ( !cinfo ) { cinfo = readjpg_dcinfo = new jpeg_decompress_struct; - cinfo->err = jpeg_std_error( &jpg_err.pub ); + cinfo->err = jpeg_std_error(&jpg_err.pub); jpg_err.pub.error_exit = zm_jpeg_error_exit; jpg_err.pub.emit_message = zm_jpeg_emit_message; - jpeg_create_decompress( cinfo ); + jpeg_create_decompress(cinfo); } FILE *infile; - if ( (infile = fopen( filename, "rb" )) == NULL ) - { - Error( "Can't open %s: %s", filename, strerror(errno) ); - return( false ); + if ( (infile = fopen(filename, "rb")) == NULL ) { + Error("Can't open %s: %s", filename, strerror(errno)); + return false; } - if ( setjmp( jpg_err.setjmp_buffer ) ) - { - jpeg_abort_decompress( cinfo ); - fclose( infile ); - return( false ); + if ( setjmp(jpg_err.setjmp_buffer) ) { + jpeg_abort_decompress(cinfo); + fclose(infile); + return false; } - jpeg_stdio_src( cinfo, infile ); + jpeg_stdio_src(cinfo, infile); - jpeg_read_header( cinfo, TRUE ); + jpeg_read_header(cinfo, TRUE); - if ( cinfo->num_components != 1 && cinfo->num_components != 3 ) - { + if ( cinfo->num_components != 1 && cinfo->num_components != 3 ) { Error( "Unexpected colours when reading jpeg image: %d", colours ); - jpeg_abort_decompress( cinfo ); - fclose( infile ); - return( false ); + jpeg_abort_decompress(cinfo); + fclose(infile); + return false; } /* Check if the image has at least one huffman table defined. If not, use the standard ones */ /* This is required for the MJPEG capture palette of USB devices */ - if(cinfo->dc_huff_tbl_ptrs[0] == NULL) { + if ( cinfo->dc_huff_tbl_ptrs[0] == NULL ) { zm_use_std_huff_tables(cinfo); } new_width = cinfo->image_width; new_height = cinfo->image_height; - if ( width != new_width || height != new_height ) - { + if ( width != new_width || height != new_height ) { Debug(9,"Image dimensions differ. Old: %ux%u New: %ux%u",width,height,new_width,new_height); } @@ -954,10 +948,10 @@ bool Image::WriteJpeg(const char *filename, struct timeval timestamp) const { return Image::WriteJpeg(filename, 0, timestamp); } -bool Image::WriteJpeg( const char *filename, int quality_override, struct timeval timestamp ) const { +bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval timestamp) const { if ( config.colour_jpeg_files && colours == ZM_COLOUR_GRAY8 ) { - Image temp_image( *this ); - temp_image.Colourise( ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); + Image temp_image(*this); + temp_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB); return temp_image.WriteJpeg(filename, quality_override, timestamp); } int quality = quality_override?quality_override:config.jpeg_file_quality; @@ -973,9 +967,9 @@ bool Image::WriteJpeg( const char *filename, int quality_override, struct timeva } FILE *outfile; - if ( (outfile = fopen( filename, "wb" )) == NULL ) { - Error( "Can't open %s: %s", filename, strerror(errno) ); - return( false ); + if ( (outfile = fopen(filename, "wb")) == NULL ) { + Error("Can't open %s: %s", filename, strerror(errno)); + return false; } jpeg_stdio_dest( cinfo, outfile ); @@ -1663,30 +1657,24 @@ void Image::Blend( const Image &image, int transparency ) AssignDirect( width, height, colours, subpixelorder, new_buffer, size, ZM_BUFTYPE_ZM); } -Image *Image::Merge( unsigned int n_images, Image *images[] ) -{ - if ( n_images <= 0 ) return( 0 ); - if ( n_images == 1 ) return( new Image( *images[0] ) ); +Image *Image::Merge( unsigned int n_images, Image *images[] ) { + if ( n_images == 1 ) return new Image(*images[0]); unsigned int width = images[0]->width; unsigned int height = images[0]->height; unsigned int colours = images[0]->colours; - for ( unsigned int i = 1; i < n_images; i++ ) - { - if ( !(width == images[i]->width && height == images[i]->height && colours == images[i]->colours) ) - { + for ( unsigned int i = 1; i < n_images; i++ ) { + if ( !(width == images[i]->width && height == images[i]->height && colours == images[i]->colours) ) { Panic( "Attempt to merge different sized images, expected %dx%dx%d, got %dx%dx%d, for image %d", width, height, colours, images[i]->width, images[i]->height, images[i]->colours, i ); } } Image *result = new Image( width, height, images[0]->colours, images[0]->subpixelorder); unsigned int size = result->size; - for ( unsigned int i = 0; i < size; i++ ) - { + for ( unsigned int i = 0; i < size; i++ ) { unsigned int total = 0; uint8_t *pdest = result->buffer; - for ( unsigned int j = 0; j < n_images; j++ ) - { + for ( unsigned int j = 0; j < n_images; j++ ) { uint8_t *psrc = images[j]->buffer; total += *psrc; psrc++; @@ -1694,21 +1682,17 @@ Image *Image::Merge( unsigned int n_images, Image *images[] ) *pdest = total/n_images; pdest++; } - return( result ); + return result; } -Image *Image::Merge( unsigned int n_images, Image *images[], double weight ) -{ - if ( n_images <= 0 ) return( 0 ); - if ( n_images == 1 ) return( new Image( *images[0] ) ); +Image *Image::Merge( unsigned int n_images, Image *images[], double weight ) { + if ( n_images == 1 ) return new Image(*images[0]); unsigned int width = images[0]->width; unsigned int height = images[0]->height; unsigned int colours = images[0]->colours; - for ( unsigned int i = 1; i < n_images; i++ ) - { - if ( !(width == images[i]->width && height == images[i]->height && colours == images[i]->colours) ) - { + for ( unsigned int i = 1; i < n_images; i++ ) { + if ( !(width == images[i]->width && height == images[i]->height && colours == images[i]->colours) ) { Panic( "Attempt to merge different sized images, expected %dx%dx%d, got %dx%dx%d, for image %d", width, height, colours, images[i]->width, images[i]->height, images[i]->colours, i ); } } @@ -1716,55 +1700,46 @@ Image *Image::Merge( unsigned int n_images, Image *images[], double weight ) Image *result = new Image( *images[0] ); unsigned int size = result->size; double factor = 1.0*weight; - for ( unsigned int i = 1; i < n_images; i++ ) - { + for ( unsigned int i = 1; i < n_images; i++ ) { uint8_t *pdest = result->buffer; uint8_t *psrc = images[i]->buffer; - for ( unsigned int j = 0; j < size; j++ ) - { + for ( unsigned int j = 0; j < size; j++ ) { *pdest = (uint8_t)(((*pdest)*(1.0-factor))+((*psrc)*factor)); pdest++; psrc++; } factor *= weight; } - return( result ); + return result; } Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb threshold, const Rgb ref_colour ) { - if ( n_images <= 0 ) return( 0 ); - if ( n_images == 1 ) return( new Image( *images[0] ) ); + if ( n_images == 1 ) return new Image(*images[0]); unsigned int width = images[0]->width; unsigned int height = images[0]->height; unsigned int colours = images[0]->colours; - for ( unsigned int i = 1; i < n_images; i++ ) - { - if ( !(width == images[i]->width && height == images[i]->height && colours == images[i]->colours) ) - { + for ( unsigned int i = 1; i < n_images; i++ ) { + if ( !(width == images[i]->width && height == images[i]->height && colours == images[i]->colours) ) { Panic( "Attempt to highlight different sized images, expected %dx%dx%d, got %dx%dx%d, for image %d", width, height, colours, images[i]->width, images[i]->height, images[i]->colours, i ); } } Image *result = new Image( width, height, images[0]->colours, images[0]->subpixelorder ); unsigned int size = result->size; - for ( unsigned int c = 0; c < colours; c++ ) - { + for ( unsigned int c = 0; c < colours; c++ ) { unsigned int ref_colour_rgb = RGB_VAL(ref_colour,c); - for ( unsigned int i = 0; i < size; i++ ) - { + for ( unsigned int i = 0; i < size; i++ ) { unsigned int count = 0; uint8_t *pdest = result->buffer+c; - for ( unsigned int j = 0; j < n_images; j++ ) - { + for ( unsigned int j = 0; j < n_images; j++ ) { uint8_t *psrc = images[j]->buffer+c; unsigned int diff = ((*psrc)-ref_colour_rgb) > 0 ? (*psrc)-ref_colour_rgb : ref_colour_rgb - (*psrc); - if (diff >= RGB_VAL(threshold,c)) - { + if (diff >= RGB_VAL(threshold,c)) { count++; } psrc += colours; diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index 4b72bbf5b..2fb5c1add 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -18,6 +18,7 @@ */ #include "zm.h" +#include "zm_signal.h" #include "zm_libvlc_camera.h" #if HAVE_LIBVLC @@ -39,7 +40,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { LibvlcPrivateData* data = reinterpret_cast(opaque); bool newFrame = false; - for( uint32_t i = 0; i < data->bufferSize; i++ ) { + for( unsigned int i=0; i < data->bufferSize; i++ ) { if ( data->buffer[i] != data->prevBuffer[i] ) { newFrame = true; break; @@ -56,11 +57,38 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { } } -LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : - Camera( p_id, LIBVLC_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), - mPath( p_path ), - mMethod( p_method ), - mOptions( p_options ) +LibvlcCamera::LibvlcCamera( + int p_id, + const std::string &p_path, + const std::string &p_method, + const std::string &p_options, + int p_width, + int p_height, + int p_colours, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio + ) : + Camera( + p_id, + LIBVLC_SRC, + p_width, + p_height, + p_colours, + ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), + p_brightness, + p_contrast, + p_hue, + p_colour, + p_capture, + p_record_audio + ), + mPath(p_path), + mMethod(p_method), + mOptions(p_options) { mLibvlcInstance = NULL; mLibvlcMedia = NULL; @@ -70,15 +98,15 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri mOptArgV = NULL; /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ - if(colours == ZM_COLOUR_RGB32) { + if ( colours == ZM_COLOUR_RGB32 ) { subpixelorder = ZM_SUBPIX_ORDER_BGRA; mTargetChroma = "RV32"; mBpp = 4; - } else if(colours == ZM_COLOUR_RGB24) { + } else if ( colours == ZM_COLOUR_RGB24 ) { subpixelorder = ZM_SUBPIX_ORDER_BGR; mTargetChroma = "RV24"; mBpp = 3; - } else if(colours == ZM_COLOUR_GRAY8) { + } else if ( colours == ZM_COLOUR_GRAY8 ) { subpixelorder = ZM_SUBPIX_ORDER_NONE; mTargetChroma = "GREY"; mBpp = 1; @@ -118,11 +146,13 @@ void LibvlcCamera::Initialise() { void LibvlcCamera::Terminate() { libvlc_media_player_stop(mLibvlcMediaPlayer); - if(mLibvlcData.buffer != NULL) { + if ( mLibvlcData.buffer ) { zm_freealigned(mLibvlcData.buffer); + mLibvlcData.buffer = NULL; } - if(mLibvlcData.prevBuffer != NULL) { + if ( mLibvlcData.prevBuffer ) { zm_freealigned(mLibvlcData.prevBuffer); + mLibvlcData.prevBuffer = NULL; } } @@ -139,6 +169,8 @@ int LibvlcCamera::PrimeCapture() { else if ( Method() == "rtpRtspHttp" ) opVect.push_back("--rtsp-http"); + opVect.push_back("--no-audio"); + if ( opVect.size() > 0 ) { mOptArgV = new char*[opVect.size()]; Debug(2, "Number of Options: %d",opVect.size()); @@ -149,17 +181,23 @@ int LibvlcCamera::PrimeCapture() { } } - mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV); - if ( mLibvlcInstance == NULL ) - Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg()); + mLibvlcInstance = libvlc_new(opVect.size(), (const char* const*)mOptArgV); + if ( mLibvlcInstance == NULL ) { + Error("Unable to create libvlc instance due to: %s", libvlc_errmsg()); + return -1; + } mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str()); - if(mLibvlcMedia == NULL) - Fatal("Unable to open input %s due to: %s", mPath.c_str(), libvlc_errmsg()); + if ( mLibvlcMedia == NULL ) { + Error("Unable to open input %s due to: %s", mPath.c_str(), libvlc_errmsg()); + return -1; + } mLibvlcMediaPlayer = libvlc_media_player_new_from_media(mLibvlcMedia); - if(mLibvlcMediaPlayer == NULL) - Fatal("Unable to create player for %s due to: %s", mPath.c_str(), libvlc_errmsg()); + if ( mLibvlcMediaPlayer == NULL ) { + Error("Unable to create player for %s due to: %s", mPath.c_str(), libvlc_errmsg()); + return -1; + } libvlc_video_set_format(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp); libvlc_video_set_callbacks(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData); @@ -177,13 +215,17 @@ int LibvlcCamera::PrimeCapture() { } int LibvlcCamera::PreCapture() { - return(0); + return 0; } // Should not return -1 as cancels capture. Always wait for image if available. int LibvlcCamera::Capture( ZMPacket &zm_packet ) { - while(!mLibvlcData.newImage.getValueImmediate()) + // newImage is a mutex/condition based flag to tell us when there is an image available + while( !mLibvlcData.newImage.getValueImmediate() ) { + if (zm_terminate) + return 0; mLibvlcData.newImage.getUpdatedValue(1); + } mLibvlcData.mutex.lock(); zm_packet.image->Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); @@ -194,7 +236,7 @@ int LibvlcCamera::Capture( ZMPacket &zm_packet ) { } int LibvlcCamera::PostCapture() { - return(0); + return 0; } #endif // HAVE_LIBVLC diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h index aa2765dbf..c5842fcb3 100644 --- a/src/zm_libvlc_camera.h +++ b/src/zm_libvlc_camera.h @@ -69,6 +69,7 @@ public: int PreCapture(); int Capture( ZMPacket &p ); int PostCapture(); + int Close() { return 0; }; }; #endif // HAVE_LIBVLC diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index d75c9b854..4e1349562 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -668,7 +668,7 @@ LocalCamera::~LocalCamera() { sws_freeContext(imgConversionContext); imgConversionContext = NULL; - av_frame_free( &tmpPicture ); + av_frame_free(&tmpPicture); } #endif } // end LocalCamera::~LocalCamera @@ -1091,54 +1091,51 @@ void LocalCamera::Initialise() { void LocalCamera::Terminate() { #if ZM_HAS_V4L2 if ( v4l_version == 2 ) { - Debug( 3, "Terminating video stream" ); + Debug(3, "Terminating video stream"); //enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // enum v4l2_buf_type type = v4l2_data.fmt.type; enum v4l2_buf_type type = (v4l2_buf_type)v4l2_data.fmt.type; - if ( vidioctl( vid_fd, VIDIOC_STREAMOFF, &type ) < 0 ) - Error( "Failed to stop capture stream: %s", strerror(errno) ); + if ( vidioctl(vid_fd, VIDIOC_STREAMOFF, &type) < 0 ) + Error("Failed to stop capture stream: %s", strerror(errno)); - Debug( 3, "Unmapping video buffers" ); + Debug(3, "Unmapping video buffers"); for ( unsigned int i = 0; i < v4l2_data.reqbufs.count; i++ ) { #if HAVE_LIBSWSCALE /* Free capture pictures */ #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - av_frame_free( &capturePictures[i] ); + av_frame_free(&capturePictures[i]); #else - av_freep( &capturePictures[i] ); + av_freep(&capturePictures[i]); #endif #endif - if ( munmap( v4l2_data.buffers[i].start, v4l2_data.buffers[i].length ) < 0 ) - Error( "Failed to munmap buffer %d: %s", i, strerror(errno) ); + if ( munmap(v4l2_data.buffers[i].start, v4l2_data.buffers[i].length) < 0 ) + Error("Failed to munmap buffer %d: %s", i, strerror(errno)); } - } else #endif // ZM_HAS_V4L2 - #if ZM_HAS_V4L1 if ( v4l_version == 1 ) { #if HAVE_LIBSWSCALE - for(int i=0; i < v4l1_data.frames.frames; i++) { + for( int i=0; i < v4l1_data.frames.frames; i++ ) { /* Free capture pictures */ #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - av_frame_free( &capturePictures[i] ); + av_frame_free(&capturePictures[i]); #else - av_freep( &capturePictures[i] ); + av_freep(&capturePictures[i]); #endif } #endif - Debug( 3, "Unmapping video buffers" ); + Debug(3, "Unmapping video buffers"); if ( munmap((char*)v4l1_data.bufptr, v4l1_data.frames.size) < 0 ) - Error( "Failed to munmap buffers: %s", strerror(errno) ); + Error("Failed to munmap buffers: %s", strerror(errno)); delete[] v4l1_data.buffers; } // end if using v4l1 #endif // ZM_HAS_V4L1 - close( vid_fd ); - + close(vid_fd); } // end LocalCamera::Terminate uint32_t LocalCamera::AutoSelectFormat(int p_colours) { diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index 314b20ac1..c466f72b8 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -158,6 +158,7 @@ public: int PreCapture(); int Capture(ZMPacket &p); int PostCapture(); + int Close() { return 0; }; static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose ); AVStream* get_VideoStream(); }; diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 68e6a7540..d99f72b1c 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -62,22 +62,22 @@ void Logger::usrHandler( int sig ) { logger->level( logger->level()+1 ); else if ( sig == SIGUSR2 ) logger->level( logger->level()-1 ); - Info( "Logger - Level changed to %d", logger->level() ); + Info("Logger - Level changed to %d", logger->level()); } Logger::Logger() : - mLevel( INFO ), - mTerminalLevel( NOLOG ), - mDatabaseLevel( NOLOG ), - mFileLevel( NOLOG ), - mSyslogLevel( NOLOG ), - mEffectiveLevel( NOLOG ), + mLevel(INFO), + mTerminalLevel(NOLOG), + mDatabaseLevel(NOLOG), + mFileLevel(NOLOG), + mSyslogLevel(NOLOG), + mEffectiveLevel(NOLOG), //mLogPath( staticConfig.PATH_LOGS.c_str() ), //mLogFile( mLogPath+"/"+mId+".log" ), - mDbConnected( false ), - mLogFileFP( NULL ), - mHasTerminal( false ), - mFlush( false ) { + mDbConnected(false), + mLogFileFP(NULL), + mHasTerminal(false), + mFlush(false) { if ( smInstance ) { Panic( "Attempt to create second instance of Logger class" ); @@ -99,7 +99,7 @@ Logger::Logger() : char code[4] = ""; for ( int i = DEBUG1; i <= DEBUG9; i++ ) { - snprintf( code, sizeof(code), "DB%d", i ); + snprintf(code, sizeof(code), "DB%d", i); smCodes[i] = code; smSyslogPriorities[i] = LOG_DEBUG; } @@ -115,6 +115,7 @@ Logger::~Logger() { terminate(); smCodes.clear(); smSyslogPriorities.clear(); + smInitialised = false; #if 0 for ( StringMap::iterator itr = smCodes.begin(); itr != smCodes.end(); itr ++ ) { smCodes.erase( itr ); @@ -125,7 +126,7 @@ Logger::~Logger() { #endif } -void Logger::initialise( const std::string &id, const Options &options ) { +void Logger::initialise(const std::string &id, const Options &options) { char *envPtr; if ( !id.empty() ) @@ -133,7 +134,7 @@ void Logger::initialise( const std::string &id, const Options &options ) { std::string tempLogFile; - if ( (envPtr = getTargettedEnv( "LOG_FILE" )) ) + if ( (envPtr = getTargettedEnv("LOG_FILE")) ) tempLogFile = envPtr; else if ( options.mLogFile.size() ) tempLogFile = options.mLogFile; @@ -172,20 +173,20 @@ void Logger::initialise( const std::string &id, const Options &options ) { if ( (envPtr = getenv( "LOG_PRINT" )) ) tempTerminalLevel = atoi(envPtr) ? DEBUG9 : NOLOG; - if ( (envPtr = getTargettedEnv( "LOG_LEVEL" )) ) + if ( (envPtr = getTargettedEnv("LOG_LEVEL")) ) tempLevel = atoi(envPtr); - if ( (envPtr = getTargettedEnv( "LOG_LEVEL_TERM" )) ) + if ( (envPtr = getTargettedEnv("LOG_LEVEL_TERM")) ) tempTerminalLevel = atoi(envPtr); - if ( (envPtr = getTargettedEnv( "LOG_LEVEL_DATABASE" )) ) + if ( (envPtr = getTargettedEnv("LOG_LEVEL_DATABASE")) ) tempDatabaseLevel = atoi(envPtr); - if ( (envPtr = getTargettedEnv( "LOG_LEVEL_FILE" )) ) + if ( (envPtr = getTargettedEnv("LOG_LEVEL_FILE")) ) tempFileLevel = atoi(envPtr); - if ( (envPtr = getTargettedEnv( "LOG_LEVEL_SYSLOG" )) ) + if ( (envPtr = getTargettedEnv("LOG_LEVEL_SYSLOG")) ) tempSyslogLevel = atoi(envPtr); if ( config.log_debug ) { - StringVector targets = split( config.log_debug_target, "|" ); + StringVector targets = split(config.log_debug_target, "|"); for ( unsigned int i = 0; i < targets.size(); i++ ) { const std::string &target = targets[i]; if ( target == mId || target == "_"+mId || target == "_"+mIdRoot || target == "" ) { @@ -207,15 +208,14 @@ void Logger::initialise( const std::string &id, const Options &options ) { if ( tempLevel > INFO ) tempLevel = INFO; } // end if config.log_debug + logFile(tempLogFile); - logFile( tempLogFile ); + terminalLevel(tempTerminalLevel); + databaseLevel(tempDatabaseLevel); + fileLevel(tempFileLevel); + syslogLevel(tempSyslogLevel); - terminalLevel( tempTerminalLevel ); - databaseLevel( tempDatabaseLevel ); - fileLevel( tempFileLevel ); - syslogLevel( tempSyslogLevel ); - - level( tempLevel ); + level(tempLevel); mFlush = false; if ( (envPtr = getenv("LOG_FLUSH")) ) { @@ -224,24 +224,24 @@ void Logger::initialise( const std::string &id, const Options &options ) { mFlush = true; } - //mRuntime = (envPtr = getenv( "LOG_RUNTIME")) ? atoi( envPtr ) : false; { struct sigaction action; - memset( &action, 0, sizeof(action) ); + memset(&action, 0, sizeof(action)); action.sa_handler = usrHandler; action.sa_flags = SA_RESTART; - if ( sigaction( SIGUSR1, &action, 0 ) < 0 ) { - Fatal( "sigaction(), error = %s", strerror(errno) ); + // Does this REALLY need to be fatal? + if ( sigaction(SIGUSR1, &action, 0) < 0 ) { + Fatal("sigaction(), error = %s", strerror(errno)); } - if ( sigaction( SIGUSR2, &action, 0 ) < 0) { - Fatal( "sigaction(), error = %s", strerror(errno) ); + if ( sigaction(SIGUSR2, &action, 0) < 0) { + Fatal("sigaction(), error = %s", strerror(errno)); } } mInitialised = true; - Debug( 1, "LogOpts: level=%s/%s, screen=%s, database=%s, logfile=%s->%s, syslog=%s", + Debug(1, "LogOpts: level=%s/%s, screen=%s, database=%s, logfile=%s->%s, syslog=%s", smCodes[mLevel].c_str(), smCodes[mEffectiveLevel].c_str(), smCodes[mTerminalLevel].c_str(), @@ -253,7 +253,7 @@ void Logger::initialise( const std::string &id, const Options &options ) { } void Logger::terminate() { - Debug(1, "Terminating Logger" ); + Debug(1, "Terminating Logger"); if ( mFileLevel > NOLOG ) closeFile(); @@ -265,58 +265,59 @@ void Logger::terminate() { closeDatabase(); } -bool Logger::boolEnv( const std::string &name, bool defaultValue ) { - const char *envPtr = getenv( name.c_str() ); - return( envPtr ? atoi( envPtr ) : defaultValue ); +// These don't belong here, they have nothing to do with logging +bool Logger::boolEnv(const std::string &name, bool defaultValue) { + const char *envPtr = getenv(name.c_str()); + return envPtr ? atoi(envPtr) : defaultValue; } -int Logger::intEnv( const std::string &name, bool defaultValue ) { - const char *envPtr = getenv( name.c_str() ); - return( envPtr ? atoi( envPtr ) : defaultValue ); +int Logger::intEnv(const std::string &name, bool defaultValue) { + const char *envPtr = getenv(name.c_str()); + return envPtr ? atoi(envPtr) : defaultValue; } -std::string Logger::strEnv( const std::string &name, const std::string &defaultValue ) { - const char *envPtr = getenv( name.c_str() ); - return( envPtr ? envPtr : defaultValue ); +std::string Logger::strEnv(const std::string &name, const std::string &defaultValue) { + const char *envPtr = getenv(name.c_str()); + return envPtr ? envPtr : defaultValue; } -char *Logger::getTargettedEnv( const std::string &name ) { +char *Logger::getTargettedEnv(const std::string &name) { std::string envName = name+"_"+mId; - char *envPtr = getenv( envName.c_str() ); + char *envPtr = getenv(envName.c_str()); if ( !envPtr && mId != mIdRoot ) { envName = name+"_"+mIdRoot; - envPtr = getenv( envName.c_str() ); + envPtr = getenv(envName.c_str()); } if ( !envPtr ) - envPtr = getenv( name.c_str() ); + envPtr = getenv(name.c_str()); return envPtr; } -const std::string &Logger::id( const std::string &id ) { +const std::string &Logger::id(const std::string &id) { std::string tempId = id; size_t pos; // Remove whitespace while ( (pos = tempId.find_first_of( " \t" )) != std::string::npos ) { - tempId.replace( pos, 1, "" ); + tempId.replace(pos, 1, ""); } // Replace non-alphanum with underscore - while ( (pos = tempId.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" )) != std::string::npos ) { - tempId.replace( pos, 1, "_" ); + while ( (pos = tempId.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")) != std::string::npos ) { + tempId.replace(pos, 1, "_"); } if ( mId != tempId ) { mId = tempId; - pos = mId.find( '_' ); + pos = mId.find('_'); if ( pos != std::string::npos ) { - mIdRoot = mId.substr( 0, pos ); + mIdRoot = mId.substr(0, pos); if ( ++pos < mId.size() ) - mIdArgs = mId.substr( pos ); + mIdArgs = mId.substr(pos); } } - return( mId ); + return mId; } -Logger::Level Logger::level( Logger::Level level ) { +Logger::Level Logger::level(Logger::Level level) { if ( level > NOOPT ) { level = limit(level); if ( mLevel != level ) @@ -334,7 +335,7 @@ Logger::Level Logger::level( Logger::Level level ) { if ( mEffectiveLevel > mLevel) mEffectiveLevel = mLevel; } - return( mLevel ); + return mLevel; } Logger::Level Logger::terminalLevel( Logger::Level terminalLevel ) { @@ -345,7 +346,7 @@ Logger::Level Logger::terminalLevel( Logger::Level terminalLevel ) { if ( mTerminalLevel != terminalLevel ) mTerminalLevel = terminalLevel; } - return( mTerminalLevel ); + return mTerminalLevel; } Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) { @@ -359,7 +360,7 @@ Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) { } // end if ( mDatabaseLevel != databaseLevel ) } // end if ( databaseLevel > NOOPT ) - return( mDatabaseLevel ); + return mDatabaseLevel; } Logger::Level Logger::fileLevel( Logger::Level fileLevel ) { @@ -372,7 +373,7 @@ Logger::Level Logger::fileLevel( Logger::Level fileLevel ) { if ( mFileLevel > NOLOG ) openFile(); } - return( mFileLevel ); + return mFileLevel; } Logger::Level Logger::syslogLevel( Logger::Level syslogLevel ) { @@ -386,7 +387,7 @@ Logger::Level Logger::syslogLevel( Logger::Level syslogLevel ) { openSyslog(); } } - return( mSyslogLevel ); + return mSyslogLevel; } void Logger::logFile( const std::string &logFile ) { @@ -448,9 +449,9 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co const char *classString = smCodes[level].c_str(); if ( level < PANIC || level > DEBUG9 ) - Panic( "Invalid logger level %d", level ); + Panic("Invalid logger level %d", level); - gettimeofday( &timeVal, NULL ); + gettimeofday(&timeVal, NULL); #if 0 if ( logRuntime ) { @@ -462,8 +463,8 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co } else { #endif char *timePtr = timeString; - timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) ); - snprintf( timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec ); + timePtr += strftime(timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec)); + snprintf(timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec); #if 0 } #endif @@ -529,25 +530,29 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co } else { puts("Logging to file, but file not open\n"); } - } else { - puts("Not logging to file because level <= mFileLevel"); } *syslogEnd = '\0'; if ( level <= mDatabaseLevel ) { char sql[ZM_SQL_MED_BUFSIZ]; char escapedString[(strlen(syslogStart)*2)+1]; - db_mutex.lock(); - mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); + if ( ! db_mutex.trylock() ) { + mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); - 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( &dbconn, sql ) ) { + 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(&dbconn, sql) ) { + Level tempDatabaseLevel = mDatabaseLevel; + databaseLevel(NOLOG); + Error("Can't insert log entry: sql(%s) error(%s)", sql, mysql_error(&dbconn)); + databaseLevel(tempDatabaseLevel); + } + db_mutex.unlock(); + } else { Level tempDatabaseLevel = mDatabaseLevel; - databaseLevel( NOLOG ); - Error( "Can't insert log entry: sql(%s) error(%s)", sql, mysql_error( &dbconn ) ); + databaseLevel(NOLOG); + Error("Can't insert log entry: sql(%s) error(db is locked)", logString); databaseLevel(tempDatabaseLevel); } - db_mutex.unlock(); } if ( level <= mSyslogLevel ) { int priority = smSyslogPriorities[level]; @@ -561,7 +566,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co zmDbClose(); if ( level <= PANIC ) abort(); - exit( -1 ); + exit(-1); } } diff --git a/src/zm_logger.h b/src/zm_logger.h index d23b28875..8e2ab6c9d 100644 --- a/src/zm_logger.h +++ b/src/zm_logger.h @@ -108,10 +108,10 @@ private: bool mFlush; private: - static void usrHandler( int sig ); + static void usrHandler(int sig); public: - friend void logInit( const char *name, const Options &options ); + friend void logInit(const char *name, const Options &options); friend void logTerm(); static Logger *fetch() { @@ -120,7 +120,7 @@ public: Options options; smInstance->initialise( "undef", options ); } - return( smInstance ); + return smInstance; } private: @@ -128,48 +128,48 @@ private: ~Logger(); public: - void initialise( const std::string &id, const Options &options ); + void initialise(const std::string &id, const Options &options); void terminate(); private: - int limit( int level ) { + int limit(int level) { if ( level > DEBUG9 ) - return( DEBUG9 ); + return DEBUG9; if ( level < NOLOG ) - return( NOLOG ); - return( level ); + return NOLOG; + return level; } - bool boolEnv( const std::string &name, bool defaultValue=false ); - int intEnv( const std::string &name, bool defaultValue=0 ); - std::string strEnv( const std::string &name, const std::string &defaultValue="" ); - char *getTargettedEnv( const std::string &name ); + bool boolEnv(const std::string &name, bool defaultValue=false); + int intEnv(const std::string &name, bool defaultValue=0); + std::string strEnv(const std::string &name, const std::string &defaultValue=""); + char *getTargettedEnv(const std::string &name); void loadEnv(); public: const std::string &id() const { - return( mId ); + return mId; } - const std::string &id( const std::string &id ); + const std::string &id(const std::string &id); Level level() const { - return( mLevel ); + return mLevel; } - Level level( Level=NOOPT ); + Level level(Level=NOOPT); bool debugOn() { - return( mEffectiveLevel >= DEBUG1 ); + return mEffectiveLevel >= DEBUG1; } - Level terminalLevel( Level=NOOPT ); - Level databaseLevel( Level=NOOPT ); - Level fileLevel( Level=NOOPT ); - Level syslogLevel( Level=NOOPT ); + Level terminalLevel(Level=NOOPT); + Level databaseLevel(Level=NOOPT); + Level fileLevel(Level=NOOPT); + Level syslogLevel(Level=NOOPT); private: - void logFile( const std::string &logFile ); + void logFile(const std::string &logFile); void openFile(); void closeFile(); void openSyslog(); @@ -177,22 +177,19 @@ private: void closeDatabase(); public: - void logPrint( bool hex, const char * const filepath, const int line, const int level, const char *fstring, ... ); + void logPrint(bool hex, const char * const filepath, const int line, const int level, const char *fstring, ...); }; -void logInit( const char *name, const Logger::Options &options=Logger::Options() ); +void logInit(const char *name, const Logger::Options &options=Logger::Options()); void logTerm(); inline const std::string &logId() { - return( Logger::fetch()->id() ); + return Logger::fetch()->id(); } inline Logger::Level logLevel() { - return( Logger::fetch()->level() ); -} -inline void logCapLevel( Logger::Level level ) { - Logger::fetch()->level( level ); + return Logger::fetch()->level(); } inline Logger::Level logDebugging() { - return( Logger::fetch()->debugOn() ); + return Logger::fetch()->debugOn(); } #define logPrintf(logLevel,params...) {\ diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e6519acd4..0224c3b4a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1,26 +1,27 @@ // // ZoneMinder Monitor Class Implementation, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// #include #include #include #include +#include #include "zm.h" #include "zm_db.h" @@ -63,17 +64,43 @@ #define MAP_LOCKED 0 #endif -Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : - id( p_id ), +// This is the official SQL (and ordering of the fields) to load a Monitor. +// It will be used whereever a Monitor dbrow is needed. WHERE conditions can be appended +std::string load_monitor_sql = +"SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, " +"AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS," +"Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, " // V4L Settings +"Protocol, Method, Options, User, Pass, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, " +"SaveJPEGs, VideoWriter, EncoderParameters, " +"OutputCodec, Encoder, OutputContainer, " +"RecordAudio, " +"Brightness, Contrast, Hue, Colour, " +"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize," +"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, " +"SectionLength, FrameSkip, MotionFrameSkip, " +"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckPoints, SignalCheckColour FROM Monitors"; + +std::string CameraType_Strings[] = { + "Local", + "Remote", + "File", + "Ffmpeg", + "LibVLC", + "cURL", + "NVSOCKET", +}; + +Monitor::MonitorLink::MonitorLink(int p_id, const char *p_name) : + id(p_id), shared_data(NULL), trigger_data(NULL), video_store_data(NULL) { - strncpy( name, p_name, sizeof(name)-1 ); + strncpy(name, p_name, sizeof(name)-1); #if ZM_MEM_MAPPED map_fd = -1; - snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id ); + snprintf(mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id); #else // ZM_MEM_MAPPED shm_id = 0; #endif // ZM_MEM_MAPPED @@ -166,7 +193,7 @@ bool Monitor::MonitorLink::connect() { return( true ); } return( false ); -} +} // end bool Monitor::MonitorLink::connect() bool Monitor::MonitorLink::disconnect() { if ( connected ) { @@ -225,135 +252,284 @@ bool Monitor::MonitorLink::inAlarm() { bool Monitor::MonitorLink::hasAlarmed() { if ( shared_data->state == ALARM ) { - return( true ); + return true; } - //} else if ( shared_data->last_event_id != (unsigned int)last_event ) { -// Why test for it, just set it... - last_event_id = shared_data->last_event_id; - //} - return( false ); + last_event_id = shared_data->last_event_id; + return false; } -Monitor::Monitor( - int p_id, - const char *p_name, - const unsigned int p_server_id, - const unsigned int p_storage_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_colours, - VideoWriter p_videowriter, - std::string &p_encoderparams, - std::string &p_output_codec, - std::string &p_output_container, - bool p_record_audio, - const char *p_event_prefix, - const char *p_label_format, - const Coord &p_label_coord, - int p_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_limit, - 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, - Zone *p_zones[] -) : id( p_id ), - server_id( p_server_id ), - storage_id( p_storage_id ), - function( (Function)p_function ), - enabled( p_enabled ), - width( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Height():p_camera->Width() ), - height( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Width():p_camera->Height() ), - orientation( (Orientation)p_orientation ), - deinterlacing( p_deinterlacing ), - savejpegspref( p_savejpegs ), - colours( p_colours ), - videowriter( p_videowriter ), - encoderparams( p_encoderparams ), - output_codec( p_output_codec ), - output_container( p_output_container ), - record_audio( p_record_audio ), - label_coord( p_label_coord ), - label_size( p_label_size ), - image_buffer_count( p_image_buffer_count ), - warmup_count( p_warmup_count ), - pre_event_count( p_pre_event_count ), - post_event_count( p_post_event_count ), - stream_replay_buffer( p_stream_replay_buffer ), - section_length( p_section_length ), - frame_skip( p_frame_skip ), - motion_frame_skip( p_motion_frame_skip ), - analysis_fps_limit( p_analysis_fps_limit ), - analysis_update_delay( p_analysis_update_delay ), - capture_delay( p_capture_delay ), - alarm_capture_delay( p_alarm_capture_delay ), - alarm_frame_count( p_alarm_frame_count ), - fps_report_interval( p_fps_report_interval ), - ref_blend_perc( p_ref_blend_perc ), - alarm_ref_blend_perc( p_alarm_ref_blend_perc ), - track_motion( p_track_motion ), - signal_check_colour( p_signal_check_colour ), - embed_exif( p_embed_exif ), - delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ), - ref_image( width, height, p_camera->Colours(), p_camera->SubpixelOrder() ), - purpose( p_purpose ), - last_motion_score(0), - camera( p_camera ), - n_zones( p_n_zones ), - zones( p_zones ), - timestamps( 0 ), - images( 0 ), - privacy_bitmask( NULL ) -{ - strncpy( name, p_name, sizeof(name)-1 ); +Monitor::Monitor() + : id(0), + name(""), + server_id(0), + storage_id(0), + type(LOCAL), + function(NONE), + enabled(0), + //protocol + //method + //options + //host + //port + //user + //pass + //path + //device + palette(0), + channel(0), + format(0), - strncpy( event_prefix, p_event_prefix, sizeof(event_prefix)-1 ); - strncpy( label_format, p_label_format, sizeof(label_format)-1 ); + width(0), + height(0), + //v4l_multi_buffer + //v4l_captures_per_frame + orientation(ROTATE_0), + deinterlacing(0), + deinterlacing_value(0), + videoRecording(0), + rtsp_describe(0), + + savejpegs(0), + colours(0), + videowriter(DISABLED), + encoderparams(""), + output_codec(0), + output_container(""), + record_audio(0), +//event_prefix +//label_format + label_coord(Coord(0,0)), + label_size(0), + image_buffer_count(0), + warmup_count(0), + pre_event_count(0), + post_event_count(0), + stream_replay_buffer(0), + section_length(0), + frame_skip(0), + motion_frame_skip(0), + analysis_fps_limit(0), + analysis_update_delay(0), + capture_delay(0), + alarm_capture_delay(0), + alarm_frame_count(0), + fps_report_interval(0), + ref_blend_perc(0), + alarm_ref_blend_perc(0), + track_motion(0), + signal_check_points(0), + signal_check_colour(0), + embed_exif(0), + purpose(QUERY), + auto_resume_time(0), + last_motion_score(0), + camera(0), + n_zones(0), + zones(NULL), + timestamps(0), + images(0), + privacy_bitmask( NULL ), + event_delete_thread(NULL), + n_linked_monitors(0), + linked_monitors(NULL) +{ + + if ( strcmp(config.event_close_mode, "time") == 0 ) + event_close_mode = CLOSE_TIME; + else if ( strcmp(config.event_close_mode, "alarm") == 0 ) + event_close_mode = CLOSE_ALARM; + else + event_close_mode = CLOSE_IDLE; + + start_time = last_fps_time = time( 0 ); + event = 0; + last_section_mod = 0; + + adaptive_skip = true; + + videoStore = NULL; +} // Monitor::Monitor + +/* + std::string load_monitor_sql = + "SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, " + "AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS," + "Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, " // V4L Settings + "Protocol, Method, Options, User, Pass, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, " + "SaveJPEGs, VideoWriter, EncoderParameters, +"OutputCodec, Encoder, OutputContainer," +" RecordAudio, " + "Brightness, Contrast, Hue, Colour, " + "EventPrefix, LabelFormat, LabelX, LabelY, LabelSize," + "ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, " + "SectionLength, FrameSkip, MotionFrameSkip, " + "FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckColour FROM Monitors"; +*/ + +void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { + purpose = p; + int col = 0; + + id = atoi(dbrow[col]); col++; + strncpy(name, dbrow[col], sizeof(name)-1); col++; + server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + + storage_id = atoi(dbrow[col]); col++; + storage = new Storage(storage_id); + Debug(1, "Storage path: %s", storage->Path() ); + + if ( ! strcmp(dbrow[col], "Local") ) { + type = LOCAL; + } else if ( ! strcmp(dbrow[col], "Ffmpeg") ) { + type = FFMPEG; + } else if ( ! strcmp(dbrow[col], "Remote") ) { + type = REMOTE; + } else if ( ! strcmp(dbrow[col], "File") ) { + type = FILE; + } else if ( ! strcmp(dbrow[col], "NVSocket") ) { + type = NVSOCKET; + } else if ( ! strcmp(dbrow[col], "Libvlc") ) { + type = LIBVLC; + } else if ( ! strcmp(dbrow[col], "cURL") ) { + type = CURL; + } else { + Fatal("Bogus monitor type '%s' for monitor %d", dbrow[col], id); + } + Debug(1,"Have camera type %s", CameraType_Strings[type].c_str()); + col++; + function = (Function)atoi(dbrow[col]); col++; + enabled = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + + ReloadLinkedMonitors(dbrow[col]); col++; + + analysis_fps = dbrow[col] ? strtod(dbrow[col], NULL) : 0; col++; + analysis_update_delay = strtoul(dbrow[col++], NULL, 0); + capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + alarm_capture_delay = (dbrow[col]&&atof(dbrow[col])>0.0)?int(DT_PREC_3/atof(dbrow[col])):0; col++; + + if ( dbrow[col] ) + strncpy(device, dbrow[col], sizeof(device)-1); + else + device[0] = 0; + col++; + + channel = atoi(dbrow[col]); col++; + format = atoi(dbrow[col]); col++; + 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++; + + v4l_captures_per_frame = 0; + if ( dbrow[col] ) { + v4l_captures_per_frame = atoi(dbrow[col]); + } else { + v4l_captures_per_frame = config.captures_per_frame; + } + col++; + + protocol = dbrow[col] ? dbrow[col] : ""; col++; + method = dbrow[col] ? dbrow[col] : ""; col++; + options = dbrow[col] ? dbrow[col] : ""; col++; + user = dbrow[col] ? dbrow[col] : ""; col++; + pass = dbrow[col] ? dbrow[col] : ""; col++; + host = dbrow[col] ? dbrow[col] : ""; col++; + port = dbrow[col] ? dbrow[col] : ""; col++; + path = dbrow[col] ? dbrow[col] : ""; col++; + + camera_width = atoi(dbrow[col]); col++; + camera_height = atoi(dbrow[col]); col++; + + colours = atoi(dbrow[col]); col++; + palette = atoi(dbrow[col]); col++; + orientation = (Orientation)atoi(dbrow[col]); col++; + width = (orientation==ROTATE_90||orientation==ROTATE_270) ? camera_height : camera_width; + height = (orientation==ROTATE_90||orientation==ROTATE_270) ? camera_width : camera_height; + + deinterlacing = atoi(dbrow[col]); col++; + deinterlacing_value = deinterlacing & 0xff; + + rtsp_describe = (dbrow[col] && *dbrow[col] != '0'); col++; + + savejpegs = atoi(dbrow[col]); col++; + videowriter = (VideoWriter)atoi(dbrow[col]); col++; + encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + /* Parse encoder parameters */ + ParseEncoderParameters(encoderparams.c_str(), &encoderparamsvec); + + output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + encoder = dbrow[col] ? dbrow[col] : ""; col++; + output_container = dbrow[col] ? dbrow[col] : ""; col++; + record_audio = (*dbrow[col] != '0'); col++; + + brightness = atoi(dbrow[col]); col++; + contrast = atoi(dbrow[col]); col++; + hue = atoi(dbrow[col]); col++; + colour = atoi(dbrow[col]); col++; + + if ( dbrow[col] ) + strncpy(event_prefix, dbrow[col], sizeof(event_prefix)-1); + else + event_prefix[0] = 0; + col++; + + if ( dbrow[col] ) + strncpy(label_format, dbrow[col], sizeof(label_format)-1); + else + label_format[0] = 0; + col++; // Change \n to actual line feeds char *token_ptr = label_format; const char *token_string = "\n"; - while( ( token_ptr = strstr( token_ptr, token_string ) ) ) { + while( ( token_ptr = strstr(token_ptr, token_string) ) ) { if ( *(token_ptr+1) ) { *token_ptr = '\n'; token_ptr++; - strcpy( token_ptr, token_ptr+1 ); + strcpy(token_ptr, token_ptr+1); } else { *token_ptr = '\0'; break; } } - /* Parse encoder parameters */ - ParseEncoderParameters(encoderparams.c_str(), &encoderparamsvec); + label_coord = Coord(atoi(dbrow[col]), atoi(dbrow[col+1])); col += 2; + label_size = atoi(dbrow[col]); col++; + + image_buffer_count = atoi(dbrow[col]); col++; + warmup_count = atoi(dbrow[col]); col++; + pre_event_count = atoi(dbrow[col]); col++; + post_event_count = atoi(dbrow[col]); col++; + stream_replay_buffer = atoi(dbrow[col]); col++; + alarm_frame_count = atoi(dbrow[col]); col++; + if ( alarm_frame_count < 1 ) + alarm_frame_count = 1; + else if ( alarm_frame_count > MAX_PRE_ALARM_FRAMES ) + alarm_frame_count = MAX_PRE_ALARM_FRAMES; + pre_event_buffer_count = pre_event_count + alarm_frame_count + warmup_count - 1; + + section_length = atoi(dbrow[col]); col++; + frame_skip = atoi(dbrow[col]); col++; + motion_frame_skip = atoi(dbrow[col]); col++; + fps_report_interval = atoi(dbrow[col]); col++; + ref_blend_perc = atoi(dbrow[col]); col++; + alarm_ref_blend_perc = atoi(dbrow[col]); col++; + track_motion = atoi(dbrow[col]); col++; + + signal_check_colour = strtol(dbrow[col][0] == '#' ? dbrow[col]+1 : dbrow[col], 0, 16); col++; + embed_exif = (*dbrow[col] != '0'); col++; capture_fps = 0.0; analysis_fps = 0.0; + last_camera_bytes = 0; event_count = 0; image_count = 0; analysis_image_count = 0; - deinterlacing_value = deinterlacing & 0xff; // How many frames we need to have before we start analysing ready_count = warmup_count; @@ -362,129 +538,232 @@ Monitor::Monitor( state = IDLE; last_signal = false; - if ( alarm_frame_count < 1 ) - alarm_frame_count = 1; - else if ( alarm_frame_count > MAX_PRE_ALARM_FRAMES ) - alarm_frame_count = MAX_PRE_ALARM_FRAMES; - - auto_resume_time = 0; - - if ( strcmp( config.event_close_mode, "time" ) == 0 ) - event_close_mode = CLOSE_TIME; - else if ( strcmp( config.event_close_mode, "alarm" ) == 0 ) - event_close_mode = CLOSE_ALARM; - else - event_close_mode = CLOSE_IDLE; - - Debug( 1, "monitor purpose=%d", purpose ); - + camera = NULL; mem_size = sizeof(SharedData) + sizeof(TriggerData) + sizeof(VideoStoreData) //Information to pass back to the capture process - + (image_buffer_count*sizeof(struct timeval)) - + (image_buffer_count*camera->ImageSize()) + + (image_buffer_count * sizeof(struct timeval)) + + (image_buffer_count * width * height * colours) + 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */ - Debug( 1, "mem.size=%d", mem_size ); + Debug(1, "mem.size SharedData=%d TriggerData=%d VideoStoreData=%d total=%d", + sizeof(SharedData), sizeof(TriggerData), sizeof(VideoStoreData), mem_size); mem_ptr = NULL; - storage = new Storage( storage_id ); - Debug(1, "Storage path: %s", storage->Path() ); + Zone **zones = 0; + int n_zones = Zone::Load(this, zones); + this->AddZones(n_zones, zones); + this->AddPrivacyBitmask(zones); + +// maybe unneeded + storage = new Storage(storage_id); + Debug(1, "Storage path: %s", storage->Path()); // Should maybe store this for later use char monitor_dir[PATH_MAX] = ""; - snprintf( monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id ); - struct stat statbuf; + snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id); - // If we are going to actually do capture, then yes, we should stat this dir, otherwise not - if ( stat( monitor_dir, &statbuf ) ) { - if ( errno == ENOENT || errno == ENOTDIR ) { - if ( mkdir( monitor_dir, 0755 ) ) { - Error( "Can't mkdir %s: %s", monitor_dir, strerror(errno)); - } - } else { - Warning( "Error stat'ing %s, may be fatal. error is %s", monitor_dir, strerror(errno)); - } - } + //this0>delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ), + //ref_image( width, height, p_camera->Colours(), p_camera->SubpixelOrder() ), + Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones); + getCamera(); +} // Monitor::Load - if ( purpose == CAPTURE ) { +Camera * Monitor::getCamera() { + if ( camera ) + return camera; - if ( ! this->connect() ) { - Error("unable to connect, but doing capture"); - exit(-1); - } - memset( mem_ptr, 0, mem_size ); - shared_data->size = sizeof(SharedData); - Debug( 1, "shared.size=%d", shared_data->size ); - shared_data->active = enabled; - shared_data->signal = false; - shared_data->state = IDLE; - shared_data->last_write_index = image_buffer_count; - shared_data->last_read_index = image_buffer_count; - shared_data->last_write_time = 0; - shared_data->last_event_id = 0; - shared_data->action = (Action)0; - shared_data->brightness = -1; - shared_data->hue = -1; - shared_data->colour = -1; - shared_data->contrast = -1; - shared_data->alarm_x = -1; - shared_data->alarm_y = -1; - shared_data->format = camera->SubpixelOrder(); - shared_data->imagesize = camera->ImageSize(); - trigger_data->size = sizeof(TriggerData); - trigger_data->trigger_state = TRIGGER_CANCEL; - trigger_data->trigger_score = 0; - trigger_data->trigger_cause[0] = 0; - trigger_data->trigger_text[0] = 0; - trigger_data->trigger_showtext[0] = 0; - shared_data->valid = true; - video_store_data->recording = (struct timeval){0}; - // Uh, why nothing? Why not NULL? - snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "nothing"); - video_store_data->size = sizeof(VideoStoreData); - //video_store_data->frameNumber = 0; - } + if ( type == LOCAL ) { - //if ( ( ! mem_ptr ) || ! shared_data->valid ) { - //if ( purpose != QUERY ) { - //Error( "Shared data not initialised by capture daemon for monitor %s", name ); - //exit( -1 ); - //} - //} + int extras = (deinterlacing>>24)&0xff; - start_time = last_fps_time = time( 0 ); - - event = 0; - last_section_mod = 0; - pre_event_buffer_count = pre_event_count + alarm_frame_count + warmup_count- 1; - - Debug( 1, "Monitor %s\ - function: %d\ - label_format: '%s', label_x = %d, label_y = %d, label size = %d \ - IBC = %d, WUC = %d, pEC = %d, PEC = %d, EAF = %d, FRI = %d, RBP = %d, ARBP = %d, FM = %d", - name, - function, label_format, label_coord.X(), label_coord.Y(), label_size, - image_buffer_count, warmup_count, - pre_event_count, post_event_count, alarm_frame_count, - fps_report_interval, ref_blend_perc, alarm_ref_blend_perc, track_motion + camera = new LocalCamera( + id, + device, + channel, + format, + v4l_multi_buffer, + v4l_captures_per_frame, + method, + camera_width, + camera_height, + colours, + palette, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio, + extras + ); + } else if ( type == REMOTE ) { + if ( protocol == "http" ) { + camera = new RemoteCameraHttp( + id, + method, + host, + port, + path, + camera_width, + camera_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio ); + } +#if HAVE_LIBAVFORMAT + else if ( protocol == "rtsp" ) { + camera = new RemoteCameraRtsp( + id, + method, + host, // Host + port, // Port + path, // Path + camera_width, + camera_height, + rtsp_describe, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); + } +#endif // HAVE_LIBAVFORMAT + else { + Error( "Unexpected remote camera protocol '%s'", protocol.c_str() ); + } + } else if ( type == FILE ) { + camera = new FileCamera( + id, + path.c_str(), + camera_width, + camera_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); + } else if ( type == FFMPEG ) { +#if HAVE_LIBAVFORMAT + camera = new FfmpegCamera( + id, + path, + method, + options, + camera_width, + camera_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); +#endif // HAVE_LIBAVFORMAT + } else if ( type == NVSOCKET ) { + camera = new RemoteCameraNVSocket( + id, + host.c_str(), + port.c_str(), + path.c_str(), + camera_width, + camera_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); + } else if ( type == LIBVLC ) { +#if HAVE_LIBVLC + camera = new LibvlcCamera( + id, + path.c_str(), + method, + options, + camera_width, + camera_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); +#else // HAVE_LIBVLC + Error( "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(), + camera_width, + camera_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE, + record_audio + ); +#else // HAVE_LIBCURL + Error("You must have libcurl installed to use ffmpeg cameras for monitor %d", id); +#endif // HAVE_LIBCURL + } // end if type - n_linked_monitors = 0; - linked_monitors = 0; + camera->setMonitor(this); +} // end Monitor::getCamera - adaptive_skip = true; +Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) { + std::string sql = load_monitor_sql + stringtf(" WHERE Id=%d", p_id); - ReloadLinkedMonitors( p_linked_monitors ); - videoStore = NULL; -} // Monitor::Monitor + zmDbRow dbrow; + if ( !dbrow.fetch(sql.c_str()) ) { + Error("Can't use query result: %s", mysql_error(&dbconn)); + return NULL; + } + Monitor *monitor = new Monitor(); + monitor->Load(dbrow.mysql_row(),load_zones,purpose); + if ( purpose == CAPTURE ) { + Debug(1,"Connecting"); + if ( ! ( + monitor->getCamera() + && + monitor->connect() + ) ) { + delete monitor; + return NULL; + } + } + + return monitor; +} // end Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) bool Monitor::connect() { - Debug(3, "Connecting to monitor. Purpose is %d", purpose ); + Debug(3, "Connecting to monitor. Purpose is %d", purpose ); #if ZM_MEM_MAPPED - snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id ); - map_fd = open( mem_file, O_RDWR|O_CREAT, (mode_t)0600 ); + snprintf(mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id); + map_fd = open(mem_file, O_RDWR|O_CREAT, (mode_t)0600); if ( map_fd < 0 ) { - Fatal( "Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno) ); + Fatal("Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno)); } else { Debug(3, "Success opening mmap file at (%s)", mem_file ); } @@ -508,19 +787,19 @@ bool Monitor::connect() { } } - Debug(3, "MMap file size is %ld", map_stat.st_size ); + Debug(3, "MMap file size is %ld", map_stat.st_size); #ifdef MAP_LOCKED - mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0 ); + mem_ptr = (unsigned char *)mmap(NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0); if ( mem_ptr == MAP_FAILED ) { if ( errno == EAGAIN ) { - Debug( 1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size ); + Debug(1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size); #endif - mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 ); - Debug( 1, "Mapped file %s (%d bytes) to unlocked memory", mem_file, mem_size ); + mem_ptr = (unsigned char *)mmap(NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); + Debug(1, "Mapped file %s (%d bytes) to unlocked memory", mem_file, mem_size); #ifdef MAP_LOCKED } else { - Error( "Unable to map file %s (%d bytes) to locked memory (%s)", mem_file, mem_size , strerror(errno) ); + Error("Unable to map file %s (%d bytes) to locked memory (%s)", mem_file, mem_size , strerror(errno)); } } #endif @@ -557,7 +836,7 @@ bool Monitor::connect() { shared_images = (uint8_t*)((unsigned long)shared_images + (64 - ((unsigned long)shared_images % 64))); } - Debug(3, "Allocating %d image buffers", image_buffer_count ); + Debug(3, "Allocating %d image buffers", image_buffer_count); image_buffer = new ZMPacket[image_buffer_count]; for ( int i = 0; i < image_buffer_count; i++ ) { image_buffer[i].image_index = i; @@ -571,41 +850,76 @@ bool Monitor::connect() { next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); } + if ( purpose == CAPTURE ) { + memset( mem_ptr, 0, mem_size ); + shared_data->size = sizeof(SharedData); + Debug( 1, "shared.size=%d", shared_data->size ); + shared_data->active = enabled; + shared_data->signal = false; + shared_data->state = IDLE; + shared_data->last_write_index = image_buffer_count; + shared_data->last_read_index = image_buffer_count; + shared_data->last_write_time = 0; + shared_data->last_event_id = 0; + shared_data->action = (Action)0; + shared_data->brightness = -1; + shared_data->hue = -1; + shared_data->colour = -1; + shared_data->contrast = -1; + shared_data->alarm_x = -1; + shared_data->alarm_y = -1; + shared_data->format = camera->SubpixelOrder(); + shared_data->imagesize = camera->ImageSize(); + shared_data->alarm_cause[0] = 0; + trigger_data->size = sizeof(TriggerData); + trigger_data->trigger_state = TRIGGER_CANCEL; + trigger_data->trigger_score = 0; + trigger_data->trigger_cause[0] = 0; + trigger_data->trigger_text[0] = 0; + trigger_data->trigger_showtext[0] = 0; + shared_data->valid = true; + video_store_data->recording = (struct timeval){0}; + // Uh, why nothing? Why not NULL? + snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "nothing"); + video_store_data->size = sizeof(VideoStoreData); + //video_store_data->frameNumber = 0; + } + if ( ( ! mem_ptr ) || ! shared_data->valid ) { + if ( purpose != QUERY ) { + Error("Shared data not initialised by capture daemon for monitor %s", name); + exit(-1); + } + } + Debug(3, "Success connecting"); return true; } // Monitor::connect Monitor::~Monitor() { - if ( videoStore ) { - delete videoStore; - videoStore = NULL; - } - delete packetqueue; - packetqueue = NULL; - if ( timestamps ) { - delete[] timestamps; - timestamps = 0; - } - if ( images ) { - delete[] images; - images = 0; - } - if ( privacy_bitmask ) { - delete[] privacy_bitmask; - privacy_bitmask = NULL; - } if ( mem_ptr ) { if ( event ) { - Info( "%s: image_count:%d - Closing event %d, shutting down", name, image_count, event->Id() ); + Info( "%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name, image_count, event->Id() ); closeEvent(); + + // closeEvent may start another thread to close the event, so wait for it to finish + if ( event_delete_thread ) { + event_delete_thread->join(); + delete event_delete_thread; + event_delete_thread = NULL; + } + } + if ( event_delete_thread ) { + event_delete_thread->join(); + delete event_delete_thread; + event_delete_thread = NULL; } if ( deinterlacing_value == 4 ) { delete next_buffer.image; } #if 1 - for ( int i = 0; i < image_buffer_count; i++ ) { + for ( int i=0; i < image_buffer_count; i++ ) { delete image_buffer[i].image; } #endif @@ -618,15 +932,15 @@ Monitor::~Monitor() { shared_data->last_read_time = 0; } else if ( purpose == CAPTURE ) { shared_data->valid = false; - memset( mem_ptr, 0, mem_size ); + memset(mem_ptr, 0, mem_size); } #if ZM_MEM_MAPPED - if ( msync( mem_ptr, mem_size, MS_SYNC ) < 0 ) - Error( "Can't msync: %s", strerror(errno) ); - if ( munmap( mem_ptr, mem_size ) < 0 ) - Fatal( "Can't munmap: %s", strerror(errno) ); - close( map_fd ); + if ( msync(mem_ptr, mem_size, MS_SYNC) < 0 ) + Error("Can't msync: %s", strerror(errno)); + if ( munmap(mem_ptr, mem_size) < 0 ) + Fatal("Can't munmap: %s", strerror(errno)); + close(map_fd); if ( purpose == CAPTURE ) { // How about we store this in the object on instantiation so that we don't have to do this again. @@ -639,20 +953,41 @@ Monitor::~Monitor() { } #else // ZM_MEM_MAPPED struct shmid_ds shm_data; - if ( shmctl( shm_id, IPC_STAT, &shm_data ) < 0 ) { - Error( "Can't shmctl: %s", strerror(errno) ); - exit( -1 ); + if ( shmctl(shm_id, IPC_STAT, &shm_data) < 0 ) { + Error("Can't shmctl: %s", strerror(errno)); + exit(-1); } if ( shm_data.shm_nattch <= 1 ) { - if ( shmctl( shm_id, IPC_RMID, 0 ) < 0 ) { - Error( "Can't shmctl: %s", strerror(errno) ); - exit( -1 ); + if ( shmctl(shm_id, IPC_RMID, 0) < 0 ) { + Error("Can't shmctl: %s", strerror(errno)); + exit(-1); } } #endif // ZM_MEM_MAPPED } // end if mem_ptr - for ( int i = 0; i < n_zones; i++ ) { + if ( videoStore ) { + delete videoStore; + videoStore = NULL; + } + + if ( timestamps ) { + delete[] timestamps; + timestamps = 0; + } + if ( images ) { + delete[] images; + images = 0; + } + + delete packetqueue; + packetqueue = NULL; + + if ( privacy_bitmask ) { + delete[] privacy_bitmask; + privacy_bitmask = NULL; + } + for ( int i=0; i < n_zones; i++ ) { delete zones[i]; } delete[] zones; @@ -661,29 +996,29 @@ Monitor::~Monitor() { delete storage; } -void Monitor::AddZones( int p_n_zones, Zone *p_zones[] ) { - for ( int i = 0; i < n_zones; i++ ) +void Monitor::AddZones(int p_n_zones, Zone *p_zones[]) { + for ( int i=0; i < n_zones; i++ ) delete zones[i]; delete[] zones; n_zones = p_n_zones; zones = p_zones; } -void Monitor::AddPrivacyBitmask( Zone *p_zones[] ) { +void Monitor::AddPrivacyBitmask(Zone *p_zones[]) { if ( privacy_bitmask ) { delete[] privacy_bitmask; privacy_bitmask = NULL; } Image *privacy_image = NULL; - for ( int i = 0; i < n_zones; i++ ) { + for ( int i=0; i < n_zones; i++ ) { if ( p_zones[i]->IsPrivacy() ) { if ( !privacy_image ) { - privacy_image = new Image( width, height, 1, ZM_SUBPIX_ORDER_NONE); + privacy_image = new Image(width, height, 1, ZM_SUBPIX_ORDER_NONE); privacy_image->Clear(); } - privacy_image->Fill( 0xff, p_zones[i]->GetPolygon() ); - privacy_image->Outline( 0xff, p_zones[i]->GetPolygon() ); + privacy_image->Fill(0xff, p_zones[i]->GetPolygon()); + privacy_image->Outline(0xff, p_zones[i]->GetPolygon()); } } // end foreach zone if ( privacy_image ) @@ -691,7 +1026,7 @@ void Monitor::AddPrivacyBitmask( Zone *p_zones[] ) { } Monitor::State Monitor::GetState() const { - return( (State)shared_data->state ); + return (State)shared_data->state; } int Monitor::GetImage( int index, int scale ) { @@ -724,16 +1059,16 @@ Debug(3, "GetImage"); static char filename[PATH_MAX]; snprintf( filename, sizeof(filename), "Monitor%d.jpg", id ); - image->WriteJpeg( filename ); + image->WriteJpeg(filename); } else { Error( "Unable to generate image, no images in buffer" ); } - return( 0 ); + return 0; } -ZMPacket *Monitor::getSnapshot( int index ) { +ZMPacket *Monitor::getSnapshot(int index) const { - if ( index < 0 || index > image_buffer_count ) { + if ( (index < 0) || (index > image_buffer_count) ) { index = shared_data->last_write_index; } return &image_buffer[index]; @@ -741,8 +1076,8 @@ ZMPacket *Monitor::getSnapshot( int index ) { return NULL; } -struct timeval Monitor::GetTimestamp( int index ) { - ZMPacket *packet = getSnapshot( index ); +struct timeval Monitor::GetTimestamp(int index) const { + ZMPacket *packet = getSnapshot(index); if ( packet ) return *packet->timestamp; @@ -758,8 +1093,8 @@ unsigned int Monitor::GetLastWriteIndex() const { return( shared_data->last_write_index!=(unsigned int)image_buffer_count?shared_data->last_write_index:-1 ); } -uint32_t Monitor::GetLastEventId() const { - Debug(2, "mem_ptr(%x), size(%d) State(%d) last_read_index(%d) last_read_time(%d) last_event(%d)", +uint64_t Monitor::GetLastEventId() const { + Debug(2, "mem_ptr(%x), size(%d) State(%d) last_read_index(%d) last_read_time(%d) last_event(%" PRIu64 ")", mem_ptr, shared_data->size, shared_data->state, @@ -767,7 +1102,7 @@ uint32_t Monitor::GetLastEventId() const { shared_data->last_read_time, shared_data->last_event_id ); - return( shared_data->last_event_id ); + return shared_data->last_event_id; } // This function is crap. @@ -782,7 +1117,7 @@ double Monitor::GetFPS() const { ZMPacket *snap1 = &image_buffer[index1]; if ( !snap1->timestamp->tv_sec ) { // This should be impossible - Warning("Impossible situation. No timestamp on captured image"); + Warning("Impossible situation. No timestamp on captured image index was %d, image-buffer_count was (%d)", index1, image_buffer_count); return 0.0; } struct timeval time1 = *snap1->timestamp; @@ -873,11 +1208,11 @@ void Monitor::actionReload() { void Monitor::actionEnable() { shared_data->action |= RELOAD; - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "update Monitors set Enabled = 1 where Id='%d'", id ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf(sql, sizeof(sql), "UPDATE Monitors SET Enabled = 1 WHERE Id = %d", id); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); } db_mutex.unlock(); } @@ -886,10 +1221,10 @@ void Monitor::actionDisable() { shared_data->action |= RELOAD; static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "update Monitors set Enabled = 0 where Id='%d'", id ); + snprintf(sql, sizeof(sql), "update Monitors set Enabled = 0 where Id = %d", id); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); } db_mutex.unlock(); } @@ -1032,8 +1367,8 @@ void Monitor::DumpZoneImage( const char *zone_string ) { Polygon extra_zone; if ( zone_string ) { - if ( !Zone::ParseZoneString( zone_string, exclude_id, extra_colour, extra_zone ) ) { - Error( "Failed to parse zone string, ignoring" ); + if ( !Zone::ParseZoneString(zone_string, exclude_id, extra_colour, extra_zone) ) { + Error("Failed to parse zone string, ignoring"); } } @@ -1042,29 +1377,31 @@ void Monitor::DumpZoneImage( const char *zone_string ) { Debug(3, "Trying to load from local zmc"); int index = shared_data->last_write_index; ZMPacket *snap = getSnapshot(index); - zone_image = new Image( *snap->image ); + zone_image = new Image(*snap->image); } else { Debug(3, "Trying to load from event"); // Grab the most revent event image - std::string sql = stringtf( "SELECT MAX(Id) FROM Events WHERE MonitorId=%d AND Frames > 0", id ); + std::string sql = stringtf("SELECT MAX(Id) FROM Events WHERE MonitorId=%d AND Frames > 0", id); zmDbRow eventid_row; - if ( eventid_row.fetch( sql.c_str() ) ) { - int event_id = atoi( eventid_row[0] ); + if ( eventid_row.fetch(sql.c_str()) ) { + uint64_t event_id = atoll(eventid_row[0]); - Debug( 3, "Got event %d", event_id ); + Debug(3, "Got event %" PRIu64, event_id); EventStream *stream = new EventStream(); - stream->setStreamStart( event_id, (unsigned int)1 ); + stream->setStreamStart(event_id, (unsigned int)1); zone_image = stream->getImage(); + delete stream; + stream = NULL; } else { - Error("Unable to load an event for monitor %d", id ); + Error("Unable to load an event for monitor %d", id); return; } } - if(zone_image->Colours() == ZM_COLOUR_GRAY8) { - zone_image->Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); + if ( zone_image->Colours() == ZM_COLOUR_GRAY8 ) { + zone_image->Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB); } - + for( int i = 0; i < n_zones; i++ ) { if ( exclude_id && (!extra_colour || extra_zone.getNumCoords()) && zones[i]->Id() == exclude_id ) continue; @@ -1117,11 +1454,11 @@ bool Monitor::CheckSignal( const Image *image ) { static uint8_t red_val; static uint8_t green_val; static uint8_t blue_val; - static uint8_t grayscale_val; /* 8bit grayscale color */ + static uint8_t grayscale_val; /* 8bit grayscale color */ static Rgb colour_val; /* RGB32 color */ static int usedsubpixorder; - if ( config.signal_check_points > 0 ) { + if ( signal_check_points > 0 ) { if ( static_undef ) { static_undef = false; usedsubpixorder = camera->SubpixelOrder(); @@ -1139,8 +1476,9 @@ bool Monitor::CheckSignal( const Image *image ) { int colours = image->Colours(); int index = 0; - for ( int i = 0; i < config.signal_check_points; i++ ) { + for ( int i = 0; i < signal_check_points; i++ ) { while( true ) { + // Why the casting to long long? also note that on a 64bit cpu, long long is 128bits index = (int)(((long long)rand()*(long long)(pixels-1))/RAND_MAX); if ( !config.timestamp_on_capture || !label_format[0] ) break; @@ -1148,15 +1486,15 @@ bool Monitor::CheckSignal( const Image *image ) { if ( index < (label_coord.Y()*width) || index >= (label_coord.Y()+Image::LINE_HEIGHT)*width ) break; } - - if(colours == ZM_COLOUR_GRAY8) { + + if ( colours == ZM_COLOUR_GRAY8 ) { if ( *(buffer+index) != grayscale_val ) return true; - } else if(colours == ZM_COLOUR_RGB24) { + } else if ( colours == ZM_COLOUR_RGB24 ) { const uint8_t *ptr = buffer+(index*colours); - if ( usedsubpixorder == ZM_SUBPIX_ORDER_BGR) { + if ( usedsubpixorder == ZM_SUBPIX_ORDER_BGR ) { if ( (RED_PTR_BGRA(ptr) != red_val) || (GREEN_PTR_BGRA(ptr) != green_val) || (BLUE_PTR_BGRA(ptr) != blue_val) ) return true; } else { @@ -1166,7 +1504,7 @@ bool Monitor::CheckSignal( const Image *image ) { } } else if ( colours == ZM_COLOUR_RGB32 ) { - if ( usedsubpixorder == ZM_SUBPIX_ORDER_ARGB || usedsubpixorder == ZM_SUBPIX_ORDER_ABGR) { + if ( usedsubpixorder == ZM_SUBPIX_ORDER_ARGB || usedsubpixorder == ZM_SUBPIX_ORDER_ABGR ) { if ( ARGB_ABGR_ZEROALPHA(*(((const Rgb*)buffer)+index)) != ARGB_ABGR_ZEROALPHA(colour_val) ) return true; } else { @@ -1175,30 +1513,31 @@ bool Monitor::CheckSignal( const Image *image ) { return true; } } - } - return( false ); - } - return( true ); + } // end for < signal_check_points + Debug(1,"SignalCheck: %d points, colour_val(%d)", signal_check_points, colour_val); + return false; + } // end if signal_check_points + return true; } void Monitor::CheckAction() { struct timeval now; - gettimeofday( &now, NULL ); + gettimeofday(&now, NULL); if ( shared_data->action ) { // Can there be more than 1 bit set in the action? Shouldn't these be elseifs? if ( shared_data->action & RELOAD ) { - Info( "Received reload indication at count %d", image_count ); + Info("Received reload indication at count %d", image_count); shared_data->action &= ~RELOAD; Reload(); } if ( shared_data->action & SUSPEND ) { if ( Active() ) { - Info( "Received suspend indication at count %d", image_count ); + Info("Received suspend indication at count %d", image_count); shared_data->active = false; //closeEvent(); } else { - Info( "Received suspend indication at count %d, but wasn't active", image_count ); + Info("Received suspend indication at count %d, but wasn't active", image_count); } if ( config.max_suspend_time ) { auto_resume_time = now.tv_sec + config.max_suspend_time; @@ -1206,7 +1545,7 @@ void Monitor::CheckAction() { shared_data->action &= ~SUSPEND; } else if ( shared_data->action & RESUME ) { if ( Enabled() && !Active() ) { - Info( "Received resume indication at count %d", image_count ); + Info("Received resume indication at count %d", image_count); shared_data->active = true; ref_image = *(image_buffer[shared_data->last_write_index].image); ready_count = image_count+(warmup_count/2); @@ -1217,7 +1556,7 @@ void Monitor::CheckAction() { } // end if shared_data->action if ( auto_resume_time && (now.tv_sec >= auto_resume_time) ) { - Info( "Auto resuming at count %d", image_count ); + Info("Auto resuming at count %d", image_count); shared_data->active = true; ref_image = *(image_buffer[shared_data->last_write_index].image); ready_count = image_count+(warmup_count/2); @@ -1226,23 +1565,23 @@ void Monitor::CheckAction() { } void Monitor::UpdateAnalysisFPS() { - struct timeval now; - gettimeofday( &now, NULL ); if ( analysis_image_count && fps_report_interval && !(analysis_image_count%fps_report_interval) ) { + struct timeval now; + gettimeofday(&now, NULL); double new_analysis_fps = double(fps_report_interval)/(now.tv_sec - last_analysis_fps_time); Info("%s: %d - Analysing at %.2f fps", name, image_count, new_analysis_fps); if ( new_analysis_fps != analysis_fps ) { analysis_fps = new_analysis_fps; - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, analysis_fps, analysis_fps ); + char sql[ZM_SQL_SML_BUFSIZ]; + snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, analysis_fps, analysis_fps); db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } db_mutex.unlock(); + last_analysis_fps_time = now.tv_sec; } - last_analysis_fps_time = now.tv_sec; } } @@ -1268,22 +1607,29 @@ bool Monitor::Analyse() { ZMPacket *snap; // Is it possible for snap->score to be ! -1? while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) { - snap->lock(); unsigned int index = snap->image_index; Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index); + if ( index == shared_data->last_read_index ) { + Debug(2, "Returning because we are re-analyzing"); + return 0; + } + + snap->lock(); packets_processed += 1; - struct timeval *timestamp = snap->timestamp; - Image *snap_image = snap->image; if ( snap->image_index == -1 ) { snap->unlock(); Debug(2, "skipping because audio"); + // We want to skip, but if we return, we may sleep. + // if ( ! packetqueue->increment_analysis_it() ) { Debug(2, "No more packets to analyse"); return false; } continue; } + struct timeval *timestamp = snap->timestamp; + Image *snap_image = snap->image; // signal is set by capture bool signal = shared_data->signal; @@ -1318,7 +1664,7 @@ bool Monitor::Analyse() { if ( !signal ) { signalText = "Lost"; if ( event ) { - Info( "%s: %03d - Closing event %d, signal loss", name, analysis_image_count, event->Id() ); + Info( "%s: %03d - Closing event %" PRIu64 ", signal loss", name, analysis_image_count, event->Id() ); closeEvent(); last_section_mod = 0; } @@ -1398,7 +1744,7 @@ bool Monitor::Analyse() { Debug( 3, "Section length (%d) Last Section Mod(%d), tv_sec(%d) new section mod(%d)", section_length, last_section_mod, timestamp->tv_sec, section_mod ); // This is not clear, but basically due to pauses, etc we might not get section_mod == 0 if ( ( section_mod < last_section_mod ) && ( timestamp->tv_sec >= 10 ) ) { - Info( "%s: %03d - Closing event %d, section end forced ", name, analysis_image_count, event->Id() ); + Info( "%s: %03d - Closing event %llu, section end forced ", name, analysis_image_count, event->Id() ); closeEvent(); last_section_mod = 0; } else { @@ -1411,8 +1757,21 @@ bool Monitor::Analyse() { // Create event event = new Event( this, *timestamp, "Continuous", noteSetMap ); shared_data->last_event_id = event->Id(); + + // lets construct alarm cause. It will contain cause + names of zones alarmed + std::string alarm_cause="Continuous"; + for ( int i=0; i < n_zones; i++) { + if (zones[i]->Alarmed()) { + alarm_cause += std::string(zones[i]->Label()); + if (i < n_zones-1) { + alarm_cause +=","; + } + } + } + alarm_cause = cause+" "+alarm_cause; + strncpy( shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause) ); video_store_data->recording = event->StartTime(); - Info( "%s: %03d - Opening new event %d, section start", name, analysis_image_count, event->Id() ); + Info( "%s: %03d - Opening new event %" PRIu64 ", section start", name, analysis_image_count, event->Id() ); /* To prevent cancelling out an existing alert\prealarm\alarm state */ if ( state == IDLE ) { shared_data->state = state = TAPE; @@ -1422,34 +1781,46 @@ bool Monitor::Analyse() { if ( score ) { Debug(9, "Score: (%d)", score ); - if ( state == IDLE || state == TAPE || state == PREALARM ) { - if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { - Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); - shared_data->state = state = ALARM; - if ( ! event ) { - event = new Event( this, *timestamp, cause, noteSetMap ); - shared_data->last_event_id = event->Id(); - } - } else if ( state != PREALARM ) { - Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); - shared_data->state = state = PREALARM; - } - } else if ( state == ALERT ) { - Info( "%s: %03d - Gone back into alarm state", name, analysis_image_count ); + if ( state == IDLE || state == TAPE || state == PREALARM ) { + if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { + Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); shared_data->state = state = ALARM; + if ( ! event ) { + // lets construct alarm cause. It will contain cause + names of zones alarmed + std::string alarm_cause=""; + for ( int i=0; i < n_zones; i++) { + if (zones[i]->Alarmed()) { + alarm_cause += std::string(zones[i]->Label()); + if (i < n_zones-1) { + alarm_cause +=","; + } + } + } + alarm_cause = cause+" "+alarm_cause; + strncpy( shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause) ); + event = new Event( this, *timestamp, cause, noteSetMap ); + shared_data->last_event_id = event->Id(); + } + } else if ( state != PREALARM ) { + Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); + shared_data->state = state = PREALARM; } + } else if ( state == ALERT ) { + Info( "%s: %03d - Gone back into alarm state", name, analysis_image_count ); + shared_data->state = state = ALARM; + } last_alarm_count = analysis_image_count; } else { // no score? if ( state == ALARM ) { - Info( "%s: %03d - Gone into alert state", name, analysis_image_count ); + Info("%s: %03d - Gone into alert state", name, analysis_image_count ); shared_data->state = state = ALERT; } else if ( state == ALERT ) { if ( analysis_image_count-last_alarm_count > post_event_count ) { - Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames() ); + Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames() ); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) if ( (function != RECORD && function != MOCORD ) || event_close_mode == CLOSE_ALARM ) { shared_data->state = state = IDLE; - Info( "%s: %03d - Closing event %d, alarm end%s", name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); + Info("%s: %03d - Closing event %" PRIu64 ", alarm end%s", name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); closeEvent(); } else { shared_data->state = state = TAPE; @@ -1501,9 +1872,14 @@ bool Monitor::Analyse() { // Alert means this frame has no motion, but we were alarmed and are still recording. if ( noteSetMap.size() > 0 ) event->updateNotes( noteSetMap ); - } else if ( state == TAPE ) { - if ( !(analysis_image_count%(frame_skip+1)) ) { - } + //} else if ( state == TAPE ) { + //if ( !(analysis_image_count%(frame_skip+1)) ) { + //if ( config.bulk_frame_interval > 1 ) { + //event->AddFrame( snap_image, *timestamp, (event->Frames()AddFrame( snap_image, *timestamp ); + //} + //} } if ( function == MODECT || function == MOCORD ) { ref_image.Blend( *snap_image, ( state==ALARM ? alarm_ref_blend_perc : ref_blend_perc ) ); @@ -1519,7 +1895,7 @@ bool Monitor::Analyse() { } else { Debug(3, "trigger == off"); if ( event ) { - Info( "%s: %03d - Closing event %d, trigger off", name, analysis_image_count, event->Id() ); + Info("%s: %03d - Closing event %" PRIu64 ", trigger off", name, analysis_image_count, event->Id()); closeEvent(); } shared_data->state = state = IDLE; @@ -1534,16 +1910,16 @@ bool Monitor::Analyse() { // We can't just loop here forever, because we may be capturing just as fast, and never leave the loop. // Only loop until we hit the analysis index while ( ( queued_packet = packetqueue->popPacket() ) ) { - Debug(2,"adding packet (%d) qp last_write_index(%d), written(%d)", queued_packet->image_index, last_write, written ); if ( snap == queued_packet ) { - event->AddPacket( queued_packet ); + Debug(2,"adding snap packet (%d) qp last_write_index(%d), written(%d)", queued_packet->image_index, last_write, written ); + event->AddPacket(queued_packet); // Pop may have already incrememented it //packetqueue->increment_analysis_it(); break; } else { queued_packet->lock(); - Debug(2,"adding packet (%d) qp last_write_index(%d), written(%d)", queued_packet->image_index, last_write, written ); - event->AddPacket( queued_packet ); + Debug(2,"adding queued packet (%d) qp last_write_index(%d), written(%d)", queued_packet->image_index, last_write, written ); + event->AddPacket(queued_packet); queued_packet->unlock(); } written ++; @@ -1563,85 +1939,26 @@ bool Monitor::Analyse() { analysis_image_count++; snap->unlock(); } // end while not at end of packetqueue + UpdateAnalysisFPS(); if ( packets_processed > 0 ) return true; return false; } // end Monitor::Analyze void Monitor::Reload() { - Debug( 1, "Reloading monitor %s", name ); + Debug(1, "Reloading monitor %s", name); - if ( event ) - Info( "%s: %03d - Closing event %d, reloading", name, image_count, event->Id() ); - - closeEvent(); - - static char sql[ZM_SQL_MED_BUFSIZ]; - // This seems to have fallen out of date. - snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id ); - - db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - db_mutex.unlock(); - exit( mysql_errno( &dbconn ) ); + if ( event ) { + Info( "%s: %03d - Closing event %" PRIu64 ", reloading", name, image_count, event->Id() ); + closeEvent(); } - MYSQL_RES *result = mysql_store_result( &dbconn ); - db_mutex.unlock(); - if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - int n_monitors = mysql_num_rows( result ); - if ( n_monitors != 1 ) { - Error( "Bogus number of monitors, %d, returned. Can't reload", n_monitors ); - return; - } - - if ( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) { - int index = 0; - function = (Function)atoi(dbrow[index++]); - enabled = atoi(dbrow[index++]); - const char *p_linked_monitors = dbrow[index++]; - - if ( dbrow[index] ) { - strncpy( event_prefix, dbrow[index++], sizeof(event_prefix)-1 ); - } else { - event_prefix[0] = 0; - index++; - } - if ( dbrow[index] ) { - strncpy( label_format, dbrow[index++], sizeof(label_format)-1 ); - } else { - label_format[0] = 0; - index++; - } - - label_coord = Coord( atoi(dbrow[index]), atoi(dbrow[index+1]) ); index += 2; - label_size = atoi(dbrow[index++]); - warmup_count = atoi(dbrow[index++]); - pre_event_count = atoi(dbrow[index++]); - post_event_count = atoi(dbrow[index++]); - alarm_frame_count = atoi(dbrow[index++]); - section_length = atoi(dbrow[index++]); - frame_skip = atoi(dbrow[index++]); - motion_frame_skip = atoi(dbrow[index++]); - analysis_fps = dbrow[index] ? strtod(dbrow[index], NULL) : 0; index++; - analysis_update_delay = strtoul(dbrow[index++], NULL, 0); - capture_delay = (dbrow[index]&&atof(dbrow[index])>0.0)?int(DT_PREC_3/atof(dbrow[index])):0; index++; - alarm_capture_delay = (dbrow[index]&&atof(dbrow[index])>0.0)?int(DT_PREC_3/atof(dbrow[index])):0; index++; - fps_report_interval = atoi(dbrow[index++]); - ref_blend_perc = atoi(dbrow[index++]); - alarm_ref_blend_perc = atoi(dbrow[index++]); - track_motion = atoi(dbrow[index++]); - - - if ( dbrow[index][0] == '#' ) - signal_check_colour = strtol(dbrow[index]+1,0,16); - else - signal_check_colour = strtol(dbrow[index],0,16); - index++; + std::string sql = load_monitor_sql + stringtf(" WHERE Id=%d", id); + zmDbRow *row = zmDbFetchOne(sql.c_str()); + if ( !row ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + } else if ( MYSQL_ROW dbrow = row->mysql_row() ) { + Load(dbrow,1,purpose); shared_data->state = state = IDLE; shared_data->alarm_x = shared_data->alarm_y = -1; @@ -1649,32 +1966,27 @@ void Monitor::Reload() { shared_data->active = true; ready_count = image_count+warmup_count; - ReloadLinkedMonitors( p_linked_monitors ); - } - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - mysql_free_result( result ); + delete row; + } // end if row ReloadZones(); -} +} // void Monitor::Reload() void Monitor::ReloadZones() { - Debug( 1, "Reloading zones for monitor %s", name ); + Debug(1, "Reloading zones for monitor %s", name); for( int i = 0; i < n_zones; i++ ) { delete zones[i]; } delete[] zones; zones = 0; - n_zones = Zone::Load( this, zones ); + n_zones = Zone::Load(this, zones); //DumpZoneImage(); -} +} // end void Monitor::ReloadZones() -void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { - Debug( 1, "Reloading linked monitors for monitor %s, '%s'", name, p_linked_monitors ); +void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { + Debug(1, "Reloading linked monitors for monitor %s, '%s'", name, p_linked_monitors); if ( n_linked_monitors ) { - for( int i = 0; i < n_linked_monitors; i++ ) { + for( int i=0; i < n_linked_monitors; i++ ) { delete linked_monitors[i]; } delete[] linked_monitors; @@ -1686,6 +1998,7 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { int n_link_ids = 0; unsigned int link_ids[256]; + // This nasty code picks out strings of digits from p_linked_monitors and tries to load them. char link_id_str[8]; char *dest_ptr = link_id_str; const char *src_ptr = p_linked_monitors; @@ -1702,8 +2015,8 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { if ( dest_ptr != link_id_str ) { *dest_ptr = '\0'; unsigned int link_id = atoi(link_id_str); - if ( link_id > 0 && link_id != id) { - Debug( 3, "Found linked monitor id %d", link_id ); + if ( link_id > 0 && link_id != id ) { + Debug(3, "Found linked monitor id %d", link_id); int j; for ( j = 0; j < n_link_ids; j++ ) { if ( link_ids[j] == link_id ) @@ -1723,1073 +2036,116 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { break; } if ( n_link_ids > 0 ) { - Debug( 1, "Linking to %d monitors", n_link_ids ); + Debug(1, "Linking to %d monitors", n_link_ids); linked_monitors = new MonitorLink *[n_link_ids]; int count = 0; for ( int i = 0; i < n_link_ids; i++ ) { - Debug( 1, "Checking linked monitor %d", link_ids[i] ); + Debug(1, "Checking linked monitor %d", link_ids[i]); - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id, Name from Monitors where Id = %d and Function != 'None' and Function != 'Monitor' and Enabled = 1", link_ids[i] ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + static char sql[ZM_SQL_SML_BUFSIZ]; + db_mutex.lock(); + snprintf(sql, sizeof(sql), "SELECT Id, Name FROM Monitors WHERE Id = %d AND Function != 'None' AND Function != 'Monitor' AND Enabled = 1", link_ids[i] ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); db_mutex.unlock(); - exit( mysql_errno( &dbconn ) ); + continue; } - MYSQL_RES *result = mysql_store_result( &dbconn ); + MYSQL_RES *result = mysql_store_result(&dbconn); db_mutex.unlock(); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + continue; } - int n_monitors = mysql_num_rows( result ); + int n_monitors = mysql_num_rows(result); if ( n_monitors == 1 ) { - MYSQL_ROW dbrow = mysql_fetch_row( result ); - Debug( 1, "Linking to monitor %d", link_ids[i] ); - linked_monitors[count++] = new MonitorLink( link_ids[i], dbrow[1] ); + MYSQL_ROW dbrow = mysql_fetch_row(result); + Debug(1, "Linking to monitor %d", link_ids[i]); + linked_monitors[count++] = new MonitorLink(link_ids[i], dbrow[1]); } else { - Warning( "Can't link to monitor %d, invalid id, function or not enabled", link_ids[i] ); + Warning("Can't link to monitor %d, invalid id, function or not enabled", link_ids[i]); } - mysql_free_result( result ); - } + mysql_free_result(result); + } // end foreach link_id n_linked_monitors = count; - } + } // end if has link_ids + } // end if p_linked_monitors +} // end void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) + +int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) { + + Debug(1, "Loading Monitors with %s", sql.c_str()); + + MYSQL_RES *result = zmDbFetch(sql.c_str()); + if ( !result ) { + Error("Can't load local monitors: %s", mysql_error(&dbconn)); + return 0; } + int n_monitors = mysql_num_rows(result); + Debug( 1, "Got %d monitors", n_monitors ); + delete[] monitors; + monitors = new Monitor *[n_monitors]; + for( int i=0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + monitors[i] = new Monitor(); + monitors[i]->Load(dbrow, true, purpose); + // need to load zones and set Purpose, 1, purpose); + } + if ( mysql_errno(&dbconn) ) { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + return 0; + } + mysql_free_result(result); + + return n_monitors; } #if ZM_HAS_V4L -int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, 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 += "'"; - } - if ( staticConfig.SERVER_ID ) { - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); - } - Debug( 1, "Loading Local Monitors with %s", sql.c_str() ); +int Monitor::LoadLocalMonitors(const char *device, Monitor **&monitors, Purpose purpose) { - 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 ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { - int col = 0; + std::string sql = load_monitor_sql + " WHERE Function != 'None' AND Type = 'Local'"; - int id = atoi(dbrow[col]); col++; - const char *name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - unsigned int storage_id = atoi(dbrow[col]); col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col]; col++; - - const char *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; - } - } - 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; - } - Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); - col++; - const char *method = dbrow[col] ? 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++; - - int savejpegs = atoi(dbrow[col]); col++; - VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; - bool record_audio = (*dbrow[col] != '0'); 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++; - - const char *event_prefix = dbrow[col] ? dbrow[col] : ""; col++; - const char *label_format = dbrow[col] ? 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 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 extras = (deinterlacing>>24)&0xff; - - Camera *camera = new LocalCamera( - id, - device, - channel, - format, - v4l_multi_buffer, - v4l_captures_per_frame, - method, - width, - height, - colours, - palette, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio, - extras - ); - - monitors[i] = new Monitor( - id, - name, - server_id, - storage_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - colours, - videowriter, - encoderparams, - output_codec, - output_container, - record_audio, - event_prefix, - label_format, - 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 - ); - camera->setMonitor( monitors[i] ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); - } - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); - - return( n_monitors ); + if ( device[0] ) + sql += " AND Device='" + std::string(device) + "'"; + if ( staticConfig.SERVER_ID ) + sql += stringtf(" AND ServerId=%d", staticConfig.SERVER_ID); + return LoadMonitors(sql, monitors, purpose); } #endif // ZM_HAS_V4L -int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, 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 ); - } +int Monitor::LoadRemoteMonitors(const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose) { + std::string sql = load_monitor_sql + " WHERE Function != 'None' AND Type = 'Remote'"; + if ( staticConfig.SERVER_ID ) + sql += stringtf(" AND ServerId=%d", staticConfig.SERVER_ID); - 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 ) ); - } - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { - int col = 0; - - int id = atoi(dbrow[col]); col++; - std::string name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - unsigned int storage_id = atoi(dbrow[col]); col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col]; col++; - - std::string protocol = dbrow[col] ? dbrow[col] : ""; col++; - std::string method = dbrow[col] ? dbrow[col] : ""; col++; - std::string host = dbrow[col] ? dbrow[col] : ""; col++; - std::string port = dbrow[col] ? dbrow[col] : ""; col++; - std::string path = dbrow[col] ? 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] && *dbrow[col] != '0'); col++; - int savejpegs = atoi(dbrow[col]); col++; - VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; - bool record_audio = (*dbrow[col] != '0'); 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++; - - const char *event_prefix = dbrow[col] ? dbrow[col] : ""; col++; - const char *label_format = dbrow[col] ? 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++; - bool embed_exif = (*dbrow[col] != '0'); col++; - - Camera *camera = 0; - if ( protocol == "http" ) { - camera = new RemoteCameraHttp( - id, - method, - host, // Host - port, // Port - path, // Path - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); - } -#if HAVE_LIBAVFORMAT - else if ( protocol == "rtsp" ) { - camera = new RemoteCameraRtsp( - id, - method, - host, // Host - port, // Port - path, // Path - width, - height, - rtsp_describe, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); - } -#endif // HAVE_LIBAVFORMAT - else { - Fatal( "Unexpected remote camera protocol '%s'", protocol.c_str() ); - } - - monitors[i] = new Monitor( - id, - name.c_str(), - server_id, - storage_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - colours, - videowriter, - encoderparams, - output_codec, - output_container, - record_audio, - event_prefix, - label_format, - 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, - RGB_WHITE, - embed_exif, - purpose, - 0, - 0 - ); - camera->setMonitor( monitors[i] ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name.c_str(), n_zones ); - } - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); - - return( n_monitors ); + if ( protocol ) + sql += stringtf(" AND Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path); + return LoadMonitors(sql, monitors, purpose); } int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, 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 += "'"; - } + std::string sql = load_monitor_sql + " WHERE Function != 'None' AND Type = 'File'"; + if ( file[0] ) + sql += " AND Path='" + std::string(file) + "'"; if ( staticConfig.SERVER_ID ) { sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); } - 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 ) ); - exit( mysql_errno( &dbconn ) ); - } - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { - int col = 0; - - int id = atoi(dbrow[col]); col++; - const char *name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - unsigned int storage_id = atoi(dbrow[col]); col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col]; col++; - - const char *path = 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++; - - int savejpegs = atoi(dbrow[col]); col++; - VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col]; col++; - std::string output_codec = dbrow[col]; col++; - std::string output_container = dbrow[col]; col++; - bool record_audio = (*dbrow[col] != '0'); 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++; - - const char *event_prefix = dbrow[col] ? dbrow[col] : ""; col++; - const char *label_format = dbrow[col] ? 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++; - bool embed_exif = (*dbrow[col] != '0'); col++; - - Camera *camera = new FileCamera( - id, - path, // File - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); - - monitors[i] = new Monitor( - id, - name, - server_id, - storage_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - colours, - videowriter, - encoderparams, - output_codec, - output_container, - record_audio, - event_prefix, - label_format, - 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, - embed_exif, - RGB_WHITE, - purpose, - 0, - 0 - ); - camera->setMonitor( monitors[i] ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); - } - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); - - return( n_monitors ); + return LoadMonitors(sql, monitors, purpose); } #if HAVE_LIBAVFORMAT -int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, 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 += "'"; - } +int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose purpose) { + std::string sql = load_monitor_sql + " WHERE Function != 'None' AND Type = 'Ffmpeg'"; + if ( file[0] ) + sql += " AND Path = '" + std::string(file) + "'"; + if ( staticConfig.SERVER_ID ) { - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); + sql += stringtf(" AND ServerId=%d", staticConfig.SERVER_ID); } - 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 ) ); - } - - int n_monitors = mysql_num_rows( result ); - Debug( 1, "Got %d monitors", n_monitors ); - delete[] monitors; - monitors = new Monitor *[n_monitors]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { - int col = 0; - - int id = atoi(dbrow[col]); col++; - const char *name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - unsigned int storage_id = atoi(dbrow[col]); col++; - int function = atoi(dbrow[col]); col++; - int enabled = atoi(dbrow[col]); col++; - const char *linked_monitors = dbrow[col] ? dbrow[col] : ""; col++; - - const char *path = dbrow[col]; col++; - const char *method = dbrow[col] ? dbrow[col] : ""; col++; - const char *options = dbrow[col] ? 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++; - - int savejpegs = atoi(dbrow[col]); col++; - VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; - bool record_audio = (*dbrow[col] != '0'); 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++; - - const char *event_prefix = dbrow[col] ? dbrow[col] : ""; col++; - const char *label_format = dbrow[col] ? 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); - double capture_fps = dbrow[col] ? atof(dbrow[col]) : 0;col++; - int capture_delay = capture_fps >0.0 ?int(DT_PREC_3/capture_fps):0; - double alarm_capture_fps = dbrow[col] ? atof(dbrow[col]) : 0; col++; - int alarm_capture_delay = alarm_capture_fps > 0.0 ?int(DT_PREC_3/alarm_capture_fps):0; - - 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++; - bool embed_exif = (*dbrow[col] != '0'); col++; - - Camera *camera = new FfmpegCamera( - id, - path, // File - method, - options, - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); - - monitors[i] = new Monitor( - id, - name, - server_id, - storage_id, - function, - enabled, - linked_monitors, - camera, - orientation, - deinterlacing, - savejpegs, - colours, - videowriter, - encoderparams, - output_codec, - output_container, - record_audio, - event_prefix, - label_format, - 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, - embed_exif, - RGB_WHITE, - purpose, - 0, - 0 - ); - - camera->setMonitor( monitors[i] ); - Zone **zones = 0; - int n_zones = Zone::Load( monitors[i], zones ); - monitors[i]->AddZones( n_zones, zones ); - monitors[i]->AddPrivacyBitmask( zones ); - Debug( 1, "Loaded monitor %d(%s), %d zones", id, name, n_zones ); - } - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - // Yadda yadda - mysql_free_result( result ); - - return( n_monitors ); + return LoadMonitors(sql, monitors, purpose); } #endif // HAVE_LIBAVFORMAT -Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { - std::string sql = stringtf( "select Id, Name, ServerId, StorageId, 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, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id ); - - zmDbRow dbrow; - if ( ! dbrow.fetch( sql.c_str() ) ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - Monitor *monitor = 0; - unsigned int col = 0; - - unsigned int id = atoi(dbrow[col]); col++; - std::string name = dbrow[col]; col++; - unsigned int server_id = dbrow[col] ? atoi(dbrow[col]) : 0; col++; - unsigned int storage_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] ? dbrow[col] : ""; col++; - - std::string device = dbrow[col] ? 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; - } - } - 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; - } - Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); - col++; - - std::string protocol = dbrow[col] ? dbrow[col] : ""; col++; - std::string method = dbrow[col] ? dbrow[col] : ""; col++; - std::string host = dbrow[col] ? dbrow[col] : ""; col++; - std::string port = dbrow[col] ? dbrow[col] : ""; col++; - std::string path = dbrow[col] ? dbrow[col] : ""; col++; - std::string options = dbrow[col] ? dbrow[col] : ""; col++; - std::string user = dbrow[col] ? dbrow[col] : ""; col++; - std::string pass = dbrow[col] ? 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] && *dbrow[col] != '0'); col++; - int savejpegs = atoi(dbrow[col]); col++; - VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; - bool record_audio = (*dbrow[col] != '0'); 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++; - - const char * event_prefix = dbrow[col] ? dbrow[col] : ""; col++; - const char * label_format = dbrow[col] ? 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 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 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, - width, - height, - colours, - palette, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio, - 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 == "NVSocket" ) { - camera = new RemoteCameraNVSocket( - id, - host.c_str(), - port.c_str(), - path.c_str(), - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); - } else if ( type == "Remote" ) { - if ( protocol == "http" ) { - camera = new RemoteCameraHttp( - id, - method.c_str(), - host.c_str(), - port.c_str(), - path.c_str(), - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); - } else if ( protocol == "rtsp" ) { -#if HAVE_LIBAVFORMAT - camera = new RemoteCameraRtsp( - id, - method.c_str(), - host.c_str(), - port.c_str(), - path.c_str(), - width, - height, - rtsp_describe, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); -#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(), - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); - } else if ( type == "Ffmpeg" ) { -#if HAVE_LIBAVFORMAT - camera = new FfmpegCamera( - id, - path.c_str(), - method, - options, - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); -#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, - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); -#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(), - width, - height, - colours, - brightness, - contrast, - hue, - colour, - purpose==CAPTURE, - record_audio - ); -#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, - storage_id, - function, - enabled, - linked_monitors.c_str(), - camera, - orientation, - deinterlacing, - savejpegs, - colours, - videowriter, - encoderparams, - output_codec, - output_container, - record_audio, - event_prefix, - label_format, - 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 - - ); - - camera->setMonitor( monitor ); - - 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 ); -} - /* Returns 0 on success, even if no new images are available (transient error) * Returns -1 on failure. */ @@ -2812,7 +2168,9 @@ int Monitor::Capture() { } ZMPacket *packet = &image_buffer[index]; + Debug(2,"before lock"); packet->lock(); + Debug(2,"before reset"); packet->reset(); Image* capture_image = packet->image; int captureResult = 0; @@ -2820,20 +2178,23 @@ int Monitor::Capture() { if ( deinterlacing_value == 4 ) { if ( FirstCapture != 1 ) { /* Copy the next image into the shared memory */ - capture_image->CopyBuffer(*(next_buffer.image)); + capture_image->CopyBuffer(*(next_buffer.image)); } /* Capture a new next image */ captureResult = camera->Capture(*packet); gettimeofday( packet->timestamp, NULL ); if ( FirstCapture ) { + packet->unlock(); FirstCapture = 0; return 0; } } else { + Debug(4, "Capturing"); captureResult = camera->Capture(*packet); gettimeofday( packet->timestamp, NULL ); if ( captureResult < 0 ) { + Debug(2,"failed capture"); // Unable to capture image for temporary reason // Fake a signal loss image Rgb signalcolor; @@ -2841,11 +2202,18 @@ int Monitor::Capture() { signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); capture_image->Fill(signalcolor); shared_data->signal = false; + shared_data->last_write_index = index; + shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; + image_count++; packet->unlock(); + // What about timestamping it? + // Don't want to do analysis on it, but we won't due to signal return -1; } else if ( captureResult > 0 ) { // Analysis thread will take care of consuming and emptying the packets. + Debug(2, "Have packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ", + packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) ); if ( packet->packet.stream_index != video_stream_id ) { Debug(2, "Have audio packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ", @@ -2854,14 +2222,14 @@ int Monitor::Capture() { mutex.lock(); if ( packetqueue->video_packet_count || event ) { // Need to copy it into another ZMPacket. - ZMPacket *audio_packet = new ZMPacket( *packet ); + ZMPacket *audio_packet = new ZMPacket(*packet); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; #else audio_packet->codec_type = camera->get_AudioStream()->codec->codec_type; #endif Debug(2, "Queueing packet"); - packetqueue->queuePacket( audio_packet ); + packetqueue->queuePacket(audio_packet); } // Don't update last_write_index because that is used for live streaming //shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; @@ -2877,13 +2245,14 @@ int Monitor::Capture() { packet->codec_type = camera->get_VideoStream()->codec->codec_type; #endif - if ( packet->packet.size && ! packet->in_frame ) { + if ( packet->packet.size && !packet->in_frame ) { //Debug(2,"About to decode"); - if ( packet->decode( camera->get_VideoCodecContext() ) ) { + if ( packet->decode(camera->get_VideoCodecContext()) ) { //Debug(2,"Getimage"); packet->get_image(); } // Have an av_packet, + Debug(2,"Before mutex lock"); mutex.lock(); if ( packetqueue->video_packet_count || packet->keyframe || event ) { Debug(2, "Have video packet for index (%d)", index ); @@ -2896,7 +2265,7 @@ int Monitor::Capture() { mutex.lock(); // Non-avpackets are all keyframes. Debug(2, "Queueing decoded video packet"); - packetqueue->queuePacket( packet ); + packetqueue->queuePacket(packet); mutex.unlock(); } @@ -2930,7 +2299,7 @@ int Monitor::Capture() { capture_image->Flip( orientation==FLIP_HORI ); break; } - } + } // end if have rotation if ( privacy_bitmask ) capture_image->MaskPrivacy( privacy_bitmask ); @@ -2939,27 +2308,32 @@ int Monitor::Capture() { TimestampImage( capture_image, packet->timestamp ); } - shared_data->signal = CheckSignal(capture_image); + shared_data->signal = signal_check_points ? CheckSignal(capture_image) : true; shared_data->last_write_index = index; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; image_count++; packet->unlock(); - if ( fps_report_interval && !(image_count%fps_report_interval) ) { + if ( fps_report_interval && ( !(image_count%fps_report_interval) || image_count == 5 ) ) { time_t now = image_buffer[index].timestamp->tv_sec; // If we are too fast, we get div by zero. This seems to happen in the case of audio packets. if ( now != last_fps_time ) { // # of images per interval / the amount of time it took - double new_capture_fps = double(fps_report_interval)/(now-last_fps_time); + double new_capture_fps = double((image_count < fps_report_interval ? image_count : fps_report_interval))/(now-last_fps_time); + unsigned int new_camera_bytes = camera->Bytes(); + unsigned int new_capture_bandwidth = (new_camera_bytes - last_camera_bytes)/(now-last_fps_time); + last_camera_bytes = new_camera_bytes; //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info("%s: %d - Capturing at %.2lf fps", name, image_count, new_capture_fps); + Info("%s: images:%d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec", name, image_count, new_capture_fps, new_capture_bandwidth); if ( new_capture_fps != capture_fps ) { capture_fps = new_capture_fps; last_fps_time = now; static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, capture_fps, capture_fps); db_mutex.lock(); + snprintf(sql, sizeof(sql), + "INSERT INTO Monitor_Status (MonitorId,CaptureFPS,CaptureBandwidth) VALUES (%d, %.2lf,%u) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf, CaptureBandwidth=%u", + id, capture_fps, new_capture_bandwidth, capture_fps, new_capture_bandwidth); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } @@ -2975,6 +2349,7 @@ int Monitor::Capture() { } // end if result } // end if deinterlacing + // Icon: I'm not sure these should be here. They have nothing to do with capturing if ( shared_data->action & GET_SETTINGS ) { shared_data->brightness = camera->Brightness(); @@ -3034,14 +2409,28 @@ void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) c bool Monitor::closeEvent() { if ( event ) { if ( function == RECORD || function == MOCORD ) { - gettimeofday( &(event->EndTime()), NULL ); + gettimeofday(&(event->EndTime()), NULL); } + if ( event_delete_thread ) { + event_delete_thread->join(); + delete event_delete_thread; + event_delete_thread = NULL; + } +#if 0 + event_delete_thread = new std::thread([](Event *event) { + Event * e = event; + event = NULL; + delete e; + e = NULL; + }, event); +#else delete event; + event = NULL; +#endif video_store_data->recording = (struct timeval){0}; - event = 0; - return( true ); + return true; } - return( false ); + return false; } unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet ) { @@ -3112,7 +2501,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z } else { zone->ClearAlarm(); } - } + } } } @@ -3197,7 +2586,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z // This is a small and innocent hack to prevent scores of 0 being returned in alarm state return( score?score:alarm ); -} +} bool Monitor::DumpSettings( char *output, bool verbose ) { output[0] = 0; @@ -3232,25 +2621,25 @@ bool Monitor::DumpSettings( char *output, bool verbose ) { sprintf( output+strlen(output), "Palette : %d\n", ((LocalCamera *)camera)->Palette() ); } #endif // ZM_HAS_V4L - sprintf( output+strlen(output), "Colours : %d\n", camera->Colours() ); - sprintf( output+strlen(output), "Subpixel Order : %d\n", camera->SubpixelOrder() ); - sprintf( output+strlen(output), "Event Prefix : %s\n", event_prefix ); - sprintf( output+strlen(output), "Label Format : %s\n", label_format ); - sprintf( output+strlen(output), "Label Coord : %d,%d\n", label_coord.X(), label_coord.Y() ); - sprintf( output+strlen(output), "Label Size : %d\n", label_size ); - sprintf( output+strlen(output), "Image Buffer Count : %d\n", image_buffer_count ); - sprintf( output+strlen(output), "Warmup Count : %d\n", warmup_count ); - sprintf( output+strlen(output), "Pre Event Count : %d\n", pre_event_count ); - sprintf( output+strlen(output), "Post Event Count : %d\n", post_event_count ); - sprintf( output+strlen(output), "Stream Replay Buffer : %d\n", stream_replay_buffer ); - sprintf( output+strlen(output), "Alarm Frame Count : %d\n", alarm_frame_count ); - sprintf( output+strlen(output), "Section Length : %d\n", section_length ); - sprintf( output+strlen(output), "Maximum FPS : %.2f\n", capture_delay?(double)DT_PREC_3/capture_delay:0.0 ); - sprintf( output+strlen(output), "Alarm Maximum FPS : %.2f\n", alarm_capture_delay?(double)DT_PREC_3/alarm_capture_delay:0.0 ); - sprintf( output+strlen(output), "Reference Blend %%ge : %d\n", ref_blend_perc ); - sprintf( output+strlen(output), "Alarm Reference Blend %%ge : %d\n", alarm_ref_blend_perc ); - sprintf( output+strlen(output), "Track Motion : %d\n", track_motion ); - sprintf( output+strlen(output), "Function: %d - %s\n", function, + sprintf(output+strlen(output), "Colours : %d\n", camera->Colours() ); + sprintf(output+strlen(output), "Subpixel Order : %d\n", camera->SubpixelOrder() ); + sprintf(output+strlen(output), "Event Prefix : %s\n", event_prefix ); + sprintf(output+strlen(output), "Label Format : %s\n", label_format ); + sprintf(output+strlen(output), "Label Coord : %d,%d\n", label_coord.X(), label_coord.Y() ); + sprintf(output+strlen(output), "Label Size : %d\n", label_size ); + sprintf(output+strlen(output), "Image Buffer Count : %d\n", image_buffer_count ); + sprintf(output+strlen(output), "Warmup Count : %d\n", warmup_count ); + sprintf(output+strlen(output), "Pre Event Count : %d\n", pre_event_count ); + sprintf(output+strlen(output), "Post Event Count : %d\n", post_event_count ); + sprintf(output+strlen(output), "Stream Replay Buffer : %d\n", stream_replay_buffer ); + sprintf(output+strlen(output), "Alarm Frame Count : %d\n", alarm_frame_count ); + sprintf(output+strlen(output), "Section Length : %d\n", section_length); + sprintf(output+strlen(output), "Maximum FPS : %.2f\n", capture_delay?(double)DT_PREC_3/capture_delay:0.0); + sprintf(output+strlen(output), "Alarm Maximum FPS : %.2f\n", alarm_capture_delay?(double)DT_PREC_3/alarm_capture_delay:0.0); + sprintf(output+strlen(output), "Reference Blend %%ge : %d\n", ref_blend_perc); + sprintf(output+strlen(output), "Alarm Reference Blend %%ge : %d\n", alarm_ref_blend_perc); + sprintf(output+strlen(output), "Track Motion : %d\n", track_motion); + sprintf(output+strlen(output), "Function: %d - %s\n", function, function==NONE?"None":( function==MONITOR?"Monitor Only":( function==MODECT?"Motion Detection":( @@ -3258,31 +2647,31 @@ bool Monitor::DumpSettings( char *output, bool verbose ) { function==MOCORD?"Continuous Record with Motion Detection":( function==NODECT?"Externally Triggered only, no Motion Detection":"Unknown" )))))); - sprintf( output+strlen(output), "Zones : %d\n", n_zones ); + sprintf(output+strlen(output), "Zones : %d\n", n_zones ); for ( int i = 0; i < n_zones; i++ ) { - zones[i]->DumpSettings( output+strlen(output), verbose ); + zones[i]->DumpSettings(output+strlen(output), verbose); } - return( true ); -} // bool Monitor::DumpSettings( char *output, bool verbose ) + return true; +} // bool Monitor::DumpSettings(char *output, bool verbose) -unsigned int Monitor::Colours() const { return( camera->Colours() ); } -unsigned int Monitor::SubpixelOrder() const { return( camera->SubpixelOrder() ); } +unsigned int Monitor::Colours() const { return camera->Colours(); } +unsigned int Monitor::SubpixelOrder() const { return camera->SubpixelOrder(); } int Monitor::PrimeCapture() { int ret = camera->PrimeCapture(); if ( ret == 0 ) { + if ( packetqueue ) + delete packetqueue; video_stream_id = camera->get_VideoStreamId(); - packetqueue = new zm_packetqueue( image_buffer_count, video_stream_id ); + packetqueue = new zm_packetqueue(image_buffer_count, video_stream_id); } - Debug(2, "Video stream id is (%d), minimum_packets to keep in buffer(%d)", video_stream_id, pre_event_buffer_count ); + Debug(2, "Video stream id is (%d), minimum_packets to keep in buffer(%d)", video_stream_id, pre_event_buffer_count); return ret; } -int Monitor::PreCapture() { - return camera->PreCapture(); -} -int Monitor::PostCapture() { - return camera->PostCapture(); -} + +int Monitor::PreCapture() const { return camera->PreCapture(); } +int Monitor::PostCapture() const { return camera->PostCapture() ; } +int Monitor::Close() { return camera->Close(); }; Monitor::Orientation Monitor::getOrientation() const { return orientation; } // Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup. @@ -3300,8 +2689,42 @@ void Monitor::get_ref_image() { return; int last_write_index = shared_data->last_write_index ; - Warning( "Waiting for capture daemon unlock" ); + Warning("Waiting for capture daemon unlock"); image_buffer[last_write_index].mutex.lock(); - ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[last_write_index].image->Buffer(), camera->ImageSize()); + ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[last_write_index].image->Buffer(), camera->ImageSize()); image_buffer[last_write_index].mutex.unlock(); } + +std::vector Monitor::Groups() { + // At the moment, only load groups once. + if ( ! groups.size() ) { + std::string sql = stringtf( + "SELECT Id,ParentId,Name FROM Groups WHERE Groups.Id IN " + "(SELECT GroupId FROM Groups_Monitors WHERE MonitorId=%d)",id); + MYSQL_RES *result = zmDbFetch(sql.c_str()); + if ( !result ) { + Error("Can't load groups: %s", mysql_error(&dbconn)); + return groups; + } + int n_groups = mysql_num_rows(result); + Debug(1, "Got %d groups", n_groups); + while ( MYSQL_ROW dbrow = mysql_fetch_row(result) ) { + groups.push_back(new Group(dbrow)); + } + if ( mysql_errno(&dbconn) ) { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + } + mysql_free_result(result); + } + return groups; +} + +StringVector Monitor::GroupNames() { + StringVector groupnames; + for(Group * g: Groups()) { + groupnames.push_back(std::string(g->Name())); +Debug(1,"Groups: %s", g->Name()); + } + return groupnames; +} + diff --git a/src/zm_monitor.h b/src/zm_monitor.h index d35d8e30d..c2905f0d3 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -1,27 +1,28 @@ // // ZoneMinder Monitor Class Interfaces, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// #ifndef ZM_MONITOR_H #define ZM_MONITOR_H #include #include +#include #include "zm.h" #include "zm_coord.h" @@ -34,6 +35,7 @@ #include "zm_thread.h" class Monitor; +#include "zm_group.h" #include "zm_camera.h" #include "zm_storage.h" #include "zm_utils.h" @@ -70,7 +72,17 @@ public: NODECT } Function; - typedef enum { + typedef enum { + LOCAL, + REMOTE, + FILE, + FFMPEG, + LIBVLC, + CURL, + NVSOCKET, + } CameraType; + + typedef enum { ROTATE_0=1, ROTATE_90, ROTATE_180, @@ -103,41 +115,43 @@ protected: /* sizeof(SharedData) expected to be 344 bytes on 32bit and 64bit */ typedef struct { uint32_t size; /* +0 */ - uint32_t last_write_index; /* +4 */ + uint32_t last_write_index; /* +4 */ uint32_t last_read_index; /* +8 */ uint32_t state; /* +12 */ - uint32_t last_event_id; /* +16 */ - uint32_t action; /* +20 */ - int32_t brightness; /* +24 */ - int32_t hue; /* +28 */ - int32_t colour; /* +32 */ - int32_t contrast; /* +36 */ - int32_t alarm_x; /* +40 */ - int32_t alarm_y; /* +44 */ - uint8_t valid; /* +48 */ - uint8_t active; /* +49 */ - uint8_t signal; /* +50 */ - uint8_t format; /* +51 */ - uint32_t imagesize; /* +52 */ - uint32_t epadding1; /* +56 */ - uint32_t epadding2; /* +60 */ - /* + uint64_t last_event_id; /* +16 */ + uint32_t action; /* +24 */ + int32_t brightness; /* +28 */ + int32_t hue; /* +32 */ + int32_t colour; /* +36 */ + int32_t contrast; /* +40 */ + int32_t alarm_x; /* +44 */ + int32_t alarm_y; /* +48 */ + uint8_t valid; /* +52 */ + uint8_t active; /* +53 */ + uint8_t signal; /* +54 */ + uint8_t format; /* +55 */ + uint32_t imagesize; /* +56 */ + uint32_t epadding1; /* +60 */ + uint32_t epadding2; /* +64 */ + /* ** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038. ** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16. - */ - union { /* +64 */ + */ + union { /* +68 */ time_t startup_time; /* When the zmc process started. zmwatch uses this to see how long the process has been running without getting any images */ uint64_t extrapad1; }; - union { /* +72 */ + union { /* +76 */ time_t last_write_time; uint64_t extrapad2; }; - union { /* +80 */ + union { /* +84 */ time_t last_read_time; uint64_t extrapad3; }; - uint8_t control_state[256]; /* +88 */ + uint8_t control_state[256]; /* +92 */ + + char alarm_cause[256]; } SharedData; @@ -158,7 +172,7 @@ protected: //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit typedef struct { uint32_t size; - uint32_t current_event; + uint64_t current_event; char event_file[4096]; timeval recording; // used as both bool and a pointer to the timestamp when recording should begin } VideoStoreData; @@ -188,27 +202,18 @@ protected: volatile TriggerData *trigger_data; volatile VideoStoreData *video_store_data; - int last_state; - int last_event_id; + uint64_t last_event_id; public: MonitorLink( int p_id, const char *p_name ); ~MonitorLink(); - inline int Id() const { - return( id ); - } - inline const char *Name() const { - return( name ); - } + inline int Id() const { return id; } + inline const char *Name() const { return name; } - inline bool isConnected() const { - return( connected ); - } - inline time_t getLastConnectTime() const { - return( last_connect_time ); - } + inline bool isConnected() const { return connected; } + inline time_t getLastConnectTime() const { return last_connect_time; } bool connect(); bool disconnect(); @@ -221,11 +226,29 @@ protected: protected: // These are read from the DB and thereafter remain unchanged unsigned int id; - char name[64]; + char name[64]; unsigned int server_id; // Id of the Server object unsigned int storage_id; // Id of the Storage Object, which currently will just provide a path, but in future may do more. + CameraType type; Function function; // What the monitor is doing bool enabled; // Whether the monitor is enabled or asleep + + std::string protocol; + std::string method; + std::string options; + std::string host; + std::string port; + std::string user; + std::string pass; + std::string path; + + char device[64]; + int palette; + int channel; + int format; + + unsigned int camera_width; + unsigned int camera_height; unsigned int width; // Normally the same as the camera, but not if partly rotated unsigned int height; // Normally the same as the camera, but not if partly rotated bool v4l_multi_buffer; @@ -234,21 +257,26 @@ protected: unsigned int deinterlacing; unsigned int deinterlacing_value; bool videoRecording; + bool rtsp_describe; - int savejpegspref; + int savejpegs; int colours; VideoWriter videowriter; std::string encoderparams; - std::string output_codec; + int output_codec; + std::string encoder; std::string output_container; std::vector encoderparamsvec; _AVPIXELFORMAT imagePixFormat; unsigned int subpixelorder; bool record_audio; // Whether to store the audio that we receive + + int brightness; // The statically saved brightness of the camera int contrast; // The statically saved contrast of the camera int hue; // The statically saved hue of the camera int colour; // The statically saved colour of the camera + char event_prefix[64]; // The prefix applied to event names as they are created char label_format[64]; // The format of the timestamp on the images Coord label_coord; // The coordinates of the timestamp on the images @@ -273,12 +301,15 @@ protected: int ref_blend_perc; // Percentage of new image going into reference image. int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm. bool track_motion; // Whether this monitor tries to track detected motion + int signal_check_points; // Number of points in the image to check for signal Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected bool embed_exif; // Whether to embed Exif data into each image frame or not double capture_fps; // Current capturing fps double analysis_fps; // Current analysis fps + unsigned int last_camera_bytes; + Image delta_image; Image ref_image; Image alarm_image; // Used in creating analysis images, will be initialized in Analysis @@ -292,7 +323,7 @@ protected: int first_alarm_count; int last_alarm_count; bool last_signal; - int last_section_mod; + int last_section_mod; int buffer_count; int prealarm_count; State state; @@ -312,21 +343,20 @@ protected: #endif // ZM_MEM_MAPPED off_t mem_size; unsigned char *mem_ptr; - Storage *storage; - SharedData *shared_data; TriggerData *trigger_data; VideoStoreData *video_store_data; - struct timeval *shared_timestamps; - unsigned char *shared_images; + struct timeval *shared_timestamps; + unsigned char *shared_images; ZMPacket *image_buffer; ZMPacket next_buffer; /* Used by four field deinterlacing */ int video_stream_id; // will be filled in PrimeCapture Camera *camera; - Event *event; + Event *event; + Storage *storage; int n_zones; Zone **zones; @@ -335,60 +365,19 @@ protected: Image **images; const unsigned char *privacy_bitmask; + std::thread *event_delete_thread; // Used to close events, but continue processing. int n_linked_monitors; MonitorLink **linked_monitors; + std::vector groups; + public: - explicit Monitor( int p_id ); + explicit Monitor(); + explicit Monitor(int p_id); // 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, - unsigned int p_server_id, - unsigned int p_storage_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_colours, - VideoWriter p_videowriter, - std::string &p_encoderparams, - std::string &p_output_codec, - std::string &p_output_container, - bool p_record_audio, - 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[] ); @@ -398,37 +387,31 @@ public: inline int ShmValid() const { return( shared_data->valid ); } + Camera *getCamera(); - inline int Id() const { - return( id ); - } - inline const char *Name() const { - return( name ); - } + inline int Id() const { return id; } + inline const char *Name() const { return name; } inline Storage *getStorage() { if ( ! storage ) { - storage = new Storage( storage_id ); + storage = new Storage(storage_id); } - return( storage ); + return storage; } inline Function GetFunction() const { - return( function ); - } - inline Camera *getCamera() { - return camera; + return function; } inline bool Enabled() { if ( function <= MONITOR ) - return( false ); - return( enabled ); + return false; + return enabled; } inline const char *EventPrefix() const { - return( event_prefix ); + return event_prefix; } inline bool Ready() { if ( function <= MONITOR ) { Error("Should not be calling Ready if the function doesn't include motion detection"); - return( false ); + return false; } if ( image_count >= ready_count ) { return true; @@ -438,57 +421,60 @@ public: } inline bool Active() { if ( function <= MONITOR ) - return( false ); + return false; return( enabled && shared_data->active ); } inline bool Exif() { - return( embed_exif ); + return embed_exif; } inline bool RecordAudio() { return record_audio; } + + /* + inline Purpose Purpose() { return purpose }; + inline Purpose Purpose( Purpose p ) { purpose = p; }; + */ + Orientation getOrientation() const; unsigned int Width() const { return width; } unsigned int Height() const { return height; } unsigned int Colours() const; unsigned int SubpixelOrder() const; - - int GetOptSaveJPEGs() const { return( savejpegspref ); } - VideoWriter GetOptVideoWriter() const { return( videowriter ); } - const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } - const std::string &GetEncoderOptions() const { return( encoderparams ); } - const std::string &OutputCodec() const { return output_codec; } + + int GetOptSaveJPEGs() const { return savejpegs; } + VideoWriter GetOptVideoWriter() const { return videowriter; } + const std::vector* GetOptEncoderParams() const { return &encoderparamsvec; } + const std::string &GetEncoderOptions() const { return encoderparams; } + const int OutputCodec() const { return output_codec; } + const std::string &Encoder() const { return encoder; } const std::string &OutputContainer() const { return output_container; } - uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; } - void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; } - + uint64_t GetVideoWriterEventId() const { return video_store_data->current_event; } + void SetVideoWriterEventId( uint64_t p_event_id ) { video_store_data->current_event = p_event_id; } + unsigned int GetPreEventCount() const { return pre_event_count; }; State GetState() const; int GetImage( int index=-1, int scale=100 ); - ZMPacket *getSnapshot( int index=-1 ); - struct timeval GetTimestamp( int index=-1 ); + ZMPacket *getSnapshot( int index=-1 ) const; + struct timeval GetTimestamp( int index=-1 ) const; void UpdateAdaptiveSkip(); useconds_t GetAnalysisRate(); - unsigned int GetAnalysisUpdateDelay() const { return( analysis_update_delay ); } - int GetCaptureDelay() const { return( capture_delay ); } - int GetAlarmCaptureDelay() const { return( alarm_capture_delay ); } + unsigned int GetAnalysisUpdateDelay() const { return analysis_update_delay; } + int GetCaptureDelay() const { return capture_delay; } + int GetAlarmCaptureDelay() const { return alarm_capture_delay; } unsigned int GetLastReadIndex() const; unsigned int GetLastWriteIndex() const; - uint32_t GetLastEventId() const; + uint64_t GetLastEventId() const; double GetFPS() const; void UpdateAnalysisFPS(); void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" ); void ForceAlarmOff(); void CancelForced(); - TriggerState GetTriggerState() const { return( (TriggerState)(trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL )); } - inline time_t getStartupTime() const { - return( shared_data->startup_time ); - } - inline void setStartupTime( time_t p_time ) { - shared_data->startup_time = p_time; - } + TriggerState GetTriggerState() const { return (TriggerState)(trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL); } + inline time_t getStartupTime() const { return shared_data->startup_time; } + inline void setStartupTime( time_t p_time ) { shared_data->startup_time = p_time; } void get_ref_image(); void actionReload(); @@ -503,9 +489,10 @@ public: int actionContrast( int p_contrast=-1 ); int PrimeCapture(); - int PreCapture(); + int PreCapture() const; int Capture(); - int PostCapture(); + int PostCapture() const; + int Close(); void CheckAction(); @@ -524,16 +511,20 @@ public: bool DumpSettings( char *output, bool verbose ); void DumpZoneImage( const char *zone_string=0 ); + std::vector Groups(); + StringVector GroupNames(); + static int LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose); // Returns # of Monitors loaded, 0 on failure. #if ZM_HAS_V4L - static int LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ); + static int LoadLocalMonitors(const char *device, Monitor **&monitors, Purpose purpose); #endif // ZM_HAS_V4L - static int LoadRemoteMonitors( const char *protocol, const char *host, const char*port, const char*path, Monitor **&monitors, Purpose purpose ); - static int LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ); + static int LoadRemoteMonitors(const char *protocol, const char *host, const char*port, const char*path, Monitor **&monitors, Purpose purpose); + static int LoadFileMonitors(const char *file, Monitor **&monitors, Purpose purpose); #if HAVE_LIBAVFORMAT - static int LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ); + static int LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose purpose); #endif // HAVE_LIBAVFORMAT - static Monitor *Load( unsigned int id, bool load_zones, Purpose purpose ); + static Monitor *Load(unsigned int id, bool load_zones, Purpose purpose); + void Load(MYSQL_ROW dbrow, 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_monitorstream.cpp b/src/zm_monitorstream.cpp index ae1c2743f..978dda890 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -27,28 +27,28 @@ #include #include -bool MonitorStream::checkSwapPath( const char *path, bool create_path ) { +bool MonitorStream::checkSwapPath(const char *path, bool create_path) { struct stat stat_buf; - if ( stat( path, &stat_buf ) < 0 ) { + if ( stat(path, &stat_buf) < 0 ) { if ( create_path && errno == ENOENT ) { - Debug( 3, "Swap path '%s' missing, creating", path ); - if ( mkdir( path, 0755 ) ) { - Error( "Can't mkdir %s: %s", path, strerror(errno)); - return( false ); + Debug(3, "Swap path '%s' missing, creating", path); + if ( mkdir(path, 0755) ) { + Error("Can't mkdir %s: %s", path, strerror(errno)); + return false; } - if ( stat( path, &stat_buf ) < 0 ) { - Error( "Can't stat '%s': %s", path, strerror(errno) ); - return( false ); + if ( stat(path, &stat_buf) < 0 ) { + Error("Can't stat '%s': %s", path, strerror(errno)); + return false; } } else { - Error( "Can't stat '%s': %s", path, strerror(errno) ); - return( false ); + Error("Can't stat '%s': %s", path, strerror(errno)); + return false; } } if ( !S_ISDIR(stat_buf.st_mode) ) { - Error( "Swap image path '%s' is not a directory", path ); - return( false ); + Error("Swap image path '%s' is not a directory", path); + return false; } uid_t uid = getuid(); @@ -67,73 +67,51 @@ bool MonitorStream::checkSwapPath( const char *path, bool create_path ) { } if ( (stat_buf.st_mode & mask) != mask ) { - Error( "Insufficient permissions on swap image path '%s'", path ); - return( false ); + Error("Insufficient permissions on swap image path '%s'", path); + return false; } - return( true ); + return true; } // end bool MonitorStream::checkSwapPath( const char *path, bool create_path ) -void MonitorStream::processCommand( const CmdMsg *msg ) { +void MonitorStream::processCommand(const CmdMsg *msg) { Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ); // Check for incoming command switch( (MsgCommand)msg->msg_data[0] ) { case CMD_PAUSE : - { - Debug( 1, "Got PAUSE command" ); - - // Set paused flag + Debug(1, "Got PAUSE command"); paused = true; - // Set delayed flag delayed = true; - last_frame_sent = TV_2_FLOAT( now ); + last_frame_sent = TV_2_FLOAT(now); break; - } case CMD_PLAY : - { - Debug( 1, "Got PLAY command" ); + Debug(1, "Got PLAY command"); if ( paused ) { - // Clear paused flag paused = false; - // Set delayed_play flag delayed = true; } replay_rate = ZM_RATE_BASE; break; - } case CMD_VARPLAY : - { - Debug( 1, "Got VARPLAY command" ); + Debug(1, "Got VARPLAY command"); if ( paused ) { - // Clear paused flag paused = false; - // Set delayed_play flag delayed = true; } replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768; break; - } case CMD_STOP : - { - Debug( 1, "Got STOP command" ); - - // Clear paused flag + Debug(1, "Got STOP command"); paused = false; - // Clear delayed_play flag delayed = false; break; - } case CMD_FASTFWD : - { - Debug( 1, "Got FAST FWD command" ); + Debug(1, "Got FAST FWD command"); if ( paused ) { - // Clear paused flag paused = false; - // Set delayed_play flag delayed = true; } // Set play rate - switch ( replay_rate ) - { + switch ( replay_rate ) { case 2 * ZM_RATE_BASE : replay_rate = 5 * ZM_RATE_BASE; break; @@ -152,40 +130,24 @@ void MonitorStream::processCommand( const CmdMsg *msg ) { break; } break; - } case CMD_SLOWFWD : - { Debug( 1, "Got SLOW FWD command" ); - // Set paused flag paused = true; - // Set delayed flag delayed = true; - // Set play rate replay_rate = ZM_RATE_BASE; - // Set step step = 1; break; - } case CMD_SLOWREV : - { Debug( 1, "Got SLOW REV command" ); - // Set paused flag paused = true; - // Set delayed flag delayed = true; - // Set play rate replay_rate = ZM_RATE_BASE; - // Set step step = -1; break; - } case CMD_FASTREV : - { Debug( 1, "Got FAST REV command" ); if ( paused ) { - // Clear paused flag paused = false; - // Set delayed_play flag delayed = true; } // Set play rate @@ -208,9 +170,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) { break; } break; - } case CMD_ZOOMIN : - { x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; Debug( 1, "Got ZOOM IN command, to %d,%d", x, y ); @@ -233,9 +193,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) { break; } break; - } case CMD_ZOOMOUT : - { Debug( 1, "Got ZOOM OUT command" ); switch ( zoom ) { case 500: @@ -256,36 +214,25 @@ void MonitorStream::processCommand( const CmdMsg *msg ) { break; } break; - } case CMD_PAN : - { x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; - Debug( 1, "Got PAN command, to %d,%d", x, y ); + Debug(1, "Got PAN command, to %d,%d", x, y); break; - } case CMD_SCALE : - { scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2]; - Debug( 1, "Got SCALE command, to %d", scale ); + Debug(1, "Got SCALE command, to %d", scale); break; - } case CMD_QUIT : - { - Info ("User initiated exit - CMD_QUIT"); + Info("User initiated exit - CMD_QUIT"); break; - } case CMD_QUERY : - { - Debug( 1, "Got QUERY command, sending STATUS" ); + Debug(1, "Got QUERY command, sending STATUS"); break; - } default : - { - Error( "Got unexpected command %d", msg->msg_data[0] ); + Error("Got unexpected command %d", msg->msg_data[0]); break; - } - } + } // end switch command struct { int id; @@ -316,7 +263,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) { //status_data.enabled = monitor->shared_data->active; status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF; status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON; - Debug( 2, "Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d", + Debug(2, "Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d", status_data.buffer_level, status_data.delayed, status_data.paused, @@ -329,16 +276,16 @@ void MonitorStream::processCommand( const CmdMsg *msg ) { DataMsg status_msg; status_msg.msg_type = MSG_DATA_WATCH; - memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) ); + memcpy(&status_msg.msg_data, &status_data, sizeof(status_data)); int nbytes = 0; - if ( (nbytes = sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) )) < 0 ) { + if ( (nbytes = sendto(sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr))) < 0 ) { //if ( errno != EAGAIN ) { Error( "Can't sendto on sd %d: %s", sd, strerror(errno) ); //exit( -1 ); } } -Debug(2, "NUmber of bytes sent to (%s): (%d)", rem_addr.sun_path, nbytes ); + Debug(2, "Number of bytes sent to (%s): (%d)", rem_addr.sun_path, nbytes); // quit after sending a status, if this was a quit request if ( (MsgCommand)msg->msg_data[0]==CMD_QUIT ) { @@ -346,11 +293,11 @@ Debug(2, "NUmber of bytes sent to (%s): (%d)", rem_addr.sun_path, nbytes ); exit(0); } - Debug(2,"Updating framrate"); - updateFrameRate( monitor->GetFPS() ); -} // end void MonitorStream::processCommand( const CmdMsg *msg ) + Debug(2,"Updating framerate"); + updateFrameRate(monitor->GetFPS()); +} // end void MonitorStream::processCommand(const CmdMsg *msg) -bool MonitorStream::sendFrame( const char *filepath, struct timeval *timestamp ) { +bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) { bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); if ( @@ -361,71 +308,70 @@ bool MonitorStream::sendFrame( const char *filepath, struct timeval *timestamp ) send_raw = false; if ( !send_raw ) { - Image temp_image( filepath ); + Image temp_image(filepath); - return( sendFrame( &temp_image, timestamp ) ); + return sendFrame(&temp_image, timestamp); } else { int img_buffer_size = 0; static unsigned char img_buffer[ZM_MAX_IMAGE_SIZE]; FILE *fdj = NULL; - if ( (fdj = fopen( filepath, "r" )) ) { - img_buffer_size = fread( img_buffer, 1, sizeof(img_buffer), fdj ); - fclose( fdj ); + if ( (fdj = fopen(filepath, "r")) ) { + img_buffer_size = fread(img_buffer, 1, sizeof(img_buffer), fdj); + fclose(fdj); } else { - Error( "Can't open %s: %s", filepath, strerror(errno) ); - return( false ); + Error("Can't open %s: %s", filepath, strerror(errno)); + return false; } // Calculate how long it takes to actually send the frame struct timeval frameStartTime; - gettimeofday( &frameStartTime, NULL ); + gettimeofday(&frameStartTime, NULL); - fprintf( stdout, "--ZoneMinderFrame\r\n" ); - fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size ); - fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); - if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { + fputs("--ZoneMinderFrame\r\nContent-Type: image/jpeg\r\n\r\n", stdout ); + fprintf(stdout, "Content-Length: %d\r\n", img_buffer_size); + if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) { if ( ! zm_terminate ) - Error( "Unable to send stream frame: %s", strerror(errno) ); - return( false ); + Warning("Unable to send stream frame: %s", strerror(errno)); + return false; } - fprintf( stdout, "\r\n\r\n" ); - fflush( stdout ); + fputs("\r\n\r\n", stdout); + fflush(stdout); struct timeval frameEndTime; - gettimeofday( &frameEndTime, NULL ); + gettimeofday(&frameEndTime, NULL); - int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); + int frameSendTime = tvDiffMsec(frameStartTime, frameEndTime); if ( frameSendTime > 1000/maxfps ) { maxfps /= 2; - Info( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); + Info("Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps); } - last_frame_sent = TV_2_FLOAT( now ); + last_frame_sent = TV_2_FLOAT(now); - return( true ); + return true; } - return( false ); -} + return false; +} // end bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) -bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp ) { - Image *send_image = prepareImage( image ); +bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) { + Image *send_image = prepareImage(image); if ( !config.timestamp_on_capture && timestamp ) - monitor->TimestampImage( send_image, timestamp ); + monitor->TimestampImage(send_image, timestamp); #if HAVE_LIBAVCODEC if ( type == STREAM_MPEG ) { if ( !vid_stream ) { - vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height() ); - fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() ); + vid_stream = new VideoStream("pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height()); + fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType()); vid_stream->OpenStream(); } static struct timeval base_time; struct DeltaTimeval delta_time; if ( !frame_count ) base_time = *timestamp; - DELTA_TIMEVAL( delta_time, *timestamp, base_time, DT_PREC_3 ); - /* double pts = */ vid_stream->EncodeFrame( send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_time.delta ); + DELTA_TIMEVAL(delta_time, *timestamp, base_time, DT_PREC_3); + /* double pts = */ vid_stream->EncodeFrame(send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_time.delta); } else #endif // HAVE_LIBAVCODEC { @@ -436,36 +382,38 @@ bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp ) { // Calculate how long it takes to actually send the frame struct timeval frameStartTime; - gettimeofday( &frameStartTime, NULL ); + gettimeofday(&frameStartTime, NULL); - fprintf( stdout, "--ZoneMinderFrame\r\n" ); + fputs("--ZoneMinderFrame\r\n", stdout); switch( type ) { case STREAM_JPEG : - send_image->EncodeJpeg( img_buffer, &img_buffer_size ); - fprintf( stdout, "Content-Type: image/jpeg\r\n" ); + send_image->EncodeJpeg(img_buffer, &img_buffer_size); + fputs("Content-Type: image/jpeg\r\n", stdout); break; case STREAM_RAW : - fprintf( stdout, "Content-Type: image/x-rgb\r\n" ); + fputs("Content-Type: image/x-rgb\r\n", stdout); img_buffer = (uint8_t*)send_image->Buffer(); img_buffer_size = send_image->Size(); break; case STREAM_ZIP : - fprintf( stdout, "Content-Type: image/x-rgbz\r\n" ); + fputs("Content-Type: image/x-rgbz\r\n",stdout); unsigned long zip_buffer_size; - send_image->Zip( img_buffer, &zip_buffer_size ); + send_image->Zip(img_buffer, &zip_buffer_size); img_buffer_size = zip_buffer_size; break; default : - Fatal( "Unexpected frame type %d", type ); - break; + Error("Unexpected frame type %d", type); + return false; } - fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); - if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { - if ( !zm_terminate ) - Error( "Unable to send stream frame: %s", strerror(errno) ); - return( false ); + fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size); + if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) { + if ( !zm_terminate ){ + // If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate + Warning("Unable to send stream frame: %s", strerror(errno)); + } + return false; } - fprintf( stdout, "\r\n\r\n" ); + fputs("\r\n\r\n",stdout); fflush( stdout ); struct timeval frameEndTime; @@ -484,27 +432,27 @@ bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp ) { void MonitorStream::runStream() { if ( type == STREAM_SINGLE ) { // Not yet migrated over to stream class - SingleImage( scale ); + SingleImage(scale); return; } openComms(); - if ( ! checkInitialised() ) { + if ( !checkInitialised() ) { Error("Not initialized"); return; } - updateFrameRate( monitor->GetFPS() ); + updateFrameRate(monitor->GetFPS()); if ( type == STREAM_JPEG ) - fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); + fputs("Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n", stdout); // point to end which is theoretically not a valid value because all indexes are % image_buffer_count unsigned int last_read_index = monitor->image_buffer_count; time_t stream_start_time; - time( &stream_start_time ); + time(&stream_start_time); frame_count = 0; @@ -513,48 +461,47 @@ void MonitorStream::runStream() { temp_read_index = temp_image_buffer_count; temp_write_index = temp_image_buffer_count; - char *swap_path = 0; + std::string swap_path; bool buffered_playback = false; + // Last image and timestamp when paused, will be resent occasionally to prevent timeout + Image *paused_image = NULL; + struct timeval paused_timestamp; + // 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id const int max_swap_len_suffix = 15; int swap_path_length = staticConfig.PATH_SWAP.length() + 1; // +1 for NULL terminator - int subfolder1_length = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id() ) + 1; - int subfolder2_length = snprintf(NULL, 0, "/zmswap-q%06d", connkey ) + 1; + int subfolder1_length = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id()) + 1; + int subfolder2_length = snprintf(NULL, 0, "/zmswap-q%06d", connkey) + 1; int total_swap_path_length = swap_path_length + subfolder1_length + subfolder2_length; - if ( connkey && playback_buffer > 0 ) { + if ( connkey && ( playback_buffer > 0 ) ) { if ( total_swap_path_length + max_swap_len_suffix > PATH_MAX ) { - Error( "Swap Path is too long. %d > %d ", total_swap_path_length+max_swap_len_suffix, PATH_MAX ); + Error("Swap Path is too long. %d > %d ", total_swap_path_length+max_swap_len_suffix, PATH_MAX); } else { - swap_path = (char *)malloc( total_swap_path_length+max_swap_len_suffix ); - strncpy( swap_path, staticConfig.PATH_SWAP.c_str(), swap_path_length ); + swap_path = staticConfig.PATH_SWAP; - Debug( 3, "Checking swap path folder: %s", swap_path ); - if ( checkSwapPath( swap_path, false ) ) { - // Append the subfolder name /zmswap-m{monitor-id} to the end of swap_path - int ndx = swap_path_length - 1; // Array index of the NULL terminator - snprintf( &(swap_path[ndx]), subfolder1_length, "/zmswap-m%d", monitor->Id() ); + Debug( 3, "Checking swap path folder: %s", swap_path.c_str() ); + if ( checkSwapPath(swap_path.c_str(), false) ) { + swap_path += stringtf("/zmswap-m%d", monitor->Id()); - Debug( 4, "Checking swap path subfolder: %s", swap_path ); - if ( checkSwapPath( swap_path, true ) ) { - // Append the subfolder name /zmswap-q{connection key} to the end of swap_path - ndx = swap_path_length+subfolder1_length - 2; // Array index of the NULL terminator - snprintf( &(swap_path[ndx]), subfolder2_length, "/zmswap-q%06d", connkey ); + Debug(4, "Checking swap path subfolder: %s", swap_path.c_str()); + if ( checkSwapPath(swap_path.c_str(), true) ) { + swap_path += stringtf("/zmswap-q%06d", connkey); - Debug( 4, "Checking swap path subfolder: %s", swap_path ); - if ( checkSwapPath( swap_path, true ) ) { + Debug(4, "Checking swap path subfolder: %s", swap_path.c_str()); + if ( checkSwapPath(swap_path.c_str(), true) ) { buffered_playback = true; } } } if ( !buffered_playback ) { - Error( "Unable to validate swap image path, disabling buffered playback" ); + Error("Unable to validate swap image path, disabling buffered playback"); } else { - Debug( 2, "Assigning temporary buffer" ); + Debug(2, "Assigning temporary buffer"); temp_image_buffer = new SwapImage[temp_image_buffer_count]; memset( temp_image_buffer, 0, sizeof(*temp_image_buffer)*temp_image_buffer_count ); Debug( 2, "Assigned temporary buffer" ); @@ -567,19 +514,20 @@ void MonitorStream::runStream() { float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs) while ( !zm_terminate ) { bool got_command = false; - if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) { - if ( feof( stdout ) ) { - Debug(2,"feof stdout"); - } else if ( ferror( stdout ) ) { - Debug(2,"ferror stdout"); - } else if ( !monitor->ShmValid() ) { - Debug(2,"monitor not valid.... maybe we should wait until it comes back."); - } + if ( feof(stdout) ) { + Debug(2,"feof stdout"); + break; + } else if ( ferror(stdout) ) { + Debug(2,"ferror stdout"); + break; + } else if ( !monitor->ShmValid() ) { + Debug(2,"monitor not valid.... maybe we should wait until it comes back."); break; } - gettimeofday( &now, NULL ); + gettimeofday(&now, NULL); + bool was_paused = paused; if ( connkey ) { while(checkCommandQueue()) { Debug(2, "Have checking command Queue for connkey: %d", connkey ); @@ -587,7 +535,19 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); } } - //bool frame_sent = false; + if ( paused ) { + if ( !was_paused ) { + int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; + Debug(1,"Saving paused image from index %d",index); + paused_image = new Image( *monitor->image_buffer[index].image ); + paused_timestamp = *(monitor->image_buffer[index].timestamp); + } + } else if ( paused_image ) { + Debug(1,"Clearing paused_image"); + delete paused_image; + paused_image = NULL; + } + if ( buffered_playback && delayed ) { if ( temp_read_index == temp_write_index ) { // Go back to live viewing @@ -599,14 +559,14 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); replay_rate = ZM_RATE_BASE; } else { if ( !paused ) { - int temp_index = MOD_ADD( temp_read_index, 0, temp_image_buffer_count ); + int temp_index = MOD_ADD(temp_read_index, 0, temp_image_buffer_count); //Debug( 3, "tri: %d, ti: %d", temp_read_index, temp_index ); SwapImage *swap_image = &temp_image_buffer[temp_index]; if ( !swap_image->valid ) { paused = true; delayed = true; - temp_read_index = MOD_ADD( temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count ); + temp_read_index = MOD_ADD(temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count); } else { //Debug( 3, "siT: %f, lfT: %f", TV_2_FLOAT( swap_image->timestamp ), TV_2_FLOAT( last_frame_timestamp ) ); double expected_delta_time = ((TV_2_FLOAT( swap_image->timestamp ) - TV_2_FLOAT( last_frame_timestamp )) * ZM_RATE_BASE)/replay_rate; @@ -619,12 +579,12 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); if ( temp_index%frame_mod == 0 ) { Debug( 2, "Sending delayed frame %d", temp_index ); // Send the next frame - if ( ! sendFrame( temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp ) ) + if ( ! sendFrame(temp_image_buffer[temp_index].file_name, &temp_image_buffer[temp_index].timestamp) ) zm_terminate = true; - memcpy( &last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp) ); + memcpy(&last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp)); //frame_sent = true; } - temp_read_index = MOD_ADD( temp_read_index, (replay_rate>0?1:-1), temp_image_buffer_count ); + temp_read_index = MOD_ADD(temp_read_index, (replay_rate>0?1:-1), temp_image_buffer_count); } } } else if ( step != 0 ) { @@ -639,7 +599,8 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); //frame_sent = true; step = 0; } else { - int temp_index = MOD_ADD( temp_read_index, 0, temp_image_buffer_count ); + //paused? + int temp_index = MOD_ADD(temp_read_index, 0, temp_image_buffer_count); double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent; if ( got_command || actual_delta_time > 5 ) { @@ -650,8 +611,9 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); zm_terminate = true; //frame_sent = true; } - } - } + } // end if (!paused) or step or paused + } // end if have exceeded buffer or not + if ( temp_read_index == temp_write_index ) { // Go back to live viewing Warning( "Rewound over write index, resuming live play" ); @@ -662,10 +624,12 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); replay_rate = ZM_RATE_BASE; } } // end if ( buffered_playback && delayed ) + if ( last_read_index != monitor->shared_data->last_write_index ) { + // have a new image to send int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; // % shouldn't be neccessary last_read_index = monitor->shared_data->last_write_index; - Debug( 3, "index: %d: frame_mod: %d frame count: %d", index, frame_mod, frame_count ); + Debug( 2, "index: %d: frame_mod: %d frame count: %d paused(%d) delayed(%d)", index, frame_mod, frame_count, paused, delayed ); if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) { if ( !paused && !delayed ) { // Send the next frame @@ -674,24 +638,38 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); Image *image = snap->image;// This works because connect rebuilds the image_buffer links struct timeval *timestamp = snap->timestamp; - if ( !sendFrame( image, timestamp ) ) { + if ( !sendFrame(snap->image, snap->timestamp) ) { Debug(2, "sendFrame failed, quiting."); zm_terminate = true; } + // Perhaps we should use NOW instead. last_frame_timestamp = *timestamp; //frame_sent = true; temp_read_index = temp_write_index; + } else { + double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent; + if ( actual_delta_time > 5 ) { + if ( paused_image ) { + // Send keepalive + Debug(2, "Sending keepalive frame "); + // Send the next frame + if ( !sendFrame(paused_image, &paused_timestamp) ) + zm_terminate = true; + } else { + Debug(2, "Would have sent keepalive frame, but had no paused_image "); + } + } } } // end if should send frame - if ( buffered_playback ) { + if ( buffered_playback && !paused ) { if ( monitor->shared_data->valid ) { if ( monitor->shared_timestamps[index].tv_sec ) { int temp_index = temp_write_index%temp_image_buffer_count; - Debug( 2, "Storing frame %d", temp_index ); + Debug(2, "Storing frame %d", temp_index); if ( !temp_image_buffer[temp_index].valid ) { - snprintf( temp_image_buffer[temp_index].file_name, sizeof(temp_image_buffer[0].file_name), "%s/zmswap-i%05d.jpg", swap_path, temp_index ); + snprintf( temp_image_buffer[temp_index].file_name, sizeof(temp_image_buffer[0].file_name), "%s/zmswap-i%05d.jpg", swap_path.c_str(), temp_index ); temp_image_buffer[temp_index].valid = true; } temp_image_buffer[temp_index].timestamp = monitor->shared_timestamps[index]; @@ -700,9 +678,7 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); if ( temp_write_index == temp_read_index ) { // Go back to live viewing Warning( "Exceeded temporary buffer, resuming live play" ); - // Clear paused flag paused = false; - // Clear delayed_play flag delayed = false; replay_rate = ZM_RATE_BASE; } @@ -720,7 +696,7 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); unsigned long sleep_time = (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))); Debug(4, "Sleeping for (%d)", sleep_time); - usleep( sleep_time ); + usleep(sleep_time); if ( ttl ) { if ( (now.tv_sec - stream_start_time) > ttl ) { Debug(2, "now(%d) - start(%d) > ttl(%d) break", now.tv_sec, stream_start_time, ttl); @@ -731,50 +707,49 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); // If we didn't capture above, because frame_mod was bad? Then last_frame_sent will not have a value. last_frame_sent = now.tv_sec; Warning( "no last_frame_sent. Shouldn't happen. frame_mod was (%d) frame_count (%d) ", frame_mod, frame_count ); - } else if ( (TV_2_FLOAT( now ) - last_frame_sent) > max_secs_since_last_sent_frame ) { + } else if ( (!paused) && ( (TV_2_FLOAT( now ) - last_frame_sent) > max_secs_since_last_sent_frame ) ) { Error( "Terminating, last frame sent time %f secs more than maximum of %f", TV_2_FLOAT( now ) - last_frame_sent, max_secs_since_last_sent_frame ); break; } } // end while if ( buffered_playback ) { - Debug( 1, "Cleaning swap files from %s", swap_path ); + Debug(1, "Cleaning swap files from %s", swap_path.c_str()); struct stat stat_buf; - if ( stat( swap_path, &stat_buf ) < 0 ) { + if ( stat(swap_path.c_str(), &stat_buf) < 0 ) { if ( errno != ENOENT ) { - Error( "Can't stat '%s': %s", swap_path, strerror(errno) ); + Error("Can't stat '%s': %s", swap_path.c_str(), strerror(errno)); } } else if ( !S_ISDIR(stat_buf.st_mode) ) { - Error( "Swap image path '%s' is not a directory", swap_path ); + Error("Swap image path '%s' is not a directory", swap_path.c_str()); } else { char glob_pattern[PATH_MAX] = ""; - snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path ); + snprintf(glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path.c_str()); glob_t pglob; - int glob_status = glob( glob_pattern, 0, 0, &pglob ); + int glob_status = glob(glob_pattern, 0, 0, &pglob); if ( glob_status != 0 ) { if ( glob_status < 0 ) { - Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) ); + Error("Can't glob '%s': %s", glob_pattern, strerror(errno)); } else { - Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status ); + Debug(1, "Can't glob '%s': %d", glob_pattern, glob_status); } } else { for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) { - if ( unlink( pglob.gl_pathv[i] ) < 0 ) { - Error( "Can't unlink '%s': %s", pglob.gl_pathv[i], strerror(errno) ); + if ( unlink(pglob.gl_pathv[i]) < 0 ) { + Error("Can't unlink '%s': %s", pglob.gl_pathv[i], strerror(errno)); } } } globfree( &pglob ); - if ( rmdir( swap_path ) < 0 ) { - Error( "Can't rmdir '%s': %s", swap_path, strerror(errno) ); + if ( rmdir(swap_path.c_str()) < 0 ) { + Error( "Can't rmdir '%s': %s", swap_path.c_str(), strerror(errno) ); } } // end if checking for swap_path } // end if buffered_playback - if ( swap_path ) free( swap_path ); closeComms(); -} +} // end MonitorStream::runStream void MonitorStream::SingleImage( int scale ) { int img_buffer_size = 0; diff --git a/src/zm_monitorstream.h b/src/zm_monitorstream.h index 95f538765..f3351d3b7 100644 --- a/src/zm_monitorstream.h +++ b/src/zm_monitorstream.h @@ -58,7 +58,9 @@ class MonitorStream : public StreamBase { void SingleImageZip( int scale=100 ); public: - MonitorStream() : ttl(0), playback_buffer(0), delayed(false), frame_count(0) { + MonitorStream() : + temp_image_buffer(NULL), temp_image_buffer_count(0), temp_read_index(0), temp_write_index(0), + ttl(0), playback_buffer(0), delayed(false), frame_count(0) { } void setStreamBuffer( int p_playback_buffer ) { playback_buffer = p_playback_buffer; diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index 1a09893c7..d8a26242f 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -293,7 +293,7 @@ const char *VideoStream::MimeType( ) const { return mime_type; } -void VideoStream::OpenStream( ) { +bool VideoStream::OpenStream( ) { int ret; /* now that all the parameters are set, we can open the @@ -308,7 +308,8 @@ void VideoStream::OpenStream( ) { if ( (ret = avcodec_open2(codec_context, codec, 0)) < 0 ) #endif { - Fatal( "Could not open codec. Error code %d \"%s\"", ret, av_err2str(ret) ); + Error("Could not open codec. Error code %d \"%s\"", ret, av_err2str(ret)); + return false; } Debug( 1, "Opened codec" ); @@ -316,22 +317,24 @@ void VideoStream::OpenStream( ) { /* allocate the encoded raw picture */ opicture = zm_av_frame_alloc( ); if ( !opicture ) { - Panic( "Could not allocate opicture" ); + Error("Could not allocate opicture"); + return false; } opicture->width = codec_context->width; opicture->height = codec_context->height; opicture->format = codec_context->pix_fmt; #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int size = av_image_get_buffer_size( codec_context->pix_fmt, codec_context->width, codec_context->height, 1 ); + int size = av_image_get_buffer_size(codec_context->pix_fmt, codec_context->width, codec_context->height, 1); #else - int size = avpicture_get_size( codec_context->pix_fmt, codec_context->width, codec_context->height ); + int size = avpicture_get_size(codec_context->pix_fmt, codec_context->width, codec_context->height); #endif - uint8_t *opicture_buf = (uint8_t *)av_malloc( size ); + uint8_t *opicture_buf = (uint8_t *)av_malloc(size); if ( !opicture_buf ) { av_frame_free( &opicture ); - Panic( "Could not allocate opicture_buf" ); + Error( "Could not allocate opicture_buf" ); + return false; } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(opicture->data, opicture->linesize, @@ -352,7 +355,8 @@ void VideoStream::OpenStream( ) { tmp_opicture = avcodec_alloc_frame( ); #endif if ( !tmp_opicture ) { - Panic( "Could not allocate tmp_opicture" ); + Error( "Could not allocate tmp_opicture" ); + return false; } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) int size = av_image_get_buffer_size( pf, codec_context->width, codec_context->height,1 ); @@ -362,7 +366,8 @@ void VideoStream::OpenStream( ) { uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size ); if ( !tmp_opicture_buf ) { av_frame_free( &tmp_opicture ); - Panic( "Could not allocate tmp_opicture_buf" ); + Error( "Could not allocate tmp_opicture_buf" ); + return false; } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(tmp_opicture->data, @@ -385,12 +390,14 @@ void VideoStream::OpenStream( ) { ret = url_fopen( &ofc->pb, filename, AVIO_FLAG_WRITE ); #endif if ( ret < 0 ) { - Fatal( "Could not open '%s'", filename ); + Error("Could not open '%s'", filename); + return false; } - Debug( 1, "Opened output \"%s\"", filename ); + Debug(1, "Opened output \"%s\"", filename); } else { - Fatal( "of->flags & AVFMT_NOFILE" ); + Error( "of->flags & AVFMT_NOFILE" ); + return false; } video_outbuf = NULL; @@ -417,14 +424,16 @@ void VideoStream::OpenStream( ) { #endif #if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) - ret = av_write_header( ofc ); + ret = av_write_header(ofc); #else - ret = avformat_write_header(ofc, NULL); + ret = avformat_write_header(ofc, NULL); #endif - if ( ret < 0 ) { - Fatal( "?_write_header failed with error %d \"%s\"", ret, av_err2str( ret ) ); - } + if ( ret < 0 ) { + Error("?_write_header failed with error %d \"%s\"", ret, av_err2str(ret)); + return false; + } + return true; } VideoStream::VideoStream( const char *in_filename, const char *in_format, int bitrate, double frame_rate, int colours, int subpixelorder, int width, int height ) : @@ -550,19 +559,20 @@ VideoStream::~VideoStream( ) { } double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _add_timestamp, unsigned int _timestamp ) { - if ( pthread_mutex_lock( buffer_copy_lock ) != 0 ) { + if ( pthread_mutex_lock(buffer_copy_lock) != 0 ) { Fatal( "EncodeFrame: pthread_mutex_lock failed." ); } if (buffer_copy_size < buffer_size) { if ( buffer_copy ) { - av_free( buffer_copy ); + av_free(buffer_copy); } // Allocate a buffer to store source images for the streaming thread to encode. - buffer_copy = (uint8_t *)av_malloc( buffer_size ); + buffer_copy = (uint8_t *)av_malloc(buffer_size); if ( !buffer_copy ) { - Panic( "Could not allocate buffer_copy" ); + Error( "Could not allocate buffer_copy" ); + pthread_mutex_unlock(buffer_copy_lock); return 0; } buffer_copy_size = buffer_size; @@ -573,7 +583,7 @@ double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _a buffer_copy_used = buffer_size; memcpy(buffer_copy, buffer, buffer_size); - if ( pthread_mutex_unlock( buffer_copy_lock ) != 0 ) { + if ( pthread_mutex_unlock(buffer_copy_lock) != 0 ) { Fatal( "EncodeFrame: pthread_mutex_unlock failed." ); } diff --git a/src/zm_mpeg.h b/src/zm_mpeg.h index fbc3eed4d..6e75f8743 100644 --- a/src/zm_mpeg.h +++ b/src/zm_mpeg.h @@ -1,21 +1,21 @@ /* * ZoneMinder MPEG Interface, $Date$, $Revision$ * Copyright (C) 2001-2008 Philip Coombes - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ +*/ #ifndef ZM_MPEG_H #define ZM_MPEG_H @@ -51,7 +51,7 @@ protected: uint8_t *video_outbuf; int video_outbuf_size; double last_pts; - + pthread_t streaming_thread; bool do_streaming; bool add_timestamp; @@ -78,7 +78,7 @@ public: VideoStream( const char *filename, const char *format, int bitrate, double frame_rate, int colours, int subpixelorder, int width, int height ); ~VideoStream(); const char *MimeType() const; - void OpenStream(); + bool OpenStream(); double EncodeFrame( const uint8_t *buffer, int buffer_size, bool add_timestamp=false, unsigned int timestamp=0 ); }; diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 3674144b1..b203b83d8 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -191,8 +191,8 @@ Image *ZMPacket::set_image( Image *i ) { return image; } -AVPacket *ZMPacket::set_packet( AVPacket *p ) { - if ( zm_av_packet_ref( &packet, p ) < 0 ) { +AVPacket *ZMPacket::set_packet(AVPacket *p) { + if ( zm_av_packet_ref(&packet, p) < 0 ) { Error("error refing packet"); } dumpPacket(&packet, "zmpacket:"); diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 912d8cb1f..8f36e0cd7 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -39,7 +39,7 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { // If we can never queue the same packet, then they can never go past if ( zm_packet->image_index == first_video_packet_index ) { Debug(2, "queuing packet that is already on the queue(%d)", zm_packet->image_index ); - ZMPacket *p; + ZMPacket *p = NULL;; while ( pktQueue.size() && (p = pktQueue.front()) && ( p->image_index != zm_packet->image_index ) ) { if ( ( analysis_it != pktQueue.end() ) && ( *analysis_it == p ) ) { Debug(2, "Increasing analysis_it"); @@ -250,7 +250,7 @@ ZMPacket *zm_packetqueue::get_analysis_packet() { bool zm_packetqueue::increment_analysis_it( ) { // We do this instead of distance becuase distance will traverse the entire list in the worst case std::list::iterator next_it = analysis_it; - next_it ++; + ++ next_it; if ( next_it == pktQueue.end() ) { return false; } diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 8e305ee40..d33406b07 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -21,6 +21,7 @@ #include "zm_rtsp_auth.h" #include "zm_mem_utils.h" +#include "zm_signal.h" #include #include @@ -185,24 +186,24 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) { struct timeval temp_timeout = timeout; - int n_found = select( sd+1, &rfds, NULL, NULL, &temp_timeout ); + int n_found = select(sd+1, &rfds, NULL, NULL, &temp_timeout); if( n_found == 0 ) { - Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); + Debug( 1, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); int error = 0; socklen_t len = sizeof (error); int retval = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len); if(retval != 0 ) { Debug( 1, "error getting socket error code %s", strerror(retval) ); } - if (error != 0) { + if (error != 0 ) { return -1; } // Why are we disconnecting? It's just a timeout, meaning that data wasn't available. //Disconnect(); - return( 0 ); + return 0; } else if ( n_found < 0) { - Error( "Select error: %s", strerror(errno) ); - return( -1 ); + Error("Select error: %s", strerror(errno)); + return -1; } unsigned int total_bytes_to_read = 0; @@ -298,13 +299,14 @@ int RemoteCameraHttp::GetResponse() { static RegExpr *content_length_expr = 0; static RegExpr *content_type_expr = 0; - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting for REGEXP HEADER"); } if ( buffer_len < 0 ) { Error( "Unable to read header data" ); return( -1 ); } + bytes += buffer_len; if ( !header_expr ) header_expr = new RegExpr( "^(.+?\r?\n\r?\n)", PCRE_DOTALL ); if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 ) { @@ -449,13 +451,14 @@ int RemoteCameraHttp::GetResponse() { state = CONTENT; } else { Debug( 3, "Unable to extract subheader from stream, retrying" ); - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting to extract subheader"); } if ( buffer_len < 0 ) { Error( "Unable to extract subheader data" ); return( -1 ); } + bytes += buffer_len; } break; } @@ -480,23 +483,27 @@ int RemoteCameraHttp::GetResponse() { } if ( content_length ) { - while ( (long)buffer.size() < content_length ) { + while ( ((long)buffer.size() < content_length ) && ! zm_terminate ) { Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_length ); - if ( ReadData( buffer ) < 0 ) { + int bytes_read = ReadData( buffer ); + + if ( bytes_read < 0 ) { Error( "Unable to read content" ); return( -1 ); } + bytes += bytes_read; } Debug( 3, "Got end of image by length, content-length = %d", content_length ); } else { while ( !content_length ) { - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting for content"); } if ( buffer_len < 0 ) { Error( "Unable to read content" ); return( -1 ); } + bytes += buffer_len; static RegExpr *content_expr = 0; if ( mode == MULTI_IMAGE ) { if ( !content_expr ) { @@ -603,13 +610,14 @@ int RemoteCameraHttp::GetResponse() { } case HEADERCONT : { - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) { Debug(4, "Timeout waiting for HEADERCONT"); } if ( buffer_len < 0 ) { Error( "Unable to read header" ); return( -1 ); } + bytes += buffer_len; char *crlf = 0; char *header_ptr = (char *)buffer; @@ -888,13 +896,14 @@ int RemoteCameraHttp::GetResponse() { state = CONTENT; } else { Debug( 3, "Unable to extract subheader from stream, retrying" ); - while ( ! ( buffer_len = ReadData( buffer ) ) ) { + while ( !( buffer_len = ReadData(buffer) ) &&!zm_terminate ) { Debug(1, "Timeout waiting to extra subheader non regexp"); } if ( buffer_len < 0 ) { Error( "Unable to read subheader" ); return( -1 ); } + bytes += buffer_len; state = SUBHEADERCONT; } break; @@ -927,18 +936,19 @@ int RemoteCameraHttp::GetResponse() { } if ( content_length ) { - while ( (long)buffer.size() < content_length ) { - //int buffer_len = ReadData( buffer, content_length-buffer.size() ); + while ( ( (long)buffer.size() < content_length ) && ! zm_terminate ) { Debug(4, "getting more data"); - if ( ReadData( buffer ) < 0 ) { - Error( "Unable to read content" ); - return( -1 ); + int bytes_read = ReadData(buffer); + if ( bytes_read < 0 ) { + Error("Unable to read content"); + return -1; } + bytes += bytes_read; } Debug( 3, "Got end of image by length, content-length = %d", content_length ); } else { // Read until we find the end of image or the stream closes. - while ( !content_length ) { + while ( !content_length && !zm_terminate ) { Debug(4, "!content_length, ReadData"); buffer_len = ReadData( buffer ); if ( buffer_len < 0 ) @@ -946,6 +956,7 @@ int RemoteCameraHttp::GetResponse() { Error( "Unable to read content" ); return( -1 ); } + bytes += buffer_len; int buffer_size = buffer.size(); if ( buffer_len ) { // Got some data diff --git a/src/zm_remote_camera_http.h b/src/zm_remote_camera_http.h index d2093c4d5..cbaa6e9f8 100644 --- a/src/zm_remote_camera_http.h +++ b/src/zm_remote_camera_http.h @@ -72,7 +72,8 @@ public: int PreCapture(); int Capture( ZMPacket &p ); int PostCapture(); -AVStream* get_VideoStream(); + AVStream* get_VideoStream(); + int Close() { return 0; }; }; #endif // ZM_REMOTE_CAMERA_HTTP_H diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index bcbf8e371..40fdc2e97 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -189,13 +189,14 @@ int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) { Warning( "Unable to capture image, retrying" ); return 0; } - if ( Read( sd, buffer, imagesize ) < imagesize ) { - Warning( "Unable to capture image, retrying" ); + int bytes_read = Read(sd, buffer, imagesize); + if ( (bytes_read < 0) || ( (unsigned int)bytes_read < imagesize ) ) { + Warning("Unable to capture image, retrying"); return 0; } uint32_t end; if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) { - Warning( "Unable to capture image, retrying" ); + Warning("Unable to capture image, retrying"); return 0; } if ( end != 0xFFFFFFFF) { @@ -203,7 +204,7 @@ int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) { return 0; } - zm_packet.image->Assign( width, height, colours, subpixelorder, buffer, imagesize ); + zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize); zm_packet.keyframe = 1; return 1; } diff --git a/src/zm_remote_camera_nvsocket.h b/src/zm_remote_camera_nvsocket.h index 276c38513..47a353d3d 100644 --- a/src/zm_remote_camera_nvsocket.h +++ b/src/zm_remote_camera_nvsocket.h @@ -65,7 +65,8 @@ public: int PrimeCapture(); int Capture( ZMPacket &p ); int PostCapture(); -AVStream* get_VideoStream(); + AVStream* get_VideoStream(); + int Close() { return 0; }; }; #endif // ZM_REMOTE_CAMERA_NVSOCKET_H diff --git a/src/zm_remote_camera_rtsp.h b/src/zm_remote_camera_rtsp.h index ddc456cfc..73d4ff5a1 100644 --- a/src/zm_remote_camera_rtsp.h +++ b/src/zm_remote_camera_rtsp.h @@ -85,6 +85,7 @@ public: int PreCapture(); int Capture( ZMPacket &p ); int PostCapture(); + int Close() { return 0; }; }; #endif // ZM_REMOTE_CAMERA_RTSP_H diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index 1a0e74560..f911f2c78 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -39,48 +39,49 @@ StreamBase::~StreamBase() { closeComms(); } -bool StreamBase::loadMonitor( int monitor_id ) { - if ( !(monitor = Monitor::Load( monitor_id, false, Monitor::QUERY )) ) { - Fatal( "Unable to load monitor id %d for streaming", monitor_id ); - return( false ); +bool StreamBase::loadMonitor(int monitor_id) { + if ( !(monitor = Monitor::Load(monitor_id, false, Monitor::QUERY)) ) { + Error("Unable to load monitor id %d for streaming", monitor_id); + return false; } if ( ! monitor->connect() ) { - Fatal( "Unable to connect to monitor id %d for streaming", monitor_id ); - return( false ); + Error("Unable to connect to monitor id %d for streaming", monitor_id); + return false; } - - return( true ); + + return true; } bool StreamBase::checkInitialised() { if ( !monitor ) { Fatal( "Cannot stream, not initialised" ); - return( false ); + return false; } - return( true ); + return true; } -void StreamBase::updateFrameRate( double fps ) { +void StreamBase::updateFrameRate(double fps) { base_fps = fps; effective_fps = (base_fps*abs(replay_rate))/ZM_RATE_BASE; frame_mod = 1; - Debug( 3, "FPS:%.2f, MXFPS:%.2f, BFPS:%.2f, EFPS:%.2f, FM:%d", fps, maxfps, base_fps, effective_fps, frame_mod ); + Debug(3, "FPS:%.2f, MXFPS:%.2f, BFPS:%.2f, EFPS:%.2f, FM:%d", fps, maxfps, base_fps, effective_fps, frame_mod); // Min frame repeat? while( effective_fps > maxfps ) { effective_fps /= 2.0; frame_mod *= 2; - Debug( 3, "aEFPS:%.2f, aFM:%d", effective_fps, frame_mod ); + Debug(3, "EffectiveFPS:%.2f, FrameMod:%d", effective_fps, frame_mod); } } bool StreamBase::checkCommandQueue() { if ( sd >= 0 ) { CmdMsg msg; - memset( &msg, 0, sizeof(msg) ); - int nbytes = recvfrom( sd, &msg, sizeof(msg), MSG_DONTWAIT, 0, 0 ); + memset(&msg, 0, sizeof(msg)); + int nbytes = recvfrom(sd, &msg, sizeof(msg), MSG_DONTWAIT, 0, 0); if ( nbytes < 0 ) { if ( errno != EAGAIN ) { - Fatal( "recvfrom(), errno = %d, error = %s", errno, strerror(errno) ); + Error("recvfrom(), errno = %d, error = %s", errno, strerror(errno)); + return false; } } //else if ( (nbytes != sizeof(msg)) ) @@ -88,14 +89,14 @@ bool StreamBase::checkCommandQueue() { //Error( "Partial message received, expected %d bytes, got %d", sizeof(msg), nbytes ); //} else { -Debug(2, "Message length is (%d)", nbytes ); - processCommand( &msg ); - return( true ); + Debug(2, "Message length is (%d)", nbytes); + processCommand(&msg); + return true; } } else { - Error("sd is < 0"); + Warning("No sd in checkCommandQueue, comms not open?"); } - return( false ); + return false; } Image *StreamBase::prepareImage( Image *image ) { @@ -152,18 +153,18 @@ Image *StreamBase::prepareImage( Image *image ) { if ( mag != ZM_SCALE_BASE ) { if ( act_mag != ZM_SCALE_BASE ) { - Debug( 3, "Magnifying by %d", mag ); + Debug(3, "Magnifying by %d", mag); if ( !image_copied ) { static Image copy_image; - copy_image.Assign( *image ); + copy_image.Assign(*image); image = ©_image; image_copied = true; } - image->Scale( mag ); + image->Scale(mag); } } - Debug( 3, "Real image width = %d, height = %d", image->Width(), image->Height() ); + Debug(3, "Real image width = %d, height = %d", image->Width(), image->Height()); if ( disp_image_width < virt_image_width || disp_image_height < virt_image_height ) { static Box last_crop; @@ -222,23 +223,23 @@ Image *StreamBase::prepareImage( Image *image ) { last_x = x; last_y = y; - return( image ); + return image; } bool StreamBase::sendTextFrame( const char *frame_text ) { - Debug( 2, "Sending text frame '%s'", frame_text ); + Debug(2, "Sending text frame '%s'", frame_text); - Image image( monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder() ); - image.Annotate( frame_text, image.centreCoord( frame_text ) ); + Image image(monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder()); + image.Annotate(frame_text, image.centreCoord(frame_text)); if ( scale != 100 ) { - image.Scale( scale ); + image.Scale(scale); } #if HAVE_LIBAVCODEC if ( type == STREAM_MPEG ) { if ( !vid_stream ) { - vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, image.Colours(), image.SubpixelOrder(), image.Width(), image.Height() ); - fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() ); + vid_stream = new VideoStream("pipe:", format, bitrate, effective_fps, image.Colours(), image.SubpixelOrder(), image.Width(), image.Height()); + fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType()); vid_stream->OpenStream(); } /* double pts = */ vid_stream->EncodeFrame( image.Buffer(), image.Size() ); @@ -248,30 +249,29 @@ bool StreamBase::sendTextFrame( const char *frame_text ) { static unsigned char buffer[ZM_MAX_IMAGE_SIZE]; int n_bytes = 0; - image.EncodeJpeg( buffer, &n_bytes ); + image.EncodeJpeg(buffer, &n_bytes); - fprintf( stdout, "--ZoneMinderFrame\r\n" ); - fprintf( stdout, "Content-Length: %d\r\n", n_bytes ); - fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); - if ( fwrite( buffer, n_bytes, 1, stdout ) != 1 ) { - Error( "Unable to send stream text frame: %s", strerror(errno) ); - return( false ); + fputs("--ZoneMinderFrame\r\nContent-Type: image/jpeg\r\n\r\n", stdout); + fprintf(stdout, "Content-Length: %d\r\n", n_bytes); + if ( fwrite(buffer, n_bytes, 1, stdout) != 1 ) { + Error("Unable to send stream text frame: %s", strerror(errno)); + return false; } - fprintf( stdout, "\r\n\r\n" ); - fflush( stdout ); + fputs("\r\n\r\n",stdout); + fflush(stdout); } - last_frame_sent = TV_2_FLOAT( now ); - return( true ); + last_frame_sent = TV_2_FLOAT(now); + return true; } void StreamBase::openComms() { if ( connkey > 0 ) { - unsigned int length = snprintf( sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", staticConfig.PATH_SOCKS.c_str(), connkey); + unsigned int length = snprintf(sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", staticConfig.PATH_SOCKS.c_str(), connkey); if ( length >= sizeof(sock_path_lock) ) { Warning("Socket lock path was truncated."); } - Debug( 1, "Trying to open the lock on %s", sock_path_lock ); + Debug(1, "Trying to open the lock on %s", sock_path_lock); lock_fd = open(sock_path_lock, O_CREAT|O_WRONLY, S_IRUSR | S_IWUSR); if ( lock_fd <= 0 ) { @@ -285,46 +285,46 @@ void StreamBase::openComms() { Debug( 1, "We have obtained a lock on %s fd: %d", sock_path_lock, lock_fd); } - sd = socket( AF_UNIX, SOCK_DGRAM, 0 ); + sd = socket(AF_UNIX, SOCK_DGRAM, 0); if ( sd < 0 ) { - Fatal( "Can't create socket: %s", strerror(errno) ); + Fatal("Can't create socket: %s", strerror(errno)); } else { - Debug(1, "Have socket %d", sd ); + Debug(1, "Have socket %d", sd); } - length = snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", staticConfig.PATH_SOCKS.c_str(), connkey ); + length = snprintf(loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", staticConfig.PATH_SOCKS.c_str(), connkey); if ( length >= sizeof(loc_sock_path) ) { Warning("Socket path was truncated."); length = sizeof(loc_sock_path)-1; } // Unlink before bind, in case it already exists - unlink( loc_sock_path ); + unlink(loc_sock_path); if ( sizeof(loc_addr.sun_path) < length ) { - Error("Not enough space %d in loc_addr.sun_path for socket file %s", sizeof(loc_addr.sun_path), loc_sock_path ); + Error("Not enough space %d in loc_addr.sun_path for socket file %s", sizeof(loc_addr.sun_path), loc_sock_path); } - strncpy( loc_addr.sun_path, loc_sock_path, sizeof(loc_addr.sun_path) ); + strncpy(loc_addr.sun_path, loc_sock_path, sizeof(loc_addr.sun_path)); loc_addr.sun_family = AF_UNIX; - Debug(3, "Binding to %s", loc_sock_path ); - if ( bind( sd, (struct sockaddr *)&loc_addr, strlen(loc_addr.sun_path)+sizeof(loc_addr.sun_family)+1 ) < 0 ) { - Fatal( "Can't bind: %s", strerror(errno) ); + Debug(3, "Binding to %s", loc_sock_path); + if ( bind(sd, (struct sockaddr *)&loc_addr, strlen(loc_addr.sun_path)+sizeof(loc_addr.sun_family)+1) < 0 ) { + Fatal("Can't bind: %s", strerror(errno)); } - snprintf( rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", staticConfig.PATH_SOCKS.c_str(), connkey ); - strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path)-1 ); + snprintf(rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", staticConfig.PATH_SOCKS.c_str(), connkey); + strncpy(rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path)-1); rem_addr.sun_family = AF_UNIX; } // end if connKey > 0 - Debug(2, "comms open" ); + Debug(2, "comms open"); } // end void StreamBase::openComms() void StreamBase::closeComms() { if ( connkey > 0 ) { if ( sd >= 0 ) { - close( sd ); + close(sd); sd = -1; } if ( loc_sock_path[0] ) { - unlink( loc_sock_path ); + unlink(loc_sock_path); } if ( lock_fd > 0 ) { close(lock_fd); //close it rather than unlock it incase it got deleted. @@ -332,4 +332,4 @@ void StreamBase::closeComms() { //unlink(sock_path_lock); } } -} +} // end void StreamBase::closeComms diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp index 86b1b1a1a..ae3a9662d 100644 --- a/src/zm_swscale.cpp +++ b/src/zm_swscale.cpp @@ -27,14 +27,18 @@ SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), output_avframe(NULL) { Debug(4,"SWScale object created"); +} + +bool SWScale::init() { /* Allocate AVFrame for the input */ #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) input_avframe = av_frame_alloc(); #else input_avframe = avcodec_alloc_frame(); #endif - if(input_avframe == NULL) { - Fatal("Failed allocating AVFrame for the input"); + if ( input_avframe == NULL ) { + Error("Failed allocating AVFrame for the input"); + return false; } /* Allocate AVFrame for the output */ @@ -43,21 +47,23 @@ SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), #else output_avframe = avcodec_alloc_frame(); #endif - if(output_avframe == NULL) { - Fatal("Failed allocating AVFrame for the output"); + if ( output_avframe == NULL ) { + Error("Failed allocating AVFrame for the output"); + return false; } + return true; } SWScale::~SWScale() { /* Free up everything */ - av_frame_free( &input_avframe ); - //input_avframe = NULL; + if ( input_avframe ) + av_frame_free(&input_avframe); - av_frame_free( &output_avframe ); - //output_avframe = NULL; + if ( output_avframe ) + av_frame_free(&output_avframe); - if(swscale_ctx) { + if ( swscale_ctx ) { sws_freeContext(swscale_ctx); swscale_ctx = NULL; } diff --git a/src/zm_swscale.h b/src/zm_swscale.h index f8749b463..4b4226ddb 100644 --- a/src/zm_swscale.h +++ b/src/zm_swscale.h @@ -10,6 +10,7 @@ class SWScale { public: SWScale(); ~SWScale(); + bool init(); int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size); int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size); diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index f42ee5041..e9f6f7621 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -30,10 +30,10 @@ struct timespec getTimeout( int secs ) { struct timespec timeout; struct timeval temp_timeout; - gettimeofday( &temp_timeout, 0 ); + gettimeofday(&temp_timeout, 0); timeout.tv_sec = temp_timeout.tv_sec + secs; timeout.tv_nsec = temp_timeout.tv_usec*1000; - return( timeout ); + return timeout; } struct timespec getTimeout( double secs ) { @@ -46,23 +46,26 @@ struct timespec getTimeout( double secs ) { timeout.tv_sec += 1; timeout.tv_nsec -= 1000000000; } - return( timeout ); + return timeout; } Mutex::Mutex() { - if ( pthread_mutex_init( &mMutex, NULL ) < 0 ) - Fatal( "Unable to create pthread mutex: %s", strerror(errno) ); + if ( pthread_mutex_init(&mMutex, NULL) < 0 ) + Error("Unable to create pthread mutex: %s", strerror(errno)); } Mutex::~Mutex() { if ( locked() ) - Warning( "Destroying mutex when locked" ); - if ( pthread_mutex_destroy( &mMutex ) < 0 ) - Fatal( "Unable to destroy pthread mutex: %s", strerror(errno) ); + Warning("Destroying mutex when locked"); + if ( pthread_mutex_destroy(&mMutex) < 0 ) + Error("Unable to destroy pthread mutex: %s", strerror(errno)); } +int Mutex::trylock() { + return pthread_mutex_trylock(&mMutex); +} void Mutex::lock() { - if ( pthread_mutex_lock( &mMutex ) < 0 ) + if ( pthread_mutex_lock(&mMutex) < 0 ) throw ThreadException( stringtf( "Unable to lock pthread mutex: %s", strerror(errno) ) ); //Debug(3, "Lock"); } @@ -101,7 +104,7 @@ Condition::Condition( Mutex &mutex ) : mMutex( mutex ) { Condition::~Condition() { if ( pthread_cond_destroy( &mCondition ) < 0 ) - Fatal( "Unable to destroy pthread condition: %s", strerror(errno) ); + Error("Unable to destroy pthread condition: %s", strerror(errno)); } void Condition::wait() { @@ -141,31 +144,29 @@ template const T ThreadData::getValue() const { mMutex.lock(); const T valueCopy = mValue; mMutex.unlock(); - return( valueCopy ); + return valueCopy; } -template T ThreadData::setValue( const T value ) { +template T ThreadData::setValue(const T value) { mMutex.lock(); const T valueCopy = mValue = value; mMutex.unlock(); - return( valueCopy ); + return valueCopy; } template const T ThreadData::getUpdatedValue() const { - Debug( 8, "Waiting for value update, %p", this ); + Debug(8, "Waiting for value update, %p", this); mMutex.lock(); mChanged = false; - //do { - mCondition.wait(); - //} while ( !mChanged ); + mCondition.wait(); const T valueCopy = mValue; mMutex.unlock(); - Debug( 9, "Got value update, %p", this ); - return( valueCopy ); + Debug(9, "Got value update, %p", this); + return valueCopy; } -template const T ThreadData::getUpdatedValue( double secs ) const { - Debug( 8, "Waiting for value update, %.2f secs, %p", secs, this ); +template const T ThreadData::getUpdatedValue(double secs) const { + Debug(8, "Waiting for value update, %.2f secs, %p", secs, this); mMutex.lock(); mChanged = false; //do { @@ -173,41 +174,41 @@ template const T ThreadData::getUpdatedValue( double secs ) const { //} while ( !mChanged ); const T valueCopy = mValue; mMutex.unlock(); - Debug( 9, "Got value update, %p", this ); - return( valueCopy ); + Debug(9, "Got value update, %p", this ); + return valueCopy; } -template const T ThreadData::getUpdatedValue( int secs ) const { - Debug( 8, "Waiting for value update, %d secs, %p", secs, this ); +template const T ThreadData::getUpdatedValue(int secs) const { + Debug(8, "Waiting for value update, %d secs, %p", secs, this); mMutex.lock(); mChanged = false; //do { - mCondition.wait( secs ); + mCondition.wait(secs); //} while ( !mChanged ); const T valueCopy = mValue; mMutex.unlock(); - Debug( 9, "Got value update, %p", this ); - return( valueCopy ); + Debug(9, "Got value update, %p", this); + return valueCopy; } -template void ThreadData::updateValueSignal( const T value ) { - Debug( 8, "Updating value with signal, %p", this ); +template void ThreadData::updateValueSignal(const T value) { + Debug(8, "Updating value with signal, %p", this); mMutex.lock(); mValue = value; mChanged = true; mCondition.signal(); mMutex.unlock(); - Debug( 9, "Updated value, %p", this ); + Debug(9, "Updated value, %p", this); } template void ThreadData::updateValueBroadcast( const T value ) { - Debug( 8, "Updating value with broadcast, %p", this ); + Debug(8, "Updating value with broadcast, %p", this); mMutex.lock(); mValue = value; mChanged = true; mCondition.broadcast(); mMutex.unlock(); - Debug( 9, "Updated value, %p", this ); + Debug(9, "Updated value, %p", this); } Thread::Thread() : diff --git a/src/zm_thread.h b/src/zm_thread.h index 199d1f764..e1facc6a5 100644 --- a/src/zm_thread.h +++ b/src/zm_thread.h @@ -54,7 +54,7 @@ private: pthread_t pid() { return( pthread_self() ); } #endif public: - explicit ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { + explicit ThreadException( const std::string &message ) : Exception( stringtf("(%d) ", (long int)pid())+message ) { } }; @@ -74,6 +74,7 @@ private: } public: + int trylock(); void lock(); void lock( int secs ); void lock( double secs ); @@ -97,61 +98,53 @@ private: ScopedMutex( const ScopedMutex & ); }; -class Condition -{ +class Condition { private: Mutex &mMutex; pthread_cond_t mCondition; public: - Condition( Mutex &mutex ); + explicit Condition(Mutex &mutex); ~Condition(); void wait(); - bool wait( int secs ); - bool wait( double secs ); + bool wait(int secs); + bool wait(double secs); void signal(); void broadcast(); }; -class Semaphore : public Condition -{ +class Semaphore : public Condition { private: Mutex mMutex; public: - Semaphore() : Condition( mMutex ) - { + Semaphore() : Condition(mMutex) { } - void wait() - { + void wait() { mMutex.lock(); Condition::wait(); mMutex.unlock(); } - bool wait( int secs ) - { + bool wait(int secs) { mMutex.lock(); - bool result = Condition::wait( secs ); + bool result = Condition::wait(secs); mMutex.unlock(); - return( result ); + return result; } - bool wait( double secs ) - { + bool wait(double secs) { mMutex.lock(); - bool result = Condition::wait( secs ); + bool result = Condition::wait(secs); mMutex.unlock(); - return( result ); + return result; } - void signal() - { + void signal() { mMutex.lock(); Condition::signal(); mMutex.unlock(); } - void broadcast() - { + void broadcast() { mMutex.lock(); Condition::broadcast(); mMutex.unlock(); @@ -169,7 +162,7 @@ public: __attribute__((used)) ThreadData() : mValue(0), mCondition( mMutex ) { mChanged = false; } - __attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex ) { + explicit __attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex ) { mChanged = false; } //~ThreadData() {} @@ -200,8 +193,7 @@ public: __attribute__((used)) void updateValueBroadcast( const T value ); }; -class Thread -{ +class Thread { public: typedef void *(*ThreadFunc)( void * ); @@ -224,8 +216,7 @@ protected: virtual ~Thread(); #ifndef SOLARIS - pid_t id() const - { + pid_t id() const { pid_t tid; #ifdef __FreeBSD__ long lwpid; @@ -239,16 +230,14 @@ protected: tid=syscall(SYS_gettid); #endif #endif -return tid; + return tid; } #else - pthread_t id() const - { - return( pthread_self() ); + pthread_t id() const { + return pthread_self(); } #endif - void exit( int p_status = 0 ) - { + void exit( int p_status = 0 ) { //INFO( "Exiting" ); pthread_exit( (void *)&p_status ); } @@ -260,12 +249,11 @@ public: void start(); void join(); void kill( int signal ); - bool isThread() - { + bool isThread() { return( mPid > -1 && pthread_equal( pthread_self(), mThread ) ); } - bool isStarted() const { return( mStarted ); } - bool isRunning() const { return( mRunning ); } + bool isStarted() const { return mStarted; } + bool isRunning() const { return mRunning; } }; #endif // ZM_THREAD_H diff --git a/src/zm_time.h b/src/zm_time.h index de9d2a22f..a9af32777 100644 --- a/src/zm_time.h +++ b/src/zm_time.h @@ -77,8 +77,6 @@ struct DeltaTimeval #define MSEC_PER_SEC 1000 extern struct timeval tv; -typedef typeof(tv.tv_sec) ast_time_t; -typedef typeof(tv.tv_usec) ast_suseconds_t; inline int tvDiffUsec( struct timeval first, struct timeval last ) { diff --git a/src/zm_timer.h b/src/zm_timer.h index 221aec222..da3b95783 100644 --- a/src/zm_timer.h +++ b/src/zm_timer.h @@ -53,8 +53,7 @@ private: pthread_t pid() { return( pthread_self() ); } #endif public: - TimerException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) - { + explicit TimerException( const std::string &message ) : Exception( stringtf("(%d) ", (long int)pid())+message ) { } }; diff --git a/src/zm_user.h b/src/zm_user.h index 2c932dd74..37bf45736 100644 --- a/src/zm_user.h +++ b/src/zm_user.h @@ -59,7 +59,7 @@ public: ~User(); User( User &u ) { Copy(u); } void Copy( const User &u ); - User operator=(const User &u) { + User& operator=(const User &u) { Copy(u); return *this; } diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index 43873b37b..b56fba22d 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -49,7 +49,7 @@ std::string trimSet(std::string str, std::string trimset) { return str.substr( startpos, endpos-startpos+1 ); } -std::string trimSpaces(std::string str) { +std::string trimSpaces(const std::string &str) { return trimSet(str, " \t"); } @@ -94,9 +94,8 @@ const std::string stringtf( const std::string format, ... ) return( tempString ); } -bool startsWith( const std::string &haystack, const std::string &needle ) -{ - return( haystack.substr( 0, needle.length() ) == needle ); +bool startsWith(const std::string &haystack, const std::string &needle) { + return( haystack.substr(0, needle.length()) == needle ); } std::vector split(const std::string &s, char delim) { @@ -109,20 +108,18 @@ std::vector split(const std::string &s, char delim) { return elems; } -StringVector split( const std::string &string, const std::string &chars, int limit ) { +StringVector split(const std::string &string, const std::string &chars, int limit) { StringVector stringVector; std::string tempString = string; std::string::size_type startIndex = 0; std::string::size_type endIndex = 0; //Info( "Looking for '%s' in '%s', limit %d", chars.c_str(), string.c_str(), limit ); - do - { + do { // Find delimiters endIndex = string.find_first_of( chars, startIndex ); //Info( "Got endIndex at %d", endIndex ); - if ( endIndex > 0 ) - { + if ( endIndex > 0 ) { //Info( "Adding '%s'", string.substr( startIndex, endIndex-startIndex ).c_str() ); stringVector.push_back( string.substr( startIndex, endIndex-startIndex ) ); } @@ -130,8 +127,7 @@ StringVector split( const std::string &string, const std::string &chars, int lim break; // Find non-delimiters startIndex = tempString.find_first_not_of( chars, endIndex ); - if ( limit && (stringVector.size() == (unsigned int)(limit-1)) ) - { + if ( limit && (stringVector.size() == (unsigned int)(limit-1)) ) { stringVector.push_back( string.substr( startIndex ) ); break; } @@ -139,22 +135,21 @@ StringVector split( const std::string &string, const std::string &chars, int lim } while ( startIndex != std::string::npos ); //Info( "Finished with %d strings", stringVector.size() ); - return( stringVector ); + return stringVector; } -const std::string join(const StringVector &v, const char * delim ) { +const std::string join(const StringVector &v, const char * delim=",") { std::stringstream ss; - for(size_t i = 0; i < v.size(); ++i) { - if(i != 0) - ss << ","; + for (size_t i = 0; i < v.size(); ++i) { + if ( i != 0 ) + ss << delim; ss << v[i]; } return ss.str(); } -const std::string base64Encode( const std::string &inString ) -{ +const std::string base64Encode(const std::string &inString) { static char base64_table[64] = { '\0' }; if ( !base64_table[0] ) diff --git a/src/zm_utils.h b/src/zm_utils.h index a10c89f48..8352edecb 100644 --- a/src/zm_utils.h +++ b/src/zm_utils.h @@ -28,12 +28,12 @@ typedef std::vector StringVector; -std::string trimSpaces(std::string str); +std::string trimSpaces(const std::string &str); std::string trimSet(std::string str, std::string trimset); std::string replaceAll(std::string str, std::string from, std::string to); const std::string stringtf( const char *format, ... ); -const std::string stringtf( const std::string format, ... ); +const std::string stringtf( const std::string &format, ... ); bool startsWith( const std::string &haystack, const std::string &needle ); StringVector split( const std::string &string, const std::string &chars, int limit=0 ); diff --git a/src/zm_video.cpp b/src/zm_video.cpp index 369819098..22379f2b3 100644 --- a/src/zm_video.cpp +++ b/src/zm_video.cpp @@ -97,6 +97,11 @@ X264MP4Writer::X264MP4Writer( } codec_pf = AV_PIX_FMT_YUV420P; + if ( ! swscaleobj.init() ) { + Error("Failed init swscaleobj"); + return; + } + swscaleobj.SetDefaults(zm_pf, codec_pf, width, height); /* Calculate the image sizes. We will need this for parameter checking */ @@ -211,7 +216,9 @@ int X264MP4Writer::Open() { int X264MP4Writer::Close() { /* Flush all pending frames */ for ( int i = (x264_encoder_delayed_frames(x264enc) + 1); i > 0; i-- ) { - x264encodeloop(true); +Debug(1,"Encoding delayed frame"); + if ( x264encodeloop(true) < 0 ) + break; } /* Close the encoder */ @@ -220,6 +227,7 @@ int X264MP4Writer::Close() { /* Close MP4 handle */ MP4Close(mp4h); + Debug(1,"Optimising"); /* Required for proper HTTP streaming */ MP4Optimize((path + ".incomplete").c_str(), path.c_str()); @@ -228,7 +236,7 @@ int X264MP4Writer::Close() { bOpen = false; - Debug(7, "Video closed. Total frames: %d", frame_count); + Debug(1, "Video closed. Total frames: %d", frame_count); return 0; } @@ -401,7 +409,7 @@ int X264MP4Writer::x264config() { return 0; } -void X264MP4Writer::x264encodeloop(bool bFlush) { +int X264MP4Writer::x264encodeloop(bool bFlush) { x264_nal_t* nals; int i_nals; int frame_size; @@ -413,7 +421,7 @@ void X264MP4Writer::x264encodeloop(bool bFlush) { } if ( frame_size > 0 || bFlush ) { - Debug(8, "x264 Frame: %d PTS: %d DTS: %d Size: %d\n", + Debug(1, "x264 Frame: %d PTS: %d DTS: %d Size: %d\n", frame_count, x264picout.i_pts, x264picout.i_dts, frame_size); /* Handle the previous frame */ @@ -490,11 +498,12 @@ void X264MP4Writer::x264encodeloop(bool bFlush) { } } else if ( frame_size == 0 ) { - Debug(7, "x264 encode returned zero. Delayed frames: %d", + Debug(1, "x264 encode returned zero. Delayed frames: %d", x264_encoder_delayed_frames(x264enc)); } else { Error("x264 encode failed: %d", frame_size); } + return frame_size; } #endif // ZM_VIDEOWRITER_X264MP4 diff --git a/src/zm_video.h b/src/zm_video.h index 2b71f12df..46d7c3635 100644 --- a/src/zm_video.h +++ b/src/zm_video.h @@ -146,7 +146,7 @@ protected: /* Internal functions */ int x264config(); - void x264encodeloop(bool bFlush = false); + int x264encodeloop(bool bFlush = false); /* x264 objects */ x264_t* x264enc; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 253eb500a..1615427ac 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -20,7 +20,7 @@ #define __STDC_FORMAT_MACROS 1 -#include +#include #include #include @@ -31,6 +31,13 @@ extern "C" { #include "libavutil/time.h" } +VideoStore::CodecData VideoStore::codec_data[] = { + { AV_CODEC_ID_H264, "h264", "h264_omx", AV_PIX_FMT_YUV420P }, + { AV_CODEC_ID_H264, "h264", "h264", AV_PIX_FMT_YUV420P }, + { AV_CODEC_ID_H264, "h264", "libx264", AV_PIX_FMT_YUV420P }, + { AV_CODEC_ID_MJPEG, "mjpeg", "mjpeg", AV_PIX_FMT_YUVJ422P }, +}; + VideoStore::VideoStore( const char *filename_in, const char *format_in, @@ -39,7 +46,7 @@ VideoStore::VideoStore( Monitor *p_monitor ) { -monitor = p_monitor; + monitor = p_monitor; video_in_stream = p_video_in_stream; audio_in_stream = p_audio_in_stream; filename = filename_in; @@ -49,6 +56,9 @@ monitor = p_monitor; frame_count = 0; in_frame = NULL; + video_out_codec = NULL; + video_out_stream = NULL; + converted_in_samples = NULL; audio_out_codec = NULL; audio_in_codec = NULL; @@ -140,95 +150,34 @@ bool VideoStore::open() { video_in_stream_index = 0; } - if ( monitor->OutputCodec() == "mjpeg" ) { -Debug(2,"Using mjpeg"); - video_out_codec = avcodec_find_encoder_by_name("mjpeg"); - if ( ! video_out_codec ) { - Debug(1, "Didn't find mjpeg encoder"); - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); - } - video_out_ctx = avcodec_alloc_context3( video_out_codec ); - video_out_ctx->codec_id = video_out_codec->id; - video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; - - } else if ( monitor->OutputCodec() == "h264" || monitor->OutputCodec() == "" ) { - AVPixelFormat pf = AV_PIX_FMT_YUV420P; - - // First try hardware accell - video_out_codec = avcodec_find_encoder_by_name("h264_omx"); - if ( ! video_out_codec ) { - Debug(1, "Didn't find omx"); - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); - } - if ( ! video_out_codec ) { - if ( AV_CODEC_ID_NONE == -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_in_stream->codecpar->codec_id -#else - video_in_stream->codec->codec_id + video_out_ctx = avcodec_alloc_context3(NULL); + if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; #endif - ) { - Debug(1, "trying xh264rgb"); - // We will be encoding rgb images, so prefer - video_out_codec = avcodec_find_encoder_by_name("libx264rgb"); - if ( ! video_out_codec ) { - video_out_codec = avcodec_find_encoder_by_name("libx264"); - } else { - pf = -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - (AVPixelFormat)video_in_stream->codecpar->format; -#else - video_in_stream->codec->pix_fmt; -#endif - } - } else { - video_out_codec = avcodec_find_encoder_by_name("libx264"); - pf = AV_PIX_FMT_YUV420P; - } - } - // Need to do lookup by codec_id - if ( ! video_out_codec ) { - Error("Didn't find h264 encoder"); - video_out_codec = NULL; - return false; - } - Debug(1, "Using %s for codec", video_out_codec->name); - video_out_ctx = avcodec_alloc_context3(video_out_codec); - if ( AV_CODEC_ID_H264 != video_out_ctx->codec_id ) { - Warning("Have to set codec_id?"); - video_out_ctx->codec_id = AV_CODEC_ID_H264; - } - - video_out_ctx->pix_fmt = pf; - video_out_ctx->level = 32; - - } else { - Error("Unsupported output codec selected"); - return false; + } + int wanted_codec = monitor->OutputCodec(); + if ( ! wanted_codec ) { + // default to h264 + wanted_codec = AV_CODEC_ID_H264; } - // Copy params from instream to ctx // // FIXME SHould check that we are set to passthrough - if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { + if ( video_in_stream && ( video_in_ctx->codec_id == wanted_codec ) ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); #else ret = avcodec_copy_context( video_out_ctx, video_in_ctx ); #endif + // Copy params from instream to ctx if ( ret < 0 ) { Error("Could not initialize ctx parameteres"); return false; } //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate video_out_ctx->time_base = video_in_ctx->time_base; - - if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { -#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -#else - video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; -#endif - } // Fix deprecated formats switch ( video_out_ctx->pix_fmt ) { case AV_PIX_FMT_YUVJ422P : @@ -243,128 +192,9 @@ Debug(2,"Using mjpeg"); case AV_PIX_FMT_NONE : case AV_PIX_FMT_YUVJ420P : default: - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; break; } - zm_dump_codec(video_out_ctx); - - } else { - - /** Create a new frame to store the */ - if ( !(video_in_frame = zm_av_frame_alloc()) ) { - Error("Could not allocate video_in frame"); - return false; - } - // Don't have an input stream, so need to tell it what we are sending it, or are transcoding - video_out_ctx->width = monitor->Width(); - video_out_ctx->height = monitor->Height(); - video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; - - if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { -#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -#else - video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; -#endif - } - - /* video time_base can be set to whatever is handy and supported by encoder */ - //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - video_out_ctx->time_base = (AVRational){1, 30}; // microseconds as base frame rate - video_out_ctx->framerate = (AVRational){30,1}; - //video_out_ctx->gop_size = 12; - //video_out_ctx->qmin = 10; - //video_out_ctx->qmax = 51; - //video_out_ctx->qcompress = 0.6; - video_out_ctx->bit_rate = 400*1024; - video_out_ctx->thread_count = 0; - - if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { - video_out_ctx->max_b_frames = 1; - if ( video_out_ctx->priv_data ) { - av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); - //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); - } else { - Debug(2, "Not setting priv_data"); - } - } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - /* just for testing, we also add B frames */ - video_out_ctx->max_b_frames = 2; - } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { - /* Needed to avoid using macroblocks in which some coeffs overflow. - * This does not happen with normal video, it just happens here as - * the motion of the chroma plane does not match the luma plane. */ - video_out_ctx->mb_decision = 2; - } - - AVDictionary *opts = 0; - std::string Options = monitor->GetEncoderOptions(); - ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); - if ( ret < 0 ) { - Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); - } else { - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Debug( 3, "Encoder Option %s=%s", e->key, e->value ); - } - } - - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Warning("Can't open video codec (%s)! %s, trying h264", - video_out_codec->name, - av_make_error_string(ret).c_str() - ); - video_out_codec = avcodec_find_encoder_by_name("h264"); - if ( ! video_out_codec ) { - Error("Can't find h264 encoder"); - video_out_codec = avcodec_find_encoder_by_name("libx264"); - if ( ! video_out_codec ) { - Error("Can't find libx264 encoder"); - return false; - } - } - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Error("Can't open video codec (%s)! %s", video_out_codec->name, - av_make_error_string(ret).c_str() ); -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // We allocate and copy in newer ffmpeg, so need to free it - avcodec_free_context(&video_out_ctx); -#endif - video_out_ctx=NULL; - - return false; - } - } // end if can't open codec - Debug(2,"Sucess opening codec"); - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); - } - av_dict_free(&opts); - - if ( !video_out_ctx->codec_tag ) { - video_out_ctx->codec_tag = - av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id ); - Debug(2, "No codec_tag, setting to h264 ? "); - } - } // end if copying or trasncoding - - video_out_stream = avformat_new_stream(oc, video_out_codec); - if ( ! video_out_stream ) { - Error("Unable to create video out stream"); - return false; - } -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); - if ( ret < 0 ) { - Error("Could not initialize stream parameteres"); - return false; - } -#else - avcodec_copy_context(video_out_stream->codec, video_out_ctx); -#endif - - if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { // Only set orientation if doing passthrough, otherwise the frame image will be rotated Monitor::Orientation orientation = monitor->getOrientation(); if ( orientation ) { @@ -382,23 +212,140 @@ Debug(2,"Using mjpeg"); } else { Warning("Unsupported Orientation(%d)", orientation); } - } + } // end if orientation + } else { + for ( unsigned int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) { + if ( codec_data[i].codec_id != monitor->OutputCodec() ) + continue; + + video_out_codec = avcodec_find_encoder_by_name(codec_data[i].codec_name); + if ( ! video_out_codec ) { + Debug(1, "Didn't find encoder for %s", codec_data[i].codec_name); + continue; + } + + Debug(1, "Using %s for codec", video_out_codec->name); + //video_out_ctx = avcodec_alloc_context3(video_out_codec); + if ( video_out_codec->id != video_out_ctx->codec_id ) { + Warning("Have to set codec_id?"); + video_out_ctx->codec_id = AV_CODEC_ID_H264; + } + + video_out_ctx->pix_fmt = codec_data[i].pix_fmt; + video_out_ctx->level = 32; + + // Don't have an input stream, so need to tell it what we are sending it, or are transcoding + video_out_ctx->width = monitor->Width(); + video_out_ctx->height = monitor->Height(); + video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; + + /* video time_base can be set to whatever is handy and supported by encoder */ + //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + video_out_ctx->time_base = (AVRational){1, 30}; // microseconds as base frame rate + video_out_ctx->framerate = (AVRational){30,1}; + //video_out_ctx->gop_size = 12; + //video_out_ctx->qmin = 10; + //video_out_ctx->qmax = 51; + //video_out_ctx->qcompress = 0.6; + video_out_ctx->bit_rate = 400*1024; + video_out_ctx->thread_count = 0; + + if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { + video_out_ctx->max_b_frames = 1; + if ( video_out_ctx->priv_data ) { + av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); + //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); + } else { + Debug(2, "Not setting priv_data"); + } + } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + /* just for testing, we also add B frames */ + video_out_ctx->max_b_frames = 2; + } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + /* Needed to avoid using macroblocks in which some coeffs overflow. + * This does not happen with normal video, it just happens here as + * the motion of the chroma plane does not match the luma plane. */ + video_out_ctx->mb_decision = 2; + } + + AVDictionary *opts = 0; + std::string Options = monitor->GetEncoderOptions(); + ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); + if ( ret < 0 ) { + Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); + } else { + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Debug( 3, "Encoder Option %s=%s", e->key, e->value ); + } + } + + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Warning("Can't open video codec (%s) %s", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + video_out_codec = NULL; + } + + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); + } + av_dict_free(&opts); + if ( video_out_codec ) break; + + } // end foreach codec + + if ( ! video_out_codec ) { + Error("Can't open video codec!"); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // We allocate and copy in newer ffmpeg, so need to free it + avcodec_free_context(&video_out_ctx); +#endif + video_out_ctx = NULL; + + return false; + } // end if can't open codec + + Debug(2,"Sucess opening codec"); + + } // end if copying or trasncoding + + if ( !video_out_ctx->codec_tag ) { + video_out_ctx->codec_tag = + av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id ); + Debug(2, "No codec_tag, setting to h264 ? "); } + video_out_stream = avformat_new_stream(oc, video_out_codec); + if ( ! video_out_stream ) { + Error("Unable to create video out stream"); + return false; + } +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); + if ( ret < 0 ) { + Error("Could not initialize stream parameteres"); + return false; + } +#else + avcodec_copy_context(video_out_stream->codec, video_out_ctx); +#endif + if ( audio_in_stream ) { audio_in_stream_index = audio_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_in_ctx = avcodec_alloc_context3(NULL); ret = avcodec_parameters_to_context(audio_in_ctx, - audio_in_stream->codecpar); + audio_in_stream->codecpar); #else audio_in_ctx = audio_in_stream->codec; #endif if ( audio_in_ctx->codec_id != AV_CODEC_ID_AAC ) { static char error_buffer[256]; - avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, - 0); + avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); Debug(2, "Got something other than AAC (%s)", error_buffer); if ( !setup_resampler() ) { @@ -409,9 +356,9 @@ Debug(2,"Using mjpeg"); audio_out_stream = #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec)); + avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec)); #else - avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec); + avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec); #endif if ( !audio_out_stream ) { Error("Unable to create audio out stream\n"); @@ -424,13 +371,13 @@ Debug(2,"Using mjpeg"); // Copy params from instream to ctx if ( (ret = avcodec_parameters_to_context(audio_out_ctx, audio_in_stream->codecpar) ) < 0 ) { Error("Unable to copy audio params to ctx %s\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } // Then from ctx to out_stream ret = avcodec_parameters_from_context(audio_out_stream->codecpar, audio_out_ctx); if ( ret < 0 ) { Error("Unable to copy audio params to stream %s\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } if ( !audio_out_ctx->codec_tag ) { @@ -445,7 +392,7 @@ Debug(2,"Using mjpeg"); #endif if ( ret < 0 ) { Error("Unable to copy audio ctx %s\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); audio_out_stream = NULL; } else { if ( audio_out_ctx->channels > 1 ) { @@ -456,26 +403,24 @@ Debug(2,"Using mjpeg"); } } } // end if audio_out_stream - } // end if is AAC + } // end if is AAC if ( audio_out_stream ) { if (oc->oformat->flags & AVFMT_GLOBALHEADER) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; #else - audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; #endif } } } // end if audio_in_stream /* open the out file, if needed */ - if (!(out_format->flags & AVFMT_NOFILE)) { - ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL); - if (ret < 0) { + if ( !(out_format->flags & AVFMT_NOFILE) ) { + if ( (ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL) ) < 0 ) { Error("Could not open out file '%s': %s\n", filename, - av_make_error_string(ret).c_str()); - + av_make_error_string(ret).c_str()); return false; } } @@ -495,7 +440,7 @@ Debug(2,"Using mjpeg"); } if ( ret < 0 ) { Error("Error occurred when writing out file header to %s: %s\n", - filename, av_make_error_string(ret).c_str()); + filename, av_make_error_string(ret).c_str()); return false; } if ( opts ) av_dict_free(&opts); @@ -506,8 +451,8 @@ Debug(2,"Using mjpeg"); } // end bool VideoStore::open() void VideoStore::write_audio_packet( AVPacket &pkt ) { -//Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, - //pkt.dts, pkt.duration); + //Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, + //pkt.dts, pkt.duration); pkt.pts = audio_next_pts; pkt.dts = audio_next_dts; @@ -525,98 +470,86 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { av_interleaved_write_frame(oc, &pkt); } // end void VideoStore::Write_audio_packet( AVPacket &pkt ) +void VideoStore::flush_codecs() { + // The codec queues data. We need to send a flush command and out + // whatever we get. Failures are not fatal. + + // I got crashes if the codec didn't do DELAY, so let's test for it. + if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + AV_CODEC_CAP_DELAY +#else + CODEC_CAP_DELAY +#endif + ) ) { + + // Put encoder into flushing mode + avcodec_send_frame(video_out_ctx, NULL); + while (1) { + AVPacket pkt; + // Without these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_receive_packet(video_out_ctx, &pkt)) < 0 ) { + if ( AVERROR_EOF != ret ) { + Error("Error encoding audio while flushing (%d) (%s)", ret, + av_err2str(ret)); + } + break; + } +#else + int got_packet = 0; + if ( (ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet)) < 0 ) { + Error("ERror encoding video while flushing (%d) (%s)", ret, av_err2str(ret)); + break; + } + if ( !got_packet ) { + break; + } +#endif + write_video_packet(pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if have delay capability + + if ( audio_out_codec ) { + avcodec_send_frame(audio_out_ctx, NULL); + while (1) { + AVPacket pkt; + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_receive_packet(audio_out_ctx, &pkt) ) < 0 ) { + if ( AVERROR_EOF != ret ) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); + } + break; + } +#else + int got_packet = 0; + if ( (ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet)) < 0 ) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); + break; + } + Debug(1, "Have audio encoder, need to flush it's out"); + if (!got_packet) { + break; + } +#endif + write_audio_packet(pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if audio_out_codec +} + VideoStore::~VideoStore() { if ( oc->pb ) { if ( ( video_out_ctx->codec_id != video_in_ctx->codec_id ) || audio_out_codec ) { Debug(2,"Different codecs between in and out"); - // The codec queues data. We need to send a flush command and out - // whatever we get. Failures are not fatal. - AVPacket pkt; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - - // I got crashes if the codec didn't do DELAY, so let's test for it. - if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - AV_CODEC_CAP_DELAY -#else - CODEC_CAP_DELAY -#endif - ) ) { - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Put encoder into flushing mode - avcodec_send_frame(video_out_ctx, NULL); - while (1) { - ret = avcodec_receive_packet(video_out_ctx, &pkt); - if (ret < 0) { - if (AVERROR_EOF != ret) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, - av_err2str(ret)); - } - break; - } -#else - while (1) { - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - int got_packet = 0; - ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); - if ( ret < 0 ) { - Error("ERror encoding video while flushing (%d) (%s)", ret, av_err2str(ret)); - break; - } - if (!got_packet) { - break; - } -#endif - write_video_packet(pkt); - zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if have delay capability - - if ( audio_out_codec ) { - // The codec queues data. We need to send a flush command and out - // whatever we get. Failures are not fatal. - AVPacket pkt; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Put encoder into flushing mode - avcodec_send_frame(audio_out_ctx, NULL); - while (1) { - if ( (ret = avcodec_receive_packet(audio_out_ctx, &pkt) ) < 0 ) { - if ( AVERROR_EOF != ret ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); - } - break; - } -#else - while (1) { - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - int got_packet = 0; - if ( (ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet)) < 0 ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); - break; - } - Debug(1, "Have audio encoder, need to flush it's out"); - if (!got_packet) { - break; - } -#endif - write_audio_packet(pkt); - zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if audio_out_codec + flush_codecs(); } // end if buffers // Flush Queues @@ -647,7 +580,7 @@ VideoStore::~VideoStore() { // allocation/de-allocation constantly, or whether we can just re-use it. // Just do a file open/close/writeheader/etc. // What if we were only doing audio recording? - + if ( video_out_stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it @@ -664,13 +597,13 @@ VideoStore::~VideoStore() { } if ( audio_out_stream ) { if ( audio_in_codec ) { - avcodec_close(audio_in_ctx); + avcodec_close(audio_in_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // We allocate and copy in newer ffmpeg, so need to free it - avcodec_free_context(&audio_in_ctx); + // We allocate and copy in newer ffmpeg, so need to free it + avcodec_free_context(&audio_in_ctx); #endif - audio_in_ctx = NULL; - audio_in_codec = NULL; + audio_in_ctx = NULL; + audio_in_codec = NULL; } // end if audio_in_codec avcodec_close(audio_out_ctx); @@ -683,6 +616,10 @@ VideoStore::~VideoStore() { avresample_close(resample_ctx); avresample_free(&resample_ctx); } + if ( in_frame ) { + av_frame_free(&in_frame); + in_frame = NULL; + } if ( out_frame ) { av_frame_free(&out_frame); out_frame = NULL; @@ -692,7 +629,7 @@ VideoStore::~VideoStore() { converted_in_samples = NULL; } #endif - } + } // end if audio_out_stream #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( video_in_ctx ) { avcodec_free_context(&video_in_ctx); @@ -707,7 +644,7 @@ VideoStore::~VideoStore() { /* free the stream */ avformat_free_context(oc); -} +} // VideoStore::~VideoStore() bool VideoStore::setup_resampler() { //I think this is unneccessary, we should be able to just pass in the decoder from the input. @@ -766,16 +703,16 @@ bool VideoStore::setup_resampler() { Debug(4, "Sample rate is good"); } else { audio_out_ctx->sample_rate = - audio_out_codec->supported_samplerates[0]; + audio_out_codec->supported_samplerates[0]; Debug(1, "Sampel rate is no good, setting to (%d)", - audio_out_codec->supported_samplerates[0]); + audio_out_codec->supported_samplerates[0]); } } /* check that the encoder supports s16 pcm in */ if ( !check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt) ) { Debug(3, "Encoder does not support sample format %s, setting to FLTP", - av_get_sample_fmt_name(audio_out_ctx->sample_fmt)); + av_get_sample_fmt_name(audio_out_ctx->sample_fmt)); audio_out_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; } @@ -791,7 +728,7 @@ bool VideoStore::setup_resampler() { ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); av_dict_free(&opts); if ( ret < 0 ) { - Fatal("could not open codec (%d) (%s)\n", ret, av_make_error_string(ret).c_str()); + Error("could not open codec (%d) (%s)\n", ret, av_make_error_string(ret).c_str()); audio_out_codec = NULL; audio_out_ctx = NULL; audio_out_stream = NULL; @@ -813,26 +750,26 @@ bool VideoStore::setup_resampler() { #endif Debug(1, - "Audio out context bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " - "layout(%d) frame_size(%d)", - audio_out_ctx->bit_rate, audio_out_ctx->sample_rate, - audio_out_ctx->channels, audio_out_ctx->sample_fmt, - audio_out_ctx->channel_layout, audio_out_ctx->frame_size); + "Audio out context bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_ctx->bit_rate, audio_out_ctx->sample_rate, + audio_out_ctx->channels, audio_out_ctx->sample_fmt, + audio_out_ctx->channel_layout, audio_out_ctx->frame_size); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) Debug(1, - "Audio out stream bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " - "layout(%d) frame_size(%d)", - audio_out_stream->codecpar->bit_rate, audio_out_stream->codecpar->sample_rate, - audio_out_stream->codecpar->channels, audio_out_stream->codecpar->format, - audio_out_stream->codecpar->channel_layout, audio_out_stream->codecpar->frame_size); + "Audio out stream bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_stream->codecpar->bit_rate, audio_out_stream->codecpar->sample_rate, + audio_out_stream->codecpar->channels, audio_out_stream->codecpar->format, + audio_out_stream->codecpar->channel_layout, audio_out_stream->codecpar->frame_size); #else Debug(1, - "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " - "layout(%d) frame_size(%d)", - audio_out_stream->codec->bit_rate, audio_out_stream->codec->sample_rate, - audio_out_stream->codec->channels, audio_out_stream->codec->sample_fmt, - audio_out_stream->codec->channel_layout, audio_out_stream->codec->frame_size); + "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_stream->codec->bit_rate, audio_out_stream->codec->sample_rate, + audio_out_stream->codec->channels, audio_out_stream->codec->sample_fmt, + audio_out_stream->codec->channel_layout, audio_out_stream->codec->frame_size); #endif /** Create a new frame to store the audio samples. */ @@ -866,7 +803,7 @@ bool VideoStore::setup_resampler() { } else { Debug(1, "channel layout. set it to mono (%d).", audio_in_ctx->channel_layout); av_opt_set_int(resample_ctx, "in_channel_layout", - audio_in_ctx->channel_layout, 0); + audio_in_ctx->channel_layout, 0); } av_opt_set_int(resample_ctx, "in_sample_fmt", audio_in_ctx->sample_fmt, 0); @@ -876,11 +813,11 @@ bool VideoStore::setup_resampler() { // audio_out_ctx->channel_layout, 0); av_opt_set_int(resample_ctx, "out_channel_layout", mono_layout, 0); av_opt_set_int(resample_ctx, "out_sample_fmt", - audio_out_ctx->sample_fmt, 0); + audio_out_ctx->sample_fmt, 0); av_opt_set_int(resample_ctx, "out_sample_rate", - audio_out_ctx->sample_rate, 0); + audio_out_ctx->sample_rate, 0); av_opt_set_int(resample_ctx, "out_channels", - audio_out_ctx->channels, 0); + audio_out_ctx->channels, 0); if ( (ret = avresample_open(resample_ctx)) < 0 ) { Error("Could not open resample ctx\n"); @@ -905,9 +842,9 @@ bool VideoStore::setup_resampler() { // Setup the data pointers in the AVFrame if ( avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, - audio_out_ctx->sample_fmt, - (const uint8_t *)converted_in_samples, - audioSampleBuffer_size, 0) < 0 ) { + audio_out_ctx->sample_fmt, + (const uint8_t *)converted_in_samples, + audioSampleBuffer_size, 0) < 0 ) { Error("Could not allocate converted in sample pointers\n"); return false; } @@ -921,7 +858,6 @@ bool VideoStore::setup_resampler() { #endif } // end bool VideoStore::setup_resampler() - int VideoStore::writePacket( ZMPacket *ipkt ) { if ( ipkt->packet.stream_index == video_in_stream_index ) { return writeVideoFramePacket( ipkt ); @@ -1019,7 +955,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->display_picture_number = frame_count; zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - zm_packet->out_frame->pkt_duration = 0; + zm_packet->out_frame->pkt_duration = 0; #endif if ( ! video_start_pts ) { @@ -1064,15 +1000,15 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { if ( AVERROR(EAGAIN) == ret ) { // THe codec may need more samples than it has, perfectly valid Debug(3, "Could not recieve packet (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); return 0; } else { Error("Could not recieve packet (error %d = '%s')", ret, - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } return -1; } -//Debug(2, "Got packet using receive_packet, dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); + //Debug(2, "Got packet using receive_packet, dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); #else av_init_packet(&opkt); opkt.data = NULL; @@ -1081,7 +1017,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { if ( (ret = avcodec_encode_video2( video_out_ctx, &opkt, zm_packet->out_frame, &data_present)) < 0) { Error("Could not encode frame (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; } @@ -1121,13 +1057,13 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.dts = av_rescale_q( ipkt->dts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); else opkt.dts = 0; - Debug(2, "out_stream_time_base(%d/%d) in_stream_time_base(%d/%d) video_start_pts(%" PRId64 ")", - video_out_stream->time_base.num, video_out_stream->time_base.den, - video_in_stream->time_base.num, video_in_stream->time_base.den, - video_start_pts - ); + Debug(2, "out_stream_time_base(%d/%d) in_stream_time_base(%d/%d) video_start_pts(%" PRId64 ")", + video_out_stream->time_base.num, video_out_stream->time_base.den, + video_in_stream->time_base.num, video_in_stream->time_base.den, + video_start_pts + ); - dumpPacket(&opkt); + dumpPacket(&opkt); opkt.duration = av_rescale_q( opkt.duration, video_in_stream->time_base, video_out_stream->time_base); } @@ -1145,9 +1081,9 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { if ( opkt.dts > opkt.pts ) { Debug(1, - "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " - "before presentation.", - opkt.dts, opkt.pts); + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " + "before presentation.", + opkt.dts, opkt.pts); opkt.dts = opkt.pts; } @@ -1160,31 +1096,31 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); //dumpPacket(&opkt); - //} else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { + //} else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { //Warning("%s:%d: DTS out of order: next:%lld \u226E opkt.dts %lld; discarding frame", - //__FILE__, __LINE__, video_next_dts, opkt.dts); + //__FILE__, __LINE__, video_next_dts, opkt.dts); //video_next_dts = opkt.dts; //dumpPacket(&opkt); - } else { - if ( (ret = av_interleaved_write_frame(oc, &opkt)) < 0 ) { - // There's nothing we can really do if the frame is rejected, just drop it - // and get on with the next - Warning( - "%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) " - " ", - __FILE__, __LINE__, av_make_error_string(ret).c_str(), ret); +} else { + if ( (ret = av_interleaved_write_frame(oc, &opkt)) < 0 ) { + // There's nothing we can really do if the frame is rejected, just drop it + // and get on with the next + Warning( + "%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) " + " ", + __FILE__, __LINE__, av_make_error_string(ret).c_str(), ret); - //dumpPacket(&safepkt); + //dumpPacket(&safepkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( video_in_stream ) - zm_dump_codecpar(video_in_stream->codecpar); - zm_dump_codecpar(video_out_stream->codecpar); + if ( video_in_stream ) + zm_dump_codecpar(video_in_stream->codecpar); + zm_dump_codecpar(video_out_stream->codecpar); #endif - } else { - packets_written += 1; - } + } else { + packets_written += 1; } +} } // end void VideoStore::write_video_packet @@ -1196,7 +1132,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { if ( !audio_out_stream ) { Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at - // the moment + // the moment } if ( audio_out_codec ) { @@ -1213,10 +1149,10 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { return 0; } Debug(2, - "Input Frame: samples(%d), format(%d), sample_rate(%d), channel " - "layout(%d)", - in_frame->nb_samples, in_frame->format, - in_frame->sample_rate, in_frame->channel_layout); + "Input Frame: samples(%d), format(%d), sample_rate(%d), channel " + "layout(%d)", + in_frame->nb_samples, in_frame->format, + in_frame->sample_rate, in_frame->channel_layout); #else /** * Decode the audio frame stored in the packet. @@ -1226,9 +1162,9 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { */ int data_present; if ( (ret = avcodec_decode_audio4(audio_in_ctx, in_frame, - &data_present, ipkt)) < 0 ) { + &data_present, ipkt)) < 0 ) { Error("Could not decode frame (error '%s')\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); dumpPacket(ipkt); av_frame_free(&in_frame); return 0; @@ -1244,9 +1180,9 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { // Resample the in into the audioSampleBuffer until we proceed the whole // decoded data if ((ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, in_frame->nb_samples)) < 0) { + 0, in_frame->nb_samples)) < 0) { Error("Could not resample frame (error '%s')\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); av_frame_unref(in_frame); return 0; } @@ -1265,9 +1201,9 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { return 0; } Debug(2, - "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", - out_frame->nb_samples, out_frame->format, - out_frame->sample_rate, out_frame->channel_layout); + "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", + out_frame->nb_samples, out_frame->format, + out_frame->sample_rate, out_frame->channel_layout); av_init_packet(&opkt); Debug(5, "after init packet"); @@ -1275,7 +1211,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ((ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0) { Error("Could not send frame (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; } @@ -1286,10 +1222,10 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { if ( AVERROR(EAGAIN) == ret ) { // THe codec may need more samples than it has, perfectly valid Debug(3, "Could not recieve packet (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } else { Error("Could not recieve packet (error %d = '%s')", ret, - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } //zm_av_packet_unref(&opkt); av_frame_unref(in_frame); @@ -1298,9 +1234,9 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { } #else if ( (ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame, - &data_present)) < 0) { + &data_present)) < 0) { Error("Could not encode frame (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; } @@ -1321,12 +1257,12 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { opkt.duration = ipkt->duration; } -// PTS is difficult, because of the buffering of the audio packets in the -// resampler. So we have to do it once we actually have a packet... -// audio_last_pts is the pts of ipkt, audio_next_pts is the last pts of the -// out + // PTS is difficult, because of the buffering of the audio packets in the + // resampler. So we have to do it once we actually have a packet... + // audio_last_pts is the pts of ipkt, audio_next_pts is the last pts of the + // out -// Scale the PTS of the outgoing packet to be the correct time base + // Scale the PTS of the outgoing packet to be the correct time base #if 0 if ( ipkt->pts != AV_NOPTS_VALUE ) { if ( !audio_last_pts ) { @@ -1352,60 +1288,60 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { #endif #if 0 - if ( ipkt->dts == AV_NOPTS_VALUE ) { - // So if the in has no dts assigned... still need an out dts... so we use cur_dts? + if ( ipkt->dts == AV_NOPTS_VALUE ) { + // So if the in has no dts assigned... still need an out dts... so we use cur_dts? - if ( audio_last_dts >= audio_in_stream->cur_dts ) { - Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_in_stream->cur_dts); - opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); - } else { - opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); - } - audio_last_dts = audio_in_stream->cur_dts; - Debug(2, "opkt.dts = %d from video_in_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_in_stream->cur_dts, audio_last_dts); + if ( audio_last_dts >= audio_in_stream->cur_dts ) { + Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_in_stream->cur_dts); + opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); } else { - if ( audio_last_dts >= ipkt->dts ) { - Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts ); - opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts, audio_in_stream->time_base, audio_out_stream->time_base); - } else { - opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_in_stream->time_base, audio_out_stream->time_base); - Debug(2, "opkt.dts = %d from previous(%d) + ( ipkt->dts(%d) - last_dts(%d) )", opkt.dts, audio_next_dts, ipkt->dts, audio_last_dts ); - } + opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); + } + audio_last_dts = audio_in_stream->cur_dts; + Debug(2, "opkt.dts = %d from video_in_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_in_stream->cur_dts, audio_last_dts); + } else { + if ( audio_last_dts >= ipkt->dts ) { + Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts ); + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts, audio_in_stream->time_base, audio_out_stream->time_base); + } else { + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_in_stream->time_base, audio_out_stream->time_base); + Debug(2, "opkt.dts = %d from previous(%d) + ( ipkt->dts(%d) - last_dts(%d) )", opkt.dts, audio_next_dts, ipkt->dts, audio_last_dts ); } } +} #endif - // audio_last_dts = ipkt->dts; - if ( opkt.dts > opkt.pts ) { - Debug(1, - "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " - "before presentation.", - opkt.dts, opkt.pts); - opkt.dts = opkt.pts; - } +// audio_last_dts = ipkt->dts; +if ( opkt.dts > opkt.pts ) { + Debug(1, + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " + "before presentation.", + opkt.dts, opkt.pts); + opkt.dts = opkt.pts; +} - //opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; - // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, - // audio_out_stream->time_base); - dumpPacket(&opkt); +//opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; +// opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, +// audio_out_stream->time_base); +dumpPacket(&opkt); - // pkt.pos: byte position in stream, -1 if unknown - opkt.pos = -1; - opkt.stream_index = audio_out_stream->index; - audio_next_dts = opkt.dts + opkt.duration; - audio_next_pts = opkt.pts + opkt.duration; +// pkt.pos: byte position in stream, -1 if unknown +opkt.pos = -1; +opkt.stream_index = audio_out_stream->index; +audio_next_dts = opkt.dts + opkt.duration; +audio_next_pts = opkt.pts + opkt.duration; - AVPacket safepkt; - memcpy(&safepkt, &opkt, sizeof(AVPacket)); - ret = av_interleaved_write_frame(oc, &opkt); - if ( ret != 0 ) { - Error("Error writing audio frame packet: %s\n", - av_make_error_string(ret).c_str()); - dumpPacket(&safepkt); - } else { - Debug(2, "Success writing audio frame"); - } - zm_av_packet_unref(&opkt); - return 1; +AVPacket safepkt; +memcpy(&safepkt, &opkt, sizeof(AVPacket)); +ret = av_interleaved_write_frame(oc, &opkt); +if ( ret != 0 ) { + Error("Error writing audio frame packet: %s\n", + av_make_error_string(ret).c_str()); + dumpPacket(&safepkt); +} else { + Debug(2, "Success writing audio frame"); +} +zm_av_packet_unref(&opkt); +return 1; } // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) int VideoStore::write_packets( zm_packetqueue &queue ) { diff --git a/src/zm_videostore.h b/src/zm_videostore.h index d2b14ae2e..486daf989 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -3,7 +3,6 @@ #include "zm_ffmpeg.h" extern "C" { - #ifdef HAVE_LIBAVRESAMPLE #include "libavresample/avresample.h" #endif @@ -19,6 +18,15 @@ class VideoStore; class VideoStore { private: +struct CodecData { + const int codec_id; + const char *codec_codec; + const char *codec_name; + const enum AVPixelFormat pix_fmt; + +}; +static struct CodecData codec_data[]; + Monitor *monitor; AVOutputFormat *out_format; AVFormatContext *oc; @@ -53,7 +61,7 @@ int audio_in_stream_index; AVCodec *audio_out_codec; AVCodecContext *audio_out_ctx; #ifdef HAVE_LIBAVRESAMPLE -AVAudioResampleContext* resample_ctx; + AVAudioResampleContext* resample_ctx; #endif uint8_t *converted_in_samples; @@ -90,6 +98,7 @@ public: int writeAudioFramePacket( ZMPacket *pkt ); int writePacket( ZMPacket *pkt ); int write_packets( zm_packetqueue &queue ); + void flush_codecs(); }; #endif //havelibav diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index ae0d82108..b75d3678f 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -108,14 +108,12 @@ void Zone::Setup( } } - // FIXME: Is this not a problem? If you had two zones for a monitor.. then these would conflict. You would only get 1 dump file if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( ! diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); - } - pg_image->WriteJpeg( diag_path ); - } + snprintf(diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); + pg_image->WriteJpeg(diag_path); + } else { + diag_path[0] = 0; + } } // end Zone::Setup Zone::~Zone() { @@ -127,21 +125,22 @@ Zone::~Zone() { void Zone::RecordStats( const Event *event ) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "insert into Stats set MonitorId=%d, ZoneId=%d, EventId=%d, FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score ); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't insert event stats: %s", mysql_error( &dbconn ) ); + snprintf(sql, sizeof(sql), + "INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", + monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score + ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't insert event stats: %s", mysql_error(&dbconn)); } db_mutex.unlock(); } // end void Zone::RecordStats( const Event *event ) bool Zone::CheckOverloadCount() { - Info("Overloaded count: %d, Overloaded frames: %d", overload_count, overload_frames); if ( overload_count ) { - Info( "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); - Debug( 4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); + Debug(4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames); overload_count--; - return( false ); + return false; } return true; } // end bool Zone::CheckOverloadCount() @@ -180,28 +179,27 @@ int Zone::GetExtendAlarmFrames() { } // end int Zone::GetExtendAlarmFrames() bool Zone::CheckExtendAlarmCount() { - Info( "ExtendAlarm count: %d, ExtendAlarm frames: %d", extend_alarm_count, extend_alarm_frames ); + Info("ExtendAlarm count: %d, ExtendAlarm frames: %d", extend_alarm_count, extend_alarm_frames); if ( extend_alarm_count ) { - Debug( 3, "In extend mode, %d frames of %d remaining", extend_alarm_count, extend_alarm_frames ); + Debug(3, "In extend mode, %d frames of %d remaining", extend_alarm_count, extend_alarm_frames); extend_alarm_count--; - return( true ); + return true; } return false; } // end bool Zone::CheckExtendAlarmCount -bool Zone::CheckAlarms( const Image *delta_image ) { +bool Zone::CheckAlarms(const Image *delta_image) { ResetStats(); if ( overload_count ) { - Info( "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); - Debug( 4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames ); + Info("In overload mode, %d frames of %d remaining", overload_count, overload_frames); overload_count--; - return( false ); + return false; } delete image; // Get the difference image - Image *diff_image = image = new Image( *delta_image ); + Image *diff_image = image = new Image(*delta_image); int diff_width = diff_image->Width(); uint8_t* diff_buff = (uint8_t*)diff_image->Buffer(); uint8_t* pdiff; @@ -221,7 +219,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { unsigned int hi_x = polygon.HiX(); unsigned int hi_y = polygon.HiY(); - Debug( 4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y ); + Debug(4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y); /* if(config.cpu_extensions && sseversion >= 20) { sse2_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count); @@ -230,36 +228,31 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } */ std_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count); - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( ! diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 1 ); - } - diff_image->WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); if ( pixel_diff_count && alarm_pixels ) pixel_diff = pixel_diff_count/alarm_pixels; - Debug( 5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff ); + Debug(5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff); - if( alarm_pixels ) { - if( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) { + if ( alarm_pixels ) { + if ( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) { /* Not enough pixels alarmed */ - return (false); - } else if( max_alarm_pixels && (alarm_pixels > (unsigned int)max_alarm_pixels) ) { + return false; + } else if ( max_alarm_pixels && (alarm_pixels > (unsigned int)max_alarm_pixels) ) { /* Too many pixels alarmed */ overload_count = overload_frames; - return (false); + return false; } } else { /* No alarmed pixels */ - return (false); + return false; } score = (100*alarm_pixels)/polygon.Area(); if ( score < 1 ) score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */ - Debug( 5, "Current score is %d", score ); + Debug(5, "Current score is %d", score); if ( check_method >= FILTERED_PIXELS ) { int bx = filter_box.X(); @@ -268,7 +261,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { int by1 = by-1; - Debug( 5, "Checking for filtered pixels" ); + Debug(5, "Checking for filtered pixels"); if ( bx > 1 || by > 1 ) { // Now remove any pixels smaller than our filter size unsigned char *cpdiff; @@ -306,47 +299,42 @@ bool Zone::CheckAlarms( const Image *delta_image ) { continue; } alarm_filter_pixels++; - } - } - } + } // end if white + } // end for x + } // end foreach y line } else { alarm_filter_pixels = alarm_pixels; } - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 2 ); - } - diff_image->WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); - Debug( 5, "Got %d filtered pixels, need %d -> %d", alarm_filter_pixels, min_filter_pixels, max_filter_pixels ); + Debug(5, "Got %d filtered pixels, need %d -> %d", alarm_filter_pixels, min_filter_pixels, max_filter_pixels); - if( alarm_filter_pixels ) { - if( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) { + if ( alarm_filter_pixels ) { + if ( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) { /* Not enough pixels alarmed */ - return (false); - } else if( max_filter_pixels && (alarm_filter_pixels > max_filter_pixels) ) { + return false; + } else if ( max_filter_pixels && (alarm_filter_pixels > max_filter_pixels) ) { /* Too many pixels alarmed */ overload_count = overload_frames; - return (false); + return false; } } else { /* No filtered pixels */ - return (false); + return false; } score = (100*alarm_filter_pixels)/(polygon.Area()); if ( score < 1 ) score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */ - Debug( 5, "Current score is %d", score ); + Debug(5, "Current score is %d", score); if ( check_method >= BLOBS ) { - Debug( 5, "Checking for blob pixels" ); + Debug(5, "Checking for blob pixels"); typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats; BlobStats blob_stats[256]; - memset( blob_stats, 0, sizeof(BlobStats)*256 ); + memset(blob_stats, 0, sizeof(BlobStats)*256); uint8_t *spdiff; uint8_t last_x, last_y; BlobStats *bsx, *bsy; @@ -358,32 +346,32 @@ bool Zone::CheckAlarms( const Image *delta_image ) { pdiff = (uint8_t*)diff_image->Buffer( lo_x, y ); for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) { if ( *pdiff == WHITE ) { - Debug( 9, "Got white pixel at %d,%d (%p)", x, y, pdiff ); + Debug(9, "Got white pixel at %d,%d (%p)", x, y, pdiff); //last_x = (x>lo_x)?*(pdiff-1):0; //last_y = (y>lo_y&&x>=last_lo_x&&x<=last_hi_x)?*(pdiff-diff_width):0; last_x = 0; - if(x > 0) { - if((x-1) >= lo_x) { + if ( x > 0 ) { + if ( (x-1) >= lo_x ) { last_x = *(pdiff-1); } } last_y = 0; - if(y > 0) { - if((y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x) { + if (y > 0 ) { + if ( (y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x ) { last_y = *(pdiff-diff_width); } } if ( last_x ) { - Debug( 9, "Left neighbour is %d", last_x ); + Debug(9, "Left neighbour is %d", last_x); bsx = &blob_stats[last_x]; if ( last_y ) { - Debug( 9, "Top neighbour is %d", last_y ); + Debug(9, "Top neighbour is %d", last_y); bsy = &blob_stats[last_y]; if ( last_x == last_y ) { - Debug( 9, "Matching neighbours, setting to %d", last_x ); + Debug(9, "Matching neighbours, setting to %d", last_x); // Add to the blob from the x side (either side really) *pdiff = last_x; alarm_blob_pixels++; @@ -395,22 +383,29 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bsm = bsx->count>=bsy->count?bsx:bsy; bss = bsm==bsx?bsy:bsx; - Debug( 9, "Different neighbours, setting pixels of %d to %d", bss->tag, bsm->tag ); - Debug( 9, "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y ); - Debug( 9, "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y ); + Debug(9, + "Different neighbours, setting pixels of %d to %d\n" + "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n" + "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n", + bss->tag, bsm->tag, + bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y, + bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y + ); // Now change all those pixels to the other setting int changed = 0; - for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++) { + for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++ ) { int lo_sx = bss->lo_x>=ranges[sy].lo_x?bss->lo_x:ranges[sy].lo_x; int hi_sx = bss->hi_x<=ranges[sy].hi_x?bss->hi_x:ranges[sy].hi_x; - Debug( 9, "Changing %d, %d->%d", sy, lo_sx, hi_sx ); - Debug( 9, "Range %d, %d->%d", sy, ranges[sy].lo_x, ranges[sy].hi_x ); + Debug(9, + "Changing %d, %d->%d Range %d->%d", + sy, lo_sx, hi_sx, ranges[sy].lo_x, ranges[sy].hi_x + ); spdiff = diff_buff + ((diff_width * sy) + lo_sx); for ( int sx = lo_sx; sx <= hi_sx; sx++, spdiff++ ) { - Debug( 9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff ); + Debug(9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff); if ( *spdiff == bss->tag ) { - Debug( 9, "Setting pixel" ); + Debug(9, "Setting pixel"); *spdiff = bsm->tag; changed++; } @@ -419,10 +414,14 @@ bool Zone::CheckAlarms( const Image *delta_image ) { *pdiff = bsm->tag; alarm_blob_pixels++; if ( !changed ) { - Info( "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y ); - Info( "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y ); - Error( "No pixels changed, exiting" ); - exit( -1 ); + Info( + "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n" + "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", + bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y, + bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y + ); + Error("No pixels changed, exiting"); + exit(-1); } // Merge the slave blob into the master @@ -436,7 +435,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { alarm_blobs--; - Debug( 6, "Merging blob %d with %d at %d,%d, %d current blobs", bss->tag, bsm->tag, x, y, alarm_blobs ); + Debug(6, "Merging blob %d with %d at %d,%d, %d current blobs", bss->tag, bsm->tag, x, y, alarm_blobs); // Clear out the old blob bss->tag = 0; @@ -447,7 +446,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bss->hi_y = 0; } } else { - Debug( 9, "Setting to left neighbour %d", last_x ); + Debug(9, "Setting to left neighbour %d", last_x); // Add to the blob from the x side *pdiff = last_x; alarm_blob_pixels++; @@ -457,8 +456,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } } else { if ( last_y ) { - Debug( 9, "Top neighbour is %d", last_y ); - Debug( 9, "Setting to top neighbour %d", last_y ); + Debug(9, "Top neighbour is %d", last_y); // Add to the blob from the y side BlobStats *bsy = &blob_stats[last_y]; @@ -489,7 +487,8 @@ bool Zone::CheckAlarms( const Image *delta_image ) { alarm_blobs--; alarm_blob_pixels -= bs->count; - Debug( 6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); + Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", + i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs); bs->tag = 0; bs->count = 0; @@ -500,7 +499,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } } if ( !bs->count ) { - Debug( 9, "Creating new blob %d", i ); + Debug(9, "Creating new blob %d", i); *pdiff = i; alarm_blob_pixels++; bs->tag = i; @@ -509,12 +508,12 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bs->lo_y = bs->hi_y = y; alarm_blobs++; - Debug( 6, "Created blob %d at %d,%d, %d current blobs", bs->tag, x, y, alarm_blobs ); + Debug(6, "Created blob %d at %d,%d, %d current blobs", bs->tag, x, y, alarm_blobs); break; } } if ( i == 0 ) { - Warning( "Max blob count reached. Unable to allocate new blobs so terminating. Zone settings may be too sensitive." ); + Warning("Max blob count reached. Unable to allocate new blobs so terminating. Zone settings may be too sensitive."); x = hi_x+1; y = hi_y+1; } @@ -523,19 +522,15 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } } } - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 3 ); - } - diff_image->WriteJpeg( diag_path ); - } + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); if ( !alarm_blobs ) { - return( false ); + return false; } - Debug( 5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs ); + Debug(5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d", + alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); // Now eliminate blobs under the threshold for ( int i = 1; i < WHITE; i++ ) { @@ -555,7 +550,8 @@ bool Zone::CheckAlarms( const Image *delta_image ) { alarm_blobs--; alarm_blob_pixels -= bs->count; - Debug( 6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); + Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", + i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); bs->tag = 0; bs->count = 0; @@ -564,39 +560,37 @@ bool Zone::CheckAlarms( const Image *delta_image ) { bs->hi_x = 0; bs->hi_y = 0; } else { - Debug( 6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); + Debug(6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", + i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); if ( !min_blob_size || bs->count < min_blob_size ) min_blob_size = bs->count; if ( !max_blob_size || bs->count > max_blob_size ) max_blob_size = bs->count; } - } - } - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 4 ); - } - diff_image->WriteJpeg( diag_path ); - } - Debug( 5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs ); + } // end if bs_count + } // end for i < WHITE + if ( config.record_diag_images ) + diff_image->WriteJpeg(diag_path); - if( alarm_blobs ) { - if( min_blobs && (alarm_blobs < min_blobs) ) { + Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", + alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); + + if ( alarm_blobs ) { + if ( min_blobs && (alarm_blobs < min_blobs) ) { /* Not enough pixels alarmed */ - return (false); - } else if(max_blobs && (alarm_blobs > max_blobs) ) { + return false; + } else if ( max_blobs && (alarm_blobs > max_blobs) ) { /* Too many pixels alarmed */ overload_count = overload_frames; - return (false); + return false; } } else { /* No blobs */ - return (false); + return false; } score = (100*alarm_blob_pixels)/(polygon.Area()); if ( score < 1 ) score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */ - Debug( 5, "Current score is %d", score ); + Debug(5, "Current score is %d", score); alarm_lo_x = polygon.HiX()+1; alarm_hi_x = polygon.LoX()-1; @@ -648,15 +642,15 @@ bool Zone::CheckAlarms( const Image *delta_image ) { score *= 2; } - Debug( 5, "Adjusted score is %d", score ); + Debug(5, "Adjusted score is %d", score); // Now outline the changed region if ( score ) { - alarm_box = Box( Coord( alarm_lo_x, alarm_lo_y ), Coord( alarm_hi_x, alarm_hi_y ) ); + alarm_box = Box(Coord(alarm_lo_x, alarm_lo_y), Coord(alarm_hi_x, alarm_hi_y)); //if ( monitor->followMotion() ) if ( true ) { - alarm_centre = Coord( alarm_mid_x, alarm_mid_y ); + alarm_centre = Coord(alarm_mid_x, alarm_mid_y); } else { alarm_centre = alarm_box.Centre(); } @@ -698,9 +692,9 @@ bool Zone::CheckAlarms( const Image *delta_image ) { } if ( monitor->Colours() == ZM_COLOUR_GRAY8 ) { - image = diff_image->HighlightEdges( alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent() ); + image = diff_image->HighlightEdges(alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent()); } else { - image = diff_image->HighlightEdges( alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent() ); + image = diff_image->HighlightEdges(alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent()); } // Only need to delete this when 'image' becomes detached and points somewhere else @@ -710,18 +704,18 @@ bool Zone::CheckAlarms( const Image *delta_image ) { image = 0; } - Debug( 1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d", - Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score ); + Debug(1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d", + Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score); } - return( true ); + return true; } -bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { - Debug( 3, "Parsing polygon string '%s'", poly_string ); +bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) { + Debug(3, "Parsing polygon string '%s'", poly_string); char *str_ptr = new char[strlen(poly_string)+1]; char *str = str_ptr; - strcpy( str, poly_string ); + strcpy(str, poly_string); char *ws; int n_coords = 0; @@ -731,16 +725,16 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { if ( *str == '\0' ) { break; } - ws = strchr( str, ' ' ); + ws = strchr(str, ' '); if ( ws ) { *ws = '\0'; } - char *cp = strchr( str, ',' ); + char *cp = strchr(str, ','); if ( !cp ) { - Error( "Bogus coordinate %s found in polygon string", str ); + Error("Bogus coordinate %s found in polygon string", str); delete[] coords; delete[] str_ptr; - return( false ); + return false; } else { *cp = '\0'; char *xp = str; @@ -749,7 +743,7 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { int x = atoi(xp); int y = atoi(yp); - Debug( 3, "Got coordinate %d,%d from polygon string", x, y ); + Debug(3, "Got coordinate %d,%d from polygon string", x, y); #if 0 if ( x < 0 ) x = 0; @@ -767,82 +761,86 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) { else break; } - polygon = Polygon( n_coords, coords ); + polygon = Polygon(n_coords, coords); - Debug( 3, "Successfully parsed polygon string" ); + Debug(3, "Successfully parsed polygon string"); //printf( "Area: %d\n", pg.Area() ); //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); delete[] coords; delete[] str_ptr; - return( true ); + return true; } -bool Zone::ParseZoneString( const char *zone_string, int &zone_id, int &colour, Polygon &polygon ) { - Debug( 3, "Parsing zone string '%s'", zone_string ); +bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) { + Debug(3, "Parsing zone string '%s'", zone_string); char *str_ptr = new char[strlen(zone_string)+1]; char *str = str_ptr; - strcpy( str, zone_string ); + strcpy(str, zone_string); - char *ws = strchr( str, ' ' ); + char *ws = strchr(str, ' '); if ( !ws ) { - Debug( 3, "No initial whitespace found in zone string '%s', finishing", str ); + Debug(3, "No initial whitespace found in zone string '%s', finishing", str); } - zone_id = strtol( str, 0, 10 ); - Debug( 3, "Got zone %d from zone string", zone_id ); + zone_id = strtol(str, 0, 10); + Debug(3, "Got zone %d from zone string", zone_id); if ( !ws ) { delete[] str_ptr; - return( true ); + return true; } *ws = '\0'; str = ws+1; - ws = strchr( str, ' ' ); + ws = strchr(str, ' '); if ( !ws ) { - Debug( 3, "No secondary whitespace found in zone string '%s', finishing", zone_string ); + Debug(3, "No secondary whitespace found in zone string '%s', finishing", zone_string); } - colour = strtol( str, 0, 16 ); - Debug( 3, "Got colour %06x from zone string", colour ); + colour = strtol(str, 0, 16); + Debug(3, "Got colour %06x from zone string", colour); if ( !ws ) { delete[] str_ptr; - return( true ); + return true; } *ws = '\0'; str = ws+1; - bool result = ParsePolygonString( str, polygon ); + bool result = ParsePolygonString(str, polygon); //printf( "Area: %d\n", pg.Area() ); //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); delete[] str_ptr; - return( result ); + return result; } -int Zone::Load( Monitor *monitor, Zone **&zones ) { +int Zone::Load(Monitor *monitor, Zone **&zones) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id() ); + db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + snprintf(sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id()); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + db_mutex.unlock(); + return 0; } MYSQL_RES *result = mysql_store_result( &dbconn ); db_mutex.unlock(); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + db_mutex.unlock(); return 0; } - int n_zones = mysql_num_rows( result ); - Debug( 1, "Got %d zones for monitor %s", n_zones, monitor->Name() ); + db_mutex.unlock(); + int n_zones = mysql_num_rows(result); + Debug(1, "Got %d zones for monitor %s", n_zones, monitor->Name()); delete[] zones; zones = new Zone *[n_zones]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { + for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { int col = 0; int Id = atoi(dbrow[col++]); @@ -870,17 +868,18 @@ int Zone::Load( Monitor *monitor, Zone **&zones ) { /* HTML colour code is actually BGR in memory, we want RGB */ AlarmRGB = rgb_convert(AlarmRGB, ZM_SUBPIX_ORDER_BGR); - Debug( 5, "Parsing polygon %s", Coords ); + Debug(5, "Parsing polygon %s", Coords); Polygon polygon; - if ( !ParsePolygonString( Coords, polygon ) ) { - Error( "Unable to parse polygon string '%s' for zone %d/%s for monitor %s, ignoring", Coords, Id, Name, monitor->Name() ); + if ( !ParsePolygonString(Coords, polygon) ) { + Error("Unable to parse polygon string '%s' for zone %d/%s for monitor %s, ignoring", Coords, Id, Name, monitor->Name()); n_zones -= 1; continue; } if ( polygon.LoX() < 0 || polygon.HiX() >= (int)monitor->Width() || polygon.LoY() < 0 || polygon.HiY() >= (int)monitor->Height() ) { - Error( "Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring", Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY() ); + Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring", + Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY()); n_zones -= 1; continue; } @@ -895,21 +894,17 @@ int Zone::Load( Monitor *monitor, Zone **&zones ) { } if ( atoi(dbrow[2]) == Zone::INACTIVE ) { - zones[i] = new Zone( monitor, Id, Name, polygon ); + zones[i] = new Zone(monitor, Id, Name, polygon); } else if ( atoi(dbrow[2]) == Zone::PRIVACY ) { - zones[i] = new Zone( monitor, Id, Name, (Zone::ZoneType)Type, polygon ); + zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon); } - zones[i] = new Zone( monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames ); - } - if ( mysql_errno( &dbconn ) ) { - Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); - } - mysql_free_result( result ); - return( n_zones ); -} + zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames); + } // end foreach row + mysql_free_result(result); + return n_zones; +} // end int Zone::Load(Monitor *monitor, Zone **&zones) -bool Zone::DumpSettings( char *output, bool /*verbose*/ ) { +bool Zone::DumpSettings(char *output, bool /*verbose*/) { output[0] = 0; sprintf( output+strlen(output), " Id : %d\n", id ); @@ -953,7 +948,7 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig unsigned int lo_y; unsigned int hi_y; - if(max_pixel_threshold) + if ( max_pixel_threshold ) calc_max_pixel_threshold = max_pixel_threshold; lo_y = polygon.LoY(); @@ -962,9 +957,9 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig unsigned int lo_x = ranges[y].lo_x; unsigned int hi_x = ranges[y].hi_x; - Debug( 7, "Checking line %d from %d -> %d", y, lo_x, hi_x ); - uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer( lo_x, y ); - const uint8_t *ppoly = ppoly_image->Buffer( lo_x, y ); + Debug(7, "Checking line %d from %d -> %d", y, lo_x, hi_x); + uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer(lo_x, y); + const uint8_t *ppoly = ppoly_image->Buffer(lo_x, y); for ( unsigned int x = lo_x; x <= hi_x; x++, pdiff++, ppoly++ ) { if ( *ppoly && (*pdiff > min_pixel_threshold) && (*pdiff <= calc_max_pixel_threshold) ) { diff --git a/src/zm_zone.h b/src/zm_zone.h index 9ac8371f0..0c7b26a57 100644 --- a/src/zm_zone.h +++ b/src/zm_zone.h @@ -94,6 +94,7 @@ protected: int overload_count; int extend_alarm_count; + char diag_path[PATH_MAX]; protected: void Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_type, const Polygon &p_polygon, const Rgb p_alarm_rgb, CheckMethod p_check_method, int p_min_pixel_threshold, int p_max_pixel_threshold, int p_min_alarm_pixels, int p_max_alarm_pixels, const Coord &p_filter_box, int p_min_filter_pixels, int p_max_filter_pixels, int p_min_blob_pixels, int p_max_blob_pixels, int p_min_blobs, int p_max_blobs, int p_overload_frames, int p_extend_alarm_frames ); diff --git a/src/zma.cpp b/src/zma.cpp new file mode 100644 index 000000000..83035f011 --- /dev/null +++ b/src/zma.cpp @@ -0,0 +1,185 @@ +// +// ZoneMinder Analysis Daemon, $Date$, $Revision$ +// Copyright (C) 2001-2008 Philip Coombes +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// + +/* + +=head1 NAME + +zma - The ZoneMinder Analysis daemon + +=head1 SYNOPSIS + + zma -m + zma --monitor + zma -h + zma --help + zma -v + zma --version + +=head1 DESCRIPTION + +This is the component that goes through the captured frames and checks them +for motion which might generate an alarm or event. It generally keeps up with +the Capture daemon but if very busy may skip some frames to prevent it falling +behind. + +=head1 OPTIONS + + -m, --monitor_id - ID of the monitor to analyse + -h, --help - Display usage information + -v, --version - Print the installed version of ZoneMinder + +=cut + +*/ + +#include +#include + +#include "zm.h" +#include "zm_db.h" +#include "zm_signal.h" +#include "zm_monitor.h" + +void Usage() { + fprintf(stderr, "zma -m \n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -m, --monitor : Specify which monitor to use\n"); + fprintf(stderr, " -h, --help : This screen\n"); + fprintf(stderr, " -v, --version : Report the installed version of ZoneMinder\n"); + exit(0); +} + +int main( int argc, char *argv[] ) { + self = argv[0]; + + srand(getpid() * time(0)); + + int id = -1; + + static struct option long_options[] = { + {"monitor", 1, 0, 'm'}, + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'v'}, + {0, 0, 0, 0} + }; + + while (1) { + int option_index = 0; + + int c = getopt_long (argc, argv, "m:h:v", long_options, &option_index); + if ( c == -1 ) { + break; + } + + switch (c) { + case 'm': + id = atoi(optarg); + break; + case 'h': + case '?': + Usage(); + break; + case 'v': + std::cout << ZM_VERSION << "\n"; + exit(0); + default: + //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); + break; + } + } + + if (optind < argc) { + fprintf(stderr, "Extraneous options, "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + Usage(); + } + + if ( id < 0 ) { + fprintf(stderr, "Bogus monitor %d\n", id); + Usage(); + exit(0); + } + + char log_id_string[16]; + snprintf(log_id_string, sizeof(log_id_string), "zma_m%d", id); + + zmLoadConfig(); + + logInit(log_id_string); + + hwcaps_detect(); + + Monitor *monitor = Monitor::Load(id, true, Monitor::ANALYSIS); + + if ( monitor ) { + Info("In mode %d/%d, warming up", monitor->GetFunction(), monitor->Enabled()); + + zmSetDefaultHupHandler(); + zmSetDefaultTermHandler(); + zmSetDefaultDieHandler(); + + sigset_t block_set; + sigemptyset(&block_set); + + useconds_t analysis_rate = monitor->GetAnalysisRate(); + unsigned int analysis_update_delay = monitor->GetAnalysisUpdateDelay(); + time_t last_analysis_update_time, cur_time; + monitor->UpdateAdaptiveSkip(); + last_analysis_update_time = time( 0 ); + + while( (!zm_terminate) && monitor->ShmValid() ) { + // Process the next image + sigprocmask(SIG_BLOCK, &block_set, 0); + + // Some periodic updates are required for variable capturing framerate + if ( analysis_update_delay ) { + cur_time = time(0); + if ( (unsigned int)( cur_time - last_analysis_update_time ) > analysis_update_delay ) { + analysis_rate = monitor->GetAnalysisRate(); + monitor->UpdateAdaptiveSkip(); + last_analysis_update_time = cur_time; + } + } + + if ( !monitor->Analyse() ) { + usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); + } else if ( analysis_rate ) { + usleep(analysis_rate); + } + + if ( zm_reload ) { + monitor->Reload(); + logTerm(); + logInit(log_id_string); + zm_reload = false; + } + sigprocmask(SIG_UNBLOCK, &block_set, 0); + } // end while ! zm_terminate + delete monitor; + } else { + fprintf(stderr, "Can't find monitor with id of %d\n", id); + } + Image::Deinitialise(); + logTerm(); + zmDbClose(); + return( 0 ); +} diff --git a/src/zmc.cpp b/src/zmc.cpp index 8feb5ddc2..543a67135 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -1,21 +1,21 @@ // // ZoneMinder Capture Daemon, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// /* @@ -39,7 +39,7 @@ zmc - The ZoneMinder Capture daemon =head1 DESCRIPTION This binary's job is to sit on a video device and suck frames off it as fast as -possible, this should run at more or less constant speed. +possible, this should run at more or less constant speed. =head1 OPTIONS @@ -149,7 +149,7 @@ int main(int argc, char *argv[]) { std::cout << ZM_VERSION << "\n"; exit(0); default: - //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); + // fprintf(stderr, "?? getopt returned character code 0%o ??\n", c); break; } } @@ -162,7 +162,7 @@ int main(int argc, char *argv[]) { Usage(); } - int modes = ( (device[0]?1:0) + (host[0]?1:0) + (file[0]?1:0) + (monitor_id > 0 ? 1 : 0)); + int modes = ( (device[0]?1:0) + (host[0]?1:0) + (file[0]?1:0) + (monitor_id > 0 ? 1 : 0) ); if ( modes > 1 ) { fprintf(stderr, "Only one of device, host/port/path, file or monitor id allowed\n"); Usage(); @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) { if ( device[0] ) { n_monitors = Monitor::LoadLocalMonitors(device, monitors, Monitor::CAPTURE); } else -#endif // ZM_HAS_V4L +#endif // ZM_HAS_V4L if ( host[0] ) { if ( !port ) port = "80"; @@ -222,26 +222,35 @@ int main(int argc, char *argv[]) { } Info("Starting Capture version %s", ZM_VERSION); + zmSetDefaultHupHandler(); zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); sigset_t block_set; sigemptyset(&block_set); + sigaddset(&block_set, SIGHUP); sigaddset(&block_set, SIGUSR1); sigaddset(&block_set, SIGUSR2); int result = 0; - while( ! zm_terminate ) { + + while ( !zm_terminate ) { result = 0; static char sql[ZM_SQL_SML_BUFSIZ]; - for ( int i = 0; i < n_monitors; i ++ ) { + for ( int i = 0; i < n_monitors; i++ ) { + if ( ! monitors[i]->getCamera() ) { + } + if ( ! monitors[i]->connect() ) { + } time_t now = (time_t)time(NULL); monitors[i]->setStartupTime(now); - snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", monitors[i]->Id() ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + snprintf(sql, sizeof(sql), + "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", + monitors[i]->Id()); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); } } // Outer primary loop, handles connection to camera @@ -250,16 +259,18 @@ int main(int argc, char *argv[]) { sleep(10); continue; } - for ( int i = 0; i < n_monitors; i ++ ) { - snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", monitors[i]->Id() ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + for ( int i = 0; i < n_monitors; i++ ) { + snprintf(sql, sizeof(sql), + "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", + monitors[i]->Id()); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); } } AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors]; - long *capture_delays = new long[n_monitors]; - long *alarm_capture_delays = new long[n_monitors]; + int *capture_delays = new int[n_monitors]; + int *alarm_capture_delays = new int[n_monitors]; struct timeval * last_capture_times = new struct timeval[n_monitors]; for ( int i = 0; i < n_monitors; i++ ) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; @@ -288,16 +299,19 @@ int main(int argc, char *argv[]) { if ( monitors[i]->PreCapture() < 0 ) { Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + monitors[i]->Close(); result = -1; break; } if ( monitors[i]->Capture() < 0 ) { Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + monitors[i]->Close(); result = -1; break; } if ( monitors[i]->PostCapture() < 0 ) { Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + monitors[i]->Close(); result = -1; break; } @@ -305,9 +319,9 @@ int main(int argc, char *argv[]) { gettimeofday(&now, NULL); // capture_delay is the amount of time we should sleep to achieve the desired framerate. if ( last_capture_times[i].tv_sec ) { - long sleep_time; + int sleep_time; DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3); - long delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i]; + int delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i]; sleep_time = delay - delta_time.delta; Debug(3, "Sleep time is %d from now:%d.%d last:%d.%d delay: %d", sleep_time, now.tv_sec, now.tv_usec, last_capture_times[i].tv_sec, last_capture_times[i].tv_usec, delay ); @@ -325,17 +339,17 @@ int main(int argc, char *argv[]) { } // end foreach n_monitors //Debug(2,"unblocking"); sigprocmask(SIG_UNBLOCK, &block_set, 0); + if ( result < 0 ) { + // Failure, try reconnecting + break; + } if ( zm_reload ) { for ( int i = 0; i < n_monitors; i++ ) { monitors[i]->Reload(); } logTerm(); - logInit( log_id_string ); + logInit(log_id_string); zm_reload = false; - if ( result < 0 ) { - // Failure, try reconnecting - break; - } } // end if zm_reload } // end while ! zm_terminate and connected @@ -353,16 +367,16 @@ int main(int argc, char *argv[]) { } } // end foreach monitor delete [] analysis_threads; - if ( !zm_terminate ) - sleep(10); } // end while ! zm_terminate outer connection loop Debug(1,"Updating Monitor status"); for ( int i = 0; i < n_monitors; i++ ) { static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')", monitors[i]->Id() ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + snprintf(sql, sizeof(sql), + "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')", + monitors[i]->Id()); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); } delete monitors[i]; } diff --git a/src/zms.cpp b/src/zms.cpp index 66b3dc683..e8d20f72f 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "zm.h" #include "zm_db.h" @@ -58,7 +59,7 @@ int main( int argc, const char *argv[] ) { char format[32] = ""; int monitor_id = 0; time_t event_time = 0; - int event_id = 0; + uint64_t event_id = 0; unsigned int frame_id = 1; unsigned int scale = 100; unsigned int rate = 100; @@ -174,7 +175,7 @@ int main( int argc, const char *argv[] ) { if ( monitor_id ) { snprintf(log_id_string, sizeof(log_id_string), "zms_m%d", monitor_id); } else { - snprintf(log_id_string, sizeof(log_id_string), "zms_e%d", event_id); + snprintf(log_id_string, sizeof(log_id_string), "zms_e%" PRIu64, event_id); } logInit( log_id_string ); @@ -283,10 +284,10 @@ int main( int argc, const char *argv[] ) { stream.setStreamMode( replay ); stream.setStreamQueue( connkey ); if ( monitor_id && event_time ) { - stream.setStreamStart( monitor_id, event_time ); + stream.setStreamStart(monitor_id, event_time); } else { Debug(3, "Setting stream start to frame (%d)", frame_id); - stream.setStreamStart( event_id, frame_id ); + stream.setStreamStart(event_id, frame_id); } if ( mode == ZMS_JPEG ) { stream.setStreamType( EventStream::STREAM_JPEG ); diff --git a/src/zmu.cpp b/src/zmu.cpp index 4c94d0b51..dd38cb0c0 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -87,6 +87,7 @@ Options for use with monitors: */ #include +#include #include "zm.h" #include "zm_db.h" @@ -95,49 +96,51 @@ Options for use with monitors: #include "zm_monitor.h" #include "zm_local_camera.h" -void Usage( int status=-1 ) { - fprintf( stderr, "zmu <-d device_path> [-v] [function] [-U -P]\n" ); - fprintf( stderr, "zmu <-m monitor_id> [-v] [function] [-U -P]\n" ); - fprintf( stderr, "General options:\n" ); - fprintf( stderr, " -h, --help : This screen\n" ); - fprintf( stderr, " -v, --verbose : Produce more verbose output\n" ); - fprintf( stderr, " -l, --list : List the current status of active (or all with -v) monitors\n" ); - fprintf( stderr, "Options for use with devices:\n" ); - fprintf( stderr, " -d, --device [device_path] : Get the current video device settings for [device_path] or all devices\n" ); - fprintf( stderr, " -V, --version : Set the Video 4 Linux API version to use for the query, use 1 or 2\n" ); - fprintf( stderr, " -q, --query : Query the current settings for the device\n" ); - fprintf( stderr, "Options for use with monitors:\n" ); - fprintf( stderr, " -m, --monitor : Specify which monitor to address, default 1 if absent\n" ); - fprintf( stderr, " -q, --query : Query the current settings for the monitor\n" ); - fprintf( stderr, " -s, --state : Output the current monitor state, 0 = idle, 1 = prealarm, 2 = alarm,\n" ); - fprintf( stderr, " 3 = alert, 4 = tape\n" ); - fprintf( stderr, " -B, --brightness [value] : Output the current brightness, set to value if given \n" ); - fprintf( stderr, " -C, --contrast [value] : Output the current contrast, set to value if given \n" ); - fprintf( stderr, " -H, --hue [value] : Output the current hue, set to value if given \n" ); - fprintf( stderr, " -O, --colour [value] : Output the current colour, set to value if given \n" ); - fprintf( stderr, " -i, --image [image_index] : Write captured image to disk as .jpg, last image captured\n" ); - fprintf( stderr, " or specified ring buffer index if given.\n" ); - fprintf( stderr, " -S, --scale : With --image specify any scaling (in %%) to be applied to the image\n" ); - fprintf( stderr, " -t, --timestamp [image_index] : Output captured image timestamp, last image captured or specified\n" ); - fprintf( stderr, " ring buffer index if given\n" ); - fprintf( stderr, " -R, --read_index : Output ring buffer read index\n" ); - fprintf( stderr, " -W, --write_index : Output ring buffer write index\n" ); - fprintf( stderr, " -e, --event : Output last event index\n" ); - fprintf( stderr, " -f, --fps : Output last Frames Per Second captured reading\n" ); - fprintf( stderr, " -z, --zones : Write last captured image overlaid with zones to -Zones.jpg\n" ); - fprintf( stderr, " -a, --alarm : Force alarm in monitor, this will trigger recording until cancelled with -c\n" ); - fprintf( stderr, " -n, --noalarm : Force no alarms in monitor, this will prevent alarms until cancelled with -c\n" ); - fprintf( stderr, " -c, --cancel : Cancel a forced alarm/noalarm in monitor, required after being enabled with -a or -n\n" ); - fprintf( stderr, " -L, --reload : Signal monitor to reload settings\n" ); - fprintf( stderr, " -E, --enable : Enable detection, wake monitor up\n" ); - fprintf( stderr, " -D, --disable : Disable detection, put monitor to sleep\n" ); - fprintf( stderr, " -u, --suspend : Suspend detection, useful to prevent bogus alarms when panning etc\n" ); - fprintf( stderr, " -r, --resume : Resume detection after a suspend\n" ); - fprintf( stderr, " -U, --username : When running in authenticated mode the username and\n" ); - fprintf( stderr, " -P, --password : password combination of the given user\n" ); - fprintf( stderr, " -A, --auth : Pass authentication hash string instead of user details\n" ); +void Usage(int status=-1) { + fputs( + "zmu <-d device_path> [-v] [function] [-U -P]\n" + "zmu <-m monitor_id> [-v] [function] [-U -P]\n" + "General options:\n" + " -h, --help : This screen\n" + " -v, --verbose : Produce more verbose output\n" + " -l, --list : List the current status of active (or all with -v) monitors\n" + "Options for use with devices:\n" + " -d, --device [device_path] : Get the current video device settings for [device_path] or all devices\n" + " -V, --version : Set the Video 4 Linux API version to use for the query, use 1 or 2\n" + " -q, --query : Query the current settings for the device\n" + "Options for use with monitors:\n" + " -m, --monitor : Specify which monitor to address, default 1 if absent\n" + " -q, --query : Query the current settings for the monitor\n" + " -s, --state : Output the current monitor state, 0 = idle, 1 = prealarm, 2 = alarm,\n" + " 3 = alert, 4 = tape\n" + " -B, --brightness [value] : Output the current brightness, set to value if given \n" + " -C, --contrast [value] : Output the current contrast, set to value if given \n" + " -H, --hue [value] : Output the current hue, set to value if given \n" + " -O, --colour [value] : Output the current colour, set to value if given \n" + " -i, --image [image_index] : Write captured image to disk as .jpg, last image captured\n" + " or specified ring buffer index if given.\n" + " -S, --scale : With --image specify any scaling (in %%) to be applied to the image\n" + " -t, --timestamp [image_index] : Output captured image timestamp, last image captured or specified\n" + " ring buffer index if given\n" + " -R, --read_index : Output ring buffer read index\n" + " -W, --write_index : Output ring buffer write index\n" + " -e, --event : Output last event index\n" + " -f, --fps : Output last Frames Per Second captured reading\n" + " -z, --zones : Write last captured image overlaid with zones to -Zones.jpg\n" + " -a, --alarm : Force alarm in monitor, this will trigger recording until cancelled with -c\n" + " -n, --noalarm : Force no alarms in monitor, this will prevent alarms until cancelled with -c\n" + " -c, --cancel : Cancel a forced alarm/noalarm in monitor, required after being enabled with -a or -n\n" + " -L, --reload : Signal monitor to reload settings\n" + " -E, --enable : Enable detection, wake monitor up\n" + " -D, --disable : Disable detection, put monitor to sleep\n" + " -u, --suspend : Suspend detection, useful to prevent bogus alarms when panning etc\n" + " -r, --resume : Resume detection after a suspend\n" + " -U, --username : When running in authenticated mode the username and\n" + " -P, --password : password combination of the given user\n" + " -A, --auth : Pass authentication hash string instead of user details\n" + "", stderr ); - exit( status ); + exit(status); } typedef enum { @@ -166,7 +169,7 @@ typedef enum { ZMU_LIST = 0x10000000, } Function; -bool ValidateAccess( User *user, int mon_id, int function ) { +bool ValidateAccess(User *user, int mon_id, int function) { bool allowed = true; if ( function & (ZMU_STATE|ZMU_IMAGE|ZMU_TIME|ZMU_READ_IDX|ZMU_WRITE_IDX|ZMU_FPS) ) { if ( user->getStream() < User::PERM_VIEW ) @@ -185,26 +188,30 @@ bool ValidateAccess( User *user, int mon_id, int function ) { allowed = false; } if ( mon_id > 0 ) { - if ( !user->canAccess( mon_id ) ) { + if ( !user->canAccess(mon_id) ) { allowed = false; } } - if ( !allowed ) { - fprintf( stderr, "Error, insufficient privileges for requested action\n" ); - exit( -1 ); - } - return( allowed ); + return allowed; } -int main( int argc, char *argv[] ) { +int exit_zmu(int exit_code) { + logTerm(); + zmDbClose(); + + exit(exit_code); + return exit_code; +} + +int main(int argc, char *argv[]) { if ( access(ZM_CONFIG, R_OK) != 0 ) { - fprintf( stderr, "Can't open %s: %s\n", ZM_CONFIG, strerror(errno) ); - exit( -1 ); + fprintf(stderr, "Can't open %s: %s\n", ZM_CONFIG, strerror(errno)); + exit(-1); } self = argv[0]; - srand( getpid() * time( 0 ) ); + srand(getpid() * time(0)); static struct option long_options[] = { {"device", 2, 0, 'd'}, @@ -266,8 +273,8 @@ int main( int argc, char *argv[] ) { while (1) { int option_index = 0; - int c = getopt_long (argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::U:P:A:V:", long_options, &option_index); - if (c == -1) { + int c = getopt_long(argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::U:P:A:V:", long_options, &option_index); + if ( c == -1 ) { break; } @@ -288,7 +295,7 @@ int main( int argc, char *argv[] ) { case 'i': function |= ZMU_IMAGE; if ( optarg ) - image_idx = atoi( optarg ); + image_idx = atoi(optarg); break; case 'S': scale = atoi(optarg); @@ -296,7 +303,7 @@ int main( int argc, char *argv[] ) { case 't': function |= ZMU_TIME; if ( optarg ) - image_idx = atoi( optarg ); + image_idx = atoi(optarg); break; case 'R': function |= ZMU_READ_IDX; @@ -345,22 +352,22 @@ int main( int argc, char *argv[] ) { case 'B': function |= ZMU_BRIGHTNESS; if ( optarg ) - brightness = atoi( optarg ); + brightness = atoi(optarg); break; case 'C': function |= ZMU_CONTRAST; if ( optarg ) - contrast = atoi( optarg ); + contrast = atoi(optarg); break; case 'H': function |= ZMU_HUE; if ( optarg ) - hue = atoi( optarg ); + hue = atoi(optarg); break; case 'O': function |= ZMU_COLOUR; if ( optarg ) - colour = atoi( optarg ); + colour = atoi(optarg); break; case 'U': username = optarg; @@ -377,41 +384,39 @@ int main( int argc, char *argv[] ) { break; #endif // ZM_HAS_V4L case 'h': - Usage( 0 ); + case '?': + Usage(0); break; case 'l': function |= ZMU_LIST; break; - case '?': - Usage(); - break; default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); break; } } - if (optind < argc) { - fprintf( stderr, "Extraneous options, " ); + if ( optind < argc ) { + fprintf(stderr, "Extraneous options, "); while (optind < argc) - fprintf( stderr, "%s ", argv[optind++]); - fprintf( stderr, "\n"); + fprintf(stderr, "%s ", argv[optind++]); + fprintf(stderr, "\n"); Usage(); } if ( device && !(function&ZMU_QUERY) ) { - fprintf( stderr, "Error, -d option cannot be used with this option\n" ); + fprintf(stderr, "Error, -d option cannot be used with this option\n"); Usage(); } if ( scale != -1 && !(function&ZMU_IMAGE) ) { - fprintf( stderr, "Error, -S option cannot be used with this option\n" ); + fprintf(stderr, "Error, -S option cannot be used with this option\n"); Usage(); } //printf( "Monitor %d, Function %d\n", mon_id, function ); zmLoadConfig(); - logInit( "zmu" ); + logInit("zmu"); zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); @@ -419,62 +424,66 @@ int main( int argc, char *argv[] ) { User *user = 0; if ( config.opt_use_auth ) { - if ( strcmp( config.auth_relay, "none" ) == 0 ) { + if ( strcmp(config.auth_relay, "none") == 0 ) { if ( !username ) { - fprintf( stderr, "Error, username must be supplied\n" ); - exit( -1 ); + fprintf(stderr, "Error, username must be supplied\n"); + exit_zmu(-1); } if ( username ) { - user = zmLoadUser( username ); + user = zmLoadUser(username); } } else { if ( !(username && password) && !auth ) { - fprintf( stderr, "Error, username and password or auth string must be supplied\n" ); - exit( -1 ); + fprintf(stderr, "Error, username and password or auth string must be supplied\n"); + exit_zmu(-1); } //if ( strcmp( config.auth_relay, "hashed" ) == 0 ) { if ( auth ) { - user = zmLoadAuthUser( auth, false ); + user = zmLoadAuthUser(auth, false); } } //else if ( strcmp( config.auth_relay, "plain" ) == 0 ) { if ( username && password ) { - user = zmLoadUser( username, password ); + user = zmLoadUser(username, password); } } } if ( !user ) { - fprintf( stderr, "Error, unable to authenticate user\n" ); - exit( -1 ); + fprintf(stderr, "Error, unable to authenticate user\n"); + return exit_zmu(-1); } - ValidateAccess( user, mon_id, function ); - } - + if ( !ValidateAccess(user, mon_id, function) ) { + fprintf(stderr, "Error, insufficient privileges for requested action\n"); + exit_zmu(-1); + } + } // end if auth if ( mon_id > 0 ) { - Monitor *monitor = Monitor::Load( mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY ); + fprintf(stderr,"Monitor %d\n", mon_id); + Monitor *monitor = Monitor::Load(mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY); if ( monitor ) { + fprintf(stderr,"Monitor %d(%s)\n", monitor->Id(), monitor->Name()); if ( verbose ) { - printf( "Monitor %d(%s)\n", monitor->Id(), monitor->Name() ); + printf("Monitor %d(%s)\n", monitor->Id(), monitor->Name()); } if ( ! monitor->connect() ) { - Error( "Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name() ); - exit( -1 ); - } + Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); + exit_zmu(-1); + } char separator = ' '; bool have_output = false; if ( function & ZMU_STATE ) { Monitor::State state = monitor->GetState(); if ( verbose ) - printf( "Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle") ); + printf("Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle")); else { - if ( have_output ) printf( "%c", separator ); - printf( "%d", state ); + if ( have_output ) printf("%c", separator); + printf("%d", state); have_output = true; } } @@ -514,10 +523,10 @@ int main( int argc, char *argv[] ) { } if ( function & ZMU_EVENT ) { if ( verbose ) - printf( "Last event id: %d\n", monitor->GetLastEventId() ); + printf( "Last event id: %" PRIu64 "\n", monitor->GetLastEventId() ); else { if ( have_output ) printf( "%c", separator ); - printf( "%d", monitor->GetLastEventId() ); + printf( "%" PRIu64, monitor->GetLastEventId() ); have_output = true; } } @@ -660,8 +669,8 @@ int main( int argc, char *argv[] ) { } delete monitor; } else { - fprintf( stderr, "Error, invalid monitor id %d\n", mon_id ); - exit( -1 ); + fprintf(stderr, "Error, invalid monitor id %d\n", mon_id); + exit_zmu(-1); } } else { if ( function & ZMU_QUERY ) { @@ -669,10 +678,10 @@ int main( int argc, char *argv[] ) { char vidString[0x10000] = ""; bool ok = LocalCamera::GetCurrentSettings( device, vidString, v4lVersion, verbose ); printf( "%s", vidString ); - exit( ok?0:-1 ); + exit_zmu( ok?0:-1 ); #else // ZM_HAS_V4L fprintf( stderr, "Error, video4linux is required for device querying\n" ); - exit( -1 ); + exit_zmu( -1 ); #endif // ZM_HAS_V4L } @@ -685,13 +694,13 @@ int main( int argc, char *argv[] ) { if ( mysql_query( &dbconn, sql.c_str() ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + exit_zmu( 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 ) ); + exit_zmu( mysql_errno( &dbconn ) ); } Debug( 1, "Got %d monitors", mysql_num_rows( result ) ); @@ -704,7 +713,7 @@ int main( int argc, char *argv[] ) { Monitor *monitor = Monitor::Load( mon_id, false, Monitor::QUERY ); if ( monitor && monitor->connect() ) { struct timeval tv = monitor->GetTimestamp(); - printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8d%8.2f\n", + printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8" PRIu64 "%8.2f\n", monitor->Id(), function, monitor->GetState(), @@ -738,8 +747,5 @@ int main( int argc, char *argv[] ) { } delete user; - logTerm(); - zmDbClose(); - - return( 0 ); + return exit_zmu(0); } diff --git a/utils/generate_apache_config.pl b/utils/generate_apache_config.pl index 9d9e94e10..664b4c819 100755 --- a/utils/generate_apache_config.pl +++ b/utils/generate_apache_config.pl @@ -55,6 +55,22 @@ DocumentRoot /usr/share/zoneminder/www qq` ErrorLog $$opts{error_log} +Alias /zm/cache "/var/cache/zoneminder/cache" +Alias /cache "/var/cache/zoneminder/cache" + + Options -Indexes +FollowSymLinks + AllowOverride None + + # Apache 2.4 + Require all granted + + + # Apache 2.2 + Order deny,allow + Allow from all + + + ScriptAlias /zm/cgi-bin/ /usr/lib/zoneminder/cgi-bin/ ScriptAlias /cgi-bin/ /usr/lib/zoneminder/cgi-bin/ @@ -67,7 +83,6 @@ ScriptAlias /cgi-bin/ /usr/lib/zoneminder/cgi-bin/ Alias /zm /usr/share/zoneminder/www - php_flag register_globals off Options +Indexes +FollowSymLinks @@ -81,6 +96,32 @@ Alias /zm /usr/share/zoneminder/www Allow from all + +# For better visibility, the following directives have been migrated from the +# default .htaccess files included with the CakePHP project. +# Parameters not set here are inherited from the parent directive above. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api + + `; if ( $$opts{protocol} eq 'https' ) { $template .= qq` diff --git a/utils/packpack/nolintian.patch b/utils/packpack/nolintian.patch new file mode 100644 index 000000000..89b93a4c3 --- /dev/null +++ b/utils/packpack/nolintian.patch @@ -0,0 +1,22 @@ +From 634281a4204467b9a3c8a1a5febcc8dd9828e0f6 Mon Sep 17 00:00:00 2001 +From: Andy Bauer +Date: Thu, 22 Feb 2018 08:53:50 -0600 +Subject: [PATCH] don't run lintian checks to speed up build + +--- + pack/deb.mk | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pack/deb.mk b/pack/deb.mk +index de4a0b7..bddf9df 100644 +--- a/packpack/pack/deb.mk ++++ b/packpack/pack/deb.mk +@@ -130,7 +130,7 @@ $(BUILDDIR)/$(DPKG_CHANGES): $(BUILDDIR)/$(PRODUCT)-$(VERSION)/debian \ + @echo "Building Debian packages" + @echo "-------------------------------------------------------------------" + cd $(BUILDDIR)/$(PRODUCT)-$(VERSION) && \ +- debuild --preserve-envvar CCACHE_DIR --prepend-path=/usr/lib/ccache \ ++ debuild --no-lintian --preserve-envvar CCACHE_DIR --prepend-path=/usr/lib/ccache \ + -Z$(TARBALL_COMPRESSOR) -uc -us $(SMPFLAGS) + rm -rf $(BUILDDIR)/$(PRODUCT)-$(VERSION)/ + @echo "------------------------------------------------------------------" diff --git a/utils/packpack/rsync_xfer.sh b/utils/packpack/rsync_xfer.sh index 46cda18cb..8a7f01f4f 100755 --- a/utils/packpack/rsync_xfer.sh +++ b/utils/packpack/rsync_xfer.sh @@ -27,7 +27,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ]; then echo mkdir -p ./zmrepo - ssh_mntchk="$(sshfs zmrepo@zmrepo.zoneminder.com:./ ./zmrepo -o workaround=rename,reconnect)" + ssh_mntchk="$(sshfs zmrepo@zmrepo.zoneminder.com:./ ./zmrepo -o workaround=rename,reconnect 2>&1)" if [ -z "$ssh_mntchk" ]; then echo diff --git a/utils/packpack/setarch.patch b/utils/packpack/setarch.patch new file mode 100644 index 000000000..4f196ec86 --- /dev/null +++ b/utils/packpack/setarch.patch @@ -0,0 +1,57 @@ +From 62a98b36fd62d328956503bc9427ae128bb811af Mon Sep 17 00:00:00 2001 +From: Andrew Bauer +Date: Mon, 26 Feb 2018 10:05:02 -0600 +Subject: [PATCH] fix 32bit rpm builds + +--- + pack/rpm.mk | 2 +- + packpack | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/packpack/pack/rpm.mk b/packpack/pack/rpm.mk +index c74e942..9a6b016 100644 +--- a/packpack/pack/rpm.mk ++++ b/packpack/pack/rpm.mk +@@ -124,7 +124,7 @@ package: $(BUILDDIR)/$(RPMSRC) + @echo "-------------------------------------------------------------------" + @echo "Building RPM packages" + @echo "-------------------------------------------------------------------" +- rpmbuild \ ++ setarch $(ARCH) rpmbuild \ + --define '_topdir $(BUILDDIR)' \ + --define '_sourcedir $(BUILDDIR)' \ + --define '_specdir $(BUILDDIR)' \ +diff --git a/packpack/packpack b/packpack/packpack +index 6f4c80f..c329399 100755 +--- a/packpack/packpack ++++ b/packpack/packpack +@@ -125,7 +125,7 @@ chmod a+x ${BUILDDIR}/userwrapper.sh + # + # Save defined configuration variables to ./env file + # +-env | grep -E "^PRODUCT=|^VERSION=|^RELEASE=|^ABBREV=|^TARBALL_|^CHANGELOG_|^CCACHE_|^PACKAGECLOUD_|^SMPFLAGS=|^OS=|^DIST=" \ ++env | grep -E "^PRODUCT=|^VERSION=|^RELEASE=|^ABBREV=|^TARBALL_|^CHANGELOG_|^CCACHE_|^PACKAGECLOUD_|^SMPFLAGS=|^OS=|^DIST=|^ARCH=" \ + > ${BUILDDIR}/env + + # +diff --git a/packpack/packpack b/packpack/packpack +index c329399..6ffaa9c 100755 +--- a/packpack/packpack ++++ b/packpack/packpack +@@ -19,11 +19,11 @@ DOCKER_REPO=${DOCKER_REPO:-packpack/packpack} + if [ -z "${ARCH}" ]; then + # Use uname -m instead of HOSTTYPE + case "$(uname -m)" in +- i*86) ARCH="i386" ;; +- arm*) ARCH="armhf" ;; +- x86_64) ARCH="x86_64"; ;; +- aarch64) ARCH="aarch64" ;; +- *) ARCH="${HOSTTYPE}" ;; ++ i*86) export ARCH="i386" ;; ++ arm*) export ARCH="armhf" ;; ++ x86_64) export ARCH="x86_64"; ;; ++ aarch64) export ARCH="aarch64" ;; ++ *) export ARCH="${HOSTTYPE}" ;; + esac + fi + diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 4bf9e9ff6..3794e4645 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -19,20 +19,7 @@ checksanity () { exit 1 fi done - - if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then - type repoquery 2>&1 > /dev/null - - if [ $? -ne 0 ]; then - echo - echo "ERROR: The script cannot find the required command \"reqoquery\"." - echo "This command is required in order to build ZoneMinder on el6." - echo "Please install the \"yum-utils\" package then try again." - echo - exit 1 - fi - fi - + # Verify OS & DIST environment variables have been set before calling this script if [ -z "${OS}" ] || [ -z "${DIST}" ]; then echo "ERROR: both OS and DIST environment variables must be set" @@ -102,28 +89,56 @@ commonprep () { git clone https://github.com/packpack/packpack.git packpack fi + # Rpm builds are broken in latest packpack master. Temporarily roll back. + #git -C packpack checkout 7cf23ee + # Patch packpack patch --dry-run --silent -f -p1 < utils/packpack/packpack-rpm.patch if [ $? -eq 0 ]; then patch -p1 < utils/packpack/packpack-rpm.patch fi - # The rpm specfile requires we download the tarball and manually move it into place + # Skip deb lintian checks to speed up the build + patch --dry-run --silent -f -p1 < utils/packpack/nolintian.patch + if [ $? -eq 0 ]; then + patch -p1 < utils/packpack/nolintian.patch + fi + + # fix 32bit rpm builds + # FIXME: breaks arm rpm builds + #patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch + #if [ $? -eq 0 ]; then + # patch -p1 < utils/packpack/setarch.patch + #fi + + # The rpm specfile requires we download each submodule as a tarball then manually move it into place # Might as well do this for Debian as well, rather than git submodule init - CRUDVER="3.0.10" + CRUDVER="3.1.0-zm" if [ -e "build/crud-${CRUDVER}.tar.gz" ]; then echo "Found existing Crud ${CRUDVER} tarball..." else echo "Retrieving Crud ${CRUDVER} submodule..." - curl -L https://github.com/FriendsOfCake/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz + curl -L https://github.com/ZoneMinder/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz if [ $? -ne 0 ]; then echo "ERROR: Crud tarball retreival failed..." exit 1 fi fi + + CEBVER="1.0-zm" + if [ -e "build/cakephp-enum-behavior-${CEBVER}.tar.gz" ]; then + echo "Found existing CakePHP-Enum-Behavior ${CEBVER} tarball..." + else + echo "Retrieving CakePHP-Enum-Behavior ${CEBVER} submodule..." + curl -L https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/${CEBVER}.tar.gz > build/cakephp-enum-behavior-${CEBVER}.tar.gz + if [ $? -ne 0 ]; then + echo "ERROR: CakePHP-Enum-Behavior tarball retreival failed..." + exit 1 + fi + fi } -# Uncompress the Crud tarball and move it into place +# Uncompress the submodule tarballs and move them into place movecrud () { if [ -e "web/api/app/Plugin/Crud/LICENSE.txt" ]; then echo "Crud plugin already installed..." @@ -133,6 +148,14 @@ movecrud () { rmdir web/api/app/Plugin/Crud mv -f crud-${CRUDVER} web/api/app/Plugin/Crud fi + if [ -e "web/api/app/Plugin/CakePHP-Enum-Behavior/readme.md" ]; then + echo "CakePHP-Enum-Behavior plugin already installed..." + else + echo "Unpacking CakePHP-Enum-Behavior plugin..." + tar -xzf build/cakephp-enum-behavior-${CEBVER}.tar.gz + rmdir web/api/app/Plugin/CakePHP-Enum-Behavior + mv -f crud-${CEBVER} web/api/app/Plugin/CakePHP-Enum-Behavior + fi } # previsouly part of installzm.sh @@ -244,10 +267,43 @@ execpackpack () { fi } +# Check for connectivity with the deploy target host +checkdeploytarget () { + echo + echo "Checking Internet connectivity with the deploy host ${DEPLOYTARGET}" + echo + + ping -c 1 ${DEPLOYTARGET} + + if [ $? -ne 0 ]; then + echo + echo "*** WARNING: THERE WAS A PROBLEM CONNECTING TO THE DEPLOY HOST ***" + echo + echo "Printing additional diagnostic information..." + + echo + echo "*** NSLOOKUP ***" + echo + nslookup ${DEPLOYTARGET} + + echo + echo "*** TRACEROUTE ***" + echo + traceroute -w 2 -m 15 ${DEPLOYTARGET} + fi +} + ################ # MAIN PROGRAM # ################ +# Set the hostname we will deploy packages to +DEPLOYTARGET="zmrepo.zoneminder.com" + +# If we are running inside Travis then verify we can connect to the target host machine +if [ "${TRAVIS}" == "true" ]; then + checkdeploytarget +fi checksanity # We don't want to build packages for all supported distros after every commit @@ -268,20 +324,12 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then rm -rf web/api/app/Plugin/Crud mkdir web/api/app/Plugin/Crud - # We use zmrepo to build el6 only. All other redhat distros use rpm fusion - if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then - baseurl="https://zmrepo.zoneminder.com/el/${DIST}/x86_64/" - reporpm="zmrepo" - # Let repoquery determine the full url and filename to the latest zmrepo package - dlurl=`repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2> /dev/null` - else - reporpm="rpmfusion-free-release" - dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm" - fi + reporpm="rpmfusion-free-release" + dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm" # Give our downloaded repo rpm a common name so redhat_package.mk can find it if [ -n "$dlurl" ] && [ $? -eq 0 ]; then - echo "Retrieving ${reporpm} repo rpm..."gd + echo "Retrieving ${reporpm} repo rpm..." curl $dlurl > build/external-repo.noarch.rpm else echo "ERROR: Failed to retrieve ${reporpm} repo rpm..." @@ -295,7 +343,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then execpackpack # Steps common to Debian based distros - elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then + elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ] || [ "${OS}" == "raspbian" ]; then echo "Begin ${OS} ${DIST} build..." setdebpkgname diff --git a/version b/version index 6367ac8f2..856307b22 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.39 +1.31.44 diff --git a/web/.htaccess b/web/.htaccess deleted file mode 100644 index f23dbaf66..000000000 --- a/web/.htaccess +++ /dev/null @@ -1,5 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ app/webroot/ [L] - RewriteRule (.*) app/webroot/$1 [L] - \ No newline at end of file diff --git a/web/ajax/log.php b/web/ajax/log.php index ac9b62ad6..14fc1d772 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -4,443 +4,404 @@ # These are the valid columns that you can filter on. $filterFields = array( 'Component', 'ServerId', 'Pid', 'Level', 'File', 'Line' ); -switch ( $_REQUEST['task'] ) -{ - case 'create' : - { - // Silently ignore bogus requests - if ( !empty($_POST['level']) && !empty($_POST['message']) ) - { - logInit( array( 'id' => "web_js" ) ); +switch ( $_REQUEST['task'] ) { + case 'create' : + { + // Silently ignore bogus requests + if ( !empty($_POST['level']) && !empty($_POST['message']) ) { + logInit(array('id'=>'web_js')); - $string = $_POST['message']; + $string = $_POST['message']; - $file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/\w+\//', '', $_POST['file'] ) : ''; - if ( !empty( $_POST['line'] ) ) - $line = $_POST['line']; - else - $line = NULL; + $file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/\w+\//', '', $_POST['file'] ) : ''; + if ( !empty( $_POST['line'] ) ) + $line = $_POST['line']; + else + $line = NULL; - $levels = array_flip(Logger::$codes); - if ( !isset($levels[$_POST['level']]) ) - Panic( "Unexpected logger level '".$_POST['level']."'" ); - $level = $levels[$_POST['level']]; - Logger::fetch()->logPrint( $level, $string, $file, $line ); - } - ajaxResponse(); - break; + $levels = array_flip(Logger::$codes); + if ( !isset($levels[$_POST['level']]) ) + Panic("Unexpected logger level '".$_POST['level']."'"); + $level = $levels[$_POST['level']]; + Logger::fetch()->logPrint( $level, $string, $file, $line ); } - case 'query' : - { - if ( !canView( 'System' ) ) - ajaxError( 'Insufficient permissions to view log entries' ); + ajaxResponse(); + break; + } + case 'query' : + { + 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($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL; - $maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL; - - $limit = 100; - if ( isset($_REQUEST['limit']) ) { - if ( ( !is_integer( $_REQUEST['limit'] ) and !ctype_digit($_REQUEST['limit']) ) ) { - Error("Invalid value for limit " . $_REQUEST['limit'] ); - } else { - $limit = $_REQUEST['limit']; - } - } - $sortField = 'TimeKey'; - if ( isset($_REQUEST['sortField']) ) { - if ( ! in_array( $_REQUEST['sortField'], $filterFields ) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) { - Error("Invalid sort field " . $_REQUEST['sortField'] ); - } else { - $sortField = $_REQUEST['sortField']; - } - } - $sortOrder = (isset($_REQUEST['sortOrder']) and $_REQUEST['sortOrder']) == 'asc' ? 'asc':'desc'; - $filter = isset($_REQUEST['filter'])?$_REQUEST['filter']:array(); - - $total = dbFetchOne( 'SELECT count(*) AS Total FROM Logs', 'Total' ); - $sql = 'SELECT * FROM Logs'; - $where = array(); - $values = array(); - if ( $minTime ) { - $where[] = "TimeKey > ?"; - $values[] = $minTime; - } elseif ( $maxTime ) { - $where[] = "TimeKey < ?"; - $values[] = $maxTime; - } - - foreach ( $filter as $field=>$value ) { - if ( ! in_array( $field, $filterFields ) ) { - Error("$field is not in valid filter fields"); - continue; - } - if ( $field == 'Level' ){ - $where[] = $field." <= ?"; - $values[] = $value; - } else { - $where[] = $field." = ?"; - $values[] = $value; - } - } - if ( count($where) ) - $sql.= ' WHERE '.join( ' AND ', $where ); - $sql .= " order by ".$sortField." ".$sortOrder." limit ".$limit; - $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() : ''; - $log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message'] ); - $logs[] = $log; - } - $options = array(); - $where = array(); - $values = array(); - foreach( $filter as $field=>$value ) { - if ( $field == 'Level' ) { - $where[$field] = $field." <= ?"; - $values[$field] = $value; - } else { - $where[$field] = $field." = ?"; - $values[$field] = $value; - } - } - foreach( $filterFields as $field ) - { - $sql = "SELECT DISTINCT $field FROM Logs WHERE NOT isnull($field)"; - $fieldWhere = array_diff_key( $where, array( $field=>true ) ); - $fieldValues = array_diff_key( $values, array( $field=>true ) ); - if ( count($fieldWhere) ) - $sql.= " AND ".join( ' AND ', $fieldWhere ); - $sql.= " ORDER BY $field ASC"; - if ( $field == 'Level' ) - { - foreach( dbFetchAll( $sql, $field, array_values($fieldValues) ) as $value ) - if ( $value <= Logger::INFO ) - $options[$field][$value] = Logger::$codes[$value]; - 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 ) - if ( $value != '' ) - $options[$field][] = $value; - } - } - if ( count($filter) ) - { - $sql = "SELECT count(*) AS Available FROM Logs WHERE ".join( ' AND ', $where ); - $available = dbFetchOne( $sql, 'Available', array_values($values) ); - } - ajaxResponse( array( - 'updated' => preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG ), - 'total' => $total, - 'available' => isset($available)?$available:$total, - 'logs' => $logs, - 'state' => logState(), - 'options' => $options - ) ); - break; + $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; } - case 'export' : + + $minTime = isset($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL; + $maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL; + + $limit = 100; + if ( isset($_REQUEST['limit']) ) { + if ( ( !is_integer( $_REQUEST['limit'] ) and !ctype_digit($_REQUEST['limit']) ) ) { + Error('Invalid value for limit ' . $_REQUEST['limit'] ); + } else { + $limit = $_REQUEST['limit']; + } + } + $sortField = 'TimeKey'; + if ( isset($_REQUEST['sortField']) ) { + if ( ! in_array( $_REQUEST['sortField'], $filterFields ) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) { + Error("Invalid sort field " . $_REQUEST['sortField'] ); + } else { + $sortField = $_REQUEST['sortField']; + } + } + $sortOrder = (isset($_REQUEST['sortOrder']) and $_REQUEST['sortOrder']) == 'asc' ? 'asc':'desc'; + $filter = isset($_REQUEST['filter'])?$_REQUEST['filter']:array(); + + $total = dbFetchOne('SELECT count(*) AS Total FROM Logs', 'Total'); + $sql = 'SELECT * FROM Logs'; + $where = array(); + $values = array(); + if ( $minTime ) { + $where[] = 'TimeKey > ?'; + $values[] = $minTime; + } elseif ( $maxTime ) { + $where[] = 'TimeKey < ?'; + $values[] = $maxTime; + } + + foreach ( $filter as $field=>$value ) { + if ( ! in_array($field, $filterFields) ) { + Error("$field is not in valid filter fields"); + continue; + } + if ( $field == 'Level' ){ + $where[] = $field.' <= ?'; + $values[] = $value; + } else { + $where[] = $field.' = ?'; + $values[] = $value; + } + } + $options = array(); + if ( count($where) ) + $sql.= ' WHERE '.join( ' AND ', $where ); + $sql .= ' ORDER BY '.$sortField.' '.$sortOrder.' LIMIT '.$limit; + $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() : ''; + $log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message'] ); + foreach( $filterFields as $field ) { + if ( ! isset( $options[$field] ) ) + $options[$field] = array(); + $value = $log[$field]; + + if ( $field == 'Level' ) { + if ( $value <= Logger::INFO ) + $options[$field][$value] = Logger::$codes[$value]; + else + $options[$field][$value] = 'DB'.$value; + } else if ( $field == 'ServerId' ) { + $options['ServerId'][$value] = ( $value and isset($servers_by_Id[$value]) ) ? $servers_by_Id[$value]->Name() : ''; + } else if ( isset($log[$field]) ) { + $options[$field][$log[$field]] = $log[$field]; + } + } + $logs[] = $log; + } + + $available = count($logs); + ajaxResponse( array( + 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG)?strftime(DATE_FMT_CONSOLE_LONG):date(DATE_FMT_CONSOLE_LONG), + 'total' => $total, + 'available' => isset($available)?$available:$total, + 'logs' => $logs, + 'state' => logState(), + 'options' => $options + ) ); + break; + } + case 'export' : + { + if ( !canView('System') ) + ajaxError('Insufficient permissions to export logs'); + + $minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL; + $maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL; + if ( !is_null($minTime) && !is_null($maxTime) && $minTime > $maxTime ) { + $tempTime = $minTime; + $minTime = $maxTime; + $maxTime = $tempTime; + } + //$limit = isset($_POST['limit'])?$_POST['limit']:1000; + $filter = isset($_POST['filter'])?$_POST['filter']:array(); + $sortField = 'TimeKey'; + if ( isset($_POST['sortField']) ) { + if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) { + Error("Invalid sort field " . $_POST['sortField'] ); + } else { + $sortField = $_POST['sortField']; + } + } + $sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc'; + + $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(); + if ( $minTime ) { + preg_match('/(.+)(\.\d+)/', $minTime, $matches); + $minTime = strtotime($matches[1]).$matches[2]; + $where[] = 'TimeKey >= ?'; + $values[] = $minTime; + } + if ( $maxTime ) { + preg_match('/(.+)(\.\d+)/', $maxTime, $matches); + $maxTime = strtotime($matches[1]).$matches[2]; + $where[] = 'TimeKey <= ?'; + $values[] = $maxTime; + } + foreach ( $filter as $field=>$value ) { + if ( $value != '' ) { + if ( $field == 'Level' ) { + $where[] = $field.' <= ?'; + $values[] = $value; + } else { + $where[] = $field.' = ?'; + $values[] = $value; + } + } + } + if ( count($where) ) + $sql.= ' WHERE '.join( ' AND ', $where ); + $sql .= ' ORDER BY '.$sortField.' '.$sortOrder; + //$sql .= " limit ".dbEscape($limit); + $format = isset($_POST['format'])?$_POST['format']:'text'; + switch( $format ) { + case 'text' : + $exportExt = 'txt'; + break; + case 'tsv' : + $exportExt = 'tsv'; + break; + case 'html' : + $exportExt = 'html'; + break; + case 'xml' : + $exportExt = 'xml'; + break; + default : + Fatal("Unrecognised log export format '$format'"); + } + $exportKey = substr(md5(rand()),0,8); + $exportFile = "zm-log.$exportExt"; + $exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt"; + if ( !($exportFP = fopen( $exportPath, "w" )) ) + Fatal("Unable to open log export file $exportPath"); + $logs = array(); + foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) { + $log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] ); + $log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : ''; + $logs[] = $log; + } + switch( $format ) { + case 'text' : { - if ( !canView( 'System' ) ) - ajaxError( 'Insufficient permissions to export logs' ); - - $minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL; - $maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL; - if ( !is_null($minTime) && !is_null($maxTime) && $minTime > $maxTime ) - { - $tempTime = $minTime; - $minTime = $maxTime; - $maxTime = $tempTime; - } - //$limit = isset($_POST['limit'])?$_POST['limit']:1000; - $filter = isset($_POST['filter'])?$_POST['filter']:array(); - $sortField = 'TimeKey'; - if ( isset($_POST['sortField']) ) { - if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) { - Error("Invalid sort field " . $_POST['sortField'] ); - } else { - $sortField = $_POST['sortField']; - } - } - $sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc'; - - $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(); - if ( $minTime ) - { - preg_match( '/(.+)(\.\d+)/', $minTime, $matches ); - $minTime = strtotime($matches[1]).$matches[2]; - $where[] = "TimeKey >= ?"; - $values[] = $minTime; - } - if ( $maxTime ) - { - preg_match( '/(.+)(\.\d+)/', $maxTime, $matches ); - $maxTime = strtotime($matches[1]).$matches[2]; - $where[] = "TimeKey <= ?"; - $values[] = $maxTime; - } - foreach ( $filter as $field=>$value ) { - if ( $value != '' ) { - if ( $field == 'Level' ) { - $where[] = $field." <= ?"; - $values[] = $value; - } else { - $where[] = $field." = ?'"; - $values[] = $value; - } - } - } - if ( count($where) ) - $sql.= " where ".join( " and ", $where ); - $sql .= " order by ".$sortField." ".$sortOrder; - //$sql .= " limit ".dbEscape($limit); - $format = isset($_POST['format'])?$_POST['format']:'text'; - switch( $format ) - { - case 'text' : - $exportExt = "txt"; - break; - case 'tsv' : - $exportExt = "tsv"; - break; - case 'html' : - $exportExt = "html"; - break; - case 'xml' : - $exportExt = "xml"; - break; - default : - Fatal( "Unrecognised log export format '$format'" ); - } - $exportKey = substr(md5(rand()),0,8); - $exportFile = "zm-log.$exportExt"; - $exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt"; - if ( !($exportFP = fopen( $exportPath, "w" )) ) - Fatal( "Unable to open log export file $exportPath" ); - $logs = array(); - foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) - { - $log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] ); - $log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : ''; - $logs[] = $log; - } - switch( $format ) - { - case 'text' : - { - foreach ( $logs as $log ) - { - if ( $log['Line'] ) - fprintf( $exportFP, "%s %s[%d].%s-%s/%d [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message'] ); - else - fprintf( $exportFP, "%s %s[%d].%s-%s [%s]\n", $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message'] ); - } - break; - } - case 'tsv' : - { -# This line doesn't need fprintf, it could use fwrite - fprintf( $exportFP, join( "\t", - translate('DateTime'), - translate('Component'), - translate('Server'), - translate('Pid'), - translate('Level'), - translate('Message'), - translate('File'), - translate('Line') - )."\n" ); - foreach ( $logs as $log ) - { - fprintf( $exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); - } - break; - } - case 'html' : - { - fwrite( $exportFP, -' - - - '.translate('ZoneMinderLog').' - - - + foreach ( $logs as $log ) { + if ( $log['Line'] ) + fprintf( $exportFP, "%s %s[%d].%s-%s/%d [%s]\n", + $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message'] ); + else + fprintf( $exportFP, "%s %s[%d].%s-%s [%s]\n", + $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message'] ); + } + break; + } + case 'tsv' : + { + # This line doesn't need fprintf, it could use fwrite + fprintf( $exportFP, join( "\t", + translate('DateTime'), + translate('Component'), + translate('Server'), + translate('Pid'), + translate('Level'), + translate('Message'), + translate('File'), + translate('Line') + )."\n" ); + foreach ( $logs as $log ) { + fprintf( $exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); + } + break; + } + case 'html' : + { + fwrite( $exportFP, + ' + + + + '.translate('ZoneMinderLog').' + + +

'.translate('ZoneMinderLog').'

'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'

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

- - -' ); - foreach ( $logs as $log ) - { - $classLevel = $log['Level']; - if ( $classLevel < Logger::FATAL ) - $classLevel = Logger::FATAL; - elseif ( $classLevel > Logger::DEBUG ) - $classLevel = Logger::DEBUG; - $logClass = 'log-'.strtolower(Logger::$codes[$classLevel]); - fprintf( $exportFP, " \n", $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); - } - fwrite( $exportFP, -' -
'.translate('DateTime').''.translate('Component').''.translate('Server').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').'
%s%s%s%d%s%s%s%s
- -' ); - break; - } - case 'xml' : - { - fwrite( $exportFP, -' - - '.$_POST['selector'].'' ); - foreach ( $filter as $field=>$value ) - if ( $value != '' ) - fwrite( $exportFP, -' - <'.strtolower($field).'>'.htmlspecialchars($value).' - ' ); - fwrite( $exportFP, -' - '.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' - - -' ); - foreach ( $logs as $log ) - { - fprintf( $exportFP, -" - %s - %s - %s - %d - %s - - %s - %d - \n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); - } - fwrite( $exportFP, -' -' ); - break; - } - $exportExt = "xml"; - break; - } - fclose( $exportFP ); - ajaxResponse( array( - 'key' => $exportKey, - 'format' => $format, - ) ); - break; + + '.translate('DateTime').''.translate('Component').''.translate('Server').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' + ' ); + foreach ( $logs as $log ) { + $classLevel = $log['Level']; + if ( $classLevel < Logger::FATAL ) + $classLevel = Logger::FATAL; + elseif ( $classLevel > Logger::DEBUG ) + $classLevel = Logger::DEBUG; + $logClass = 'log-'.strtolower(Logger::$codes[$classLevel]); + fprintf( $exportFP, " %s%s%s%d%s%s%s%s\n", $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); } - case 'download' : + fwrite( $exportFP, + ' + + + ' ); + break; + } + case 'xml' : { - if ( !canView( 'System' ) ) - ajaxError( 'Insufficient permissions to download logs' ); - - if ( empty($_REQUEST['key']) ) - Fatal( "No log export key given" ); - $exportKey = $_REQUEST['key']; - if ( empty($_REQUEST['format']) ) - Fatal( "No log export format given" ); - $format = $_REQUEST['format']; - - switch( $format ) - { - case 'text' : - $exportExt = "txt"; - break; - case 'tsv' : - $exportExt = "tsv"; - break; - case 'html' : - $exportExt = "html"; - break; - case 'xml' : - $exportExt = "xml"; - break; - default : - Fatal( "Unrecognised log export format '$format'" ); - } - - $exportFile = "zm-log.$exportExt"; - $exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt"; - - header( "Pragma: public" ); - header( "Expires: 0" ); - header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); - header( "Cache-Control: private", false ); // required by certain browsers - header( "Content-Description: File Transfer" ); - header( 'Content-Disposition: attachment; filename="'.$exportFile.'"' ); - header( "Content-Transfer-Encoding: binary" ); - header( "Content-Type: application/force-download" ); - header( "Content-Length: ".filesize($exportPath) ); - readfile( $exportPath ); - exit( 0 ); - break; + fwrite( $exportFP, + ' + + '.$_POST['selector'].'' ); + foreach ( $filter as $field=>$value ) + if ( $value != '' ) + fwrite( $exportFP, + ' + <'.strtolower($field).'>'.htmlspecialchars($value).' + ' ); + fwrite( $exportFP, + ' + '.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' + + + ' ); + foreach ( $logs as $log ) { + fprintf( $exportFP, + " + %s + %s + %s + %d + %s + + %s + %d + \n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); + } + fwrite( $exportFP, + ' + ' ); + break; } + $exportExt = "xml"; + break; + } + fclose( $exportFP ); + ajaxResponse( array( + 'key' => $exportKey, + 'format' => $format, + ) ); + break; + } + case 'download' : + { + if ( !canView('System') ) + ajaxError('Insufficient permissions to download logs'); + + if ( empty($_REQUEST['key']) ) + Fatal( "No log export key given" ); + $exportKey = $_REQUEST['key']; + if ( empty($_REQUEST['format']) ) + Fatal( "No log export format given" ); + $format = $_REQUEST['format']; + + switch( $format ) { + case 'text' : + $exportExt = 'txt'; + break; + case 'tsv' : + $exportExt = 'tsv'; + break; + case 'html' : + $exportExt = 'html'; + break; + case 'xml' : + $exportExt = 'xml'; + break; + default : + Fatal("Unrecognised log export format '$format'"); + } + + $exportFile = "zm-log.$exportExt"; + $exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt"; + + header( "Pragma: public" ); + header( "Expires: 0" ); + header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); + header( "Cache-Control: private", false ); // required by certain browsers + header( "Content-Description: File Transfer" ); + header( 'Content-Disposition: attachment; filename="'.$exportFile.'"' ); + header( "Content-Transfer-Encoding: binary" ); + header( "Content-Type: application/force-download" ); + header( "Content-Length: ".filesize($exportPath) ); + readfile( $exportPath ); + exit( 0 ); + break; + } } - -ajaxError( 'Unrecognised action or insufficient permissions' ); - +ajaxError('Unrecognised action or insufficient permissions'); ?> diff --git a/web/ajax/status.php b/web/ajax/status.php index 3d4cc85b4..0348952f1 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -109,83 +109,83 @@ $statusData = array( 'MaxScore' => true, ), ), - 'event' => array( - 'permission' => 'Events', - 'table' => 'Events', - 'limit' => 1, - 'selector' => 'Events.Id', - 'elements' => array( - 'Id' => array( 'sql' => 'Events.Id' ), - 'MonitorId' => true, - 'MonitorName' => array('sql' => '(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)'), - 'Name' => true, - 'Cause' => true, - 'StartTime' => true, - 'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), - 'EndTime' => true, - 'Width' => true, - 'Height' => true, - 'Length' => true, - 'Frames' => true, - 'DefaultVideo' => true, - 'AlarmFrames' => true, - 'TotScore' => true, - 'AvgScore' => true, - 'MaxScore' => true, - 'Archived' => true, - 'Videoed' => true, - 'Uploaded' => true, - 'Emailed' => true, - 'Messaged' => true, - 'Executed' => true, - 'Notes' => true, - 'MinFrameId' => array( 'sql' => '(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)' ), - 'MaxFrameId' => array( 'sql' => '(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)' ), - 'MinFrameDelta' => array( 'sql' => '(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ), - 'MaxFrameDelta' => array( 'sql' => '(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ), - ), - ), - 'frames' => array( - 'permission' => 'Events', - 'table' => 'Frames', - 'selector' => 'EventId', - 'elements' => array( - 'EventId' => true, - 'FrameId' => true, - 'Type' => true, - 'Delta' => true, - ), - ), - 'frame' => array( - 'permission' => 'Events', - 'table' => 'Frames', - 'limit' => 1, - 'selector' => array( array( 'table' => 'Events', 'join' => 'Events.Id = Frames.EventId', 'selector'=>'Events.Id' ), 'Frames.FrameId' ), - 'elements' => array( - //'Id' => array( 'sql' => 'Frames.FrameId' ), - 'FrameId' => true, - 'EventId' => true, - 'Type' => true, - 'TimeStamp' => true, - 'TimeStampShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), - 'Delta' => true, - 'Score' => true, - //'Image' => array( 'postFunc' => 'getFrameImage' ), - ), - ), - 'frameimage' => array( - 'permission' => 'Events', - 'func' => 'getFrameImage()' - ), - 'nearframe' => array( - 'permission' => 'Events', - 'func' => 'getNearFrame()' - ), - 'nearevents' => array( - 'permission' => 'Events', - 'func' => 'getNearEvents()' - ) - ); + 'event' => array( + 'permission' => 'Events', + 'table' => 'Events', + 'limit' => 1, + 'selector' => 'Events.Id', + 'elements' => array( + 'Id' => array( 'sql' => 'Events.Id' ), + 'MonitorId' => true, + 'MonitorName' => array('sql' => '(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)'), + 'Name' => true, + 'Cause' => true, + 'StartTime' => true, + 'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), + 'EndTime' => true, + 'Width' => true, + 'Height' => true, + 'Length' => true, + 'Frames' => true, + 'DefaultVideo' => true, + 'AlarmFrames' => true, + 'TotScore' => true, + 'AvgScore' => true, + 'MaxScore' => true, + 'Archived' => true, + 'Videoed' => true, + 'Uploaded' => true, + 'Emailed' => true, + 'Messaged' => true, + 'Executed' => true, + 'Notes' => true, + 'MinFrameId' => array( 'sql' => '(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)' ), + 'MaxFrameId' => array( 'sql' => '(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)' ), + 'MinFrameDelta' => array( 'sql' => '(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ), + 'MaxFrameDelta' => array( 'sql' => '(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ), + ), + ), + 'frames' => array( + 'permission' => 'Events', + 'table' => 'Frames', + 'selector' => 'EventId', + 'elements' => array( + 'EventId' => true, + 'FrameId' => true, + 'Type' => true, + 'Delta' => true, + ), + ), + 'frame' => array( + 'permission' => 'Events', + 'table' => 'Frames', + 'limit' => 1, + 'selector' => array( array( 'table' => 'Events', 'join' => 'Events.Id = Frames.EventId', 'selector'=>'Events.Id' ), 'Frames.FrameId' ), + 'elements' => array( + //'Id' => array( 'sql' => 'Frames.FrameId' ), + 'FrameId' => true, + 'EventId' => true, + 'Type' => true, + 'TimeStamp' => true, + 'TimeStampShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), + 'Delta' => true, + 'Score' => true, + //'Image' => array( 'postFunc' => 'getFrameImage' ), + ), + ), + 'frameimage' => array( + 'permission' => 'Events', + 'func' => 'getFrameImage()' + ), + 'nearframe' => array( + 'permission' => 'Events', + 'func' => 'getNearFrame()' + ), + 'nearevents' => array( + 'permission' => 'Events', + 'func' => 'getNearEvents()' + ) + ); function collectData() { global $statusData; @@ -302,8 +302,8 @@ function collectData() { } } } -#print_r( $data ); - return( $data ); + #Logger::Debug(print_r($data, true)); + return $data; } $data = collectData(); @@ -345,8 +345,8 @@ function getFrameImage() { $eventId = $_REQUEST['id'][0]; $frameId = $_REQUEST['id'][1]; - $sql = 'select * from Frames where EventId = ? and FrameId = ?'; - if ( !($frame = dbFetchOne( $sql, NULL, array( $eventId, $frameId ) )) ) { + $sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?'; + if ( !($frame = dbFetchOne( $sql, NULL, array($eventId, $frameId ) )) ) { $frame = array(); $frame['EventId'] = $eventId; $frame['FrameId'] = $frameId; diff --git a/web/ajax/stream.php b/web/ajax/stream.php index 57e138254..1c2fb3d62 100644 --- a/web/ajax/stream.php +++ b/web/ajax/stream.php @@ -10,11 +10,12 @@ if ( !($_REQUEST['connkey'] && $_REQUEST['command']) ) { ajaxError( "Unexpected received message type '$type'" ); } -$key = ftok(ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'w.lock', 'Z'); +# The file that we point ftok to has to exist, and only exist if zms is running, so we are pointing it at the .sock +$key = ftok(ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'s.sock', 'Z'); $semaphore = sem_get($key,1); if ( sem_acquire($semaphore,1) !== false ) { - if ( !($socket = @socket_create( AF_UNIX, SOCK_DGRAM, 0 )) ) { - ajaxError( 'socket_create() failed: '.socket_strerror(socket_last_error()) ); + if ( !($socket = @socket_create(AF_UNIX, SOCK_DGRAM, 0)) ) { + ajaxError('socket_create() failed: '.socket_strerror(socket_last_error())); } $localSocketFile = ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'w.sock'; @@ -133,31 +134,27 @@ if ( sem_acquire($semaphore,1) !== false ) { $data['delay'] = round( $data['delay'], 2 ); $data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 ); if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' ) { - session_start(); $time = time(); // Regenerate auth hash after half the lifetime of the hash if ( (!isset($_SESSION['AuthHashGeneratedAt'])) or ( $_SESSION['AuthHashGeneratedAt'] < $time - (ZM_AUTH_HASH_TTL * 1800) ) ) { - $data['auth'] = generateAuthHash( ZM_AUTH_HASH_IPS ); + $data['auth'] = generateAuthHash(ZM_AUTH_HASH_IPS); } - session_write_close(); } ajaxResponse( array( 'status'=>$data ) ); break; } case MSG_DATA_EVENT : { - $data = unpack( "ltype/ievent/iprogress/irate/izoom/Cpaused", $msg ); + $data = unpack( "ltype/Pevent/iprogress/irate/izoom/Cpaused", $msg ); //$data['progress'] = sprintf( "%.2f", $data['progress'] ); $data['rate'] /= RATE_BASE; $data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 ); if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' ) { - session_start(); $time = time(); // Regenerate auth hash after half the lifetime of the hash if ( (!isset($_SESSION['AuthHashGeneratedAt'])) or ( $_SESSION['AuthHashGeneratedAt'] < $time - (ZM_AUTH_HASH_TTL * 1800) ) ) { - $data['auth'] = generateAuthHash( ZM_AUTH_HASH_IPS ); + $data['auth'] = generateAuthHash(ZM_AUTH_HASH_IPS); } - session_write_close(); } ajaxResponse( array( 'status'=>$data ) ); break; diff --git a/web/api/.htaccess b/web/api/.htaccess deleted file mode 100644 index 7139a2766..000000000 --- a/web/api/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ app/webroot/ [L] - RewriteRule (.*) app/webroot/$1 [L] - RewriteBase /zm/api - diff --git a/web/api/app/.htaccess b/web/api/app/.htaccess deleted file mode 100644 index 1af74d971..000000000 --- a/web/api/app/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ webroot/ [L] - RewriteRule (.*) webroot/$1 [L] - RewriteBase /zm/api - diff --git a/web/api/app/Config/Schema/db_acl.php b/web/api/app/Config/Schema/db_acl.php index 91d93e084..7dfc7f7ef 100644 --- a/web/api/app/Config/Schema/db_acl.php +++ b/web/api/app/Config/Schema/db_acl.php @@ -4,32 +4,42 @@ * * Use it to configure database for ACL * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config.Schema * @since CakePHP(tm) v 0.2.9 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ -/* - * +/** * Using the Schema command line utility * cake schema run create DbAcl - * */ class DbAclSchema extends CakeSchema { +/** + * Before event. + * + * @param array $event The event data. + * @return bool Success + */ public function before($event = array()) { return true; } +/** + * After event. + * + * @param array $event The event data. + * @return void + */ public function after($event = array()) { } @@ -44,7 +54,11 @@ class DbAclSchema extends CakeSchema { 'alias' => array('type' => 'string', 'null' => true), 'lft' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10), 'rght' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10), - 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)) + 'indexes' => array( + 'PRIMARY' => array('column' => 'id', 'unique' => 1), + 'idx_acos_lft_rght' => array('column' => array('lft', 'rght'), 'unique' => 0), + 'idx_acos_alias' => array('column' => 'alias', 'unique' => 0) + ) ); /** @@ -58,7 +72,11 @@ class DbAclSchema extends CakeSchema { 'alias' => array('type' => 'string', 'null' => true), 'lft' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10), 'rght' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10), - 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)) + 'indexes' => array( + 'PRIMARY' => array('column' => 'id', 'unique' => 1), + 'idx_aros_lft_rght' => array('column' => array('lft', 'rght'), 'unique' => 0), + 'idx_aros_alias' => array('column' => 'alias', 'unique' => 0) + ) ); /** @@ -73,7 +91,11 @@ class DbAclSchema extends CakeSchema { '_read' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2), '_update' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2), '_delete' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2), - 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'ARO_ACO_KEY' => array('column' => array('aro_id', 'aco_id'), 'unique' => 1)) + 'indexes' => array( + 'PRIMARY' => array('column' => 'id', 'unique' => 1), + 'ARO_ACO_KEY' => array('column' => array('aro_id', 'aco_id'), 'unique' => 1), + 'idx_aco_id' => array('column' => 'aco_id', 'unique' => 0) + ) ); } diff --git a/web/api/app/Config/Schema/db_acl.sql b/web/api/app/Config/Schema/db_acl.sql index 274780e26..cbb0ccece 100644 --- a/web/api/app/Config/Schema/db_acl.sql +++ b/web/api/app/Config/Schema/db_acl.sql @@ -1,11 +1,11 @@ # $Id$ # -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. -# MIT License (http://www.opensource.org/licenses/mit-license.php) +# MIT License (https://opensource.org/licenses/mit-license.php) CREATE TABLE acos ( id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, @@ -38,4 +38,15 @@ CREATE TABLE aros ( lft INTEGER(10) DEFAULT NULL, rght INTEGER(10) DEFAULT NULL, PRIMARY KEY (id) -); \ No newline at end of file +); + +/* this indexes will improve acl perfomance */ +CREATE INDEX idx_acos_lft_rght ON `acos` (`lft`, `rght`); + +CREATE INDEX idx_acos_alias ON `acos` (`alias`); + +CREATE INDEX idx_aros_lft_rght ON `aros` (`lft`, `rght`); + +CREATE INDEX idx_aros_alias ON `aros` (`alias`); + +CREATE INDEX idx_aco_id ON `aros_acos` (`aco_id`); diff --git a/web/api/app/Config/Schema/i18n.php b/web/api/app/Config/Schema/i18n.php index febb2dbd5..63dc0db9f 100644 --- a/web/api/app/Config/Schema/i18n.php +++ b/web/api/app/Config/Schema/i18n.php @@ -4,22 +4,21 @@ * * Use it to configure database for i18n * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config.Schema * @since CakePHP(tm) v 0.2.9 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** - * * Using the Schema command line utility * * Use it to configure database for i18n @@ -28,15 +27,37 @@ */ class I18nSchema extends CakeSchema { +/** + * The name property + * + * @var string + */ public $name = 'i18n'; +/** + * Before callback. + * + * @param array $event Schema object properties + * @return bool Should process continue + */ public function before($event = array()) { return true; } +/** + * After callback. + * + * @param array $event Schema object properties + * @return void + */ public function after($event = array()) { } +/** + * The i18n table definition + * + * @var array + */ public $i18n = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'), 'locale' => array('type' => 'string', 'null' => false, 'length' => 6, 'key' => 'index'), diff --git a/web/api/app/Config/Schema/i18n.sql b/web/api/app/Config/Schema/i18n.sql index 66a42bd19..a1a4e6893 100644 --- a/web/api/app/Config/Schema/i18n.sql +++ b/web/api/app/Config/Schema/i18n.sql @@ -1,11 +1,11 @@ # $Id$ # -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. -# MIT License (http://www.opensource.org/licenses/mit-license.php) +# MIT License (https://opensource.org/licenses/mit-license.php) CREATE TABLE i18n ( id int(10) NOT NULL auto_increment, diff --git a/web/api/app/Config/Schema/sessions.sql b/web/api/app/Config/Schema/sessions.sql index 76845bdc8..e19755622 100644 --- a/web/api/app/Config/Schema/sessions.sql +++ b/web/api/app/Config/Schema/sessions.sql @@ -1,13 +1,13 @@ # $Id$ # -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # 1785 E. Sahara Avenue, Suite 490-204 # Las Vegas, Nevada 89104 # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. -# MIT License (http://www.opensource.org/licenses/mit-license.php) +# MIT License (https://opensource.org/licenses/mit-license.php) CREATE TABLE cake_sessions ( id varchar(255) NOT NULL default '', diff --git a/web/api/app/Config/acl.ini.php b/web/api/app/Config/acl.ini.php index 9a4672132..5c890f50a 100644 --- a/web/api/app/Config/acl.ini.php +++ b/web/api/app/Config/acl.ini.php @@ -2,20 +2,20 @@ ;/** ; * ACL Configuration ; * -; * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) -; * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +; * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +; * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) ; * ; * Licensed under The MIT License ; * Redistributions of files must retain the above copyright notice. ; * -; * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) -; * @link http://cakephp.org CakePHP(tm) Project +; * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +; * @link https://cakephp.org CakePHP(tm) Project ; * @package app.Config ; * @since CakePHP(tm) v 0.10.0.1076 -; * @license http://www.opensource.org/licenses/mit-license.php MIT License +; * @license https://opensource.org/licenses/mit-license.php MIT License ; */ -; acl.ini.php - Cake ACL Configuration +; acl.ini.php - CakePHP ACL Configuration ; --------------------------------------------------------------------- ; Use this file to specify user permissions. ; aco = access control object (something in your application) diff --git a/web/api/app/Config/acl.php b/web/api/app/Config/acl.php index a8d6e380b..cddb9f47e 100644 --- a/web/api/app/Config/acl.php +++ b/web/api/app/Config/acl.php @@ -4,18 +4,18 @@ * * Use it to configure access control of your CakePHP application. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 2.1 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** @@ -34,60 +34,72 @@ * will ask the configured ACL interface if access is granted. Under the assumptions 1. and 2. this will be * done via a call to Acl->check() with * - * array('User' => array('username' => 'jeff', 'group_id' => 4, ...)) + * ``` + * array('User' => array('username' => 'jeff', 'group_id' => 4, ...)) + * ``` * * as ARO and * - * '/controllers/invoices/delete' + * ``` + * '/controllers/invoices/delete' + * ``` * * as ACO. * * If the configured map looks like * - * $config['map'] = array( - * 'User' => 'User/username', - * 'Role' => 'User/group_id', - * ); + * ``` + * $config['map'] = array( + * 'User' => 'User/username', + * 'Role' => 'User/group_id', + * ); + * ``` * * then PhpAcl will lookup if we defined a role like User/jeff. If that role is not found, PhpAcl will try to * find a definition for Role/4. If the definition isn't found then a default role (Role/default) will be used to * check rules for the given ACO. The search can be expanded by defining aliases in the alias configuration. * E.g. if you want to use a more readable name than Role/4 in your definitions you can define an alias like * - * $config['alias'] = array( - * 'Role/4' => 'Role/editor', - * ); + * ``` + * $config['alias'] = array( + * 'Role/4' => 'Role/editor', + * ); + * ``` * * In the roles configuration you can define roles on the lhs and inherited roles on the rhs: * - * $config['roles'] = array( - * 'Role/admin' => null, - * 'Role/accountant' => null, - * 'Role/editor' => null, - * 'Role/manager' => 'Role/editor, Role/accountant', - * 'User/jeff' => 'Role/manager', - * ); + * ``` + * $config['roles'] = array( + * 'Role/admin' => null, + * 'Role/accountant' => null, + * 'Role/editor' => null, + * 'Role/manager' => 'Role/editor, Role/accountant', + * 'User/jeff' => 'Role/manager', + * ); + * ``` * * In this example manager inherits all rules from editor and accountant. Role/admin doesn't inherit from any role. * Lets define some rules: * - * $config['rules'] = array( - * 'allow' => array( - * '*' => 'Role/admin', - * 'controllers/users/(dashboard|profile)' => 'Role/default', - * 'controllers/invoices/*' => 'Role/accountant', - * 'controllers/articles/*' => 'Role/editor', - * 'controllers/users/*' => 'Role/manager', - * 'controllers/invoices/delete' => 'Role/manager', - * ), - * 'deny' => array( - * 'controllers/invoices/delete' => 'Role/accountant, User/jeff', - * 'controllers/articles/(delete|publish)' => 'Role/editor', - * ), - * ); + * ``` + * $config['rules'] = array( + * 'allow' => array( + * '*' => 'Role/admin', + * 'controllers/users/(dashboard|profile)' => 'Role/default', + * 'controllers/invoices/*' => 'Role/accountant', + * 'controllers/articles/*' => 'Role/editor', + * 'controllers/users/*' => 'Role/manager', + * 'controllers/invoices/delete' => 'Role/manager', + * ), + * 'deny' => array( + * 'controllers/invoices/delete' => 'Role/accountant, User/jeff', + * 'controllers/articles/(delete|publish)' => 'Role/editor', + * ), + * ); + * ``` * * Ok, so as jeff inherits from Role/manager he's matched every rule that references User/jeff, Role/manager, - * Role/editor, Role/accountant and Role/default. However, for jeff, rules for User/jeff are more specific than + * Role/editor, and Role/accountant. However, for jeff, rules for User/jeff are more specific than * rules for Role/manager, rules for Role/manager are more specific than rules for Role/editor and so on. * This is important when allow and deny rules match for a role. E.g. Role/accountant is allowed * controllers/invoices/* but at the same time controllers/invoices/delete is denied. But there is a more diff --git a/web/api/app/Config/bootstrap.php.in b/web/api/app/Config/bootstrap.php.in index 4e2d99c63..a94b58fc1 100644 --- a/web/api/app/Config/bootstrap.php.in +++ b/web/api/app/Config/bootstrap.php.in @@ -8,18 +8,18 @@ * You should also use this file to include any files that provide global functions/constants * that your application uses. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 0.10.8.2117 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ // Setup a 'default' cache configuration for use in the application. @@ -120,29 +120,17 @@ Configure::write('ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@'); Configure::write('ZM_VERSION', '@VERSION@'); Configure::write('ZM_API_VERSION', '@API_VERSION@'); -# Process name, value pairs from the main config file first -$configvals = process_configfile(Configure::read('ZM_CONFIG')); +require_once("../../../includes/config.php"); +global $configvals; -# Search for user created config files. If one or more are found then -# update our config value array with those values -$configSubFolder = Configure::read('ZM_CONFIG_SUBDIR'); -if ( is_dir($configSubFolder) ) { - if ( is_readable($configSubFolder) ) { - foreach ( glob("$configSubFolder/*.conf") as $filename ) { - $configvals = array_replace($configvals, process_configfile($filename) ); - } - } else { - error_log( "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on $configSubFolder." ); - } -} - -# Now that our array our finalized, define each key => value -# pair in the array as a constant +# Now that our array our finalized, and the config has been defined. +# Add them to the cakephp Config foreach( $configvals as $key => $value) { - define( $key, $value ); - Configure::write( $key, $value ); + Configure::write($key, $value); } - +if ( 0 ) { + // No longer needed, but I want to keep the code for reference + // // For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID if ( ! defined('ZM_SERVER_ID') ) { App::uses('ClassRegistry', 'Utility'); @@ -163,26 +151,4 @@ if ( ! defined('ZM_SERVER_ID') ) { } } } - -function process_configfile($configFile) { - if ( is_readable( $configFile ) ) { - $configvals = array(); - - $cfg = fopen( $configFile, 'r') or die('Could not open config file.'); - while ( !feof($cfg) ) { - $str = fgets( $cfg, 256 ); - if ( preg_match( '/^\s*$/', $str )) - continue; - elseif ( preg_match( '/^\s*#/', $str )) - continue; - elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*(.*?)\s*$/', $str, $matches )) - $configvals[$matches[1]] = $matches[2]; - } - fclose( $cfg ); - return( $configvals ); - } else { - error_log( "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $configFile." ); - return( false ); - } } - diff --git a/web/api/app/Config/core.php.default b/web/api/app/Config/core.php.default index cffb43c77..39a51690c 100644 --- a/web/api/app/Config/core.php.default +++ b/web/api/app/Config/core.php.default @@ -31,7 +31,7 @@ * In production mode, flash messages redirect after a time interval. * In development mode, you need to click the flash message to continue. */ - Configure::write('debug', 0); + Configure::write('debug', 2); /** * Configure the Error handler used to handle errors for your application. By default diff --git a/web/api/app/Config/database.php.default b/web/api/app/Config/database.php.default index c06953ec7..a62f55321 100644 --- a/web/api/app/Config/database.php.default +++ b/web/api/app/Config/database.php.default @@ -2,18 +2,18 @@ /** * * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 0.2.9 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/app/Config/email.php.default b/web/api/app/Config/email.php.default index cee93c305..6dcfdd8f9 100644 --- a/web/api/app/Config/email.php.default +++ b/web/api/app/Config/email.php.default @@ -2,18 +2,18 @@ /** * * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 2.0.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/app/Config/routes.php b/web/api/app/Config/routes.php index 0f9343644..a684f241e 100644 --- a/web/api/app/Config/routes.php +++ b/web/api/app/Config/routes.php @@ -6,18 +6,18 @@ * Routes are very important mechanism that allows you to freely connect * different URLs to chosen controllers and their actions (functions). * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 0.2.9 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** @@ -35,7 +35,8 @@ /* Add new API to retrieve camera controls - for PTZ */ /* refer to https://github.com/ZoneMinder/ZoneMinder/issues/799#issuecomment-105233112 */ - Router::mapResources('controls'); + Router::mapResources('controls'); + Router::mapResources('groups'); Router::parseExtensions(); /** diff --git a/web/api/app/Console/Command/AppShell.php b/web/api/app/Console/Command/AppShell.php index 4ea0f2dd8..030ae49fd 100644 --- a/web/api/app/Console/Command/AppShell.php +++ b/web/api/app/Console/Command/AppShell.php @@ -2,17 +2,17 @@ /** * AppShell file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('Shell', 'Console'); diff --git a/web/api/app/Console/cake b/web/api/app/Console/cake index 67454513d..fee8e35a3 100755 --- a/web/api/app/Console/cake +++ b/web/api/app/Console/cake @@ -3,18 +3,18 @@ # # Bake is a shell script for running CakePHP bake script # -# CakePHP(tm) : Rapid Development Framework (http://cakephp.org) -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. # -# @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) -# @link http://cakephp.org CakePHP(tm) Project +# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# @link https://cakephp.org CakePHP(tm) Project # @package app.Console # @since CakePHP(tm) v 1.2.0.5012 -# @license http://www.opensource.org/licenses/mit-license.php MIT License +# @license https://opensource.org/licenses/mit-license.php MIT License # ################################################################################ diff --git a/web/api/app/Console/cake.bat b/web/api/app/Console/cake.bat index c33bf22f8..fe1b6d4a5 100644 --- a/web/api/app/Console/cake.bat +++ b/web/api/app/Console/cake.bat @@ -2,17 +2,17 @@ :: :: Bake is a shell script for running CakePHP bake script :: -:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org) -:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) :: :: Licensed under The MIT License :: Redistributions of files must retain the above copyright notice. :: -:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) -:: @link http://cakephp.org CakePHP(tm) Project +:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: @link https://cakephp.org CakePHP(tm) Project :: @package app.Console :: @since CakePHP(tm) v 2.0 -:: @license http://www.opensource.org/licenses/mit-license.php MIT License +:: @license https://opensource.org/licenses/mit-license.php MIT License :: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: diff --git a/web/api/app/Console/cake.php b/web/api/app/Console/cake.php index e6f748e1b..d4a6aeaf0 100644 --- a/web/api/app/Console/cake.php +++ b/web/api/app/Console/cake.php @@ -3,34 +3,45 @@ /** * Command-line code generation utility to automate programmer chores. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Console * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ -$ds = DIRECTORY_SEPARATOR; -$dispatcher = 'Cake' . $ds . 'Console' . $ds . 'ShellDispatcher.php'; +if (!defined('DS')) { + define('DS', DIRECTORY_SEPARATOR); +} + +$dispatcher = 'Cake' . DS . 'Console' . DS . 'ShellDispatcher.php'; if (function_exists('ini_set')) { $root = dirname(dirname(dirname(__FILE__))); + $appDir = basename(dirname(dirname(__FILE__))); + $install = $root . DS . 'lib'; + $composerInstall = $root . DS . $appDir . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib'; - // the following line differs from its sibling + // the following lines differ from its sibling // /lib/Cake/Console/Templates/skel/Console/cake.php - ini_set('include_path', $root . $ds . 'lib' . PATH_SEPARATOR . ini_get('include_path')); + if (file_exists($composerInstall . DS . $dispatcher)) { + $install = $composerInstall; + } + + ini_set('include_path', $install . PATH_SEPARATOR . ini_get('include_path')); + unset($root, $appDir, $install, $composerInstall); } if (!include $dispatcher) { trigger_error('Could not locate CakePHP core files.', E_USER_ERROR); } -unset($paths, $path, $dispatcher, $root, $ds); +unset($dispatcher); return ShellDispatcher::run($argv); diff --git a/web/api/app/Controller/AppController.php b/web/api/app/Controller/AppController.php index e9c84ab4f..7be1cd72a 100644 --- a/web/api/app/Controller/AppController.php +++ b/web/api/app/Controller/AppController.php @@ -46,7 +46,10 @@ class AppController extends Controller { 'category' => 'Crud.Category' ], 'listeners' => ['Api', 'ApiTransformation'] - ] + #], + #'DebugKit.Toolbar' => [ + # 'bootstrap' => true, 'routes' => true + ] ]; // Global beforeFilter function @@ -72,7 +75,9 @@ class AppController extends Controller { $config = $this->Config->find('first', $options); $zmOptAuth = $config['Config']['Value']; - if ( $zmOptAuth=='1' ) { + if ( $zmOptAuth == '1' ) { + require_once "../../../includes/auth.php"; + $this->loadModel('User'); if ( isset($_REQUEST['user']) and isset($_REQUEST['pass']) ) { $user = $this->User->find('first', array ('conditions' => array ( @@ -89,34 +94,23 @@ class AppController extends Controller { } if ( isset($_REQUEST['auth']) ) { - require_once "../../../includes/functions.php"; - - // Define some defines required by getAuthUser in functions.php - $defines = array('ZM_AUTH_HASH_IPS', 'ZM_AUTH_HASH_SECRET', 'ZM_AUTH_RELAY', 'ZM_OPT_USE_AUTH'); - $configQuery = array( - 'conditions' => array('OR' => array('Name' => $defines)), - 'fields' => array('Name', 'Value') - ); - $config = $this->Config->find('list', $configQuery); - - foreach ($defines as $define) { - define($define, $config[$define]); - } $user = getAuthUser($_REQUEST['auth']); if ( ! $user ) { throw new UnauthorizedException(__('User not found')); return; } else { - $this->Session->Write( 'user.Username', $user['Username'] ); - $this->Session->Write( 'user.Enabled', $user['Enabled'] ); + if ( ! $this->Session->Write('user.Username', $user['Username']) ) + $this->log("Error writing session var user.Username"); + if ( ! $this->Session->Write('user.Enabled', $user['Enabled']) ) + $this->log("Error writing session var user.Enabled"); } - } + } # end if REQUEST['auth'] - if( ! $this->Session->Read('user.Username') ) { + if ( ! $this->Session->read('user.Username') ) { throw new UnauthorizedException(__('Not Authenticated')); return; - } else if ( ! $this->Session->Read('user.Enabled') ) { + } else if ( ! $this->Session->read('user.Enabled') ) { throw new UnauthorizedException(__('User is not enabled')); return; } @@ -129,9 +123,8 @@ class AppController extends Controller { $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 - { + } 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'); diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index f43672737..fd0c4ef98 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -125,6 +125,9 @@ class EventsController extends AppController { $event['Event']['Next'] = $event_neighbors['next']['Event']['Id']; $event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id']; + $event['Event']['fileExists'] = $this->Event->fileExists($event['Event']); + $event['Event']['fileSize'] = $this->Event->fileSize($event['Event']); + # 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']) diff --git a/web/api/app/Controller/GroupsController.php b/web/api/app/Controller/GroupsController.php index 525d500bf..7859f492e 100644 --- a/web/api/app/Controller/GroupsController.php +++ b/web/api/app/Controller/GroupsController.php @@ -4,15 +4,24 @@ App::uses('AppController', 'Controller'); * Groups Controller * * @property Group $Group + * @property PaginatorComponent $Paginator */ class GroupsController extends AppController { - /** * Components * * @var array */ - public $components = array('RequestHandler'); + public $components = array('Paginator', 'RequestHandler'); + + public function beforeFilter() { + parent::beforeFilter(); + $canView = $this->Session->Read('groupsPermission'); + if ( $canView == 'None' ) { + throw new UnauthorizedException(__('Insufficient Privileges')); + return; + } + } /** * index method @@ -55,6 +64,12 @@ class GroupsController extends AppController { */ public function add() { if ($this->request->is('post')) { + + if ($this->Session->Read('groupPermission') != 'Edit') { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + $this->Group->create(); if ($this->Group->save($this->request->data)) { return $this->flash(__('The group has been saved.'), array('action' => 'index')); @@ -75,16 +90,26 @@ class GroupsController extends AppController { if (!$this->Group->exists($id)) { throw new NotFoundException(__('Invalid group')); } - if ($this->request->is(array('post', 'put'))) { + if ( $this->request->is(array('post', 'put'))) { + if ( $this->Session->Read('groupPermission') != 'Edit' ) { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } if ($this->Group->save($this->request->data)) { return $this->flash(__('The group has been saved.'), array('action' => 'index')); + } else { + $message = 'Error'; } } else { $options = array('conditions' => array('Group.' . $this->Group->primaryKey => $id)); $this->request->data = $this->Group->find('first', $options); } $monitors = $this->Group->Monitor->find('list'); - $this->set(compact('monitors')); + $this->set(array( + 'message' => $message, + 'monitors'=> $monitors, + '_serialize' => array('message',) + )); } /** @@ -100,9 +125,15 @@ class GroupsController extends AppController { throw new NotFoundException(__('Invalid group')); } $this->request->allowMethod('post', 'delete'); + if ( $this->Session->Read('groupPermission') != 'Edit' ) { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + if ($this->Group->delete()) { return $this->flash(__('The group has been deleted.'), array('action' => 'index')); } else { return $this->flash(__('The group could not be deleted. Please, try again.'), array('action' => 'index')); } - }} + } // end function delete +} // end class GroupController diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index 4fdb48cba..0313bd97a 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -6,15 +6,14 @@ class HostController extends AppController { public $components = array('RequestHandler'); public function daemonCheck($daemon=false, $args=false) { - $string = Configure::read('ZM_PATH_BIN')."/zmdc.pl check"; - if ( $daemon ) - { + $string = Configure::read('ZM_PATH_BIN').'/zmdc.pl check'; + if ( $daemon ) { $string .= " $daemon"; if ( $args ) $string .= " $args"; } - $result = exec( $string ); - $result = preg_match( '/running/', $result ); + $result = exec($string); + $result = preg_match('/running/', $result); $this->set(array( 'result' => $result, @@ -31,6 +30,38 @@ class HostController extends AppController { )); } + function getCredentials() { + // ignore debug warnings from other functions + $this->view='Json'; + $credentials = ""; + $appendPassword = 0; + + $this->loadModel('Config'); + $isZmAuth = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')))['Config']['Value']; + + if ($isZmAuth) { + $zmAuthRelay = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY')))['Config']['Value']; + if ($zmAuthRelay == 'hashed') { + $zmAuthHashIps= $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_IPS')))['Config']['Value']; + $credentials = 'auth='.generateAuthHash($zmAuthHashIps); + } + elseif ($zmAuthRelay == 'plain') { + // user will need to append the store password here + $credentials = "user=".$this->Session->read('user.Username')."&pass="; + $appendPassword = 1; + } + elseif ($zmAuthRelay == 'none') { + $credentials = "user=".$this->Session->read('user.Username'); + } + } + $this->set(array( + 'credentials'=> $credentials, + 'append_password'=>$appendPassword, + '_serialize' => array('credentials', 'append_password') + ) ); + } + + // If $mid is set, only return disk usage for that monitor // Else, return an array of total disk usage, and per-monitor // usage. @@ -99,15 +130,14 @@ class HostController extends AppController { )); } - function getTimeZone() - { - //http://php.net/manual/en/function.date-default-timezone-get.php - $tz = date_default_timezone_get(); - $this->set(array( - 'tz' => $tz, - '_serialize' => array('tz') - )); - } + function getTimeZone() { + //http://php.net/manual/en/function.date-default-timezone-get.php + $tz = date_default_timezone_get(); + $this->set(array( + 'tz' => $tz, + '_serialize' => array('tz') + )); + } function getVersion() { //throw new UnauthorizedException(__('API Disabled')); diff --git a/web/api/app/Controller/PagesController.php b/web/api/app/Controller/PagesController.php index 5073f2e1a..bf1dbefa6 100644 --- a/web/api/app/Controller/PagesController.php +++ b/web/api/app/Controller/PagesController.php @@ -4,18 +4,18 @@ * * This file will render views from views/pages/ * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Controller * @since CakePHP(tm) v 0.2.9 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppController', 'Controller'); @@ -26,7 +26,7 @@ App::uses('AppController', 'Controller'); * Override this controller by placing a copy in controllers directory of an application * * @package app.Controller - * @link http://book.cakephp.org/2.0/en/controllers/pages-controller.html + * @link https://book.cakephp.org/2.0/en/controllers/pages-controller.html */ class PagesController extends AppController { @@ -40,10 +40,10 @@ class PagesController extends AppController { /** * Displays a view * - * @param mixed What page to display - * @return void + * @return CakeResponse|null + * @throws ForbiddenException When a directory traversal attempt. * @throws NotFoundException When the view file could not be found - * or MissingViewException in debug mode. + * or MissingViewException in debug mode. */ public function display() { $path = func_get_args(); @@ -52,6 +52,9 @@ class PagesController extends AppController { if (!$count) { return $this->redirect('/'); } + if (in_array('..', $path, true) || in_array('.', $path, true)) { + throw new ForbiddenException(); + } $page = $subpage = $title_for_layout = null; if (!empty($path[0])) { diff --git a/web/api/app/Model/Event.php b/web/api/app/Model/Event.php index dd5cc0531..a59393d9a 100644 --- a/web/api/app/Model/Event.php +++ b/web/api/app/Model/Event.php @@ -44,7 +44,15 @@ class Event extends AppModel { 'conditions' => '', 'fields' => '', 'order' => '' - ) + ), + 'Storage' => array( + 'className' => 'Storage', + 'joinTable' => 'Storage', + 'foreignKey' => 'StorageId', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ) ); /** @@ -92,4 +100,40 @@ class Event extends AppModel { ), ); + public function Relative_Path($event) { + $event_path = ''; + + if ( $event['Scheme'] == 'Deep' ) { + $event_path = $event['MonitorId'] .'/'.strftime('%y/%m/%d/%H/%M/%S', strtotime($event['StartTime'])); + } else if ( $event['Scheme'] == 'Medium' ) { + $event_path = $event['MonitorId'] .'/'.strftime('%Y-%m-%d', strtotime($event['StartTime'])) . '/'.$event['Id']; + } else { + $event_path = $event['MonitorId'] .'/'.$event['Id']; + } + + return $event_path; + } // end function Relative_Path() + + + public function fileExists($event) { + //$data = $this->findById($id); + //return $data['Event']['dataset_filename']; + $storage = $this->Storage->findById($event['StorageId']); + + if ( $event['DefaultVideo'] ) { + if ( file_exists($storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo']) ) { + return 1; + } else { + Logger::Debug("FIle does not exist at " . $storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo'] ); + } + } else { +Logger::Debug("No DefaultVideo in Event" . $this->Event); + return 0; + } + } // end function fileExists($event) + + public function fileSize($event) { + $storage = $this->Storage->findById($event['StorageId']); + return filesize($storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo']); + } } diff --git a/web/api/app/Model/Group.php b/web/api/app/Model/Group.php index 595bc3b3a..e27460424 100644 --- a/web/api/app/Model/Group.php +++ b/web/api/app/Model/Group.php @@ -4,6 +4,7 @@ App::uses('AppModel', 'Model'); * Group Model * * @property Event $Event + * @property Zone $Zone */ class Group extends AppModel { @@ -21,6 +22,15 @@ class Group extends AppModel { */ public $primaryKey = 'Id'; +/** + * Display field + * + * @var string + */ + public $displayField = 'Name'; + + public $recursive = -1; + /** * Validation rules * @@ -29,7 +39,10 @@ class Group extends AppModel { public $validate = array( 'Name' => array( 'notEmpty' => array( - 'rule' => array('notEmpty'), + 'rule' => array('notEmpty'))), + 'Id' => array( + 'numeric' => array( + 'rule' => array('numeric'), //'message' => 'Your custom message here', //'allowEmpty' => false, //'required' => false, @@ -39,7 +52,6 @@ class Group extends AppModel { ), ); - public $recursive = -1; //The Associations below have been created with all possible keys, those that are not needed can be removed /** diff --git a/web/api/app/Model/Host.php b/web/api/app/Model/Host.php index 5c24c7531..481849db9 100644 --- a/web/api/app/Model/Host.php +++ b/web/api/app/Model/Host.php @@ -1,4 +1,3 @@ - array( + 'numeric' => array( + 'rule' => array('numeric'), + //'message' => 'Your custom message here', + //'allowEmpty' => false, + //'required' => false, + //'last' => false, // Stop validation after this rule + //'on' => 'create', // Limit validation to 'create' or 'update' operations + ), + ), + ); + + //The Associations below have been created with all possible keys, those that are not needed can be removed + +/** + * hasMany associations + * + * @var array + */ + public $belongsTo = array( + 'Server' => array( + 'className' => 'Server', + 'foreignKey' => 'ServerId', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + ) + ); +} diff --git a/web/api/app/View/Groups/json/edit.ctp b/web/api/app/View/Groups/json/edit.ctp new file mode 100644 index 000000000..ce19d17e8 --- /dev/null +++ b/web/api/app/View/Groups/json/edit.ctp @@ -0,0 +1,2 @@ +echo json_encode($message); +echo json_encode($group); diff --git a/web/api/app/View/Groups/json/index.ctp b/web/api/app/View/Groups/json/index.ctp new file mode 100644 index 000000000..330bf9262 --- /dev/null +++ b/web/api/app/View/Groups/json/index.ctp @@ -0,0 +1 @@ +echo json_encode($groups); diff --git a/web/api/app/View/Groups/json/view.ctp b/web/api/app/View/Groups/json/view.ctp new file mode 100644 index 000000000..04dc11392 --- /dev/null +++ b/web/api/app/View/Groups/json/view.ctp @@ -0,0 +1 @@ +echo json_encode($group); diff --git a/web/api/app/View/Groups/xml/edit.ctp b/web/api/app/View/Groups/xml/edit.ctp new file mode 100644 index 000000000..09fb8979a --- /dev/null +++ b/web/api/app/View/Groups/xml/edit.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $message)); +echo $xml->asXML(); diff --git a/web/api/app/View/Groups/xml/index.ctp b/web/api/app/View/Groups/xml/index.ctp new file mode 100644 index 000000000..8f45dfd14 --- /dev/null +++ b/web/api/app/View/Groups/xml/index.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $groups)); +echo $xml->asXML(); diff --git a/web/api/app/View/Groups/xml/view.ctp b/web/api/app/View/Groups/xml/view.ctp new file mode 100644 index 000000000..b54cad5ca --- /dev/null +++ b/web/api/app/View/Groups/xml/view.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $group)); +echo $xml->asXML(); diff --git a/web/api/app/View/Layouts/js/default.ctp b/web/api/app/View/Layouts/js/default.ctp index 7239b5dae..f694538e4 100644 --- a/web/api/app/View/Layouts/js/default.ctp +++ b/web/api/app/View/Layouts/js/default.ctp @@ -1,2 +1,2 @@ - +fetch('script'); ?> diff --git a/web/api/app/webroot/.htaccess b/web/api/app/webroot/.htaccess deleted file mode 100644 index f08afa8b2..000000000 --- a/web/api/app/webroot/.htaccess +++ /dev/null @@ -1,7 +0,0 @@ - - RewriteEngine On - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [L] - RewriteBase /zm/api - diff --git a/web/api/lib/Cake/Cache/Cache.php b/web/api/lib/Cake/Cache/Cache.php index a7a01d0a1..3db66c4f9 100644 --- a/web/api/lib/Cake/Cache/Cache.php +++ b/web/api/lib/Cake/Cache/Cache.php @@ -1,17 +1,17 @@ _groupPrefix)) { - $prefix = vsprintf($this->_groupPrefix, $this->groups()); + $prefix = md5(implode('_', $this->groups())); } $key = preg_replace('/[\s]+/', '_', strtolower(trim(str_replace(array(DS, '/', '.'), '_', strval($key))))); diff --git a/web/api/lib/Cake/Cache/Engine/ApcEngine.php b/web/api/lib/Cake/Cache/Engine/ApcEngine.php index da31651e3..329e87196 100644 --- a/web/api/lib/Cake/Cache/Engine/ApcEngine.php +++ b/web/api/lib/Cake/Cache/Engine/ApcEngine.php @@ -2,18 +2,18 @@ /** * APC storage engine for cache. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Cache.Engine * @since CakePHP(tm) v 1.2.0.4933 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** @@ -31,6 +31,13 @@ class ApcEngine extends CacheEngine { */ protected $_compiledGroupNames = array(); +/** + * APC or APCu extension + * + * @var string + */ + protected $_apcExtension = 'apc'; + /** * Initialize the Cache Engine * @@ -47,6 +54,10 @@ class ApcEngine extends CacheEngine { } $settings += array('engine' => 'Apc'); parent::init($settings); + if (function_exists('apcu_dec')) { + $this->_apcExtension = 'apcu'; + return true; + } return function_exists('apc_dec'); } @@ -63,8 +74,9 @@ class ApcEngine extends CacheEngine { if ($duration) { $expires = time() + $duration; } - apc_store($key . '_expires', $expires, $duration); - return apc_store($key, $value, $duration); + $func = $this->_apcExtension . '_store'; + $func($key . '_expires', $expires, $duration); + return $func($key, $value, $duration); } /** @@ -75,11 +87,12 @@ class ApcEngine extends CacheEngine { */ public function read($key) { $time = time(); - $cachetime = (int)apc_fetch($key . '_expires'); + $func = $this->_apcExtension . '_fetch'; + $cachetime = (int)$func($key . '_expires'); if ($cachetime !== 0 && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) { return false; } - return apc_fetch($key); + return $func($key); } /** @@ -90,7 +103,8 @@ class ApcEngine extends CacheEngine { * @return New incremented value, false otherwise */ public function increment($key, $offset = 1) { - return apc_inc($key, $offset); + $func = $this->_apcExtension . '_inc'; + return $func($key, $offset); } /** @@ -101,7 +115,8 @@ class ApcEngine extends CacheEngine { * @return New decremented value, false otherwise */ public function decrement($key, $offset = 1) { - return apc_dec($key, $offset); + $func = $this->_apcExtension . '_dec'; + return $func($key, $offset); } /** @@ -111,7 +126,8 @@ class ApcEngine extends CacheEngine { * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed */ public function delete($key) { - return apc_delete($key); + $func = $this->_apcExtension . '_delete'; + return $func($key); } /** @@ -125,19 +141,20 @@ class ApcEngine extends CacheEngine { if ($check) { return true; } + $func = $this->_apcExtension . '_delete'; if (class_exists('APCIterator', false)) { $iterator = new APCIterator( 'user', '/^' . preg_quote($this->settings['prefix'], '/') . '/', APC_ITER_NONE ); - apc_delete($iterator); + $func($iterator); return true; } - $cache = apc_cache_info('user'); + $cache = $this->_apcExtension === 'apc' ? apc_cache_info('user') : apcu_cache_info(); foreach ($cache['cache_list'] as $key) { if (strpos($key['info'], $this->settings['prefix']) === 0) { - apc_delete($key['info']); + $func($key['info']); } } return true; @@ -157,11 +174,13 @@ class ApcEngine extends CacheEngine { } } - $groups = apc_fetch($this->_compiledGroupNames); + $fetchFunc = $this->_apcExtension . '_fetch'; + $storeFunc = $this->_apcExtension . '_store'; + $groups = $fetchFunc($this->_compiledGroupNames); if (count($groups) !== count($this->settings['groups'])) { foreach ($this->_compiledGroupNames as $group) { if (!isset($groups[$group])) { - apc_store($group, 1); + $storeFunc($group, 1); $groups[$group] = 1; } } @@ -184,7 +203,8 @@ class ApcEngine extends CacheEngine { * @return bool success */ public function clearGroup($group) { - apc_inc($this->settings['prefix'] . $group, 1, $success); + $func = $this->_apcExtension . '_inc'; + $func($this->settings['prefix'] . $group, 1, $success); return $success; } @@ -203,7 +223,8 @@ class ApcEngine extends CacheEngine { if ($duration) { $expires = time() + $duration; } - apc_add($key . '_expires', $expires, $duration); - return apc_add($key, $value, $duration); + $func = $this->_apcExtension . '_add'; + $func($key . '_expires', $expires, $duration); + return $func($key, $value, $duration); } } diff --git a/web/api/lib/Cake/Cache/Engine/FileEngine.php b/web/api/lib/Cake/Cache/Engine/FileEngine.php index d650e60ee..9b8eae0a7 100644 --- a/web/api/lib/Cake/Cache/Engine/FileEngine.php +++ b/web/api/lib/Cake/Cache/Engine/FileEngine.php @@ -6,17 +6,17 @@ * * You can configure a FileEngine cache, using Cache::config() * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2.0.4933 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** @@ -132,7 +132,7 @@ class FileEngine extends CacheEngine { } $expires = time() + $duration; - $contents = $expires . $lineBreak . $data . $lineBreak; + $contents = implode(array($expires, $lineBreak, $data, $lineBreak)); if ($this->settings['lock']) { $this->_File->flock(LOCK_EX); @@ -267,6 +267,10 @@ class FileEngine extends CacheEngine { } $dir = dir($path); + if ($dir === false) { + return; + } + while (($entry = $dir->read()) !== false) { if (substr($entry, 0, $prefixLength) !== $this->settings['prefix']) { continue; diff --git a/web/api/lib/Cake/Cache/Engine/MemcacheEngine.php b/web/api/lib/Cake/Cache/Engine/MemcacheEngine.php index eba2ec451..d70c1c56d 100644 --- a/web/api/lib/Cake/Cache/Engine/MemcacheEngine.php +++ b/web/api/lib/Cake/Cache/Engine/MemcacheEngine.php @@ -2,18 +2,18 @@ /** * Memcache storage engine for cache * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Cache.Engine * @since CakePHP(tm) v 1.2.0.4933 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Cache/Engine/MemcachedEngine.php b/web/api/lib/Cake/Cache/Engine/MemcachedEngine.php index cc101a2bf..655eb5d1c 100644 --- a/web/api/lib/Cake/Cache/Engine/MemcachedEngine.php +++ b/web/api/lib/Cake/Cache/Engine/MemcachedEngine.php @@ -1,16 +1,16 @@ _Redis->get($key); - if (ctype_digit($value)) { - $value = (int)$value; + if (preg_match('/^[-]?\d+$/', $value)) { + return (int)$value; } if ($value !== false && is_string($value)) { - $value = unserialize($value); + return unserialize($value); } return $value; } diff --git a/web/api/lib/Cake/Cache/Engine/WincacheEngine.php b/web/api/lib/Cake/Cache/Engine/WincacheEngine.php index e5c9d7bd7..dc8348171 100644 --- a/web/api/lib/Cake/Cache/Engine/WincacheEngine.php +++ b/web/api/lib/Cake/Cache/Engine/WincacheEngine.php @@ -4,18 +4,18 @@ * * Supports wincache 1.1.0 and higher. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Cache.Engine * @since CakePHP(tm) v 1.2.0.4933 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Cache/Engine/XcacheEngine.php b/web/api/lib/Cake/Cache/Engine/XcacheEngine.php index c46a7b9c5..2ce3324f1 100644 --- a/web/api/lib/Cake/Cache/Engine/XcacheEngine.php +++ b/web/api/lib/Cake/Cache/Engine/XcacheEngine.php @@ -2,18 +2,18 @@ /** * Xcache storage engine for cache. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Cache.Engine * @since CakePHP(tm) v 1.2.0.4947 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Config/cacert.pem b/web/api/lib/Cake/Config/cacert.pem index 4ef2da5c9..b4109e40a 100644 --- a/web/api/lib/Cake/Config/cacert.pem +++ b/web/api/lib/Cake/Config/cacert.pem @@ -1,76 +1,25 @@ ## -## ca-bundle.crt -- Bundle of CA Root Certificates +## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Thu Oct 18 19:05:59 2012 +## Certificate data from Mozilla as of: Wed Jan 20 04:12:04 2016 +## +## The Equifax Secure CA was readded as there were replies to the issue +## that updated this certificate bundle. ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates -## file (certdata.txt). This file can be found in the mozilla source tree: -## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## file (certdata.txt). This file can be found in the mozilla source tree: +## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## - -# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.86 $ $Date: 2012/10/18 16:26:52 $ - -GTE CyberTrust Global Root -========================== ------BEGIN CERTIFICATE----- -MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg -Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG -A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz -MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL -Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 -IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u -sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql -HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID -AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW -M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF -NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ ------END CERTIFICATE----- - -Thawte Server CA -================ ------BEGIN CERTIFICATE----- -MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT -DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs -dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE -AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j -b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV -BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u -c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG -A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 -ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl -/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 -1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR -MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J -GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ -GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= ------END CERTIFICATE----- - -Thawte Premium Server CA -======================== ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT -DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs -dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE -AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl -ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT -AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU -VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 -aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ -cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 -aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh -Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ -qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm -SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf -8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t -UCemDaYj+bvLpgcUQg== ------END CERTIFICATE----- - +## Conversion done with mk-ca-bundle.pl version 1.25. +## SHA1: 0ab47e2f41518f8d223eab517cb799e5b071231e +## +# Equifax Secure CA ================= -----BEGIN CERTIFICATE----- @@ -91,118 +40,6 @@ BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 70+sB3c4 -----END CERTIFICATE----- -Digital Signature Trust Co. Global CA 1 -======================================= ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE -ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy -MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs -IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE -NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i -o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo -BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 -dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw -IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY -MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM -BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB -ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq -kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4 -RbyhkwS7hp86W0N6w4pl ------END CERTIFICATE----- - -Digital Signature Trust Co. Global CA 3 -======================================= ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE -ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy -MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs -IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD -VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS -xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo -BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 -dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw -IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY -MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM -BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB -AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi -up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1 -mPnHfxsb1gYgAlihw6ID ------END CERTIFICATE----- - -Verisign Class 3 Public Primary Certification Authority -======================================================= ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx -FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow -XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz -IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 -f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol -hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA -TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah -WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf -Tqj/ZA1k ------END CERTIFICATE----- - -Verisign Class 1 Public Primary Certification Authority - G2 -============================================================ ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgd -k4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIq -WpDBucSmFc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQAB -MA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9ZrbWB85a7FkCMM -XErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2uluIncrKTdcu1OofdPvAbT6shkdHvC -lUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68DzFc6PLZ ------END CERTIFICATE----- - -Verisign Class 2 Public Primary Certification Authority - G2 -============================================================ ------BEGIN CERTIFICATE----- -MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h -cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp -Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 -c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h -cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp -Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 -c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjx -nNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRC -wiNPStjwDqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEA -ATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/7aHmZuovCfTK -1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAXrXfMSTWqz9iP0b63GJZHc2pUIjRk -LbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnInjBJ7xUS0rg== ------END CERTIFICATE----- - -Verisign Class 3 Public Primary Certification Authority - G2 -============================================================ ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO -FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 -lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB -MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT -1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD -Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 ------END CERTIFICATE----- GlobalSign Root CA ================== @@ -247,111 +84,6 @@ BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- -ValiCert Class 1 VA -=================== ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp -b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh -bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy -MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 -d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg -UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 -LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi -GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm -DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG -lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX -icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP -Orf1LXLI ------END CERTIFICATE----- - -ValiCert Class 2 VA -=================== ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp -b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh -bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw -MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 -d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg -UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 -LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC -CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf -ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ -SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV -UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 -W9ViH0Pd ------END CERTIFICATE----- - -RSA Root Certificate 1 -====================== ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp -b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh -bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw -MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 -d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg -UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 -LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td -3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H -BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs -3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF -V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r -on+jjBXu ------END CERTIFICATE----- - -Verisign Class 1 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/E -bRrsC+MO8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJ -rKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7PoBMAGrgnoeS+ -Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP26KbqxzcSXKMpHgLZ2x87tNcPVkeB -FQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA -q2aN17O6x5q25lXQBfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N -y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 -ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrspSCAaWihT37h -a88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/Pc -D98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== ------END CERTIFICATE----- - -Verisign Class 2 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29y -azE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ug -b25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 -c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y -aXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6 -tW8UvxDOJxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7 -C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQHgiBVrKtaaNS -0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjNqWm6o+sdDZykIKbBoMXRRkwXbdKs -Zj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0 -JhU8wI1NQ0kdvekhktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf -0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU -sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RIsH/7NiXaldDx -JBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//j -GHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q ------END CERTIFICATE----- - Verisign Class 3 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- @@ -376,65 +108,14 @@ xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- -Verisign Class 4 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS -tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM -8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW -Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX -Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA -j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt -mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm -fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd -RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG -UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== ------END CERTIFICATE----- - -Entrust.net Secure Server CA -============================ ------BEGIN CERTIFICATE----- -MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV -BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg -cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl -ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG -A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi -eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p -dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ -aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 -gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw -ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw -CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l -dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF -bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu -dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw -NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow -HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA -BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN -Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 -n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= ------END CERTIFICATE----- - Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- -MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx -NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A @@ -442,14 +123,13 @@ MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi -VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC -AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER -gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B -AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo -oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS -o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z -2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX -OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= -----END CERTIFICATE----- Baltimore CyberTrust Root @@ -473,60 +153,6 @@ Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -Equifax Secure Global eBusiness CA -================================== ------BEGIN CERTIFICATE----- -MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp -bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx -HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds -b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV -PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN -qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn -hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j -BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs -MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN -I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY -NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV ------END CERTIFICATE----- - -Equifax Secure eBusiness CA 1 -============================= ------BEGIN CERTIFICATE----- -MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB -LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE -ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz -IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ -1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a -IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk -MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW -Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF -AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 -lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ -KpYrtWKmpj29f5JZzVoqgrI3eQ== ------END CERTIFICATE----- - -Equifax Secure eBusiness CA 2 -============================= ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE -ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y -MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT -DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB -nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn -2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5 -BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG -A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx -JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG -A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e -uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB -Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1 -jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia -78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm -V+GRMOrN ------END CERTIFICATE----- - AddTrust Low-Value Services Root ================================ -----BEGIN CERTIFICATE----- @@ -772,84 +398,6 @@ gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- -UTN-USER First-Network Applications -=================================== ------BEGIN CERTIFICATE----- -MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzAp -BgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5 -WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5T -YWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBB -cHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFug -mliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4Cj -DUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXu -Ozr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwi -P8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIE -j3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8w -HQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9j -cmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G -CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y -IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTK -RIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4Qp -xFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAq -DbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE ------END CERTIFICATE----- - -America Online Root Certification Authority 1 -============================================= ------BEGIN CERTIFICATE----- -MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG -A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg -T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG -v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z -DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh -sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP -8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z -o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf -GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF -VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft -3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g -Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds -sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 ------END CERTIFICATE----- - -America Online Root Certification Authority 2 -============================================= ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG -A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg -T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en -fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 -f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO -qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN -RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 -gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn -6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid -FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 -Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj -B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op -aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY -T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p -+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg -JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy -zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO -ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh -1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf -GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff -Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP -cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= ------END CERTIFICATE----- - Visa eCommerce Root =================== -----BEGIN CERTIFICATE----- @@ -1084,26 +632,6 @@ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ FL39vmwLAw== -----END CERTIFICATE----- -Sonera Class 1 Root CA -====================== ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG -U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQw -NjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh -IENsYXNzMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H88 -7dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9 -EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl -0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF645 -2F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW1ebZrgUa -HXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZT -iFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE9 -28Jj2VuXZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxV -yhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2nBBhjrZTOqMR -vq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2UvkVrCqIexVmiUefkl98HVrhq4uz2P -qYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9Z -IRlXvVWa ------END CERTIFICATE----- - Sonera Class 2 Root CA ====================== -----BEGIN CERTIFICATE----- @@ -1146,109 +674,6 @@ nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- -TDC Internet Root CA -==================== ------BEGIN CERTIFICATE----- -MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE -ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx -NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu -ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j -xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL -znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc -5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 -otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI -AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM -VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM -MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC -AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe -UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G -CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m -gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ -2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb -O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU -Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l ------END CERTIFICATE----- - -TDC OCES Root CA -================ ------BEGIN CERTIFICATE----- -MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJESzEMMAoGA1UE -ChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5 -MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuH -nEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0 -zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvV -iGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBde -dObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO -3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB -5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5k -ay9yZXBvc2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBm -cmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLiBDZXJ0aWZp -Y2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x -LjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEM -MAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm -aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy -MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647 -+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6 -NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4 -A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYsc -A+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9 -AOoBmbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1 -AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2LqL19iUw== ------END CERTIFICATE----- - -UTN DATACorp SGC Root CA -======================== ------BEGIN CERTIFICATE----- -MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ -BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa -MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w -HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy -dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys -raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo -wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA -9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv -33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud -DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 -BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD -LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 -DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft -Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 -I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx -EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP -DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI ------END CERTIFICATE----- - -UTN USERFirst Email Root CA -=========================== ------BEGIN CERTIFICATE----- -MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0 -BgNVBAMTLVVUTi1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05 -OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQx -FzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx -ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJz -dC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIx -B8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8 -om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHG -TPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7Nl -yP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws6wIDAQABo4G5MIG2MAsGA1UdDwQE -AwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNV -HR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll -bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH -AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u7mFVbwQ+zzne -xRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+ -5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarV -NZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZ -w7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= ------END CERTIFICATE----- - UTN USERFirst Hardware Root CA ============================== -----BEGIN CERTIFICATE----- @@ -1275,31 +700,6 @@ iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 nfhmqA== -----END CERTIFICATE----- -UTN USERFirst Object Root CA -============================ ------BEGIN CERTIFICATE----- -MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAb -BgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAz -NlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx -HjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2Vy -dHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VR -loTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ -w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vu -lBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7 -RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEAAaOBrzCBrDAL -BgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8 -ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly -c3QtT2JqZWN0LmNybDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw -DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw -NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNO -PmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFE -qmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCG -hU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= ------END CERTIFICATE----- - Camerfirma Chambers of Commerce Root ==================================== -----BEGIN CERTIFICATE----- @@ -1354,42 +754,6 @@ IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- -NetLock Qualified (Class QA) Root -================================= ------BEGIN CERTIFICATE----- -MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUxETAPBgNVBAcT -CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV -BAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVn -eXpvaSAoQ2xhc3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0 -bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTER -MA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0 -LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0 -dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3DQEJARYP -aW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRV -CacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e -8ia6AFQer7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhb -m+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrqOU+L73Sa58XQ -0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0lmT+1fMptsK6ZmfoIYOcZwvK9UdPM -0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV -HQ8BAf8EBAMCAQYwggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2 -YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh -biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQgZWxla3Ryb25p -a3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFz -YW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwg -YXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kg -ZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczov -L3d3dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2Nr -Lm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0 -aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMg -YXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0 -IGluZm9AbmV0bG9jay5uZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3 -DQEBBQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQMznN -wNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+NFAwLvt/MpqNPfMg -W/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTc -R08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR -5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko ------END CERTIFICATE----- - NetLock Notary (Class A) Root ============================= -----BEGIN CERTIFICATE----- @@ -1425,64 +789,6 @@ KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM 8CgHrTwXZoi1/baI -----END CERTIFICATE----- -NetLock Business (Class B) Root -=============================== ------BEGIN CERTIFICATE----- -MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT -CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV -BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg -VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD -VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv -bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg -VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S -o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr -1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV -HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ -RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh -dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 -ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv -c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg -YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh -c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz -Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA -bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl -IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 -YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj -cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM -43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR -stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI ------END CERTIFICATE----- - -NetLock Express (Class C) Root -============================== ------BEGIN CERTIFICATE----- -MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT -CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV -BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD -KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ -BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 -dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j -ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB -jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z -W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 -euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw -DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN -RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn -YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB -IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i -aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 -ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs -ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo -dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y -emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k -IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ -UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg -YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 -xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW -gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== ------END CERTIFICATE----- - XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- @@ -1626,54 +932,6 @@ CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy +fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS -----END CERTIFICATE----- -Firmaprofesional Root CA -======================== ------BEGIN CERTIFICATE----- -MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT -GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp -Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA -ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL -MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT -OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 -ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V -j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH -lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf -3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 -NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww -KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG -AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD -ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq -u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf -wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm -7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG -VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= ------END CERTIFICATE----- - -Wells Fargo Root CA -=================== ------BEGIN CERTIFICATE----- -MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV -BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN -MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl -bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv -MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX -x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 -E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 -OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j -sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj -YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF -BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD -ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv -m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R -OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx -x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 -tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= ------END CERTIFICATE----- - Swisscom Root CA 1 ================== -----BEGIN CERTIFICATE----- @@ -1838,85 +1096,6 @@ vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 oKfN5XozNmr6mis= -----END CERTIFICATE----- -TURKTRUST Certificate Services Provider Root 1 -============================================== ------BEGIN CERTIFICATE----- -MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP -MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 -acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx -MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg -U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB -TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC -aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX -yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i -Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ -8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 -W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME -BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 -sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE -q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy -B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY -nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H ------END CERTIFICATE----- - -TURKTRUST Certificate Services Provider Root 2 -============================================== ------BEGIN CERTIFICATE----- -MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP -MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg -QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN -MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr -dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G -A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls -acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe -LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI -x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g -QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr -5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB -AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt -Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 -Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ -hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P -9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 -UrbnBEI= ------END CERTIFICATE----- - -SwissSign Platinum CA - G2 -========================== ------BEGIN CERTIFICATE----- -MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCQ0gxFTAT -BgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWduIFBsYXRpbnVtIENBIC0gRzIw -HhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMM -U3dpc3NTaWduIEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu -669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UF -eNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kne -WCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIo -j5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/6 -8++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34T -aNhxKFrYzt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjy -domyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3HBqi7Ri6Cr2D -+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuWae5ogObnmLo2t/5u7Su9IPhlGdpV -CX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCv -zAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW -IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1 -Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3 -NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4 -U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8 -KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl -9x8DYSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1B -aYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyIIoK6q8QNs -OktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSY -Mdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAci -IfNAChs0B0QTwoRqjt8ZWr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== ------END CERTIFICATE----- - SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- @@ -2254,32 +1433,6 @@ hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= -----END CERTIFICATE----- -S-TRUST Authentication and Encryption Root CA 2005 PN -===================================================== ------BEGIN CERTIFICATE----- -MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE -BhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcpMRIwEAYDVQQHEwlTdHV0dGdh -cnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fzc2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVT -LVRSVVNUIEF1dGhlbnRpY2F0aW9uIGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0w -NTA2MjIwMDAwMDBaFw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFk -ZW4tV3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMgRGV1dHNj -aGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJVU1QgQXV0aGVudGljYXRp -b24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBOMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob -4QSwI7+Vio5bG0F/WsPoTUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXL -g3KSwlOyggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1Xgqf -eN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteFhy+S8dF2g08LOlk3 -KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm7QIDAQABo4GSMIGPMBIGA1UdEwEB -/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJv -bmxpbmUxLTIwNDgtNTAdBgNVHQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAU -D8oeXHngovMpttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD -pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFoLtU96G7m1R08 -P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersFiXOMy6ZNwPv2AtawB6MDwidA -nwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0yh9WUUpY6RsZxlj33mA6ykaqP2vROJAA5Veit -F7nTNCtKqUDMFypVZUF0Qn71wK/Ik63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8b -Hz2eBIPdltkdOpQ= ------END CERTIFICATE----- - Microsec e-Szigno Root CA ========================= -----BEGIN CERTIFICATE----- @@ -2342,117 +1495,6 @@ PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- -AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. -====================================== ------BEGIN CERTIFICATE----- -MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT -AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg -LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w -HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ -U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh -IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN -yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU -2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 -4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP -2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm -8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf -HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa -Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK -5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b -czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g -ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF -BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug -cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf -AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX -EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v -/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 -MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 -3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk -eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f -/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h -RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU -Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== ------END CERTIFICATE----- - -TC TrustCenter Class 2 CA II -============================ ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy -IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw -MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 -c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE -AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw -IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 -xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ -Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u -SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB -7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 -Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU -cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i -SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G -dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ -KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj -TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP -JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk -vQ== ------END CERTIFICATE----- - -TC TrustCenter Class 3 CA II -============================ ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy -IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw -MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 -c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE -AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W -yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo -6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ -uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk -2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB -7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 -Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU -cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i -SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE -O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 -yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 -IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal -092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc -5A== ------END CERTIFICATE----- - -TC TrustCenter Universal CA I -============================= ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy -IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN -MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg -VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw -JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC -qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv -xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw -ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O -gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j -BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG -1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy -vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 -ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT -ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a -7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY ------END CERTIFICATE----- - Deutsche Telekom Root CA 2 ========================== -----BEGIN CERTIFICATE----- @@ -2475,50 +1517,6 @@ dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- -ComSign CA -========== ------BEGIN CERTIFICATE----- -MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0MRMwEQYDVQQD -EwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTMy -MThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMTCkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNp -Z24xCzAJBgNVBAYTAklMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49q -ROR+WCf4C9DklBKK8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTy -P2Q298CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb2CEJKHxN -GGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxCejVb7Us6eva1jsz/D3zk -YDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7KpiXd3DTKaCQeQzC6zJMw9kglcq/QytNuEM -rkvF7zuZ2SOzW120V+x0cAwqTwIDAQABo4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAy -oDCgLoYsaHR0cDovL2ZlZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0P -AQH/BAQDAgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRLAZs+ -VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWdfoPPbrxHbvUanlR2 -QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0McXS6hMTXcpuEfDhOZAYnKuGntewI -mbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb -/627HOkthIDYIb6FUtnUdLlphbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VG -zT2ouvDzuFYkRes3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U -AGegcQCCSA== ------END CERTIFICATE----- - -ComSign Secured CA -================== ------BEGIN CERTIFICATE----- -MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE -AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w -NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD -QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs -49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH -7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB -kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 -9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw -AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t -U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA -j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC -AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a -BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp -FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP -51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz -OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== ------END CERTIFICATE----- - Cybertrust Global Root ====================== -----BEGIN CERTIFICATE----- @@ -2620,26 +1618,6 @@ fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho -----END CERTIFICATE----- -Buypass Class 3 CA 1 -==================== ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 -MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh -c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx -ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 -n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia -AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c -1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P -AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 -pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA -EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 -htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj -el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 ------END CERTIFICATE----- - EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 ========================================================================== -----BEGIN CERTIFICATE----- @@ -2865,7 +1843,7 @@ A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- -NetLock Arany (Class Gold) FÅ‘tanúsítvány +NetLock Arany (Class Gold) Főtanúsítvány ============================================ -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G @@ -3045,38 +2023,6 @@ MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== -----END CERTIFICATE----- -Verisign Class 1 Public Primary Certification Authority -======================================================= ------BEGIN CERTIFICATE----- -MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx -FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow -XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAx -IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0fzGVuDLDQ -VoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHiTkVWaR94AoDa3EeRKbs2 -yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFgVKTk8d6Pa -XCUDfGD67gmZPCcQcMgMCeazh88K4hiWNWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n -0a3hUKw8fGJLj7qE1xIVGx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZ -RjXZ+Hxb ------END CERTIFICATE----- - -Verisign Class 3 Public Primary Certification Authority -======================================================= ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx -FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow -XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz -IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 -f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol -hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky -CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX -bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ -D/xwzoiQ ------END CERTIFICATE----- - Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- @@ -3101,28 +2047,6 @@ yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi LXpUq3DDfSJlgnCW -----END CERTIFICATE----- -E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi -=================================================== ------BEGIN CERTIFICATE----- -MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG -EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz -ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 -MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 -cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u -aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY -8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y -jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI -JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk -9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG -SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d -F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq -D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 -Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq -fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX ------END CERTIFICATE----- - GlobalSign Root CA - R3 ======================= -----BEGIN CERTIFICATE----- @@ -3144,29 +2068,6 @@ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- -TC TrustCenter Universal CA III -=============================== ------BEGIN CERTIFICATE----- -MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy -IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe -Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU -QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex -KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt -QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO -juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut -CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1 -M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G -A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA -g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+ -KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK -BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV -CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq -woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== ------END CERTIFICATE----- - Autoridad de Certificacion Firmaprofesional CIF A62634068 ========================================================= -----BEGIN CERTIFICATE----- @@ -3482,7 +2383,7 @@ Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- -Certinomis - Autorité Racine +Certinomis - Autorité Racine ============================= -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK @@ -3548,29 +2449,6 @@ iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt +GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= -----END CERTIFICATE----- -A-Trust-nQual-03 -================ ------BEGIN CERTIFICATE----- -MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE -Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy -a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R -dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw -RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 -ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 -c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA -zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n -yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE -SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 -iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V -cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV -eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 -ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr -sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd -JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS -mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 -ahq97BvIxYSazQ== ------END CERTIFICATE----- - TWCA Root Certification Authority ================================= -----BEGIN CERTIFICATE----- @@ -3848,31 +2726,6 @@ eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi Cp/HuZc= -----END CERTIFICATE----- -TÃœRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı -====================================================== ------BEGIN CERTIFICATE----- -MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP -MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg -QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X -DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl -a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN -BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp -bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N -YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv -KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya -KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT -rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC -AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s -Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I -aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO -Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb -BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK -poRq0Tl9 ------END CERTIFICATE----- - T-TeleSec GlobalRoot Class 3 ============================ -----BEGIN CERTIFICATE----- @@ -3918,3 +2771,1146 @@ uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU 3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM dcGWxZ0= -----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2007 +================================================= +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X +DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl +a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN +BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp +bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N +YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv +KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya +KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT +rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC +AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s +Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO +Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb +BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK +poRq0Tl9 +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +PSCProcert +========== +-----BEGIN CERTIFICATE----- +MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk +ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ +MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz +dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl +cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw +IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw +MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w +DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD +ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp +Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC +wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA +3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh +RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO +EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 +0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH +0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU +td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw +Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp +r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ +AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz +Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId +xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp +ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH +EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h +Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k +ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG +9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG +MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG +LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 +ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy +YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v +Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o +dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq +T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN +g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q +uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 +n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn +FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo +5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq +3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 +poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y +eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km +-----END CERTIFICATE----- + +China Internet Network Information Center EV Certificates Root +============================================================== +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D +aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg +Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG +A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM +PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl +cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y +jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV +98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H +klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 +KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC +7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD +glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 +0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM +7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 +5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= +-----END CERTIFICATE----- + +Swisscom Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 +MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM +LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo +ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ +wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH +Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a +SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS +NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab +mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY +Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 +qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O +BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu +MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO +v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ +82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz +o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs +a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx +OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW +mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o ++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC +rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX +5OfNeOI5wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- + +Swisscom Root EV CA 2 +===================== +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE +BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl +cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN +MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT +HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg +Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz +o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy +Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti +GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li +qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH +Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG +alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa +m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox +bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi +xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED +MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB +bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL +j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU +wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 +XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH +59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ +23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq +J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA +HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi +uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW +l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- + +CA Disig Root R1 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy +3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 +u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 +m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk +CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa +YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 +vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL +LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX +ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is +XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ +04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B +LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM +CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb +VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 +YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS +ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix +lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N +UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ +a7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +=============================== +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w +DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls +ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw +NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx +QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl +cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD +DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd +hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K +CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g +ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ +BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 +E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz +rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq +jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 +dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK +kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO +XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 +VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo +a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc +dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV +KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT +Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 +8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G +C7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE +PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm +PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 +Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN +ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l +g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV +7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX +9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f +iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg +t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI +hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 +GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct +Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP ++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh +3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa +wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 +O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 +FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV +hMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh +ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY +NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t +oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o +MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l +V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo +L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ +sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD +6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh +lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI +hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K +pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 +x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz +dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X +U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw +mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD +zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN +JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr +O3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 +IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL +Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe +6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 +I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U +VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 +5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi +Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM +dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt +rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI +hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS +t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ +TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du +DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib +Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD +hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX +0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW +dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 +PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +=========================== +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw +MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH +35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq +bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw +VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP +YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn +lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO +w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv +0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz +d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW +hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M +jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +=========================== +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD +VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb +RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs +KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF +UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy +YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy +1vUhZscv6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx +MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ +kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO +3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV +BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM +UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu +5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr +F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U +WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH +QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ +iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +======================= +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD +VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw +MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k +aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O +YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp +Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y +3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 +VOKa5Vt8sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +======================== +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw +HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp +pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o +k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa +vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 +MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm +mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 +f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH +dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 +oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY +ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr +yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy +7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah +ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN +5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb +/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa +5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK +G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP +82Z+ +-----END CERTIFICATE----- + +WoSign +====== +-----BEGIN CERTIFICATE----- +MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG +EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g +QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ +BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA +vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO +CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX +2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5 +KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR ++ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez +EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk +lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2 +8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY +yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C +AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R +8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1 +LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq +T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj +y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC +2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes +5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/ +EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh +mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx +kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi +kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w== +-----END CERTIFICATE----- + +WoSign China +============ +-----BEGIN CERTIFICATE----- +MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG +EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv +geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD +VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k +8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5 +uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85 +dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5 +Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy +b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc +76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m ++Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6 +yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX +GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA +A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6 +yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY +r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115 +j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A +kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97 +qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y +jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB +ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv +T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO +kI26oQ== +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz +0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j +Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn +RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O ++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq +/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE +Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM +lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 +yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ +eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW +FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ +7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ +Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM +8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi +FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi +yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c +J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw +sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx +Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 +0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez +nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV +HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB +HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu +9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl +OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV +MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF +JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +=========================== +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 +SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS +h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx +uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 +yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G3 +================================== +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y +olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t +x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy +EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K +Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur +mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5 +1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp +07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo +FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE +41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu +yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq +KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1 +v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA +8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b +8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r +mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq +1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI +JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV +tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk= +-----END CERTIFICATE----- + +Staat der Nederlanden EV Root CA +================================ +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M +MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl +cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk +SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW +O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r +0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 +Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV +XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr +08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV +0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd +74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx +fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa +ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu +c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq +5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN +b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN +f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi +5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 +WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK +DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy +eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5 +========================================================= +-----BEGIN CERTIFICATE----- +MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN +BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp +bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg +RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw +ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w +SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE +n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp +ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537 +jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m +ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP +9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV +4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH +HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo +BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq +URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl +lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8 +B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU= +-----END CERTIFICATE----- + +TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6 +========================================================= +-----BEGIN CERTIFICATE----- +MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5 +MDQxMFoXDTIzMTIxNjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBL +BgNVBAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSf +aSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2VydGlm +aWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCdsGjW6L0UlqMACprx9MfMkU1xeHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a +2uqsxgbPJQ1BgfbBOCK9+bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EED +wnS3/faAz1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0pu5Fb +HH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6plVxiSvgNZ1GpryHV ++DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMBAAGjQjBAMB0GA1UdDgQWBBTdVRcT +9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQsFAAOCAQEAb1gNl0OqFlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3R +fdCaqaXKGDsCQC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy +o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKIDgI6tflEATseW +hvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm9ocJV612ph1jmv3XZch4gyt1 +O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsGtAuYSyher4hYyw== +-----END CERTIFICATE----- + +Certinomis - Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg +LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx +EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD +ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos +P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo +d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap +z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00 +8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x +RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE +6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t +FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV +PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH +i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj +YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I +6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV +WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw +Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX +lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ +y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9 +Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng +DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi +I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM +cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr +hkIGuUE= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +=============================== +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG +EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw +MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds +b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX +scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP +rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk +9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o +Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg +GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI +hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD +dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 +VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui +HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +Certification Authority of WoSign G2 +==================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG +EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g +QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx +CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai +XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du +W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9 +5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK +v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI +hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY +P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3 +TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu ++sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+ +7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg= +-----END CERTIFICATE----- + +CA WoSign ECC Root +================== +-----BEGIN CERTIFICATE----- +MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD +TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v +dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK +ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU +t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw +QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R +MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0 +Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu +a/GRspBl9JrmkO5K +-----END CERTIFICATE----- diff --git a/web/api/lib/Cake/Config/config.php b/web/api/lib/Cake/Config/config.php index cd3a398c4..755944ab4 100644 --- a/web/api/lib/Cake/Config/config.php +++ b/web/api/lib/Cake/Config/config.php @@ -2,18 +2,18 @@ /** * Core Configurations. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Config * @since CakePHP(tm) v 1.1.11.4062 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ $versionFile = file(CAKE . 'VERSION.txt'); diff --git a/web/api/lib/Cake/Config/routes.php b/web/api/lib/Cake/Config/routes.php index 7bcc0c06b..5d603ed8e 100644 --- a/web/api/lib/Cake/Config/routes.php +++ b/web/api/lib/Cake/Config/routes.php @@ -1,17 +1,17 @@ _path = $path; $this->_section = $section; diff --git a/web/api/lib/Cake/Configure/PhpReader.php b/web/api/lib/Cake/Configure/PhpReader.php index d15a41b83..40176ce9f 100644 --- a/web/api/lib/Cake/Configure/PhpReader.php +++ b/web/api/lib/Cake/Configure/PhpReader.php @@ -2,17 +2,17 @@ /** * PhpReader file * - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://book.cakephp.org/2.0/en/development/configuration.html#loading-configuration-files CakePHP(tm) Configuration + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://book.cakephp.org/2.0/en/development/configuration.html#loading-configuration-files CakePHP(tm) Configuration * @package Cake.Configure * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('CakePlugin', 'Core'); @@ -38,11 +38,11 @@ class PhpReader implements ConfigReaderInterface { /** * Constructor for PHP Config file reading. * - * @param string $path The path to read config files from. Defaults to APP . 'Config' . DS + * @param string $path The path to read config files from. Defaults to CONFIG */ public function __construct($path = null) { if (!$path) { - $path = APP . 'Config' . DS; + $path = CONFIG; } $this->_path = $path; } diff --git a/web/api/lib/Cake/Console/Command/AclShell.php b/web/api/lib/Cake/Console/Command/AclShell.php index 15536ebb6..10db318eb 100644 --- a/web/api/lib/Cake/Console/Command/AclShell.php +++ b/web/api/lib/Cake/Console/Command/AclShell.php @@ -2,17 +2,17 @@ /** * Acl Shell provides Acl access in the CLI environment * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2.0.5012 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -89,7 +89,7 @@ class AclShell extends AppShell { $this->args = null; return $this->DbConfig->execute(); } - require_once APP . 'Config' . DS . 'database.php'; + require_once CONFIG . 'database.php'; if (!in_array($this->command, array('initdb'))) { $collection = new ComponentCollection(); diff --git a/web/api/lib/Cake/Console/Command/ApiShell.php b/web/api/lib/Cake/Console/Command/ApiShell.php index 8b0c979d7..3c3dd1cef 100644 --- a/web/api/lib/Cake/Console/Command/ApiShell.php +++ b/web/api/lib/Cake/Console/Command/ApiShell.php @@ -4,17 +4,17 @@ * * Implementation of a Cake Shell to show CakePHP core method signatures. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2.0.5012 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); diff --git a/web/api/lib/Cake/Console/Command/AppShell.php b/web/api/lib/Cake/Console/Command/AppShell.php index 4ea0f2dd8..030ae49fd 100644 --- a/web/api/lib/Cake/Console/Command/AppShell.php +++ b/web/api/lib/Cake/Console/Command/AppShell.php @@ -2,17 +2,17 @@ /** * AppShell file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('Shell', 'Console'); diff --git a/web/api/lib/Cake/Console/Command/BakeShell.php b/web/api/lib/Cake/Console/Command/BakeShell.php index c1e59c690..e0db7bc0c 100644 --- a/web/api/lib/Cake/Console/Command/BakeShell.php +++ b/web/api/lib/Cake/Console/Command/BakeShell.php @@ -6,17 +6,17 @@ * application development by writing fully functional skeleton controllers, * models, and views. Going further, Bake can also write Unit Tests for you. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2.0.5012 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -30,7 +30,7 @@ App::uses('Model', 'Model'); * models, and views. Going further, Bake can also write Unit Tests for you. * * @package Cake.Console.Command - * @link http://book.cakephp.org/2.0/en/console-and-shells/code-generation-with-bake.html + * @link https://book.cakephp.org/2.0/en/console-and-shells/code-generation-with-bake.html */ class BakeShell extends AppShell { diff --git a/web/api/lib/Cake/Console/Command/CommandListShell.php b/web/api/lib/Cake/Console/Command/CommandListShell.php index ca6620a5b..49b987783 100644 --- a/web/api/lib/Cake/Console/Command/CommandListShell.php +++ b/web/api/lib/Cake/Console/Command/CommandListShell.php @@ -1,17 +1,17 @@ out(" -working: " . rtrim(APP, DS)); $this->out(" -root: " . rtrim(ROOT, DS)); $this->out(" -core: " . rtrim(CORE_PATH, DS)); + $this->out(" -webroot: " . rtrim(WWW_ROOT, DS)); $this->out(""); $this->out(__d('cake_console', "Changing Paths:"), 2); $this->out(__d('cake_console', "Your working path should be the same as your application path. To change your path use the '-app' param.")); diff --git a/web/api/lib/Cake/Console/Command/CompletionShell.php b/web/api/lib/Cake/Console/Command/CompletionShell.php index 57e86f949..3d6fa17e0 100644 --- a/web/api/lib/Cake/Console/Command/CompletionShell.php +++ b/web/api/lib/Cake/Console/Command/CompletionShell.php @@ -1,17 +1,17 @@ __d('cake_console', 'Path to read and write schema.php'), - 'default' => APP . 'Config' . DS . 'Schema' + 'default' => CONFIG . 'Schema' ); $file = array( 'help' => __d('cake_console', 'File name to read and write.'), diff --git a/web/api/lib/Cake/Console/Command/ServerShell.php b/web/api/lib/Cake/Console/Command/ServerShell.php index 8c7d5e5e3..014d3978a 100644 --- a/web/api/lib/Cake/Console/Command/ServerShell.php +++ b/web/api/lib/Cake/Console/Command/ServerShell.php @@ -2,17 +2,17 @@ /** * built-in Server Shell * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.3.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -78,7 +78,7 @@ class ServerShell extends AppShell { * or otherwise modify the pre-command flow. * * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup */ public function startup() { if (!empty($this->params['host'])) { diff --git a/web/api/lib/Cake/Console/Command/Task/BakeTask.php b/web/api/lib/Cake/Console/Command/Task/BakeTask.php index 8298e112a..c886c95e6 100644 --- a/web/api/lib/Cake/Console/Command/Task/BakeTask.php +++ b/web/api/lib/Cake/Console/Command/Task/BakeTask.php @@ -2,17 +2,17 @@ /** * Base class for Bake Tasks. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.3 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); diff --git a/web/api/lib/Cake/Console/Command/Task/CommandTask.php b/web/api/lib/Cake/Console/Command/Task/CommandTask.php index fca006a72..99c888f8e 100644 --- a/web/api/lib/Cake/Console/Command/Task/CommandTask.php +++ b/web/api/lib/Cake/Console/Command/Task/CommandTask.php @@ -1,16 +1,16 @@ doComponents(); $wannaUseSession = $this->in( - __d('cake_console', "Would you like to use Session flash messages?"), array('y', 'n'), 'y' + __d('cake_console', "Would you like to use the FlashComponent to display flash messages?"), array('y', 'n'), 'y' ); if (strtolower($wannaUseSession) === 'y') { - array_push($components, 'Session'); + array_push($components, 'Session', 'Flash'); } array_unique($components); } @@ -331,6 +331,12 @@ class ControllerTask extends BakeTask { public function bake($controllerName, $actions = '', $helpers = null, $components = null) { $this->out("\n" . __d('cake_console', 'Baking controller class for %s...', $controllerName), 1, Shell::QUIET); + if ($helpers === null) { + $helpers = array(); + } + if ($components === null) { + $components = array(); + } $isScaffold = ($actions === 'scaffold') ? true : false; $this->Template->set(array( @@ -384,9 +390,9 @@ class ControllerTask extends BakeTask { * @return array Components the user wants to use. */ public function doComponents() { - $components = array('Paginator', 'Flash'); + $components = array('Paginator'); return array_merge($components, $this->_doPropertyChoices( - __d('cake_console', "Would you like this controller to use other components\nbesides PaginatorComponent and FlashComponent?"), + __d('cake_console', "Would you like this controller to use other components\nbesides PaginatorComponent?"), __d('cake_console', "Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'") )); } diff --git a/web/api/lib/Cake/Console/Command/Task/DbConfigTask.php b/web/api/lib/Cake/Console/Command/Task/DbConfigTask.php index ee1aa6c99..c76b87bcd 100644 --- a/web/api/lib/Cake/Console/Command/Task/DbConfigTask.php +++ b/web/api/lib/Cake/Console/Command/Task/DbConfigTask.php @@ -2,17 +2,17 @@ /** * The DbConfig Task handles creating and updating the database.php * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -64,7 +64,7 @@ class DbConfigTask extends AppShell { * @return void */ public function initialize() { - $this->path = APP . 'Config' . DS; + $this->path = CONFIG; } /** diff --git a/web/api/lib/Cake/Console/Command/Task/ExtractTask.php b/web/api/lib/Cake/Console/Command/Task/ExtractTask.php index 740528f70..eaa691e31 100644 --- a/web/api/lib/Cake/Console/Command/Task/ExtractTask.php +++ b/web/api/lib/Cake/Console/Command/Task/ExtractTask.php @@ -2,17 +2,17 @@ /** * Language string extractor * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2.0.5012 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); diff --git a/web/api/lib/Cake/Console/Command/Task/FixtureTask.php b/web/api/lib/Cake/Console/Command/Task/FixtureTask.php index 1f578d083..7b2ee52e7 100644 --- a/web/api/lib/Cake/Console/Command/Task/FixtureTask.php +++ b/web/api/lib/Cake/Console/Command/Task/FixtureTask.php @@ -2,17 +2,17 @@ /** * The FixtureTask handles creating and updating fixture files. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.3 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -125,7 +125,8 @@ class FixtureTask extends BakeTask { return $this->all(); } $model = $this->_modelName($this->args[0]); - $this->bake($model); + $importOptions = $this->importOptions($model); + $this->bake($model, false, $importOptions); } } @@ -177,24 +178,29 @@ class FixtureTask extends BakeTask { */ public function importOptions($modelName) { $options = array(); + $plugin = ''; + if (isset($this->params['plugin'])) { + $plugin = $this->params['plugin'] . '.'; + } if (!empty($this->params['schema'])) { - $options['schema'] = $modelName; - } else { + $options['schema'] = $plugin . $modelName; + } elseif ($this->interactive) { $doSchema = $this->in(__d('cake_console', 'Would you like to import schema for this fixture?'), array('y', 'n'), 'n'); if ($doSchema === 'y') { $options['schema'] = $modelName; } } + if (!empty($this->params['records'])) { - $doRecords = 'y'; - } else { + $options['fromTable'] = true; + } elseif ($this->interactive) { $doRecords = $this->in(__d('cake_console', 'Would you like to use record importing for this fixture?'), array('y', 'n'), 'n'); + if ($doRecords === 'y') { + $options['records'] = true; + } } - if ($doRecords === 'y') { - $options['records'] = true; - } - if ($doRecords === 'n') { + if (!isset($options['records']) && $this->interactive) { $prompt = __d('cake_console', "Would you like to build this fixture with data from %s's table?", $modelName); $fromTable = $this->in($prompt, array('y', 'n'), 'n'); if (strtolower($fromTable) === 'y') { @@ -329,6 +335,9 @@ class FixtureTask extends BakeTask { } $insert = ''; switch ($fieldInfo['type']) { + case 'tinyinteger': + case 'smallinteger': + case 'biginteger': case 'integer': case 'float': $insert = $i + 1; diff --git a/web/api/lib/Cake/Console/Command/Task/ModelTask.php b/web/api/lib/Cake/Console/Command/Task/ModelTask.php index 2dc03a5c3..4619655f9 100644 --- a/web/api/lib/Cake/Console/Command/Task/ModelTask.php +++ b/web/api/lib/Cake/Console/Command/Task/ModelTask.php @@ -2,17 +2,17 @@ /** * The ModelTask handles creating and updating models files. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -450,6 +450,10 @@ class ModelTask extends BakeTask { $guess = $methods['notBlank']; } elseif ($metaData['type'] === 'integer') { $guess = $methods['numeric']; + } elseif ($metaData['type'] === 'smallinteger') { + $guess = $methods['numeric']; + } elseif ($metaData['type'] === 'tinyinteger') { + $guess = $methods['numeric']; } elseif ($metaData['type'] === 'float') { $guess = $methods['numeric']; } elseif ($metaData['type'] === 'boolean') { diff --git a/web/api/lib/Cake/Console/Command/Task/PluginTask.php b/web/api/lib/Cake/Console/Command/Task/PluginTask.php index 7cd507942..10a00864a 100644 --- a/web/api/lib/Cake/Console/Command/Task/PluginTask.php +++ b/web/api/lib/Cake/Console/Command/Task/PluginTask.php @@ -1,16 +1,16 @@ path = current(App::path('plugins')); - $this->bootstrap = APP . 'Config' . DS . 'bootstrap.php'; + $this->bootstrap = CONFIG . 'bootstrap.php'; } /** diff --git a/web/api/lib/Cake/Console/Command/Task/ProjectTask.php b/web/api/lib/Cake/Console/Command/Task/ProjectTask.php index df1ab19db..ed38f6855 100644 --- a/web/api/lib/Cake/Console/Command/Task/ProjectTask.php +++ b/web/api/lib/Cake/Console/Command/Task/ProjectTask.php @@ -2,17 +2,17 @@ /** * The Project Task handles creating the base application * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -79,14 +79,14 @@ class ProjectTask extends AppShell { if ($this->securitySalt($path) === true) { $this->out(__d('cake_console', ' * Random hash key created for \'Security.salt\'')); } else { - $this->err(__d('cake_console', 'Unable to generate random hash for \'Security.salt\', you should change it in %s', APP . 'Config' . DS . 'core.php')); + $this->err(__d('cake_console', 'Unable to generate random hash for \'Security.salt\', you should change it in %s', CONFIG . 'core.php')); $success = false; } if ($this->securityCipherSeed($path) === true) { $this->out(__d('cake_console', ' * Random seed created for \'Security.cipherSeed\'')); } else { - $this->err(__d('cake_console', 'Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s', APP . 'Config' . DS . 'core.php')); + $this->err(__d('cake_console', 'Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s', CONFIG . 'core.php')); $success = false; } @@ -362,7 +362,7 @@ class ProjectTask extends AppShell { * @return bool Success */ public function cakeAdmin($name) { - $path = (empty($this->configPath)) ? APP . 'Config' . DS : $this->configPath; + $path = (empty($this->configPath)) ? CONFIG : $this->configPath; $File = new File($path . 'core.php'); $contents = $File->read(); if (preg_match('%(\s*[/]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) { diff --git a/web/api/lib/Cake/Console/Command/Task/TemplateTask.php b/web/api/lib/Cake/Console/Command/Task/TemplateTask.php index d5dfc4440..0691bf5c2 100644 --- a/web/api/lib/Cake/Console/Command/Task/TemplateTask.php +++ b/web/api/lib/Cake/Console/Command/Task/TemplateTask.php @@ -2,17 +2,17 @@ /** * Template Task can generate templated output Used in other Tasks * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.3 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); diff --git a/web/api/lib/Cake/Console/Command/Task/TestTask.php b/web/api/lib/Cake/Console/Command/Task/TestTask.php index a147951c2..342494e57 100644 --- a/web/api/lib/Cake/Console/Command/Task/TestTask.php +++ b/web/api/lib/Cake/Console/Command/Task/TestTask.php @@ -2,17 +2,17 @@ /** * The TestTask handles creating and updating test files. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.3 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -367,7 +367,7 @@ class TestTask extends BakeTask { * Generate the list of fixtures that will be required to run this test based on * loaded models. * - * @param object $subject The object you want to generate fixtures for. + * @param CakeObject $subject The object you want to generate fixtures for. * @return array Array of fixtures to be included in the test. */ public function generateFixtureList($subject) { diff --git a/web/api/lib/Cake/Console/Command/Task/ViewTask.php b/web/api/lib/Cake/Console/Command/Task/ViewTask.php index 06ecf0013..fa7ddef44 100644 --- a/web/api/lib/Cake/Console/Command/Task/ViewTask.php +++ b/web/api/lib/Cake/Console/Command/Task/ViewTask.php @@ -2,17 +2,17 @@ /** * The View Tasks handles creating and updating view files. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 1.2 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); diff --git a/web/api/lib/Cake/Console/Command/TestShell.php b/web/api/lib/Cake/Console/Command/TestShell.php index 4dfacfdfc..b12f6a078 100644 --- a/web/api/lib/Cake/Console/Command/TestShell.php +++ b/web/api/lib/Cake/Console/Command/TestShell.php @@ -4,17 +4,17 @@ * * This Shell allows the running of test suites via the cake command line * - * CakePHP(tm) Tests - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) Tests + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://book.cakephp.org/2.0/en/development/testing.html + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://book.cakephp.org/2.0/en/development/testing.html * @since CakePHP(tm) v 1.2.0.4433 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('Shell', 'Console'); @@ -71,6 +71,9 @@ class TestShell extends Shell { ))->addOption('coverage-clover', array( 'help' => __d('cake_console', ' Write code coverage data in Clover XML format.'), 'default' => false + ))->addOption('coverage-text', array( + 'help' => __d('cake_console', 'Output code coverage report in Text format.'), + 'boolean' => true ))->addOption('testdox-html', array( 'help' => __d('cake_console', ' Write agile documentation in HTML format to file.'), 'default' => false @@ -152,6 +155,7 @@ class TestShell extends Shell { 'default' => false ))->addOption('directive', array( 'help' => __d('cake_console', 'key[=value] Sets a php.ini value.'), + 'short' => 'd', 'default' => false ))->addOption('fixture', array( 'help' => __d('cake_console', 'Choose a custom fixture manager.') @@ -234,7 +238,11 @@ class TestShell extends Shell { if ($value === false) { continue; } - $options[] = '--' . $param; + if ($param === 'directive') { + $options[] = '-d'; + } else { + $options[] = '--' . $param; + } if (is_string($value)) { $options[] = $value; } diff --git a/web/api/lib/Cake/Console/Command/TestsuiteShell.php b/web/api/lib/Cake/Console/Command/TestsuiteShell.php index d37ac501b..911f787c9 100644 --- a/web/api/lib/Cake/Console/Command/TestsuiteShell.php +++ b/web/api/lib/Cake/Console/Command/TestsuiteShell.php @@ -4,17 +4,17 @@ * * This is a bc wrapper for the newer Test shell * - * CakePHP(tm) Tests - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) Tests + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://book.cakephp.org/2.0/en/development/testing.html + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://book.cakephp.org/2.0/en/development/testing.html * @since CakePHP(tm) v 1.2.0.4433 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('TestShell', 'Console/Command'); diff --git a/web/api/lib/Cake/Console/Command/UpgradeShell.php b/web/api/lib/Cake/Console/Command/UpgradeShell.php index 12b3fbc9d..f9d1223af 100644 --- a/web/api/lib/Cake/Console/Command/UpgradeShell.php +++ b/web/api/lib/Cake/Console/Command/UpgradeShell.php @@ -2,18 +2,18 @@ /** * Upgrade Shell * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Console.Command * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('AppShell', 'Console/Command'); @@ -532,7 +532,7 @@ class UpgradeShell extends AppShell { /** * Update components. * - * - Make components that extend Object to extend Component. + * - Make components that extend CakeObject to extend Component. * * @return void */ @@ -547,6 +547,11 @@ class UpgradeShell extends AppShell { '/([a-zA-Z]*Component extends) Object/', '\1 Component' ), + array( + '*Component extends CakeObject to *Component extends Component', + '/([a-zA-Z]*Component extends) CakeObject/', + '\1 Component' + ), ); $this->_filesRegexpUpdate($patterns); diff --git a/web/api/lib/Cake/Console/ConsoleErrorHandler.php b/web/api/lib/Cake/Console/ConsoleErrorHandler.php index 7cbb2df15..3df0bf734 100644 --- a/web/api/lib/Cake/Console/ConsoleErrorHandler.php +++ b/web/api/lib/Cake/Console/ConsoleErrorHandler.php @@ -2,17 +2,17 @@ /** * ErrorHandler for Console Shells * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('ErrorHandler', 'Error'); diff --git a/web/api/lib/Cake/Console/ConsoleInput.php b/web/api/lib/Cake/Console/ConsoleInput.php index 551635b82..dc416ce82 100644 --- a/web/api/lib/Cake/Console/ConsoleInput.php +++ b/web/api/lib/Cake/Console/ConsoleInput.php @@ -2,18 +2,18 @@ /** * ConsoleInput file. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Console * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Console/ConsoleInputArgument.php b/web/api/lib/Cake/Console/ConsoleInputArgument.php index 08dbc21e9..36f085509 100644 --- a/web/api/lib/Cake/Console/ConsoleInputArgument.php +++ b/web/api/lib/Cake/Console/ConsoleInputArgument.php @@ -2,17 +2,17 @@ /** * ConsoleArgumentOption file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** @@ -159,7 +159,7 @@ class ConsoleInputArgument { $option = $parent->addChild('argument'); $option->addAttribute('name', $this->_name); $option->addAttribute('help', $this->_help); - $option->addAttribute('required', $this->isRequired()); + $option->addAttribute('required', (int)$this->isRequired()); $choices = $option->addChild('choices'); foreach ($this->_choices as $valid) { $choices->addChild('choice', $valid); diff --git a/web/api/lib/Cake/Console/ConsoleInputOption.php b/web/api/lib/Cake/Console/ConsoleInputOption.php index 3a4b7a1c9..139c98353 100644 --- a/web/api/lib/Cake/Console/ConsoleInputOption.php +++ b/web/api/lib/Cake/Console/ConsoleInputOption.php @@ -2,17 +2,17 @@ /** * ConsoleInputOption file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** @@ -205,10 +205,11 @@ class ConsoleInputOption { $option->addAttribute('name', '--' . $this->_name); $short = ''; if (strlen($this->_short)) { - $short = $this->_short; + $short = '-' . $this->_short; } - $option->addAttribute('short', '-' . $short); - $option->addAttribute('boolean', $this->_boolean); + $option->addAttribute('short', $short); + $option->addAttribute('help', $this->_help); + $option->addAttribute('boolean', (int)$this->_boolean); $option->addChild('default', $this->_default); $choices = $option->addChild('choices'); foreach ($this->_choices as $valid) { diff --git a/web/api/lib/Cake/Console/ConsoleInputSubcommand.php b/web/api/lib/Cake/Console/ConsoleInputSubcommand.php index 65c10db06..b67210698 100644 --- a/web/api/lib/Cake/Console/ConsoleInputSubcommand.php +++ b/web/api/lib/Cake/Console/ConsoleInputSubcommand.php @@ -2,17 +2,17 @@ /** * ConsoleInputSubcommand file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Console/ConsoleOptionParser.php b/web/api/lib/Cake/Console/ConsoleOptionParser.php index f54c5460d..f90dbc4e1 100644 --- a/web/api/lib/Cake/Console/ConsoleOptionParser.php +++ b/web/api/lib/Cake/Console/ConsoleOptionParser.php @@ -2,17 +2,17 @@ /** * ConsoleOptionParser file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('TaskCollection', 'Console'); diff --git a/web/api/lib/Cake/Console/ConsoleOutput.php b/web/api/lib/Cake/Console/ConsoleOutput.php index ec6fb3941..4690a850b 100644 --- a/web/api/lib/Cake/Console/ConsoleOutput.php +++ b/web/api/lib/Cake/Console/ConsoleOutput.php @@ -2,17 +2,17 @@ /** * ConsoleOutput file. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Console/HelpFormatter.php b/web/api/lib/Cake/Console/HelpFormatter.php index 3a8fac98f..0c4259aae 100644 --- a/web/api/lib/Cake/Console/HelpFormatter.php +++ b/web/api/lib/Cake/Console/HelpFormatter.php @@ -2,16 +2,16 @@ /** * HelpFormatter * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('CakeText', 'Utility'); @@ -182,7 +182,6 @@ class HelpFormatter { $xml->addChild('command', $parser->command()); $xml->addChild('description', $parser->description()); - $xml->addChild('epilog', $parser->epilog()); $subcommands = $xml->addChild('subcommands'); foreach ($parser->subcommands() as $command) { $command->xml($subcommands); @@ -195,6 +194,7 @@ class HelpFormatter { foreach ($parser->arguments() as $argument) { $argument->xml($arguments); } + $xml->addChild('epilog', $parser->epilog()); return $string ? $xml->asXml() : $xml; } diff --git a/web/api/lib/Cake/Console/Helper/BaseShellHelper.php b/web/api/lib/Cake/Console/Helper/BaseShellHelper.php index f06a17aac..96f12c1bb 100644 --- a/web/api/lib/Cake/Console/Helper/BaseShellHelper.php +++ b/web/api/lib/Cake/Console/Helper/BaseShellHelper.php @@ -1,16 +1,16 @@ name) { @@ -222,7 +222,7 @@ class Shell extends Object { * allows configuration of tasks prior to shell execution * * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::initialize + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::initialize */ public function initialize() { $this->_loadModels(); @@ -237,7 +237,7 @@ class Shell extends Object { * or otherwise modify the pre-command flow. * * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup */ public function startup() { $this->_welcome(); @@ -340,7 +340,7 @@ class Shell extends Object { * * @param string $task The task name to check. * @return bool Success - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasTask + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasTask */ public function hasTask($task) { return isset($this->_taskMap[Inflector::camelize($task)]); @@ -351,7 +351,7 @@ class Shell extends Object { * * @param string $name The method name to check. * @return bool - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasMethod + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasMethod */ public function hasMethod($name) { try { @@ -369,7 +369,7 @@ class Shell extends Object { } /** - * Dispatch a command to another Shell. Similar to Object::requestAction() + * Dispatch a command to another Shell. Similar to CakeObject::requestAction() * but intended for running shells from other shells. * * ### Usage: @@ -387,7 +387,7 @@ class Shell extends Object { * `return $this->dispatchShell('schema', 'create', 'i18n', '--dry');` * * @return mixed The return of the other shell. - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::dispatchShell + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::dispatchShell */ public function dispatchShell() { $args = func_get_args(); @@ -415,8 +415,8 @@ class Shell extends Object { * @param string $command The command name to run on this shell. If this argument is empty, * and the shell has a `main()` method, that will be called instead. * @param array $argv Array of arguments to run the shell with. This array should be missing the shell name. - * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::runCommand + * @return int|bool + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::runCommand */ public function runCommand($command, $argv) { $isTask = $this->hasTask($command); @@ -431,6 +431,7 @@ class Shell extends Object { try { list($this->params, $this->args) = $this->OptionParser->parse($argv, $command); } catch (ConsoleException $e) { + $this->err(__d('cake_console', 'Error: %s', $e->getMessage())); $this->out($this->OptionParser->help($command)); return false; } @@ -468,7 +469,7 @@ class Shell extends Object { * Display the help in the correct format * * @param string $command The command to get help for. - * @return void + * @return int|bool */ protected function _displayHelp($command) { $format = 'text'; @@ -487,7 +488,7 @@ class Shell extends Object { * By overriding this method you can configure the ConsoleOptionParser before returning it. * * @return ConsoleOptionParser - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::getOptionParser + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::getOptionParser */ public function getOptionParser() { $name = ($this->plugin ? $this->plugin . '.' : '') . $this->name; @@ -533,7 +534,7 @@ class Shell extends Object { * @param string|array $options Array or string of options. * @param string $default Default input value. * @return mixed Either the default value, or the user-provided input. - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::in + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::in */ public function in($prompt, $options = null, $default = null) { if (!$this->interactive) { @@ -570,7 +571,7 @@ class Shell extends Object { * @param string $prompt Prompt text. * @param string|array $options Array or string of options. * @param string $default Default input value. - * @return Either the default value, or the user-provided input. + * @return string|int the default value, or the user-provided input. */ protected function _getInput($prompt, $options, $default) { if (!is_array($options)) { @@ -612,7 +613,7 @@ class Shell extends Object { * @param string|int|array $options Array of options to use, or an integer to wrap the text to. * @return string Wrapped / indented text * @see CakeText::wrap() - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::wrapText + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::wrapText */ public function wrapText($text, $options = array()) { return CakeText::wrap($text, $options); @@ -633,7 +634,7 @@ class Shell extends Object { * @param int $newlines Number of newlines to append * @param int $level The message's output level, see above. * @return int|bool Returns the number of bytes returned from writing to stdout. - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::out + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::out */ public function out($message = null, $newlines = 1, $level = Shell::NORMAL) { $currentLevel = Shell::NORMAL; @@ -688,7 +689,7 @@ class Shell extends Object { * @param string|array $message A string or an array of strings to output * @param int $newlines Number of newlines to append * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::err + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::err */ public function err($message = null, $newlines = 1) { $this->stderr->write($message, $newlines); @@ -699,7 +700,7 @@ class Shell extends Object { * * @param int $multiplier Number of times the linefeed sequence should be repeated * @return string - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::nl + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::nl */ public function nl($multiplier = 1) { return str_repeat(ConsoleOutput::LF, $multiplier); @@ -711,7 +712,7 @@ class Shell extends Object { * @param int $newlines Number of newlines to pre- and append * @param int $width Width of the line, defaults to 63 * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hr + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hr */ public function hr($newlines = 0, $width = 63) { $this->out(null, $newlines); @@ -725,8 +726,8 @@ class Shell extends Object { * * @param string $title Title of the error * @param string $message An optional error message - * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::error + * @return int + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::error */ public function error($title, $message = null) { $this->err(__d('cake_console', 'Error: %s', $title)); @@ -742,7 +743,7 @@ class Shell extends Object { * Clear the console * * @return void - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::clear + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::clear */ public function clear() { if (empty($this->params['noclear'])) { @@ -760,7 +761,7 @@ class Shell extends Object { * @param string $path Where to put the file. * @param string $contents Content to put in the file. * @return bool Success - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::createFile + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::createFile */ public function createFile($path, $contents) { $path = str_replace(DS . DS, DS, $path); @@ -849,7 +850,7 @@ class Shell extends Object { * * @param string $file Absolute file path * @return string short path - * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::shortPath + * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::shortPath */ public function shortPath($file) { $shortPath = str_replace(ROOT, null, $file); @@ -974,15 +975,48 @@ class Shell extends Object { CakeLog::drop('stderr'); return; } + if (!$this->_loggerIsConfigured("stdout")) { + $this->_configureStdOutLogger(); + } + if (!$this->_loggerIsConfigured("stderr")) { + $this->_configureStdErrLogger(); + } + } + +/** + * Configure the stdout logger + * + * @return void + */ + protected function _configureStdOutLogger() { CakeLog::config('stdout', array( 'engine' => 'Console', 'types' => array('notice', 'info'), 'stream' => $this->stdout, )); + } + +/** + * Configure the stderr logger + * + * @return void + */ + protected function _configureStdErrLogger() { CakeLog::config('stderr', array( 'engine' => 'Console', 'types' => array('emergency', 'alert', 'critical', 'error', 'warning', 'debug'), 'stream' => $this->stderr, )); } + +/** + * Checks if the given logger is configured + * + * @param string $logger The name of the logger to check + * @return bool + */ + protected function _loggerIsConfigured($logger) { + $configured = CakeLog::configured(); + return in_array($logger, $configured); + } } diff --git a/web/api/lib/Cake/Console/ShellDispatcher.php b/web/api/lib/Cake/Console/ShellDispatcher.php index d53851127..9f21befb2 100644 --- a/web/api/lib/Cake/Console/ShellDispatcher.php +++ b/web/api/lib/Cake/Console/ShellDispatcher.php @@ -2,17 +2,17 @@ /** * ShellDispatcher file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** @@ -106,7 +106,7 @@ class ShellDispatcher { $message = "This file has been loaded incorrectly and cannot continue.\n" . "Please make sure that " . DS . 'lib' . DS . 'Cake' . DS . "Console is in your system path,\n" . "and check the cookbook for the correct usage of this command.\n" . - "(http://book.cakephp.org/)"; + "(https://book.cakephp.org/)"; throw new CakeException($message); } @@ -129,15 +129,22 @@ class ShellDispatcher { define('APP', $this->params['working'] . DS); } if (!defined('WWW_ROOT')) { - define('WWW_ROOT', APP . $this->params['webroot'] . DS); + if (!$this->_isAbsolutePath($this->params['webroot'])) { + $webroot = realpath(APP . $this->params['webroot']); + } else { + $webroot = $this->params['webroot']; + } + define('WWW_ROOT', $webroot . DS); } if (!defined('TMP') && !is_dir(APP . 'tmp')) { define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS); } + + // $boot is used by Cake/bootstrap.php file $boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php'); require CORE_PATH . 'Cake' . DS . 'bootstrap.php'; - if (!file_exists(APP . 'Config' . DS . 'core.php')) { + if (!file_exists(CONFIG . 'core.php')) { include_once CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'Config' . DS . 'core.php'; App::build(); } @@ -305,25 +312,45 @@ class ShellDispatcher { } } - if ($params['app'][0] === '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) { + if ($this->_isAbsolutePath($params['app'])) { $params['root'] = dirname($params['app']); } elseif (strpos($params['app'], '/')) { $params['root'] .= '/' . dirname($params['app']); } - + $isWindowsAppPath = $this->_isWindowsPath($params['app']); $params['app'] = basename($params['app']); $params['working'] = rtrim($params['root'], '/'); if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) { $params['working'] .= '/' . $params['app']; } - if (!empty($matches[0]) || !empty($isWin)) { + if ($isWindowsAppPath || !empty($isWin)) { $params = str_replace('/', '\\', $params); } $this->params = $params + $this->params; } +/** + * Checks whether the given path is absolute or relative. + * + * @param string $path absolute or relative path. + * @return bool + */ + protected function _isAbsolutePath($path) { + return $path[0] === '/' || $this->_isWindowsPath($path); + } + +/** + * Checks whether the given path is Window OS path. + * + * @param string $path absolute path. + * @return bool + */ + protected function _isWindowsPath($path) { + return preg_match('/([a-z])(:)/i', $path) == 1; + } + /** * Parses out the paths from from the argv * @@ -332,7 +359,7 @@ class ShellDispatcher { */ protected function _parsePaths($args) { $parsed = array(); - $keys = array('-working', '--working', '-app', '--app', '-root', '--root'); + $keys = array('-working', '--working', '-app', '--app', '-root', '--root', '-webroot', '--webroot'); $args = (array)$args; foreach ($keys as $key) { while (($index = array_search($key, $args)) !== false) { diff --git a/web/api/lib/Cake/Console/TaskCollection.php b/web/api/lib/Cake/Console/TaskCollection.php index 3fafddd13..5d2e7a7a9 100644 --- a/web/api/lib/Cake/Console/TaskCollection.php +++ b/web/api/lib/Cake/Console/TaskCollection.php @@ -3,17 +3,17 @@ * Task collection is used as a registry for loaded tasks and handles loading * and constructing task class objects. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ App::uses('ObjectCollection', 'Utility'); @@ -64,7 +64,7 @@ class TaskCollection extends ObjectCollection { * * @param string $task Task name to load * @param array $settings Settings for the task. - * @return Task A task object, Either the existing loaded task or a new one. + * @return AppShell A task object, Either the existing loaded task or a new one. * @throws MissingTaskException when the task could not be found */ public function load($task, $settings = array()) { diff --git a/web/api/lib/Cake/Console/Templates/default/actions/controller_actions.ctp b/web/api/lib/Cake/Console/Templates/default/actions/controller_actions.ctp index dfc309215..8a943b9e7 100644 --- a/web/api/lib/Cake/Console/Templates/default/actions/controller_actions.ctp +++ b/web/api/lib/Cake/Console/Templates/default/actions/controller_actions.ctp @@ -2,18 +2,18 @@ /** * Bake Template for Controller action generation. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Console.Templates.default.actions * @since CakePHP(tm) v 1.3 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ ?> diff --git a/web/api/lib/Cake/Console/Templates/default/classes/controller.ctp b/web/api/lib/Cake/Console/Templates/default/classes/controller.ctp index 6beb4b401..30a9846d3 100644 --- a/web/api/lib/Cake/Console/Templates/default/classes/controller.ctp +++ b/web/api/lib/Cake/Console/Templates/default/classes/controller.ctp @@ -4,18 +4,18 @@ * * Allows templating of Controllers generated from bake. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package Cake.Console.Templates.default.classes * @since CakePHP(tm) v 1.3 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ echo "
diff --git a/web/api/lib/Cake/Console/Templates/default/views/index.ctp b/web/api/lib/Cake/Console/Templates/default/views/index.ctp index cf77c0ed9..72277141f 100644 --- a/web/api/lib/Cake/Console/Templates/default/views/index.ctp +++ b/web/api/lib/Cake/Console/Templates/default/views/index.ctp @@ -1,17 +1,17 @@
diff --git a/web/api/lib/Cake/Console/Templates/default/views/view.ctp b/web/api/lib/Cake/Console/Templates/default/views/view.ctp index 3acfad8be..b229b9f11 100644 --- a/web/api/lib/Cake/Console/Templates/default/views/view.ctp +++ b/web/api/lib/Cake/Console/Templates/default/views/view.ctp @@ -1,17 +1,17 @@
diff --git a/web/api/lib/Cake/Console/Templates/skel/.htaccess b/web/api/lib/Cake/Console/Templates/skel/.htaccess deleted file mode 100644 index 128e7871b..000000000 --- a/web/api/lib/Cake/Console/Templates/skel/.htaccess +++ /dev/null @@ -1,5 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ webroot/ [L] - RewriteRule (.*) webroot/$1 [L] - \ No newline at end of file diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php index 9a4f54337..12ad8ee98 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php @@ -4,7 +4,7 @@ * * Use it to configure database for ACL * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config.Schema * @since CakePHP(tm) v 0.2.9 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql index 0bf3f7687..cbb0ccece 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql +++ b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql @@ -1,11 +1,11 @@ # $Id$ # -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. -# MIT License (http://www.opensource.org/licenses/mit-license.php) +# MIT License (https://opensource.org/licenses/mit-license.php) CREATE TABLE acos ( id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.php b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.php index cd598b35e..63dc0db9f 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.php @@ -4,18 +4,18 @@ * * Use it to configure database for i18n * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config.Schema * @since CakePHP(tm) v 0.2.9 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql index 66a42bd19..a1a4e6893 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql +++ b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql @@ -1,11 +1,11 @@ # $Id$ # -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. -# MIT License (http://www.opensource.org/licenses/mit-license.php) +# MIT License (https://opensource.org/licenses/mit-license.php) CREATE TABLE i18n ( id int(10) NOT NULL auto_increment, diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.php b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.php index bd7b1efc3..b766ebff0 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.php @@ -4,18 +4,18 @@ * * Use it to configure database for Sessions * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config.Schema * @since CakePHP(tm) v 0.2.9 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ /** diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql index 76845bdc8..e19755622 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql +++ b/web/api/lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql @@ -1,13 +1,13 @@ # $Id$ # -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # 1785 E. Sahara Avenue, Suite 490-204 # Las Vegas, Nevada 89104 # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. -# MIT License (http://www.opensource.org/licenses/mit-license.php) +# MIT License (https://opensource.org/licenses/mit-license.php) CREATE TABLE cake_sessions ( id varchar(255) NOT NULL default '', diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/acl.ini.php b/web/api/lib/Cake/Console/Templates/skel/Config/acl.ini.php index 5f37e1c97..1f9315869 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/acl.ini.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/acl.ini.php @@ -2,7 +2,7 @@ ;/** ; * ACL Configuration ; * -; * @link http://cakephp.org CakePHP(tm) Project +; * @link https://cakephp.org CakePHP(tm) Project ; * @package app.Config ; * @since CakePHP(tm) v 0.10.0.1076 ; */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/acl.php b/web/api/lib/Cake/Console/Templates/skel/Config/acl.php index d008979c9..2fe93fea4 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/acl.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/acl.php @@ -4,7 +4,7 @@ * * Use it to configure access control of your CakePHP application. * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 2.1 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/bootstrap.php b/web/api/lib/Cake/Console/Templates/skel/Config/bootstrap.php index 0cf81bec3..6d05aabbb 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/bootstrap.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/bootstrap.php @@ -8,7 +8,7 @@ * You should also use this file to include any files that provide global functions/constants * that your application uses. * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 0.10.8.2117 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/core.php b/web/api/lib/Cake/Console/Templates/skel/Config/core.php index 18d645a33..864777666 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/core.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/core.php @@ -4,7 +4,7 @@ * * Use it to configure core behavior of Cake. * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 0.2.9 */ @@ -104,7 +104,7 @@ * will override the automatic detection of full base URL and can be * useful when generating links from the CLI (e.g. sending emails) */ - //Configure::write('App.fullBaseUrl', 'http://example.com'); + //Configure::write('App.fullBaseUrl', 'https://example.com'); /** * Web path to the public images directory under webroot. @@ -273,7 +273,7 @@ * 'mask' => 0664, //[optional] * )); * - * APC (http://pecl.php.net/package/APC) + * APC (https://pecl.php.net/package/APC) * * Cache::config('default', array( * 'engine' => 'Apc', //[required] @@ -282,7 +282,7 @@ * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string * )); * - * Xcache (http://xcache.lighttpd.net/) + * Xcache (https://xcache.lighttpd.net/) * * Cache::config('default', array( * 'engine' => 'Xcache', //[required] @@ -307,7 +307,7 @@ * 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory) * )); * - * Wincache (http://php.net/wincache) + * Wincache (https://secure.php.net/wincache) * * Cache::config('default', array( * 'engine' => 'Wincache', //[required] diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/database.php.default b/web/api/lib/Cake/Console/Templates/skel/Config/database.php.default index cc549a5f6..202b821e7 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/database.php.default +++ b/web/api/lib/Cake/Console/Templates/skel/Config/database.php.default @@ -1,6 +1,6 @@ * Array of key/value pairs, on connection it executes SET statements for each pair - * For MySQL : http://dev.mysql.com/doc/refman/5.6/en/set-statement.html - * For Postgres : http://www.postgresql.org/docs/9.2/static/sql-set.html - * For Sql Server : http://msdn.microsoft.com/en-us/library/ms190356.aspx + * For MySQL : https://dev.mysql.com/doc/refman/5.6/en/set-statement.html + * For Postgres : https://www.postgresql.org/docs/9.2/static/sql-set.html + * For Sql Server : https://msdn.microsoft.com/en-us/library/ms190356.aspx * * flags => * A key/value array of driver specific connection options. diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/email.php.default b/web/api/lib/Cake/Console/Templates/skel/Config/email.php.default index 0a01e38d0..aadb515d9 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/email.php.default +++ b/web/api/lib/Cake/Console/Templates/skel/Config/email.php.default @@ -4,7 +4,7 @@ * * Use it to configure email transports of Cake. * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 2.0.0 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Config/routes.php b/web/api/lib/Cake/Console/Templates/skel/Config/routes.php index 2562ebed6..ac19d9f51 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Config/routes.php +++ b/web/api/lib/Cake/Console/Templates/skel/Config/routes.php @@ -6,7 +6,7 @@ * Routes are very important mechanism that allows you to freely connect * different URLs to chosen controllers and their actions (functions). * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Config * @since CakePHP(tm) v 0.2.9 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/Command/AppShell.php b/web/api/lib/Cake/Console/Templates/skel/Console/Command/AppShell.php index 04a3430f0..f73c35afe 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Console/Command/AppShell.php +++ b/web/api/lib/Cake/Console/Templates/skel/Console/Command/AppShell.php @@ -2,7 +2,7 @@ /** * AppShell file * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @since CakePHP(tm) v 2.0 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/Command/Task/empty b/web/api/lib/Cake/Console/Templates/skel/Console/Command/Task/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/Templates/empty b/web/api/lib/Cake/Console/Templates/skel/Console/Templates/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/cake b/web/api/lib/Cake/Console/Templates/skel/Console/cake index 67454513d..fee8e35a3 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Console/cake +++ b/web/api/lib/Cake/Console/Templates/skel/Console/cake @@ -3,18 +3,18 @@ # # Bake is a shell script for running CakePHP bake script # -# CakePHP(tm) : Rapid Development Framework (http://cakephp.org) -# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) # # Licensed under The MIT License # For full copyright and license information, please see the LICENSE.txt # Redistributions of files must retain the above copyright notice. # -# @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) -# @link http://cakephp.org CakePHP(tm) Project +# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# @link https://cakephp.org CakePHP(tm) Project # @package app.Console # @since CakePHP(tm) v 1.2.0.5012 -# @license http://www.opensource.org/licenses/mit-license.php MIT License +# @license https://opensource.org/licenses/mit-license.php MIT License # ################################################################################ diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat b/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat index e37d4a524..31bde01b1 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat +++ b/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat @@ -2,14 +2,14 @@ :: :: Bake is a shell script for running CakePHP bake script :: -:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org) -:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) +:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) :: :: Licensed under The MIT License :: Redistributions of files must retain the above copyright notice. :: -:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) -:: @link http://cakephp.org CakePHP(tm) Project +:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: @link https://cakephp.org CakePHP(tm) Project :: @package app.Console :: @since CakePHP(tm) v 2.0 :: diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/cake.php b/web/api/lib/Cake/Console/Templates/skel/Console/cake.php index f5b262a2a..280613a27 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Console/cake.php +++ b/web/api/lib/Cake/Console/Templates/skel/Console/cake.php @@ -3,15 +3,15 @@ /** * Command-line code generation utility to automate programmer chores. * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Console * @since CakePHP(tm) v 2.0 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Controller/AppController.php b/web/api/lib/Cake/Console/Templates/skel/Controller/AppController.php index db4b9e2c3..4e927f693 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Controller/AppController.php +++ b/web/api/lib/Cake/Console/Templates/skel/Controller/AppController.php @@ -5,7 +5,7 @@ * This file is application-wide controller file. You can put all * application-wide controller-related methods here. * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Controller * @since CakePHP(tm) v 0.2.9 */ @@ -19,7 +19,7 @@ App::uses('Controller', 'Controller'); * will inherit them. * * @package app.Controller - * @link http://book.cakephp.org/2.0/en/controllers.html#the-app-controller + * @link https://book.cakephp.org/2.0/en/controllers.html#the-app-controller */ class AppController extends Controller { } diff --git a/web/api/lib/Cake/Console/Templates/skel/Controller/Component/empty b/web/api/lib/Cake/Console/Templates/skel/Controller/Component/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Controller/PagesController.php b/web/api/lib/Cake/Console/Templates/skel/Controller/PagesController.php index eb023a573..75df741de 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Controller/PagesController.php +++ b/web/api/lib/Cake/Console/Templates/skel/Controller/PagesController.php @@ -4,7 +4,7 @@ * * This file will render views from views/pages/ * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Controller * @since CakePHP(tm) v 0.2.9 */ @@ -17,7 +17,7 @@ App::uses('AppController', 'Controller'); * Override this controller by placing a copy in controllers directory of an application * * @package app.Controller - * @link http://book.cakephp.org/2.0/en/controllers/pages-controller.html + * @link https://book.cakephp.org/2.0/en/controllers/pages-controller.html */ class PagesController extends AppController { @@ -32,6 +32,7 @@ class PagesController extends AppController { * Displays a view * * @return void + * @throws ForbiddenException When a directory traversal attempt. * @throws NotFoundException When the view file could not be found * or MissingViewException in debug mode. */ @@ -42,6 +43,9 @@ class PagesController extends AppController { if (!$count) { return $this->redirect('/'); } + if (in_array('..', $path, true) || in_array('.', $path, true)) { + throw new ForbiddenException(); + } $page = $subpage = $title_for_layout = null; if (!empty($path[0])) { diff --git a/web/api/lib/Cake/Console/Templates/skel/Lib/empty b/web/api/lib/Cake/Console/Templates/skel/Lib/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Locale/eng/LC_MESSAGES/empty b/web/api/lib/Cake/Console/Templates/skel/Locale/eng/LC_MESSAGES/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Model/AppModel.php b/web/api/lib/Cake/Console/Templates/skel/Model/AppModel.php index eef715013..cc5ca8fb5 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Model/AppModel.php +++ b/web/api/lib/Cake/Console/Templates/skel/Model/AppModel.php @@ -5,7 +5,7 @@ * This file is application-wide model file. You can put all * application-wide model-related methods here. * - * @link http://cakephp.org CakePHP(tm) Project + * @link https://cakephp.org CakePHP(tm) Project * @package app.Model * @since CakePHP(tm) v 0.2.9 */ diff --git a/web/api/lib/Cake/Console/Templates/skel/Model/Behavior/empty b/web/api/lib/Cake/Console/Templates/skel/Model/Behavior/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Model/Datasource/empty b/web/api/lib/Cake/Console/Templates/skel/Model/Datasource/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Plugin/empty b/web/api/lib/Cake/Console/Templates/skel/Plugin/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Test/Case/AllTestsTest.php b/web/api/lib/Cake/Console/Templates/skel/Test/Case/AllTestsTest.php index 9929fa582..98b803cc1 100644 --- a/web/api/lib/Cake/Console/Templates/skel/Test/Case/AllTestsTest.php +++ b/web/api/lib/Cake/Console/Templates/skel/Test/Case/AllTestsTest.php @@ -2,18 +2,18 @@ /** * AllTests file * - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @package app.Test.Case * @since CakePHP(tm) v 2.5 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://opensource.org/licenses/mit-license.php MIT License */ class AllTestsTest extends CakeTestSuite { diff --git a/web/api/lib/Cake/Console/Templates/skel/Test/Case/Controller/Component/empty b/web/api/lib/Cake/Console/Templates/skel/Test/Case/Controller/Component/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Test/Case/Model/Behavior/empty b/web/api/lib/Cake/Console/Templates/skel/Test/Case/Model/Behavior/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Test/Case/View/Helper/empty b/web/api/lib/Cake/Console/Templates/skel/Test/Case/View/Helper/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Test/Fixture/empty b/web/api/lib/Cake/Console/Templates/skel/Test/Fixture/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/Vendor/empty b/web/api/lib/Cake/Console/Templates/skel/Vendor/empty new file mode 100644 index 000000000..e69de29bb diff --git a/web/api/lib/Cake/Console/Templates/skel/View/Emails/html/default.ctp b/web/api/lib/Cake/Console/Templates/skel/View/Emails/html/default.ctp index a1333dc19..f4dd9e6ae 100644 --- a/web/api/lib/Cake/Console/Templates/skel/View/Emails/html/default.ctp +++ b/web/api/lib/Cake/Console/Templates/skel/View/Emails/html/default.ctp @@ -1,17 +1,17 @@ \ No newline at end of file diff --git a/web/api/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp b/web/api/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp index 6c84d88fa..ff6730d08 100644 --- a/web/api/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp +++ b/web/api/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp @@ -1,6 +1,6 @@ fetch('content'); ?> -

This email was sent using the CakePHP Framework

+

This email was sent using the CakePHP Framework

\ No newline at end of file diff --git a/web/api/lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp b/web/api/lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp index 539615895..82a1e195b 100644 --- a/web/api/lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp +++ b/web/api/lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp @@ -1,19 +1,19 @@ fetch('content'); ?> -This email was sent using the CakePHP Framework, http://cakephp.org. +This email was sent using the CakePHP Framework, https://cakephp.org. diff --git a/web/api/lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp b/web/api/lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp index f2338e66e..950d4d9e7 100644 --- a/web/api/lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp +++ b/web/api/lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp @@ -1,6 +1,6 @@
@@ -39,7 +39,7 @@ $cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework