From cbc1636b110370f33ff5842f1ed27fd17124eb95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Sun, 7 May 2017 23:31:38 +0200 Subject: [PATCH 01/18] Update danish translation file --- web/lang/dk_dk.php | 1441 +++++++++++++++++++++++--------------------- 1 file changed, 741 insertions(+), 700 deletions(-) diff --git a/web/lang/dk_dk.php b/web/lang/dk_dk.php index 54ad0df31..605f9fb19 100644 --- a/web/lang/dk_dk.php +++ b/web/lang/dk_dk.php @@ -18,7 +18,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -// ZoneMinder Danish Translation by Tom Stage +// ZoneMinder Danish Translation by Jørgen Edelbo // Notes for Translators // 0. Get some credit, put your name in the line above (optional) @@ -50,8 +50,8 @@ // do this by default, uncomment this if required. // // Example -// header( "Content-Type: text/html; charset=iso-8859-1" ); -header( "Content-Type: text/html; charset=windows-1252" ); +header( "Content-Type: text/html; charset=utf-8" ); +// header( "Content-Type: text/html; charset=windows-1252" ); // You may need to change your locale here if your default one is incorrect for the // language described in this file, or if you have multiple languages supported. @@ -72,704 +72,720 @@ header( "Content-Type: text/html; charset=windows-1252" ); // Simple String Replacements $SLANG = array( - '24BitColour' => '24 bit farve', - '32BitColour' => '32 bit farve', // Added - 2011-06-15 - '8BitGrey' => '8 bit greyscale', - 'Action' => 'Action', - 'Actual' => 'Aktuel', - 'AddNewControl' => 'Tilføj Ny kontrol', - 'AddNewMonitor' => 'Tilføj Ny Monitor', - 'AddNewUser' => 'Tilføj Ny Bruger', - 'AddNewZone' => 'Tilføj Ny Zone', - 'Alarm' => 'Alarm', - 'AlarmBrFrames' => 'Alarm
Billeder', - 'AlarmFrame' => 'Alarm Billede', - 'AlarmFrameCount' => 'Alarm Billede Tæller', - 'AlarmLimits' => 'Alarm Begrændsing', - 'AlarmMaximumFPS' => 'Alarm Maximum FPS', - 'AlarmPx' => 'Alarm Px', - 'AlarmRGBUnset' => 'You must set an alarm RGB colour', - 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 - 'Alert' => 'Alarm', - 'All' => 'Alle', - 'AnalysisFPS' => 'Analysis FPS', // Added - 2015-07-22 - 'AnalysisUpdateDelay' => 'Analysis Update Delay', // Added - 2015-07-23 - 'Apply' => 'Aktiver', - 'ApplyingStateChange' => 'Aktivere State Ændring', - 'ArchArchived' => 'Kun Arkiverede', - 'ArchUnarchived' => 'Kun Ikke Arkiverede', - 'Archive' => 'Arkiver', - 'Archived' => 'Archived', - 'Area' => 'Area', - 'AreaUnits' => 'Area (px/%)', - 'AttrAlarmFrames' => 'Alarm Billeder', - 'AttrArchiveStatus' => 'Arkiverings Status', - 'AttrAvgScore' => 'Avg. Skore', - 'AttrCause' => 'Årsag', - 'AttrDate' => 'Dato', - 'AttrDateTime' => 'Dato/Tid', - 'AttrDiskBlocks' => 'Disk Blocks', - 'AttrDiskPercent' => 'Disk Procent', - 'AttrDuration' => 'Forløb', - 'AttrFrames' => 'Billeder', - 'AttrId' => 'Id', - 'AttrMaxScore' => 'Max. Skore', - 'AttrMonitorId' => 'Monitor Id', - 'AttrMonitorName' => 'Monitor Navn', - 'AttrName' => 'Navn', - 'AttrNotes' => 'Notes', - 'AttrSystemLoad' => 'System Load', - 'AttrTime' => 'Tid', - 'AttrTotalScore' => 'Total Skore', - 'AttrWeekday' => 'Uge Dag', - 'Auto' => 'Auto', - 'AutoStopTimeout' => 'Auto Stop Timeout', - 'Available' => 'Available', // Added - 2009-03-31 - 'AvgBrScore' => 'Avg.
Skore', - 'Background' => 'Background', - 'BackgroundFilter' => 'Run filter in background', - 'BadAlarmFrameCount' => 'Alarm frame count must be an integer of one or more', - 'BadAlarmMaxFPS' => 'Alarm Maximum FPS must be a positive integer or floating point value', - 'BadAnalysisFPS' => 'Analysis FPS must be a positive integer or floating point value', // Added - 2015-07-22 - 'BadAnalysisUpdateDelay'=> 'Analysis update delay must be set to an integer of zero or more', // Added - 2015-07-23 - 'BadChannel' => 'Channel must be set to an integer of zero or more', - 'BadColours' => 'Target colour must be set to a valid value', // Added - 2011-06-15 - 'BadDevice' => 'Device must be set to a valid value', - 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', - 'BadFormat' => 'Format must be set to an integer of zero or more', - 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadHeight' => 'Height must be set to a valid value', - 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', - 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', - 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', - 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', - 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', - 'BadNameChars' => 'Navne må kun indeholde alphanumeric karaktere, rum plus hyphen og underscore', - 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 - 'BadPath' => 'Path must be set to a valid value', - 'BadPort' => 'Port must be set to a valid number', - 'BadPostEventCount' => 'Post event image count must be an integer of zero or more', - 'BadPreEventCount' => 'Pre event image count must be at least zero, and less than image buffer size', - 'BadRefBlendPerc' => 'Reference blend percentage must be a positive integer', - 'BadSectionLength' => 'Section length must be an integer of 30 or more', - 'BadSignalCheckColour' => 'Signal check colour must be a valid RGB colour string', - 'BadStreamReplayBuffer'=> 'Stream replay buffer must be an integer of zero or more', - 'BadWarmupCount' => 'Warmup frames must be an integer of zero or more', - 'BadWebColour' => 'Web colour must be a valid web colour string', - 'BadWidth' => 'Width must be set to a valid value', - 'Bandwidth' => 'Båndbrede', - 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing - 'BlobPx' => 'Blob Px', - 'BlobSizes' => 'Blob Størelse', - 'Blobs' => 'Blobs', - 'Brightness' => 'Brightness', - 'Buffer' => 'Buffer', // Added - 2015-04-18 - 'Buffers' => 'Buffere', - 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 - 'CanAutoFocus' => 'Kan Auto Focus', - 'CanAutoGain' => 'Kan Auto Gain', - 'CanAutoIris' => 'Kan Auto Iris', - 'CanAutoWhite' => 'Kan Auto White Bal.', - 'CanAutoZoom' => 'Kan Auto Zoom', - 'CanFocus' => 'Kan Focus', - 'CanFocusAbs' => 'Kan Focus Absolut', - 'CanFocusCon' => 'Kan Focus Kontinuerligt', - 'CanFocusRel' => 'Kan Focus Relativt', - 'CanGain' => 'Kan Gain ', - 'CanGainAbs' => 'Kan Gain Absolut', - 'CanGainCon' => 'Kan Gain Kontinuerligt', - 'CanGainRel' => 'Kan Gain Relativt', - 'CanIris' => 'Kan Iris', - 'CanIrisAbs' => 'Kan Iris Absolut', - 'CanIrisCon' => 'Kan Iris Kontinuerligt', - 'CanIrisRel' => 'Kan Iris Relativt', - 'CanMove' => 'Kan Bevæge', - 'CanMoveAbs' => 'Kan Bevæge Absolut', - 'CanMoveCon' => 'Kan Bevæge Kontinuerligt', - 'CanMoveDiag' => 'Kan Bevæge Diagonalt', - 'CanMoveMap' => 'Kan Bevæge Mapped', - 'CanMoveRel' => 'Kan Bevæge Relativt', - 'CanPan' => 'Kan Pan' , - 'CanReset' => 'Kan Reset', - 'CanSetPresets' => 'Kan Set Presets', - 'CanSleep' => 'Kan Sove', - 'CanTilt' => 'Kan Tilt', - 'CanWake' => 'Kan Vågne', - 'CanWhite' => 'Kan White Balance', - 'CanWhiteAbs' => 'Kan White Bal. Absolut', - 'CanWhiteBal' => 'Kan White Bal.', - 'CanWhiteCon' => 'Kan White Bal. Kontinuerligt', - 'CanWhiteRel' => 'Kan White Bal. Relativt', - 'CanZoom' => 'Kan Zoom', - 'CanZoomAbs' => 'Kan Zoom Absolut', - 'CanZoomCon' => 'Kan Zoom Kontinuerligt', - 'CanZoomRel' => 'Kan Zoom Relativt', - 'Cancel' => 'Fortryd', - 'CancelForcedAlarm' => 'Fortryd Forced Alarm', - 'CaptureHeight' => 'Capture Height', - 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 - 'CapturePalette' => 'Capture Palette', - 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 - 'CaptureWidth' => 'Capture Width', - 'Cause' => 'Årsag', - 'CheckMethod' => 'Alarm Check Methode', - 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 - 'ChooseFilter' => 'Vælg Filter', - 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 - 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 - 'ChoosePreset' => 'Choose Preset', - 'Clear' => 'Clear', // Added - 2011-06-16 - 'Close' => 'Luk', - 'Colour' => 'Farve', - 'Command' => 'Kommando', - 'Component' => 'Component', // Added - 2011-06-16 - 'Config' => 'konfig', - 'ConfiguredFor' => 'Konfigureret for', - 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', - 'ConfirmPassword' => 'Verifiser Password', - 'ConjAnd' => 'og', - 'ConjOr' => 'eller', - 'Console' => 'Konsol', - 'ContactAdmin' => 'Kontakt Din adminstrator for detalier.', - 'Continue' => 'Fortsæt', - 'Contrast' => 'Kontrast', - 'Control' => 'Kontrol', - 'ControlAddress' => 'Kontrol Addresse', - 'ControlCap' => 'Kontrol Capability', - 'ControlCaps' => 'Kontrol Capabilities', - 'ControlDevice' => 'Kontrol Enhed', - 'ControlType' => 'Kontrol Type', - 'Controllable' => 'Controllable', - 'Current' => 'Current', // Added - 2015-04-18 - 'Cycle' => 'Cycle', - 'CycleWatch' => 'Cycle Watch', - 'DateTime' => 'Date/Time', // Added - 2011-06-16 - 'Day' => 'Dag', - 'Debug' => 'Debug', - 'DefaultRate' => 'Default Rate', - 'DefaultScale' => 'Default Scale', - 'DefaultView' => 'Default View', - 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 - 'Delay' => 'Delay', // Added - 2015-04-18 - 'Delete' => 'Slet', - 'DeleteAndNext' => 'Slet & Næste', - 'DeleteAndPrev' => 'Slet & Forrige', - 'DeleteSavedFilter' => 'Slet Gemte filter', - 'Description' => 'Beskrivelse', - 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 - 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 - 'Device' => 'Device', // Added - 2009-02-08 - 'DeviceChannel' => 'Enheds Kanal', - 'DeviceFormat' => 'Enheds Format', - 'DeviceNumber' => 'Enheds Nummer', - 'DevicePath' => 'Device Path', - 'Devices' => 'Devices', - 'Dimensions' => 'Dimentioner', - 'DisableAlarms' => 'Disable Alarms', - 'Disk' => 'Disk', - 'Display' => 'Display', // Added - 2011-01-30 - 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'SystemLog' => 'System Log', + 'DateTime' => 'Dato/Tid', + 'Component' => 'Komponent', + 'Pid' => 'PID', + 'Level' => 'Niveau', + 'Message' => 'Meddelelse', + 'Line' => 'Linie', + 'More' => 'Mere', + 'Clear' => 'Slet', + '24BitColour' => '24 bit farve', + '32BitColour' => '32 bit farve', + '8BitGrey' => '8 bit grÃ¥skala', + 'Action' => 'Handling', + 'Actual' => 'Aktuel', + 'AddNewControl' => 'Tilføj Ny Kontrol', + 'AddNewMonitor' => 'Tilføj Ny Monitor', + 'AddNewServer' => 'Tilføj Ny Server', + 'AddNewUser' => 'Tilføj Ny Bruger', + 'AddNewZone' => 'Tilføj Ny Zone', + 'Alarm' => 'Alarm', + 'AlarmBrFrames' => 'Alarm
Rammer', + 'AlarmFrame' => 'Alarm Ramme', + 'AlarmFrameCount' => 'Antal Alarm Rammer', + 'AlarmLimits' => 'Alarm Grænser', + 'AlarmMaximumFPS' => 'Alarm Maksimum FPS', + 'AlarmPx' => 'Alarm Px', + 'AlarmRefImageBlendPct' => 'Alarm Reference Billede Blandings %', + 'AlarmRGBUnset' => 'Du skal vælge en alarm RGB farve', + 'Alert' => 'Advarsel', + 'All' => 'Alle', + 'AnalysisFPS' => 'Analyse FPS', + 'AnalysisUpdateDelay' => 'Analyse Opdaterings Forsinkelse', + 'Apply' => 'Udfør', + 'ApplyingStateChange' => 'Udfører tilstandsændring', + 'ArchArchived' => 'Kun arkiverede', + 'Archive' => 'Arkivér', + 'Archived' => 'Arkiverede', + 'ArchUnarchived' => 'Kun ikke-arkiverede', + 'Area' => 'Område', + 'AreaUnits' => 'Område (px/%)', + 'AttrAlarmFrames' => 'Alarm Rammer', + 'AttrArchiveStatus' => 'Arkiverings Status', + 'AttrAvgScore' => 'Middel Score', + 'AttrCause' => 'Årsag', + 'AttrDate' => 'Dato', + 'AttrDateTime' => 'Dato/Tid', + 'AttrDiskBlocks' => 'Disk Blokke', + 'AttrDiskPercent' => 'Disk Procent', + 'AttrDuration' => 'Varighed', + 'AttrFrames' => 'Rammer', + 'AttrId' => 'Id', + 'AttrMaxScore' => 'Max. Score', + 'AttrMonitorId' => 'Monitor Id', + 'AttrMonitorName' => 'Monitor Navn', + 'AttrServer' => 'Server', + 'AttrName' => 'Navn', + 'AttrNotes' => 'Noter', + 'AttrSystemLoad' => 'System Belastning', + 'AttrTime' => 'Tid', + 'AttrTotalScore' => 'Total Score', + 'AttrWeekday' => 'Ugedag', + 'Auto' => 'Auto', + 'AutoStopTimeout' => 'Auto Stop Timeout', + 'Available' => 'Tilgængelig', + 'AvgBrScore' => 'Middel
Score', + 'Available' => 'Tilgængelig', + 'Background' => 'Baggrund', + 'BackgroundFilter' => 'Kør filteret i baggrunden', + 'BadAlarmFrameCount' => 'Antal alarm rammer skal være et positivt heltal', + 'BadAlarmMaxFPS' => 'Alarm Maximum FPS skal være et positivt heltal eller flydende tal', + 'BadAnalysisFPS' => 'Analyse FPS skal være et positivt heltal eller flydende tal', + 'BadAnalysisUpdateDelay'=> 'Analyse opdaterings forsinkelse skal være et heltal på 0 eller mere', + 'BadChannel' => 'Kanal skal sættes til et heltal på 0 eller mere', + 'BadDevice' => 'Enhed skal sættes til en gyldig værdi', + 'BadFormat' => 'Format skal sættes til en gyldig værdi', + 'BadFPSReportInterval' => 'Antal FPS report interval buffere skal være et heltal på 0 eller mere', + 'BadFrameSkip' => 'Antal Frame skip skal være et heltal på 0 eller mere', + 'BadMotionFrameSkip' => 'Antal Motion Frame skip skal være et heltal på 0 eller mere', + 'BadHeight' => 'Højde skal sættes til en gyldig værdi', + 'BadHost' => 'Host skal vare en gyldig IP adresse eller hostname, inkludér ikke http://', + 'BadImageBufferCount' => 'Billed buffer størrelse skal være et heltal på 10 eller mere', + 'BadLabelX' => 'Mærkat X co-ordinaten skal sættes til et heltal på 0 eller mere', + 'BadLabelY' => 'Mærkat Y co-ordinaten skal sættes til et heltal på 0 eller mere', + 'BadMaxFPS' => 'Maximum FPS skal være et positivt heltal eller flydende tal', + 'BadNameChars' => 'Navne kan kun indeholde alfanumeriske tegn samt mellemrum, bindestreg og understregning', + 'BadPalette' => 'Palette skal sættes til en gyldig værdi', + 'BadColours' => 'Målfarven skal sættes til en gyldig værdi', + 'BadPath' => 'Sti skal sættes til en gyldig værdi', + 'BadPort' => 'Port skal sættes til et gyldigt nummer', + 'BadPostEventCount' => 'Antal rammer efter hændelsen skal være et heltal på 0 eller mere', + 'BadPreEventCount' => 'Antal rammer før hændelsen skal være mindst 0 samt mindre en billedbufferstørrelsen', + 'BadRefBlendPerc' => 'Reference blandings procentdelen skal være et positivt heltal', + 'BadSectionLength' => 'Sektionslængden skal være et heltal på 30 eller mere', + 'BadSignalCheckColour' => 'Signal check farve skal være en gyldig RGB farve streng', + 'BadStreamReplayBuffer' => 'Videostrøm genspilsbufferen skal sættes til et heltal på 0 eller mere', + 'BadWarmupCount' => 'Opvarmnings rammer skal være et heltal på 0 eller mere', + 'BadWebColour' => 'Web farve skal være en gyldigt web farve streng', + 'BadWidth' => 'Bredde skal sættes til en gyldig værdi', + 'Bandwidth' => 'Båndbredde', + 'BandwidthHead' => 'Båndbredde', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing + 'BlobPx' => 'Blob Px', + 'Blobs' => 'Blobs', + 'BlobSizes' => 'Blob Størrelser', + 'Brightness' => 'Lysstyrke', + 'Buffer' => 'Buffer', + 'Buffers' => 'Buffere', + 'CanAutoFocus' => 'Can Auto Focus', + 'CanAutoGain' => 'Can Auto Gain', + 'CanAutoIris' => 'Can Auto Iris', + 'CanAutoWhite' => 'Can Auto White Bal.', + 'CanAutoZoom' => 'Can Auto Zoom', + 'Cancel' => 'Fortryd', + 'CancelForcedAlarm' => 'Fortryd Tvungen Alarm', + 'CanFocusAbs' => 'Can Focus Absolute', + 'CanFocus' => 'Can Focus', + 'CanFocusCon' => 'Can Focus Continuous', + 'CanFocusRel' => 'Can Focus Relative', + 'CanGainAbs' => 'Can Gain Absolute', + 'CanGain' => 'Can Gain ', + 'CanGainCon' => 'Can Gain Continuous', + 'CanGainRel' => 'Can Gain Relative', + 'CanIrisAbs' => 'Can Iris Absolute', + 'CanIris' => 'Can Iris', + 'CanIrisCon' => 'Can Iris Continuous', + 'CanIrisRel' => 'Can Iris Relative', + 'CanMoveAbs' => 'Can Move Absolute', + 'CanMove' => 'Can Move', + 'CanMoveCon' => 'Can Move Continuous', + 'CanMoveDiag' => 'Can Move Diagonally', + 'CanMoveMap' => 'Can Move Mapped', + 'CanMoveRel' => 'Can Move Relative', + 'CanPan' => 'Can Pan' , + 'CanReset' => 'Can Reset', + 'CanSetPresets' => 'Can Set Presets', + 'CanSleep' => 'Can Sleep', + 'CanTilt' => 'Can Tilt', + 'CanWake' => 'Can Wake', + 'CanWhiteAbs' => 'Can White Bal. Absolute', + 'CanWhiteBal' => 'Can White Bal.', + 'CanWhite' => 'Can White Balance', + 'CanWhiteCon' => 'Can White Bal. Continuous', + 'CanWhiteRel' => 'Can White Bal. Relative', + 'CanZoomAbs' => 'Can Zoom Absolute', + 'CanZoom' => 'Can Zoom', + 'CanZoomCon' => 'Can Zoom Continuous', + 'CanZoomRel' => 'Can Zoom Relative', + 'CaptureHeight' => 'Capture Højde', + 'CaptureMethod' => 'Capture Metode', + 'CaptureResolution' => 'Capture Opløsning', + 'CapturePalette' => 'Capture Palette', + 'CaptureWidth' => 'Capture Bredde', + 'Cause' => 'Årsag', + 'CheckMethod' => 'Alarm Check Metode', + 'ChooseDetectedCamera' => 'Vælg Fundet Kamera', + 'ChooseFilter' => 'Vælg Filter', + 'ChooseLogFormat' => 'Vælg et lognings format', + 'ChooseLogSelection' => 'Vælg et lognings udvælgelse', + 'ChoosePreset' => 'Vælg Forudindstilling', + 'CloneMonitor' => 'Klon Monitor', + 'Close' => 'Luk', + 'Colour' => 'Farve', + 'Command' => 'Kommando', + 'Config' => 'Konfigurer', + 'ConfiguredFor' => 'Konfigureret for', + 'ConfirmDeleteEvents' => 'Er du sikker på, at du vil slette de markerede hændelser?', + 'ConfirmPassword' => 'Bekræft Adgangskode', + 'ConjAnd' => 'og', + 'ConjOr' => 'eller', + 'Console' => 'Konsol', + 'ContactAdmin' => 'Venligst kontakt din administrator for detaljer.', + 'Continue' => 'Fortsæt', + 'Contrast' => 'Kontrast', + 'ControlAddress' => 'Control Address', + 'ControlCap' => 'Control Capability', + 'ControlCaps' => 'Control Capabilities', + 'Control' => 'Control', + 'ControlDevice' => 'Control Device', + 'Controllable' => 'Controllable', + 'ControlType' => 'Control Type', + 'Current' => 'Nuværende', + 'Cycle' => 'Cyklisk', + 'CycleWatch' => 'Cyklisk Overvågning', + 'Day' => 'Dag', + 'Debug' => 'Fejlfind', + 'DefaultRate' => 'Standard Rate', + 'DefaultScale' => 'Standard Skalering', + 'DefaultView' => 'Standard Visning', + 'Deinterlacing' => 'Deinterlacing', + 'RTSPDescribe' => 'Brug RTSP Response Media URL', + 'Delay' => 'Forsilkelse', + 'DeleteAndNext' => 'Slet & Næste', + 'DeleteAndPrev' => 'Slet & Forrige', + 'Delete' => 'Slet', + 'DeleteSavedFilter' => 'Slet gemt filter', + 'Description' => 'Beskrivelse', + 'DetectedCameras' => 'Fundne Kameraer', + 'DetectedProfiles' => 'Fundne Profiler', + 'DeviceChannel' => 'Enheds Kanal', + 'DeviceFormat' => 'Enheds Format', + 'DeviceNumber' => 'Enheds Number', + 'DevicePath' => 'Sti Til Enhed', + 'Device' => 'Enheds', + 'Devices' => 'Enheder', + 'Dimensions' => 'Dimensioner', + 'DisableAlarms' => 'Deaktiver Alarmer', + 'Disk' => 'Disk', + 'Display' => 'Display', + 'Displaying' => 'Displaying', + 'DonateAlready' => 'Nej, jeg har allerede doneret', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'Donate' => 'Venligst Donér', + 'DonateRemindDay' => 'Ikke endnu, påmind igen on 1 dag', + 'DonateRemindHour' => 'Ikke endnu, påmind igen on 1 time', + 'DonateRemindMonth' => 'Ikke endnu, påmind igen on 1 måned', + 'DonateRemindNever' => 'Nej, jeg ønsker ikke at donere, påmind ikke igen', + 'DonateRemindWeek' => 'Ikke endnu, påmind igen on 1 uge', + 'DonateYes' => 'Ja, jeg vil gerne donere nu', 'DoNativeMotionDetection'=> 'Do Native Motion Detection', - 'Donate' => 'Please Donate', - 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', - 'DonateRemindDay' => 'Not yet, remind again in 1 day', - 'DonateRemindHour' => 'Not yet, remind again in 1 hour', - 'DonateRemindMonth' => 'Not yet, remind again in 1 month', - 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', - 'DonateRemindWeek' => 'Not yet, remind again in 1 week', - 'DonateYes' => 'Yes, I\'d like to donate now', - 'Download' => 'Download', - 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 - 'Duration' => 'Forløb', - 'Edit' => 'Rediger', - 'Email' => 'Email', - 'EnableAlarms' => 'Enable Alarms', - 'Enabled' => 'Aktiv', - 'EnterNewFilterName' => 'Skriv Nyt filter navn', - 'Error' => 'Fejl', - 'ErrorBrackets' => 'Fejl, check at du har lige antal af Åbnings og Lukkende brackets', - 'ErrorValidValue' => 'Fejl, check at alle terms har en valid værdig', - 'Etc' => 'etc', - 'Event' => 'Event', - 'EventFilter' => 'Event Filter', - 'EventId' => 'Event Id', - 'EventName' => 'Event Navn', - 'EventPrefix' => 'Event Prefix', - 'Events' => 'Events', - 'Exclude' => 'Exclude', - 'Execute' => 'Execute', - 'Export' => 'Export', - 'ExportDetails' => 'Export Event Details', - 'ExportFailed' => 'Export Failed', - 'ExportFormat' => 'Export File Format', - 'ExportFormatTar' => 'Tar', - 'ExportFormatZip' => 'Zip', - 'ExportFrames' => 'Export Frame Details', - 'ExportImageFiles' => 'Export Image Files', - 'ExportLog' => 'Export Log', // Added - 2011-06-17 - 'ExportMiscFiles' => 'Export Other Files (if present)', - 'ExportOptions' => 'Export Options', - 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 - 'ExportVideoFiles' => 'Export Video Files (if present)', - 'Exporting' => 'Exporting', - 'FPS' => 'fps', - 'FPSReportInterval' => 'FPS Raport Interval', - 'FTP' => 'FTP', - 'Far' => 'Far', - 'FastForward' => 'Fast Forward', - 'Feed' => 'Feed', - 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 - 'File' => 'File', - 'Filter' => 'Filter', // Added - 2015-04-18 - 'FilterArchiveEvents' => 'Arkiver alle matchende', - 'FilterDeleteEvents' => 'Slet alle matchende', - 'FilterEmailEvents' => 'Email detalier af alle matchende', - 'FilterExecuteEvents' => 'Kør kommando på alle matchende', - 'FilterLog' => 'Filter log', // Added - 2015-04-18 - 'FilterMessageEvents' => 'Send detalier af alle matchende', - 'FilterPx' => 'Filter Px', - 'FilterUnset' => 'You must specify a filter width and height', - 'FilterUploadEvents' => 'Upload alle matchende', - 'FilterVideoEvents' => 'Create video for all matches', - 'Filters' => 'Filters', - 'First' => 'Første', - 'FlippedHori' => 'Flipped Horizontally', - 'FlippedVert' => 'Flipped Vertically', - 'FnMocord' => 'Mocord', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'Download' => 'Download', + 'DuplicateMonitorName' => 'Dupliket Monitor Navn', + 'Duration' => 'Varighed', + 'Edit' => 'Ret', + 'Email' => 'Email', + 'EnableAlarms' => 'Aktivér Alarmer', + 'Enabled' => 'Virksom', + 'EnterNewFilterName' => 'Indtast nyt filternavn', + 'ErrorBrackets' => 'Fejl, venligst check, at du har samme antal open og lukke klammer', + 'Error' => 'Fejl', + 'ErrorValidValue' => 'Fejl, venligst check at alle parametre har en gyldig værdi', + 'Etc' => 'etc', + 'Event' => 'Hændelse', + 'EventFilter' => 'Hændelses Filter', + 'EventId' => 'Hændelses Id', + 'EventName' => 'Hændelses Name', + 'EventPrefix' => 'Hændelses Prefix', + 'Events' => 'Hændelser', + 'Exclude' => 'Ekskluder', + 'Execute' => 'Udfør', + 'ExportDetails' => 'Exporter Hændelses Detaljer', + 'Exif' => 'Indlejre EXIF data i billede', + 'Export' => 'Exporter', + 'ExportFailed' => 'Export Mislykkedes', + 'ExportFormat' => 'Export Fil Format', + 'ExportFormatTar' => 'Tar', + 'ExportFormatZip' => 'Zip', + 'ExportFrames' => 'Exporter Ramme Detaljer', + 'ExportImageFiles' => 'Exporter billed filer', + 'ExportLog' => 'Export Log', + 'Exporting' => 'Exporterer', + 'ExportMiscFiles' => 'Exporter Andre Filer (hvis tilstede)', + 'ExportOptions' => 'Export Indstillinger', + 'ExportSucceeded' => 'Export Lykkedes', + 'ExportVideoFiles' => 'Exporter Video Filer (hvis tilstede)', + 'Far' => 'Fjern', + 'FastForward' => 'Hurtigt Frem', + 'Feed' => 'Feed', + 'Ffmpeg' => 'Ffmpeg', + 'File' => 'Fil', + 'FilterArchiveEvents' => 'Arkiver alle matchende', + 'FilterDeleteEvents' => 'Slet alle matchende', + 'FilterEmailEvents' => 'Email detaljer for alle matchende', + 'FilterExecuteEvents' => 'Udfør kommando for alle matchende', + 'FilterLog' => 'Filter log', + 'FilterMessageEvents' => 'Meddel detaljer for alle matchende', + 'FilterPx' => 'Filter Px', + 'Filter' => 'Filter', + 'Filters' => 'Filtre', + 'FilterUnset' => 'Du skal angive filter bredde og højde', + 'FilterUploadEvents' => 'Upload alle match', + 'FilterVideoEvents' => 'Opret video for alle match', + 'First' => 'Første', + 'FlippedHori' => 'Spejlet Horizontalt', + 'FlippedVert' => 'Spejlet Vertikalt', 'FnNone' => 'None', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. 'FnRecord' => 'Record', // Added 2013.08.16. - 'Focus' => 'Fokus', - 'ForceAlarm' => 'Tving Alarm', - 'Format' => 'Format', - 'Frame' => 'Billede', - 'FrameId' => 'Billede Id', - 'FrameRate' => 'Billede Rate', - 'FrameSkip' => 'Billede Skip', - 'Frames' => 'Billede', - 'Func' => 'Func', - 'Function' => 'Funktion', - 'Gain' => 'Gain', - 'General' => 'General', - 'GenerateVideo' => 'Generer Video', - 'GeneratingVideo' => 'Generere Video', - 'GoToZoneMinder' => 'Gå til ZoneMinder.com', - 'Grey' => 'Grå', - 'Group' => 'Group', - 'Groups' => 'Grupper', - 'HasFocusSpeed' => 'Har Fokus Hastighed', - 'HasGainSpeed' => 'Har Gain Hastighed', - 'HasHomePreset' => 'Har Hjem Preset', - 'HasIrisSpeed' => 'Har Iris Hastighed', - 'HasPanSpeed' => 'Har Pan Hastighed', - 'HasPresets' => 'Har Presets', - 'HasTiltSpeed' => 'Har Tilt Hastighed', - 'HasTurboPan' => 'Har Turbo Pan', - 'HasTurboTilt' => 'Har Turbo Tilt', - 'HasWhiteSpeed' => 'Har White Bal. Hastighed', - 'HasZoomSpeed' => 'Har Zoom Hastighed', - 'High' => 'Høj', - 'HighBW' => 'Høj B/B', - 'Home' => 'Hjem', - 'Hour' => 'Time', - 'Hue' => 'Hue', - 'Id' => 'Id', - 'Idle' => 'Idle', - 'Ignore' => 'Ignorer', - 'Image' => 'Billede', - 'ImageBufferSize' => 'Billede Buffer Størelse (Billeder)', - 'Images' => 'Images', - 'In' => 'Ind', - 'Include' => 'Inkluder', - 'Inverted' => 'Inverteret', - 'Iris' => 'Iris', - 'KeyString' => 'Key String', - 'Label' => 'Label', - 'Language' => 'Sprog', - 'Last' => 'Sidste', - 'Layout' => 'Layout', // Added - 2009-02-08 - 'Level' => 'Level', // Added - 2011-06-16 - 'Libvlc' => 'Libvlc', - 'LimitResultsPost' => 'results only;', // This is used at the end of the phrase 'Limit to first N results only' - 'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only' - 'Line' => 'Line', // Added - 2011-06-16 - 'LinkedMonitors' => 'Linked Monitors', - 'List' => 'List', - 'Load' => 'Load', - 'Local' => 'Lokal', - 'Log' => 'Log', // Added - 2011-06-16 - 'LoggedInAs' => 'Logget Ind Som', - 'Logging' => 'Logging', // Added - 2011-06-16 - 'LoggingIn' => 'Logger Ind', - 'Login' => 'Logind', - 'Logout' => 'Logud', - 'Logs' => 'Logs', // Added - 2011-06-17 - 'Low' => 'Lav', - 'LowBW' => 'Lav B/B', - 'Main' => 'Main', - 'Man' => 'Man', - 'Manual' => 'Manual', - 'Mark' => 'Marker', - 'Max' => 'Max', - 'MaxBandwidth' => 'Max Bandwidth', - 'MaxBrScore' => 'Max.
Skore', - 'MaxFocusRange' => 'Max Focus Range', - 'MaxFocusSpeed' => 'Max Focus Speed', - 'MaxFocusStep' => 'Max Focus Step', - 'MaxGainRange' => 'Max Gain Range', - 'MaxGainSpeed' => 'Max Gain Speed', - 'MaxGainStep' => 'Max Gain Step', - 'MaxIrisRange' => 'Max Iris Range', - 'MaxIrisSpeed' => 'Max Iris Speed', - 'MaxIrisStep' => 'Max Iris Step', - 'MaxPanRange' => 'Max Pan Range', - 'MaxPanSpeed' => 'Max Pan Speed', - 'MaxPanStep' => 'Max Pan Step', - 'MaxTiltRange' => 'Max Tilt Range', - 'MaxTiltSpeed' => 'Max Tilt Speed', - 'MaxTiltStep' => 'Max Tilt Step', - 'MaxWhiteRange' => 'Max White Bal. Range', - 'MaxWhiteSpeed' => 'Max White Bal. Speed', - 'MaxWhiteStep' => 'Max White Bal. Step', - 'MaxZoomRange' => 'Max Zoom Range', - 'MaxZoomSpeed' => 'Max Zoom Speed', - 'MaxZoomStep' => 'Max Zoom Step', - 'MaximumFPS' => 'Maximale FPS', - 'Medium' => 'Medium', - 'MediumBW' => 'Medium B/B', - 'Message' => 'Message', // Added - 2011-06-16 - 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', - 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', - 'MinBlobAreaLtMax' => 'Minimum blob område bør være mindre end maximum', - 'MinBlobAreaUnset' => 'You must specify the minimum blob pixel count', - 'MinBlobLtMinFilter' => 'Minimum blob area should be less than or equal to minimum filter area', - 'MinBlobsLtMax' => 'Minimum blobs bør være mindre end maximum', - 'MinBlobsUnset' => 'You must specify the minimum blob count', - 'MinFilterAreaLtMax' => 'Minimum filter area should be less than maximum', - 'MinFilterAreaUnset' => 'You must specify the minimum filter pixel count', - 'MinFilterLtMinAlarm' => 'Minimum filter area should be less than or equal to minimum alarm area', - 'MinFocusRange' => 'Min Focus Range', - 'MinFocusSpeed' => 'Min Focus Speed', - 'MinFocusStep' => 'Min Focus Step', - 'MinGainRange' => 'Min Gain Range', - 'MinGainSpeed' => 'Min Gain Speed', - 'MinGainStep' => 'Min Gain Step', - 'MinIrisRange' => 'Min Iris Range', - 'MinIrisSpeed' => 'Min Iris Speed', - 'MinIrisStep' => 'Min Iris Step', - 'MinPanRange' => 'Min Pan Range', - 'MinPanSpeed' => 'Min Pan Speed', - 'MinPanStep' => 'Min Pan Step', - 'MinPixelThresLtMax' => 'Minimum pixel threshold bør være mindre end maximum', - 'MinPixelThresUnset' => 'You must specify a minimum pixel threshold', - 'MinTiltRange' => 'Min Tilt Range', - 'MinTiltSpeed' => 'Min Tilt Speed', - 'MinTiltStep' => 'Min Tilt Step', - 'MinWhiteRange' => 'Min White Bal. Range', - 'MinWhiteSpeed' => 'Min White Bal. Speed', - 'MinWhiteStep' => 'Min White Bal. Step', - 'MinZoomRange' => 'Min Zoom Range', - 'MinZoomSpeed' => 'Min Zoom Speed', - 'MinZoomStep' => 'Min Zoom Step', - 'Misc' => 'Misc', - 'Mode' => 'Mode', // Added - 2015-04-18 - 'Monitor' => 'Monitor', - 'MonitorIds' => 'Monitor Ids', - 'MonitorPreset' => 'Monitor Preset', - 'MonitorPresetIntro' => 'Select an appropriate preset from the list below.

Please note that this may overwrite any values you already have configured for this monitor.

', - 'MonitorProbe' => 'Monitor Probe', // Added - 2009-03-31 - 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2009-03-31 - 'Monitors' => 'Monitore', - 'Montage' => 'Montage', - 'Month' => 'Måned', - 'More' => 'More', // Added - 2011-06-16 - 'MotionFrameSkip' => 'Motion Frame Skip', - 'Move' => 'Flyt', - 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. - 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. - 'MtgDefault' => 'Default', // Added 2013.08.15. - 'MustBeGe' => 'skal være støre end eller ligmed', - 'MustBeLe' => 'Skal være mindre end eller ligmed', - 'MustConfirmPassword' => 'Du skal konfimere password', - 'MustSupplyPassword' => 'Du skal angive et password', - 'MustSupplyUsername' => 'Du skal opgive et username', - 'Name' => 'Navn', - 'Near' => 'Near', - 'Network' => 'Netværk', - 'New' => 'Ny', - 'NewGroup' => 'Ny Gruppe', - 'NewLabel' => 'New Label', - 'NewPassword' => 'Nyt Password', - 'NewState' => 'Ny State', - 'NewUser' => 'Ny User', - 'Next' => 'Næste', - 'No' => 'Nej', - 'NoDetectedCameras' => 'No Detected Cameras', // Added - 2009-03-31 - 'NoFramesRecorded' => 'Der er ingen billeder optaget for denne event', - 'NoGroup' => 'No Group', - 'NoSavedFilters' => 'NoSavedFilters', - 'NoStatisticsRecorded' => 'Der er ingen statestikker optaget for denne event/frame', - 'None' => 'Ingen', - 'NoneAvailable' => 'Ingen Tilstede', - 'Normal' => 'Normal', - 'Notes' => 'Notes', - 'NumPresets' => 'Num Presets', - 'Off' => 'Off', - 'On' => 'On', - 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 - 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 - 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 - 'OpEq' => 'ligmed', - 'OpGt' => 'støre end', - 'OpGtEq' => 'støre end eller ligmed', - 'OpIn' => 'i sættet', - 'OpLt' => 'mindre end', - 'OpLtEq' => 'mindre end eller ligmed', - 'OpMatches' => 'matches', - 'OpNe' => 'ikke ligmed', - 'OpNotIn' => 'ikke i sættet', - 'OpNotMatches' => 'does not match', - 'Open' => 'Åben', - 'OptionHelp' => 'OptionHelp', - 'OptionRestartWarning' => 'Disse ændringer træder ikke i fuld effect\nmens systemt køre. Når du har\nafsluttet ændringer bedes du\ngenstarte ZoneMinder.', - 'Options' => 'Indstillinger', - 'OrEnterNewName' => 'eller skriv nyt navn', - 'Order' => 'Order', - 'Orientation' => 'Orientation', - 'Out' => 'Ud', - 'OverwriteExisting' => 'Overskriv Eksisterende', - 'Paged' => 'Paged', - 'Pan' => 'Pan', - 'PanLeft' => 'Pan Left', - 'PanRight' => 'Pan Right', - 'PanTilt' => 'Pan/Tilt', - 'Parameter' => 'Parameter', - 'Password' => 'Password', - 'PasswordsDifferent' => 'Det nye og konfimerede passwords er forskellige', - 'Paths' => 'Stiger', - 'Pause' => 'Pause', - 'Phone' => 'Telefon', - 'PhoneBW' => 'Telefon B/B', - 'Pid' => 'PID', // Added - 2011-06-16 - 'PixelDiff' => 'Pixel Diff', - 'Pixels' => 'pixels', - 'Play' => 'Play', - 'PlayAll' => 'Afspil Alle', - 'PleaseWait' => 'Vent venligst', - 'Plugins' => 'Plugins', - 'Point' => 'Point', - 'PostEventImageBuffer' => 'Efter Event Billed Buffer', - 'PreEventImageBuffer' => 'Før Event Billed Buffer', - 'PreserveAspect' => 'Preserve Aspect Ratio', - 'Preset' => 'Preset', - 'Presets' => 'Presets', - 'Prev' => 'Prev', - 'Probe' => 'Probe', // Added - 2009-03-31 - 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 - 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 - 'Progress' => 'Progress', // Added - 2015-04-18 - 'Protocol' => 'Protocol', - 'Rate' => 'Rate', - 'Real' => 'Real', - 'Record' => 'Optag', - 'RefImageBlendPct' => 'Reference Billede Blend %ge', - 'Refresh' => 'Opdater', - 'Remote' => 'Remote', - 'RemoteHostName' => 'Remote Host Navn', - 'RemoteHostPath' => 'Remote Host Stig', - 'RemoteHostPort' => 'Remote Host Port', - 'RemoteHostSubPath' => 'Remote Host SubPath', // Added - 2009-02-08 - 'RemoteImageColours' => 'Remote Image Farver', - 'RemoteMethod' => 'Remote Method', // Added - 2009-02-08 - 'RemoteProtocol' => 'Remote Protocol', // Added - 2009-02-08 - 'Rename' => 'Omdøb', - 'Replay' => 'Spil Igen', - 'ReplayAll' => 'All Events', - 'ReplayGapless' => 'Gapless Events', - 'ReplaySingle' => 'Single Event', - 'Reset' => 'Nulstil', - 'ResetEventCounts' => 'Reset Event Counts', - 'Restart' => 'Genstart', - 'Restarting' => 'Genstarter', - 'RestrictedCameraIds' => 'Begranset Kamera Ids', - 'RestrictedMonitors' => 'Restricted Monitors', - 'ReturnDelay' => 'Return Delay', - 'ReturnLocation' => 'Return Location', - 'Rewind' => 'Rewind', - 'RotateLeft' => 'Rotate Left', - 'RotateRight' => 'Rotate Right', - 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 - 'RunMode' => 'Kørsels Mode', - 'RunState' => 'Run State', - 'Running' => 'Køre', - 'Save' => 'Gem', - 'SaveAs' => 'Gem Som', - 'SaveFilter' => 'Gem Filter', - 'Scale' => 'Scale', - 'Score' => 'Skore', - 'Secs' => 'Sekunder', - 'Sectionlength' => 'Sektion længde', - 'Select' => 'Vælg', - 'SelectFormat' => 'Select Format', // Added - 2011-06-17 - 'SelectLog' => 'Select Log', // Added - 2011-06-17 - 'SelectMonitors' => 'Select Monitors', - 'SelfIntersecting' => 'Polygon edges must not intersect', - 'Set' => 'Sæt', - 'SetNewBandwidth' => 'Sæt Ny Båndbrede', - 'SetPreset' => 'Sæt Preset', - 'Settings' => 'Indstillinger', - 'ShowFilterWindow' => 'VisFilterVindue', - 'ShowTimeline' => 'Show Timeline', - 'SignalCheckColour' => 'Signal Check Colour', - 'Size' => 'Size', - 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 - 'Sleep' => 'Sov', - 'SortAsc' => 'Asc', - 'SortBy' => 'Sorter efter', - 'SortDesc' => 'Desc', - 'Source' => 'Enhed', - 'SourceColours' => 'Source Colours', // Added - 2009-02-08 - 'SourcePath' => 'Source Path', // Added - 2009-02-08 - 'SourceType' => 'Enheds Type', - 'Speed' => 'Hastighed', - 'SpeedHigh' => 'Høj Hastighed', - 'SpeedLow' => 'Lav Hastighed', - 'SpeedMedium' => 'Medium Hastighed', - 'SpeedTurbo' => 'Turbo Hastighed', - 'Start' => 'Start', - 'State' => 'State', - 'Stats' => 'Stats', - 'Status' => 'Status', - 'Step' => 'Step', - 'StepBack' => 'Step Back', - 'StepForward' => 'Step Forward', - 'StepLarge' => 'Large Step', - 'StepMedium' => 'Medium Step', - 'StepNone' => 'No Step', - 'StepSmall' => 'Small Step', - 'Stills' => 'Stills', - 'Stop' => 'Stop', - 'Stopped' => 'Stoppet', - 'Stream' => 'Stream', - 'StreamReplayBuffer' => 'Stream Replay Image Buffer', - 'Submit' => 'Submit', - 'System' => 'System', - 'SystemLog' => 'System Log', // Added - 2011-06-16 - 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 - 'Tele' => 'Tele', - 'Thumbnail' => 'Thumbnail', - 'Tilt' => 'Tilt', - 'Time' => 'Tid', - 'TimeDelta' => 'Time Delta', - 'TimeStamp' => 'Tids Stempel', - 'Timeline' => 'Timeline', - 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. - 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. - 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. - 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. - 'Timestamp' => 'Tidsstempel', - 'TimestampLabelFormat' => 'Tidsstempel Mærkning´s Format', - 'TimestampLabelX' => 'Tidsstempel Mærkning X', - 'TimestampLabelY' => 'Tidsstempel Mærkning Y', - 'Today' => 'Idag', - 'Tools' => 'Tools', - 'Total' => 'Total', // Added - 2011-06-16 - 'TotalBrScore' => 'Total
Skore', - 'TrackDelay' => 'Track Delay', - 'TrackMotion' => 'Track Motion', - 'Triggers' => 'Triggers', - 'TurboPanSpeed' => 'Turbo Pan Hastighed', - 'TurboTiltSpeed' => 'Turbo Tilt Hastighed', - 'Type' => 'Type', - 'Unarchive' => 'Unarchive', - 'Undefined' => 'Undefined', // Added - 2009-02-08 - 'Units' => 'Units', - 'Unknown' => 'Unknown', - 'Update' => 'Update', - 'UpdateAvailable' => 'En updatering til ZoneMinder er tilstede.', - 'UpdateNotNecessary' => 'Ingen updatering er nødvendig.', - 'Updated' => 'Updated', // Added - 2011-06-16 - 'Upload' => 'Upload', // Added - 2011-08-23 - 'UseFilter' => 'Brug Filter', - 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' - 'UseFilterExprsPre' => 'Brug ', // This is used at the beginning of the phrase 'use N filter expressions' - 'UsedPlugins' => 'Used Plugins', - 'User' => 'Bruger', - 'Username' => 'Bruger Navn', - 'Users' => 'Brugere', - 'V4L' => 'V4L', // Added - 2015-04-18 - 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 - 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 - 'Value' => 'Værdig', - 'Version' => 'Version', - 'VersionIgnore' => 'Ignorer denne version', - 'VersionRemindDay' => 'Påmind igen om 1 dag', - 'VersionRemindHour' => 'Påmind igen om 1 time', - 'VersionRemindNever' => 'Mind ikke om nye versioner', - 'VersionRemindWeek' => 'Påmind igen om 1 uge', - 'Video' => 'Video', - 'VideoFormat' => 'Video Format', - 'VideoGenFailed' => 'Video Generering Fejlede!', - 'VideoGenFiles' => 'Existing Video Files', - 'VideoGenNoFiles' => 'No Video Files Found', - 'VideoGenParms' => 'Video Generaring Parametre', - 'VideoGenSucceeded' => 'Video Generation Succeeded!', - 'VideoSize' => 'Video Størelse', - 'View' => 'Vis', - 'ViewAll' => 'Vis Alle', - 'ViewEvent' => 'View Event', - 'ViewPaged' => 'View Paged', - 'Wake' => 'Wake', - 'WarmupFrames' => 'Varmop Billeder', - 'Watch' => 'Se', - 'Web' => 'Web', - 'WebColour' => 'Web Colour', - 'Week' => 'Uge', - 'White' => 'White', - 'WhiteBalance' => 'White Balance', - 'Wide' => 'Wide', - 'X' => 'X', - 'X10' => 'X10', - 'X10ActivationString' => 'X10 Activerings Streng', - 'X10InputAlarmString' => 'X10 Input Alarm Streng', - 'X10OutputAlarmString' => 'X10 Output Alarm Streng', - 'Y' => 'Y', - 'Yes' => 'Ja', - 'YouNoPerms' => 'Du har ikke adgang til denne resourse.', - 'Zone' => 'Zone', - 'ZoneAlarmColour' => 'Alarm Farve (Red/Green/Blue)', - 'ZoneArea' => 'Zone Area', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', - 'ZoneFilterSize' => 'Filter Width/Height (pixels)', - 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', - 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', - 'ZoneMinMaxBlobs' => 'Min/Max Blobs', - 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', - 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', - 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 - 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'Zones' => 'Zoner', - 'Zoom' => 'Zoom', - 'ZoomIn' => 'Zoom In', - 'ZoomOut' => 'Zoom Out', + 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'Focus' => 'Focus', + 'ForceAlarm' => 'Force Alarm', + 'Format' => 'Format', + 'FPS' => 'fps', + 'FPSReportInterval' => 'FPS Rapport Interval', + 'Frame' => 'Ramme', + 'FrameId' => 'Ramme Id', + 'FrameRate' => 'Billedhastighed', + 'Frames' => 'Rammer', + 'FrameSkip' => 'Spring over antal rammer', + 'MotionFrameSkip' => 'Spring over antal bevægelsesrammer', + 'FTP' => 'FTP', + 'Func' => 'Funk', + 'Function' => 'Funktion', + 'Gain' => 'Gain', + 'General' => 'Generelt', + 'GenerateVideo' => 'Generer Video', + 'GeneratingVideo' => 'Genererer Video', + 'GoToZoneMinder' => 'GÃ¥ til ZoneMinder.com', + 'Grey' => 'GrÃ¥skala', + 'Group' => 'Gruppe', + 'Groups' => 'Grupper', + 'HasFocusSpeed' => 'Has Focus Speed', + 'HasGainSpeed' => 'Has Gain Speed', + 'HasHomePreset' => 'Has Home Preset', + 'HasIrisSpeed' => 'Has Iris Speed', + 'HasPanSpeed' => 'Has Pan Speed', + 'HasPresets' => 'Has Presets', + 'HasTiltSpeed' => 'Has Tilt Speed', + 'HasTurboPan' => 'Has Turbo Pan', + 'HasTurboTilt' => 'Has Turbo Tilt', + 'HasWhiteSpeed' => 'Has White Bal. Speed', + 'HasZoomSpeed' => 'Has Zoom Speed', + 'HighBW' => 'High B/W', + 'High' => 'Høj', + 'Home' => 'Hjemme', + 'Hostname' => 'Hostname', + 'Hour' => 'Time', + 'Hue' => 'Farvetone', + 'Id' => 'Id', + 'Idle' => 'Afventende', + 'Ignore' => 'Ignorer', + 'ImageBufferSize' => 'Billed Buffer Størrelse (rammer)', + 'Image' => 'Billede', + 'Images' => 'Billeder', + 'Include' => 'Inkluder', + 'In' => 'I', + 'Inverted' => 'Inverteret', + 'Iris' => 'Blænde', + 'KeyString' => 'Nøgle Streng', + 'Label' => 'Mærkat', + 'Language' => 'Sprog', + 'Last' => 'Sidste', + 'Layout' => 'Layout', + 'Libvlc' => 'Libvlc', + 'LimitResultsPost' => 'resultater', // This is used at the end of the phrase 'Limit to first N results only' + 'LimitResultsPre' => 'Begræns til kun de første', // This is used at the beginning of the phrase 'Limit to first N results only' + 'LinkedMonitors' => 'Sammenkædede Monitorer', + 'List' => 'Liste', + 'Load' => 'Belastning', + 'Local' => 'Lokal', + 'Log' => 'Log', + 'Logs' => 'Logs', + 'Logging' => 'Logning', + 'LoggedInAs' => 'Logget ind som', + 'LoggingIn' => 'Logger ind', + 'Login' => 'Logind', + 'Logout' => 'Logud', + 'LowBW' => 'Lav B/W', + 'Low' => 'Lav', + 'Main' => 'Hoved', + 'Man' => 'Man', + 'Manual' => 'Manuel', + 'Mark' => 'Markér', + 'MaxBandwidth' => 'Max BÃ¥ndbredde', + 'MaxBrScore' => 'Max.
Score', + 'MaxFocusRange' => 'Max Focus Range', + 'MaxFocusSpeed' => 'Max Focus Speed', + 'MaxFocusStep' => 'Max Focus Step', + 'MaxGainRange' => 'Max Gain Range', + 'MaxGainSpeed' => 'Max Gain Speed', + 'MaxGainStep' => 'Max Gain Step', + 'MaximumFPS' => 'Maximum FPS', + 'MaxIrisRange' => 'Max Iris Range', + 'MaxIrisSpeed' => 'Max Iris Speed', + 'MaxIrisStep' => 'Max Iris Step', + 'Max' => 'Max', + 'MaxPanRange' => 'Max Pan Range', + 'MaxPanSpeed' => 'Max Pan Speed', + 'MaxPanStep' => 'Max Pan Step', + 'MaxTiltRange' => 'Max Tilt Range', + 'MaxTiltSpeed' => 'Max Tilt Speed', + 'MaxTiltStep' => 'Max Tilt Step', + 'MaxWhiteRange' => 'Max White Bal. Range', + 'MaxWhiteSpeed' => 'Max White Bal. Speed', + 'MaxWhiteStep' => 'Max White Bal. Step', + 'MaxZoomRange' => 'Max Zoom Range', + 'MaxZoomSpeed' => 'Max Zoom Speed', + 'MaxZoomStep' => 'Max Zoom Step', + 'MediumBW' => 'Medium B/W', + 'Medium' => 'Medium', + 'MinAlarmAreaLtMax' => 'Minimum alarm omrÃ¥de skal være mindre end maksimum', + 'MinAlarmAreaUnset' => 'Du skal angive det minimale antal alarm pixels', + 'MinBlobAreaLtMax' => 'Minimum blob omrÃ¥de skal være mindre end maksimum', + 'MinBlobAreaUnset' => 'Du skal angive det minimale antal blob pixels', + 'MinBlobLtMinFilter' => 'Minimum blob omrÃ¥de skal være mindre end eller lig med minimum filter omrÃ¥de', + 'MinBlobsLtMax' => 'Minimum blobs skal være mindre end maksimum', + 'MinBlobsUnset' => 'Du skal angive det minimale antal blobs', + 'MinFilterAreaLtMax' => 'Minimum filter omrÃ¥de skal være mindre end maksimum', + 'MinFilterAreaUnset' => 'Du skal angive det minimale antal filter pixels', + 'MinFilterLtMinAlarm' => 'Minimum filter omrÃ¥de skal være mindre end eller lig med minimum alarm omrÃ¥de', + 'MinFocusRange' => 'Min Focus Range', + 'MinFocusSpeed' => 'Min Focus Speed', + 'MinFocusStep' => 'Min Focus Step', + 'MinGainRange' => 'Min Gain Range', + 'MinGainSpeed' => 'Min Gain Speed', + 'MinGainStep' => 'Min Gain Step', + 'MinIrisRange' => 'Min Iris Range', + 'MinIrisSpeed' => 'Min Iris Speed', + 'MinIrisStep' => 'Min Iris Step', + 'MinPanRange' => 'Min Pan Range', + 'MinPanSpeed' => 'Min Pan Speed', + 'MinPanStep' => 'Min Pan Step', + 'MinPixelThresLtMax' => 'Minimum pixel grænseværdi skal være mindre end maksimum', + 'MinPixelThresUnset' => 'Du skal angive en minimum pixel grænseværdi', + 'MinTiltRange' => 'Min Tilt Range', + 'MinTiltSpeed' => 'Min Tilt Speed', + 'MinTiltStep' => 'Min Tilt Step', + 'MinWhiteRange' => 'Min White Bal. Range', + 'MinWhiteSpeed' => 'Min White Bal. Speed', + 'MinWhiteStep' => 'Min White Bal. Step', + 'MinZoomRange' => 'Min Zoom Range', + 'MinZoomSpeed' => 'Min Zoom Speed', + 'MinZoomStep' => 'Min Zoom Step', + 'Misc' => 'Diverse', + 'Mode' => 'Mode', + 'MonitorIds' => 'Monitor Ids', + 'Monitor' => 'Monitor', + 'MonitorPresetIntro' => 'Vælg en passende forudindstilling fra listen herunder.

Vær opmærksom på, at dette kan overskrive værdier, du allerede har angivet for den aktuelle monitor.

', + 'MonitorPreset' => 'Monitor Forudindstillinger', + 'MonitorProbeIntro' => 'Listen herunder viser fundne analoge og nætværks kameraer samt hvorvidt de allerede er i brug eller tilgængelige for udvælgelse.

Vælg det ønskede fra listen herunder.

Vær opmærksom på, at muligvis ikke alle kameraer er fundet og at valg af et kamera kan overskrive værdier, du allerede har angivet for den aktuelle monitor.

', + 'MonitorProbe' => 'Monitor Probe', + 'Monitors' => 'Monitorer', + 'Montage' => 'Montage', + 'MontageReview' => 'Montage Review', + 'Month' => 'Måned', + 'Move' => 'Bevæg', + 'MtgDefault' => 'Standard', // Added 2013.08.15. + 'Mtg2widgrd' => '2-bred gitter', // Added 2013.08.15. + 'Mtg3widgrd' => '3-bred gitter', // Added 2013.08.15. + 'Mtg4widgrd' => '4-bred gitter', // Added 2013.08.15. + 'Mtg3widgrx' => '3-bred gitter, skaleret, forstørret ved alarm', // Added 2013.08.15. + 'MustBeGe' => 'Skal være større end eller lig med', + 'MustBeLe' => 'Skal være mindre end eller lig med', + 'MustConfirmPassword' => 'Du skal bekræfte adgangskoden', + 'MustSupplyPassword' => 'Du skal levere en adgangskode', + 'MustSupplyUsername' => 'Du skal levere et brugernavn', + 'Name' => 'Navn', + 'Near' => 'Nær', + 'Network' => 'Netværk', + 'NewGroup' => 'Ny Gruppe', + 'NewLabel' => 'Ny Mærkat', + 'New' => 'Ny', + 'NewPassword' => 'Ny Adgangskode', + 'NewState' => 'Ny Tilstand', + 'NewUser' => 'Ny bruger', + 'Next' => 'Næste', + 'NoDetectedCameras' => 'Ingen Detected Cameras', + 'NoDetectedProfiles' => 'Ingen Fundne Profiler', + 'NoFramesRecorded' => 'Der er ingen billeder optaget for denne hændelse', + 'NoGroup' => 'Ingen gruppe', + 'NoneAvailable' => 'Ingen tilgængelig', + 'None' => 'Ingen', + 'No' => 'Nej', + 'Normal' => 'Normalt', + 'NoSavedFilters' => 'IngenGemteFiltre', + 'NoStatisticsRecorded' => 'Der er ingen statistik noteret for denne hændelse/ramme', + 'Notes' => 'Noter', + 'NumPresets' => 'Num Forudinst.', + 'Off' => 'Fra', + 'On' => 'Til', + 'OnvifProbe' => 'ONVIF', + 'OnvifProbeIntro' => 'Listen nedenfor viser fundne ONVIF kameraer samt hvorvidt de allerede er i brug eller tilgængelige for udvælgelse.

Vælg det ønskede fra listen herunder.

Vær opmærksom på, at muligvis ikke alle kameraer er fundet og at valg af et kamera kan overskrive værdier, du allerede har angivet for den aktuelle monitor.

', + 'OnvifCredentialsIntro' => 'Venligst lever brugernavn og adgangskodefor de valgte kamera.
Hvis der ikke er oprettet nogen bruger for kameraet, så vil brugeren givet her blive oprettet med den angivne adgangskode.

', + 'Open' => 'Ã…ben', + 'OpEq' => 'lig med', + 'OpGtEq' => 'større end eller lig med', + 'OpGt' => 'større end', + 'OpIn' => 'indeholdt i', + 'OpLtEq' => 'mindre end eller lig med', + 'OpLt' => 'mindre end', + 'OpMatches' => 'matcher', + 'OpNe' => 'ikke lig med', + 'OpNotIn' => 'ikke indeholdt i', + 'OpNotMatches' => 'matcher ikke', + 'OptionalEncoderParam' => 'Optionelle Encoder Parametre', + 'OptionHelp' => 'Indstillinger hjælp', + 'OptionRestartWarning' => 'Disse ændringer har muligvis ikke fuld effekt\nmens systemet er kørende. NÃ¥r du har\nafsluttet dine ændringer, skal du huske at\ngenstarte ZoneMinder.', + 'Options' => 'Indstillinger', + 'Order' => 'Rækkefølge', + 'OrEnterNewName' => 'eller indtast nyt navn', + 'Orientation' => 'Orientering', + 'Out' => 'Ud', + 'OverwriteExisting' => 'Overskriv Eksisterende', + 'Paged' => 'Sidevis', + 'PanLeft' => 'Pan Left', + 'Pan' => 'Pan', + 'PanRight' => 'Pan Right', + 'PanTilt' => 'Pan/Tilt', + 'Parameter' => 'Parameter', + 'Password' => 'Adgangskode', + 'PasswordsDifferent' => 'Den nye og den bekræftende adgangskode er forskellige', + 'Paths' => 'Stier', + 'Pause' => 'Pause', + 'PhoneBW' => 'Telefon B/W', + 'Phone' => 'Telefon', + 'PixelDiff' => 'Pixel Forskel', + 'Pixels' => 'pixels', + 'PlayAll' => 'Afspil Alle', + 'Play' => 'Afspil', + 'Plugins' => 'Plugins', + 'PleaseWait' => 'Vent venligst', + 'Point' => 'Point', + 'PostEventImageBuffer' => 'Antal Billeder Efter Hændelse', + 'PreEventImageBuffer' => 'Antal Billeder Før Hændelse', + 'PreserveAspect' => 'Oprethold højde-bredde-forhold', + 'Preset' => 'Forudindstilling', + 'Presets' => 'Forudindstillinger', + 'Prev' => 'Forrige', + 'Probe' => 'Probe', + 'ProfileProbe' => 'Stream Probe', + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', + 'Progress' => 'Position', + 'Protocol' => 'Protokol', + 'Rate' => 'Rate', + 'RecaptchaWarning' => 'Your reCaptcha secret key is invalid. Please correct it, or reCaptcha will not work', // added Sep 24 2015 - PP + 'RecordAudio' => 'Skal lydsporet gemmes sammen med en hændelse.', + 'Real' => 'Naturtro', + 'Record' => 'Optag', + 'RefImageBlendPct' => 'Reference Billede Blandings %', + 'Refresh' => 'Genindlæs', + 'RemoteHostName' => 'Remote Host Name', + 'RemoteHostPath' => 'Remote Host Path', + 'RemoteHostSubPath' => 'Remote Host SubPath', + 'RemoteHostPort' => 'Remote Host Port', + 'RemoteImageColours' => 'Remote Image Colours', + 'RemoteMethod' => 'Remote Method', + 'RemoteProtocol' => 'Remote Protocol', + 'Remote' => 'Remote', + 'Rename' => 'Omdøb', + 'ReplayAll' => 'Alle Hændelser', + 'ReplayGapless' => 'Hændelser uafbrudt', + 'Replay' => 'Genafspil', + 'ReplaySingle' => 'Enkelt Hændelse', + 'ResetEventCounts' => 'Nulstil Hændelses Tæller', + 'Reset' => 'Nulstil', + 'Restarting' => 'Genstarter', + 'Restart' => 'Genstart', + 'RestrictedCameraIds' => 'Restricted Camera Ids', + 'RestrictedMonitors' => 'Restricted Monitors', + 'ReturnDelay' => 'Return Delay', + 'ReturnLocation' => 'Return Location', + 'Rewind' => 'Hurtigt Tilbage', + 'RotateLeft' => 'Roter til venstrte', + 'RotateRight' => 'Roter til højre', + 'RTSPTransport' => 'RTSP Transport Protocol', + 'RunLocalUpdate' => 'Kør venligst zmupdate.pl for at opdatere', + 'RunMode' => 'Driftsmåde', + 'Running' => 'Kørende', + 'RunState' => 'Drift Tilstand', + 'SaveAs' => 'Gem som', + 'SaveFilter' => 'Gem Filter', + 'SaveJPEGS' => 'Gem JPEGs', + 'Save' => 'Gem', + 'Scale' => 'Skaler', + 'Score' => 'Score', + 'Secs' => 'Sek.', + 'Sectionlength' => 'Sektions længde', + 'SelectMonitors' => 'Vælg Monitorer', + 'Select' => 'Vælg', + 'SelectFormat' => 'Vælg Format', + 'SelectLog' => 'Vælg Log', + 'SelfIntersecting' => 'Polygonens kanter må ikke krydses', + 'SetNewBandwidth' => 'Vælg ny båndbredde', + 'SetPreset' => 'Set Preset', + 'Set' => 'Sæt', + 'Settings' => 'Indstillinger', + 'ShowFilterWindow' => 'Vis Filter Vindue', + 'ShowTimeline' => 'Vis Tidslinie', + 'SignalCheckColour' => 'Signal Check Colour', + 'Size' => 'Størrelse', + 'SkinDescription' => 'SKift standard skin for denne computer', + 'CSSDescription' => 'SKift standard css for denne computer', + 'Sleep' => 'Sover', + 'SortAsc' => 'Voksende', + 'SortBy' => 'Sortér efter', + 'SortDesc' => 'Faldende', + 'Source' => 'Kilde', + 'SourceColours' => 'Kilde Farver', + 'SourcePath' => 'Kilde Sti', + 'SourceType' => 'Kilde Type', + 'SpeedHigh' => 'High Speed', + 'SpeedLow' => 'Low Speed', + 'SpeedMedium' => 'Medium Speed', + 'Speed' => 'Speed', + 'SpeedTurbo' => 'Turbo Speed', + 'Start' => 'Start', + 'State' => 'Tilstand', + 'Stats' => 'Stats', + 'Status' => 'Status', + 'StepBack' => 'Skridt Tilbage', + 'StepForward' => 'Skridt Frem', + 'StepLarge' => 'Langt Skridt', + 'StepMedium' => 'Medium Skridt', + 'StepNone' => 'Ingen Skridt', + 'StepSmall' => 'Lille Skridt', + 'Step' => 'Skridt', + 'Stills' => 'Stilbilleder', + 'Stopped' => 'Stoppet', + 'Stop' => 'Stop', + 'StreamReplayBuffer' => 'Stream Replay Image Buffer', + 'Stream' => 'Stream', + 'Submit' => 'Påtryk', + 'System' => 'System', + 'TargetColorspace' => 'Target colorspace', + 'Tele' => 'Tele', + 'Thumbnail' => 'Thumbnail', + 'Tilt' => 'Tilt', + 'TimeDelta' => 'Tidsforskel', + 'Timeline' => 'Tidslinie', + 'TimelineTip1' => 'Før musen over grafen for at vise snapshot billede og detaljer om hændelsen.', // Added 2013.08.15. + 'TimelineTip2' => 'Klip på de farvede områder af grafen, eller billedet, for at se hændelsen.', // Added 2013.08.15. + 'TimelineTip3' => 'Klik på baggrunden for at zoome ind på en mindre tidsperiode omkring dit klik.', // Added 2013.08.15. + 'TimelineTip4' => 'Brug kontrollerne nedenfor for at zoome ud eller navigere frem eller tilbage i tiden.', // Added 2013.08.15. + 'TimestampLabelFormat' => 'Tidsstempel Mærkat Format', + 'TimestampLabelX' => 'Tidsstempel Mærkat X', + 'TimestampLabelY' => 'Tidsstempel Mærkat Y', + 'TimestampLabelSize' => 'Font Størrelse', + 'Timestamp' => 'Tidsstempel', + 'TimeStamp' => 'Tids stempel', + 'Time' => 'Tidspunkt', + 'Today' => 'Idag', + 'Tools' => 'Værktøjer', + 'Total' => 'Total', + 'TotalBrScore' => 'Total
Score', + 'TrackDelay' => 'Track Delay', + 'TrackMotion' => 'Track Motion', + 'Triggers' => 'Triggere', + 'TurboPanSpeed' => 'Turbo Pan Speed', + 'TurboTiltSpeed' => 'Turbo Tilt Speed', + 'Type' => 'Type', + 'Unarchive' => 'Ikke Arkiveret', + 'Undefined' => 'Udefineret', + 'Units' => 'Enheder', + 'Unknown' => 'Ukendt', + 'UpdateAvailable' => 'En opdatering til ZoneMinder er tilgængelig.', + 'UpdateNotNecessary' => 'Ingen opdatering er nødvendig.', + 'Update' => 'Opdater', + 'Upload' => 'Upload', + 'Updated' => 'Opdateret', + 'UsedPlugins' => 'Anvendte Plugins', + 'UseFilterExprsPost' => ' filter udtryk', // This is used at the end of the phrase 'use N filter expressions' + 'UseFilterExprsPre' => 'Anvend ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UseFilter' => 'Anvend Filter', + 'Username' => 'Brugernavn', + 'Users' => 'Brugere', + 'User' => 'Bruger', + 'Value' => 'Værdi', + 'VersionIgnore' => 'Ignorer denne værdi', + 'VersionRemindDay' => 'PÃ¥mind igen om 1 dag', + 'VersionRemindHour' => 'PÃ¥mind igen om 1 time', + 'VersionRemindNever' => 'PÃ¥mind ikke om nye versioner', + 'VersionRemindWeek' => 'PÃ¥mind igen om 1 uge', + 'Version' => 'Version', + 'VideoFormat' => 'Video Format', + 'VideoGenFailed' => 'Video Generering Fejlede!', + 'VideoGenFiles' => 'Existerende Video Filer', + 'VideoGenNoFiles' => 'Ingen Video Filer Fundet', + 'VideoGenParms' => 'Video Genererings Parametre', + 'VideoGenSucceeded' => 'Video Generering Succeeded!', + 'VideoSize' => 'Video Størrelse', + 'VideoWriter' => 'Video Skriver', + 'Video' => 'Video', + 'ViewAll' => 'Vis Alle', + 'ViewEvent' => 'Vis Hændelse', + 'ViewPaged' => 'Vis Sidevis', + 'View' => 'Vis', + 'V4L' => 'V4L', + 'V4LCapturesPerFrame' => 'Captures Per Frame', + 'V4LMultiBuffer' => 'Multi Buffering', + 'Wake' => 'VÃ¥gen', + 'WarmupFrames' => 'Opvarmningsbilleder', + 'Watch' => 'Ur', + 'WebColour' => 'Web Farve', + 'Web' => 'Web', + 'Week' => 'Uge', + 'WhiteBalance' => 'Hvidbalance', + 'White' => 'Hvid', + 'Wide' => 'Bred', + 'X10ActivationString' => 'X10 Activerings Streng', + 'X10InputAlarmString' => 'X10 Input Alarm Streng', + 'X10OutputAlarmString' => 'X10 Output Alarm Streng', + 'X10' => 'X10', + 'X' => 'X', + 'Yes' => 'Ja', + 'YouNoPerms' => 'Du har ikke tilladelse til at tilgÃ¥ denne ressurse.', + 'Y' => 'Y', + 'ZoneAlarmColour' => 'Alarm Farve (Rød/Grøn/BlÃ¥)', + 'ZoneArea' => 'Zone OmrÃ¥de', + 'ZoneFilterSize' => 'Filter Bredde/Højde (pixels)', + 'ZoneMinderLog' => 'ZoneMinder Log', + 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmeret OmrÃ¥de', + 'ZoneMinMaxBlobArea' => 'Min/Max Blob OmrÃ¥de', + 'ZoneMinMaxBlobs' => 'Min/Max Blobs', + 'ZoneMinMaxFiltArea' => 'Min/Max Filtreret OmrÃ¥de', + 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Grænseværdi (0-255)', + 'ZoneOverloadFrames' => 'Antal Rammer At Ignorere Efter Overload', + 'ZoneExtendAlarmFrames' => 'Udvid Antal Alarm Rammer', + 'Zones' => 'Zoner', + 'Zone' => 'Zone', + 'ZoomIn' => 'Zoom Ind', + 'ZoomOut' => 'Zoom Ud', + 'Zoom' => 'Zoom', ); // Complex replacements with formatting and/or placements, must be passed through sprintf $CLANG = array( - 'CurrentLogin' => 'Nuværende login er \'%1$s\'', - 'EventCount' => '%1$s %2$s', // For example '37 Events' (from Vlang below) - 'LastEvents' => 'Sidste %1$s %2$s', // For example 'Last 37 Events' (from Vlang below) - 'LatestRelease' => 'Den Seneste version er v%1$s, du har v%2$s.', - 'MonitorCount' => '%1$s %2$s', // For example '4 Monitors' (from Vlang below) - 'MonitorFunction' => 'Monitor %1$s Function', - 'RunningRecentVer' => 'Du Køre med seneste version af ZoneMinder, v%s.', - 'VersionMismatch' => 'Version mismatch, system is version %1$s, database is %2$s.', // Added - 2011-05-25 + 'CurrentLogin' => 'Nuværende login er \'%1$s\'', + 'EventCount' => '%1$s %2$s', // For example '37 Events' (from Vlang below) + 'LastEvents' => 'Sidste %1$s %2$s', // For example 'Last 37 Events' (from Vlang below) + 'LatestRelease' => 'Sidste release er v%1$s, du har v%2$s.', + 'MonitorCount' => '%1$s %2$s', // For example '4 Monitors' (from Vlang below) + 'MonitorFunction' => 'Monitor %1$s Function', + 'RunningRecentVer' => 'Du kører den nyeste version af ZoneMinder, v%s.', + 'VersionMismatch' => 'Version misforhold, system er version %1$s, database er %2$s.', ); // The next section allows you to describe a series of word ending and counts used to @@ -798,7 +814,7 @@ $CLANG = array( // // So an example in Russian might be (using English words, and made up endings as I // don't know any Russian!!) -// $zmVlangPotato = array( 1=>'Potati', 2=>'Potaton', 3=>'Potaten' ); +// 'Potato' => array( 1=>'Potati', 2=>'Potaton', 3=>'Potaten' ), // // and the zmVlang function decides that the first form is used for counts ending in // 0, 5-9 or 11-19 and the second form when ending in 1 etc. @@ -806,16 +822,15 @@ $CLANG = array( // Variable arrays expressing plurality, see the zmVlang description above $VLANG = array( - 'Event' => array( 0=>'Events', 1=>'Event', 2=>'Events' ), - 'Monitor' => array( 0=>'Monitors', 1=>'Monitor', 2=>'Monitors' ), + 'Event' => array( 0=>'Hændelser', 1=>'Hændelse', 2=>'Hændelser' ), + 'Monitor' => array( 0=>'Monitorer', 1=>'Monitor', 2=>'Monitorer' ), ); - // You will need to choose or write a function that can correlate the plurality string arrays // with variable counts. This is used to conjugate the Vlang arrays above with a number passed // in to generate the correct noun form. // // In languages such as English this is fairly simple -// Note this still has to be used with printf etc to get the right formating +// Note this still has to be used with printf etc to get the right formatting function zmVlang( $langVarArray, $count ) { krsort( $langVarArray ); @@ -880,7 +895,7 @@ function zmVlang( $langVarArray, $count ) // use to test your custom function. //$monitors = array(); //$monitors[] = 1; // Choose any number -//echo sprintf( $zmClangMonitorCount, count($monitors), zmVlang( $zmVlangMonitor, count($monitors) ) ); +//echo sprintf( $CLANG['MonitorCount'], count($monitors), zmVlang( $VLANG['VlangMonitor'], count($monitors) ) ); // In this section you can override the default prompt and help texts for the options area // These overrides are in the form show below where the array key represents the option name minus the initial ZM_ @@ -893,12 +908,38 @@ $OLANG = array( "\"reorder_queue_size=nnn\" Set number of packets to buffer for handling of reordered packets~~~~". "\"loglevel=debug\" Set verbosity of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)" ), + 'OPTIONS_RTSPTrans' => array( + 'Help' => "This sets the RTSP Transport Protocol for FFmpeg.~~ ". + "TCP - Use TCP (interleaving within the RTSP control channel) as transport protocol.~~". + "UDP - Use UDP as transport protocol. Higher resolution cameras have experienced some 'smearing' while using UDP, if so try TCP~~". + "UDP Multicast - Use UDP Multicast as transport protocol~~". + "HTTP - Use HTTP tunneling as transport protocol, which is useful for passing proxies.~~" + ), 'OPTIONS_LIBVLC' => array( 'Help' => "Parameters in this field are passed on to libVLC. Multiple parameters can be separated by ,~~ ". "Examples (do not enter quotes)~~~~". "\"--rtp-client-port=nnn\" Set local port to use for rtp data~~~~". "\"--verbose=2\" Set verbosity of libVLC" ), + 'OPTIONS_EXIF' => array( + 'Help' => "Enable this option to embed EXIF data into each jpeg frame." + ), + 'OPTIONS_RTSPDESCRIBE' => array( + 'Help' => "Sometimes, during the initial RTSP handshake, the camera will send an updated media URL. ". + "Enable this option to tell ZoneMinder to use this URL. Disable this option to ignore the ". + "value from the camera and use the value as entered in the monitor configuration~~~~". + "Generally this should be enabled. However, there are cases where the camera can get its". + "own URL incorrect, such as when the camera is streaming through a firewall"), + 'OPTIONS_MAXFPS' => array( + 'Help' => "This field has certain limitations when used for non-local devices.~~ ". + "Failure to adhere to these limitations will cause a delay in live video, irregular frame skipping, ". + "and missed events~~". + "For streaming IP cameras, do not use this field to reduce the frame rate. Set the frame rate in the". + " camera, instead. You can, however, use a value that is slightly higher than the frame rate in the camera. ". + "In this case, this helps keep the cpu from being overtaxed in the event of a network problem.~~". + "Some, mostly older, IP cameras support snapshot mode. In this case ZoneMinder is actively polling the camera ". + "for new images. In this case, it is safe to use the field." + ), // 'LANG_DEFAULT' => array( // 'Prompt' => "This is a new prompt for this option", From a9183a15990671cf41ba1338f68775888fe37478 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 5 Jun 2017 09:40:19 -0400 Subject: [PATCH 02/18] more quotes --- web/skins/classic/views/console.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index ede536295..638fe9467 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -33,7 +33,7 @@ $eventCounts = array( 'title' => translate('Hour'), 'filter' => array( 'terms' => array( - array( 'attr' => "DateTime", 'op' => ">=", 'val' => "-1 hour" ), + array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-1 hour' ), ) ), ), @@ -41,7 +41,7 @@ $eventCounts = array( 'title' => translate('Day'), 'filter' => array( 'terms' => array( - array( 'attr' => "DateTime", 'op' => ">=", 'val' => "-1 day" ), + array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 day' ), ) ), ), @@ -49,7 +49,7 @@ $eventCounts = array( 'title' => translate('Week'), 'filter' => array( 'terms' => array( - array( 'attr' => "DateTime", 'op' => ">=", 'val' => "-7 day" ), + array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-7 day' ), ) ), ), @@ -57,7 +57,7 @@ $eventCounts = array( 'title' => translate('Month'), 'filter' => array( 'terms' => array( - array( 'attr' => "DateTime", 'op' => ">=", 'val' => "-1 month" ), + array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 month' ), ) ), ), @@ -65,7 +65,7 @@ $eventCounts = array( 'title' => translate('Archived'), 'filter' => array( 'terms' => array( - array( 'attr' => "Archived", 'op' => "=", 'val' => "1" ), + array( 'attr' => "Archived", 'op' => '=', 'val' => '1' ), ) ), ), @@ -115,7 +115,7 @@ for ( $i = 0; $i < count($monitors); $i++ ) { $counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) as EventCount$j"; $monitors[$i]['eventCounts'][$j]['filter'] = $filter; } - $sql = 'select '.join($counts,", ").' from Events as E where MonitorId = ?'; + $sql = 'SELECT '.join($counts,', ').' FROM Events AS E WHERE MonitorId = ?'; $counts = dbFetchOne( $sql, NULL, array($monitors[$i]['Id']) ); if ( $monitors[$i]['Function'] != 'None' ) { $cycleCount++; From a1940935d5cbca1e08ee0793f153680f2191a4e0 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Mon, 5 Jun 2017 12:04:29 -0500 Subject: [PATCH 03/18] build system - track the version file rather than git tag --- utils/packpack/startpackpack.sh | 109 ++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 34 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index a64be651a..3cabf3a59 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -36,24 +36,46 @@ checksanity () { echo exit 1 fi +} +# Create key variables used to assemble the package name +createvars () { + # We need today's date in year/month/day format + thedate=$(date +%Y%m%d) + + # We need the (short) commit hash of the latest commit (rpm packaging only) + shorthash=$(git describe --long --always | awk -F - '{print $3}') + + # Grab the ZoneMinder version from the contents of the version file + versionfile=$(cat version) + + # git the latest (short) commit hash of the version file + versionhash=$(git log -n1 --pretty=format:%h version) + + # Number of commits since the version file was last changed + numcommits=$(git rev-list ${versionhash}..HEAD --count) } # Check key variables before calling packpack checkvars () { - if [ -z ${VERSION} ]; then - echo - echo "FATAL: VERSION variable was null. Cannot continue." - echo - exit 98 - fi - if [ -z ${RELEASE} ]; then - echo - echo "FATAL: RELEASE variable was null. Cannot Continue" - echo - exit 98 - fi + for var in $thedate $shorthash $versionfile $versionhash $numcommits; do + if [ -z ${var} ]; then + echo + echo "FATAL: This script was unable to determine one or more key variables. Cannot continue." + echo + echo "VARIABLE DUMP" + echo "-------------" + echo + echo "thedate: ${thedate}" + echo "shorthash: ${shorthash}" + echo "versionfile: ${versionfile}" + echo "versionhash: ${versionhash}" + echo "numcommits: ${numcommits}" + echo + exit 98 + fi + done } # Steps common to all builds @@ -131,15 +153,33 @@ installtrusty () { fi } -# This sets the naming convention for the deb packages -setdebpkgver () { +# This sets the naming convention for the rpm packages +setrpmpkgname () { + + createvars + + # Set VERSION to the contents of the version file e.g. 1.31.0 + # Set RELEASE to 1.{number of commits}.{today's date}git{short hash of HEAD} e.g. 1.82.20170605gitg7ae0b4a + export VERSION="$versionfile" + export RELEASE="1.${numcommits}.${thedate}git${shorthash}" + + checkvars - # Set VERSION to x.xx.x+x e.g. 1.30.2+15 - # the last x is number of commits since release - # Creates zoneminder packages in the format: zoneminder-{version}-{release} - zmver=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\1/p') - commitnum=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p') - export VERSION="$zmver+$commitnum" + echo + echo "Packpack VERSION has been set to: ${VERSION}" + echo "Packpack RELEASE has been set to: ${RELEASE}" + echo + +} + +# This sets the naming convention for the deb packages +setdebpkgname () { + + createvars + + # Set VERSION to {zm version}~{today's date}.{number of commits} e.g. 1.31.0~20170605.82 + # Set RELEASE to the packpack DIST variable e.g. Trusty + export VERSION="${versionfile}~${thedate}.${numcommits}" export RELEASE="${DIST}" checkvars @@ -151,6 +191,16 @@ setdebpkgver () { } +# This adds an entry to the rpm specfile changelog +setrpmchangelog () { + + export CHANGELOG_NAME="Andrew Bauer" + export CHANGELOG_EMAIL="zonexpertconsulting@outlook.com" + export CHANGELOG_TEXT="Automated, development snapshot of git ${shorthash}" + +} + + # This adds an entry to the debian changelog setdebchangelog () { DATE=`date -R` @@ -177,18 +227,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then if [ "${OS}" == "el" ] || [ "${OS}" == "fedora" ]; then echo "Begin Redhat build..." - # Set VERSION to x.xx.x e.g. 1.30.2 - # Set RELEASE to x where x is number of commits since release - # Creates zoneminder packages in the format: zoneminder-{version}-{release} - export VERSION=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\1/p') - export RELEASE=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p') - - checkvars - - echo - echo "Packpack VERSION has been set to: ${VERSION}" - echo "Packpack RELEASE has been set to: ${RELEASE}" - echo + setrpmpkgname ln -sfT distros/redhat rpm @@ -213,6 +252,8 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then exit 1 fi + setrpmchangelog + echo "Starting packpack..." packpack/packpack -f utils/packpack/redhat_package.mk redhat_package @@ -220,7 +261,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then echo "Begin ${OS} ${DIST} build..." - setdebpkgver + setdebpkgname movecrud if [ "${DIST}" == "trusty" ] || [ "${DIST}" == "precise" ]; then @@ -246,7 +287,7 @@ elif [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86 echo "Begin Ubuntu Trusty build..." commonprep - setdebpkgver + setdebpkgname movecrud ln -sfT distros/ubuntu1204 debian From 2bc6f1627e2bddd79fb8c4acf0d00f45d02fd82f Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 5 Jun 2017 15:39:19 -0500 Subject: [PATCH 04/18] Add support for conf.d subfolder (#1902) * cmake changes to support conf.d * php changes to support conf.d * perl changes to support conf.d * C changes to support conf.d * add conf.d support to rpmspecfile * fix typo * specify ZM_CONFIG_SUBDIR in relevant target distros * put back my config_file perl definition * remove quotes from ZM macros * fix snprintf * add README to conf.d folder * adjust rpm specfile * remove custom permissions from README in rpmspecfile * modify rpm README documentation to reflect conf.d support * set ZM_CONFIG_SUBDIR in debian rules file --- CMakeLists.txt | 15 ++- conf.d/README | 19 ++++ conf.d/zm-server-host.conf | 7 ++ distros/debian/rules | 3 +- distros/redhat/readme/README.Fedora | 55 +++++---- distros/redhat/readme/README.Redhat6 | 50 +++++---- distros/redhat/readme/README.Redhat7 | 59 +++++----- distros/redhat/zoneminder.spec | 8 +- distros/ubuntu1204/rules | 1 + distros/ubuntu1504_cmake_split_packages/rules | 4 +- distros/ubuntu1604/rules | 1 + .../ZoneMinder/lib/ZoneMinder/Config.pm.in | 53 ++++++--- src/zm_config.cpp | 104 ++++++++++++------ src/zm_config.h.in | 3 + web/includes/config.php.in | 56 ++++++++-- zm.conf.in | 17 ++- 16 files changed, 298 insertions(+), 157 deletions(-) create mode 100644 conf.d/README create mode 100644 conf.d/zm-server-host.conf diff --git a/CMakeLists.txt b/CMakeLists.txt index 9737e4d15..95beacca9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ mark_as_advanced( ZM_PERL_SEARCH_PATH ZM_TARGET_DISTRO ZM_CONFIG_DIR + ZM_CONFIG_SUBDIR ZM_SYSTEMD) set(ZM_RUNDIR "/var/run/zm" CACHE PATH @@ -137,6 +138,8 @@ set(ZM_WEB_GROUP "" CACHE STRING # Advanced set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH "Location of ZoneMinder configuration, default system config directory") +set(ZM_CONFIG_SUBDIR "${ZM_CONFIG_DIR}/conf.d" CACHE PATH + "Location of ZoneMinder configuration subfolder, default: ZM_CONFIG_DIR/conf.d") set(ZM_EXTRA_LIBS "" CACHE STRING "A list of optional libraries, separated by semicolons, e.g. ssl;theora") set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING @@ -177,6 +180,7 @@ if((ZM_TARGET_DISTRO STREQUAL "fc24") OR (ZM_TARGET_DISTRO STREQUAL "fc25")) set(ZM_TMPDIR "/var/lib/zoneminder/temp") set(ZM_LOGDIR "/var/log/zoneminder") set(ZM_CONFIG_DIR "/etc/zm") + set(ZM_CONFIG_SUBDIR "/etc/zm/conf.d") set(ZM_WEBDIR "/usr/share/zoneminder/www") set(ZM_CGIDIR "/usr/libexec/zoneminder/cgi-bin") elseif(ZM_TARGET_DISTRO STREQUAL "el6") @@ -185,6 +189,7 @@ elseif(ZM_TARGET_DISTRO STREQUAL "el6") set(ZM_TMPDIR "/var/lib/zoneminder/temp") set(ZM_LOGDIR "/var/log/zoneminder") set(ZM_CONFIG_DIR "/etc/zm") + set(ZM_CONFIG_SUBDIR "/etc/zm/conf.d") set(ZM_WEBDIR "/usr/share/zoneminder/www") set(ZM_CGIDIR "/usr/libexec/zoneminder/cgi-bin") elseif(ZM_TARGET_DISTRO STREQUAL "el7") @@ -193,6 +198,7 @@ elseif(ZM_TARGET_DISTRO STREQUAL "el7") set(ZM_TMPDIR "/var/lib/zoneminder/temp") set(ZM_LOGDIR "/var/log/zoneminder") set(ZM_CONFIG_DIR "/etc/zm") + set(ZM_CONFIG_SUBDIR "/etc/zm/conf.d") set(ZM_WEBDIR "/usr/share/zoneminder/www") set(ZM_CGIDIR "/usr/libexec/zoneminder/cgi-bin") elseif(ZM_TARGET_DISTRO STREQUAL "OS13") @@ -212,6 +218,7 @@ elseif(ZM_TARGET_DISTRO STREQUAL "FreeBSD") set(ZM_WEB_USER "www") set(ZM_WEB_GROUP "www") set(ZM_CONFIG_DIR "/usr/local/etc/zm") + set(ZM_CONFIG_SUBDIR "/usr/local/etc/zm/conf.d") set(ZM_WEBDIR "/usr/local/share/zoneminder/www") set(ZM_CGIDIR "/usr/local/libexec/zoneminder/cgi-bin") set(ZM_PERL_MM_PARMS "INSTALLDIRS=site") @@ -791,6 +798,11 @@ else(ZM_PERL_SEARCH_PATH) set(EXTRA_PERL_LIB "# Include from system perl paths only") endif(ZM_PERL_SEARCH_PATH) +# If this is an out-of-source build, copy the files we need to the binary directory +if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf.d" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/conf.d") +endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + # Generate files from the .in files configure_file(zm.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" @ONLY) configure_file(zoneminder-config.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) @@ -837,8 +849,9 @@ else(zmconfgen_result EQUAL 0) "ZoneMinder configuration generator failed. Exit code: ${zmconfgen_result}") endif(zmconfgen_result EQUAL 0) -# Install zm.conf +# Install zm.conf and conf.d subfolder install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" DESTINATION "${ZM_CONFIG_DIR}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/conf.d/" DESTINATION "${ZM_CONFIG_SUBDIR}") # Uninstall target configure_file( diff --git a/conf.d/README b/conf.d/README new file mode 100644 index 000000000..dedfcd11f --- /dev/null +++ b/conf.d/README @@ -0,0 +1,19 @@ +conf.d/README + +Any changes to ZoneMinder's configuration should be made here in this folder, +rather than directly editing the default zm.conf file. + +ZoneMinder will process each file in this folder with a ".conf" extension. +Each "Var = Value" pair, in each config file, will be loaded into ZoneMinder's +running configuration, overriding any variables with the same name found in the +default zm.conf file. + +After creating a custom config file, don't forget to set the proper file and +owner permission on it. For example, this is typically what you should do after +saving the config file to disk: + + sudo chown root:apache *.conf + sudo chmod 640 *.conf + +Substitute "apache" with the name of the web server user account on your system. + diff --git a/conf.d/zm-server-host.conf b/conf.d/zm-server-host.conf new file mode 100644 index 000000000..7c61c200d --- /dev/null +++ b/conf.d/zm-server-host.conf @@ -0,0 +1,7 @@ +# Do NOT set ZM_SERVER_HOST if you are not using Multi-Server +# You have been warned +# +# The name specified here must have a corresponding entry +# in the Servers tab under Options +ZM_SERVER_HOST= + diff --git a/distros/debian/rules b/distros/debian/rules index 48a3bdab0..45a64332c 100755 --- a/distros/debian/rules +++ b/distros/debian/rules @@ -22,7 +22,8 @@ override_dh_auto_configure: -DZM_CGIDIR=/usr/lib/zoneminder/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ - -DCMAKE_INSTALL_SYSCONFDIR=etc/zm + -DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \ + -DZM_CONFIG_DIR="/etc/zm" override_dh_auto_install: dh_auto_install --buildsystem=cmake diff --git a/distros/redhat/readme/README.Fedora b/distros/redhat/readme/README.Fedora index 626d74df1..e3cca1f8c 100644 --- a/distros/redhat/readme/README.Fedora +++ b/distros/redhat/readme/README.Fedora @@ -1,7 +1,16 @@ What's New ========== -1. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to +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 @@ -9,16 +18,10 @@ What's New 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. -2. Due to the active state of the ZoneMinder project, we now recommend granting - ALL permission to the ZoneMinder mysql account. This change must be done - manually before ZoneMinder will run. See the installation steps below. - -3. This package uses the HTTPS protocol by default to access the web portal. +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. -4. This package ships with the new ZoneMinder API enabled. - New installs ============ @@ -43,13 +46,17 @@ New installs 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 edit /etc/zm/zm.conf. - Change ZM_DB_USER and ZM_DB_PASS to the values you created in the previous - step. + 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} - This version of zoneminder no longer requires you to make a similar change - to the credentials in /usr/share/zoneminder/www/api/app/Config/database.php - This now happens dynamically. Do *not* make any changes to this file. + 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 @@ -107,21 +114,11 @@ New installs Upgrades ======== -1. Verify /etc/zm/zm.conf. - - If zm.conf was manually edited before running the upgrade, the installation - may not overwrite it. In this case, it will create the file - /etc/zm/zm.conf.rpmnew. - - For example, this will happen if you are using database account credentials - other than zmuser/zmpass. - - Compare /etc/zm/zm.conf to /etc/zm/zm.conf.rpmnew. Verify that zm.conf - contains any new config settings that may be in zm.conf.rpmnew. - - This version of zoneminder no longer requires you to make a similar change - to the credentials in /usr/share/zoneminder/www/api/app/Config/database.php - This now happens dynamically. Do *not* make any changes to this file. +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. diff --git a/distros/redhat/readme/README.Redhat6 b/distros/redhat/readme/README.Redhat6 index a913f7d76..939300d96 100644 --- a/distros/redhat/readme/README.Redhat6 +++ b/distros/redhat/readme/README.Redhat6 @@ -11,7 +11,16 @@ What's New 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. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to +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. @@ -19,14 +28,6 @@ What's New 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. -3. The ZoneMinder configuration file, zm.conf, has been moved to /etc/zm/. - This has been to done match the configuration of CentOS7/Fedora and - simplify the build process. - -4. Due to the active state of the ZoneMinder project, we now recommend granting - ALL permission to the ZoneMinder mysql account. This change must be done - manually before ZoneMinder will run. See the installation steps below. - 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. @@ -59,9 +60,18 @@ New installs 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 mysql credentials to something - other than zmuser/zmpass then you must now edit /etc/zm/zm.conf. Change - ZM_DB_USER and ZM_DB_PASS to the values you created in the previous step. +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 @@ -110,17 +120,11 @@ New installs Upgrades ======== -1. Verify /etc/zm/zm.conf. - - If zm.conf was manually edited before running the upgrade, the installation - may not overwrite it. In this case, it will create the file - /etc/zm/zm.conf.rpmnew. - - For example, this will happen if you are using database account credentials - other than zmuser/zmpass. - - Compare /etc/zm/zm.conf to /etc/zm/zm.conf.rpmnew. Verify that zm.conf - contains any new config settings that may be in zm.conf.rpmnew. +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. diff --git a/distros/redhat/readme/README.Redhat7 b/distros/redhat/readme/README.Redhat7 index fd3b87cc4..8817b925c 100644 --- a/distros/redhat/readme/README.Redhat7 +++ b/distros/redhat/readme/README.Redhat7 @@ -1,23 +1,26 @@ What's New ========== -1. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to +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 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 + 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. -2. Due to the active state of the ZoneMinder project, we now recommend granting - ALL permission to the ZoneMinder mysql account. This change must be done - manually before ZoneMinder will run. See the installation steps below. - -3. This package uses the HTTPS protocol by default to access the web portal. +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. - -4. This package ships with the new ZoneMinder API enabled. New installs ============ @@ -43,13 +46,17 @@ New installs 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 edit /etc/zm/zm.conf. - Change ZM_DB_USER and ZM_DB_PASS to the values you created in the previous - step. + 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} - This version of zoneminder no longer requires you to make a similar change - to the credentials in /usr/share/zoneminder/www/api/app/Config/database.php - This now happens dynamically. Do *not* make any changes to this file. + 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 @@ -98,21 +105,11 @@ New installs Upgrades ======== -1. Verify /etc/zm/zm.conf. - - If zm.conf was manually edited before running the upgrade, the installation - may not overwrite it. In this case, it will create the file - /etc/zm/zm.conf.rpmnew. - - For example, this will happen if you are using database account credentials - other than zmuser/zmpass. - - Compare /etc/zm/zm.conf to /etc/zm/zm.conf.rpmnew. Verify that zm.conf - contains any new config settings that may be in zm.conf.rpmnew. - - This version of zoneminder no longer requires you to make a similar change - to the credentials in /usr/share/zoneminder/www/api/app/Config/database.php - This now happens dynamically. Do *not* make any changes to this file. +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. diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index dad18d307..4eab2a429 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -280,7 +280,13 @@ rm -rf %{_docdir}/%{name}-%{version} %files %license COPYING %doc AUTHORS README.md distros/redhat/readme/README.%{readme_suffix} distros/redhat/readme/README.https distros/redhat/jscalendar-doc -%config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/zm.conf +%dir %{_sysconfdir}/zm +%dir %{_sysconfdir}/zm/conf.d +%{_sysconfdir}/zm/conf.d/README +# Always overwrite zm.conf now that ZoneMinder supports conf.d folder +%attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/zm.conf +%config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/*.conf + %config(noreplace) %attr(644,root,root) %{wwwconfdir}/zoneminder.conf %config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder diff --git a/distros/ubuntu1204/rules b/distros/ubuntu1204/rules index 2b54a2131..1f7755c45 100755 --- a/distros/ubuntu1204/rules +++ b/distros/ubuntu1204/rules @@ -20,6 +20,7 @@ override_dh_auto_configure: -DCMAKE_VERBOSE_MAKEFILE=ON \ -DCMAKE_BUILD_TYPE=Release \ -DZM_CONFIG_DIR="/etc/zm" \ + -DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \ -DZM_RUNDIR="/var/run/zm" \ -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ diff --git a/distros/ubuntu1504_cmake_split_packages/rules b/distros/ubuntu1504_cmake_split_packages/rules index a534e8089..8a2c2643e 100755 --- a/distros/ubuntu1504_cmake_split_packages/rules +++ b/distros/ubuntu1504_cmake_split_packages/rules @@ -62,7 +62,9 @@ override_dh_auto_configure: -DZM_CGIDIR=/usr/lib/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ - -DCMAKE_INSTALL_SYSCONFDIR=etc/zm + -DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \ + -DZM_CONFIG_DIR="/etc/zm" + override_dh_auto_test: # do not run tests... diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules index e3b235be8..c91790d68 100755 --- a/distros/ubuntu1604/rules +++ b/distros/ubuntu1604/rules @@ -20,6 +20,7 @@ override_dh_auto_configure: -DCMAKE_VERBOSE_MAKEFILE=ON \ -DCMAKE_BUILD_TYPE=Release \ -DZM_CONFIG_DIR="/etc/zm" \ + -DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \ -DZM_RUNDIR="/var/run/zm" \ -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index 2ba12dfa2..60cdce658 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -65,26 +65,28 @@ our $VERSION = $ZoneMinder::Base::VERSION; use constant ZM_PID => "@ZM_PID@"; # Path to the ZoneMinder run pid file use constant ZM_CONFIG => "@ZM_CONFIG@"; # Path to the ZoneMinder config file +use constant ZM_CONFIG_SUBDIR => "@ZM_CONFIG_SUBDIR@"; # Path to the ZoneMinder config subfolder use Carp; # Load the config from the database into the symbol table BEGIN { + + # Process name, value pairs from the main config file first my $config_file = ZM_CONFIG; - open( my $CONFIG, "<", $config_file ) - or croak( "Can't open config file '$config_file': $!" ); - foreach my $str ( <$CONFIG> ) { - next if ( $str =~ /^\s*$/ ); - next if ( $str =~ /^\s*#/ ); - my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/; - if ( ! $name ) { - print( STDERR "Warning, bad line in $config_file: $str\n" ); - next; - } # end if - $name =~ tr/a-z/A-Z/; - $Config{$name} = $value; + process_configfile($config_file); + + # Search for user created config files. If one or more are found then + # update the Config hash with those values + if ( -d ZM_CONFIG_SUBDIR ) { + if ( -R ZM_CONFIG_SUBDIR ) { + foreach my $filename ( glob ZM_CONFIG_SUBDIR."/*.conf" ) { + process_configfile($filename); + } + } else { + print( STDERR "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on ".ZM_CONFIG_SUBDIR.".\n" ); + } } - close( $CONFIG ); use DBI; my $socket; @@ -126,6 +128,31 @@ BEGIN { } $sth->finish(); } + + # This subroutine must be inside the BEGIN block + sub process_configfile { + my $config_file = shift; + + if ( -R $config_file ) { + open( my $CONFIG, "<", $config_file ) + or croak( "Can't open config file '$config_file': $!" ); + foreach my $str ( <$CONFIG> ) { + next if ( $str =~ /^\s*$/ ); + next if ( $str =~ /^\s*#/ ); + my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/; + if ( ! $name ) { + print( STDERR "Warning, bad line in $config_file: $str\n" ); + next; + } # end if + $name =~ tr/a-z/A-Z/; + $Config{$name} = $value; + } + close( $CONFIG ); + } else { + print( STDERR "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $config_file\n" ); + } + } + } # end BEGIN sub loadConfigFromDB { diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 61c61bf5a..eedebaf45 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -24,14 +24,80 @@ #include #include #include +#include +#include #include "zm_utils.h" void zmLoadConfig() { + + // Process name, value pairs from the main config file first + char configFile[PATH_MAX] = ZM_CONFIG; + process_configfile(configFile); + + // Search for user created config files. If one or more are found then + // update the Config hash with those values + DIR* configSubFolder = opendir(ZM_CONFIG_SUBDIR); + if ( configSubFolder ) { // subfolder exists and is readable + char glob_pattern[PATH_MAX] = ""; + snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.conf", ZM_CONFIG_SUBDIR ); + + glob_t 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) ); + } else { + Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status ); + } + } else { + for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) { + process_configfile(pglob.gl_pathv[i]); + } + closedir(configSubFolder); + } + globfree( &pglob ); + } + + zmDbConnect(); + config.Load(); + config.Assign(); + + // Populate the server config entries + if ( ! staticConfig.SERVER_ID ) { + if ( ! staticConfig.SERVER_NAME.empty() ) { + + Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() ); + std::string sql = stringtf("SELECT Id FROM Servers WHERE Name='%s'", staticConfig.SERVER_NAME.c_str() ); + if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { + staticConfig.SERVER_ID = atoi(dbrow[0]); + } else { + Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() ); + } + + } // end if has SERVER_NAME + } else if ( staticConfig.SERVER_NAME.empty() ) { + Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID ); + std::string sql = stringtf("SELECT Name FROM Servers WHERE Id='%d'", staticConfig.SERVER_ID ); + + if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { + staticConfig.SERVER_NAME = std::string(dbrow[0]); + } else { + Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID ); + } + if ( staticConfig.SERVER_ID ) { + Debug( 3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID ); + } else { + Debug( 3, "Single server configuration assumed because no Server ID or Name was specified." ); + } + } +} + +void process_configfile( char* configFile) { FILE *cfg; char line[512]; - if ( (cfg = fopen( ZM_CONFIG, "r")) == NULL ) { - Fatal( "Can't open %s: %s", ZM_CONFIG, strerror(errno) ); + if ( (cfg = fopen( configFile, "r")) == NULL ) { + Fatal( "Can't open %s: %s", configFile, strerror(errno) ); } while ( fgets( line, sizeof(line), cfg ) != NULL ) { char *line_ptr = line; @@ -58,7 +124,7 @@ void zmLoadConfig() { // Now look for the '=' in the middle of the line temp_ptr = strchr( line_ptr, '=' ); if ( !temp_ptr ) { - Warning( "Invalid data in %s: '%s'", ZM_CONFIG, line ); + Warning( "Invalid data in %s: '%s'", configFile, line ); continue; } @@ -99,38 +165,6 @@ void zmLoadConfig() { } } // end foreach line of the config fclose( cfg ); - zmDbConnect(); - config.Load(); - config.Assign(); - - // Populate the server config entries - if ( ! staticConfig.SERVER_ID ) { - if ( ! staticConfig.SERVER_NAME.empty() ) { - - Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() ); - std::string sql = stringtf("SELECT Id FROM Servers WHERE Name='%s'", staticConfig.SERVER_NAME.c_str() ); - if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { - staticConfig.SERVER_ID = atoi(dbrow[0]); - } else { - Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() ); - } - - } // end if has SERVER_NAME - } else if ( staticConfig.SERVER_NAME.empty() ) { - Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID ); - std::string sql = stringtf("SELECT Name FROM Servers WHERE Id='%d'", staticConfig.SERVER_ID ); - - if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) { - staticConfig.SERVER_NAME = std::string(dbrow[0]); - } else { - Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID ); - } - if ( staticConfig.SERVER_ID ) { - Debug( 3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID ); - } else { - Debug( 3, "Single server configuration assumed because no Server ID or Name was specified." ); - } - } } StaticConfig staticConfig; diff --git a/src/zm_config.h.in b/src/zm_config.h.in index 919cb0c82..49b983fa7 100644 --- a/src/zm_config.h.in +++ b/src/zm_config.h.in @@ -26,6 +26,7 @@ #include #define ZM_CONFIG "@ZM_CONFIG@" // Path to config file +#define ZM_CONFIG_SUBDIR "@ZM_CONFIG_SUBDIR@" // Path to the ZoneMinder config subfolder #define ZM_VERSION "@VERSION@" // ZoneMinder Version #define ZM_HAS_V4L1 @ZM_HAS_V4L1@ @@ -58,6 +59,8 @@ extern void zmLoadConfig(); +extern void process_configfile( char* configFile ); + struct StaticConfig { std::string DB_HOST; diff --git a/web/includes/config.php.in b/web/includes/config.php.in index 0af60b76a..991414a56 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -22,6 +22,7 @@ // This section contains options substituted by the zmconfig.pl utility, do not edit these directly // define( "ZM_CONFIG", "@ZM_CONFIG@" ); // Path to config file +define( "ZM_CONFIG_SUBDIR", "@ZM_CONFIG_SUBDIR@" ); // Path to config subfolder // Define, and override any given in config file define( "ZM_VERSION", "@VERSION@" ); // Version define( "ZM_DIR_TEMP", "@ZM_TMPDIR@" ); @@ -36,19 +37,28 @@ if ( file_exists( $localConfigFile ) && filesize( $localConfigFile ) > 0 ) error_log( "Warning, overriding installed $localConfigFile file with local copy" ); $configFile = $localConfigFile; } - -$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 )) - define( $matches[1], $matches[2] ); + +# Process name, value pairs from the main config file first +$configvals = process_configfile($configFile); + +# Search for user created config files. If one or more are found then +# update our config value array with those values +$configSubFolder = 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 +foreach( $configvals as $key => $value) { + define( $key, $value ); } -fclose( $cfg ); // // This section is options normally derived from other options or configuration @@ -189,5 +199,27 @@ 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/zm.conf.in b/zm.conf.in index 73e4a3d9c..296078dde 100644 --- a/zm.conf.in +++ b/zm.conf.in @@ -1,13 +1,16 @@ # ========================================================================== # -# ZoneMinder Base Configuration, $Date$, $Revision$ +# ZoneMinder Base Configuration File # # ========================================================================== # -# This file is generated by 'configure'. Care should be taken if manually -# editing this file as an changes may be overwritten by subsequent configuration -# or installations. +# *** DO NOT EDIT THIS FILE *** +# Changes made directly to this configuration file are no longer supported. +# They will be overwritten during an upgrade. # +# Instead, create a custom configuration file, with an extention of ".conf" +# under the @ZM_CONFIG_SUBDIR@ subfolder containing your desired modifications. +# # Path to installed data directory, used mostly for finding DB upgrade scripts ZM_PATH_DATA=@PKGDATADIR@ @@ -47,9 +50,3 @@ ZM_DB_USER=@ZM_DB_USER@ # ZoneMinder database password ZM_DB_PASS=@ZM_DB_PASS@ -# Do NOT set ZM_SERVER_HOST if you are not using Multi-Server -# You have been warned -# -# The name specified here must have a corresponding entry -# in the Servers tab under Options -ZM_SERVER_HOST= From 54312fa994b074c7eb76ab341cf1fc3b6b89b3f7 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Tue, 6 Jun 2017 11:56:53 -0500 Subject: [PATCH 05/18] consolidate ZM_TARGET_DISTRO parameters --- CMakeLists.txt | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95beacca9..2583f43ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,25 +174,7 @@ set(ZM_SYSTEMD "OFF" CACHE BOOL "Set to ON to force building ZM with systemd support. default: OFF") # Reassign some variables if a target distro has been specified -if((ZM_TARGET_DISTRO STREQUAL "fc24") OR (ZM_TARGET_DISTRO STREQUAL "fc25")) - set(ZM_RUNDIR "/var/run/zoneminder") - set(ZM_SOCKDIR "/var/lib/zoneminder/sock") - set(ZM_TMPDIR "/var/lib/zoneminder/temp") - set(ZM_LOGDIR "/var/log/zoneminder") - set(ZM_CONFIG_DIR "/etc/zm") - set(ZM_CONFIG_SUBDIR "/etc/zm/conf.d") - set(ZM_WEBDIR "/usr/share/zoneminder/www") - set(ZM_CGIDIR "/usr/libexec/zoneminder/cgi-bin") -elseif(ZM_TARGET_DISTRO STREQUAL "el6") - set(ZM_RUNDIR "/var/run/zoneminder") - set(ZM_SOCKDIR "/var/lib/zoneminder/sock") - set(ZM_TMPDIR "/var/lib/zoneminder/temp") - set(ZM_LOGDIR "/var/log/zoneminder") - set(ZM_CONFIG_DIR "/etc/zm") - set(ZM_CONFIG_SUBDIR "/etc/zm/conf.d") - set(ZM_WEBDIR "/usr/share/zoneminder/www") - set(ZM_CGIDIR "/usr/libexec/zoneminder/cgi-bin") -elseif(ZM_TARGET_DISTRO STREQUAL "el7") +if((ZM_TARGET_DISTRO MATCHES "^el") OR (ZM_TARGET_DISTRO MATCHES "^fc")) set(ZM_RUNDIR "/var/run/zoneminder") set(ZM_SOCKDIR "/var/lib/zoneminder/sock") set(ZM_TMPDIR "/var/lib/zoneminder/temp") @@ -222,7 +204,7 @@ elseif(ZM_TARGET_DISTRO STREQUAL "FreeBSD") set(ZM_WEBDIR "/usr/local/share/zoneminder/www") set(ZM_CGIDIR "/usr/local/libexec/zoneminder/cgi-bin") set(ZM_PERL_MM_PARMS "INSTALLDIRS=site") -endif((ZM_TARGET_DISTRO STREQUAL "fc24") OR (ZM_TARGET_DISTRO STREQUAL "fc25")) +endif((ZM_TARGET_DISTRO MATCHES "^el") OR (ZM_TARGET_DISTRO MATCHES "^fc")) # Required for certain checks to work set(CMAKE_EXTRA_INCLUDE_FILES From 0892be3970e9be422a9f1106916c89c1c9bef01e Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Tue, 6 Jun 2017 11:59:56 -0500 Subject: [PATCH 06/18] further consolidation of ZM_TARGET_DISTRO --- CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2583f43ee..cc1067903 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -808,13 +808,11 @@ if(ZM_ONVIF) endif(ZM_ONVIF) # Process distro subdirectories -if((ZM_TARGET_DISTRO STREQUAL "fc24") OR (ZM_TARGET_DISTRO STREQUAL "fc25")) - add_subdirectory(distros/redhat) -elseif((ZM_TARGET_DISTRO STREQUAL "el6") OR (ZM_TARGET_DISTRO STREQUAL "el7")) +if((ZM_TARGET_DISTRO MATCHES "^el") OR (ZM_TARGET_DISTRO MATCHES "^fc")) add_subdirectory(distros/redhat) elseif(ZM_TARGET_DISTRO STREQUAL "OS13") add_subdirectory(distros/opensuse) -endif((ZM_TARGET_DISTRO STREQUAL "fc24") OR (ZM_TARGET_DISTRO STREQUAL "fc25")) +endif((ZM_TARGET_DISTRO MATCHES "^el") OR (ZM_TARGET_DISTRO MATCHES "^fc")) # Print optional libraries detection status message(STATUS "Optional libraries found:${optlibsfound}") From 7d97267dd2e27cc1a0e96e95364b4ec3812dc12e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 6 Jun 2017 15:35:17 -0400 Subject: [PATCH 07/18] fix compile on old ffmpeg --- src/zm_videostore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 89537d87f..e7ad821d9 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -455,11 +455,13 @@ bool VideoStore::setup_resampler() { // Now copy them to the output stream audio_output_stream = avformat_new_stream( oc, audio_output_codec ); +#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context ); if ( ret < 0 ) { Error( "Could not initialize stream parameteres"); return false; } +#endif AVDictionary *opts = NULL; av_dict_set( &opts, "strict", "experimental", 0); From 070f0d5d62009cde9939f95952ee817c9ba5a953 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 6 Jun 2017 15:57:42 -0400 Subject: [PATCH 08/18] don't init converted_input_samples --- src/zm_videostore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_videostore.h b/src/zm_videostore.h index e4d337df0..36ddd7bcf 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -46,7 +46,7 @@ private: #ifdef HAVE_LIBAVRESAMPLE AVAudioResampleContext* resample_context; #endif - uint8_t *converted_input_samples = NULL; + uint8_t *converted_input_samples; const char *filename; const char *format; From a9ebcd6e8aa11aa284bbc68fddc2d8d42375de91 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 6 Jun 2017 16:03:10 -0400 Subject: [PATCH 09/18] set email address to send complaints to --- code_of_conduct.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code_of_conduct.md b/code_of_conduct.md index d05f4bc06..aa6195359 100644 --- a/code_of_conduct.md +++ b/code_of_conduct.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +reported by contacting the project team at abuse@zoneminder.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. From 214d9898a387efaa3a01417185c3f60e4cbd06d4 Mon Sep 17 00:00:00 2001 From: Ravaka Razafimanantsoa Date: Wed, 7 Jun 2017 02:22:37 +0200 Subject: [PATCH 10/18] Enchancing Dockerfile and docker execution (#1898) * Enchancing Dockerfile and docker execution * Setting database if does not exist\nSolving SQL problem when adding monitor * Sharing events and images * Dockerfile a little bit more flexible * Setting better start command --- Dockerfile | 91 +++++++++++++++++++++++++++++++--------- utils/docker/setup.sh | 97 ++++++++++++++++++++++++++++--------------- utils/docker/start.sh | 2 +- 3 files changed, 136 insertions(+), 54 deletions(-) diff --git a/Dockerfile b/Dockerfile index 27b5bc636..5486703a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,75 @@ -# ZoneMinder +# ZoneMinder, you need the GIT repository code and submodules (git submodule update --init --recursive) FROM ubuntu:xenial MAINTAINER Markos Vakondios # Resynchronize the package index files -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libpolkit-gobject-1-dev build-essential libmysqlclient-dev libssl-dev libbz2-dev libpcre3-dev \ - libdbi-perl libarchive-zip-perl libdate-manip-perl libdevice-serialport-perl libmime-perl libpcre3 \ - libwww-perl libdbd-mysql-perl libsys-mmap-perl yasm cmake libjpeg-turbo8-dev \ - libjpeg-turbo8 libtheora-dev libvorbis-dev libvpx-dev libx264-dev libmp4v2-dev libav-tools mysql-client \ - apache2 php php-mysql libapache2-mod-php php-cli \ - mysql-server libvlc-dev libvlc5 libvlccore-dev libvlccore8 vlc-data libcurl4-openssl-dev \ - libavformat-dev libswscale-dev libavutil-dev libavcodec-dev libavfilter-dev \ - libavresample-dev libavdevice-dev libpostproc-dev libv4l-dev libtool libnetpbm10-dev \ - libmime-lite-perl dh-autoreconf dpatch \ - && apt-get clean +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + apache2 \ + build-essential \ + cmake \ + dh-autoreconf \ + dpatch \ + libapache2-mod-php \ + libarchive-zip-perl \ + libavcodec-dev \ + libavdevice-dev \ + libavfilter-dev \ + libavformat-dev \ + libavresample-dev \ + libav-tools \ + libavutil-dev \ + libbz2-dev \ + libcurl4-openssl-dev \ + libdate-manip-perl \ + libdbd-mysql-perl \ + libdbi-perl \ + libdevice-serialport-perl \ + libjpeg-turbo8 \ + libjpeg-turbo8-dev \ + libmime-lite-perl \ + libmime-perl \ + libmp4v2-dev \ + libmysqlclient-dev \ + libnetpbm10-dev \ + libpcre3 \ + libpcre3-dev \ + libpolkit-gobject-1-dev \ + libpostproc-dev \ + libssl-dev \ + libswscale-dev \ + libsys-mmap-perl \ + libtheora-dev \ + libtool \ + libv4l-dev \ + libvlc5 \ + libvlccore8 \ + libvlccore-dev \ + libvlc-dev \ + libvorbis-dev \ + libvpx-dev \ + libwww-perl \ + libx264-dev \ + mysql-client \ + mysql-server \ + php \ + php-cli \ + php-mysql \ + vlc-data \ + yasm \ + && rm -rf /var/lib/apt/lists/* # Copy local code into our container -ADD . /ZoneMinder +ADD cmake /ZoneMinder/cmake/ +ADD db /ZoneMinder/db/ +ADD misc /ZoneMinder/misc/ +ADD onvif /ZoneMinder/onvif/ +ADD scripts /ZoneMinder/scripts/ +ADD src /ZoneMinder/src/ +ADD umutils /ZoneMinder/umutils/ +ADD web /ZoneMinder/web/ +ADD cmakecacheimport.sh CMakeLists.txt version zm.conf.in zmconfgen.pl.in zmlinkcontent.sh.in zoneminder-config.cmake /ZoneMinder/ # Change into the ZoneMinder directory WORKDIR /ZoneMinder @@ -39,18 +90,20 @@ RUN ./zmlinkcontent.sh # Adding the start script ADD utils/docker/start.sh /tmp/start.sh -# give files in /usr/local/share/zoneminder/ +# Settings rights for /usr/local/share/zoneminder/ RUN chown -R www-data:www-data /usr/local/share/zoneminder/ # Adding apache virtual hosts file RUN cp misc/apache.conf /etc/apache2/sites-available/000-default.conf -ADD utils/docker/phpdate.ini /etc/php5/apache2/conf.d/25-phpdate.ini # Expose http port EXPOSE 80 -# Initial database and apache setup: -RUN "/ZoneMinder/utils/docker/setup.sh" +VOLUME /var/lib/zoneminder/images /var/lib/zoneminder/events /var/lib/mysql /var/log/zm -CMD ["/ZoneMinder/utils/docker/start.sh"] +# To speed up configuration testing, we put it here +ADD utils/docker /ZoneMinder/utils/docker/ +CMD /ZoneMinder/utils/docker/setup.sh && /ZoneMinder/utils/docker/start.sh >/var/log/start.log 2>&1 & /bin/bash + +# Run example docker run -it -p 1080:80 -e PHP_TIMEZONE='Europe/Paris' -v /disk/zoneminder/events:/var/lib/zoneminder/events -v /disk/zoneminder/images:/var/lib/zoneminder/images -v /disk/zoneminder/mysql:/var/lib/mysql -v /disk/zoneminder/logs:/var/log/zm --name zoneminder zoneminder/zoneminder diff --git a/utils/docker/setup.sh b/utils/docker/setup.sh index 603035a0b..d1572d494 100755 --- a/utils/docker/setup.sh +++ b/utils/docker/setup.sh @@ -1,46 +1,75 @@ #!/bin/bash -# Start MySQL -# For Xenial the following won't start mysqld -#/usr/bin/mysqld_safe & -# Use this instead: -service mysql start - -# Give MySQL time to wake up -SECONDS_LEFT=120 -while true; do - sleep 1 - mysqladmin ping - if [ $? -eq 0 ];then - break; # Success +setup_mysql_first_time(){ + if [ "$(ls /var/lib/mysql)" ]; then + return fi - let SECONDS_LEFT=SECONDS_LEFT-1 - # If we have waited >120 seconds, give up - # ZM should never have a database that large! - # if $COUNTER -lt 120 - if [ $SECONDS_LEFT -eq 0 ];then - return -1; - fi -done + # Set MySQL in the volume + rm -rf /var/lib/mysql/* + chown -R mysql:mysql /var/lib/mysql + mysqld --initialize-insecure + + # Start MySQL + # For Xenial the following won't start mysqld + #/usr/bin/mysqld_safe & + # Use this instead: + service mysql start -# Create the ZoneMinder database -mysql -u root < db/zm_create.sql + # Give MySQL time to wake up + SECONDS_LEFT=120 + while true; do + sleep 1 + mysqladmin ping + if [ $? -eq 0 ];then + break; # Success + fi + let SECONDS_LEFT=SECONDS_LEFT-1 -# Add the ZoneMinder DB user -mysql -u root -e "grant insert,select,update,delete,lock tables,alter on zm.* to 'zmuser'@'localhost' identified by 'zmpass';" + # If we have waited >120 seconds, give up + # ZM should never have a database that large! + # if $COUNTER -lt 120 + if [ $SECONDS_LEFT -eq 0 ];then + return -1; + fi + done -# Make ZM_LOGDIR -mkdir /var/log/zm + # Create the ZoneMinder database + mysql -u root < db/zm_create.sql -# Activate CGI -a2enmod cgi + # Add the ZoneMinder DB user + mysql -u root -e "grant insert,select,update,delete,lock tables,alter on zm.* to 'zmuser'@'localhost' identified by 'zmpass';" + + # Shut down mysql cleanly: + kill $(cat /var/run/mysqld/mysqld.pid) + sleep 5 +} -# Activate modrewrite -a2enmod rewrite +setup_mysql() { + # To configure MySQL if no container did it before + setup_mysql_first_time + + # Add configuration to avoid SQL error when adding monitor + echo "sql_mode=NO_ENGINE_SUBSTITUTION" >> /etc/mysql/mysql.conf.d/mysqld.cnf +} -# Shut down mysql cleanly: -kill $(cat /var/run/mysqld/mysqld.pid) -sleep 5 +setup_php() { + # Activate CGI + a2enmod cgi + + # Activate modrewrite + a2enmod rewrite + + # Setting timezone + sed -i "s#;date.timezone =#date.timezone = $PHP_TIMEZONE#" /etc/php/7.0/apache2/php.ini + + # Settings rights for volume + chown -R www-data:www-data /var/lib/zoneminder/events + chown -R www-data:www-data /var/lib/zoneminder/images +} + + +setup_mysql +setup_php exit 0 diff --git a/utils/docker/start.sh b/utils/docker/start.sh index 86247e734..599b6fcb2 100755 --- a/utils/docker/start.sh +++ b/utils/docker/start.sh @@ -35,7 +35,7 @@ done service apache2 restart # Start ZoneMinder -/usr/local/bin/zmpkg.pl start +/usr/local/bin/zmpkg.pl start && echo "Zone Minder started" while : do From c55814647cae7f48e40df589aa57e873c223f07b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 7 Jun 2017 15:28:31 -0400 Subject: [PATCH 11/18] fix spacing, braces, quotes --- scripts/zmcamtool.pl.in | 497 ++++++++++++++++++++-------------------- 1 file changed, 246 insertions(+), 251 deletions(-) diff --git a/scripts/zmcamtool.pl.in b/scripts/zmcamtool.pl.in index e0260ac13..e26aca8a6 100644 --- a/scripts/zmcamtool.pl.in +++ b/scripts/zmcamtool.pl.in @@ -55,6 +55,7 @@ a sql file, which can then be easily imported to another zoneminder system. --help - Print usage information. --user= - Alternate dB user with privileges to alter dB. --pass= - Password of alternate dB user with privileges to alter dB. + --version - Print version. =cut use strict; @@ -105,43 +106,43 @@ $Config{ZM_DB_USER} = $dbUser; $Config{ZM_DB_PASS} = $dbPass; if ( $version ) { - print( ZoneMinder::Base::ZM_VERSION . "\n"); - exit(0); + print( ZoneMinder::Base::ZM_VERSION . "\n"); + exit(0); } # Check to make sure commandline params make sense if ( ((!$help) && ($import + $export + $topreset) != 1 )) { - print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ ); - pod2usage(-exitstatus => -1); + print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ ); + pod2usage(-exitstatus => -1); } if ( ($export)&&($overwrite) ) { - print( "Warning: Overwrite parameter ignored during an export.\n"); + print( "Warning: Overwrite parameter ignored during an export.\n"); } if ( ($noregex)&&(!$topreset) ) { - print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/); + print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/); } if ( ($topreset)&&($ARGV[0] !~ /\d\d*/) ) { - print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ ); - pod2usage(-exitstatus => -1); + print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ ); + pod2usage(-exitstatus => -1); } # Call the appropriate subroutine based on the params given on the commandline if ($help) { - pod2usage(-exitstatus => -1); + pod2usage(-exitstatus => -1); } if ($export) { - exportsql(); + exportsql(); } if ($import) { - importsql(); + importsql(); } if ($topreset) { - toPreset(); + toPreset(); } ############### @@ -149,299 +150,293 @@ if ($topreset) { ############### # Execute a pre-built sql select query -sub selectQuery -{ - my $dbh = shift; - my $sql = shift; - my $monitorid = shift; +sub selectQuery { + my $dbh = shift; + my $sql = shift; + my $monitorid = shift; - my $sth = $dbh->prepare_cached( $sql ) - or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($monitorid) - or die( "Can't execute: ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($monitorid) + or die( "Can't execute: ".$sth->errstr() ); - my @data = $sth->fetchrow_array(); - $sth->finish(); + my @data = $sth->fetchrow_array(); + $sth->finish(); - return @data; + return @data; } # Exectute a pre-built sql query -sub runQuery -{ - my $dbh = shift; - my $sql = shift; - my $sth = $dbh->prepare_cached( $sql ) - or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() - or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); +sub runQuery { + my $dbh = shift; + my $sql = shift; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql insert query -sub insertQuery -{ - my $dbh = shift; - my $tablename = shift; - my @data = @_; +sub insertQuery { + my $dbh = shift; + my $tablename = shift; + my @data = @_; - my $sql = "INSERT INTO $tablename VALUES (NULL," - .(join ", ", ("?") x @data).")"; # Add "?" for each array element + my $sql = "INSERT INTO $tablename VALUES (NULL," + .(join ', ', ('?') x @data).')'; # Add "?" for each array element my $sth = $dbh->prepare_cached( $sql ) - or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute(@data) - or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute(@data) + or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql delete query -sub deleteQuery -{ - my $dbh = shift; - my $sqltable = shift; - my $sqlname = shift; +sub deleteQuery { + my $dbh = shift; + my $sqltable = shift; + my $sqlname = shift; - my $sql = "DELETE FROM $sqltable WHERE Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) - or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) - or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + my $sql = "DELETE FROM $sqltable WHERE Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) + or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql select count query -sub checkExists -{ - my $dbh = shift; - my $sqltable = shift; - my $sqlname = shift; - my $result = 0; +sub checkExists { + my $dbh = shift; + my $sqltable = shift; + my $sqlname = shift; + my $result = 0; - my $sql = "SELECT count(*) FROM $sqltable WHERE Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) - or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) - or die( "Can't execute: ".$sth->errstr() ); + my $sql = "SELECT count(*) FROM $sqltable WHERE Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) + or die( "Can't execute: ".$sth->errstr() ); - my $rows = $sth->fetchrow_arrayref(); - $sth->finish(); + my $rows = $sth->fetchrow_arrayref(); + $sth->finish(); - if ($rows->[0] > 0) { - $result = 1; - } + if ($rows->[0] > 0) { + $result = 1; + } - return $result; + return $result; } # Import camera control & presets into the zoneminder dB -sub importsql -{ - my @newcontrols; - my @overwritecontrols; - my @skippedcontrols; - my @newpresets; - my @overwritepresets; - my @skippedpresets; - my %controls; - my %monitorpresets; +sub importsql { + my @newcontrols; + my @overwritecontrols; + my @skippedcontrols; + my @newpresets; + my @overwritepresets; + my @skippedpresets; + my %controls; + my %monitorpresets; - if ($ARGV[0]) { - $sqlfile = $ARGV[0]; + if ($ARGV[0]) { + $sqlfile = $ARGV[0]; + } else { + $sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql'; + } + + open(my $SQLFILE,'<',$sqlfile) + or die( "Can't Open file: $!\n" ); + +# Find and extract ptz control and monitor preset records + while (<$SQLFILE>) { +# Our regex replaces the primary key with NULL + if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { + $controls{$3} = $_; + } elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { + $monitorpresets{$3} = $_; + } + } + close $SQLFILE; + + if ( ! (%controls || %monitorpresets) ) { + die( "Error: No relevant data found in $sqlfile.\n" ); + } + +# Now that we've got what we were looking for, +# compare to what is already in the dB + + my $dbh = zmDbConnect(); + foreach (keys %controls) { + if (!checkExists($dbh,'Controls',$_)) { +# No existing Control was found. Add new control to dB. + runQuery($dbh,$controls{$_}); + push @newcontrols, $_; + } elsif ($overwrite) { +# An existing Control was found and the overwrite flag is set. +# Overwrite the control. + deleteQuery($dbh,'Controls',$_); + runQuery($dbh,$controls{$_}); + push @overwritecontrols, $_; } else { - $sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql'; - } +# An existing Control was found and the overwrite flag was not set. +# Do nothing. + push @skippedcontrols, $_; + } + } - open(my $SQLFILE,"<",$sqlfile) - or die( "Can't Open file: $!\n" ); + foreach (keys %monitorpresets) { + if (!checkExists($dbh,'MonitorPresets',$_)) { +# No existing MonitorPreset was found. Add new MonitorPreset to dB. + runQuery($dbh,$monitorpresets{$_}); + push @newpresets, $_; + } elsif ($overwrite) { +# An existing MonitorPreset was found and the overwrite flag is set. +# Overwrite the MonitorPreset. + deleteQuery($dbh,'MonitorPresets',$_); + runQuery($dbh,$monitorpresets{$_}); + push @overwritepresets, $_; + } else { +# An existing MonitorPreset was found and the overwrite flag was +# not set. Do nothing. + push @skippedpresets, $_; + } + } - # Find and extract ptz control and monitor preset records - while (<$SQLFILE>) { - # Our regex replaces the primary key with NULL - if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { - $controls{$3} = $_; - } elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { - $monitorpresets{$3} = $_; - } - } - close $SQLFILE; + if (@newcontrols) { + print 'Number of ptz camera controls added: ' + .scalar(@newcontrols)."\n"; + } + if (@overwritecontrols) { + print 'Number of existing ptz camera controls overwritten: ' + .scalar(@overwritecontrols)."\n"; + } + if (@skippedcontrols) { + print 'Number of existing ptz camera controls skipped: ' + .scalar(@skippedcontrols)."\n"; + } - if ( ! (%controls || %monitorpresets) ) { - die( "Error: No relevant data found in $sqlfile.\n" ); - } - - # Now that we've got what we were looking for, - # compare to what is already in the dB - - my $dbh = zmDbConnect(); - foreach (keys %controls) { - if (!checkExists($dbh,"Controls",$_)) { - # No existing Control was found. Add new control to dB. - runQuery($dbh,$controls{$_}); - push @newcontrols, $_; - } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. - # Overwrite the control. - deleteQuery($dbh,"Controls",$_); - runQuery($dbh,$controls{$_}); - push @overwritecontrols, $_; - } else { - # An existing Control was found and the overwrite flag was not set. - # Do nothing. - push @skippedcontrols, $_; - } - } - - foreach (keys %monitorpresets) { - if (!checkExists($dbh,"MonitorPresets",$_)) { - # No existing MonitorPreset was found. Add new MonitorPreset to dB. - runQuery($dbh,$monitorpresets{$_}); - push @newpresets, $_; - } elsif ($overwrite) { - # An existing MonitorPreset was found and the overwrite flag is set. - # Overwrite the MonitorPreset. - deleteQuery($dbh,"MonitorPresets",$_); - runQuery($dbh,$monitorpresets{$_}); - push @overwritepresets, $_; - } else { - # An existing MonitorPreset was found and the overwrite flag was - # not set. Do nothing. - push @skippedpresets, $_; - } - } - - if (@newcontrols) { - print "Number of ptz camera controls added: " - .scalar(@newcontrols)."\n"; - } - if (@overwritecontrols) { - print "Number of existing ptz camera controls overwritten: " - .scalar(@overwritecontrols)."\n"; - } - if (@skippedcontrols) { - print "Number of existing ptz camera controls skipped: " - .scalar(@skippedcontrols)."\n"; - } - - if (@newpresets) { - print "Number of monitor presets added: " - .scalar(@newpresets)."\n"; - } - if (@overwritepresets) { - print "Number of existing monitor presets overwritten: " - .scalar(@overwritepresets)."\n"; - } - if (@skippedpresets) { - print "Number of existing presets skipped: " - .scalar(@skippedpresets)."\n"; - } + if (@newpresets) { + print 'Number of monitor presets added: ' + .scalar(@newpresets)."\n"; + } + if (@overwritepresets) { + print 'Number of existing monitor presets overwritten: ' + .scalar(@overwritepresets)."\n"; + } + if (@skippedpresets) { + print 'Number of existing presets skipped: ' + .scalar(@skippedpresets)."\n"; + } } # Export camera controls & presets from the zoneminder dB to STDOUT -sub exportsql -{ +sub exportsql { -my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); -my $command = "mysqldump -t --skip-opt --compact -h".$host; -$command .= " -P".$port if defined($port); -if ( $dbUser ) { - $command .= " -u".$dbUser; + my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); + my $command = 'mysqldump -t --skip-opt --compact -h'.$host; + $command .= ' -P'.$port if defined($port); + if ( $dbUser ) { + $command .= ' -u'.$dbUser; if ( $dbPass ) { - $command .= " -p".$dbPass; - } + $command .= ' -p'.$dbPass; } + } -if ($ARGV[0]) { + if ($ARGV[0]) { $command .= qq( --where="Name = '$ARGV[0]'"); -} + } -$command .= " zm Controls MonitorPresets"; + $command .= " zm Controls MonitorPresets"; -my $output = qx($command); -my $status = $? >> 8; -if ( $status || logDebugging() ) { + my $output = qx($command); + my $status = $? >> 8; + if ( $status || logDebugging() ) { chomp( $output ); print( "Output: $output\n" ); -} -if ( $status ) { + } + if ( $status ) { die( "Command '$command' exited with status: $status\n" ); -} else { - # NULLify the primary keys before printing the output to STDOUT + } else { +# NULLify the primary keys before printing the output to STDOUT $output =~ s/VALUES \((.*?),'/VALUES \(NULL,'/ig; print $output; - } + } } -sub toPreset -{ - my $dbh = zmDbConnect(); - my $monitorid = $ARGV[0]; +sub toPreset { + my $dbh = zmDbConnect(); + my $monitorid = $ARGV[0]; - # Grap the following fields from the Monitors table - my $sql = "SELECT - Name, - Type, - Device, - Channel, - Format, - Protocol, - Method, - Host, - Port, - Path, - SubPath, - Width, - Height, - Palette, - MaxFPS, - Controllable, - ControlId, - ControlDevice, - ControlAddress, - DefaultRate, - DefaultScale - FROM Monitors WHERE Id = ?"; - my @data = selectQuery($dbh,$sql,$monitorid); +# Grap the following fields from the Monitors table + my $sql = 'SELECT + Name, + Type, + Device, + Channel, + Format, + Protocol, + Method, + Host, + Port, + Path, + SubPath, + Width, + Height, + Palette, + MaxFPS, + Controllable, + ControlId, + ControlDevice, + ControlAddress, + DefaultRate, + DefaultScale + FROM Monitors WHERE Id = ?'; + my @data = selectQuery($dbh,$sql,$monitorid); - if (!@data) { - die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" ); + if (!@data) { + die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" ); + } + +# Attempt to search for and replace system specific values such as +# ip addresses, ports, usernames, etc. with generic placeholders + if (!$noregex) { + foreach (@data) { + next if ! $_; + s/\b(?:\d{1,3}\.){3}\d{1,3}\b//; # ip address + s/:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/:/; # tcpip port + s/\/\/.*:.*@/\/\/:@/; # user & pwd preceding an ip address + s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=$3/i; # username embedded in url + s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=$3/i; # password embedded in url + s/\w\w*:\w\w*/:/; # user & pwd in their own field + s/\/dev\/video\d\d*/\/dev\/video/; # local video devices } + } - # Attempt to search for and replace system specific values such as - # ip addresses, ports, usernames, etc. with generic placeholders - if (!$noregex) { - foreach (@data) { - next if ! $_; - s/\b(?:\d{1,3}\.){3}\d{1,3}\b//; # ip address - s/:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/:/; # tcpip port - s/\/\/.*:.*@/\/\/:@/; # user & pwd preceding an ip address - s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=$3/i; # username embedded in url - s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=$3/i; # password embedded in url - s/\w\w*:\w\w*/:/; # user & pwd in their own field - s/\/dev\/video\d\d*/\/dev\/video/; # local video devices - } - } - - if (!checkExists($dbh,"MonitorPresets",$data[0])) { - # No existing Preset was found. Add new Preset to dB. - print "Adding new preset: $data[0]\n"; - insertQuery($dbh,"MonitorPresets",@data); - } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. - # Overwrite the control. - print "Existing preset $data[0] detected.\nOverwriting...\n"; - deleteQuery($dbh,"MonitorPresets",$data[0]); - insertQuery($dbh,"MonitorPresets",@data); - } else { - # An existing Control was found and the overwrite flag was not set. - # Do nothing. - print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n"; - } + if (!checkExists($dbh,"MonitorPresets",$data[0])) { +# No existing Preset was found. Add new Preset to dB. + print "Adding new preset: $data[0]\n"; + insertQuery($dbh,'MonitorPresets',@data); + } elsif ($overwrite) { +# An existing Control was found and the overwrite flag is set. +# Overwrite the control. + print "Existing preset $data[0] detected.\nOverwriting...\n"; + deleteQuery($dbh,'MonitorPresets',$data[0]); + insertQuery($dbh,'MonitorPresets',@data); + } else { +# An existing Control was found and the overwrite flag was not set. +# Do nothing. + print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n"; + } } +1; +__END__ From 84fd80b242a6299194226160fb0ecddb6a99c4aa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Jun 2017 12:21:51 -0400 Subject: [PATCH 12/18] undo cake log path changes --- web/api/app/Config/bootstrap.php.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/api/app/Config/bootstrap.php.in b/web/api/app/Config/bootstrap.php.in index a2bfe9c26..ac3bcb62c 100644 --- a/web/api/app/Config/bootstrap.php.in +++ b/web/api/app/Config/bootstrap.php.in @@ -100,12 +100,12 @@ App::uses('CakeLog', 'Log'); CakeLog::config('debug', array( 'engine' => 'File', 'types' => array('notice', 'info', 'debug'), - 'file' => '@ZM_LOGDIR@/cake_debug', + 'file' => 'cake_debug', )); CakeLog::config('error', array( 'engine' => 'File', 'types' => array('warning', 'error', 'critical', 'alert', 'emergency'), - 'file' => '@ZM_LOGDIR@/cake_error', + 'file' => 'cake_error', )); CakeLog::config('custom_path', array( 'engine' => 'File', From 81c2216eb6b867dc29a0633d5435acdeb4a7f95d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Jun 2017 13:37:26 -0400 Subject: [PATCH 13/18] spaces/quotes --- web/ajax/event.php | 203 +++++++++++++++++++++++---------------------- 1 file changed, 102 insertions(+), 101 deletions(-) diff --git a/web/ajax/event.php b/web/ajax/event.php index 5291f0f7a..661a2f1ce 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -1,119 +1,120 @@ $videoFile ) ); - else - ajaxError( "Video Generation Failed" ); - } - $ok = true; - break; + switch ( $_REQUEST['action'] ) { + case 'video' : + { + if ( empty($_REQUEST['videoFormat']) ) { + ajaxError( 'Video Generation Failure, no format given' ); + } elseif ( empty($_REQUEST['rate']) ) { + ajaxError( 'Video Generation Failure, no rate given' ); + } elseif ( empty($_REQUEST['scale']) ) { + ajaxError( 'Video Generation Failure, no scale given' ); + } else { + $sql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultRate,M.DefaultScale FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?'.monitorLimitSql(); + if ( !($event = dbFetchOne( $sql, NULL, array( $_REQUEST['id'] ) )) ) + ajaxError( "Video Generation Failure, can't load event" ); + else + if ( $videoFile = createVideo( $event, $_REQUEST['videoFormat'], $_REQUEST['rate'], $_REQUEST['scale'], !empty($_REQUEST['overwrite']) ) ) + ajaxResponse( array( 'response'=>$videoFile ) ); + else + ajaxError( "Video Generation Failed" ); } - case 'deleteVideo' : - { - unlink( $videoFiles[$_REQUEST['id']] ); - unset( $videoFiles[$_REQUEST['id']] ); - ajaxResponse(); - break; - } - case "export" : - { - require_once( ZM_SKIN_PATH.'/includes/export_functions.php' ); + $ok = true; + break; + } + case 'deleteVideo' : + { + unlink( $videoFiles[$_REQUEST['id']] ); + unset( $videoFiles[$_REQUEST['id']] ); + ajaxResponse(); + break; + } + case 'export' : + { + require_once( ZM_SKIN_PATH.'/includes/export_functions.php' ); - # We use session vars in here, so we need to restart the session because we stopped it in index.php to improve concurrency. - session_start(); +# We use session vars in here, so we need to restart the session because we stopped it in index.php to improve concurrency. + session_start(); - if ( !empty($_REQUEST['exportDetail']) ) - $exportDetail = $_SESSION['export']['detail'] = $_REQUEST['exportDetail']; - else - $exportDetail = false; - if ( !empty($_REQUEST['exportFrames']) ) - $exportFrames = $_SESSION['export']['frames'] = $_REQUEST['exportFrames']; - else - $exportFrames = false; - if ( !empty($_REQUEST['exportImages']) ) - $exportImages = $_SESSION['export']['images'] = $_REQUEST['exportImages']; - else - $exportImages = false; - if ( !empty($_REQUEST['exportVideo']) ) - $exportVideo = $_SESSION['export']['video'] = $_REQUEST['exportVideo']; - else - $exportVideo = false; - if ( !empty($_REQUEST['exportMisc']) ) - $exportMisc = $_SESSION['export']['misc'] = $_REQUEST['exportMisc']; - else - $exportMisc = false; - if ( !empty($_REQUEST['exportFormat']) ) - $exportFormat = $_SESSION['export']['format'] = $_REQUEST['exportFormat']; - else - $exportFormat = ''; + if ( !empty($_REQUEST['exportDetail']) ) + $exportDetail = $_SESSION['export']['detail'] = $_REQUEST['exportDetail']; + else + $exportDetail = false; + if ( !empty($_REQUEST['exportFrames']) ) + $exportFrames = $_SESSION['export']['frames'] = $_REQUEST['exportFrames']; + else + $exportFrames = false; + if ( !empty($_REQUEST['exportImages']) ) + $exportImages = $_SESSION['export']['images'] = $_REQUEST['exportImages']; + else + $exportImages = false; + if ( !empty($_REQUEST['exportVideo']) ) + $exportVideo = $_SESSION['export']['video'] = $_REQUEST['exportVideo']; + else + $exportVideo = false; + if ( !empty($_REQUEST['exportMisc']) ) + $exportMisc = $_SESSION['export']['misc'] = $_REQUEST['exportMisc']; + else + $exportMisc = false; + if ( !empty($_REQUEST['exportFormat']) ) + $exportFormat = $_SESSION['export']['format'] = $_REQUEST['exportFormat']; + else + $exportFormat = ''; - session_write_close(); + session_write_close(); - $exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id']; - if ( $exportFile = exportEvents( $exportIds, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat ) ) - ajaxResponse( array( 'exportFile'=>$exportFile ) ); - else - ajaxError( "Export Failed" ); - break; - } - } + $exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id']; + if ( $exportFile = exportEvents( $exportIds, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat ) ) + ajaxResponse( array( 'exportFile'=>$exportFile ) ); + else + ajaxError( 'Export Failed' ); + break; + } + } } if ( canEdit( 'Events' ) ) { - switch ( $_REQUEST['action'] ) { - case 'rename' : - { - if ( !empty($_REQUEST['eventName']) ) - dbQuery( 'UPDATE Events SET Name = ? WHERE Id = ?', array( $_REQUEST['eventName'], $_REQUEST['id'] ) ); - else - ajaxError( "No new event name supplied" ); - ajaxResponse( array( 'refreshEvent'=>true, 'refreshParent'=>true ) ); - break; + switch ( $_REQUEST['action'] ) { + case 'rename' : + { + if ( !empty($_REQUEST['eventName']) ) + dbQuery( 'UPDATE Events SET Name = ? WHERE Id = ?', array( $_REQUEST['eventName'], $_REQUEST['id'] ) ); + else + ajaxError( "No new event name supplied" ); + ajaxResponse( array( 'refreshEvent'=>true, 'refreshParent'=>true ) ); + break; + } + case 'eventdetail' : + { + dbQuery( 'UPDATE Events SET Cause = ?, Notes = ? WHERE Id = ?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['id'] ) ); + ajaxResponse( array( 'refreshEvent'=>true, 'refreshParent'=>true ) ); + break; + } + case 'archive' : + case 'unarchive' : + { + $archiveVal = ($_REQUEST['action'] == 'archive')?1:0; + dbQuery( 'UPDATE Events SET Archived = ? WHERE Id = ?', array( $archiveVal, $_REQUEST['id']) ); + ajaxResponse( array( 'refreshEvent'=>true, 'refreshParent'=>false ) ); + break; + } + case 'delete' : + { + $Event = new Event( $_REQUEST['id'] ); + if ( ! $Event->Id() ) { + ajaxResponse( array( 'refreshEvent'=>false, 'refreshParent'=>true, 'message'=> 'Event not found.' ) ); + } else { + $Event->delete(); + ajaxResponse( array( 'refreshEvent'=>false, 'refreshParent'=>true ) ); } - case 'eventdetail' : - { - dbQuery( 'UPDATE Events SET Cause = ?, Notes = ? WHERE Id = ?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['id'] ) ); - ajaxResponse( array( 'refreshEvent'=>true, 'refreshParent'=>true ) ); - break; - } - case 'archive' : - case 'unarchive' : - { - $archiveVal = ($_REQUEST['action'] == "archive")?1:0; - dbQuery( 'UPDATE Events SET Archived = ? WHERE Id = ?', array( $archiveVal, $_REQUEST['id']) ); - ajaxResponse( array( 'refreshEvent'=>true, 'refreshParent'=>false ) ); - break; - } - case 'delete' : - { - $Event = new Event( $_REQUEST['id'] ); - if ( ! $Event->Id() ) { - ajaxResponse( array( 'refreshEvent'=>false, 'refreshParent'=>true, 'message'=> 'Event not found.' ) ); - } else { - $Event->delete(); - ajaxResponse( array( 'refreshEvent'=>false, 'refreshParent'=>true ) ); - } - break; - } - } + break; + } + } } ajaxError( 'Unrecognised action or insufficient permissions' ); From d7b291f9331c69b02d8a08056bf8ee9fe1bc0cc9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Jun 2017 13:44:22 -0400 Subject: [PATCH 14/18] add more debug --- src/zm_user.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 12dcf0cf4..08f8ff820 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -171,7 +171,7 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) Debug( 1, "Attempting to authenticate user from auth string '%s'", auth ); char sql[ZM_SQL_SML_BUFSIZ] = ""; - snprintf( sql, sizeof(sql), "select Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds from Users where Enabled = 1" ); + snprintf( sql, sizeof(sql), "SELECT Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds FROM Users WHERE Enabled = 1" ); if ( mysql_query( &dbconn, sql ) ) { @@ -232,7 +232,7 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { sprintf( &auth_md5[2*j], "%02x", md5sum[j] ); } - Debug( 1, "Checking auth_key '%s' -> auth_md5 '%s'", auth_key, auth_md5 ); + Debug( 1, "Checking auth_key '%s' -> auth_md5 '%s' == '%s'", auth_key, auth_md5, auth ); if ( !strcmp( auth, auth_md5 ) ) { @@ -246,5 +246,6 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) #else // HAVE_DECL_MD5 Error( "You need to build with gnutls or openssl installed to use hash based authentication" ); #endif // HAVE_DECL_MD5 + Debug(1, "No user found for auth_key %s", auth ); return( 0 ); } From 405078686a12e270c881c6ddfe3aefa8094a37d1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Jun 2017 14:01:22 -0400 Subject: [PATCH 15/18] update getStreamSrc to take a hash instead of an array of thing=thing --- web/includes/Event.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index f4bf4a3da..70668690b 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -137,28 +137,27 @@ class Event { $streamSrc = ZM_BASE_URL.ZM_PATH_ZMS; - $args[] = 'source=event&event='.$this->{'Id'}; + $args['source'] = 'event'; + $args['event'] = $this->{'Id'}; if ( ZM_OPT_USE_AUTH ) { if ( ZM_AUTH_RELAY == 'hashed' ) { - $args[] = 'auth='.generateAuthHash( ZM_AUTH_HASH_IPS ); + $args['auth'] = generateAuthHash( ZM_AUTH_HASH_IPS ); } elseif ( ZM_AUTH_RELAY == 'plain' ) { - $args[] = 'user='.$_SESSION['username']; - $args[] = 'pass='.$_SESSION['password']; + $args['user'] = $_SESSION['username']; + $args['pass'] = $_SESSION['password']; } elseif ( ZM_AUTH_RELAY == "none" ) { - $args[] = 'user='.$_SESSION['username']; + $args['user'] = $_SESSION['username']; } } - if ( !in_array( 'mode=single', $args ) && !empty($GLOBALS['connkey']) ) { - $args[] = 'connkey='.$GLOBALS['connkey']; + if ( ( (!isset($args['mode'])) or ( $args['mode'] != 'single' ) ) && !empty($GLOBALS['connkey']) ) { + $args['connkey'] = $GLOBALS['connkey']; } if ( ZM_RAND_STREAM ) { - $args[] = 'rand='.time(); + $args['rand'] = time(); } - if ( count($args) ) { - $streamSrc .= '?'.join( $querySep, $args ); - } + $streamSrc .= '?'.http_build_query( $args,'', $querySep ); return( $streamSrc ); } // end function getStreamSrc From 2c1f576da40994cdcd2e492666ba4285f60e69ec Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Jun 2017 14:01:44 -0400 Subject: [PATCH 16/18] Don't need to check for values in args, beacuse we set one above --- web/includes/Monitor.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 9e4c6a95a..62a6ac230 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -198,9 +198,7 @@ private $control_fields = array( $args['rand'] = time(); } - if ( count($args) ) { - $streamSrc .= '?'.http_build_query( $args,'', $querySep ); - } + $streamSrc .= '?'.http_build_query( $args,'', $querySep ); return( $streamSrc ); } // end function getStreamSrc From cac5819331a66edc9e9779ab2be7ef178b91a209 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Jun 2017 14:02:27 -0400 Subject: [PATCH 17/18] update call to getStreamSrc to use ->getStreamSrc. Also remove extraneous canView(Event) --- web/skins/classic/views/event.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 1e1bedcda..c39b286ac 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -128,12 +128,11 @@ if ( canEdit( 'Events' ) ) { DefaultVideo() ) { ?> DefaultVideo -} // end if can edit Events -if ( canView( 'Events' ) ) { ?>
DefaultVideo() ) {
DefaultVideo() ) { ?>class="hidden" > getStreamSrc( array( 'mode'=>'mpeg', 'scale'=>$scale, 'rate'=>$rate, 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format'=>ZM_MPEG_REPLAY_FORMAT, 'replay'=>$replayMode ) ); outputVideoStream( "evtStream", $streamSrc, reScale( $Event->Width(), $scale ), reScale( $Event->Height(), $scale ), ZM_MPEG_LIVE_FORMAT ); } else { - $streamSrc = getStreamSrc( array( "source=event", "mode=jpeg", "event=".$eid, "frame=".$fid, "scale=".$scale, "rate=".$rate, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "replay=".$replayMode) ); + $streamSrc = $Event->getStreamSrc( array( 'mode'=>'jpeg', 'frame'=>$fid, 'scale'=>$scale, 'rate'=>$rate, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>$replayMode) ); if ( canStreamNative() ) { - outputImageStream( "evtStream", $streamSrc, reScale( $Event->Width(), $scale ), reScale( $Event->Height(), $scale ), validHtmlStr($Event->Name()) ); + outputImageStream( 'evtStream', $streamSrc, reScale( $Event->Width(), $scale ), reScale( $Event->Height(), $scale ), validHtmlStr($Event->Name()) ); } else { - outputHelperStream( "evtStream", $streamSrc, reScale( $Event->Width(), $scale ), reScale( $Event->Height(), $scale ) ); + outputHelperStream( 'evtStream', $streamSrc, reScale( $Event->Width(), $scale ), reScale( $Event->Height(), $scale ) ); } } // end if stream method ?> @@ -244,8 +243,7 @@ if ($Event->SaveJPEGs() & 3) { // frames or analysis
From c6a15185483579f5284f649e79fd86981e982984 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Jun 2017 14:03:07 -0400 Subject: [PATCH 18/18] remark out call to set progressBarWidth, but that should never change and it uses a var that isn't global barWidth --- web/skins/classic/views/js/event.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 236f65c7b..c27462c3e 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -628,17 +628,16 @@ function drawProgressBar() { var cells = $('progressBar').getElements( 'div' ); var cellWidth = parseInt( eventData.Width/$$(cells).length ); $$(cells).forEach( - function( cell, index ) - { + function( cell, index ) { if ( index == 0 ) - $(cell).setStyles( { 'left': barWidth, 'width': cellWidth, 'borderLeft': 0 } ); + $(cell).setStyles( { 'left': barWidth, 'width': cellWidth, 'borderLeft': 0 } ); else - $(cell).setStyles( { 'left': barWidth, 'width': cellWidth } ); - var offset = parseInt((index*eventData.Length)/$$(cells).length); - $(cell).setProperty( 'title', '+'+secsToTime(offset)+'s' ); - $(cell).removeEvent( 'click' ); - $(cell).addEvent( 'click', function() { streamSeek( offset ); } ); - barWidth += $(cell).getCoordinates().width; + $(cell).setStyles( { 'left': barWidth, 'width': cellWidth } ); + var offset = parseInt((index*eventData.Length)/$$(cells).length); + $(cell).setProperty( 'title', '+'+secsToTime(offset)+'s' ); + $(cell).removeEvent( 'click' ); + $(cell).addEvent( 'click', function() { streamSeek( offset ); } ); + barWidth += $(cell).getCoordinates().width; } ); $('progressBar').setStyle( 'width', barWidth ); @@ -662,7 +661,7 @@ function updateProgressBar() { } // end if } // end function ); - $('progressBar').setStyle( 'width', barWidth ); + //$('progressBar').setStyle( 'width', barWidth ); $('progressBar').removeClass( 'invisible' ); } // end if eventData && streamStatus } // end function updateProgressBar()