Merge branch 'release-1.36' of github.com:ZoneMinder/zoneminder into release-1.36

This commit is contained in:
Isaac Connor 2021-10-25 16:44:01 -04:00
commit 7517bdc6ec
102 changed files with 1581 additions and 1266 deletions

2
.github/FUNDING.yml vendored
View File

@ -2,7 +2,7 @@
github: [connortechnology,pliablepixels] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] github: [connortechnology,pliablepixels] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: zoneminder # Replace with a single Patreon username patreon: zoneminder # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username open_collective: zoneminder # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry

View File

@ -9,7 +9,7 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-16.04 runs-on: zm-xenial-ci
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

17
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,17 @@
default:
image:
name: ubuntu:latest
before_script:
- apt-get update -yq
- DEBIAN_FRONTEND=noninteractive apt-get install -yq devscripts sudo
deb:
stage: build
tags:
- docker
script:
- yes "" | ./utils/do_debian_package.sh --snapshot=stable --type=binary --interactive=no --dput=no --debbuild-extra=--no-sign || true
artifacts:
paths:
- '*.deb'
expire_in: 1 week

View File

@ -30,7 +30,7 @@ This is the recommended method to install ZoneMinder onto your system. ZoneMinde
- Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder) - Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder)
- RHEL/CentOS and clones via [RPM Fusion](http://rpmfusion.org) - RHEL/CentOS and clones via [RPM Fusion](http://rpmfusion.org)
- Fedora via [RPM Fusion](http://rpmfusion.org) - Fedora via [RPM Fusion](http://rpmfusion.org)
- OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE) - OpenSuse via [third party repository](https://wiki.zoneminder.com/Installing_using_ZoneMinder_RPMs_for_SuSE)
- Mageia from their default repository - Mageia from their default repository
- Arch via the [AUR](https://aur.archlinux.org/packages/zoneminder/) - Arch via the [AUR](https://aur.archlinux.org/packages/zoneminder/)
- Gentoo via [Portage Overlays](http://gpo.zugaina.org/www-misc/zoneminder) - Gentoo via [Portage Overlays](http://gpo.zugaina.org/www-misc/zoneminder)

View File

@ -539,7 +539,7 @@ CREATE TABLE `Monitors` (
`Longitude` DECIMAL(11,8), `Longitude` DECIMAL(11,8),
`RTSPServer` BOOLEAN NOT NULL DEFAULT FALSE, `RTSPServer` BOOLEAN NOT NULL DEFAULT FALSE,
`RTSPStreamName` varchar(255) NOT NULL default '', `RTSPStreamName` varchar(255) NOT NULL default '',
`Importance` enum('Not','Less','Normal'), `Importance` enum('Normal','Less','Not') NOT NULL default 'Normal',
PRIMARY KEY (`Id`) PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@; ) ENGINE=@ZM_MYSQL_ENGINE@;

2
db/zm_update-1.36.9.sql Normal file
View File

@ -0,0 +1,2 @@
UPDATE Monitors set Importance = 'Normal' where Importance IS NULL;
ALTER TABLE `Monitors` MODIFY `Importance` enum('Normal','Less','Not') NOT NULL default 'Normal';

View File

@ -36,7 +36,7 @@
%global _hardened_build 1 %global _hardened_build 1
Name: zoneminder Name: zoneminder
Version: 1.36.5 Version: 1.36.9
Release: 1%{?dist} Release: 1%{?dist}
Summary: A camera monitoring and analysis tool Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons Group: System Environment/Daemons
@ -430,6 +430,18 @@ ln -sf %{_sysconfdir}/zm/www/zoneminder.nginx.conf %{_sysconfdir}/zm/www/zonemin
%dir %attr(755,nginx,nginx) %{_localstatedir}/log/zoneminder %dir %attr(755,nginx,nginx) %{_localstatedir}/log/zoneminder
%changelog %changelog
* Tue Oct 19 2021 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.36.9-1
- 1.36.9 release
* Wed Oct 06 2021 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.36.8-1
- 1.36.8 release
* Mon Sep 13 2021 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.36.7-1
- 1.36.7 release
* Wed Sep 08 2021 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.36.6-1
- 1.36.6 release
* Tue Jun 22 2021 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.36.5-1 * Tue Jun 22 2021 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.36.5-1
- 1.36.5 release - 1.36.5 release

View File

@ -225,7 +225,7 @@ change the 3 to a 1
I can't see more than 6 monitors in montage on my browser I can't see more than 6 monitors in montage on my browser
--------------------------------------------------------- ---------------------------------------------------------
Browsers such a Chrome and Safari only support upto 6 streams from the same domain. To work around that, take a look at the multi-port configuration discussed in the ``MIN_STREAMING_PORT`` configuration in :doc:`/userguide/options/options_network` Browsers such a Chrome and Safari only support up to 6 streams from the same domain. To work around that, take a look at the multi-port configuration discussed in the ``MIN_STREAMING_PORT`` configuration in :doc:`/userguide/options/options_network`
Why is ZoneMinder using so much CPU? Why is ZoneMinder using so much CPU?
--------------------------------------- ---------------------------------------

View File

@ -56,13 +56,13 @@ Add the following to the /etc/apt/sources.list.d/zoneminder.list file
:: ::
# ZoneMinder repository # ZoneMinder repository
deb https://zmrepo.zoneminder.com/debian/release-1.34 buster/ deb https://zmrepo.zoneminder.com/debian/release-1.36 buster/
You can do this using: You can do this using:
.. code-block:: .. code-block::
echo "deb https://zmrepo.zoneminder.com/debian/release-1.34 buster/" | sudo tee /etc/apt/sources.list.d/zoneminder.list echo "deb https://zmrepo.zoneminder.com/debian/release-1.36 buster/" | sudo tee /etc/apt/sources.list.d/zoneminder.list
Because ZoneMinder's package repository provides a secure connection through HTTPS, apt must be enabled for HTTPS. Because ZoneMinder's package repository provides a secure connection through HTTPS, apt must be enabled for HTTPS.
:: ::
@ -158,7 +158,7 @@ You are now ready to go with ZoneMinder. Open a browser and type either ``localh
Easy Way: Debian Stretch Easy Way: Debian Stretch
------------------------ ------------------------
This procedure will guide you through the installation of ZoneMinder on Debian 9 (Stretch). This section has been tested with ZoneMinder 1.34 on Debian 9.8. This procedure will guide you through the installation of ZoneMinder on Debian 9 (Stretch). This section has been tested with ZoneMinder 1.36 on Debian 9.8.
**Step 1:** Make sure your system is up to date **Step 1:** Make sure your system is up to date
@ -204,7 +204,7 @@ Add the following to the bottom of the file
:: ::
# ZoneMinder repository # ZoneMinder repository
deb https://zmrepo.zoneminder.com/debian/release-1.34 stretch/ deb https://zmrepo.zoneminder.com/debian/release-1.36 stretch/
CTRL+o and <Enter> to save CTRL+o and <Enter> to save
CTRL+x to exit CTRL+x to exit

View File

@ -41,7 +41,7 @@ guide you with a quick search.
:: ::
add-apt-repository ppa:iconnor/zoneminder-1.34 add-apt-repository ppa:iconnor/zoneminder-1.36
Update repo and upgrade. Update repo and upgrade.

View File

@ -86,7 +86,7 @@ Source Path
Use this field to enter the full URL of the stream or file your camera supports. This is usually an RTSP url. There are several methods to learn this: Use this field to enter the full URL of the stream or file your camera supports. This is usually an RTSP url. There are several methods to learn this:
* Check the documentation that came with your camera * Check the documentation that came with your camera
* Look for your camera in the hardware compatibilty list in the `hardware compatibility wiki <https://wiki.zoneminder.com/Hardware_Compatibility_List>`__ * Look for your camera in the hardware compatibility list in the `hardware compatibility wiki <https://wiki.zoneminder.com/Hardware_Compatibility_List>`__
* Try ZoneMinder's new ONVIF probe feature * Try ZoneMinder's new ONVIF probe feature
* Download and install the `ONVIF Device Manager <https://sourceforge.net/projects/onvifdm/>`__ onto a Windows machine * Download and install the `ONVIF Device Manager <https://sourceforge.net/projects/onvifdm/>`__ onto a Windows machine
* Use Google to find third party sites, such as ispy, which document this information * Use Google to find third party sites, such as ispy, which document this information
@ -179,12 +179,12 @@ Storage Tab
The storage section allows for each monitor to configure if and how video and audio are recorded. The storage section allows for each monitor to configure if and how video and audio are recorded.
Save JPEGs Save JPEGs
Records video in individual JPEG frames. Storing JPEG frames requires more storage space than h264 but it allows to view an event anytime while it is being recorded. Records video in individual JPEG frames. Storing JPEG frames requires more storage space than h264 but it allows one to view an event anytime while it is being recorded.
* Disabled video is not recorded as JPEG frames. If this setting is selected, then "Video Writer" should be enabled otherwise there is no video recording at all. * Disabled video is not recorded as JPEG frames. If this setting is selected, then "Video Writer" should be enabled otherwise there is no video recording at all.
* Frames only video is recorded in individual JPEG frames. * Frames only video is recorded in individual JPEG frames.
* Analysis images only (if available) video is recorded in invidual JPEG frames with an overlay of the motion detection analysis information. Note that this overlay remains permanently visible in the frames. * Analysis images only (if available) video is recorded in individual JPEG frames with an overlay of the motion detection analysis information. Note that this overlay remains permanently visible in the frames.
* Frames + Analysis images (if available) video is recorded twice, once as normal individual JPEG frames and once in invidual JPEG frames with analysis information overlaid. * Frames + Analysis images (if available) video is recorded twice, once as normal individual JPEG frames and once in individual JPEG frames with analysis information overlaid.
Video Writer Video Writer
Records video in real video format. It provides much better compression results than saving JPEGs, thus longer video history can be stored. Records video in real video format. It provides much better compression results than saving JPEGs, thus longer video history can be stored.

View File

@ -34,7 +34,7 @@ Here is what the filter window looks like
* Update used disk space: calculates how much disk space is currently taken by the event and updates the db record. * Update used disk space: calculates how much disk space is currently taken by the event and updates the db record.
* Create video for all matches: creates a video file of all the events that match * Create video for all matches: creates a video file of all the events that match
* Create video for all matches: ffmpeg will be used to create a video file (mp4) out of all the stored jpgs if using jpeg storage. * Create video for all matches: ffmpeg will be used to create a video file (mp4) out of all the stored jpgs if using jpeg storage.
* Execute command on all matches: Allows you to execute any arbitrary command on the matched events. You can use replacement tokens as subsequent arguents to the command, the last argument will be the absolute path to the event, preceeded by replacement arguents. eg: /usr/bin/script.sh %MN% will excecute as /usr/bin/script.sh MonitorName /path/to/event. Please note that urls may contain characters like & that need quoting. So you may need to put quotes around them like /usr/bin/scrupt.sh "%MN%". * Execute command on all matches: Allows you to execute any arbitrary command on the matched events. You can use replacement tokens as subsequent arguents to the command, the last argument will be the absolute path to the event, preceded by replacement arguents. eg: /usr/bin/script.sh %MN% will execute as /usr/bin/script.sh MonitorName /path/to/event. Please note that urls may contain characters like & that need quoting. So you may need to put quotes around them like /usr/bin/scrupt.sh "%MN%".
* Delete all matches: Deletes all the matched events. * Delete all matches: Deletes all the matched events.
* Email details of all matches: Sends an email to the configured address with details about the event. * Email details of all matches: Sends an email to the configured address with details about the event.
* Copy all matches: copies the event files to another location, specified in the Copy To dropdown. The other location must be setup in the Storage Tab under options. * Copy all matches: copies the event files to another location, specified in the Copy To dropdown. The other location must be setup in the Storage Tab under options.

View File

@ -53,7 +53,7 @@ This screen is called the "console" screen in ZoneMinder and shows a summary of
* **B**: This brings up a color coded log window that shows various system and component level logs. This window is useful if you are trying to diagnose issues. Refer to :doc:`logging`. * **B**: This brings up a color coded log window that shows various system and component level logs. This window is useful if you are trying to diagnose issues. Refer to :doc:`logging`.
* **C**: ZoneMinder allows you to group monitors for logical separation. This option lets you create new groups, associate monitors to them and edit/delete existing groups. * **C**: ZoneMinder allows you to group monitors for logical separation. This option lets you create new groups, associate monitors to them and edit/delete existing groups.
* **D**: Filters are a powerful mechanism to perform actions when certain conditions are met. ZoneMinder comes with some preset filters that keep a tab of disk space and others. Many users create their own filters for more advanced actions like sending emails when certain events occur and more. Refer to :doc:`filterevents`. * **D**: Filters are a powerful mechanism to perform actions when certain conditions are met. ZoneMinder comes with some preset filters that keep a tab of disk space and others. Many users create their own filters for more advanced actions like sending emails when certain events occur and more. Refer to :doc:`filterevents`.
* **E**: The Cycle option allows you to rotate between live views of each cofigured monitor. * **E**: The Cycle option allows you to rotate between live views of each configured monitor.
* **F**: The Montage option shows a collage of your monitors. You can customize them including moving them around. * **F**: The Montage option shows a collage of your monitors. You can customize them including moving them around.
* **G**: Montage Review allows you to simultaneously view past events for different monitors. Note that this is a very resource intensive page and its performance will vary based on your system capabilities. * **G**: Montage Review allows you to simultaneously view past events for different monitors. Note that this is a very resource intensive page and its performance will vary based on your system capabilities.
* **H**: Audit Events Report is more of a power user feature. This option looks for recording gaps in events and recording issues in mp4 files. * **H**: Audit Events Report is more of a power user feature. This option looks for recording gaps in events and recording issues in mp4 files.

View File

@ -101,6 +101,6 @@ FROM_EMAIL - The emails or messages that will be sent to you informing you of ev
URL - The emails or messages that will be sent to you informing you of events can include a link to the events themselves for easy viewing. If you intend to use this feature then set this option to the url of your installation as it would appear from where you read your email, e.g. ``http://host.your.domain/zm/index.php``. URL - The emails or messages that will be sent to you informing you of events can include a link to the events themselves for easy viewing. If you intend to use this feature then set this option to the url of your installation as it would appear from where you read your email, e.g. ``http://host.your.domain/zm/index.php``.
SSMTP_MAIL - SSMTP is a lightweight and efficient method to send email. The SSMTP application is not installed by default. NEW_MAIL_MODULES must also be enabled. Please visit the ZoneMinder `SSMTP Wiki page <http://www.zoneminder.com/wiki/index.php/How_to_get_ssmtp_working_with_Zoneminder>`__ for setup and configuration help. SSMTP_MAIL - SSMTP is a lightweight and efficient method to send email. The SSMTP application is not installed by default. NEW_MAIL_MODULES must also be enabled. Please visit the ZoneMinder `SSMTP Wiki page <https://wiki.zoneminder.com/How_to_get_ssmtp_working_with_Zoneminder>`__ for setup and configuration help.
SSMTP_PATH - The path to the SSMTP application. If path is not defined. Zoneminder will try to determine the path via shell command. Example path: /usr/sbin/ssmtp. SSMTP_PATH - The path to the SSMTP application. If path is not defined. Zoneminder will try to determine the path via shell command. Example path: /usr/sbin/ssmtp.

View File

@ -30,7 +30,7 @@ This screen allows you to configure various permissions on a per user basis. The
.. note:: if you are using zmNinja, users are required to have 'View' access to system because multi-server information is only available as part of this permission .. note:: if you are using zmNinja, users are required to have 'View' access to system because multi-server information is only available as part of this permission
- Bandwidth - Bandwidth
- Specifies the maximum bandwith that this user can configure (Low, Medium or High) - Specifies the maximum bandwidth that this user can configure (Low, Medium or High)
- API enabled - API enabled
- Specifies if the ZoneMinder API is enabled for this user (needs to be on, if you are using a mobile app such as zmNinja) - Specifies if the ZoneMinder API is enabled for this user (needs to be on, if you are using a mobile app such as zmNinja)
@ -42,4 +42,4 @@ Here is an example of a restricted user, for example:
.. image:: images/Options_Users_Example.png .. image:: images/Options_Users_Example.png
This user "home" is enabled, can view live streams and events, but only from "DoorBell" and "DeckCamera". This user also cannot control PTZ. This user "home" is enabled, can view live streams and events, but only from "DoorBell" and "DeckCamera". This user also cannot control PTZ.

2
misc/fail2ban.rules Normal file
View File

@ -0,0 +1,2 @@
failregex = ^\s*web_php\[\d+\]\.ERR \[<HOST>\].*includes/auth.php
datepattern = ^%%m/%%d/%%y %%H:%%M:%%S(?:\.%%f)

View File

@ -147,7 +147,7 @@ This attribute is of type L<SOAP::WSDL::XSD::Typelib::Builtin::integer|SOAP::WSD
=item * Cells =item * Cells
A 1 denotes a cell where motion is detected and a 0 an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0). A "1" denotes a cell where motion is detected and a "0" an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0).

View File

@ -2709,7 +2709,7 @@ Returns a L<ONVIF::Device::Elements::GetNetworkInterfacesResponse|ONVIF::Device:
=head3 SetNetworkInterfaces =head3 SetNetworkInterfaces
For interoperability with a client unaware of the IEEE 802.11 extension a device shall retain its IEEE 802.11 configuration if the IEEE 802.11 configuration element isnt present in the request. For interoperability with a client unaware of the IEEE 802.11 extension a device shall retain its IEEE 802.11 configuration if the IEEE 802.11 configuration element isn't present in the request.
Returns a L<ONVIF::Device::Elements::SetNetworkInterfacesResponse|ONVIF::Device::Elements::SetNetworkInterfacesResponse> object. Returns a L<ONVIF::Device::Elements::SetNetworkInterfacesResponse|ONVIF::Device::Elements::SetNetworkInterfacesResponse> object.
@ -3093,7 +3093,7 @@ Returns a L<ONVIF::Device::Elements::SetRelayOutputStateResponse|ONVIF::Device::
=head3 SendAuxiliaryCommand =head3 SendAuxiliaryCommand
tt:IRLamp|Auto Request to configure an IR illuminator attached to the unit so that it automatically turns ON and OFF. A device that indicates auxiliary service capability shall support this command. tt:IRLamp|Auto - Request to configure an IR illuminator attached to the unit so that it automatically turns ON and OFF. A device that indicates auxiliary service capability shall support this command.
Returns a L<ONVIF::Device::Elements::SendAuxiliaryCommandResponse|ONVIF::Device::Elements::SendAuxiliaryCommandResponse> object. Returns a L<ONVIF::Device::Elements::SendAuxiliaryCommandResponse|ONVIF::Device::Elements::SendAuxiliaryCommandResponse> object.
@ -3288,7 +3288,7 @@ Returns a L<ONVIF::Device::Elements::GetSystemUrisResponse|ONVIF::Device::Elemen
=head3 StartFirmwareUpgrade =head3 StartFirmwareUpgrade
The value of the Content-Type header in the HTTP POST request shall be application/octetstream. The value of the Content-Type header in the HTTP POST request shall be "application/octetstream".
Returns a L<ONVIF::Device::Elements::StartFirmwareUpgradeResponse|ONVIF::Device::Elements::StartFirmwareUpgradeResponse> object. Returns a L<ONVIF::Device::Elements::StartFirmwareUpgradeResponse|ONVIF::Device::Elements::StartFirmwareUpgradeResponse> object.
@ -3298,7 +3298,7 @@ Returns a L<ONVIF::Device::Elements::StartFirmwareUpgradeResponse|ONVIF::Device:
=head3 StartSystemRestore =head3 StartSystemRestore
The value of the Content-Type header in the HTTP POST request shall be application/octetstream. The value of the Content-Type header in the HTTP POST request shall be "application/octetstream".
Returns a L<ONVIF::Device::Elements::StartSystemRestoreResponse|ONVIF::Device::Elements::StartSystemRestoreResponse> object. Returns a L<ONVIF::Device::Elements::StartSystemRestoreResponse|ONVIF::Device::Elements::StartSystemRestoreResponse> object.

View File

@ -147,7 +147,7 @@ This attribute is of type L<SOAP::WSDL::XSD::Typelib::Builtin::integer|SOAP::WSD
=item * Cells =item * Cells
A 1 denotes a cell where motion is detected and a 0 an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0). A "1" denotes a cell where motion is detected and a "0" an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0).

View File

@ -2147,7 +2147,7 @@ Returns a L<ONVIF::Media::Elements::GetAudioOutputsResponse|ONVIF::Media::Elemen
=head3 CreateProfile =head3 CreateProfile
This operation creates a new empty media profile. The media profile shall be created in the device and shall be persistent (remain after reboot). A created profile shall be deletable and a device shall set the fixed attribute to false in the returned Profile. This operation creates a new empty media profile. The media profile shall be created in the device and shall be persistent (remain after reboot). A created profile shall be deletable and a device shall set the "fixed" attribute to false in the returned Profile.
Returns a L<ONVIF::Media::Elements::CreateProfileResponse|ONVIF::Media::Elements::CreateProfileResponse> object. Returns a L<ONVIF::Media::Elements::CreateProfileResponse|ONVIF::Media::Elements::CreateProfileResponse> object.

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -147,7 +147,7 @@ This attribute is of type L<SOAP::WSDL::XSD::Typelib::Builtin::integer|SOAP::WSD
=item * Cells =item * Cells
A 1 denotes a cell where motion is detected and a 0 an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0). A "1" denotes a cell where motion is detected and a "0" an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0).

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -987,7 +987,7 @@ Returns a L<ONVIF::PTZ::Elements::GotoHomePositionResponse|ONVIF::PTZ::Elements:
=head3 SetHomePosition =head3 SetHomePosition
Operation to save current position as the home position. The SetHomePosition command returns with a failure if the home position is fixed and cannot be overwritten. If the SetHomePosition is successful, it is possible to recall the Home Position with the GotoHomePosition command. Operation to save current position as the home position. The SetHomePosition command returns with a failure if the "home" position is fixed and cannot be overwritten. If the SetHomePosition is successful, it is possible to recall the Home Position with the GotoHomePosition command.
Returns a L<ONVIF::PTZ::Elements::SetHomePositionResponse|ONVIF::PTZ::Elements::SetHomePositionResponse> object. Returns a L<ONVIF::PTZ::Elements::SetHomePositionResponse|ONVIF::PTZ::Elements::SetHomePositionResponse> object.

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -147,7 +147,7 @@ This attribute is of type L<SOAP::WSDL::XSD::Typelib::Builtin::integer|SOAP::WSD
=item * Cells =item * Cells
A 1 denotes a cell where motion is detected and a 0 an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0). A "1" denotes a cell where motion is detected and a "0" an empty cell. The first cell is in the upper left corner. Then the cell order goes first from left to right and then from up to down. If the number of cells is not a multiple of 8 the last byte is filled with zeros. The information is run length encoded according to Packbit coding in ISO 12369 (TIFF, Revision 6.0).

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -100,7 +100,7 @@ of the corresponding class can be passed instead of the marked hash ref.
You may pass any combination of objects, hash and list refs to these You may pass any combination of objects, hash and list refs to these
methods, as long as you meet the structure. methods, as long as you meet the structure.
List items (i.e. multiple occurences) are not displayed in the synopsis. List items (i.e. multiple occurrences) are not displayed in the synopsis.
You may generally pass a list ref of hash refs (or objects) instead of a hash You may generally pass a list ref of hash refs (or objects) instead of a hash
ref - this may result in invalid XML if used improperly, though. Note that ref - this may result in invalid XML if used improperly, though. Note that
SOAP::WSDL always expects list references at maximum depth position. SOAP::WSDL always expects list references at maximum depth position.

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -44,7 +44,7 @@ not checked yet.
The current implementation of union resorts to inheriting from the base type, The current implementation of union resorts to inheriting from the base type,
which means (quoted from the XML Schema specs): "If the <list> or <union> which means (quoted from the XML Schema specs): "If the <list> or <union>
alternative is chosen, then the simple ur-type definition·." alternative is chosen, then the simple ur-type definition."

View File

@ -3766,7 +3766,7 @@ our @options = (
SSMTP is a lightweight and efficient method to send email. SSMTP is a lightweight and efficient method to send email.
The SSMTP application is not installed by default. The SSMTP application is not installed by default.
NEW_MAIL_MODULES must also be enabled. NEW_MAIL_MODULES must also be enabled.
Please visit the ZoneMinder [SSMTP Wiki page](http://www.zoneminder.com/wiki/index.php/How_to_get_ssmtp_working_with_Zoneminder) Please visit the ZoneMinder [SSMTP Wiki page](https://wiki.zoneminder.com/How_to_get_ssmtp_working_with_Zoneminder)
for setup and configuration help. for setup and configuration help.
`, `,
type => $types{boolean}, type => $types{boolean},

View File

@ -220,14 +220,14 @@ sub moveConUpRight {
my $self = shift; my $self = shift;
Debug('Move Diagonally Up Right'); Debug('Move Diagonally Up Right');
$$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ}; $$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ};
$$self{LastCmd} = 'code=RightUp&channel=0&arg1=0&arg2=1&arg3=0'; $$self{LastCmd} = 'code=RightUp&channel=0&arg1=1&arg2=1&arg3=0';
$self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd}); $self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd});
} }
sub moveConDownRight { sub moveConDownRight {
my $self = shift; my $self = shift;
Debug('Move Diagonally Down Right'); Debug('Move Diagonally Down Right');
$$self{LastCmd} = 'code=RightDown&channel=0&arg1=0&arg2=1&arg3=0'; $$self{LastCmd} = 'code=RightDown&channel=0&arg1=1&arg2=1&arg3=0';
$$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ}; $$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ};
$self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd}); $self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd});
} }
@ -236,7 +236,7 @@ sub moveConUpLeft {
my $self = shift; my $self = shift;
Debug('Move Diagonally Up Left'); Debug('Move Diagonally Up Left');
$$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ}; $$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ};
$$self{LastCmd} = 'code=LeftUp&channel=0&arg1=0&arg2=1&arg3=0'; $$self{LastCmd} = 'code=LeftUp&channel=0&arg1=1&arg2=1&arg3=0';
$self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd}); $self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd});
} }
@ -244,7 +244,7 @@ sub moveConDownLeft {
my $self = shift; my $self = shift;
Debug('Move Diagonally Down Left'); Debug('Move Diagonally Down Left');
$$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ}; $$self{Monitor}->suspendMotionDetection() if !$self->{Monitor}->{ModectDuringPTZ};
$$self{LastCmd} = 'code=LeftDown&channel=0&arg1=0&arg2=1&arg3=0'; $$self{LastCmd} = 'code=LeftDown&channel=0&arg1=1&arg2=1&arg3=0';
$self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd}); $self->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd});
} }

View File

@ -283,7 +283,7 @@ None by default.
=head1 SEE ALSO =head1 SEE ALSO
See if there are better instructions for the DCS-5020L at See if there are better instructions for the DCS-5020L at
http://www.zoneminder.com/wiki/index.php/Dlink https://wiki.zoneminder.com/Dlink
=head1 AUTHOR =head1 AUTHOR

View File

@ -283,7 +283,7 @@ sub presetSet
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
my $preset = $self->getParam( $params, 'preset' ); my $preset = $self->getParam( $params, 'preset' );
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&PresetNumber=1&Preset=0"; my $cmd = 'form/presetSet?flag=3&existFlag=1&language=cn&presetNum='.$preset;
$self->sendCmd( $cmd ); $self->sendCmd( $cmd );
} }
@ -294,7 +294,7 @@ sub presetGoto
my $self = shift; my $self = shift;
my $params = shift; my $params = shift;
my $preset = $self->getParam( $params, 'preset' ); my $preset = $self->getParam( $params, 'preset' );
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&PresetNumber=1&Preset=1"; my $cmd = 'form/presetSet?flag=4&existFlag=1&language=cn&presetNum='.$preset;
$self->sendCmd( $cmd ); $self->sendCmd( $cmd );
} }

View File

@ -756,9 +756,9 @@ sub CopyTo {
} # end sub CopyTo } # end sub CopyTo
sub MoveTo { sub MoveTo {
my ( $self, $NewStorage ) = @_; my ($self, $NewStorage) = @_;
if ( !$self->canEdit() ) { if (!$self->canEdit()) {
Warning('No permission to move event.'); Warning('No permission to move event.');
return 'No permission to move event.'; return 'No permission to move event.';
} }
@ -772,11 +772,9 @@ sub MoveTo {
$$self{StorageId} = $$NewStorage{Id}; $$self{StorageId} = $$NewStorage{Id};
$self->Storage($NewStorage); $self->Storage($NewStorage);
$error .= $self->save(); $error .= $self->save();
if ( $error ) { if ($error) {
$ZoneMinder::Database::dbh->commit();
return $error; return $error;
} }
$ZoneMinder::Database::dbh->commit();
$self->delete_files($OldStorage); $self->delete_files($OldStorage);
return $error; return $error;
} # end sub MoveTo } # end sub MoveTo

View File

@ -127,9 +127,11 @@ sub Execute {
foreach my $term ( @{$$self{PostSQLConditions}} ) { foreach my $term ( @{$$self{PostSQLConditions}} ) {
if ( $$term{attr} eq 'ExistsInFileSystem' ) { if ( $$term{attr} eq 'ExistsInFileSystem' ) {
foreach my $row ( @results ) { foreach my $row ( @results ) {
my $event = new ZoneMinder::Event($row); my $event = new ZoneMinder::Event($$row{Id}, $row);
if ( -e $event->Path() ) { if ( -e $event->Path() ) {
push @filtered_events, $row; push @filtered_events, $row if $$term{val} eq 'true';
} else {
push @filtered_events, $row if $$term{val} eq 'false';
} }
} }
} }
@ -164,138 +166,142 @@ sub Sql {
if ( exists($term->{obr}) ) { if ( exists($term->{obr}) ) {
$self->{Sql} .= str_repeat('(', $term->{obr}).' '; $self->{Sql} .= str_repeat('(', $term->{obr}).' ';
} }
if (!$term->{attr}) {
Error("Invalid term in filter $$self{Id}. Empty attr");
next;
}
my $value = $term->{val}; my $value = $term->{val};
my @value_list; my @value_list;
if ( $term->{attr} ) {
if ( $term->{attr} eq 'AlarmedZoneId' ) {
$term->{op} = 'EXISTS';
} elsif ( $term->{attr} =~ /^Monitor/ ) {
$sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName
FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId';
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
$self->{Sql} .= 'M.'.$temp_attr_name;
} elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) {
$sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName
FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId';
$self->{Sql} .= 'M.ServerId';
} elsif ( $term->{attr} eq 'StorageServerId' ) {
$self->{Sql} .= '(SELECT Storage.ServerId FROM Storage WHERE Storage.Id=E.StorageId)';
} elsif ( $term->{attr} eq 'FilterServerId' ) {
$self->{Sql} .= $Config{ZM_SERVER_ID};
# StartTime options
} elsif ( $term->{attr} eq 'DateTime' ) {
$self->{Sql} .= 'E.StartDateTime';
} elsif ( $term->{attr} eq 'Date' ) {
$self->{Sql} .= 'to_days( E.StartDateTime )';
} elsif ( $term->{attr} eq 'StartDate' ) {
$self->{Sql} .= 'to_days( E.StartDateTime )';
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' ) {
$self->{Sql} .= 'extract( hour_second from E.StartDateTime )';
} elsif ( $term->{attr} eq 'Weekday' or $term->{attr} eq 'StartWeekday' ) {
$self->{Sql} .= 'weekday( E.StartDateTime )';
# EndTIme options if ( $term->{attr} eq 'AlarmedZoneId' ) {
} elsif ( $term->{attr} eq 'EndDateTime' ) { $term->{op} = 'EXISTS';
$self->{Sql} .= 'E.EndDateTime'; } elsif ( $term->{attr} =~ /^Monitor/ ) {
} elsif ( $term->{attr} eq 'EndDate' ) { $sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName
$self->{Sql} .= 'to_days( E.EndDateTime )'; FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId';
} elsif ( $term->{attr} eq 'EndTime' ) { my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
$self->{Sql} .= 'extract( hour_second from E.EndDateTime )'; $self->{Sql} .= 'M.'.$temp_attr_name;
} elsif ( $term->{attr} eq 'EndWeekday' ) { } elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) {
$self->{Sql} .= 'weekday( E.EndDateTime )'; $sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName
} elsif ( $term->{attr} eq 'ExistsInFileSystem' ) { FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId';
push @{$self->{PostSQLConditions}}, $term; $self->{Sql} .= 'M.ServerId';
$self->{Sql} .= 'TRUE /* ExistsInFileSystem */'; } elsif ( $term->{attr} eq 'StorageServerId' ) {
} elsif ( $term->{attr} eq 'DiskPercent' ) { $self->{Sql} .= '(SELECT Storage.ServerId FROM Storage WHERE Storage.Id=E.StorageId)';
$self->{Sql} .= 'zmDiskPercent'; } elsif ( $term->{attr} eq 'FilterServerId' ) {
$self->{HasDiskPercent} = !undef; $self->{Sql} .= $Config{ZM_SERVER_ID};
} elsif ( $term->{attr} eq 'DiskBlocks' ) { # StartTime options
$self->{Sql} .= 'zmDiskBlocks'; } elsif ( $term->{attr} eq 'DateTime' ) {
$self->{HasDiskBlocks} = !undef; $self->{Sql} .= 'E.StartDateTime';
} elsif ( $term->{attr} eq 'SystemLoad' ) { } elsif ( $term->{attr} eq 'Date' ) {
$self->{Sql} .= 'zmSystemLoad'; $self->{Sql} .= 'to_days( E.StartDateTime )';
$self->{HasSystemLoad} = !undef; } elsif ( $term->{attr} eq 'StartDate' ) {
} else { $self->{Sql} .= 'to_days( E.StartDateTime )';
$self->{Sql} .= 'E.'.$term->{attr}; } elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' ) {
} $self->{Sql} .= 'extract( hour_second from E.StartDateTime )';
} elsif ( $term->{attr} eq 'Weekday' or $term->{attr} eq 'StartWeekday' ) {
$self->{Sql} .= 'weekday( E.StartDateTime )';
if ( $term->{attr} eq 'ExistsInFileSystem' ) { # EndTIme options
# PostCondition, so no further SQL } elsif ( $term->{attr} eq 'EndDateTime' ) {
} else { $self->{Sql} .= 'E.EndDateTime';
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/; } elsif ( $term->{attr} eq 'EndDate' ) {
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) { $self->{Sql} .= 'to_days( E.EndDateTime )';
} elsif ( $term->{attr} eq 'EndTime' ) {
$self->{Sql} .= 'extract( hour_second from E.EndDateTime )';
} elsif ( $term->{attr} eq 'EndWeekday' ) {
$self->{Sql} .= 'weekday( E.EndDateTime )';
} elsif ( $term->{attr} eq 'ExistsInFileSystem' ) {
push @{$self->{PostSQLConditions}}, $term;
$self->{Sql} .= 'TRUE /* ExistsInFileSystem */';
} elsif ( $term->{attr} eq 'DiskPercent' ) {
$self->{Sql} .= 'zmDiskPercent';
$self->{HasDiskPercent} = !undef;
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
$self->{Sql} .= 'zmDiskBlocks';
$self->{HasDiskBlocks} = !undef;
} elsif ( $term->{attr} eq 'SystemLoad' ) {
$self->{Sql} .= 'zmSystemLoad';
$self->{HasSystemLoad} = !undef;
} else {
$self->{Sql} .= 'E.'.$term->{attr};
}
if ( $term->{attr} eq 'AlarmedZoneId' ) { if ( $term->{attr} eq 'ExistsInFileSystem' ) {
$value = '(SELECT * FROM Stats WHERE EventId=E.Id AND Score > 0 AND ZoneId='.$value.')'; # PostCondition, so no further SQL
} elsif ( $term->{attr} =~ /^MonitorName/ ) { } else {
$value = "'$temp_value'"; ( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
} elsif ( $term->{attr} =~ /ServerId/) { foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
if ( $temp_value eq 'ZM_SERVER_ID' ) { if ( $term->{attr} eq 'AlarmedZoneId' ) {
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'"; $value = '(SELECT * FROM Stats WHERE EventId=E.Id AND Score > 0 AND ZoneId='.$value.')';
# This gets used later, I forget for what } elsif ( $term->{attr} =~ /^MonitorName/ ) {
$$self{Server} = new ZoneMinder::Server($ZoneMinder::Config::Config{ZM_SERVER_ID}); $value = "'$temp_value'";
} elsif ( $temp_value eq 'NULL' ) { } elsif ( $term->{attr} =~ /ServerId/) {
$value = $temp_value; Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
} else { if ( $temp_value eq 'ZM_SERVER_ID' ) {
$value = "'$temp_value'"; $value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
# This gets used later, I forget for what # This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server($temp_value); $$self{Server} = new ZoneMinder::Server($ZoneMinder::Config::Config{ZM_SERVER_ID});
} } elsif ( $temp_value eq 'NULL' ) {
} elsif ( $term->{attr} eq 'StorageId' ) {
$value = "'$temp_value'";
$$self{Storage} = new ZoneMinder::Storage($temp_value);
} elsif ( $term->{attr} eq 'Name'
|| $term->{attr} eq 'Cause'
|| $term->{attr} eq 'Notes'
) {
if ( $term->{op} eq 'LIKE'
|| $term->{op} eq 'NOT LIKE'
) {
$temp_value = '%'.$temp_value.'%' if $temp_value !~ /%/;
}
$value = "'$temp_value'";
} elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL($temp_value);
if ( !$value ) {
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
return;
}
$value = "'$value'";
}
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} elsif ( $temp_value eq 'CURDATE()' or $temp_value eq 'NOW()' ) {
$value = 'to_days('.$temp_value.')';
} else {
$value = DateTimeToSQL($temp_value);
if ( !$value ) {
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
return;
}
$value = "to_days( '$value' )";
}
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL($temp_value);
if ( !$value ) {
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
return;
}
$value = "extract( hour_second from '$value' )";
}
} else {
$value = $temp_value; $value = $temp_value;
} else {
$value = "'$temp_value'";
# This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server($temp_value);
} }
push @value_list, $value; } elsif ( $term->{attr} eq 'StorageId' ) {
} # end foreach temp_value $value = "'$temp_value'";
} # end if has an attr $$self{Storage} = new ZoneMinder::Storage($temp_value);
} elsif ( $term->{attr} eq 'Name'
|| $term->{attr} eq 'Cause'
|| $term->{attr} eq 'Notes'
) {
if ( $term->{op} eq 'LIKE'
|| $term->{op} eq 'NOT LIKE'
) {
$temp_value = '%'.$temp_value.'%' if $temp_value !~ /%/;
}
$value = "'$temp_value'";
} elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL($temp_value);
if ( !$value ) {
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
return;
}
$value = "'$value'";
}
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} elsif ( $temp_value eq 'CURDATE()' or $temp_value eq 'NOW()' ) {
$value = 'to_days('.$temp_value.')';
} else {
$value = DateTimeToSQL($temp_value);
if ( !$value ) {
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
return;
}
$value = "to_days( '$value' )";
}
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL($temp_value);
if ( !$value ) {
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
return;
}
$value = "extract( hour_second from '$value' )";
}
} else {
$value = $temp_value;
}
push @value_list, $value;
} # end foreach temp_value
if ( $term->{op} ) { if ( $term->{op} ) {
if ( $term->{op} eq '=~' ) { if ( $term->{op} eq '=~' ) {

View File

@ -136,8 +136,8 @@ $serial = $primary_key = 'Id';
%defaults = ( %defaults = (
ServerId => 0, ServerId => 0,
StorageId => 0, StorageId => 0,
Type => 'Ffmpeg', Type => q`'Ffmpeg'`,
Function => 'Mocord', Function => q`'Mocord'`,
Enabled => 1, Enabled => 1,
LinkedMonitors => undef, LinkedMonitors => undef,
Device => '', Device => '',
@ -166,15 +166,15 @@ $serial = $primary_key = 'Id';
VideoWriter => 0, VideoWriter => 0,
OutputCodec => undef, OutputCodec => undef,
OutputContainer => undef, OutputContainer => undef,
EncoderParameters => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", EncoderParameters => '',
RecordAudio=>0, RecordAudio=>0,
RTSPDescribe=>0, RTSPDescribe=>0,
Brightness => -1, Brightness => -1,
Contrast => -1, Contrast => -1,
Hue => -1, Hue => -1,
Colour => -1, Colour => -1,
EventPrefix => 'Event-', EventPrefix => q`'Event-'`,
LabelFormat => '%N - %d/%m/%y %H:%M:%S', LabelFormat => '',
LabelX => 0, LabelX => 0,
LabelY => 0, LabelY => 0,
LabelSize => 1, LabelSize => 1,
@ -208,13 +208,13 @@ $serial = $primary_key = 'Id';
DefaultRate => 100, DefaultRate => 100,
DefaultScale => 100, DefaultScale => 100,
SignalCheckPoints => 0, SignalCheckPoints => 0,
SignalCheckColour => '#0000BE', SignalCheckColour => q`'#0000BE'`,
WebColour => '#ff0000', WebColour => q`'#ff0000'`,
Exif => 0, Exif => 0,
Sequence => undef, Sequence => undef,
ZoneCount => 0, ZoneCount => 0,
Refresh => undef, Refresh => undef,
DefaultCodec => 'auto', DefaultCodec => q`'auto'`,
Latitude => undef, Latitude => undef,
Longitude => undef, Longitude => undef,
); );
@ -279,21 +279,37 @@ sub disconnect {
sub suspendMotionDetection { sub suspendMotionDetection {
my $self = shift; my $self = shift;
return 0 if ! ZoneMinder::Memory::zmMemVerify($self); return 0 if ! ZoneMinder::Memory::zmMemVerify($self);
while (ZoneMinder::Memory::zmMemRead($self, 'shared_data:active', 1)) { return if $$self{Function} eq 'Nodect' or $$self{Function} eq 'Monitor' or $$self{Function} eq 'None';
my $count = 50;
while ($count and ZoneMinder::Memory::zmMemRead($self, 'shared_data:active', 1)) {
ZoneMinder::Logger::Debug(1, 'Suspending motion detection'); ZoneMinder::Logger::Debug(1, 'Suspending motion detection');
ZoneMinder::Memory::zmMonitorSuspend($self); ZoneMinder::Memory::zmMonitorSuspend($self);
usleep(100000); usleep(100000);
$count -= 1;
}
if (!$count) {
ZoneMinder::Logger::Error('Unable to suspend motion detection after 5 seconds.');
ZoneMinder::Memory::zmMemInvalidate($self); # Close our file handle to the zmc process we are about to end
} else {
ZoneMinder::Logger::Debug(1, 'shared_data:active='.ZoneMinder::Memory::zmMemRead($self, 'shared_data:active', 1));
} }
ZoneMinder::Logger::Debug(1,ZoneMinder::Memory::zmMemRead($self, 'shared_data:active', 1));
} }
sub resumeMotionDetection { sub resumeMotionDetection {
my $self = shift; my $self = shift;
return 0 if ! ZoneMinder::Memory::zmMemVerify($self); return 0 if ! ZoneMinder::Memory::zmMemVerify($self);
#while (zmMemRead($self, 'shared_data:active', 1)) { return if $$self{Function} eq 'Nodect' or $$self{Function} eq 'Monitor' or $$self{Function} eq 'None';
my $count = 50;
while ($count and !ZoneMinder::Memory::zmMemRead($self, 'shared_data:active', 1)) {
ZoneMinder::Logger::Debug(1, 'Resuming motion detection'); ZoneMinder::Logger::Debug(1, 'Resuming motion detection');
ZoneMinder::Memory::zmMonitorResume($self); ZoneMinder::Memory::zmMonitorResume($self);
#} usleep(100000);
$count -= 1;
}
if (!$count) {
ZoneMinder::Logger::Error('Unable to resume motion detection after 5 seconds.');
ZoneMinder::Memory::zmMemInvalidate($self); # Close our file handle to the zmc process we are about to end
}
return 1; return 1;
} }

View File

@ -40,6 +40,10 @@ $serial = $primary_key = 'Id';
MonitorId MonitorId
Type Type
Units Units
NumCoords
Coords
Area
AlarmRGB
CheckMethod CheckMethod
MinPixelThreshold MinPixelThreshold
MaxPixelThreshold MaxPixelThreshold
@ -59,9 +63,13 @@ $serial = $primary_key = 'Id';
%defaults = ( %defaults = (
Name => '', Name => '',
Type => 'Active', Type => q`'Active'`,
Units => 'Pixels', Units => q`'Pixels'`,
CheckMethod => 'Blobs', NumCoords => 0,
Coords => '',
Area => 0,
AlarmRGB => 0,
CheckMethod => q`'Blobs'`,
MinPixelThreshold => undef, MinPixelThreshold => undef,
MaxPixelThreshold => undef, MaxPixelThreshold => undef,
MinAlarmPixels => undef, MinAlarmPixels => undef,

View File

@ -61,12 +61,12 @@ GetOptions(
'autostop' =>\$options{autostop}, 'autostop' =>\$options{autostop},
) or pod2usage(-exitstatus => -1); ) or pod2usage(-exitstatus => -1);
if ( !$id ) { if (!$id) {
print(STDERR "Please give a valid monitor id\n"); print(STDERR "Please give a valid monitor id\n");
pod2usage(-exitstatus => -1); pod2usage(-exitstatus => -1);
} }
( $id ) = $id =~ /^(\w+)$/; ($id) = $id =~ /^(\w+)$/;
logInit($id?(id=>'zmcontrol_'.$id):()); logInit($id?(id=>'zmcontrol_'.$id):());
my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock'; my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock';
@ -76,7 +76,7 @@ socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
my $saddr = sockaddr_un($sock_file); my $saddr = sockaddr_un($sock_file);
if ( $options{command} ) { if ($options{command}) {
# Have a command, so we are the client, connect to the server and send it. # Have a command, so we are the client, connect to the server and send it.
my $tries = 10; my $tries = 10;
@ -101,18 +101,16 @@ if ( $options{command} ) {
Error("Unable to connect to zmcontrol server at $sock_file"); Error("Unable to connect to zmcontrol server at $sock_file");
} }
} else { } else {
# The server isn't there # The server isn't there
my $monitor = zmDbGetMonitorAndControl($id); my $monitor = zmDbGetMonitorAndControl($id);
if ( !$monitor ) { Fatal("Unable to load control data for monitor $id") if !$monitor;
Fatal("Unable to load control data for monitor $id");
}
my $protocol = $monitor->{Protocol}; my $protocol = $monitor->{Protocol};
if ( !$protocol ) { if (!$protocol) {
Fatal('No protocol is set in monitor. Please edit the monitor, edit control type, select the control capability and fill in the Protocol field'); Fatal('No protocol is set in monitor. Please edit the monitor, edit control type, select the control capability and fill in the Protocol field');
} }
if ( -x $protocol ) { if (-x $protocol) {
# Protocol is actually a script! # Protocol is actually a script!
# Holdover from previous versions # Holdover from previous versions
my $command .= $protocol.' '.$arg_string; my $command .= $protocol.' '.$arg_string;
@ -120,11 +118,11 @@ if ( $options{command} ) {
my $output = qx($command); my $output = qx($command);
my $status = $? >> 8; my $status = $? >> 8;
if ( $status || logDebugging() ) { if ($status || logDebugging()) {
chomp($output); chomp($output);
Debug("Output: $output"); Debug("Output: $output");
} }
if ( $status ) { if ($status) {
Error("Command '$command' exited with status: $status"); Error("Command '$command' exited with status: $status");
exit($status); exit($status);
} }
@ -134,7 +132,7 @@ if ( $options{command} ) {
Info("Starting control server $id/$protocol"); Info("Starting control server $id/$protocol");
close(CLIENT); close(CLIENT);
if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) { if (!can_load(modules => {'ZoneMinder::Control::'.$protocol => undef})) {
Fatal("Can't load ZoneMinder::Control::$protocol\n$Module::Load::Conditional::ERROR"); Fatal("Can't load ZoneMinder::Control::$protocol\n$Module::Load::Conditional::ERROR");
} }
@ -159,7 +157,7 @@ if ( $options{command} ) {
$control->open(); $control->open();
# If we have a command when starting up, then do it. # If we have a command when starting up, then do it.
if ( $options{command} ) { if ($options{command}) {
my $command = $options{command}; my $command = $options{command};
$control->$command(\%options); $control->$command(\%options);
} }

View File

@ -358,25 +358,27 @@ sub checkFilter {
} }
} # end if AutoDelete } # end if AutoDelete
if ( $filter->{AutoMove} ) { if ($filter->{AutoMove}) {
my $NewStorage = new ZoneMinder::Storage($filter->{AutoMoveTo}); my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoMoveTo});
Info("Moving event $Event->{Id} to datastore $filter->{AutoMoveTo}"); if ($NewStorage) {
$_ = $Event->MoveTo($NewStorage); Info("Moving event $Event->{Id} to datastore $filter->{AutoMoveTo}");
Error($_) if $_; $_ = $Event->MoveTo($NewStorage);
Error($_) if $_;
} else {
Error("No storage area found for move to operation. AutoMoveTo was $$filter{AutoMoveTo}");
}
} }
if ( $filter->{AutoCopy} ) { if ($filter->{AutoCopy}) {
# Copy To is different from MoveTo in that it JUST copies the files # Copy To is different from MoveTo in that it JUST copies the files
# So we still need to update the Event object with the new SecondaryStorageId # So we still need to update the Event object with the new SecondaryStorageId
my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoCopyTo}); my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoCopyTo});
if ( $NewStorage ) { if ( $NewStorage ) {
Info("Copying event $Event->{Id} to datastore $filter->{AutoCopyTo}"); Info("Copying event $Event->{Id} to datastore $filter->{AutoCopyTo}");
$_ = $Event->CopyTo($NewStorage); $_ = $Event->CopyTo($NewStorage);
if ( $_ ) { if ($_) {
$ZoneMinder::Database::dbh->commit();
Error($_); Error($_);
} else { } else {
$Event->save({SecondaryStorageId=>$$NewStorage{Id}}); $Event->save({SecondaryStorageId=>$$NewStorage{Id}});
$ZoneMinder::Database::dbh->commit();
} }
} else { } else {
Error("No storage area found for copy to operation. AutoCopyTo was $$filter{AutoCopyTo}"); Error("No storage area found for copy to operation. AutoCopyTo was $$filter{AutoCopyTo}");
@ -399,7 +401,6 @@ sub checkFilter {
) { ) {
$Event->save(); $Event->save();
} }
$ZoneMinder::Database::dbh->commit() if !$$filter{LockRows};
} # end if UpdateDiskSpace } # end if UpdateDiskSpace
} # end foreach event } # end foreach event
ZoneMinder::Database::end_transaction($dbh, $in_transaction) if $$filter{LockRows}; ZoneMinder::Database::end_transaction($dbh, $in_transaction) if $$filter{LockRows};
@ -843,7 +844,7 @@ sub sendEmail {
return 0; return 0;
} }
Info('Creating notification email'); Debug('Creating notification email');
my $subject = substituteTags($$filter{EmailSubject}, $filter, $Event); my $subject = substituteTags($$filter{EmailSubject}, $filter, $Event);
return 0 if !$subject; return 0 if !$subject;
@ -851,7 +852,7 @@ sub sendEmail {
my $body = substituteTags($$filter{EmailBody}, $filter, $Event, \@attachments); my $body = substituteTags($$filter{EmailBody}, $filter, $Event, \@attachments);
return 0 if !$body; return 0 if !$body;
Info("Sending notification email '$subject'"); Debug("Sending notification email '$subject'");
eval { eval {
if ( $Config{ZM_NEW_MAIL_MODULES} ) { if ( $Config{ZM_NEW_MAIL_MODULES} ) {
@ -864,7 +865,7 @@ sub sendEmail {
); );
### Add the text message part ### Add the text message part
$mail->attach ( $mail->attach (
Type => 'TEXT', Type => (($body=~/<html/)?'text/html':'text/plain'),
Data => $body Data => $body
); );
### Add the attachments ### Add the attachments
@ -886,9 +887,7 @@ sub sendEmail {
if ( $Config{ZM_SSMTP_MAIL} ) { if ( $Config{ZM_SSMTP_MAIL} ) {
my $ssmtp_location = $Config{ZM_SSMTP_PATH}; my $ssmtp_location = $Config{ZM_SSMTP_PATH};
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
if ( logDebugging() ) { Debug("which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message");
Debug("which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message");
}
$ssmtp_location = qx('which ssmtp'); $ssmtp_location = qx('which ssmtp');
} }
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
@ -916,7 +915,7 @@ sub sendEmail {
foreach my $attachment ( @attachments ) { foreach my $attachment ( @attachments ) {
my $size = -s $attachment->{path}; my $size = -s $attachment->{path};
$total_size += $size; $total_size += $size;
Info("Attaching '$attachment->{path}' which is $size bytes"); Debug("Attaching '$attachment->{path}' which is $size bytes");
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
@ -934,7 +933,7 @@ sub sendEmail {
Error("Unable to send email: $@"); Error("Unable to send email: $@");
return 0; return 0;
} else { } else {
Info('Notification email sent'); Info("Notification email sent to $$filter{EmailTo}");
} }
my $sql = 'UPDATE `Events` SET `Emailed` = 1 WHERE `Id` = ?'; my $sql = 'UPDATE `Events` SET `Emailed` = 1 WHERE `Id` = ?';
my $sth = $dbh->prepare_cached($sql) my $sth = $dbh->prepare_cached($sql)

View File

@ -27,7 +27,7 @@ zmupdate.pl - check and upgrade ZoneMinder database
=head1 SYNOPSIS =head1 SYNOPSIS
zmupdate.pl -c,--check | -f,--freshen | -v<version>,--version=<version> [-u<dbuser> -p<dbpass>] zmupdate.pl -c,--check | -f,--freshen | -v<version>,--version=<version> [-u <dbuser> -p <dbpass>]
=head1 DESCRIPTION =head1 DESCRIPTION

View File

@ -98,19 +98,19 @@ while (!$zm_terminate) {
next if $monitor->{Type} eq 'WebSite'; next if $monitor->{Type} eq 'WebSite';
my $now = time(); my $now = time();
my $restart = 0; my $restart = 0;
if ( zmMemVerify($monitor) ) { if (zmMemVerify($monitor)) {
# Check we have got an image recently # Check we have got an image recently
my $capture_time = zmGetLastWriteTime($monitor); my $capture_time = zmGetLastWriteTime($monitor);
if ( !defined($capture_time) ) { if (!defined($capture_time)) {
# Can't read from shared data # Can't read from shared data
Debug('LastWriteTime is not defined.'); Debug('LastWriteTime is not defined.');
zmMemInvalidate($monitor); zmMemInvalidate($monitor);
next; next;
} }
Debug("Monitor $$monitor{Id} LastWriteTime is $capture_time."); Debug("Monitor $$monitor{Id} LastWriteTime is $capture_time.");
if ( !$capture_time ) { if (!$capture_time) {
my $startup_time = zmGetStartupTime($monitor); my $startup_time = zmGetStartupTime($monitor);
if ( ( $now - $startup_time ) > $Config{ZM_WATCH_MAX_DELAY} ) { if (($now - $startup_time) > $Config{ZM_WATCH_MAX_DELAY}) {
Warning( Warning(
"Restarting capture daemon for $$monitor{Name}, no image since startup. ". "Restarting capture daemon for $$monitor{Name}, no image since startup. ".
"Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}" "Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}"
@ -122,7 +122,7 @@ while (!$zm_terminate) {
next; next;
} }
} }
if ( ! $restart ) { if (!$restart) {
my $max_image_delay = ( my $max_image_delay = (
$monitor->{MaxFPS} $monitor->{MaxFPS}
&&($monitor->{MaxFPS}>0) &&($monitor->{MaxFPS}>0)
@ -144,29 +144,28 @@ while (!$zm_terminate) {
$restart = 1; $restart = 1;
} }
if ( $restart ) { if ($restart) {
my $command; my $command;
if ( $monitor->{Type} eq 'Local' ) { if ($monitor->{Type} eq 'Local') {
$command = "zmdc.pl restart zmc -d $monitor->{Device}"; $command = 'zmdc.pl restart zmc -d '.$monitor->{Device};
} else { } else {
$command = "zmdc.pl restart zmc -m $monitor->{Id}"; $command = 'zmdc.pl restart zmc -m '.$monitor->{Id};
} }
runCommand($command); runCommand($command);
} elsif ( $monitor->{Function} ne 'Monitor' ) { } elsif ($monitor->{Function} ne 'Monitor') {
# Now check analysis daemon # Now check analysis daemon
$restart = 0; $restart = 0;
# Check we have got an image recently # Check we have got an image recently
my $image_time = zmGetLastReadTime($monitor); my $image_time = zmGetLastReadTime($monitor);
if ( !defined($image_time) ) { if (!defined($image_time)) {
# Can't read from shared data # Can't read from shared data
$restart = 1; $restart = 1;
Error("Error reading shared data for $$monitor{Id} $$monitor{Name}"); Error("Error reading shared data for $$monitor{Id} $$monitor{Name}");
} elsif ( !$image_time ) { } elsif (!$image_time) {
# We can't get the last capture time so can't be sure it's died. # We can't get the last capture time so can't be sure it's died.
#$restart = 1; #$restart = 1;
Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero."); Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero.");
} else { } else {
my $max_image_delay = ( $monitor->{MaxFPS} my $max_image_delay = ( $monitor->{MaxFPS}
&&($monitor->{MaxFPS}>0) &&($monitor->{MaxFPS}>0)
&&($monitor->{MaxFPS}<1) &&($monitor->{MaxFPS}<1)
@ -175,7 +174,7 @@ while (!$zm_terminate) {
; ;
my $image_delay = $now-$image_time; my $image_delay = $now-$image_time;
Debug("Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay"); Debug("Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay");
if ( $image_delay > $max_image_delay ) { if ($image_delay > $max_image_delay) {
Warning("Analysis daemon for $$monitor{Id} $$monitor{Name} needs restarting," Warning("Analysis daemon for $$monitor{Id} $$monitor{Name} needs restarting,"
." time since last analysis $image_delay seconds ($now-$image_time)" ." time since last analysis $image_delay seconds ($now-$image_time)"
); );
@ -183,13 +182,13 @@ while (!$zm_terminate) {
} }
} }
if ( $restart ) { if ($restart) {
Info("Restarting analysis daemon for $$monitor{Id} $$monitor{Name}\n"); Info("Restarting analysis daemon for $$monitor{Id} $$monitor{Name}");
my $command; my $command;
if ( $monitor->{Type} eq 'Local' ) { if ( $monitor->{Type} eq 'Local' ) {
$command = "zmdc.pl restart zmc -d $monitor->{Device}"; $command = 'zmdc.pl restart zmc -d '.$monitor->{Device};
} else { } else {
$command = "zmdc.pl restart zmc -m $monitor->{Id}"; $command = 'zmdc.pl restart zmc -m '.$monitor->{Id};
} }
runCommand($command); runCommand($command);
} # end if restart } # end if restart
@ -201,7 +200,7 @@ while (!$zm_terminate) {
sleep($Config{ZM_WATCH_CHECK_INTERVAL}); sleep($Config{ZM_WATCH_CHECK_INTERVAL});
} # end while (!$zm_terminate) } # end while (!$zm_terminate)
Info("Watchdog exiting"); Info('Watchdog exiting');
exit(); exit();
1; 1;

View File

@ -321,6 +321,7 @@ bool Image::Assign(const AVFrame *frame, SwsContext *convert_context, AVFrame *t
return false; return false;
} }
zm_dump_video_frame(temp_frame, "dest frame after convert"); zm_dump_video_frame(temp_frame, "dest frame after convert");
update_function_pointers();
return true; return true;
} // end Image::Assign(const AVFrame *frame, SwsContext *convert_context, AVFrame *temp_frame) } // end Image::Assign(const AVFrame *frame, SwsContext *convert_context, AVFrame *temp_frame)
@ -695,6 +696,7 @@ void Image::AssignDirect(
subpixelorder = p_subpixelorder; subpixelorder = p_subpixelorder;
pixels = width * height; pixels = width * height;
size = new_buffer_size; size = new_buffer_size;
update_function_pointers();
} // end void Image::AssignDirect } // end void Image::AssignDirect
void Image::Assign( void Image::Assign(
@ -796,6 +798,7 @@ void Image::Assign(const Image &image) {
linesize = image.linesize; linesize = image.linesize;
} }
update_function_pointers();
if ( image.buffer != buffer ) if ( image.buffer != buffer )
(*fptr_imgbufcpy)(buffer, image.buffer, size); (*fptr_imgbufcpy)(buffer, image.buffer, size);
} }

View File

@ -180,7 +180,7 @@ class Image {
/* Internal buffer should not be modified from functions outside of this class */ /* Internal buffer should not be modified from functions outside of this class */
inline const uint8_t* Buffer() const { return buffer; } inline const uint8_t* Buffer() const { return buffer; }
inline const uint8_t* Buffer(unsigned int x, unsigned int y=0) const { return &buffer[(y*linesize)+x]; } inline const uint8_t* Buffer(unsigned int x, unsigned int y=0) const { return &buffer[(y*linesize) + x*colours]; }
/* Request writeable buffer */ /* Request writeable buffer */
uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder); uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder);
// Is only acceptable on a pre-allocated buffer // Is only acceptable on a pre-allocated buffer

View File

@ -24,6 +24,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h>
#if ZM_HAS_V4L #if ZM_HAS_V4L

View File

@ -89,7 +89,7 @@ std::string load_monitor_sql =
"`SectionLength`, `MinSectionLength`, `FrameSkip`, `MotionFrameSkip`, " "`SectionLength`, `MinSectionLength`, `FrameSkip`, `MotionFrameSkip`, "
"`FPSReportInterval`, `RefBlendPerc`, `AlarmRefBlendPerc`, `TrackMotion`, `Exif`," "`FPSReportInterval`, `RefBlendPerc`, `AlarmRefBlendPerc`, `TrackMotion`, `Exif`,"
"`RTSPServer`, `RTSPStreamName`," "`RTSPServer`, `RTSPStreamName`,"
"`SignalCheckPoints`, `SignalCheckColour`, `Importance`-2 FROM `Monitors`"; "`SignalCheckPoints`, `SignalCheckColour`, `Importance`-1 FROM `Monitors`";
std::string CameraType_Strings[] = { std::string CameraType_Strings[] = {
"Local", "Local",
@ -151,12 +151,12 @@ bool Monitor::MonitorLink::connect() {
Debug(1, "link.mem.size=%jd", mem_size); Debug(1, "link.mem.size=%jd", mem_size);
#if ZM_MEM_MAPPED #if ZM_MEM_MAPPED
map_fd = open(mem_file.c_str(), O_RDWR, (mode_t)0600); map_fd = open(mem_file.c_str(), O_RDWR, (mode_t)0600);
if ( map_fd < 0 ) { if (map_fd < 0) {
Debug(3, "Can't open linked memory map file %s: %s", mem_file.c_str(), strerror(errno)); Debug(3, "Can't open linked memory map file %s: %s", mem_file.c_str(), strerror(errno));
disconnect(); disconnect();
return false; return false;
} }
while ( map_fd <= 2 ) { while (map_fd <= 2) {
int new_map_fd = dup(map_fd); int new_map_fd = dup(map_fd);
Warning("Got one of the stdio fds for our mmap handle. map_fd was %d, new one is %d", map_fd, new_map_fd); Warning("Got one of the stdio fds for our mmap handle. map_fd was %d, new one is %d", map_fd, new_map_fd);
close(map_fd); close(map_fd);
@ -164,31 +164,31 @@ bool Monitor::MonitorLink::connect() {
} }
struct stat map_stat; struct stat map_stat;
if ( fstat(map_fd, &map_stat) < 0 ) { if (fstat(map_fd, &map_stat) < 0) {
Error("Can't stat linked memory map file %s: %s", mem_file.c_str(), strerror(errno)); Error("Can't stat linked memory map file %s: %s", mem_file.c_str(), strerror(errno));
disconnect(); disconnect();
return false; return false;
} }
if ( map_stat.st_size == 0 ) { if (map_stat.st_size == 0) {
Error("Linked memory map file %s is empty: %s", mem_file.c_str(), strerror(errno)); Error("Linked memory map file %s is empty: %s", mem_file.c_str(), strerror(errno));
disconnect(); disconnect();
return false; return false;
} else if ( map_stat.st_size < mem_size ) { } else if (map_stat.st_size < mem_size) {
Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, mem_size); Error("Got unexpected memory map file size %ld, expected %jd", map_stat.st_size, mem_size);
disconnect(); disconnect();
return false; return false;
} }
mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0);
if ( mem_ptr == MAP_FAILED ) { if (mem_ptr == MAP_FAILED) {
Error("Can't map file %s (%jd bytes) to memory: %s", mem_file.c_str(), mem_size, strerror(errno)); Error("Can't map file %s (%jd bytes) to memory: %s", mem_file.c_str(), mem_size, strerror(errno));
disconnect(); disconnect();
return false; return false;
} }
#else // ZM_MEM_MAPPED #else // ZM_MEM_MAPPED
shm_id = shmget((config.shm_key&0xffff0000)|id, mem_size, 0700); shm_id = shmget((config.shm_key&0xffff0000)|id, mem_size, 0700);
if ( shm_id < 0 ) { if (shm_id < 0) {
Debug(3, "Can't shmget link memory: %s", strerror(errno)); Debug(3, "Can't shmget link memory: %s", strerror(errno));
connected = false; connected = false;
return false; return false;
@ -444,7 +444,7 @@ Monitor::Monitor()
"SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, " "SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, "
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif," "FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif,"
"`RTSPServer`,`RTSPStreamName`, "`RTSPServer`,`RTSPStreamName`,
"SignalCheckPoints, SignalCheckColour, Importance-2 FROM Monitors"; "SignalCheckPoints, SignalCheckColour, Importance-1 FROM Monitors";
*/ */
void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
@ -481,8 +481,18 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
Debug(1, "Have camera type %s", CameraType_Strings[type].c_str()); Debug(1, "Have camera type %s", CameraType_Strings[type].c_str());
col++; col++;
function = (Function)atoi(dbrow[col]); col++; function = (Function)atoi(dbrow[col]); col++;
enabled = dbrow[col] ? atoi(dbrow[col]) : 0; col++; enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++;
decoding_enabled = dbrow[col] ? atoi(dbrow[col]) : 0; col++; decoding_enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++;
decoding_enabled = !(
( function == RECORD or function == NODECT )
and
( savejpegs == 0 )
and
( videowriter == PASSTHROUGH )
and
!decoding_enabled
);
Debug(1, "Decoding enabled: %d", decoding_enabled);
ReloadLinkedMonitors(dbrow[col]); col++; ReloadLinkedMonitors(dbrow[col]); col++;
@ -594,7 +604,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
rtsp_server = (*dbrow[col] != '0'); col++; rtsp_server = (*dbrow[col] != '0'); col++;
rtsp_streamname = dbrow[col]; col++; rtsp_streamname = dbrow[col]; col++;
/*"SignalCheckPoints, SignalCheckColour, Importance-2 FROM Monitors"; */ /*"SignalCheckPoints, SignalCheckColour, Importance-1 FROM Monitors"; */
signal_check_points = atoi(dbrow[col]); col++; signal_check_points = atoi(dbrow[col]); col++;
signal_check_colour = strtol(dbrow[col][0] == '#' ? dbrow[col]+1 : dbrow[col], 0, 16); col++; signal_check_colour = strtol(dbrow[col][0] == '#' ? dbrow[col]+1 : dbrow[col], 0, 16); col++;
@ -606,6 +616,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
grayscale_val = signal_check_colour & 0xff; /* Clear all bytes but lowest byte */ grayscale_val = signal_check_colour & 0xff; /* Clear all bytes but lowest byte */
importance = dbrow[col] ? atoi(dbrow[col]) : 0;// col++; importance = dbrow[col] ? atoi(dbrow[col]) : 0;// col++;
if (importance < 0) importance = 0; // Should only be >= 0
// How many frames we need to have before we start analysing // How many frames we need to have before we start analysing
ready_count = std::max(warmup_count, pre_event_count); ready_count = std::max(warmup_count, pre_event_count);
@ -653,18 +664,6 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
Error("Can't mkdir %s: %s", monitor_dir.c_str(), strerror(errno)); Error("Can't mkdir %s: %s", monitor_dir.c_str(), strerror(errno));
} }
// Do this here to save a few cycles with all the comparisons
decoding_enabled = !(
( function == RECORD or function == NODECT )
and
( savejpegs == 0 )
and
( videowriter == PASSTHROUGH )
and
!decoding_enabled
);
Debug(1, "Decoding enabled: %d", decoding_enabled);
if ( config.record_diag_images ) { if ( config.record_diag_images ) {
if ( config.record_diag_images_fifo ) { if ( config.record_diag_images_fifo ) {
diag_path_ref = stringtf("%s/diagpipe-r-%d.jpg", staticConfig.PATH_SOCKS.c_str(), id); diag_path_ref = stringtf("%s/diagpipe-r-%d.jpg", staticConfig.PATH_SOCKS.c_str(), id);
@ -1061,7 +1060,13 @@ bool Monitor::disconnect() {
return true; return true;
} }
shared_data->valid = false; if (purpose == CAPTURE) {
if (unlink(mem_file.c_str()) < 0) {
Warning("Can't unlink '%s': %s", mem_file.c_str(), strerror(errno));
}
Debug(1, "Setting shared_data->valid = false");
shared_data->valid = false;
}
#if ZM_MEM_MAPPED #if ZM_MEM_MAPPED
msync(mem_ptr, mem_size, MS_ASYNC); msync(mem_ptr, mem_size, MS_ASYNC);
munmap(mem_ptr, mem_size); munmap(mem_ptr, mem_size);
@ -1071,9 +1076,6 @@ bool Monitor::disconnect() {
mem_ptr = nullptr; mem_ptr = nullptr;
shared_data = nullptr; shared_data = nullptr;
if (purpose == CAPTURE and (unlink(mem_file.c_str()) < 0) ) {
Warning("Can't unlink '%s': %s", mem_file.c_str(), strerror(errno));
}
#else // ZM_MEM_MAPPED #else // ZM_MEM_MAPPED
struct shmid_ds shm_data; struct shmid_ds shm_data;
if (shmctl(shm_id, IPC_STAT, &shm_data) < 0) { if (shmctl(shm_id, IPC_STAT, &shm_data) < 0) {
@ -1094,7 +1096,7 @@ bool Monitor::disconnect() {
} }
#endif // ZM_MEM_MAPPED #endif // ZM_MEM_MAPPED
for ( int32_t i = 0; i < image_buffer_count; i++ ) { for (int32_t i = 0; i < image_buffer_count; i++) {
// We delete the image because it is an object pointing to space that won't be free'd. // We delete the image because it is an object pointing to space that won't be free'd.
delete image_buffer[i]; delete image_buffer[i];
image_buffer[i] = nullptr; image_buffer[i] = nullptr;
@ -1108,10 +1110,6 @@ Monitor::~Monitor() {
if (mem_ptr != nullptr) { if (mem_ptr != nullptr) {
if (purpose != QUERY) { if (purpose != QUERY) {
shared_data->state = state = IDLE;
shared_data->last_read_index = image_buffer_count;
shared_data->last_read_time = 0;
shared_data->valid = false;
memset(mem_ptr, 0, mem_size); memset(mem_ptr, 0, mem_size);
} // end if purpose != query } // end if purpose != query
disconnect(); disconnect();
@ -1744,10 +1742,6 @@ bool Monitor::Analyse() {
return false; return false;
} }
// Store the it that points to our snap we will need it later
packetqueue_iterator snap_it = *analysis_it;
packetqueue.increment_it(analysis_it);
// signal is set by capture // signal is set by capture
bool signal = shared_data->signal; bool signal = shared_data->signal;
bool signal_change = (signal != last_signal); bool signal_change = (signal != last_signal);
@ -1857,7 +1851,14 @@ bool Monitor::Analyse() {
while (!snap->decoded and !zm_terminate and !analysis_thread->Stopped()) { while (!snap->decoded and !zm_terminate and !analysis_thread->Stopped()) {
// Need to wait for the decoder thread. // Need to wait for the decoder thread.
Debug(1, "Waiting for decode"); Debug(1, "Waiting for decode");
packet_lock->wait(); packetqueue.unlock(packet_lock); // This will delete packet_lock and notify_all
packetqueue.wait();
// Another thread may have moved our it. Unlikely but possible
packet_lock = packetqueue.get_packet(analysis_it);
if (!packet_lock) return false;
snap = packet_lock->packet_;
if (!snap->image and snap->decoded) { if (!snap->image and snap->decoded) {
Debug(1, "No image but was decoded, giving up"); Debug(1, "No image but was decoded, giving up");
delete packet_lock; delete packet_lock;
@ -1960,14 +1961,14 @@ bool Monitor::Analyse() {
// Must start on a keyframe so rewind. Only for passthrough though I guess. // Must start on a keyframe so rewind. Only for passthrough though I guess.
// FIXME this iterator is not protected from invalidation // FIXME this iterator is not protected from invalidation
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it( packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
snap_it, 0 /* pre_event_count */ *analysis_it, 0 /* pre_event_count */
); );
// This gets a lock on the starting packet // This gets a lock on the starting packet
ZMLockedPacket *starting_packet_lock = nullptr; ZMLockedPacket *starting_packet_lock = nullptr;
std::shared_ptr<ZMPacket> starting_packet = nullptr; std::shared_ptr<ZMPacket> starting_packet = nullptr;
if (*start_it != snap_it) { if (*start_it != *analysis_it) {
starting_packet_lock = packetqueue.get_packet(start_it); starting_packet_lock = packetqueue.get_packet(start_it);
if (!starting_packet_lock) { if (!starting_packet_lock) {
Warning("Unable to get starting packet lock"); Warning("Unable to get starting packet lock");
@ -1981,12 +1982,12 @@ bool Monitor::Analyse() {
event = new Event(this, starting_packet->timestamp, "Continuous", noteSetMap); event = new Event(this, starting_packet->timestamp, "Continuous", noteSetMap);
// Write out starting packets, do not modify packetqueue it will garbage collect itself // Write out starting packets, do not modify packetqueue it will garbage collect itself
while (starting_packet and ((*start_it) != snap_it)) { while (starting_packet and ((*start_it) != *analysis_it)) {
event->AddPacket(starting_packet); event->AddPacket(starting_packet);
// Have added the packet, don't want to unlock it until we have locked the next // Have added the packet, don't want to unlock it until we have locked the next
packetqueue.increment_it(start_it); packetqueue.increment_it(start_it);
if ((*start_it) == snap_it) { if ((*start_it) == *analysis_it) {
if (starting_packet_lock) delete starting_packet_lock; if (starting_packet_lock) delete starting_packet_lock;
break; break;
} }
@ -2025,8 +2026,7 @@ bool Monitor::Analyse() {
} // end if ! event } // end if ! event
} // end if RECORDING } // end if RECORDING
if (score) { if (score and (function != MONITOR)) {
if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) { if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) {
// If we should end then previous continuous event and start a new non-continuous event // If we should end then previous continuous event and start a new non-continuous event
if (event && event->Frames() if (event && event->Frames()
@ -2064,12 +2064,12 @@ bool Monitor::Analyse() {
if (!event) { if (!event) {
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it( packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
snap_it, *analysis_it,
(pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count) (pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count)
); );
ZMLockedPacket *starting_packet_lock = nullptr; ZMLockedPacket *starting_packet_lock = nullptr;
std::shared_ptr<ZMPacket> starting_packet = nullptr; std::shared_ptr<ZMPacket> starting_packet = nullptr;
if (*start_it != snap_it) { if (*start_it != *analysis_it) {
starting_packet_lock = packetqueue.get_packet(start_it); starting_packet_lock = packetqueue.get_packet(start_it);
if (!starting_packet_lock) return false; if (!starting_packet_lock) return false;
starting_packet = starting_packet_lock->packet_; starting_packet = starting_packet_lock->packet_;
@ -2084,11 +2084,11 @@ bool Monitor::Analyse() {
shared_data->state = state = ALARM; shared_data->state = state = ALARM;
// Write out starting packets, do not modify packetqueue it will garbage collect itself // Write out starting packets, do not modify packetqueue it will garbage collect itself
while (*start_it != snap_it) { while (*start_it != *analysis_it) {
event->AddPacket(starting_packet); event->AddPacket(starting_packet);
packetqueue.increment_it(start_it); packetqueue.increment_it(start_it);
if ( (*start_it) == snap_it ) { if ( (*start_it) == (*analysis_it) ) {
if (starting_packet_lock) delete starting_packet_lock; if (starting_packet_lock) delete starting_packet_lock;
break; break;
} }
@ -2279,6 +2279,7 @@ bool Monitor::Analyse() {
if (function == MODECT or function == MOCORD) if (function == MODECT or function == MOCORD)
UpdateAnalysisFPS(); UpdateAnalysisFPS();
} }
packetqueue.increment_it(analysis_it);
packetqueue.unlock(packet_lock); packetqueue.unlock(packet_lock);
shared_data->last_read_time = time(nullptr); shared_data->last_read_time = time(nullptr);
@ -3057,7 +3058,7 @@ int Monitor::PrimeCapture() {
Debug(1, "Creating decoder thread"); Debug(1, "Creating decoder thread");
decoder = ZM::make_unique<DecoderThread>(this); decoder = ZM::make_unique<DecoderThread>(this);
} else { } else {
Debug(1, "Restartg decoder thread"); Debug(1, "Restarting decoder thread");
decoder->Start(); decoder->Start();
} }
} }

View File

@ -89,7 +89,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
break; break;
case CMD_PLAY : case CMD_PLAY :
Debug(1, "Got PLAY command"); Debug(1, "Got PLAY command");
if ( paused ) { if (paused) {
paused = false; paused = false;
delayed = true; delayed = true;
} }
@ -97,7 +97,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
break; break;
case CMD_VARPLAY : case CMD_VARPLAY :
Debug(1, "Got VARPLAY command"); Debug(1, "Got VARPLAY command");
if ( paused ) { if (paused) {
paused = false; paused = false;
delayed = true; delayed = true;
} }
@ -110,7 +110,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
break; break;
case CMD_FASTFWD : case CMD_FASTFWD :
Debug(1, "Got FAST FWD command"); Debug(1, "Got FAST FWD command");
if ( paused ) { if (paused) {
paused = false; paused = false;
delayed = true; delayed = true;
} }
@ -135,27 +135,27 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
} }
break; break;
case CMD_SLOWFWD : case CMD_SLOWFWD :
Debug( 1, "Got SLOW FWD command" ); Debug(1, "Got SLOW FWD command");
paused = true; paused = true;
delayed = true; delayed = true;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
step = 1; step = 1;
break; break;
case CMD_SLOWREV : case CMD_SLOWREV :
Debug( 1, "Got SLOW REV command" ); Debug(1, "Got SLOW REV command");
paused = true; paused = true;
delayed = true; delayed = true;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
step = -1; step = -1;
break; break;
case CMD_FASTREV : case CMD_FASTREV :
Debug( 1, "Got FAST REV command" ); Debug(1, "Got FAST REV command");
if ( paused ) { if (paused) {
paused = false; paused = false;
delayed = true; delayed = true;
} }
// Set play rate // Set play rate
switch ( replay_rate ) { switch (replay_rate) {
case -2 * ZM_RATE_BASE : case -2 * ZM_RATE_BASE :
replay_rate = -5 * ZM_RATE_BASE; replay_rate = -5 * ZM_RATE_BASE;
break; break;
@ -255,7 +255,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
} status_data; } status_data;
status_data.id = monitor->Id(); status_data.id = monitor->Id();
if ( ! monitor->ShmValid() ) { if (!monitor->ShmValid()) {
status_data.fps = 0.0; status_data.fps = 0.0;
status_data.capture_fps = 0.0; status_data.capture_fps = 0.0;
status_data.analysis_fps = 0.0; status_data.analysis_fps = 0.0;
@ -265,7 +265,14 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
status_data.forced = false; status_data.forced = false;
status_data.buffer_level = 0; status_data.buffer_level = 0;
} else { } else {
status_data.fps = monitor->GetFPS(); int elapsed = now.tv_sec - last_fps_update.tv_sec;
if (elapsed) {
actual_fps = (frame_count - last_frame_count) / elapsed;
last_frame_count = frame_count;
last_fps_update = now;
}
status_data.fps = actual_fps;
status_data.capture_fps = monitor->get_capture_fps(); status_data.capture_fps = monitor->get_capture_fps();
status_data.analysis_fps = monitor->get_analysis_fps(); status_data.analysis_fps = monitor->get_analysis_fps();
status_data.state = monitor->shared_data->state; status_data.state = monitor->shared_data->state;
@ -520,7 +527,7 @@ void MonitorStream::runStream() {
Image *paused_image = nullptr; Image *paused_image = nullptr;
struct timeval paused_timestamp; struct timeval paused_timestamp;
if ( connkey && ( playback_buffer > 0 ) ) { if (connkey && (playback_buffer > 0)) {
// 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id // 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id
const int max_swap_len_suffix = 15; const int max_swap_len_suffix = 15;
@ -529,27 +536,27 @@ void MonitorStream::runStream() {
int subfolder2_length = snprintf(nullptr, 0, "/zmswap-q%06d", connkey) + 1; int subfolder2_length = snprintf(nullptr, 0, "/zmswap-q%06d", connkey) + 1;
int total_swap_path_length = swap_path_length + subfolder1_length + subfolder2_length; int total_swap_path_length = swap_path_length + subfolder1_length + subfolder2_length;
if ( total_swap_path_length + max_swap_len_suffix > PATH_MAX ) { if (total_swap_path_length + max_swap_len_suffix > PATH_MAX) {
Error("Swap Path is too long. %d > %d ", total_swap_path_length+max_swap_len_suffix, PATH_MAX); Error("Swap Path is too long. %d > %d ", total_swap_path_length+max_swap_len_suffix, PATH_MAX);
} else { } else {
swap_path = staticConfig.PATH_SWAP; swap_path = staticConfig.PATH_SWAP;
Debug(3, "Checking swap path folder: %s", swap_path.c_str()); Debug(3, "Checking swap path folder: %s", swap_path.c_str());
if ( checkSwapPath(swap_path.c_str(), true) ) { if (checkSwapPath(swap_path.c_str(), true)) {
swap_path += stringtf("/zmswap-m%d", monitor->Id()); swap_path += stringtf("/zmswap-m%d", monitor->Id());
Debug(4, "Checking swap path subfolder: %s", swap_path.c_str()); Debug(4, "Checking swap path subfolder: %s", swap_path.c_str());
if ( checkSwapPath(swap_path.c_str(), true) ) { if (checkSwapPath(swap_path.c_str(), true)) {
swap_path += stringtf("/zmswap-q%06d", connkey); swap_path += stringtf("/zmswap-q%06d", connkey);
Debug(4, "Checking swap path subfolder: %s", swap_path.c_str()); Debug(4, "Checking swap path subfolder: %s", swap_path.c_str());
if ( checkSwapPath(swap_path.c_str(), true) ) { if (checkSwapPath(swap_path.c_str(), true)) {
buffered_playback = true; buffered_playback = true;
} }
} }
} }
if ( !buffered_playback ) { if (!buffered_playback) {
Error("Unable to validate swap image path, disabling buffered playback"); Error("Unable to validate swap image path, disabling buffered playback");
} else { } else {
Debug(2, "Assigning temporary buffer"); Debug(2, "Assigning temporary buffer");
@ -560,14 +567,13 @@ void MonitorStream::runStream() {
} }
} else { } else {
Debug(2, "Not using playback_buffer"); Debug(2, "Not using playback_buffer");
} // end if connkey & playback_buffer } // end if connkey && playback_buffer
while (!zm_terminate) { while (!zm_terminate) {
bool got_command = false; if (feof(stdout)) {
if ( feof(stdout) ) {
Debug(2, "feof stdout"); Debug(2, "feof stdout");
break; break;
} else if ( ferror(stdout) ) { } else if (ferror(stdout)) {
Debug(2, "ferror stdout"); Debug(2, "ferror stdout");
break; break;
} else if (!monitor->ShmValid()) { } else if (!monitor->ShmValid()) {
@ -578,8 +584,9 @@ void MonitorStream::runStream() {
gettimeofday(&now, nullptr); gettimeofday(&now, nullptr);
bool was_paused = paused; bool was_paused = paused;
if ( connkey ) { bool got_command = false; // commands like zoom should output a frame even if paused
while ( checkCommandQueue() && !zm_terminate ) { if (connkey) {
while (checkCommandQueue() && !zm_terminate) {
// Loop in here until all commands are processed. // Loop in here until all commands are processed.
Debug(2, "Have checking command Queue for connkey: %d", connkey); Debug(2, "Have checking command Queue for connkey: %d", connkey);
got_command = true; got_command = true;
@ -591,35 +598,31 @@ void MonitorStream::runStream() {
} }
} // end if connkey } // end if connkey
if ( paused ) { if (paused) {
if ( !was_paused ) { if (!was_paused) {
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
Debug(1, "Saving paused image from index %d",index); Debug(1, "Saving paused image from index %d",index);
paused_image = new Image(*monitor->image_buffer[index]); paused_image = new Image(*monitor->image_buffer[index]);
paused_timestamp = monitor->shared_timestamps[index]; paused_timestamp = monitor->shared_timestamps[index];
} }
} else if ( paused_image ) { } else if (paused_image) {
Debug(1, "Clearing paused_image");
delete paused_image; delete paused_image;
paused_image = nullptr; paused_image = nullptr;
} }
if ( buffered_playback && delayed ) { if (buffered_playback && delayed) {
if ( temp_read_index == temp_write_index ) { if (temp_read_index == temp_write_index) {
// Go back to live viewing // Go back to live viewing
Debug(1, "Exceeded temporary streaming buffer"); Debug(1, "Exceeded temporary streaming buffer");
// Clear paused flag
paused = false; paused = false;
// Clear delayed_play flag
delayed = false; delayed = false;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
} else { } else {
if ( !paused ) { if (!paused) {
int temp_index = MOD_ADD(temp_read_index, 0, temp_image_buffer_count); int temp_index = MOD_ADD(temp_read_index, 0, temp_image_buffer_count);
// Debug( 3, "tri: %d, ti: %d", temp_read_index, temp_index );
SwapImage *swap_image = &temp_image_buffer[temp_index]; SwapImage *swap_image = &temp_image_buffer[temp_index];
if ( !swap_image->valid ) { if (!swap_image->valid) {
paused = true; paused = true;
delayed = true; delayed = true;
temp_read_index = MOD_ADD(temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count); temp_read_index = MOD_ADD(temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count);
@ -632,13 +635,14 @@ void MonitorStream::runStream() {
// If the next frame is due // If the next frame is due
if ( actual_delta_time > expected_delta_time ) { if ( actual_delta_time > expected_delta_time ) {
// Debug( 2, "eDT: %.3lf, aDT: %.3f", expected_delta_time, actual_delta_time ); // Debug( 2, "eDT: %.3lf, aDT: %.3f", expected_delta_time, actual_delta_time );
if ( temp_index%frame_mod == 0 ) { if ((temp_index % frame_mod) == 0) {
Debug(2, "Sending delayed frame %d", temp_index); Debug(2, "Sending delayed frame %d", temp_index);
// Send the next frame // Send the next frame
if (!sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp)) { if (!sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp)) {
zm_terminate = true; zm_terminate = true;
} }
memcpy(&last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp)); frame_count++;
last_frame_timestamp = swap_image->timestamp;
// frame_sent = true; // frame_sent = true;
} }
temp_read_index = MOD_ADD(temp_read_index, (replay_rate>0?1:-1), temp_image_buffer_count); temp_read_index = MOD_ADD(temp_read_index, (replay_rate>0?1:-1), temp_image_buffer_count);
@ -650,17 +654,15 @@ void MonitorStream::runStream() {
SwapImage *swap_image = &temp_image_buffer[temp_read_index]; SwapImage *swap_image = &temp_image_buffer[temp_read_index];
// Send the next frame // Send the next frame
if ( !sendFrame( if (!sendFrame(
temp_image_buffer[temp_read_index].file_name, temp_image_buffer[temp_read_index].file_name,
temp_image_buffer[temp_read_index].timestamp temp_image_buffer[temp_read_index].timestamp)
) ) { ) {
zm_terminate = true; zm_terminate = true;
} }
memcpy( frame_count++;
&last_frame_timestamp,
&(swap_image->timestamp), last_frame_timestamp = swap_image->timestamp;
sizeof(last_frame_timestamp)
);
// frame_sent = true; // frame_sent = true;
step = 0; step = 0;
} else { } else {
@ -675,12 +677,13 @@ void MonitorStream::runStream() {
if ( !sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp) ) { if ( !sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp) ) {
zm_terminate = true; zm_terminate = true;
} }
frame_count++;
// frame_sent = true; // frame_sent = true;
} }
} // end if (!paused) or step or paused } // end if (!paused) or step or paused
} // end if have exceeded buffer or not } // end if have exceeded buffer or not
if ( temp_read_index == temp_write_index ) { if (temp_read_index == temp_write_index) {
// Go back to live viewing // Go back to live viewing
Warning("Rewound over write index, resuming live play"); Warning("Rewound over write index, resuming live play");
// Clear paused flag // Clear paused flag
@ -689,13 +692,13 @@ void MonitorStream::runStream() {
delayed = false; delayed = false;
replay_rate = ZM_RATE_BASE; replay_rate = ZM_RATE_BASE;
} }
} // end if ( buffered_playback && delayed ) } // end if (buffered_playback && delayed)
if ( last_read_index != monitor->shared_data->last_write_index ) { if (last_read_index != monitor->shared_data->last_write_index) {
// have a new image to send // have a new image to send
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; // % shouldn't be neccessary int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) { if ((frame_mod == 1) || ((frame_count%frame_mod) == 0)) {
if ( !paused && !delayed ) { if (!paused && !delayed) {
last_read_index = monitor->shared_data->last_write_index; last_read_index = monitor->shared_data->last_write_index;
Debug(2, "Sending frame index: %d: frame_mod: %d frame count: %d paused(%d) delayed(%d)", Debug(2, "Sending frame index: %d: frame_mod: %d frame count: %d paused(%d) delayed(%d)",
index, frame_mod, frame_count, paused, delayed); index, frame_mod, frame_count, paused, delayed);
@ -710,9 +713,8 @@ void MonitorStream::runStream() {
zm_terminate = true; zm_terminate = true;
break; break;
} }
//frame_sent = true; frame_count++;
// if (frame_count == 0) {
if ( frame_count == 0 ) {
// Chrome will not display the first frame until it receives another. // Chrome will not display the first frame until it receives another.
// Firefox is fine. So just send the first frame twice. // Firefox is fine. So just send the first frame twice.
if ( !sendFrame(image, last_frame_timestamp) ) { if ( !sendFrame(image, last_frame_timestamp) ) {
@ -724,16 +726,18 @@ void MonitorStream::runStream() {
temp_read_index = temp_write_index; temp_read_index = temp_write_index;
} else { } else {
if ( delayed && !buffered_playback ) { if (delayed && !buffered_playback) {
Debug(2, "Can't delay when not buffering."); Debug(2, "Can't delay when not buffering.");
delayed = false; delayed = false;
} }
if ( last_zoom != zoom ) { if (last_zoom != zoom) {
Debug(2, "Sending 2 frames because change in zoom %d ?= %d", last_zoom, zoom); Debug(2, "Sending 2 frames because change in zoom %d ?= %d", last_zoom, zoom);
if (!sendFrame(paused_image, paused_timestamp)) if (!sendFrame(paused_image, paused_timestamp))
zm_terminate = true; zm_terminate = true;
if (!sendFrame(paused_image, paused_timestamp)) if (!sendFrame(paused_image, paused_timestamp))
zm_terminate = true; zm_terminate = true;
frame_count++;
frame_count++;
} else { } else {
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent; double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
if ( actual_delta_time > 5 ) { if ( actual_delta_time > 5 ) {
@ -744,17 +748,20 @@ void MonitorStream::runStream() {
// Send the next frame // Send the next frame
if (!sendFrame(paused_image, paused_timestamp)) if (!sendFrame(paused_image, paused_timestamp))
zm_terminate = true; zm_terminate = true;
frame_count++;
} else { } else {
Debug(2, "Would have sent keepalive frame, but had no paused_image"); Debug(2, "Would have sent keepalive frame, but had no paused_image");
} }
} // end if actual_delta_time > 5 } // end if actual_delta_time > 5
} // end if change in zoom } // end if change in zoom
} // end if paused or not } // end if paused or not
} else {
frame_count++;
} // end if should send frame } // end if should send frame
if ( buffered_playback && !paused ) { if (buffered_playback && !paused) {
if ( monitor->shared_data->valid ) { if (monitor->shared_data->valid) {
if ( monitor->shared_timestamps[index].tv_sec ) { if (monitor->shared_timestamps[index].tv_sec) {
int temp_index = temp_write_index%temp_image_buffer_count; int temp_index = temp_write_index%temp_image_buffer_count;
Debug(2, "Storing frame %d", temp_index); Debug(2, "Storing frame %d", temp_index);
if ( !temp_image_buffer[temp_index].valid ) { if ( !temp_image_buffer[temp_index].valid ) {
@ -772,7 +779,7 @@ void MonitorStream::runStream() {
config.jpeg_file_quality config.jpeg_file_quality
); );
temp_write_index = MOD_ADD(temp_write_index, 1, temp_image_buffer_count); temp_write_index = MOD_ADD(temp_write_index, 1, temp_image_buffer_count);
if ( temp_write_index == temp_read_index ) { if (temp_write_index == temp_read_index) {
// Go back to live viewing // Go back to live viewing
Warning("Exceeded temporary buffer, resuming live play"); Warning("Exceeded temporary buffer, resuming live play");
paused = false; paused = false;
@ -786,7 +793,6 @@ void MonitorStream::runStream() {
Warning("Unable to store frame as shared memory invalid"); Warning("Unable to store frame as shared memory invalid");
} }
} // end if buffered playback } // end if buffered playback
frame_count++;
} else { } else {
Debug(3, "Waiting for capture last_write_index=%u", monitor->shared_data->last_write_index); Debug(3, "Waiting for capture last_write_index=%u", monitor->shared_data->last_write_index);
} // end if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index ) } // end if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index )
@ -815,16 +821,16 @@ void MonitorStream::runStream() {
Warning("no last_frame_sent. Shouldn't happen. frame_mod was (%d) frame_count (%d)", Warning("no last_frame_sent. Shouldn't happen. frame_mod was (%d) frame_count (%d)",
frame_mod, frame_count); frame_mod, frame_count);
} }
} // end while } // end while ! zm_terminate
if ( buffered_playback ) { if (buffered_playback) {
Debug(1, "Cleaning swap files from %s", swap_path.c_str()); Debug(1, "Cleaning swap files from %s", swap_path.c_str());
struct stat stat_buf; struct stat stat_buf = {};
if ( stat(swap_path.c_str(), &stat_buf) < 0 ) { if (stat(swap_path.c_str(), &stat_buf) < 0) {
if ( errno != ENOENT ) { if (errno != ENOENT) {
Error("Can't stat '%s': %s", swap_path.c_str(), strerror(errno)); Error("Can't stat '%s': %s", swap_path.c_str(), strerror(errno));
} }
} else if ( !S_ISDIR(stat_buf.st_mode) ) { } else if (!S_ISDIR(stat_buf.st_mode)) {
Error("Swap image path '%s' is not a directory", swap_path.c_str()); Error("Swap image path '%s' is not a directory", swap_path.c_str());
} else { } else {
char glob_pattern[PATH_MAX] = ""; char glob_pattern[PATH_MAX] = "";
@ -832,21 +838,21 @@ void MonitorStream::runStream() {
snprintf(glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path.c_str()); snprintf(glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path.c_str());
glob_t pglob; glob_t pglob;
int glob_status = glob(glob_pattern, 0, 0, &pglob); int glob_status = glob(glob_pattern, 0, 0, &pglob);
if ( glob_status != 0 ) { if (glob_status != 0) {
if ( glob_status < 0 ) { if (glob_status < 0) {
Error("Can't glob '%s': %s", glob_pattern, strerror(errno)); Error("Can't glob '%s': %s", glob_pattern, strerror(errno));
} else { } else {
Debug(1, "Can't glob '%s': %d", glob_pattern, glob_status); Debug(1, "Can't glob '%s': %d", glob_pattern, glob_status);
} }
} else { } else {
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) { for (unsigned int i = 0; i < pglob.gl_pathc; i++) {
if ( unlink(pglob.gl_pathv[i]) < 0 ) { if (unlink(pglob.gl_pathv[i]) < 0) {
Error("Can't unlink '%s': %s", pglob.gl_pathv[i], strerror(errno)); Error("Can't unlink '%s': %s", pglob.gl_pathv[i], strerror(errno));
} }
} }
} }
globfree(&pglob); globfree(&pglob);
if ( rmdir(swap_path.c_str()) < 0 ) { if (rmdir(swap_path.c_str()) < 0) {
Error("Can't rmdir '%s': %s", swap_path.c_str(), strerror(errno)); Error("Can't rmdir '%s': %s", swap_path.c_str(), strerror(errno));
} }
} // end if checking for swap_path } // end if checking for swap_path

View File

@ -41,7 +41,6 @@ class MonitorStream : public StreamBase {
time_t ttl; time_t ttl;
int playback_buffer; int playback_buffer;
bool delayed; bool delayed;
int frame_count;
protected: protected:
bool checkSwapPath(const char *path, bool create_path); bool checkSwapPath(const char *path, bool create_path);
@ -62,9 +61,9 @@ class MonitorStream : public StreamBase {
temp_write_index(0), temp_write_index(0),
ttl(0), ttl(0),
playback_buffer(0), playback_buffer(0),
delayed(false), delayed(false)
frame_count(0) { {}
}
void setStreamBuffer(int p_playback_buffer) { void setStreamBuffer(int p_playback_buffer) {
playback_buffer = p_playback_buffer; playback_buffer = p_playback_buffer;
} }

View File

@ -134,6 +134,7 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
if (max_video_packet_count > 0) { if (max_video_packet_count > 0) {
while (packet_counts[video_stream_id] > max_video_packet_count) { while (packet_counts[video_stream_id] > max_video_packet_count) {
Error("Unable to free up older packets. Waiting."); Error("Unable to free up older packets. Waiting.");
condition.notify_all();
condition.wait(lck); condition.wait(lck);
if (deleting or zm_terminate) if (deleting or zm_terminate)
return false; return false;
@ -179,6 +180,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
// So start at the beginning, counting video packets until the next keyframe. // So start at the beginning, counting video packets until the next keyframe.
// Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them. // Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them.
if (deleting) return; if (deleting) return;
if (!pktQueue.size()) return;
if (keep_keyframes and ! ( if (keep_keyframes and ! (
add_packet->packet.stream_index == video_stream_id add_packet->packet.stream_index == video_stream_id
@ -197,7 +199,6 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
return; return;
} }
std::unique_lock<std::mutex> lck(mutex); std::unique_lock<std::mutex> lck(mutex);
if (!pktQueue.size()) return;
// If analysis_it isn't at the end, we need to keep that many additional packets // If analysis_it isn't at the end, we need to keep that many additional packets
int tail_count = 0; int tail_count = 0;
@ -257,15 +258,12 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
++it; ++it;
delete lp; delete lp;
if (it == pktQueue.end()) {
Debug(1, "Hit end already");
it = pktQueue.begin();
} else {
// Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that // Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that
while (*it != add_packet) { while (*it != add_packet) {
zm_packet = *it; zm_packet = *it;
lp = new ZMLockedPacket(zm_packet); lp = new ZMLockedPacket(zm_packet);
if (!lp->trylock()) { if (!lp->trylock()) {
Debug(3, "Failed locking packet %d", zm_packet->image_index);
delete lp; delete lp;
break; break;
} }
@ -282,17 +280,16 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
next_front = it; next_front = it;
} }
++video_packets_to_delete; ++video_packets_to_delete;
Debug(4, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d", Debug(3, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d",
video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count); video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count);
if (packet_counts[video_stream_id] - video_packets_to_delete <= pre_event_video_packet_count + tail_count) { if (packet_counts[video_stream_id] - video_packets_to_delete <= pre_event_video_packet_count + tail_count) {
break; break;
} }
} }
++it; ++it;
} // end while } // end while
}
} // end if first packet not locked } // end if first packet not locked
Debug(1, "Resulting pointing at latest packet? %d, next front points to begin? %d", Debug(1, "Resulting it pointing at latest packet? %d, next front points to begin? %d",
( *it == add_packet ), ( *it == add_packet ),
( next_front == pktQueue.begin() ) ( next_front == pktQueue.begin() )
); );
@ -325,6 +322,8 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
void PacketQueue::clear() { void PacketQueue::clear() {
deleting = true; deleting = true;
condition.notify_all(); condition.notify_all();
if (!packet_counts) // special case, not initialised
return;
Debug(1, "Clearing packetqueue"); Debug(1, "Clearing packetqueue");
std::unique_lock<std::mutex> lck(mutex); std::unique_lock<std::mutex> lck(mutex);
@ -662,3 +661,12 @@ void PacketQueue::setPreEventVideoPackets(int p) {
pre_event_video_packet_count = 1; pre_event_video_packet_count = 1;
// We can simplify a lot of logic in queuePacket if we can assume at least 1 packet in queue // We can simplify a lot of logic in queuePacket if we can assume at least 1 packet in queue
} }
void PacketQueue::notify_all() {
condition.notify_all();
};
void PacketQueue::wait() {
std::unique_lock<std::mutex> lck(mutex);
condition.wait(lck);
}

View File

@ -81,6 +81,8 @@ class PacketQueue {
); );
bool is_there_an_iterator_pointing_to_packet(const std::shared_ptr<ZMPacket> &zm_packet); bool is_there_an_iterator_pointing_to_packet(const std::shared_ptr<ZMPacket> &zm_packet);
void unlock(ZMLockedPacket *lp); void unlock(ZMLockedPacket *lp);
void notify_all();
void wait();
}; };
#endif /* ZM_PACKETQUEUE_H */ #endif /* ZM_PACKETQUEUE_H */

View File

@ -100,7 +100,8 @@ void RemoteCamera::Initialise() {
int ret = getaddrinfo(host.c_str(), port.c_str(), &hints, &hp); int ret = getaddrinfo(host.c_str(), port.c_str(), &hints, &hp);
if ( ret != 0 ) { if ( ret != 0 ) {
Fatal( "Can't getaddrinfo(%s port %s): %s", host.c_str(), port.c_str(), gai_strerror(ret) ); Error( "Can't getaddrinfo(%s port %s): %s", host.c_str(), port.c_str(), gai_strerror(ret) );
return;
} }
struct addrinfo *p = nullptr; struct addrinfo *p = nullptr;
int addr_count = 0; int addr_count = 0;

View File

@ -144,6 +144,14 @@ void RemoteCameraHttp::Initialise() {
int RemoteCameraHttp::Connect() { int RemoteCameraHttp::Connect() {
struct addrinfo *p = nullptr; struct addrinfo *p = nullptr;
if (!hp) {
RemoteCamera::Initialise();
if (!hp) {
Error("Unable to resolve address for remote camera, aborting");
return -1;
}
}
for ( p = hp; p != nullptr; p = p->ai_next ) { for ( p = hp; p != nullptr; p = p->ai_next ) {
sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol ); sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if ( sd < 0 ) { if ( sd < 0 ) {

View File

@ -279,9 +279,8 @@ int main(int argc, char *argv[]) {
Warning("Unknown format in %s", videoFifoPath.c_str()); Warning("Unknown format in %s", videoFifoPath.c_str());
} }
if (videoSource == nullptr) { if (videoSource == nullptr) {
Error("Unable to create source"); Error("Unable to create source for %s", videoFifoPath.c_str());
rtspServer->RemoveSession(sessions[monitor->Id()]->GetMediaSessionId()); rtspServer->RemoveSession(sessions[monitor->Id()]->GetMediaSessionId());
delete sessions[monitor->Id()];
sessions.erase(monitor->Id()); sessions.erase(monitor->Id());
continue; continue;
} }

View File

@ -102,7 +102,6 @@ protected:
int last_scale; int last_scale;
int zoom; int zoom;
int last_zoom; int last_zoom;
double maxfps;
int bitrate; int bitrate;
unsigned short last_x, last_y; unsigned short last_x, last_y;
unsigned short x, y; unsigned short x, y;
@ -122,8 +121,14 @@ protected:
struct timeval now; struct timeval now;
struct timeval last_comm_update; struct timeval last_comm_update;
double base_fps; double maxfps;
double effective_fps; double base_fps; // Should be capturing fps, hence a rough target
double effective_fps; // Target fps after taking max_fps into account
double actual_fps; // sliding calculated actual streaming fps achieved
struct timeval last_fps_update;
int frame_count; // Count of frames sent
int last_frame_count; // Used in calculating actual_fps from frame_count - last_frame_count
int frame_mod; int frame_mod;
double last_frame_sent; double last_frame_sent;
@ -154,7 +159,6 @@ public:
last_scale(DEFAULT_SCALE), last_scale(DEFAULT_SCALE),
zoom(DEFAULT_ZOOM), zoom(DEFAULT_ZOOM),
last_zoom(DEFAULT_ZOOM), last_zoom(DEFAULT_ZOOM),
maxfps(DEFAULT_MAXFPS),
bitrate(DEFAULT_BITRATE), bitrate(DEFAULT_BITRATE),
last_x(0), last_x(0),
last_y(0), last_y(0),
@ -166,7 +170,15 @@ public:
sd(-1), sd(-1),
lock_fd(0), lock_fd(0),
paused(false), paused(false),
step(0) step(0),
maxfps(DEFAULT_MAXFPS),
base_fps(0.0),
effective_fps(0.0),
actual_fps(0.0),
last_fps_update({}),
frame_count(0),
last_frame_count(0),
frame_mod(1)
{ {
memset(&loc_sock_path, 0, sizeof(loc_sock_path)); memset(&loc_sock_path, 0, sizeof(loc_sock_path));
memset(&loc_addr, 0, sizeof(loc_addr)); memset(&loc_addr, 0, sizeof(loc_addr));
@ -174,12 +186,8 @@ public:
memset(&rem_addr, 0, sizeof(rem_addr)); memset(&rem_addr, 0, sizeof(rem_addr));
memset(&sock_path_lock, 0, sizeof(sock_path_lock)); memset(&sock_path_lock, 0, sizeof(sock_path_lock));
base_fps = 0.0;
effective_fps = 0.0;
frame_mod = 1;
#if HAVE_LIBAVCODEC #if HAVE_LIBAVCODEC
vid_stream = 0; vid_stream = nullptr;
#endif // HAVE_LIBAVCODEC #endif // HAVE_LIBAVCODEC
last_frame_sent = 0.0; last_frame_sent = 0.0;
last_frame_timestamp = {}; last_frame_timestamp = {};

View File

@ -197,6 +197,7 @@ bool ValidateAccess(User *user, int mon_id, int function) {
void exit_zmu(int exit_code) { void exit_zmu(int exit_code) {
logTerm(); logTerm();
dbQueue.stop();
zmDbClose(); zmDbClose();
exit(exit_code); exit(exit_code);
@ -248,7 +249,7 @@ int main(int argc, char *argv[]) {
{nullptr, 0, nullptr, 0} {nullptr, 0, nullptr, 0}
}; };
const char *device = nullptr; std::string device;
int mon_id = 0; int mon_id = 0;
bool verbose = false; bool verbose = false;
int function = ZMU_BOGUS; int function = ZMU_BOGUS;
@ -256,9 +257,16 @@ int main(int argc, char *argv[]) {
int image_idx = -1; int image_idx = -1;
int scale = -1; int scale = -1;
int brightness = -1; int brightness = -1;
bool have_brightness = false;
int contrast = -1; int contrast = -1;
bool have_contrast = false;
int hue = -1; int hue = -1;
bool have_hue = false;
int colour = -1; int colour = -1;
bool have_colour = false;
char *zoneString = nullptr; char *zoneString = nullptr;
char *username = nullptr; char *username = nullptr;
char *password = nullptr; char *password = nullptr;
@ -275,13 +283,13 @@ int main(int argc, char *argv[]) {
int option_index = 0; int option_index = 0;
int c = getopt_long(argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::RWU:P:A:V:T:", long_options, &option_index); int c = getopt_long(argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::RWU:P:A:V:T:", long_options, &option_index);
if ( c == -1 ) { if (c == -1) {
break; break;
} }
switch (c) { switch (c) {
case 'd': case 'd':
if ( optarg ) if (optarg)
device = optarg; device = optarg;
break; break;
case 'm': case 'm':
@ -295,7 +303,7 @@ int main(int argc, char *argv[]) {
break; break;
case 'i': case 'i':
function |= ZMU_IMAGE; function |= ZMU_IMAGE;
if ( optarg ) if (optarg)
image_idx = atoi(optarg); image_idx = atoi(optarg);
break; break;
case 'S': case 'S':
@ -303,7 +311,7 @@ int main(int argc, char *argv[]) {
break; break;
case 't': case 't':
function |= ZMU_TIME; function |= ZMU_TIME;
if ( optarg ) if (optarg)
image_idx = atoi(optarg); image_idx = atoi(optarg);
break; break;
case 'R': case 'R':
@ -320,7 +328,7 @@ int main(int argc, char *argv[]) {
break; break;
case 'z': case 'z':
function |= ZMU_ZONES; function |= ZMU_ZONES;
if ( optarg ) if (optarg)
zoneString = optarg; zoneString = optarg;
break; break;
case 'a': case 'a':
@ -352,23 +360,31 @@ int main(int argc, char *argv[]) {
break; break;
case 'B': case 'B':
function |= ZMU_BRIGHTNESS; function |= ZMU_BRIGHTNESS;
if ( optarg ) if (optarg) {
have_brightness = true;
brightness = atoi(optarg); brightness = atoi(optarg);
}
break; break;
case 'C': case 'C':
function |= ZMU_CONTRAST; function |= ZMU_CONTRAST;
if ( optarg ) if (optarg) {
have_contrast = true;
contrast = atoi(optarg); contrast = atoi(optarg);
}
break; break;
case 'H': case 'H':
function |= ZMU_HUE; function |= ZMU_HUE;
if ( optarg ) if (optarg) {
have_hue = true;
hue = atoi(optarg); hue = atoi(optarg);
}
break; break;
case 'O': case 'O':
function |= ZMU_COLOUR; function |= ZMU_COLOUR;
if ( optarg ) if (optarg) {
have_colour = true;
colour = atoi(optarg); colour = atoi(optarg);
}
break; break;
case 'U': case 'U':
username = optarg; username = optarg;
@ -408,7 +424,7 @@ int main(int argc, char *argv[]) {
Usage(); Usage();
} }
if ( device && !(function&ZMU_QUERY) ) { if ( !device.empty() && !(function&ZMU_QUERY) ) {
fprintf(stderr, "Error, -d option cannot be used with this option\n"); fprintf(stderr, "Error, -d option cannot be used with this option\n");
Usage(); Usage();
} }
@ -643,60 +659,60 @@ int main(int argc, char *argv[]) {
monitor->DumpSettings(monString, verbose); monitor->DumpSettings(monString, verbose);
printf("%s\n", monString); printf("%s\n", monString);
} }
if ( function & ZMU_BRIGHTNESS ) { if (function & ZMU_BRIGHTNESS) {
if ( verbose ) { if (verbose) {
if ( brightness >= 0 ) if (have_brightness)
printf("New brightness: %d\n", monitor->actionBrightness(brightness)); printf("New brightness: %d\n", monitor->actionBrightness(brightness));
else else
printf("Current brightness: %d\n", monitor->actionBrightness()); printf("Current brightness: %d\n", monitor->actionBrightness());
} else { } else {
if ( have_output ) fputc(separator, stdout); if (have_output) fputc(separator, stdout);
if ( brightness >= 0 ) if (have_brightness)
printf("%d", monitor->actionBrightness(brightness)); printf("%d", monitor->actionBrightness(brightness));
else else
printf("%d", monitor->actionBrightness()); printf("%d", monitor->actionBrightness());
have_output = true; have_output = true;
} }
} }
if ( function & ZMU_CONTRAST ) { if (function & ZMU_CONTRAST) {
if ( verbose ) { if (verbose) {
if ( contrast >= 0 ) if (have_contrast)
printf("New brightness: %d\n", monitor->actionContrast(contrast)); printf("New contrast: %d\n", monitor->actionContrast(contrast));
else else
printf("Current contrast: %d\n", monitor->actionContrast()); printf("Current contrast: %d\n", monitor->actionContrast());
} else { } else {
if ( have_output ) fputc(separator, stdout); if (have_output) fputc(separator, stdout);
if ( contrast >= 0 ) if (have_contrast)
printf("%d", monitor->actionContrast(contrast)); printf("%d", monitor->actionContrast(contrast));
else else
printf("%d", monitor->actionContrast()); printf("%d", monitor->actionContrast());
have_output = true; have_output = true;
} }
} }
if ( function & ZMU_HUE ) { if (function & ZMU_HUE) {
if ( verbose ) { if (verbose) {
if ( hue >= 0 ) if (have_hue)
printf("New hue: %d\n", monitor->actionHue(hue)); printf("New hue: %d\n", monitor->actionHue(hue));
else else
printf("Current hue: %d\n", monitor->actionHue()); printf("Current hue: %d\n", monitor->actionHue());
} else { } else {
if ( have_output ) fputc(separator, stdout); if (have_output) fputc(separator, stdout);
if ( hue >= 0 ) if (have_hue)
printf("%d", monitor->actionHue(hue)); printf("%d", monitor->actionHue(hue));
else else
printf("%d", monitor->actionHue()); printf("%d", monitor->actionHue());
have_output = true; have_output = true;
} }
} }
if ( function & ZMU_COLOUR ) { if (function & ZMU_COLOUR) {
if ( verbose ) { if (verbose) {
if ( colour >= 0 ) if (have_colour)
printf("New colour: %d\n", monitor->actionColour(colour)); printf("New colour: %d\n", monitor->actionColour(colour));
else else
printf("Current colour: %d\n", monitor->actionColour()); printf("Current colour: %d\n", monitor->actionColour());
} else { } else {
if ( have_output ) fputc(separator, stdout); if (have_output) fputc(separator, stdout);
if ( colour >= 0 ) if (have_colour)
printf("%d", monitor->actionColour(colour)); printf("%d", monitor->actionColour(colour));
else else
printf("%d", monitor->actionColour()); printf("%d", monitor->actionColour());
@ -704,7 +720,7 @@ int main(int argc, char *argv[]) {
} }
} }
if ( have_output ) { if (have_output) {
printf("\n"); printf("\n");
} }
if ( !function ) { if ( !function ) {
@ -714,7 +730,7 @@ int main(int argc, char *argv[]) {
if ( function & ZMU_QUERY ) { if ( function & ZMU_QUERY ) {
#if ZM_HAS_V4L #if ZM_HAS_V4L
char vidString[0x10000] = ""; char vidString[0x10000] = "";
bool ok = LocalCamera::GetCurrentSettings(device, vidString, v4lVersion, verbose); bool ok = LocalCamera::GetCurrentSettings(device.c_str(), vidString, v4lVersion, verbose);
printf("%s", vidString); printf("%s", vidString);
exit_zmu(ok ? 0 : -1); exit_zmu(ok ? 0 : -1);
#else // ZM_HAS_V4L #else // ZM_HAS_V4L

View File

@ -58,6 +58,14 @@ case $i in
PACKAGE_VERSION="${i#*=}" PACKAGE_VERSION="${i#*=}"
shift shift
;; ;;
-x=*|--debbuild-extra=*)
DEBBUILD_EXTRA="${i#*=}"
shift
;;
--dput=*)
DPUT="${i#*=}"
shift
;;
--default) --default)
DEFAULT=YES DEFAULT=YES
shift # past argument with no value shift # past argument with no value
@ -80,7 +88,7 @@ fi;
if [ "$DISTROS" == "" ]; then if [ "$DISTROS" == "" ]; then
if [ "$RELEASE" != "" ]; then if [ "$RELEASE" != "" ]; then
DISTROS="xenial,bionic,focal,groovy,hirsute" DISTROS="xenial,bionic,focal,hirsute,impish"
else else
DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`; DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
fi; fi;
@ -112,6 +120,11 @@ else
if [ "$BRANCH" == "" ]; then if [ "$BRANCH" == "" ]; then
#REV=$(git rev-list --tags --max-count=1) #REV=$(git rev-list --tags --max-count=1)
BRANCH=`git describe --tags $(git rev-list --tags --max-count=1)`; BRANCH=`git describe --tags $(git rev-list --tags --max-count=1)`;
if [ -z "$BRANCH" ]; then
# This should only happen in CI environments where tag info isn't available
BRANCH=`cat version`
echo "Building branch $BRANCH"
fi
if [ "$BRANCH" == "" ]; then if [ "$BRANCH" == "" ]; then
echo "Unable to determine latest stable branch!" echo "Unable to determine latest stable branch!"
exit 0; exit 0;
@ -216,9 +229,14 @@ rm -rf .git
rm .gitignore rm .gitignore
cd ../ cd ../
if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then
if [ !-e "$DIRECTORY.orig.tar.gz" ]; then
read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]"
if [[ $REPLY == [yY] ]]; then
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
fi; fi;
fi;
IFS=',' ;for DISTRO in `echo "$DISTROS"`; do IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
echo "Generating package for $DISTRO"; echo "Generating package for $DISTRO";
@ -229,7 +247,7 @@ IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
fi; fi;
# Generate Changlog # Generate Changlog
if [ "$DISTRO" == "focal" ] || [ "$DISTRO" == "buster" ] || [ "$DISTRO" == "hirsute" ]; then if [ "$DISTRO" == "focal" ] || [ "$DISTRO" == "buster" ] || [ "$DISTRO" == "hirsute" ] || [ "$DISTRO" == "impish" ]; then
cp -Rpd distros/ubuntu2004 debian cp -Rpd distros/ubuntu2004 debian
elif [ "$DISTRO" == "beowulf" ] elif [ "$DISTRO" == "beowulf" ]
then then
@ -285,30 +303,37 @@ zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
EOF EOF
fi; fi;
# Leave the .orig so that we don't pollute it when building deps
cd ..
if [ $TYPE == "binary" ]; then if [ $TYPE == "binary" ]; then
# Auto-install all ZoneMinder's depedencies using the Debian control file # Auto-install all ZoneMinder's depedencies using the Debian control file
sudo apt-get install devscripts equivs sudo apt-get install devscripts equivs
sudo mk-build-deps -ir ./debian/control sudo mk-build-deps -ir $DIRECTORY.orig/debian/control
echo "Status: $?" echo "Status: $?"
DEBUILD=debuild DEBUILD=debuild
else else
if [ $TYPE == "local" ]; then if [ $TYPE == "local" ]; then
# Auto-install all ZoneMinder's depedencies using the Debian control file # Auto-install all ZoneMinder's depedencies using the Debian control file
sudo apt-get install devscripts equivs sudo apt-get install devscripts equivs
sudo mk-build-deps -ir ./debian/control sudo mk-build-deps -ir $DIRECTORY.orig/debian/control
echo "Status: $?" echo "Status: $?"
DEBUILD="debuild -i -us -uc -b" DEBUILD="debuild -i -us -uc -b"
else else
# Source build, don't need build depends. # Source build, don't need build depends.
DEBUILD="debuild -S -sa" DEBUILD="debuild -S -sa"
fi; fi;
fi; fi;
cd $DIRECTORY.orig
if [ "$DEBSIGN_KEYID" != "" ]; then if [ "$DEBSIGN_KEYID" != "" ]; then
DEBUILD="$DEBUILD -k$DEBSIGN_KEYID" DEBUILD="$DEBUILD -k$DEBSIGN_KEYID"
fi fi
# Add any extra options specified on the CLI
DEBUILD="$DEBUILD $DEBBUILD_EXTRA"
eval $DEBUILD eval $DEBUILD
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Error status code is: $?" echo "Error status code is: $?"
echo "Build failed."; echo "Build failed.";
exit $?; exit $?;
fi; fi;
@ -340,12 +365,14 @@ EOF
dput="Y"; dput="Y";
if [ "$INTERACTIVE" != "no" ]; then if [ "$INTERACTIVE" != "no" ]; then
read -p "Ready to dput $SC to $PPA ? Y/n..."; read -p "Ready to dput $SC to $PPA ? Y/n...";
if [[ "$REPLY" == [yY] ]]; then if [[ "$REPLY" == "" || "$REPLY" == [yY] ]]; then
dput $PPA $SC dput $PPA $SC
fi; fi;
else else
echo "dputting to $PPA"; if [ "$DPUT" != "no" ]; then
dput $PPA $SC echo "dputting to $PPA";
dput $PPA $SC
fi;
fi; fi;
fi; fi;
done; # foreach distro done; # foreach distro

View File

@ -223,7 +223,7 @@ setdebpkgname () {
if [ "" == "$VERSION" ]; then if [ "" == "$VERSION" ]; then
export VERSION="${versionfile}~${thedate}.${numcommits}" export VERSION="${versionfile}~${thedate}.${numcommits}"
fi fi
export RELEASE="${DIST}" export RELEASE="${DIST}${PACKAGE_VERSION}"
checkvars checkvars
@ -369,7 +369,7 @@ elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ] || [ "${OS}" == "raspbia
setdebpkgname setdebpkgname
movecrud movecrud
if [ "${DIST}" == "focal" ] || [ "${DIST}" == "groovy" ] || [ "${DIST}" == "hirsuit" ] || [ "${DIST}" == "buster" ]; then if [ "${DIST}" == "bionic" ] || [ "${DIST}" == "focal" ] || [ "${DIST}" == "hirsute" ] || [ "${DIST}" == "impish" ] || [ "${DIST}" == "buster" ] || [ "${DIST}" == "bullseye" ]; then
ln -sfT distros/ubuntu2004 debian ln -sfT distros/ubuntu2004 debian
elif [ "${DIST}" == "beowulf" ]; then elif [ "${DIST}" == "beowulf" ]; then
ln -sfT distros/beowulf debian ln -sfT distros/beowulf debian

View File

@ -1 +1 @@
1.36.5 1.36.9

View File

@ -5,7 +5,7 @@ if ( empty($_REQUEST['id']) && empty($_REQUEST['eids']) ) {
ajaxError('No event id(s) supplied'); ajaxError('No event id(s) supplied');
} }
if ( canView('Events') ) { if ( canView('Events') or canView('Snapshots') ) {
switch ( $_REQUEST['action'] ) { switch ( $_REQUEST['action'] ) {
case 'video' : case 'video' :
if ( empty($_REQUEST['videoFormat']) ) { if ( empty($_REQUEST['videoFormat']) ) {
@ -74,10 +74,15 @@ if ( canView('Events') ) {
else else
$exportCompress = false; $exportCompress = false;
if ( !empty($_REQUEST['exportStructure']) )
$exportStructure = $_SESSION['export']['structure'] = $_REQUEST['exportStructure'];
else
$exportStructure = false;
session_write_close(); session_write_close();
$exportIds = !empty($_REQUEST['eids']) ? $_REQUEST['eids'] : $_REQUEST['id']; $exportIds = !empty($_REQUEST['eids']) ? $_REQUEST['eids'] : $_REQUEST['id'];
if ( $exportFile = exportEvents( if ($exportFile = exportEvents(
$exportIds, $exportIds,
(isset($_REQUEST['connkey'])?$_REQUEST['connkey']:''), (isset($_REQUEST['connkey'])?$_REQUEST['connkey']:''),
$exportDetail, $exportDetail,
@ -86,11 +91,14 @@ if ( canView('Events') ) {
$exportVideo, $exportVideo,
$exportMisc, $exportMisc,
$exportFormat, $exportFormat,
$exportCompress $exportCompress,
) ) $exportStructure,
ajaxResponse(array('exportFile'=>$exportFile)); (!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport'),
else )) {
ajaxResponse(array('exportFile'=>$exportFile));
} else {
ajaxError('Export Failed'); ajaxError('Export Failed');
}
break; break;
case 'download' : case 'download' :
require_once(ZM_SKIN_PATH.'/includes/export_functions.php'); require_once(ZM_SKIN_PATH.'/includes/export_functions.php');
@ -104,7 +112,7 @@ if ( canView('Events') ) {
false,#detail false,#detail
false,#frames false,#frames
false,#images false,#images
$exportVideo, true, #$exportVideo,
false,#Misc false,#Misc
$exportFormat, $exportFormat,
false#,#Compress false#,#Compress

View File

@ -8,21 +8,23 @@ $data = array();
// INITIALIZE AND CHECK SANITY // INITIALIZE AND CHECK SANITY
// //
if ( !canView('Snapshots') ) $message = 'Insufficient permissions for user '.$user['Username']; if (!canView('Snapshots'))
$message = 'Insufficient permissions for user '.$user['Username'];
if ( empty($_REQUEST['task']) ) { $task = '';
if (empty($_REQUEST['task'])) {
$message = 'Must specify a task'; $message = 'Must specify a task';
} else { } else {
$task = $_REQUEST['task']; $task = $_REQUEST['task'];
} }
if ( empty($_REQUEST['ids']) ) { if (empty($_REQUEST['ids'])) {
if ( isset($_REQUEST['task']) && $_REQUEST['task'] != 'query' ) $message = 'No snapshot id(s) supplied'; if ($task != 'query') $message = 'No snapshot id(s) supplied';
} else { } else {
$eids = $_REQUEST['ids']; $ids = $_REQUEST['ids'];
} }
if ( $message ) { if ($message) {
ajaxError($message); ajaxError($message);
return; return;
} }
@ -36,15 +38,15 @@ $advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'],
// Sort specifies the name of the column to sort on // Sort specifies the name of the column to sort on
$sort = 'Id'; $sort = 'Id';
if ( isset($_REQUEST['sort']) ) { if (isset($_REQUEST['sort'])) {
$sort = $_REQUEST['sort']; $sort = $_REQUEST['sort'];
} }
// Offset specifies the starting row to return, used for pagination // Offset specifies the starting row to return, used for pagination
$offset = 0; $offset = 0;
if ( isset($_REQUEST['offset']) ) { if (isset($_REQUEST['offset'])) {
if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { if ((!is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']))) {
ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); ZM\Error('Invalid value for offset: '.$_REQUEST['offset']);
} else { } else {
$offset = $_REQUEST['offset']; $offset = $_REQUEST['offset'];
} }
@ -56,8 +58,8 @@ $order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc'
// Limit specifies the number of rows to return // Limit specifies the number of rows to return
// Set the default to 0 for events view, to prevent an issue with ALL pagination // Set the default to 0 for events view, to prevent an issue with ALL pagination
$limit = 0; $limit = 0;
if ( isset($_REQUEST['limit']) ) { if (isset($_REQUEST['limit'])) {
if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { if ((!is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']))) {
ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']);
} else { } else {
$limit = $_REQUEST['limit']; $limit = $_REQUEST['limit'];
@ -68,14 +70,14 @@ if ( isset($_REQUEST['limit']) ) {
// MAIN LOOP // MAIN LOOP
// //
switch ( $task ) { switch ($task) {
case 'delete' : case 'delete' :
if ( !canEdit('Snapshots') ) { if (!canEdit('Snapshots')) {
ajaxError('Insufficient permissions for user '.$user['Username']); ajaxError('Insufficient permissions for user '.$user['Username']);
return; return;
} }
foreach ( $ids as $id ) $data[] = deleteRequest($id); foreach ($ids as $id) $data[] = deleteRequest($id);
break; break;
case 'query' : case 'query' :
$data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit); $data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit);
@ -99,6 +101,7 @@ function deleteRequest($id) {
//$message[] = array($id=>'Event is archived, cannot delete it.'); //$message[] = array($id=>'Event is archived, cannot delete it.');
} else { } else {
$snapshot->delete(); $snapshot->delete();
$message[] = array($id=>'Snapshot deleted.');
} }
return $message; return $message;

View File

@ -266,7 +266,7 @@ class MonitorsController extends AppController {
if ($mToken) { if ($mToken) {
$auth = ' -T '.$mToken; $auth = ' -T '.$mToken;
} else if (ZM_AUTH_RELAY == 'hashed') { } else if (ZM_AUTH_RELAY == 'hashed') {
$auth = ' -A '.calculateAuthHash(ZM_AUTH_HASH_IPS?$_SERVER['REMOTE_ADDR']:''); $auth = ' -A '.calculateAuthHash(''); # Can't do REMOTE_IP because zmu doesn't normally have access to it.
} else if (ZM_AUTH_RELAY == 'plain') { } else if (ZM_AUTH_RELAY == 'plain') {
# Plain requires the plain text password which must either be in request or stored in session # Plain requires the plain text password which must either be in request or stored in session
$password = $this->request->query('pass') ? $this->request->query('pass') : $this->request->data('pass');; $password = $this->request->query('pass') ? $this->request->query('pass') : $this->request->data('pass');;

View File

@ -627,6 +627,29 @@ class Event extends ZM_Object {
return 'Unknown reason'; return 'Unknown reason';
} }
function canView($u=null) {
global $user;
if (!$u) $u=$user;
if (!$u) {
# auth turned on and not logged in
return false;
}
if (!empty($u['MonitorIds']) ) {
if (in_array($this->{'MonitorId'}, explode(',', $u['MonitorIds']))) {
return true;
}
return false;
}
if ($u['Events'] != 'None') {
return true;
}
if ($u['Snapshots'] != 'None') {
# If the event is contained in a snapshot, then we can still view it.
if (dbFetchOne('SELECT * FROM Snapshot_Events WHERE EventId=?', $this->Id()))
return true;
}
return false;
}
} # end class } # end class
?> ?>

View File

@ -10,7 +10,7 @@ require_once('Group.php');
$FunctionTypes = null; $FunctionTypes = null;
function getMonitorFunctionTypes() { function getMonitorFunctionTypes() {
if ( !isset($FunctionTypes ) ) { if (!isset($FunctionTypes)) {
$FunctionTypes = array( $FunctionTypes = array(
'None' => translate('FnNone'), 'None' => translate('FnNone'),
'Monitor' => translate('FnMonitor'), 'Monitor' => translate('FnMonitor'),
@ -23,6 +23,21 @@ function getMonitorFunctionTypes() {
return $FunctionTypes; return $FunctionTypes;
} }
$Statuses = null;
function getMonitorStatuses() {
if (!isset($Statuses)) {
$Statuses = array(
-1 => 'Unknown',
0 => 'Idle',
1 => 'PreAlarm',
2 => 'Alarm',
3 => 'Alert',
4 => 'Tape'
);
}
return $Statuses;
}
class Monitor extends ZM_Object { class Monitor extends ZM_Object {
protected static $table = 'Monitors'; protected static $table = 'Monitors';
@ -126,6 +141,7 @@ class Monitor extends ZM_Object {
'Longitude' => null, 'Longitude' => null,
'RTSPServer' => array('type'=>'boolean', 'default'=>0), 'RTSPServer' => array('type'=>'boolean', 'default'=>0),
'RTSPStreamName' => '', 'RTSPStreamName' => '',
'Importance' => 'Normal',
); );
private $status_fields = array( private $status_fields = array(
'Status' => null, 'Status' => null,
@ -149,46 +165,46 @@ class Monitor extends ZM_Object {
); );
public function Control() { public function Control() {
if ( !property_exists($this, 'Control') ) { if (!property_exists($this, 'Control')) {
if ( $this->ControlId() ) if ($this->ControlId())
$this->{'Control'} = Control::find_one(array('Id'=>$this->{'ControlId'})); $this->{'Control'} = Control::find_one(array('Id'=>$this->{'ControlId'}));
if ( !(property_exists($this, 'Control') and $this->{'Control'}) ) if (!(property_exists($this, 'Control') and $this->{'Control'}))
$this->{'Control'} = new Control(); $this->{'Control'} = new Control();
} }
return $this->{'Control'}; return $this->{'Control'};
} }
public function Server() { public function Server() {
if ( !property_exists($this, 'Server') ) { if (!property_exists($this, 'Server')) {
if ( $this->ServerId() ) if ($this->ServerId())
$this->{'Server'} = Server::find_one(array('Id'=>$this->{'ServerId'})); $this->{'Server'} = Server::find_one(array('Id'=>$this->{'ServerId'}));
if ( !property_exists($this, 'Server') ) { if (!property_exists($this, 'Server')) {
$this->{'Server'} = new Server(); $this->{'Server'} = new Server();
} }
} }
return $this->{'Server'}; return $this->{'Server'};
} }
public function __call($fn, array $args){ public function __call($fn, array $args) {
if ( count($args) ) { if (count($args)) {
if ( is_array($this->defaults[$fn]) and $this->defaults[$fn]['type'] == 'set' ) { if (is_array($this->defaults[$fn]) and $this->defaults[$fn]['type'] == 'set') {
$this->{$fn} = is_array($args[0]) ? implode(',', $args[0]) : $args[0]; $this->{$fn} = is_array($args[0]) ? implode(',', $args[0]) : $args[0];
} else { } else {
$this->{$fn} = $args[0]; $this->{$fn} = $args[0];
} }
} }
if ( property_exists($this, $fn) ) { if (property_exists($this, $fn)) {
return $this->{$fn}; return $this->{$fn};
} else if ( array_key_exists($fn, $this->defaults) ) { } else if (array_key_exists($fn, $this->defaults)) {
if ( is_array($this->defaults[$fn]) ) { if ( is_array($this->defaults[$fn]) ) {
return $this->defaults[$fn]['default']; return $this->defaults[$fn]['default'];
} }
return $this->defaults[$fn]; return $this->defaults[$fn];
} else if ( array_key_exists($fn, $this->status_fields) ) { } else if (array_key_exists($fn, $this->status_fields)) {
$sql = 'SELECT * FROM `Monitor_Status` WHERE `MonitorId`=?'; $sql = 'SELECT * FROM `Monitor_Status` WHERE `MonitorId`=?';
$row = dbFetchOne($sql, NULL, array($this->{'Id'})); $row = dbFetchOne($sql, NULL, array($this->{'Id'}));
if ( !$row ) { if (!$row) {
Warning('Unable to load Monitor status record for Id='.$this->{'Id'}.' using '.$sql); Warning('Unable to load Monitor status record for Id='.$this->{'Id'}.' using '.$sql);
return null; return null;
} else { } else {
@ -197,10 +213,10 @@ class Monitor extends ZM_Object {
} }
} }
return $this->{$fn}; return $this->{$fn};
} else if ( array_key_exists($fn, $this->summary_fields) ) { } else if (array_key_exists($fn, $this->summary_fields)) {
$sql = 'SELECT * FROM `Event_Summaries` WHERE `MonitorId`=?'; $sql = 'SELECT * FROM `Event_Summaries` WHERE `MonitorId`=?';
$row = dbFetchOne($sql, NULL, array($this->{'Id'})); $row = dbFetchOne($sql, NULL, array($this->{'Id'}));
if ( !$row ) { if (!$row) {
Warning('Unable to load Event Summary record for Id='.$this->{'Id'}.' using '.$sql); Warning('Unable to load Event Summary record for Id='.$this->{'Id'}.' using '.$sql);
return null; return null;
} else { } else {
@ -218,7 +234,6 @@ class Monitor extends ZM_Object {
} }
public function getStreamSrc($args, $querySep='&amp;') { public function getStreamSrc($args, $querySep='&amp;') {
$streamSrc = $this->Server()->UrlToZMS( $streamSrc = $this->Server()->UrlToZMS(
ZM_MIN_STREAMING_PORT ? ZM_MIN_STREAMING_PORT ?
ZM_MIN_STREAMING_PORT+$this->{'Id'} : ZM_MIN_STREAMING_PORT+$this->{'Id'} :
@ -226,8 +241,8 @@ class Monitor extends ZM_Object {
$args['monitor'] = $this->{'Id'}; $args['monitor'] = $this->{'Id'};
if ( ZM_OPT_USE_AUTH ) { if (ZM_OPT_USE_AUTH) {
if ( ZM_AUTH_RELAY == 'hashed' ) { if (ZM_AUTH_RELAY == 'hashed') {
$args['auth'] = generateAuthHash(ZM_AUTH_HASH_IPS); $args['auth'] = generateAuthHash(ZM_AUTH_HASH_IPS);
} elseif ( ZM_AUTH_RELAY == 'plain' ) { } elseif ( ZM_AUTH_RELAY == 'plain' ) {
$args['user'] = $_SESSION['username']; $args['user'] = $_SESSION['username'];
@ -236,24 +251,24 @@ class Monitor extends ZM_Object {
$args['user'] = $_SESSION['username']; $args['user'] = $_SESSION['username'];
} }
} }
if ( (!isset($args['mode'])) or ( $args['mode'] != 'single' ) ) { if ((!isset($args['mode'])) or ($args['mode'] != 'single')) {
$args['connkey'] = $this->connKey(); $args['connkey'] = $this->connKey();
} }
if ( ZM_RAND_STREAM ) { if (ZM_RAND_STREAM) {
$args['rand'] = time(); $args['rand'] = time();
} }
# zms doesn't support width & height, so if no scale is set, default it # zms doesn't support width & height, so if no scale is set, default it
if ( ! isset($args['scale']) ) { if (!isset($args['scale'])) {
if ( isset($args['width']) and intval($args['width']) ) { if (isset($args['width']) and intval($args['width'])) {
$args['scale'] = intval((100*intval($args['width']))/$this->ViewWidth()); $args['scale'] = intval((100*intval($args['width']))/$this->ViewWidth());
} else if ( isset($args['height']) and intval($args['height']) ) { } else if (isset($args['height']) and intval($args['height'])) {
$args['scale'] = intval((100*intval($args['height']))/$this->ViewHeight()); $args['scale'] = intval((100*intval($args['height']))/$this->ViewHeight());
} }
} }
if ( isset($args['width']) ) if (isset($args['width']))
unset($args['width']); unset($args['width']);
if ( isset($args['height']) ) if (isset($args['height']))
unset($args['height']); unset($args['height']);
$streamSrc .= '?'.http_build_query($args, '', $querySep); $streamSrc .= '?'.http_build_query($args, '', $querySep);
@ -269,21 +284,21 @@ class Monitor extends ZM_Object {
} }
public function ViewWidth($new = null) { public function ViewWidth($new = null) {
if ( $new ) if ($new)
$this->{'Width'} = $new; $this->{'Width'} = $new;
$field = ( $this->Orientation() == 'ROTATE_90' or $this->Orientation() == 'ROTATE_270' ) ? 'Height' : 'Width'; $field = ( $this->Orientation() == 'ROTATE_90' or $this->Orientation() == 'ROTATE_270' ) ? 'Height' : 'Width';
if ( property_exists($this, $field) ) if (property_exists($this, $field))
return $this->{$field}; return $this->{$field};
return $this->defaults[$field]; return $this->defaults[$field];
} // end function Width } // end function Width
public function ViewHeight($new=null) { public function ViewHeight($new=null) {
if ( $new ) if ($new)
$this->{'Height'} = $new; $this->{'Height'} = $new;
$field = ( $this->Orientation() == 'ROTATE_90' or $this->Orientation() == 'ROTATE_270' ) ? 'Width' : 'Height'; $field = ( $this->Orientation() == 'ROTATE_90' or $this->Orientation() == 'ROTATE_270' ) ? 'Width' : 'Height';
if ( property_exists($this, $field) ) if (property_exists($this, $field))
return $this->{$field}; return $this->{$field};
return $this->defaults[$field]; return $this->defaults[$field];
} // end function Height } // end function Height
@ -296,50 +311,50 @@ class Monitor extends ZM_Object {
// Validate that it's a valid colour (we seem to allow color names, not just hex). // Validate that it's a valid colour (we seem to allow color names, not just hex).
// This also helps prevent XSS. // This also helps prevent XSS.
if ( property_exists($this, $field) && preg_match('/^[#0-9a-zA-Z]+$/', $this->{$field})) { if (property_exists($this, $field) && preg_match('/^[#0-9a-zA-Z]+$/', $this->{$field})) {
return $this->{$field}; return $this->{$field};
} }
return $this->defaults[$field]; return $this->defaults[$field];
} // end function SignalCheckColour } // end function SignalCheckColour
public static function find( $parameters = array(), $options = array() ) { public static function find($parameters = array(), $options = array()) {
return ZM_Object::_find(get_class(), $parameters, $options); return ZM_Object::_find(get_class(), $parameters, $options);
} }
public static function find_one( $parameters = array(), $options = array() ) { public static function find_one($parameters = array(), $options = array()) {
return ZM_Object::_find_one(get_class(), $parameters, $options); return ZM_Object::_find_one(get_class(), $parameters, $options);
} }
function zmcControl( $mode=false ) { function zmcControl($mode=false) {
if ( !(property_exists($this,'Id') and $this->{'Id'}) ) { if (!(property_exists($this,'Id') and $this->{'Id'})) {
Warning('Attempt to control a monitor with no Id'); Warning('Attempt to control a monitor with no Id');
return; return;
} }
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { if ((!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) )) {
if ( $this->Type() == 'Local' ) { if ($this->Type() == 'Local') {
$zmcArgs = '-d '.$this->{'Device'}; $zmcArgs = '-d '.$this->{'Device'};
} else { } else {
$zmcArgs = '-m '.$this->{'Id'}; $zmcArgs = '-m '.$this->{'Id'};
} }
if ( $mode == 'stop' ) { if ($mode == 'stop') {
daemonControl('stop', 'zmc', $zmcArgs); daemonControl('stop', 'zmc', $zmcArgs);
} else { } else {
if ( $mode == 'restart' ) { if ($mode == 'restart') {
daemonControl('stop', 'zmc', $zmcArgs); daemonControl('stop', 'zmc', $zmcArgs);
} }
if ( $this->{'Function'} != 'None' ) { if ($this->{'Function'} != 'None') {
daemonControl('start', 'zmc', $zmcArgs); daemonControl('start', 'zmc', $zmcArgs);
} }
} }
} else if ( $this->ServerId() ) { } else if ($this->ServerId()) {
$Server = $this->Server(); $Server = $this->Server();
$url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zmc.json'; $url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zmc.json';
if ( ZM_OPT_USE_AUTH ) { if (ZM_OPT_USE_AUTH) {
if ( ZM_AUTH_RELAY == 'hashed' ) { if (ZM_AUTH_RELAY == 'hashed') {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS); $url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
} else if ( ZM_AUTH_RELAY == 'plain' ) { } else if (ZM_AUTH_RELAY == 'plain') {
$url .= '?user='.$_SESSION['username']; $url .= '?user='.$_SESSION['username'];
$url .= '?pass='.$_SESSION['password']; $url .= '?pass='.$_SESSION['password'];
} else { } else {
@ -349,13 +364,13 @@ class Monitor extends ZM_Object {
} }
Debug('sending command to '.$url); Debug('sending command to '.$url);
$context = stream_context_create(); $context = stream_context_create();
try { try {
$result = file_get_contents($url, false, $context); $result = file_get_contents($url, false, $context);
if ( $result === FALSE ) { /* Handle error */ if ($result === FALSE) { /* Handle error */
Error("Error restarting zmc using $url"); Error("Error restarting zmc using $url");
} }
} catch ( Exception $e ) { } catch (Exception $e) {
Error("Except $e thrown trying to restart zmc"); Error("Except $e thrown trying to restart zmc");
} }
} else { } else {
@ -363,19 +378,19 @@ class Monitor extends ZM_Object {
} }
} // end function zmcControl } // end function zmcControl
public function GroupIds( $new='' ) { public function GroupIds($new='') {
if ( $new != '' ) { if ($new != '') {
if ( !is_array($new) ) { if (!is_array($new)) {
$this->{'GroupIds'} = array($new); $this->{'GroupIds'} = array($new);
} else { } else {
$this->{'GroupIds'} = $new; $this->{'GroupIds'} = $new;
} }
} }
if ( !property_exists($this, 'GroupIds') ) { if (!property_exists($this, 'GroupIds')) {
if ( property_exists($this, 'Id') and $this->{'Id'} ) { if (property_exists($this, 'Id') and $this->{'Id'}) {
$this->{'GroupIds'} = dbFetchAll('SELECT `GroupId` FROM `Groups_Monitors` WHERE `MonitorId`=?', 'GroupId', array($this->{'Id'}) ); $this->{'GroupIds'} = dbFetchAll('SELECT `GroupId` FROM `Groups_Monitors` WHERE `MonitorId`=?', 'GroupId', array($this->{'Id'}));
if ( ! $this->{'GroupIds'} ) if (!$this->{'GroupIds'})
$this->{'GroupIds'} = array(); $this->{'GroupIds'} = array();
} else { } else {
$this->{'GroupIds'} = array(); $this->{'GroupIds'} = array();
@ -385,8 +400,8 @@ class Monitor extends ZM_Object {
} }
public function delete() { public function delete() {
if ( ! $this->{'Id'} ) { if (!$this->{'Id'}) {
Warning("Attempt to delete a monitor without id."); Warning('Attempt to delete a monitor without id.');
return; return;
} }
$this->zmcControl('stop'); $this->zmcControl('stop');
@ -394,17 +409,17 @@ class Monitor extends ZM_Object {
// If fast deletes are on, then zmaudit will clean everything else up later // If fast deletes are on, then zmaudit will clean everything else up later
// If fast deletes are off and there are lots of events then this step may // If fast deletes are off and there are lots of events then this step may
// well time out before completing, in which case zmaudit will still tidy up // well time out before completing, in which case zmaudit will still tidy up
if ( !ZM_OPT_FAST_DELETE ) { if (!ZM_OPT_FAST_DELETE) {
$markEids = dbFetchAll('SELECT Id FROM Events WHERE MonitorId=?', 'Id', array($this->{'Id'})); $markEids = dbFetchAll('SELECT Id FROM Events WHERE MonitorId=?', 'Id', array($this->{'Id'}));
foreach ($markEids as $markEid) foreach ($markEids as $markEid)
deleteEvent($markEid); deleteEvent($markEid);
if ( $this->{'Name'} ) if ($this->{'Name'})
deletePath(ZM_DIR_EVENTS.'/'.basename($this->{'Name'})); deletePath(ZM_DIR_EVENTS.'/'.basename($this->{'Name'}));
deletePath(ZM_DIR_EVENTS.'/'.$this->{'Id'}); deletePath(ZM_DIR_EVENTS.'/'.$this->{'Id'});
$Storage = $this->Storage(); $Storage = $this->Storage();
if ( $Storage->Path() != ZM_DIR_EVENTS ) { if ($Storage->Path() != ZM_DIR_EVENTS) {
if ( $this->{'Name'} ) if ($this->{'Name'})
deletePath($Storage->Path().'/'.basename($this->{'Name'})); deletePath($Storage->Path().'/'.basename($this->{'Name'}));
deletePath($Storage->Path().'/'.$this->{'Id'}); deletePath($Storage->Path().'/'.$this->{'Id'});
} }
@ -420,14 +435,14 @@ class Monitor extends ZM_Object {
} // end function delete } // end function delete
public function Storage($new = null) { public function Storage($new = null) {
if ( $new ) { if ($new) {
$this->{'Storage'} = $new; $this->{'Storage'} = $new;
} }
if ( ! ( property_exists($this, 'Storage') and $this->{'Storage'} ) ) { if (!(property_exists($this, 'Storage') and $this->{'Storage'})) {
$this->{'Storage'} = isset($this->{'StorageId'}) ? $this->{'Storage'} = isset($this->{'StorageId'}) ?
Storage::find_one(array('Id'=>$this->{'StorageId'})) : Storage::find_one(array('Id'=>$this->{'StorageId'})) :
new Storage(NULL); new Storage(NULL);
if ( ! $this->{'Storage'} ) if (!$this->{'Storage'})
$this->{'Storage'} = new Storage(NULL); $this->{'Storage'} = new Storage(NULL);
} }
return $this->{'Storage'}; return $this->{'Storage'};
@ -435,42 +450,42 @@ class Monitor extends ZM_Object {
public function Source( ) { public function Source( ) {
$source = ''; $source = '';
if ( $this->{'Type'} == 'Local' ) { if ($this->{'Type'} == 'Local') {
$source = $this->{'Device'}.' ('.$this->{'Channel'}.')'; $source = $this->{'Device'}.' ('.$this->{'Channel'}.')';
} else if ( $this->{'Type'} == 'Remote' ) { } else if ($this->{'Type'} == 'Remote') {
$source = preg_replace( '/^.*@/', '', $this->{'Host'} ); $source = preg_replace('/^.*@/', '', $this->{'Host'});
if ( $this->{'Port'} != '80' and $this->{'Port'} != '554' ) { if ($this->{'Port'} != '80' and $this->{'Port'} != '554') {
$source .= ':'.$this->{'Port'}; $source .= ':'.$this->{'Port'};
} }
} else if ( $this->{'Type'} == 'VNC' ) { } else if ($this->{'Type'} == 'VNC') {
$source = preg_replace( '/^.*@/', '', $this->{'Host'} ); $source = preg_replace( '/^.*@/', '', $this->{'Host'} );
if ( $this->{'Port'} != '5900' ) { if ($this->{'Port'} != '5900') {
$source .= ':'.$this->{'Port'}; $source .= ':'.$this->{'Port'};
} }
} else if ( $this->{'Type'} == 'Ffmpeg' || $this->{'Type'} == 'Libvlc' || $this->{'Type'} == 'WebSite' ) { } else if ($this->{'Type'} == 'Ffmpeg' || $this->{'Type'} == 'Libvlc' || $this->{'Type'} == 'WebSite') {
$url_parts = parse_url( $this->{'Path'} ); $url_parts = parse_url($this->{'Path'});
if ( ZM_WEB_FILTER_SOURCE == 'Hostname' ) { if (ZM_WEB_FILTER_SOURCE == 'Hostname') {
# Filter out everything but the hostname # Filter out everything but the hostname
if ( isset($url_parts['host']) ) { if (isset($url_parts['host'])) {
$source = $url_parts['host']; $source = $url_parts['host'];
} else { } else {
$source = $this->{'Path'}; $source = $this->{'Path'};
} }
} else if ( ZM_WEB_FILTER_SOURCE == 'NoCredentials' ) { } else if (ZM_WEB_FILTER_SOURCE == 'NoCredentials') {
# Filter out sensitive and common items # Filter out sensitive and common items
unset($url_parts['user']); unset($url_parts['user']);
unset($url_parts['pass']); unset($url_parts['pass']);
#unset($url_parts['scheme']); #unset($url_parts['scheme']);
unset($url_parts['query']); unset($url_parts['query']);
#unset($url_parts['path']); #unset($url_parts['path']);
if ( isset($url_parts['port']) and ( $url_parts['port'] == '80' or $url_parts['port'] == '554' ) ) if (isset($url_parts['port']) and ($url_parts['port'] == '80' or $url_parts['port'] == '554'))
unset($url_parts['port']); unset($url_parts['port']);
$source = unparse_url($url_parts); $source = unparse_url($url_parts);
} else { # Don't filter anything } else { # Don't filter anything
$source = $this->{'Path'}; $source = $this->{'Path'};
} }
} }
if ( $source == '' ) { if ($source == '') {
$source = 'Monitor ' . $this->{'Id'}; $source = 'Monitor ' . $this->{'Id'};
} }
return $source; return $source;
@ -478,7 +493,6 @@ class Monitor extends ZM_Object {
public function UrlToIndex($port=null) { public function UrlToIndex($port=null) {
return $this->Server()->UrlToIndex($port); return $this->Server()->UrlToIndex($port);
//ZM_MIN_STREAMING_PORT ? (ZM_MIN_STREAMING_PORT+$this->Id()) : null);
} }
public function sendControlCommand($command) { public function sendControlCommand($command) {
@ -486,78 +500,78 @@ class Monitor extends ZM_Object {
$options = array(); $options = array();
# Convert from a command line params to an option array # Convert from a command line params to an option array
foreach ( explode(' ', $command) as $option ) { foreach (explode(' ', $command) as $option) {
if ( preg_match('/--([^=]+)(?:=(.+))?/', $option, $matches) ) { if (preg_match('/--([^=]+)(?:=(.+))?/', $option, $matches)) {
$options[$matches[1]] = $matches[2]?$matches[2]:1; $options[$matches[1]] = $matches[2]?$matches[2]:1;
} else if ( $option != '' and $option != 'quit' and $option != 'start' and $option != 'stop' ) { } else if ($option != '' and $option != 'quit' and $option != 'start' and $option != 'stop') {
Warning("Ignored command for zmcontrol $option in $command"); Warning("Ignored command for zmcontrol $option in $command");
} }
} }
if ( !count($options) ) { if (!count($options)) {
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) { if ($command == 'quit' or $command == 'start' or $command == 'stop') {
# These are special as we now run zmcontrol as a daemon through zmdc. # These are special as we now run zmcontrol as a daemon through zmdc.
$status = daemonStatus('zmcontrol.pl', array('--id', $this->{'Id'})); $status = daemonStatus('zmcontrol.pl', array('--id', $this->{'Id'}));
Debug("Current status $status"); Debug("Current status $status");
if ( $status or ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) ) { if ($status or ((!defined('ZM_SERVER_ID')) or (property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'})))) {
daemonControl($command, 'zmcontrol.pl', '--id '.$this->{'Id'}); daemonControl($command, 'zmcontrol.pl', '--id '.$this->{'Id'});
return; return;
} }
$options['command'] = $command; $options['command'] = $command;
} else { } else {
Warning("No commands to send to zmcontrol from $command"); Warning('No commands to send to zmcontrol from '.$command);
return false; return false;
} }
} }
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { if ((!defined('ZM_SERVER_ID')) or (property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}))) {
# Local # Local
Debug('Trying to send options ' . print_r($options, true)); Debug('Trying to send options ' . print_r($options, true));
$optionString = jsonEncode($options); $optionString = jsonEncode($options);
Debug("Trying to send options $optionString"); Debug('Trying to send options '.$optionString);
// Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command. // Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command.
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0); $socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
if ( $socket < 0 ) { if ($socket < 0) {
Error('socket_create() failed: '.socket_strerror($socket)); Error('socket_create() failed: '.socket_strerror($socket));
return false; return false;
} }
$sockFile = ZM_PATH_SOCKS.'/zmcontrol-'.$this->{'Id'}.'.sock'; $sockFile = ZM_PATH_SOCKS.'/zmcontrol-'.$this->{'Id'}.'.sock';
if ( @socket_connect($socket, $sockFile) ) { if (@socket_connect($socket, $sockFile)) {
if ( !socket_write($socket, $optionString) ) { if (!socket_write($socket, $optionString)) {
Error('Can\'t write to control socket: '.socket_strerror(socket_last_error($socket))); Error('Can\'t write to control socket: '.socket_strerror(socket_last_error($socket)));
return false; return false;
} }
} else if ( $command != 'quit' ) { } else if ($command != 'quit') {
$command = ZM_PATH_BIN.'/zmcontrol.pl '.$command.' --id '.$this->{'Id'}; $command = ZM_PATH_BIN.'/zmcontrol.pl '.$command.' --id '.$this->{'Id'};
// Can't connect so use script // Can't connect so use script
$ctrlOutput = exec(escapeshellcmd($command)); $ctrlOutput = exec(escapeshellcmd($command));
} }
socket_close($socket); socket_close($socket);
} else if ( $this->ServerId() ) { } else if ($this->ServerId()) {
$Server = $this->Server(); $Server = $this->Server();
$url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json'; $url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json';
if ( ZM_OPT_USE_AUTH ) { if (ZM_OPT_USE_AUTH) {
if ( ZM_AUTH_RELAY == 'hashed' ) { if (ZM_AUTH_RELAY == 'hashed') {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS); $url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
} else if ( ZM_AUTH_RELAY == 'plain' ) { } else if (ZM_AUTH_RELAY == 'plain') {
$url .= '?user='.$_SESSION['username']; $url .= '?user='.$_SESSION['username'];
$url .= '?pass='.$_SESSION['password']; $url .= '?pass='.$_SESSION['password'];
} else if ( ZM_AUTH_RELAY == 'none' ) { } else if (ZM_AUTH_RELAY == 'none') {
$url .= '?user='.$_SESSION['username']; $url .= '?user='.$_SESSION['username'];
} }
} }
Debug("sending command to $url"); Debug('sending command to '.$url);
$context = stream_context_create(); $context = stream_context_create();
try { try {
$result = file_get_contents($url, false, $context); $result = file_get_contents($url, false, $context);
if ( $result === FALSE ) { /* Handle error */ if ($result === FALSE) { /* Handle error */
Error("Error sending command using $url"); Error("Error sending command using $url");
return false; return false;
} }
} catch ( Exception $e ) { } catch (Exception $e) {
Error("Exception $e thrown trying to send command to $url"); Error("Exception $e thrown trying to send command to $url");
return false; return false;
} }
@ -569,18 +583,18 @@ class Monitor extends ZM_Object {
} // end function sendControlCommand($mid, $command) } // end function sendControlCommand($mid, $command)
function Groups($new='') { function Groups($new='') {
if ( $new != '' ) if ($new != '')
$this->Groups = $new; $this->Groups = $new;
if ( !property_exists($this, 'Groups') ) { if (!property_exists($this, 'Groups')) {
$this->Groups = Group::find(array('Id'=>$this->GroupIds())); $this->Groups = Group::find(array('Id'=>$this->GroupIds()));
} }
return $this->Groups; return $this->Groups;
} }
function connKey($new='') { function connKey($new='') {
if ( $new ) if ($new)
$this->connKey = $new; $this->connKey = $new;
if ( !isset($this->connKey) ) { if (!isset($this->connKey)) {
if ( !empty($GLOBALS['connkey']) ) { if (!empty($GLOBALS['connkey'])) {
$this->connKey = $GLOBALS['connkey']; $this->connKey = $GLOBALS['connkey'];
} else { } else {
$this->connKey = generateConnKey(); $this->connKey = generateConnKey();
@ -596,11 +610,21 @@ class Monitor extends ZM_Object {
function canView() { function canView() {
global $user; global $user;
return ( $user && ($user['Monitors'] != 'None') && ( !$this->{'Id'} || visibleMonitor($this->{'Id'}) )); if (!$user) {
# auth turned on and not logged in
return false;
}
if (!empty($user['MonitorIds']) ) {
# For the purposes of viewing, having specified monitors trumps the Monitor->canView setting.
if (in_array($this->{'Id'}, explode(',', $user['MonitorIds']))) {
return true;
}
}
return ($user['Monitors'] != 'None');
} }
function AlarmCommand($cmd) { function AlarmCommand($cmd) {
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) { if ((!defined('ZM_SERVER_ID')) or (property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}))) {
switch ($cmd) { switch ($cmd) {
case 'on' : $cmd = ' -a'; break; case 'on' : $cmd = ' -a'; break;
case 'off': $cmd = ' -c'; break; case 'off': $cmd = ' -c'; break;
@ -617,7 +641,7 @@ class Monitor extends ZM_Object {
return $output; return $output;
} }
if ( $this->ServerId() ) { if ($this->ServerId()) {
$Server = $this->Server(); $Server = $this->Server();
$url = $Server->UrlToApi().'/monitors/alarm/id:'.$this->{'Id'}.'/command:'.$cmd.'.json'; $url = $Server->UrlToApi().'/monitors/alarm/id:'.$this->{'Id'}.'/command:'.$cmd.'.json';
@ -629,15 +653,15 @@ class Monitor extends ZM_Object {
$context = stream_context_create(); $context = stream_context_create();
try { try {
$result = file_get_contents($url, false, $context); $result = file_get_contents($url, false, $context);
if ( $result === FALSE ) { /* Handle error */ if ($result === FALSE) { /* Handle error */
Error('Error sending command using '.$url); Error('Error sending command using '.$url);
return false; return false;
} }
Debug("Result $result"); Debug('Result '.$result);
$json = json_decode($result, true); $json = json_decode($result, true);
return $json['status']; return $json['status'];
} catch ( Exception $e ) { } catch (Exception $e) {
Error("Exception $e thrown trying to send command to $url"); Error("Exception $e thrown trying to send command to $url");
return false; return false;
} }
@ -647,10 +671,10 @@ class Monitor extends ZM_Object {
} }
function TriggerOn() { function TriggerOn() {
$output = $this->AlarmCommand('on'); $output = $this->AlarmCommand('on');
if ( $output and preg_match('/Alarmed event id: (\d+)$/', $output, $matches) ) { if ($output and preg_match('/Alarmed event id: (\d+)$/', $output, $matches)) {
return $matches[1]; return $matches[1];
} }
Warning("No event returned from TriggerOn"); Warning('No event returned from TriggerOn');
} }
function TriggerOff() { function TriggerOff() {
$output = $this->AlarmCommand('off'); $output = $this->AlarmCommand('off');

View File

@ -434,6 +434,11 @@ class ZM_Object {
$row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($this->Id())); $row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($this->Id()));
if ( !$row ) { if ( !$row ) {
Error("Unable to lock $class record for Id=".$this->Id()); Error("Unable to lock $class record for Id=".$this->Id());
} else {
// row may have been modified since initial load
foreach ($row as $k => $v) {
$this->{$k} = $v;
}
} }
} }
public function remove_from_cache() { public function remove_from_cache() {

View File

@ -30,22 +30,25 @@ class Server extends ZM_Object {
return ZM_Object::_find_one(get_class(), $parameters, $options); return ZM_Object::_find_one(get_class(), $parameters, $options);
} }
public function Hostname( $new = null ) { public function Hostname($new = null) {
if ( $new != null ) if ($new != null)
$this->{'Hostname'} = $new; $this->{'Hostname'} = $new;
if ( isset( $this->{'Hostname'}) and ( $this->{'Hostname'} != '' ) ) { if (isset( $this->{'Hostname'}) and ($this->{'Hostname'} != '')) {
return $this->{'Hostname'}; return $this->{'Hostname'};
} else if ( $this->Id() ) { } else if ( $this->Id() ) {
return $this->{'Name'}; return $this->{'Name'};
} }
# This theoretically will match ipv6 addresses as well if (isset($_SERVER['HTTP_HOST'])) {
if ( preg_match( '/^(\[[[:xdigit:]:]+\]|[^:]+)(:[[:digit:]]+)?$/', $_SERVER['HTTP_HOST'], $matches ) ) { # This theoretically will match ipv6 addresses as well
return $matches[1]; if ( preg_match( '/^(\[[[:xdigit:]:]+\]|[^:]+)(:[[:digit:]]+)?$/', $_SERVER['HTTP_HOST'], $matches ) ) {
} return $matches[1];
}
$result = explode(':', $_SERVER['HTTP_HOST']); $result = explode(':', $_SERVER['HTTP_HOST']);
return $result[0]; return $result[0];
}
return '';
} }
public function Protocol( $new = null ) { public function Protocol( $new = null ) {

View File

@ -29,6 +29,7 @@ class Snapshot extends ZM_Object {
public function delete() { public function delete() {
if ( property_exists($this, 'Id') ) { if ( property_exists($this, 'Id') ) {
dbQuery('DELETE FROM `Snapshot_Events` WHERE `SnapshotId`=?', array($this->{'Id'})); dbQuery('DELETE FROM `Snapshot_Events` WHERE `SnapshotId`=?', array($this->{'Id'}));
dbQuery('DELETE FROM `Snapshots` WHERE `Id`=?', array($this->{'Id'}));
} }
} }

View File

@ -20,40 +20,39 @@
global $error_message; global $error_message;
// Event scope actions, view permissions only required // Event scope actions, view permissions only required
if ( !canView('Events') ) { if (!canView('Events')) {
$error_message = 'You do not have permission to view Events.'; $error_message = 'You do not have permission to view Events.';
ZM\Warning($error_message); ZM\Warning($error_message);
return; return;
} }
if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { if (isset($_REQUEST['object']) and ($_REQUEST['object'] == 'filter')) {
if ( $action == 'addterm' ) { if ($action == 'addterm') {
$_REQUEST['filter'] = addFilterTerm($_REQUEST['filter'], $_REQUEST['line']); $_REQUEST['filter'] = addFilterTerm($_REQUEST['filter'], $_REQUEST['line']);
} elseif ( $action == 'delterm' ) { } else if ($action == 'delterm') {
$_REQUEST['filter'] = delFilterTerm($_REQUEST['filter'], $_REQUEST['line']); $_REQUEST['filter'] = delFilterTerm($_REQUEST['filter'], $_REQUEST['line']);
} else if ( canEdit('Events') ) { } else if (canEdit('Events')) {
require_once('includes/Filter.php'); require_once('includes/Filter.php');
$filter = new ZM\Filter($_REQUEST['Id']); $filter = new ZM\Filter($_REQUEST['Id']);
if ( $action == 'delete' ) { if ($action == 'delete') {
if ( !empty($_REQUEST['Id']) ) { if (!empty($_REQUEST['Id'])) {
if ( $filter->Background() ) { if ($filter->Background()) {
$filter->control('stop'); $filter->control('stop');
} }
$filter->delete(); $filter->delete();
} else { } else {
ZM\Error('No filter id passed when deleting'); ZM\Error('No filter id passed when deleting');
} }
} else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) { } else if (( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' )) {
$_REQUEST['filter']['Query']['sort_field'] = validStr($_REQUEST['filter']['Query']['sort_field']); $_REQUEST['filter']['Query']['sort_field'] = validStr($_REQUEST['filter']['Query']['sort_field']);
$_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']); $_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']); $_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
$_REQUEST['filter']['AutoCopy'] = empty($_REQUEST['filter']['AutoCopy']) ? 0 : 1; $_REQUEST['filter']['AutoCopy'] = empty($_REQUEST['filter']['AutoCopy']) ? 0 : 1;
$_REQUEST['filter']['AutoCopyTo'] = empty($_REQUEST['filter']['AutoCopyTo']) ? 0 : $_REQUEST['filter']['AutoCopyTo'];
$_REQUEST['filter']['AutoMove'] = empty($_REQUEST['filter']['AutoMove']) ? 0 : 1; $_REQUEST['filter']['AutoMove'] = empty($_REQUEST['filter']['AutoMove']) ? 0 : 1;
$_REQUEST['filter']['AutoMoveTo'] = empty($_REQUEST['filter']['AutoMoveTo']) ? 0 : $_REQUEST['filter']['AutoMoveTo'];
$_REQUEST['filter']['AutoArchive'] = empty($_REQUEST['filter']['AutoArchive']) ? 0 : 1; $_REQUEST['filter']['AutoArchive'] = empty($_REQUEST['filter']['AutoArchive']) ? 0 : 1;
$_REQUEST['filter']['AutoVideo'] = empty($_REQUEST['filter']['AutoVideo']) ? 0 : 1; $_REQUEST['filter']['AutoVideo'] = empty($_REQUEST['filter']['AutoVideo']) ? 0 : 1;
$_REQUEST['filter']['AutoUpload'] = empty($_REQUEST['filter']['AutoUpload']) ? 0 : 1; $_REQUEST['filter']['AutoUpload'] = empty($_REQUEST['filter']['AutoUpload']) ? 0 : 1;
@ -65,44 +64,39 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
$_REQUEST['filter']['Background'] = empty($_REQUEST['filter']['Background']) ? 0 : 1; $_REQUEST['filter']['Background'] = empty($_REQUEST['filter']['Background']) ? 0 : 1;
$_REQUEST['filter']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1; $_REQUEST['filter']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1;
$changes = $filter->changes($_REQUEST['filter']); $changes = $filter->changes($_REQUEST['filter']);
ZM\Debug('Changes: ' . print_r($changes,true)); ZM\Debug('Changes: ' . print_r($changes, true));
if ($filter->Id() and ($action == 'Save')) { if (count($changes)) {
if ($filter->Background()) $filter->control('stop'); if ($filter->Id() and ($action == 'Save') and $filter->Background()) {
if (!$filter->save($changes)) { $filter->control('stop');
$error_message = $filter->get_last_error(); } else if ($action == 'execute') {
return; # If there are changes use a temp filter to do the execute
} $filter->Name('_TempFilter'.time());
} else { $filter->Id(null);
if ( $action == 'execute' ) { } else if ($action == 'SaveAs') {
if ( count($changes) ) { $filter->Id(null);
$filter->Name('_TempFilter'.time()); }
$filter->Id(null); if (!$filter->save($changes)) {
} $error_message = $filter->get_last_error();
} else if ( $action == 'SaveAs' ) { return;
$filter->Id(null); }
} // We update the request id so that the newly saved filter is auto-selected
if (!$filter->save($changes)) { $_REQUEST['Id'] = $filter->Id();
$error_message = $filter->get_last_error(); } # end if changes
return;
}
// We update the request id so that the newly saved filter is auto-selected if ($action == 'execute') {
$_REQUEST['Id'] = $filter->Id();
}
if ( $action == 'execute' ) {
$filter->execute(); $filter->execute();
if ( count($changes) ) if (count($changes)) {
$filter->delete(); $filter->delete();
$filter->Id(null);
$view = 'events'; }
} else if ( $filter->Background() ) { } else if ($filter->Background()) {
$filter->control('start'); $filter->control('start');
} }
global $redirect;
$redirect = '?view=filter'.$filter->querystring('filter', '&'); $redirect = '?view=filter'.$filter->querystring('filter', '&');
} else if ( $action == 'control' ) { } else if ($action == 'control') {
if ( $_REQUEST['command'] == 'start' if ( $_REQUEST['command'] == 'start'
or $_REQUEST['command'] == 'stop' or $_REQUEST['command'] == 'stop'
or $_REQUEST['command'] == 'restart' or $_REQUEST['command'] == 'restart'
@ -114,5 +108,4 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
} // end if save or execute } // end if save or execute
} // end if canEdit(Events) } // end if canEdit(Events)
} // end if object == filter } // end if object == filter
?> ?>

View File

@ -47,9 +47,12 @@ if ( $action == 'create' ) {
$monitor = new ZM\Monitor($monitor_id); $monitor = new ZM\Monitor($monitor_id);
$monitor->TriggerOff(); $monitor->TriggerOff();
} }
$dbConn->beginTransaction();
foreach ( $snapshot->Events() as $event ) { foreach ( $snapshot->Events() as $event ) {
$event->lock();
$event->save(array('Archived'=>1)); $event->save(array('Archived'=>1));
} }
$dbConn->commit();
$redirect = '?view=snapshot&id='.$snapshot->Id(); $redirect = '?view=snapshot&id='.$snapshot->Id();
return; return;
} }

View File

@ -1,5 +1,7 @@
<?php <?php
require_once('logger.php');
function buildControlCommand($monitor) { function buildControlCommand($monitor) {
$ctrlCommand = ''; $ctrlCommand = '';
$control = $monitor->Control(); $control = $monitor->Control();
@ -218,7 +220,7 @@ function buildControlCommand($monitor) {
} }
} }
} else { } else {
Error('Invalid control parameter: ' . $_REQUEST['control'] ); ZM\Error('Invalid control parameter: ' . $_REQUEST['control'] );
} }
} elseif ( isset($_REQUEST['x']) && isset($_REQUEST['y']) ) { } elseif ( isset($_REQUEST['x']) && isset($_REQUEST['y']) ) {
if ( $_REQUEST['control'] == 'moveMap' ) { if ( $_REQUEST['control'] == 'moveMap' ) {

View File

@ -192,8 +192,6 @@ $user = null;
if ( isset($_REQUEST['view']) ) if ( isset($_REQUEST['view']) )
$view = detaintPath($_REQUEST['view']); $view = detaintPath($_REQUEST['view']);
# Add CSP Headers
$cspNonce = bin2hex(zm_random_bytes(16));
$request = null; $request = null;
if ( isset($_REQUEST['request']) ) if ( isset($_REQUEST['request']) )
@ -294,8 +292,11 @@ if ( $request ) {
return; return;
} }
# Add CSP Headers
$cspNonce = bin2hex(zm_random_bytes(16));
if ( $includeFiles = getSkinIncludes('views/'.$view.'.php', true, true) ) { if ( $includeFiles = getSkinIncludes('views/'.$view.'.php', true, true) ) {
ob_start(); ob_start();
CSPHeaders($view, $cspNonce);
foreach ( $includeFiles as $includeFile ) { foreach ( $includeFiles as $includeFile ) {
if ( !file_exists($includeFile) ) if ( !file_exists($includeFile) )
ZM\Fatal("View '$view' does not exist"); ZM\Fatal("View '$view' does not exist");
@ -309,9 +310,7 @@ if ( $includeFiles = getSkinIncludes('views/'.$view.'.php', true, true) ) {
foreach ( getSkinIncludes('views/login.php', true, true) as $includeFile ) foreach ( getSkinIncludes('views/login.php', true, true) as $includeFile )
require_once $includeFile; require_once $includeFile;
} }
while (ob_get_level() > 0) ob_end_flush();
CSPHeaders($view, $cspNonce);
ob_end_flush();
} }
// If the view is missing or the view still returned error with the user logged in, // If the view is missing or the view still returned error with the user logged in,
// then it is not recoverable. // then it is not recoverable.

View File

@ -348,16 +348,16 @@ $SLANG = array(
'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08
'File' => 'Fichier', 'File' => 'Fichier',
'Filter' => 'Filtre', // Added - 2015-04-18 'Filter' => 'Filtre', // Added - 2015-04-18
'FilterArchiveEvents' => 'Archiver', 'FilterArchiveEvents' => 'Archiver les évènements',
'FilterDeleteEvents' => 'Effacer', 'FilterDeleteEvents' => 'Effacer les évènements',
'FilterEmailEvents' => 'Envoyer les détails par email', 'FilterEmailEvents' => 'Envoyer les évènements par email',
'FilterExecuteEvents' => 'Exécuter une commande', 'FilterExecuteEvents' => 'Exécuter une commande',
'FilterLog' => 'Filtre', // Added - 2015-04-18 'FilterLog' => 'Filtre', // Added - 2015-04-18
'FilterMessageEvents' => 'Envoyer les détails par message', 'FilterMessageEvents' => 'Envoyer les évènements par message',
'FilterMoveEvents' => 'Move all matches', // Added - 2018-08-30 'FilterMoveEvents' => 'Move all matches', // Added - 2018-08-30
'FilterPx' => 'Filtre Px', 'FilterPx' => 'Filtre Px',
'FilterUnset' => 'Vous devez spécifier une largeur et une hauteur de filtre', 'FilterUnset' => 'Vous devez spécifier une largeur et une hauteur de filtre',
'FilterUpdateDiskSpace'=> 'Update used disk space', // Added - 2018-08-30 'FilterUpdateDiskSpace'=> 'Mies à jour de l\'espace disque utilisé', // Added - 2018-08-30
'FilterUploadEvents' => 'Transférer', 'FilterUploadEvents' => 'Transférer',
'FilterVideoEvents' => 'Créer vidéo', 'FilterVideoEvents' => 'Créer vidéo',
'Filters' => 'Filtres', 'Filters' => 'Filtres',

View File

@ -84,7 +84,7 @@ $SLANG = array(
'AddNewControl' => 'Aggiungi nuovo Controllo', 'AddNewControl' => 'Aggiungi nuovo Controllo',
'AddNewMonitor' => 'Aggiungi nuovo Monitor', 'AddNewMonitor' => 'Aggiungi nuovo Monitor',
'AddNewServer' => 'Aggiungi nuovo Server', // Added - 2018-08-30 'AddNewServer' => 'Aggiungi nuovo Server', // Added - 2018-08-30
'AddNewStorage' => 'Aggiungi nuovo Storage', // Added - 2018-08-30 'AddNewStorage' => 'Aggiungi nuovo Archivio', // Added - 2018-08-30
'AddNewUser' => 'Aggiungi nuovo Utente', 'AddNewUser' => 'Aggiungi nuovo Utente',
'AddNewZone' => 'Aggiungi nuova Zona', 'AddNewZone' => 'Aggiungi nuova Zona',
'Alarm' => 'Allarme', 'Alarm' => 'Allarme',
@ -95,49 +95,49 @@ $SLANG = array(
'AlarmMaximumFPS' => 'FPS massimi durante l\'allarme', 'AlarmMaximumFPS' => 'FPS massimi durante l\'allarme',
'AlarmPx' => 'Pixel Allarme', 'AlarmPx' => 'Pixel Allarme',
'AlarmRGBUnset' => 'Devi settare un colore RGB di allarme', 'AlarmRGBUnset' => 'Devi settare un colore RGB di allarme',
'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'AlarmRefImageBlendPct'=> 'Riferimento Allarme - Fusione Immagine %', // Added - 2015-04-18
'Alert' => 'Attenzione', 'Alert' => 'Attenzione',
'All' => 'Tutto', 'All' => 'Tutto',
'AnalysisFPS' => 'Analysis FPS', // Added - 2015-07-22 'AnalysisFPS' => 'Analisi FPS', // Added - 2015-07-22
'AnalysisUpdateDelay' => 'Analysis Update Delay', // Added - 2015-07-23 'AnalysisUpdateDelay' => 'Intervallo aggiornamento analisi', // Added - 2015-07-23
'Apply' => 'Applica', 'Apply' => 'Applica',
'ApplyingStateChange' => 'Sto applicando le modifiche', 'ApplyingStateChange' => 'Sto applicando le modifiche',
'ArchArchived' => 'Archiviato', 'ArchArchived' => 'Archiviato',
'ArchUnarchived' => 'Non archiviato', 'ArchUnarchived' => 'Non Archiviato',
'Archive' => 'Archivio', 'Archive' => 'Archivio',
'Archived' => 'Archiviato', 'Archived' => 'Archiviato',
'Area' => 'Area', 'Area' => 'Area',
'AreaUnits' => 'Area (px/%)', 'AreaUnits' => 'Area (px/%)',
'AttrAlarmFrames' => 'Immagini in Allarme', 'AttrAlarmFrames' => 'Immagini Allarme',
'AttrArchiveStatus' => 'Stato Archivio', 'AttrArchiveStatus' => 'Stato Archivio',
'AttrAvgScore' => 'Punteggio medio', 'AttrAvgScore' => 'Punteggio Medio',
'AttrCause' => 'Causa', 'AttrCause' => 'Causa',
'AttrDiskBlocks' => 'Blocchi del Disco', 'AttrDiskBlocks' => 'Blocchi disco',
'AttrDiskPercent' => 'Percentuale del Disco', 'AttrDiskPercent' => 'Percentuale disco',
'AttrDiskSpace' => 'Disk Space', // Added - 2018-08-30 'AttrDiskSpace' => 'Spazio disco', // Added - 2018-08-30
'AttrDuration' => 'Durata', 'AttrDuration' => 'Durata',
'AttrEndDate' => 'End Date', // Added - 2018-08-30 'AttrEndDate' => 'End Date', // Added - 2018-08-30
'AttrEndDateTime' => 'End Date/Time', // Added - 2018-08-30 'AttrEndDateTime' => 'End Date/Time', // Added - 2018-08-30
'AttrEndTime' => 'End Time', // Added - 2018-08-30 'AttrEndTime' => 'End Time', // Added - 2018-08-30
'AttrEndWeekday' => 'End Weekday', // Added - 2018-08-30 'AttrEndWeekday' => 'End Weekday', // Added - 2018-08-30
'AttrFilterServer' => 'Server Filter is Running On', // Added - 2018-08-30 'AttrFilterServer' => 'Filtro attivo su Server', // Added - 2018-08-30
'AttrFrames' => 'Immagini', 'AttrFrames' => 'Immagini',
'AttrId' => 'Id', 'AttrId' => 'Id',
'AttrMaxScore' => 'Punteggio massimo', 'AttrMaxScore' => 'Punteggio Massimo',
'AttrMonitorId' => 'Id Monitor', 'AttrMonitorId' => 'Id Monitor',
'AttrMonitorName' => 'Nome Monitor', 'AttrMonitorName' => 'Nome Monitor',
'AttrMonitorServer' => 'Server Monitor is Running On', // Added - 2018-08-30 'AttrMonitorServer' => 'Monitor attivo su Server', // Added - 2018-08-30
'AttrName' => 'Nome', 'AttrName' => 'Nome',
'AttrNotes' => 'Note', 'AttrNotes' => 'Note',
'AttrStartDate' => 'Start Date', // Added - 2018-08-30 'AttrStartDate' => 'Inizio - Data', // Added - 2018-08-30
'AttrStartDateTime' => 'Start Date/Time', // Added - 2018-08-30 'AttrStartDateTime' => 'Inizio - Data/orario', // Added - 2018-08-30
'AttrStartTime' => 'Start Time', // Added - 2018-08-30 'AttrStartTime' => 'Inizio - Orario', // Added - 2018-08-30
'AttrStartWeekday' => 'Start Weekday', // Added - 2018-08-30 'AttrStartWeekday' => 'Inizio - Giorno della settimana', // Added - 2018-08-30
'AttrStateId' => 'Run State', // Added - 2018-08-30 'AttrStateId' => 'Stato Esecuzione', // Added - 2018-08-30
'AttrStorageArea' => 'Storage Area', // Added - 2018-08-30 'AttrStorageArea' => 'Area Archiviazione', // Added - 2018-08-30
'AttrStorageServer' => 'Server Hosting Storage', // Added - 2018-08-30 'AttrStorageServer' => 'Server Archiviazione remota', // Added - 2018-08-30
'AttrSystemLoad' => 'System Load', 'AttrSystemLoad' => 'Carico Sistema',
'AttrTotalScore' => 'Punteggio totale', 'AttrTotalScore' => 'Punteggio Totale',
'Auto' => 'Auto', 'Auto' => 'Auto',
'AutoStopTimeout' => 'Auto Stop Timeout', 'AutoStopTimeout' => 'Auto Stop Timeout',
'Available' => 'Disponibile', // Added - 2009-03-31 'Available' => 'Disponibile', // Added - 2009-03-31
@ -181,56 +181,56 @@ $SLANG = array(
'BlobPx' => 'Blob Px', 'BlobPx' => 'Blob Px',
'BlobSizes' => 'Dimensioni Blob', 'BlobSizes' => 'Dimensioni Blob',
'Blobs' => 'Blobs', 'Blobs' => 'Blobs',
'Brightness' => 'Luminosit&agrave;', 'Brightness' => 'Luminosità',
'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffer' => 'Buffer', // Added - 2015-04-18
'Buffers' => 'Buffers', 'Buffers' => 'Buffers',
'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18
'CanAutoFocus' => 'Puo\' Auto Focus', 'CanAutoFocus' => 'Può Auto Focus',
'CanAutoGain' => 'Puo\' Auto Gains', 'CanAutoGain' => 'Può Auto Gains',
'CanAutoIris' => 'Puo\' Auto Iris', 'CanAutoIris' => 'Può Auto Iris',
'CanAutoWhite' => 'Puo\' Auto bil bianco', 'CanAutoWhite' => 'Può Auto bil bianco',
'CanAutoZoom' => 'Puo\' Auto Zoom', 'CanAutoZoom' => 'Può Auto Zoom',
'CanFocus' => 'Puo\' Fuoco', 'CanFocus' => 'Può Fuoco',
'CanFocusAbs' => 'Puo\' Fuoco Assoluto', 'CanFocusAbs' => 'Può Fuoco Assoluto',
'CanFocusCon' => 'Puo\' Fuoco Continuo ', 'CanFocusCon' => 'Può Fuoco Continuo ',
'CanFocusRel' => 'Puo\' Fuoco Relativo', 'CanFocusRel' => 'Può Fuoco Relativo',
'CanGain' => 'Puo\' Gain ', 'CanGain' => 'Può Gain ',
'CanGainAbs' => 'Puo\' Gain Assoluto', 'CanGainAbs' => 'Può Gain Assoluto',
'CanGainCon' => 'Puo\' Gain Continuo ', 'CanGainCon' => 'Può Gain Continuo ',
'CanGainRel' => 'Puo\' Gain Relativo', 'CanGainRel' => 'Può Gain Relativo',
'CanIris' => 'Puo\' Iris', 'CanIris' => 'Può Iris',
'CanIrisAbs' => 'Puo\' Iris Assoluto', 'CanIrisAbs' => 'Può Iris Assoluto',
'CanIrisCon' => 'Puo\' Iris Continuo ', 'CanIrisCon' => 'Può Iris Continuo ',
'CanIrisRel' => 'Puo\' Iris Relativo', 'CanIrisRel' => 'Può Iris Relativo',
'CanMove' => 'Puo\' Mov.', 'CanMove' => 'Può Mov.',
'CanMoveAbs' => 'Puo\' Mov. Assoluto', 'CanMoveAbs' => 'Può Mov. Assoluto',
'CanMoveCon' => 'Puo\' Mov. Continuo ', 'CanMoveCon' => 'Può Mov. Continuo ',
'CanMoveDiag' => 'Puo\' Mov. Diagonale ', 'CanMoveDiag' => 'Può Mov. Diagonale ',
'CanMoveMap' => 'Puo\' Mov Mappato', 'CanMoveMap' => 'Può Mov Mappato',
'CanMoveRel' => 'Puo\' Mov. Relativo', 'CanMoveRel' => 'Può Mov. Relativo',
'CanPan' => 'Puo\' Pan' , 'CanPan' => 'Può Pan' ,
'CanReset' => 'Puo\' Reset', 'CanReset' => 'Può Reset',
'CanReboot' => 'Can Reboot', 'CanReboot' => 'Può Riavviare',
'CanSetPresets' => 'Puo\' impostare preset', 'CanSetPresets' => 'Può impostare preset',
'CanSleep' => 'Puo\' andare in sleep', 'CanSleep' => 'Può andare in sleep',
'CanTilt' => 'Puo\' Tilt', 'CanTilt' => 'Può inclinare',
'CanWake' => 'Puo\' essere riattivato', 'CanWake' => 'Può essere riattivato',
'CanWhite' => 'Puo\' bilanciare il bianco', 'CanWhite' => 'Può bilanciare il bianco',
'CanWhiteAbs' => 'Puo\' bilanciare il bianco assoluto', 'CanWhiteAbs' => 'Può bilanciare il bianco assoluto',
'CanWhiteBal' => 'Puo\' bilanciare il bianco', 'CanWhiteBal' => 'Può bilanciare il bianco',
'CanWhiteCon' => 'Puo\' bilanciare il bianco Continuo', 'CanWhiteCon' => 'Può bilanciare il bianco Continuo',
'CanWhiteRel' => 'Puo\' bilanciare il bianco Relativo', 'CanWhiteRel' => 'Può bilanciare il bianco Relativo',
'CanZoom' => 'Puo\' Zoom', 'CanZoom' => 'Può Zoom',
'CanZoomAbs' => 'Puo\' Zoom Assoluto', 'CanZoomAbs' => 'Può Zoom Assoluto',
'CanZoomCon' => 'Puo\' Zoom Continuo', 'CanZoomCon' => 'Può Zoom Continuo',
'CanZoomRel' => 'Puo\' Zoom Relativo', 'CanZoomRel' => 'Può Zoom Relativo',
'Cancel' => 'Annulla', 'Cancel' => 'Annulla',
'CancelForcedAlarm' => 'Annulla Allarme Forzato', 'CancelForcedAlarm' => 'Annulla Allarme Forzato',
'CaptureHeight' => 'Altezza img catturata', 'CaptureHeight' => 'Altezza Cattura Immagine',
'CaptureMethod' => 'Metodo di cattura', // Added - 2009-02-08 'CaptureMethod' => 'Metodo Cattura Immagine', // Added - 2009-02-08
'CapturePalette' => 'Paletta img catturata', 'CapturePalette' => 'Tavolozza Cattura Immagine',
'CaptureResolution' => 'Risoluzione di cattura', // Added - 2015-04-18 'CaptureResolution' => 'Risoluzione Cattura Immagine', // Added - 2015-04-18
'CaptureWidth' => 'Larghezza img Catturata', 'CaptureWidth' => 'Larghezza Cattura Immagine',
'Cause' => 'Causa', 'Cause' => 'Causa',
'CheckMethod' => 'Metodo di Controllo Allarme', 'CheckMethod' => 'Metodo di Controllo Allarme',
'ChooseDetectedCamera' => 'Scegli telecamera rilevata', // Added - 2009-03-31 'ChooseDetectedCamera' => 'Scegli telecamera rilevata', // Added - 2009-03-31
@ -238,13 +238,13 @@ $SLANG = array(
'ChooseLogFormat' => 'Scegli un formato di registro', // Added - 2011-06-17 'ChooseLogFormat' => 'Scegli un formato di registro', // Added - 2011-06-17
'ChooseLogSelection' => 'Scegli una selezione del registro', // Added - 2011-06-17 'ChooseLogSelection' => 'Scegli una selezione del registro', // Added - 2011-06-17
'ChoosePreset' => 'Scegli Preset', 'ChoosePreset' => 'Scegli Preset',
'Clear' => 'Clear', // Added - 2011-06-16 'Clear' => 'Pulisci', // Added - 2011-06-16
'CloneMonitor' => 'Clone', // Added - 2018-08-30 'CloneMonitor' => 'Clona', // Added - 2018-08-30
'Close' => 'Chiudi', 'Close' => 'Chiudi',
'Colour' => 'Colori', 'Colour' => 'Colori',
'Command' => 'Comando', 'Command' => 'Comando',
'Component' => 'Component', // Added - 2011-06-16 'Component' => 'Component', // Added - 2011-06-16
'ConcurrentFilter' => 'Run filter concurrently', // Added - 2018-08-30 'ConcurrentFilter' => 'Esegui filtro contemporaneamente', // Added - 2018-08-30
'Config' => 'Configura', 'Config' => 'Configura',
'ConfiguredFor' => 'Configurato per', 'ConfiguredFor' => 'Configurato per',
'ConfirmDeleteEvents' => 'Sei sicuro di voler cancellare gli eventi selezionati', 'ConfirmDeleteEvents' => 'Sei sicuro di voler cancellare gli eventi selezionati',
@ -257,29 +257,29 @@ $SLANG = array(
'Contrast' => 'Contrasto', 'Contrast' => 'Contrasto',
'Control' => 'Controllo', 'Control' => 'Controllo',
'ControlAddress' => 'Indirizzo di controllo', 'ControlAddress' => 'Indirizzo di controllo',
'ControlCap' => 'Capacita\' di controllo', 'ControlCap' => 'Capacità di controllo',
'ControlCaps' => 'Capacita\' di controllo', 'ControlCaps' => 'Capacità di controllo',
'ControlDevice' => 'Dispositivo di controllo', 'ControlDevice' => 'Dispositivo di controllo',
'ControlType' => 'Tipo Controllo', 'ControlType' => 'Tipo Controllo',
'Controllable' => 'Controllabile', 'Controllable' => 'Controllabile',
'Current' => 'Current', // Added - 2015-04-18 'Current' => 'Corrente', // Added - 2015-04-18
'Cycle' => 'Cicla', 'Cycle' => 'Cicla',
'CycleWatch' => 'Vista Ciclica', 'CycleWatch' => 'Vista Ciclica',
'DateTime' => 'Date/Time', // Added - 2011-06-16 'DateTime' => 'Data/Orario', // Added - 2011-06-16
'Day' => 'Giorno', 'Day' => 'Giorno',
'Debug' => 'Debug', 'Debug' => 'Debug',
'DefaultRate' => 'Default Rate', 'DefaultRate' => 'Rateo predefinito',
'DefaultScale' => 'Scala di default', 'DefaultScale' => 'Scala di default',
'DefaultView' => 'Visualizzazione di default', 'DefaultView' => 'Visualizzazione predefinita',
'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 'Deinterlacing' => 'Deinterlacciamento', // Added - 2015-04-18
'Delay' => 'Delay', // Added - 2015-04-18 'Delay' => 'Ritardo', // Added - 2015-04-18
'Delete' => 'Elimina', 'Delete' => 'Elimina',
'DeleteAndNext' => 'Elimina &amp; Prossimo', 'DeleteAndNext' => 'Elimina e Prossimo',
'DeleteAndPrev' => 'Elimina &amp; Precedente', 'DeleteAndPrev' => 'Elimina e Precedente',
'DeleteSavedFilter' => 'Elimina il filtro salvato', 'DeleteSavedFilter' => 'Elimina il filtro salvato',
'Description' => 'Descrizione', 'Description' => 'Descrizione',
'DetectedCameras' => 'Telecamere Rilevate', // Added - 2009-03-31 'DetectedCameras' => 'Telecamere Rilevate', // Added - 2009-03-31
'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'DetectedProfiles' => 'Profili Rilevati', // Added - 2015-04-18
'Device' => 'Periferica', // Added - 2009-02-08 'Device' => 'Periferica', // Added - 2009-02-08
'DeviceChannel' => 'Canale Periferica', 'DeviceChannel' => 'Canale Periferica',
'DeviceFormat' => 'Formato', 'DeviceFormat' => 'Formato',
@ -287,18 +287,18 @@ $SLANG = array(
'DevicePath' => 'Percorso Dispositivo', 'DevicePath' => 'Percorso Dispositivo',
'Devices' => 'Dispositivi', 'Devices' => 'Dispositivi',
'Dimensions' => 'Dimensioni', 'Dimensions' => 'Dimensioni',
'DisableAlarms' => 'Disabil Allarme', 'DisableAlarms' => 'Disabilita Allarme',
'Disk' => 'Utilizzo Disco', 'Disk' => 'Utilizzo Disco',
'Display' => 'Display', // Added - 2011-01-30 'Display' => 'Mostra', // Added - 2011-01-30
'Displaying' => 'Displaying', // Added - 2011-06-16 'Displaying' => 'Visualizzazione', // Added - 2011-06-16
'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'DoNativeMotionDetection'=> 'Attiva Motion Detection Nativo',
'Donate' => 'Donate,per favore', 'Donate' => 'Donate,per favore',
'DonateAlready' => 'No, ho gia donato... ', 'DonateAlready' => 'No, ho gia donato... ',
'DonateEnticement' => 'Stai usando ZoneMinder da un po\' di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.<br><br>Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a https://zoneminder.com/donate/ .<br><br>Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.', 'DonateEnticement' => 'Stai usando ZoneMinder da un pò di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.<br><br>Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a https://zoneminder.com/donate/ .<br><br>Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.',
'DonateRemindDay' => 'Non ancora, ricordamelo ancora tra 1 giorno', 'DonateRemindDay' => 'Non ancora, ricordamelo ancora tra 1 giorno',
'DonateRemindHour' => 'Non ancora, ricordamelo ancora tra 1 ora', 'DonateRemindHour' => 'Non ancora, ricordamelo ancora tra 1 ora',
'DonateRemindMonth' => 'Non ancora, ricordamelo ancora tra 1 mese', 'DonateRemindMonth' => 'Non ancora, ricordamelo ancora tra 1 mese',
'DonateRemindNever' => 'No, io non voglio donare, non lo faro\' mai', 'DonateRemindNever' => 'No, io non voglio donare, non lo farò mai',
'DonateRemindWeek' => 'Non ancora, ricordamelo ancora tra 1 settimana', 'DonateRemindWeek' => 'Non ancora, ricordamelo ancora tra 1 settimana',
'DonateYes' => 'Si,mi piacerebbe donare qualcosa ora', 'DonateYes' => 'Si,mi piacerebbe donare qualcosa ora',
'Download' => 'Scarica', 'Download' => 'Scarica',
@ -325,24 +325,24 @@ $SLANG = array(
'Execute' => 'Esegui', 'Execute' => 'Esegui',
'Exif' => 'Includi dati EXIF nell\'immagine', // Added - 2018-08-30 'Exif' => 'Includi dati EXIF nell\'immagine', // Added - 2018-08-30
'Export' => 'Esporta', 'Export' => 'Esporta',
'ExportDetails' => 'Esp. dettagli eventi', 'ExportDetails' => 'Esporta dettagli eventi',
'ExportFailed' => 'Esp. Fallita ', 'ExportFailed' => 'Esportazione Fallita ',
'ExportFormat' => 'Formato File Esp. ', 'ExportFormat' => 'Formato File Esportazione',
'ExportFormatTar' => 'Tar', 'ExportFormatTar' => 'Tar',
'ExportFormatZip' => 'Zip', 'ExportFormatZip' => 'Zip',
'ExportFrames' => 'Dettagli frame espo.', 'ExportFrames' => 'Esporta dettagli immagini',
'ExportImageFiles' => 'Esporta le immagini', 'ExportImageFiles' => 'Esporta le immagini',
'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportLog' => 'Esporta Log', // Added - 2011-06-17
'ExportMiscFiles' => 'Esporto Altri file (se presenti)', 'ExportMiscFiles' => 'Esporta Altri file (se presenti)',
'ExportOptions' => 'Opzioni Esportazione', 'ExportOptions' => 'Opzioni Esportazione',
'ExportSucceeded' => 'Export completata con successo', // Added - 2009-02-08 'ExportSucceeded' => 'Esportazione completata con successo', // Added - 2009-02-08
'ExportVideoFiles' => 'Esporto File Video (se presenti)', 'ExportVideoFiles' => 'Esporta File Video (se presenti)',
'Exporting' => 'In corso.', 'Exporting' => 'In corso',
'FPS' => 'fps', 'FPS' => 'fps',
'FPSReportInterval' => 'Intervallo Report FPS', 'FPSReportInterval' => 'Intervallo Report FPS',
'FTP' => 'FTP', 'FTP' => 'FTP',
'Far' => 'Lontano', 'Far' => 'Lontano',
'FastForward' => 'Fast Forward', 'FastForward' => 'Avanzamento veloce',
'Feed' => 'Feed', 'Feed' => 'Feed',
'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08
'File' => 'File', 'File' => 'File',
@ -351,7 +351,7 @@ $SLANG = array(
'FilterDeleteEvents' => 'Elimina gli eventi', 'FilterDeleteEvents' => 'Elimina gli eventi',
'FilterEmailEvents' => 'Invia dettagli via email', 'FilterEmailEvents' => 'Invia dettagli via email',
'FilterExecuteEvents' => 'Esegui un comando', 'FilterExecuteEvents' => 'Esegui un comando',
'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterLog' => 'Filtra log', // Added - 2015-04-18
'FilterMessageEvents' => 'Invia dettagli tramite messaggio', 'FilterMessageEvents' => 'Invia dettagli tramite messaggio',
'FilterMoveEvents' => 'Sposta tutti gli eventi', // Added - 2018-08-30 'FilterMoveEvents' => 'Sposta tutti gli eventi', // Added - 2018-08-30
'FilterPx' => 'Px Filtro', 'FilterPx' => 'Px Filtro',
@ -363,12 +363,12 @@ $SLANG = array(
'First' => 'Primo', 'First' => 'Primo',
'FlippedHori' => 'ribaltato orizzontale', 'FlippedHori' => 'ribaltato orizzontale',
'FlippedVert' => 'ribaltato verticale', 'FlippedVert' => 'ribaltato verticale',
'FnMocord' => 'Mocord', // Added 2013.08.16. 'FnMocord' => 'Mocord - Registrazione continua (con evidenziazione eventi)', // Added 2013.08.16.
'FnModect' => 'Modect', // Added 2013.08.16. 'FnModect' => 'Modect - MOtion DEteCTtion (registrazione su rilevamento movimento)', // Added 2013.08.16.
'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnMonitor' => 'Monitor - Visualizza Live', // Added 2013.08.16.
'FnNodect' => 'Nodect', // Added 2013.08.16. 'FnNodect' => 'Nodect - No DEteCTtion (registrazione su evento esterno)', // Added 2013.08.16.
'FnNone' => 'None', // Added 2013.08.16. 'FnNone' => 'None - Nessuno (Monitor disabilitato)', // Added 2013.08.16.
'FnRecord' => 'Record', // Added 2013.08.16. 'FnRecord' => 'Record - Registrazione continua', // Added 2013.08.16.
'Focus' => 'Focus', 'Focus' => 'Focus',
'ForceAlarm' => 'Forza Allarme', 'ForceAlarm' => 'Forza Allarme',
'Format' => 'Formato', 'Format' => 'Formato',
@ -379,7 +379,7 @@ $SLANG = array(
'Frames' => 'Immagini', 'Frames' => 'Immagini',
'Func' => 'Funz', 'Func' => 'Funz',
'Function' => 'Funzione', 'Function' => 'Funzione',
'Gain' => 'Gain', 'Gain' => 'Guadagno',
'General' => 'Generale', 'General' => 'Generale',
'GenerateDownload' => 'Genera download', // Added - 2018-08-30 'GenerateDownload' => 'Genera download', // Added - 2018-08-30
'GenerateVideo' => 'Genera video', 'GenerateVideo' => 'Genera video',
@ -388,19 +388,19 @@ $SLANG = array(
'Grey' => 'Grigio', 'Grey' => 'Grigio',
'Group' => 'Gruppo', 'Group' => 'Gruppo',
'Groups' => 'Gruppi', 'Groups' => 'Gruppi',
'HasFocusSpeed' => 'Ha velocita\' di focus', 'HasFocusSpeed' => 'Ha velocità di focus',
'HasGainSpeed' => 'Ha velocita\' di guadagno', 'HasGainSpeed' => 'Ha velocità di guadagno',
'HasHomePreset' => 'Ha posizioni di present', 'HasHomePreset' => 'Ha posizioni di present',
'HasIrisSpeed' => 'Ha velocota\' di iris', 'HasIrisSpeed' => 'Ha velocità di iris',
'HasPanSpeed' => 'Ha velocita\' di Pan', 'HasPanSpeed' => 'Ha velocità di Pan',
'HasPresets' => 'Ha preset', 'HasPresets' => 'Ha preset',
'HasTiltSpeed' => 'Ha velocita\' di Tilt', 'HasTiltSpeed' => 'Ha velocità di Tilt',
'HasTurboPan' => 'Ha il Turbo Pan', 'HasTurboPan' => 'Ha il Turbo Pan',
'HasTurboTilt' => 'Ha il Turbo Tilt', 'HasTurboTilt' => 'Ha il Turbo Tilt',
'HasWhiteSpeed' => 'Ha velocita\' di bilanciamento del bianco', 'HasWhiteSpeed' => 'Ha velocità di bilanciamento del bianco',
'HasZoomSpeed' => 'Ha velocita\' di zoom', 'HasZoomSpeed' => 'Ha velocità di zoom',
'High' => 'Alta', 'High' => 'Alta',
'HighBW' => 'Banda&nbsp;Alta', 'HighBW' => 'Banda Alta',
'Home' => 'Home', 'Home' => 'Home',
'Hostname' => 'Nome Host', // Added - 2018-08-30 'Hostname' => 'Nome Host', // Added - 2018-08-30
'Hour' => 'Ora', 'Hour' => 'Ora',
@ -414,7 +414,7 @@ $SLANG = array(
'In' => 'In', 'In' => 'In',
'Include' => 'Includi', 'Include' => 'Includi',
'Inverted' => 'Invertito', 'Inverted' => 'Invertito',
'Iris' => 'Iris', 'Iris' => 'Iride',
'KeyString' => 'Stringa Chiave', 'KeyString' => 'Stringa Chiave',
'Label' => 'Etichetta', 'Label' => 'Etichetta',
'Language' => 'Linguaggio', 'Language' => 'Linguaggio',
@ -438,39 +438,39 @@ $SLANG = array(
'Logout' => 'Logout', 'Logout' => 'Logout',
'Logs' => 'Logs', // Added - 2011-06-17 'Logs' => 'Logs', // Added - 2011-06-17
'Low' => 'Bassa', 'Low' => 'Bassa',
'LowBW' => 'Banda&nbsp;Bassa', 'LowBW' => 'Banda Bassa',
'Main' => 'Principale', 'Main' => 'Principale',
'Man' => 'Man', 'Man' => 'Man',
'Manual' => 'Manuale', 'Manual' => 'Manuale',
'Mark' => 'Seleziona', 'Mark' => 'Seleziona',
'Max' => 'Massima', 'Max' => 'Massima',
'MaxBandwidth' => 'Banda Massima', 'MaxBandwidth' => 'Banda Massima',
'MaxBrScore' => 'Punteggio<br/>Massimo', 'MaxBrScore' => 'Punteggio Massimo',
'MaxFocusRange' => 'Massimo range del focus', 'MaxFocusRange' => 'Massimo range del focus',
'MaxFocusSpeed' => 'Massima velocita\' del focus', 'MaxFocusSpeed' => 'Massima velocità del focus',
'MaxFocusStep' => 'Massimo step del focus', 'MaxFocusStep' => 'Massimo step del focus',
'MaxGainRange' => 'Massimo range del guadagno', 'MaxGainRange' => 'Massimo range del guadagno',
'MaxGainSpeed' => 'Massima velocita\' del guadagno', 'MaxGainSpeed' => 'Massima velocità del guadagno',
'MaxGainStep' => 'Massimo step del guadagno', 'MaxGainStep' => 'Massimo step del guadagno',
'MaxIrisRange' => 'Massima range dell\'Iris', 'MaxIrisRange' => 'Massima range dell\'Iride',
'MaxIrisSpeed' => 'Massima velocita\' dell\'Iris', 'MaxIrisSpeed' => 'Massima velocità dell\'Iride',
'MaxIrisStep' => 'Massimo step dell\'Iris', 'MaxIrisStep' => 'Massimo step dell\'Iride',
'MaxPanRange' => 'Massimo range del pan', 'MaxPanRange' => 'Massimo range del pan',
'MaxPanSpeed' => 'Massima velocita\' del tilt', 'MaxPanSpeed' => 'Massima velocità del tilt',
'MaxPanStep' => 'Massimo step del pan', 'MaxPanStep' => 'Massimo step del pan',
'MaxTiltRange' => 'Massimo range del tilt', 'MaxTiltRange' => 'Massimo range del tilt',
'MaxTiltSpeed' => 'Massima velocita\' del tilt', 'MaxTiltSpeed' => 'Massima velocità del tilt',
'MaxTiltStep' => 'Massimo passo del tilt', 'MaxTiltStep' => 'Massimo passo del tilt',
'MaxWhiteRange' => 'Massimo range del bilanciamento del bianco', 'MaxWhiteRange' => 'Massimo range del bilanciamento del bianco',
'MaxWhiteSpeed' => 'Massima velocita\' del bilanciamento del bianco', 'MaxWhiteSpeed' => 'Massima velocità del bilanciamento del bianco',
'MaxWhiteStep' => 'Massimo Step del bilanciamento del bianco', 'MaxWhiteStep' => 'Massimo Step del bilanciamento del bianco',
'MaxZoomRange' => 'Massimo range dello zoom', 'MaxZoomRange' => 'Massimo range dello zoom',
'MaxZoomSpeed' => 'Massima velocita\' dello zoom', 'MaxZoomSpeed' => 'Massima velocità dello zoom',
'MaxZoomStep' => 'Massimo step dello zoom', 'MaxZoomStep' => 'Massimo step dello zoom',
'MaximumFPS' => 'Massimi FPS', 'MaximumFPS' => 'Massimi FPS',
'Medium' => 'Media', 'Medium' => 'Media',
'MediumBW' => 'Banda&nbsp;Media', 'MediumBW' => 'Larghezza Banda Media',
'Message' => 'Message', // Added - 2011-06-16 'Message' => 'Messaggio', // Added - 2011-06-16
'MinAlarmAreaLtMax' => 'L\'area minima dell\'allarme deve essere minore di quella massima', 'MinAlarmAreaLtMax' => 'L\'area minima dell\'allarme deve essere minore di quella massima',
'MinAlarmAreaUnset' => 'Devi specificare il numero minimo di pixel per l\'allarme', 'MinAlarmAreaUnset' => 'Devi specificare il numero minimo di pixel per l\'allarme',
'MinBlobAreaLtMax' => 'L\'area di blob minima deve essere minore dell\'area di blob massima', 'MinBlobAreaLtMax' => 'L\'area di blob minima deve essere minore dell\'area di blob massima',
@ -482,47 +482,47 @@ $SLANG = array(
'MinFilterAreaUnset' => 'Devi specificare il numero minimo di pixel per il filtro', 'MinFilterAreaUnset' => 'Devi specificare il numero minimo di pixel per il filtro',
'MinFilterLtMinAlarm' => 'L\'area minima di filtro deve essere minore o uguale dell\area minima di allarme', 'MinFilterLtMinAlarm' => 'L\'area minima di filtro deve essere minore o uguale dell\area minima di allarme',
'MinFocusRange' => 'Range minimo del Focus', 'MinFocusRange' => 'Range minimo del Focus',
'MinFocusSpeed' => 'Velocita\' minima del Focus', 'MinFocusSpeed' => 'Velocità minima del Focus',
'MinFocusStep' => 'Minimo step del Focus', 'MinFocusStep' => 'Minimo step del Focus',
'MinGainRange' => 'Minimo range del Guadagno', 'MinGainRange' => 'Minimo range del Guadagno',
'MinGainSpeed' => 'Velocita\' minima del Guadagno', 'MinGainSpeed' => 'Velocità minima del Guadagno',
'MinGainStep' => 'Step minimo del guadagno', 'MinGainStep' => 'Step minimo del guadagno',
'MinIrisRange' => 'Range minimo dell\'Iris', 'MinIrisRange' => 'Range minimo dell\'Iride',
'MinIrisSpeed' => 'Velocita\' minima dell\'Iris', 'MinIrisSpeed' => 'Velocità minima dell\'Iride',
'MinIrisStep' => 'Step minimo dell\'Iris', 'MinIrisStep' => 'Step minimo dell\'Iride',
'MinPanRange' => 'Range minimo del pan', 'MinPanRange' => 'Range minimo del Pan',
'MinPanSpeed' => 'Velocita\' minima del Pan', 'MinPanSpeed' => 'Velocità minima del Pan',
'MinPanStep' => 'Step minimo del Pan', 'MinPanStep' => 'Step minimo del Pan',
'MinPixelThresLtMax' => 'I pixel minimi della soglia devono essere minori dei pixel massimi della soglia', 'MinPixelThresLtMax' => 'I pixel minimi della soglia devono essere minori dei pixel massimi della soglia',
'MinPixelThresUnset' => 'Devi specificare una soglia minima di pixel', // Added - 2009-02-08 'MinPixelThresUnset' => 'Devi specificare una soglia minima di pixel', // Added - 2009-02-08
'MinTiltRange' => 'Range minimo del Tilt', 'MinTiltRange' => 'Range minimo del Tilt',
'MinTiltSpeed' => 'Velocita\' minima del Tilt', 'MinTiltSpeed' => 'Velocità minima del Tilt',
'MinTiltStep' => 'Step minimo del Tilt', 'MinTiltStep' => 'Step minimo del Tilt',
'MinWhiteRange' => 'Range minimo del bilanciamento del bianco', 'MinWhiteRange' => 'Range minimo del bilanciamento del bianco',
'MinWhiteSpeed' => 'Velocita\' minima del bialnciamento del bianco', 'MinWhiteSpeed' => 'Velocità minima del bialnciamento del bianco',
'MinWhiteStep' => 'Minimo step del bilanciamento del bianco', 'MinWhiteStep' => 'Minimo step del bilanciamento del bianco',
'MinZoomRange' => 'Range minimo dello zoom', 'MinZoomRange' => 'Range minimo dello zoom',
'MinZoomSpeed' => 'Velocita\' minima dello zoom', 'MinZoomSpeed' => 'Velocità minima dello zoom',
'MinZoomStep' => 'Step minimo dello zoom', 'MinZoomStep' => 'Step minimo dello zoom',
'Misc' => 'Altro', 'Misc' => 'Altro',
'Mode' => 'Modalità', // Added - 2015-04-18 'Mode' => 'Modalità', // Added - 2015-04-18
'Monitor' => 'Monitor', 'Monitor' => 'Monitor',
'MonitorIds' => 'Monitor&nbsp;Ids', 'MonitorIds' => 'Monitor Ids',
'MonitorPreset' => 'Monitor Presenti', 'MonitorPreset' => 'Monitor Presenti',
'MonitorPresetIntro' => 'Selezionare un appropriato pre settaggio dalla lista riportata qui sotto.<br><br>Per favore notare che questo potrebbe sovrascrivere ogni valore che hai gi&agrave; configurato su questo monitor.<br><br>', 'MonitorPresetIntro' => 'Selezionare un appropriato pre settaggio dalla lista riportata qui sotto.<br><br>Per favore notare che questo potrebbe sovrascrivere ogni valore che hai gi&agrave; configurato su questo monitor.<br><br>',
'MonitorProbe' => 'Prova Monitor', // Added - 2009-03-31 'MonitorProbe' => 'Prova Monitor', // 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.<br/><br/>Select the desired entry from the list below.<br/><br/>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.<br/><br/>', // 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.<br/><br/>Select the desired entry from the list below.<br/><br/>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.<br/><br/>', // Added - 2009-03-31
'Monitors' => 'Monitors', 'Monitors' => 'Monitors',
'Montage' => 'Montaggio', 'Montage' => 'Montaggio',
'MontageReview' => 'Montage Review', // Added - 2018-08-30 'MontageReview' => 'Revisione del montaggio', // Added - 2018-08-30
'Month' => 'Mese', 'Month' => 'Mese',
'More' => 'More', // Added - 2011-06-16 'More' => 'Più', // Added - 2011-06-16
'MotionFrameSkip' => 'Motion Frame Skip', 'MotionFrameSkip' => 'Salta/scarta fotogramma',
'Move' => 'Sposta', 'Move' => 'Sposta',
'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg2widgrd' => 'Griglia 2 colonne', // Added 2013.08.15.
'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => 'Griglia 3 colonne', // Added 2013.08.15.
'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. 'Mtg3widgrx' => 'Griglia 3 colonne, scalata, ingrandita su allarme', // Added 2013.08.15.
'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg4widgrd' => 'Griglia 4 colonne', // Added 2013.08.15.
'MtgDefault' => 'Predefinito', // Added 2013.08.15. 'MtgDefault' => 'Predefinito', // Added 2013.08.15.
'MustBeGe' => 'deve essere superiore a', 'MustBeGe' => 'deve essere superiore a',
'MustBeLe' => 'deve essere inferiore o pari a', 'MustBeLe' => 'deve essere inferiore o pari a',
@ -550,7 +550,7 @@ $SLANG = array(
'NoneAvailable' => 'Nessuno disponibile', 'NoneAvailable' => 'Nessuno disponibile',
'Normal' => 'Normale', 'Normal' => 'Normale',
'Notes' => 'Note', 'Notes' => 'Note',
'NumPresets' => 'Num Presets', 'NumPresets' => 'Num redefiniti',
'Off' => 'Off', 'Off' => 'Off',
'On' => 'On', 'On' => 'On',
'OnvifCredentialsIntro'=> 'Fornire nome utente e password per la telecamera selezionata.<br/>Se non è stato creato alcun utente per la videocamera, l\'utente qui indicato verrà creato con la password specificata.<br/><br/>', // Added - 2015-04-18 'OnvifCredentialsIntro'=> 'Fornire nome utente e password per la telecamera selezionata.<br/>Se non è stato creato alcun utente per la videocamera, l\'utente qui indicato verrà creato con la password specificata.<br/><br/>', // Added - 2015-04-18
@ -589,7 +589,7 @@ $SLANG = array(
'Paths' => 'Percorsi', 'Paths' => 'Percorsi',
'Pause' => 'Pause', 'Pause' => 'Pause',
'Phone' => 'Telefono', 'Phone' => 'Telefono',
'PhoneBW' => 'Banda&nbsp;Tel', 'PhoneBW' => 'Banda Tel',
'Pid' => 'PID', // Added - 2011-06-16 'Pid' => 'PID', // Added - 2011-06-16
'PixelDiff' => 'Pixel Diff', 'PixelDiff' => 'Pixel Diff',
'Pixels' => 'pixels', 'Pixels' => 'pixels',
@ -598,18 +598,18 @@ $SLANG = array(
'PleaseWait' => 'Attendere prego', 'PleaseWait' => 'Attendere prego',
'Plugins' => 'Plugins', 'Plugins' => 'Plugins',
'Point' => 'Punto', 'Point' => 'Punto',
'PostEventImageBuffer' => 'Buffer di immagini Dopo Evento', 'PostEventImageBuffer' => 'Buffer immagini Dopo Evento',
'PreEventImageBuffer' => 'Buffer di immagini Pre Evento', 'PreEventImageBuffer' => 'Buffer immagini Pre Evento',
'PreserveAspect' => 'Preserve Aspect Ratio', 'PreserveAspect' => 'Preserve Aspect Ratio',
'Preset' => 'Preset', 'Preset' => 'Preset',
'Presets' => 'Presets', 'Presets' => 'Predefiniti',
'Prev' => 'Prec', 'Prev' => 'Prec',
'Probe' => 'Prova la telecamera', // Added - 2009-03-31 'Probe' => 'Prova la telecamera', // Added - 2009-03-31
'ProfileProbe' => 'Prova lo stream', // Added - 2015-04-18 'ProfileProbe' => 'Prova lo stream', // Added - 2015-04-18
'ProfileProbeIntro' => 'L\'elenco seguente mostra i profili di streaming esistenti della telecamera selezionata.<br/><br/>Selezionare la voce desiderata dall\'elenco seguente.<br/><br/>Si noti che ZoneMinder non è in grado di configurare profili aggiuntivi e che la scelta di una telecamera qui può sovrascrivere qualsiasi valore già configurato per il monitor corrente.<br/><br/>', // Added - 2015-04-18 'ProfileProbeIntro' => 'L\'elenco seguente mostra i profili di streaming esistenti della telecamera selezionata.<br/><br/>Selezionare la voce desiderata dall\'elenco seguente.<br/><br/>Si noti che ZoneMinder non è in grado di configurare profili aggiuntivi e che la scelta di una telecamera qui può sovrascrivere qualsiasi valore già configurato per il monitor corrente.<br/><br/>', // Added - 2015-04-18
'Progress' => 'Progresso', // Added - 2015-04-18 'Progress' => 'Progresso', // Added - 2015-04-18
'Protocol' => 'Protocollo', 'Protocol' => 'Protocollo',
'RTSPDescribe' => 'Use RTSP Response Media URL', // Added - 2018-08-30 'RTSPDescribe' => 'Usa URL multimediale di risposta RTSP', // Added - 2018-08-30
'RTSPTransport' => 'RTSP Transport Protocol', // Added - 2018-08-30 'RTSPTransport' => 'RTSP Transport Protocol', // Added - 2018-08-30
'Rate' => 'Velocità', 'Rate' => 'Velocità',
'Real' => 'Reale', 'Real' => 'Reale',
@ -622,18 +622,18 @@ $SLANG = array(
'RemoteHostName' => 'Nome dell\'Host Remoto', 'RemoteHostName' => 'Nome dell\'Host Remoto',
'RemoteHostPath' => 'Percorso dell\'Host Remoto', 'RemoteHostPath' => 'Percorso dell\'Host Remoto',
'RemoteHostPort' => 'Porta dell\'Host Remoto', 'RemoteHostPort' => 'Porta dell\'Host Remoto',
'RemoteHostSubPath' => 'SubPath host remoto', // Added - 2009-02-08 'RemoteHostSubPath' => 'Percorso secondario dell\'Host remoto', // Added - 2009-02-08
'RemoteImageColours' => 'Colori delle immagini Remote', 'RemoteImageColours' => 'Colori delle immagini Remote',
'RemoteMethod' => 'Metodo Remoto', // Added - 2009-02-08 'RemoteMethod' => 'Metodo Remoto', // Added - 2009-02-08
'RemoteProtocol' => 'Protocollo Remoto', // Added - 2009-02-08 'RemoteProtocol' => 'Protocollo Remoto', // Added - 2009-02-08
'Rename' => 'Rinomina', 'Rename' => 'Rinomina',
'Replay' => 'Replay', 'Replay' => 'Riproduci',
'ReplayAll' => 'All Events', 'ReplayAll' => 'Tutti gli Eventi',
'ReplayGapless' => 'Gapless Events', 'ReplayGapless' => 'Eventi continui',
'ReplaySingle' => 'Single Event', 'ReplaySingle' => 'Evento singolo',
'ReportEventAudit' => 'Rapporto Eventi di controllo', // Added - 2018-08-30 'ReportEventAudit' => 'Controllo Eventi', // Added - 2018-08-30
'Reset' => 'Resetta', 'Reset' => 'Reset',
'ResetEventCounts' => 'Resetta Contatore Eventi', 'ResetEventCounts' => 'Reset Contatore Eventi',
'Restart' => 'Riavvia', 'Restart' => 'Riavvia',
'Restarting' => 'Sto riavviando', 'Restarting' => 'Sto riavviando',
'RestrictedCameraIds' => 'Camera Ids Riservati', 'RestrictedCameraIds' => 'Camera Ids Riservati',
@ -644,7 +644,7 @@ $SLANG = array(
'RotateLeft' => 'Ruota a Sinista', 'RotateLeft' => 'Ruota a Sinista',
'RotateRight' => 'Ruota a Destra', 'RotateRight' => 'Ruota a Destra',
'RunLocalUpdate' => 'Eseguire zmupdate.pl per l\'aggiornamento', // Added - 2011-05-25 'RunLocalUpdate' => 'Eseguire zmupdate.pl per l\'aggiornamento', // Added - 2011-05-25
'RunMode' => 'Modalita\' funzionamento', 'RunMode' => 'Modalità funzionamento',
'RunState' => 'Stato di funzionamento', 'RunState' => 'Stato di funzionamento',
'Running' => 'Attivo', 'Running' => 'Attivo',
'Save' => 'Salva', 'Save' => 'Salva',
@ -671,69 +671,69 @@ $SLANG = array(
'Size' => 'grandezza', 'Size' => 'grandezza',
'SkinDescription' => 'Cambia la skin predefinita per questo computer', // Added - 2011-01-30 'SkinDescription' => 'Cambia la skin predefinita per questo computer', // Added - 2011-01-30
'Sleep' => 'Sleep', 'Sleep' => 'Sleep',
'SortAsc' => 'Cresc', 'SortAsc' => 'Crescente',
'SortBy' => 'Ordina per', 'SortBy' => 'Ordina per',
'SortDesc' => 'Decr', 'SortDesc' => 'Decrescente',
'Source' => 'Sorgente', 'Source' => 'Sorgente',
'SourceColours' => 'Colori della Sorgente', // Added - 2009-02-08 'SourceColours' => 'Colori della Sorgente', // Added - 2009-02-08
'SourcePath' => 'Percorso della Sorgente', // Added - 2009-02-08 'SourcePath' => 'Percorso della Sorgente', // Added - 2009-02-08
'SourceType' => 'Tipo Sorgente', 'SourceType' => 'Tipo Sorgente',
'Speed' => 'Velocita\'', 'Speed' => 'Velocità',
'SpeedHigh' => 'Alta Velocita\'', 'SpeedHigh' => 'Alta Velocità',
'SpeedLow' => 'Bassa Velocita\'', 'SpeedLow' => 'Bassa Velocità',
'SpeedMedium' => 'Media Velocita\'', 'SpeedMedium' => 'Media Velocità',
'SpeedTurbo' => 'Turbo Velocita\'', 'SpeedTurbo' => 'Turbo Velocità',
'Start' => 'Avvia', 'Start' => 'Avvia',
'State' => 'Stato', 'State' => 'Stato',
'Stats' => 'Statistiche', 'Stats' => 'Statistiche',
'Status' => 'Stato', 'Status' => 'Stato',
'StatusConnected' => 'Capturing', // Added - 2018-08-30 'StatusConnected' => 'Registrazione in corso', // Added - 2018-08-30
'StatusNotRunning' => 'Not Running', // Added - 2018-08-30 'StatusNotRunning' => 'Non in esecuzione', // Added - 2018-08-30
'StatusRunning' => 'Not Capturing', // Added - 2018-08-30 'StatusRunning' => 'Registrazione in pausa', // Added - 2018-08-30
'StatusUnknown' => 'Unknown', // Added - 2018-08-30 'StatusUnknown' => 'Sconosciuto', // Added - 2018-08-30
'Step' => 'Passo', 'Step' => 'Passo',
'StepBack' => 'Passo indietro', 'StepBack' => 'Passo indietro',
'StepForward' => 'Passo avanti', 'StepForward' => 'Passo avanti',
'StepLarge' => 'Lungo passo', 'StepLarge' => 'Passo lungo',
'StepMedium' => 'Medio passo', 'StepMedium' => 'Passo medio',
'StepNone' => 'No passo', 'StepNone' => 'Nessun passo',
'StepSmall' => 'Piccolo passo', 'StepSmall' => 'Passo piccolo',
'Stills' => 'Foto', 'Stills' => 'Immagini fisse',
'Stop' => 'Stop', 'Stop' => 'Stop',
'Stopped' => 'Inattivo', 'Stopped' => 'Inattivo',
'StorageArea' => 'Area di salvataggio', // Added - 2018-08-30 'StorageArea' => 'Area Archiviazione', // Added - 2018-08-30
'StorageScheme' => 'Scheme', // Added - 2018-08-30 'StorageScheme' => 'Schema Archiviazione', // Added - 2018-08-30
'Stream' => 'Flusso', 'Stream' => 'Stream',
'StreamReplayBuffer' => 'Stream Replay Image Buffer', 'StreamReplayBuffer' => 'Buffer immagini riproduzione stream',
'Submit' => 'Accetta', 'Submit' => 'Accetta',
'System' => 'Sistema', 'System' => 'Sistema',
'SystemLog' => 'Log di sistema', // Added - 2011-06-16 'SystemLog' => 'Log di sistema', // Added - 2011-06-16
'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'TargetColorspace' => 'Spazio dei colori obiettivo', // Added - 2015-04-18
'Tele' => 'Tele', 'Tele' => 'Tele',
'Thumbnail' => 'Anteprima', 'Thumbnail' => 'Anteprima',
'Tilt' => 'Tilt', 'Tilt' => 'Tilt (Inclinazione)',
'Time' => 'Ora', 'Time' => 'Ora',
'TimeDelta' => 'Tempo di Delta', 'TimeDelta' => 'Differenza orario',
'TimeStamp' => 'Time Stamp', 'TimeStamp' => 'Sovraimpressione data/orario',
'Timeline' => 'Linea Temporale', 'Timeline' => 'Linea Temporale',
'TimelineTip1' => 'Passa il mouse sul grafico per visualizzare un\'immagine dell\'istantanea e i dettagli dell\'evento.', // Added 2013.08.15. 'TimelineTip1' => 'Passa il mouse sul grafico per visualizzare un\'immagine dell\'istantanea e i dettagli dell\'evento.', // Added 2013.08.15.
'TimelineTip2' => 'Fai clic sulle sezioni colorate del grafico o sull\'immagine per visualizzare l\'evento.', // Added 2013.08.15. 'TimelineTip2' => 'Fai clic sulle sezioni colorate del grafico o sull\'immagine per visualizzare l\'evento.', // Added 2013.08.15.
'TimelineTip3' => 'Fare clic sullo sfondo per ingrandire un periodo di tempo più piccolo basato sul clic.', // Added 2013.08.15. 'TimelineTip3' => 'Fare clic sullo sfondo per ingrandire un periodo di tempo più piccolo basato sul clic.', // Added 2013.08.15.
'TimelineTip4' => 'Utilizzare i controlli seguenti per ridurre o spostarsi avanti e indietro nell\'intervallo di tempo.', // Added 2013.08.15. 'TimelineTip4' => 'Utilizzare i controlli seguenti per ridurre o spostarsi avanti e indietro nell\'intervallo di tempo.', // Added 2013.08.15.
'Timestamp' => 'Timestamp', 'Timestamp' => 'Sovraimpressione data/orario',
'TimestampLabelFormat' => 'Formato etichetta timestamp', 'TimestampLabelFormat' => 'Formato etichetta Sovraimpressione data/orario',
'TimestampLabelSize' => 'Dimensione carattere', // Added - 2018-08-30 'TimestampLabelSize' => 'Dimensione carattere', // Added - 2018-08-30
'TimestampLabelX' => 'coordinata X etichetta', 'TimestampLabelX' => 'coordinata X etichetta',
'TimestampLabelY' => 'coordinata Y etichetta', 'TimestampLabelY' => 'coordinata Y etichetta',
'Today' => 'Oggi ', 'Today' => 'Oggi ',
'Tools' => 'Strumenti', 'Tools' => 'Strumenti',
'Total' => 'Totale', // Added - 2011-06-16 'Total' => 'Totale', // Added - 2011-06-16
'TotalBrScore' => 'Punteggio<br/>Totale', 'TotalBrScore' => 'Punteggio Totale',
'TrackDelay' => 'Track Delay', 'TrackDelay' => 'Ritardo traccia',
'TrackMotion' => 'Track Motion', 'TrackMotion' => 'Segui movimento',
'Triggers' => 'Triggers', 'Triggers' => 'Inneschi/Interruttori',
'TurboPanSpeed' => 'Velocita\' Turbo Pan', 'TurboPanSpeed' => 'Velocità Turbo Pan',
'TurboTiltSpeed' => 'Velocita\' Turbo Tilt', 'TurboTiltSpeed' => 'Velocità Turbo Tilt',
'Type' => 'Tipo', 'Type' => 'Tipo',
'Unarchive' => 'Togli dall\'archivio', 'Unarchive' => 'Togli dall\'archivio',
'Undefined' => 'Non specificato', // Added - 2009-02-08 'Undefined' => 'Non specificato', // Added - 2009-02-08
@ -742,17 +742,17 @@ $SLANG = array(
'Update' => 'Aggiorna', 'Update' => 'Aggiorna',
'UpdateAvailable' => 'Un aggiornamento di ZoneMinder è disponibilie.', 'UpdateAvailable' => 'Un aggiornamento di ZoneMinder è disponibilie.',
'UpdateNotNecessary' => 'Nessun aggiornamento necessario.', 'UpdateNotNecessary' => 'Nessun aggiornamento necessario.',
'Updated' => 'Updated', // Added - 2011-06-16 'Updated' => 'Aggiornato', // Added - 2011-06-16
'Upload' => 'Upload', // Added - 2011-08-23 'Upload' => 'Carica', // Added - 2011-08-23
'UseFilter' => 'Usa Filtro', 'UseFilter' => 'Usa Filtro',
'UseFilterExprsPost' => '&nbsp;espressioni&nbsp;filtri', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPost' => ' espressioni filtri', // This is used at the end of the phrase 'use N filter expressions'
'UseFilterExprsPre' => 'Usa&nbsp;', // This is used at the beginning of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usa&nbsp;', // This is used at the beginning of the phrase 'use N filter expressions'
'UsedPlugins' => 'Used Plugins', 'UsedPlugins' => 'Plugins in uso',
'User' => 'Utente', 'User' => 'Utente',
'Username' => 'Nome Utente', 'Username' => 'Nome Utente',
'Users' => 'Utenti', 'Users' => 'Utenti',
'V4L' => 'V4L', // Added - 2015-04-18 'V4L' => 'V4L', // Added - 2015-04-18
'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 'V4LCapturesPerFrame' => 'Rilevamenti per immagine', // Added - 2015-04-18
'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18
'Value' => 'Valore', 'Value' => 'Valore',
'Version' => 'Versione', 'Version' => 'Versione',
@ -767,9 +767,9 @@ $SLANG = array(
'VideoGenFiles' => 'File Video Esistenti', 'VideoGenFiles' => 'File Video Esistenti',
'VideoGenNoFiles' => 'Non ho trovato file ', 'VideoGenNoFiles' => 'Non ho trovato file ',
'VideoGenParms' => 'Parametri Generazione Video', 'VideoGenParms' => 'Parametri Generazione Video',
'VideoGenSucceeded' => 'Successo: Generato Video !', 'VideoGenSucceeded' => 'Successo: Video Generato!',
'VideoSize' => 'Dimensioni Video', 'VideoSize' => 'Dimensioni Video',
'VideoWriter' => 'Scrittore video', // Added - 2018-08-30 'VideoWriter' => 'Scrittore Video', // Added - 2018-08-30
'View' => 'Vedi', 'View' => 'Vedi',
'ViewAll' => 'Vedi Tutto', 'ViewAll' => 'Vedi Tutto',
'ViewEvent' => 'Vedi Evento', 'ViewEvent' => 'Vedi Evento',
@ -782,20 +782,20 @@ $SLANG = array(
'WebSiteUrl' => 'Website URL', // Added - 2018-08-30 'WebSiteUrl' => 'Website URL', // Added - 2018-08-30
'Week' => 'Settimana', 'Week' => 'Settimana',
'White' => 'Bianco', 'White' => 'Bianco',
'WhiteBalance' => 'Bil. Bianco ', 'WhiteBalance' => 'Bilanciamento del Bianco',
'Wide' => 'Larghezza', 'Wide' => 'Larghezza',
'X' => 'X', 'X' => 'X',
'X10' => 'X10', 'X10' => 'X10',
'X10ActivationString' => 'Stringa attivazione X10', 'X10ActivationString' => 'Stringa attivazione X10',
'X10InputAlarmString' => 'Stringa allarme input X10', 'X10InputAlarmString' => 'Stringa allarme input X10',
'X10OutputAlarmString' => 'Stringa allarme output X10', 'X10OutputAlarmString' => 'Stringa allarme output X10',
'Y' => 'Y', 'Y' => 'S',
'Yes' => 'Si', 'Yes' => 'Si',
'YouNoPerms' => 'Non hai i permessi per accedere a questa risorsa.', 'YouNoPerms' => 'Non hai i permessi per accedere a questa risorsa.',
'Zone' => 'Zona', 'Zone' => 'Zona',
'ZoneAlarmColour' => 'Colore Allarme (RGB)', 'ZoneAlarmColour' => 'Colore Allarme (RGB)',
'ZoneArea' => 'Zone Area', 'ZoneArea' => 'Zone Area',
'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneExtendAlarmFrames' => 'Estendi conteggio immagini allarme',
'ZoneFilterSize' => 'Larghezza/Altezza Filtro (pixels)', 'ZoneFilterSize' => 'Larghezza/Altezza Filtro (pixels)',
'ZoneMinMaxAlarmArea' => 'Min/Max Area Allarmata', 'ZoneMinMaxAlarmArea' => 'Min/Max Area Allarmata',
'ZoneMinMaxBlobArea' => 'Min/Max Area di Blob', 'ZoneMinMaxBlobArea' => 'Min/Max Area di Blob',
@ -803,7 +803,7 @@ $SLANG = array(
'ZoneMinMaxFiltArea' => 'Min/Max Area Filtrata', 'ZoneMinMaxFiltArea' => 'Min/Max Area Filtrata',
'ZoneMinMaxPixelThres' => 'Min/Max Soglia Pixel (0-255)', 'ZoneMinMaxPixelThres' => 'Min/Max Soglia Pixel (0-255)',
'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17
'ZoneOverloadFrames' => 'Overload Frame Ignore Count', 'ZoneOverloadFrames' => 'Sovraccarico - contatore immagini ignorate',
'Zones' => 'Zone', 'Zones' => 'Zone',
'Zoom' => 'Zoom', 'Zoom' => 'Zoom',
'ZoomIn' => 'Ingrandisci', 'ZoomIn' => 'Ingrandisci',

View File

@ -746,3 +746,9 @@ a.flip {
#modalLogout .modal-body { #modalLogout .modal-body {
overflow:auto; overflow:auto;
} }
#shutdownButton {
padding: 3px 10px 5px 10px;
color: white;
}
#shutdownButton i {
}

View File

@ -63,7 +63,7 @@ select {
input[name="filter[EmailSubject]"], input[name="filter[EmailSubject]"],
input[name="filter[EmailTo]"], input[name="filter[EmailTo]"],
textarea[name="filter[EmailBody]"] { textarea[name="filter[EmailBody]"] {
width: 500px; width: 100%;
} }
select#Id { select#Id {
min-width: 500px; min-width: 500px;
@ -71,3 +71,16 @@ min-width: 500px;
.Name input { .Name input {
min-width: 500px; min-width: 500px;
} }
#ActionsAndOptions {
padding-top: 5px;
border-top: 1px solid #7f7fb2;
border-bottom: 1px solid #7f7fb2;
}
#ActionsAndOptions:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}

View File

@ -1,5 +1,5 @@
/* /*
* ZoneMinder Base Stylesheet, $Date$, $Revision$ * ZoneMinder Dark Stylesheet, $Date$, $Revision$
* Copyright (C) 2001-2008 Philip Coombes * Copyright (C) 2001-2008 Philip Coombes
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -47,7 +47,7 @@ p {
} }
th { th {
color: #117AAd; color: #10a4e8;
} }
img.normal { img.normal {
@ -147,9 +147,9 @@ fieldset {
border-bottom: 1px solid #000000; border-bottom: 1px solid #000000;
} }
input { input, textarea, select, button, .btn-primary {
background-color: rgb(68,68,68); background-color: rgb(68,68,68);
color: #999; color: #dddddd;
} }
/* PP - make it easy to identify disabled buttons */ /* PP - make it easy to identify disabled buttons */
@ -185,7 +185,8 @@ input[type=submit]:disabled,
} }
.table-hover > tbody > tr:hover { .table-hover > tbody > tr:hover {
background-color: orange; color: orange;
background-color: #444444;
} }
.nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover { .nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover {
@ -216,6 +217,14 @@ li.search-choice {
} }
/* end chosen override */ /* end chosen override */
modal-content { .modal-content {
background-color: #222222; background-color: #222222;
} }
ul.nav.nav-pills.flex-column {
background-color: #485460;
}
.thead-highlight {
background-color:#485460;
}

View File

@ -225,15 +225,15 @@ function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist) {
<h2><?php echo translate('Images').': '.validHtmlStr($event->Name()).( (!empty($otherlinks)) ? ' ('.$otherlinks.') ' : '' ) ?></h2> <h2><?php echo translate('Images').': '.validHtmlStr($event->Name()).( (!empty($otherlinks)) ? ' ('.$otherlinks.') ' : '' ) ?></h2>
<?php <?php
if ( $event->DefaultVideo() ) { if ($event->DefaultVideo()) {
// videojs zoomrotate only when direct recording // videojs zoomrotate only when direct recording
$Zoom = 1; $Zoom = 1;
$Rotation = 0; $Rotation = 0;
$Monitor = $event->Monitor(); $Monitor = $event->Monitor();
if ( $Monitor->VideoWriter() == '2' ) { if ($Monitor->VideoWriter() == '2') {
# Passthrough # Passthrough
$Rotation = $event->Orientation(); $Rotation = $event->Orientation();
if ( in_array($event->Orientation(), array('ROTATE_90','ROTATE_270')) ) if (in_array($event->Orientation(), array('ROTATE_90','ROTATE_270')))
$Zoom = $event->Height()/$event->Width(); $Zoom = $event->Height()/$event->Width();
} # end if passthrough } # end if passthrough
?> ?>
@ -242,7 +242,7 @@ function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist) {
width="<?php echo $event->Width() ?>" width="<?php echo $event->Width() ?>"
height="<?php echo $event->Height() ?>" height="<?php echo $event->Height() ?>"
data-setup='{ "controls": true, "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'> data-setup='{ "controls": true, "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'>
<source src="<?php echo $event->getStreamSrc(array('mode'=>'mpeg','format'=>'h264')); ?>" type="video/mp4"> <source src="<?php echo $event->DefaultVideo(); ?>" type="video/mp4">
<track id="monitorCaption" kind="captions" label="English" srclang="en" src='data:plain/text;charset=utf-8,"WEBVTT\n\n 00:00:00.000 --> 00:00:01.000 ZoneMinder"' default> <track id="monitorCaption" kind="captions" label="English" srclang="en" src='data:plain/text;charset=utf-8,"WEBVTT\n\n 00:00:00.000 --> 00:00:01.000 ZoneMinder"' default>
Your browser does not support the video tag. Your browser does not support the video tag.
</video> </video>
@ -250,7 +250,7 @@ function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist) {
<?php <?php
} else { // end if DefaultVideo } else { // end if DefaultVideo
?> ?>
<ilayer id="slidensmain" width=&{slidewidth}; height=&{slideheight}; bgColor=&{slidebgcolor}; visibility=hide> <ilayer id="slidensmain" width="&{slidewidth};" height="&{slideheight};" bgColor="&{slidebgcolor};" visibility="hide">
<layer id="slidenssub" width="&{slidewidth};" left="auto" top="auto"></layer> <layer id="slidenssub" width="&{slidewidth};" left="auto" top="auto"></layer>
</ilayer> </ilayer>
<div id="imagevideo" align="center"></div> <div id="imagevideo" align="center"></div>
@ -570,30 +570,24 @@ else if (document.layers) window.onload=start_slider;
return ob_get_clean(); return ob_get_clean();
} # end function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist) } # end function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist)
function eventlist_html($Event, $exportDetail, $exportFrames) { function eventlist_html($Event, $exportDetail, $exportFrames, $exportStructure) {
$html = '<div class="event"> $html = '';
'; if ($Event->SaveJPEGs()) {
if ( $Event->SaveJPEGs() ) {
$html .= '<a href="#" onclick="switchevent(\''.$Event->Id().'/zmEventImages.html\');return false;"> $html .= '<a href="#" onclick="switchevent(\''.$Event->Id().'/zmEventImages.html\');return false;">
'; ';
if ( ZM_WEB_LIST_THUMBS ) { if ( ZM_WEB_LIST_THUMBS ) {
$html .= '<img width="'.ZM_WEB_LIST_THUMB_WIDTH.'" src="'. $Event->Id().'/snapshot.jpg" alt="'.$Event->Id().'"/> $html .= '<img width="'.ZM_WEB_LIST_THUMB_WIDTH.'" src="'. $Event->Id().($exportStructure=='flat'?'_':'/').'snapshot.jpg" alt="'.$Event->Id().'"/>
'; ';
} else {
$html .= $Event->Id();
} }
$html .= '</a><br/> $html .= '</a><br/>
'; ';
} # end if has jpegs } # end if has jpegs
if ( $Event->DefaultVideo() ) { if ($Event->DefaultVideo()) {
if ( ZM_WEB_LIST_THUMBS ) { $html .= '<a href="'.$Event->Id().'/'.$Event->DefaultVideo() .'">';
$html .= '<a href="'.$Event->Id().'/'.$Event->DefaultVideo() .'">'; $html .= '<img width="'.ZM_WEB_LIST_THUMB_WIDTH.'" src="'. $Event->Id().($exportStructure=='flat'?'_':'/').'snapshot.jpg" alt="'.$Event->Id().'"/>';
$html .= '<img width="'.ZM_WEB_LIST_THUMB_WIDTH.'" src="'. $Event->Id().'/snapshot.jpg" alt="'.$Event->Id().'"/>'; $html .= '</a><br/>'.PHP_EOL;
$html .= '</a><br/>
';
}
} }
if ( $exportDetail ) { if ($exportDetail) {
$html .= '<a href="#" onclick="switchevent(\''.$Event->Id().'/zmEventDetail.html\');return false;">Detail</a> $html .= '<a href="#" onclick="switchevent(\''.$Event->Id().'/zmEventDetail.html\');return false;">Detail</a>
'; ';
} }
@ -601,12 +595,12 @@ function eventlist_html($Event, $exportDetail, $exportFrames) {
$html .= '<a href="#" onclick="switchevent(\''.$Event->Id().'/zmEventFrames.html\');return false;">Frames</a> $html .= '<a href="#" onclick="switchevent(\''.$Event->Id().'/zmEventFrames.html\');return false;">Frames</a>
'; ';
} }
$html .= '</div><!--event--> if (!$html) $html = $Event->Id();
'; $html = '<div class="event">'.PHP_EOL.$html.PHP_EOL.'</div><!--event-->'.PHP_EOL;
return $html; return $html;
} // end function eventlist_html } // end function eventlist_html
function exportEventImagesMaster($eids, $exportDetail, $exportFrames) { function exportEventImagesMaster($eids, $exportDetail, $exportFrames, $exportStructure) {
ob_start(); ob_start();
exportHeader(translate('Images').' Master'); exportHeader(translate('Images').' Master');
?> ?>
@ -615,7 +609,7 @@ function exportEventImagesMaster($eids, $exportDetail, $exportFrames) {
<?php <?php
$events = ZM\Event::find(array('Id'=>$eids)); $events = ZM\Event::find(array('Id'=>$eids));
foreach ( $events as $event ) { foreach ($events as $event) {
//get monitor id and event id //get monitor id and event id
$eventMonitorId[$event->Id()] = $event->MonitorId(); $eventMonitorId[$event->Id()] = $event->MonitorId();
$eventPath[$event->Id()] = $event->Relative_Path(); $eventPath[$event->Id()] = $event->Relative_Path();
@ -625,7 +619,7 @@ function exportEventImagesMaster($eids, $exportDetail, $exportFrames) {
$monitorNames = array(); $monitorNames = array();
//* //*
if ( !empty($monitors) ) { if (!empty($monitors)) {
$tmp = dbFetchAll('SELECT Id, Name FROM Monitors WHERE Id IN ('.implode(',', $monitors).') '); $tmp = dbFetchAll('SELECT Id, Name FROM Monitors WHERE Id IN ('.implode(',', $monitors).') ');
foreach ( $tmp as $row ) { $monitorNames[$row['Id']] = $row['Name']; } foreach ( $tmp as $row ) { $monitorNames[$row['Id']] = $row['Name']; }
} }
@ -641,31 +635,31 @@ function exportEventImagesMaster($eids, $exportDetail, $exportFrames) {
?> ?>
</ul> </ul>
</div> </div>
<table> <table style="width: 100%;">
<tr> <tr>
<td valign="top" bgcolor="#dddddd" style="padding:10px;"> <td valign="top" bgcolor="#dddddd" style="padding:10px;">
<div class="tab_content" id="all"> <div class="tab_content" id="all">
<h2> All </h2> <h2> All </h2>
<?php <?php
foreach($events as $event) { foreach ($events as $event) {
echo eventlist_html($event, $exportDetail, $exportFrames); echo eventlist_html($event, $exportDetail, $exportFrames, $exportStructure);
} # end foreach event } # end foreach event
?> ?>
</div> </div>
<?php <?php
foreach ( $monitors as $monitor_id ) { foreach ($monitors as $monitor_id) {
echo '<div class="tab_content" id="tab'.$monitor_id.'">'; echo '<div class="tab_content" id="tab'.$monitor_id.'">';
echo '<h2>Monitor: '.$monitorNames[$monitor_id].'</h2>'; echo '<h2>Monitor: '.$monitorNames[$monitor_id].'</h2>';
foreach ( $events as $event ) { foreach ($events as $event) {
if ( $event->MonitorId() == $monitor_id ) { if ($event->MonitorId() == $monitor_id) {
echo eventlist_html($event, $exportDetail, $exportFrames); echo eventlist_html($event, $exportDetail, $exportFrames, $exportStructure);
} # end if its the right monitor } # end if its the right monitor
} # end foreach event } # end foreach event
echo '</div>'; echo '</div>';
} # end foreach monitor } # end foreach monitor
?> ?>
</td><td valign="top"> </td><td valign="top" style="height: 100%;">
<iframe id="myframe" onload="resizeCaller();" name="myframe" src="about:blank" <iframe id="myframe" onload="resizeCaller();" name="myframe" src="about:blank"
scrolling="no" marginwidth="0" marginheight="0" frameborder="0" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"
vspace="0" hspace="0" style="overflow:visible; width:100%; display:none"> vspace="0" hspace="0" style="overflow:visible; width:100%; display:none">
@ -772,53 +766,64 @@ function exportFileList(
$exportVideo, $exportVideo,
$exportMisc $exportMisc
) { ) {
if (!$event) {
if ( !canView('Events') or !$event ) { ZM\Error("Empty event passed to exportFileList");
return;
}
if (!$event->canView()) {
ZM\Error('Can\'t view event '.$event->Id());
return; return;
} }
$eventPath = $event->Path(); $eventPath = $event->Path();
$eventRelativePath = $event->Relative_Path(); $eventRelativePath = $event->Relative_Path();
$files = array(); $files = array();
if ( $dir = opendir($eventPath) ) { if ($dir = opendir($eventPath)) {
while ( ($file = readdir($dir)) !== false ) { while (($file = readdir($dir)) !== false) {
if ( is_file($eventPath.'/'.$file) ) { if (is_file($eventPath.'/'.$file)) {
$files[$file] = $file; $files[$file] = $file;
} }
} }
closedir($dir); closedir($dir);
} }
ZM\Debug(print_r($files, true));
$exportFileList = array(); $exportFileList = array();
if ( $exportDetail ) { if ($exportDetail) {
$file = 'zmEventDetail.html'; $file = 'zmEventDetail.html';
if ( $fp = fopen($eventPath.'/'.$file, 'w') ) { if ($fp = fopen($eventPath.'/'.$file, 'w')) {
fwrite($fp, exportEventDetail($event, $exportFrames, $exportImages)); fwrite($fp, exportEventDetail($event, $exportFrames, $exportImages));
fclose($fp); fclose($fp);
$exportFileList[$file] = $file; $exportFileList[$file] = $file;
} else { } else {
ZM\Error("Can't open event detail export file '$file'"); ZM\Error("Can't open event detail export file '$eventPath/$file'");
} }
} else {
ZM\Debug('Not including detail');
} }
if ( $exportFrames ) { if ($exportFrames) {
$file = 'zmEventFrames.html'; $file = 'zmEventFrames.html';
if ( $fp = fopen($eventPath.'/'.$file, 'w') ) { if ($fp = fopen($eventPath.'/'.$file, 'w')) {
fwrite($fp, exportEventFrames($event, $exportDetail, $exportImages)); fwrite($fp, exportEventFrames($event, $exportDetail, $exportImages));
fclose($fp); fclose($fp);
$exportFileList[$file] = $file; $exportFileList[$file] = $file;
} else { } else {
ZM\Error("Can't open event frames export file '$file'"); ZM\Error("Can't open event frames export file '$eventPath/$file' is writable? ".is_writable($eventPath));
} }
} else {
ZM\Debug('Not including frames');
} }
if ( $exportImages ) { if ($exportImages) {
$filesLeft = array(); $filesLeft = array();
$myfilelist = array(); $myfilelist = array();
foreach ( $files as $file ) { foreach ($files as $file) {
if ( preg_match('/-(?:capture|analyse).jpg$/', $file) ) { if (preg_match('/-(?:capture|analyse).jpg$/', $file)) {
$myfilelist[$file] = $exportFileList[$file] = $file; $myfilelist[$file] = $exportFileList[$file] = $file;
} else if ($exportVideo and preg_match('/\.(?:mpg|mpeg|mov|swf|mp4|mkv|avi|asf|3gp)$/', $file)) {
$exportFileList[$file] = $file;
} else { } else {
$filesLeft[$file] = $file; $filesLeft[$file] = $file;
} }
@ -826,36 +831,27 @@ function exportFileList(
$files = $filesLeft; $files = $filesLeft;
// create an image slider // create an image slider
if ( !empty($myfilelist) ) { $file = 'zmEventImages.html';
$file = 'zmEventImages.html'; if ($fp = fopen($eventPath.'/'.$file, 'w')) {
if ( $fp = fopen($eventPath.'/'.$file, 'w') ) { fwrite($fp, exportEventImages($event, $exportDetail, $exportFrames, $myfilelist));
fwrite($fp, exportEventImages($event, $exportDetail, $exportFrames, $myfilelist)); fclose($fp);
fclose($fp); $exportFileList[$file] = $file;
$exportFileList[$file] = $file; } else {
} else { ZM\Error("Can't open event images export file '$file'");
ZM\Error("Can't open event images export file '$file'");
}
} }
} else {
ZM\Debug('Not including frame images');
} # end if exportImages } # end if exportImages
if ( $exportVideo ) { if ($exportMisc) {
$filesLeft = array(); foreach ($files as $file) {
foreach ( $files as $file ) {
if ( preg_match('/\.(?:mpg|mpeg|mov|swf|mp4|mkv|avi|asf|3gp)$/', $file) ) {
$exportFileList[$file] = $file;
} else {
$filesLeft[$file] = $file;
}
}
$files = $filesLeft;
} # end if exportVideo
if ( $exportMisc ) {
foreach ( $files as $file ) {
$exportFileList[$file] = $file; $exportFileList[$file] = $file;
} }
$files = array(); $files = array();
} else {
ZM\Debug('Not including misc');
} }
ZM\Debug(print_r($exportFileList, true));
return array_values($exportFileList); return array_values($exportFileList);
} # end exportFileList() } # end exportFileList()
@ -869,76 +865,89 @@ function exportEvents(
$exportMisc, $exportMisc,
$exportFormat, $exportFormat,
$exportCompressed, $exportCompressed,
$exportStructure = false $exportStructure = false,
$export_root = 'zmExport'
) { ) {
if ( !canView('Events') ) { if (!(canView('Events') or canView('Snapshots'))) {
ZM\Error('You do not have permission to view events.'); ZM\Error('You do not have permission to view events.');
return false; return false;
} else if ( empty($eids) ) { } else if (empty($eids)) {
ZM\Error('Attempt to export an empty list of events.'); ZM\Error('Attempt to export an empty list of events.');
return false; return false;
} }
if ( !($exportFormat == 'tar' or $exportFormat == 'zip') ) { if (!($exportFormat == 'tar' or $exportFormat == 'zip')) {
ZM\Error("None or invalid exportFormat specified $exportFormat."); ZM\Error("None or invalid exportFormat specified $exportFormat.");
return false; return false;
} }
# Ensure that we are going to be able to do this. # Ensure that we are going to be able to do this.
if ( ! ( mkdir(ZM_DIR_EXPORTS) or file_exists(ZM_DIR_EXPORTS) ) ) { if (!(@mkdir(ZM_DIR_EXPORTS) or file_exists(ZM_DIR_EXPORTS))) {
ZM\Fatal('Can\'t create exports dir at \''.ZM_DIR_EXPORTS.'\''); ZM\Fatal('Can\'t create exports dir at \''.ZM_DIR_EXPORTS.'\'');
} }
chmod(ZM_DIR_EXPORTS, 0700); chmod(ZM_DIR_EXPORTS, 0700);
$export_dir = ZM_DIR_EXPORTS.'/zmExport_'.$connkey; $export_dir = ZM_DIR_EXPORTS.'/'.$export_root.($connkey?'_'.$connkey:'');
# Ensure that we are going to be able to do this. # Ensure that we are going to be able to do this.
if ( ! ( mkdir($export_dir) or file_exists($export_dir) ) ) { if (!(@mkdir($export_dir) or file_exists($export_dir))) {
ZM\Error("Can't create exports dir at '$export_dir'"); ZM\Error("Can't create exports dir at '$export_dir'");
return false; return false;
} }
ZM\Debug("Successfully created dir '$export_dir'");
chmod($export_dir, 0700); chmod($export_dir, 0700);
if ( !chdir($export_dir) ) { if (!chdir($export_dir)) {
ZM\Error("Can't chdir to $export_dir"); ZM\Error("Can't chdir to $export_dir");
return; return;
} }
$export_root = 'zmExport';
$export_listFile = 'zmFileList.txt'; $export_listFile = 'zmFileList.txt';
$exportFileList = array(); $exportFileList = array();
$html_eventMaster = ''; $html_eventMaster = '';
if ( !is_array($eids) ) { if (!is_array($eids)) {
$eids = array($eids); $eids = array($eids);
} }
foreach ( $eids as $eid ) { foreach ($eids as $eid) {
$event = new ZM\Event($eid); $event = new ZM\Event($eid);
if (!$event->canView()) {
global $user;
ZM\Warning('User '.($user?$user['Username']:'').' cannot view event '.$event->Id());
continue;
}
$event_dir = $export_dir.'/'.$event->Id(); $event_dir = $export_dir.'/'.$event->Id();
if ( !(mkdir($event_dir) or file_exists($event_dir)) ) { if (!(@mkdir($event_dir) or file_exists($event_dir))) {
ZM\Error("Can't mkdir $event_dir"); ZM\Error("Can't mkdir $event_dir");
} }
$event_exportFileList = exportFileList($event, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc); $event_exportFileList = exportFileList($event, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc);
$exportFileList = array_merge($exportFileList, $event_exportFileList); $exportFileList = array_merge($exportFileList, $event_exportFileList);
foreach ( $event_exportFileList as $file ) { foreach ($event_exportFileList as $file) {
#if ( preg_match('/\.html$/', $file) ) #if ( preg_match('/\.html$/', $file) )
#continue; #continue;
$cmd = 'cp -as '.$event->Path().'/'.$file.' '.$export_dir.'/'.$event->Id().'/'.$file. ' 2>&1'; if ($exportStructure == 'flat') {
$cmd = 'cp -as '.$event->Path().'/'.$file.' '.$export_dir.'/'.$event->Id().'_'.$file. ' 2>&1';
} else {
$cmd = 'cp -as '.$event->Path().'/'.$file.' '.$export_dir.'/'.$event->Id().'/'.$file. ' 2>&1';
}
exec($cmd, $output, $return); exec($cmd, $output, $return);
ZM\Debug($cmd.' return code: '.$return.' output: '.print_r($output,true)); ZM\Debug($cmd.' return code: '.$return.' output: '.print_r($output,true));
} # end foreach event_exportFile } # end foreach event_exportFile
} # end foreach event } # end foreach event
if ( !symlink(ZM_PATH_WEB.'/'.ZM_SKIN_PATH.'/js/jquery.min.js', $export_dir.'/jquery.min.js') ) if (!(
ZM\Error('Failed linking jquery.min.js'); @symlink(ZM_PATH_WEB.'/'.ZM_SKIN_PATH.'/js/jquery.min.js', $export_dir.'/jquery.min.js')
or
file_exists($export_dir.'/jquery.min.js')
)) {
ZM\Error('Failed linking '.ZM_PATH_WEB.'/'.ZM_SKIN_PATH.'/js/jquery.min.js to '.$export_dir.'/jquery.min.js');
}
//if ( !symlink(ZM_PATH_WEB.'/'.ZM_SKIN_PATH.'/js/video.js', $export_dir.'/video.js') ) //if ( !symlink(ZM_PATH_WEB.'/'.ZM_SKIN_PATH.'/js/video.js', $export_dir.'/video.js') )
//Error("Failed linking video.js"); //Error("Failed linking video.js");
$html_eventMaster_file = 'zmEventImagesMaster.html'; $html_eventMaster_file = 'zmEventImagesMaster.html';
$html_eventMaster_path = $export_dir.'/'.$html_eventMaster_file; $html_eventMaster_path = $export_dir.'/'.$html_eventMaster_file;
if ( ($fp = fopen($html_eventMaster_path, 'w')) ) { if (($fp = fopen($html_eventMaster_path, 'w'))) {
fwrite($fp, exportEventImagesMaster($eids, $exportDetail, $exportFrames)); fwrite($fp, exportEventImagesMaster($eids, $exportDetail, $exportFrames, $exportStructure));
fclose($fp); fclose($fp);
$exportFileList[] = $html_eventMaster_file; $exportFileList[] = $html_eventMaster_file;
} else { } else {
@ -946,58 +955,63 @@ function exportEvents(
} }
$listFile = $export_dir.'/'.$export_listFile; $listFile = $export_dir.'/'.$export_listFile;
if ( !($fp = fopen($listFile, 'w')) ) { if (!($fp = fopen($listFile, 'w'))) {
ZM\Fatal("Can't open event export list file '$listFile'"); ZM\Error("Can't open event export list file '$listFile'");
return false;
} }
foreach ( $exportFileList as $exportFile ) { foreach ($exportFileList as $exportFile) {
$exportFile = 'zmExport'.$connkey.'/'.$exportFile; $exportFile = $export_root.$connkey.'/'.$exportFile;
fwrite($fp, "$exportFile\n"); fwrite($fp, $exportFile.PHP_EOL);
} }
fwrite($fp, "$listFile\n"); fwrite($fp, $listFile.PHP_EOL);
fclose($fp); fclose($fp);
chdir(ZM_DIR_EXPORTS); chdir(ZM_DIR_EXPORTS);
$archive = ''; $archive = '';
if ( $exportFormat == 'tar' ) { if ($exportFormat == 'tar') {
$archive = ZM_DIR_EXPORTS.'/'.$export_root.($connkey?'_'.$connkey:'').'.tar'; $archive = $export_root.($connkey?'_'.$connkey:'').'.tar';
$version = shell_exec('tar -v'); $version = @shell_exec('tar --version');
ZM\Debug("Version $version");
$command = 'tar --create --dereference'; $command = 'tar --create --dereference';
if ( $exportCompressed ) { if ($exportCompressed) {
$archive .= '.gz'; $archive .= '.gz';
$command .= ' --gzip'; $command .= ' --gzip';
$exportFormat .= '.gz'; $exportFormat .= '.gz';
} }
if ( $exportStructure == 'flat' ) { if ($exportStructure == 'flat') {
if ( preg_match('/BSD/i', $version) ) { if (preg_match('/BSD/i', $version)) {
$command .= ' -s \'#^.*/##\''; $command .= ' -s \'#^.*/##\'';
} else { } else {
$command .= ' --xform=\'s#^.+/##x\''; $command .= ' --xform=\'s#^.+/##x\'';
} }
} }
$command .= ' --file='.escapeshellarg($archive); $archive_path = ZM_DIR_EXPORTS.'/'.$archive;
} elseif ( $exportFormat == 'zip' ) { $command .= ' --file='.escapeshellarg($archive_path);
$archive = ZM_DIR_EXPORTS.'/'.$export_root.($connkey?'_'.$connkey:'').'.zip'; } else if ($exportFormat == 'zip') {
$command = 'zip '; $archive = $export_root.($connkey?'_'.$connkey:'').'.zip';
$command .= ($exportStructure == 'flat' ? ' -j ' : ' -r ' ).escapeshellarg($archive); $archive_path = ZM_DIR_EXPORTS.'/'.$archive;
$command = 'zip -r ';
$command .= ($exportStructure == 'flat' ? ' -j ' : '').escapeshellarg($archive_path);
$command .= $exportCompressed ? ' -9' : ' -0'; $command .= $exportCompressed ? ' -9' : ' -0';
} // if $exportFormat } // if $exportFormat
@unlink($archive); @unlink($archive_path);
$command .= ' zmExport_' . $connkey.'/'; $command .= ' '.$export_root.($connkey?'_'.$connkey:'').'/';
ZM\Debug($command);
exec($command, $output, $status); exec($command, $output, $status);
if ( $status ) { if ($status) {
ZM\Error("Command '$command' returned with status $status"); ZM\Error("Command '$command' returned with status $status");
if ( isset($output[0]) ) { if (isset($output[0])) {
ZM\Error('First line of output is \''.$output[0].'\''); ZM\Error('First line of output is \''.$output[0].'\'');
} }
return false; return false;
} }
// clean up temporary files // clean up temporary files
if ( !empty($html_eventMaster) ) { if (!empty($html_eventMaster)) {
unlink($monitorPath.'/'.$html_eventMaster); unlink($monitorPath.'/'.$html_eventMaster);
} }
return '?view=archive&type='.$exportFormat.'&connkey='.$connkey; return '?view=archive&type='.$exportFormat.'&connkey='.$connkey.'&file='.$archive;
} // end function exportEvents } // end function exportEvents

View File

@ -766,25 +766,23 @@ function getAccountCircleHTML($skin, $user=null) {
function getStatusBtnHTML($status) { function getStatusBtnHTML($status) {
$result = ''; $result = '';
if ( canEdit('System') ) { if (canEdit('System')) {
//$result .= '<li class="nav-item dropdown">'.PHP_EOL;
$result .= '<li id="getStatusBtnHTML">'.PHP_EOL; $result .= '<li id="getStatusBtnHTML">'.PHP_EOL;
$result .= '<button type="button" class="btn btn-default navbar-btn" id="stateModalBtn">' .$status. '</button>'.PHP_EOL; $result .= '<button type="button" class="btn btn-default navbar-btn" id="stateModalBtn">' .$status. '</button>'.PHP_EOL;
$result .= '</li>'.PHP_EOL; $result .= '</li>'.PHP_EOL;
//$result .= '</li>'.PHP_EOL;
if ( ZM_SYSTEM_SHUTDOWN ) { if (ZM_SYSTEM_SHUTDOWN) {
$result .= '<li class="navbar-text pr-2 align-self-center">'.PHP_EOL; $result .= '<li class="pr-2">'.PHP_EOL;
$result .= '<button class="btn btn-outline" data-on-click="getShutdownModal" data-toggle="tooltip" data-placement="top" title="' .translate("Shutdown"). '" ><i class="material-icons md-18">power_settings_new</i></button>'.PHP_EOL; $result .= '<button id="shutdownButton" class="btn btn-default navbar-btn" data-on-click="getShutdownModal" data-toggle="tooltip" data-placement="top" title="' .translate('Shutdown'). '"><i class="material-icons md-18">power_settings_new</i></button>'.PHP_EOL;
$result .= '</li>'.PHP_EOL; $result .= '</li>'.PHP_EOL;
} }
} else if ( canView('System') ) { } else if (canView('System')) {
$result .= '<li id="getStatusBtnHTML" class="navbar-text">'.PHP_EOL; $result .= '<li id="getStatusBtnHTML" class="navbar-text">'.PHP_EOL;
$result .= $status.PHP_EOL; $result .= $status.PHP_EOL;
$result .= '</li>'.PHP_EOL; $result .= '</li>'.PHP_EOL;
} }
return $result; return $result;
} }
@ -900,7 +898,6 @@ function xhtmlFooter() {
'js/Server.js', 'js/Server.js',
), true ); ), true );
?> ?>
<script nonce="<?php echo $cspNonce; ?>">var $j = jQuery.noConflict();</script>
<?php <?php
if ( $view == 'event' ) { if ( $view == 'event' ) {
?> ?>
@ -914,7 +911,7 @@ function xhtmlFooter() {
<script src="skins/<?php echo $skin ?>/js/moment.min.js"></script> <script src="skins/<?php echo $skin ?>/js/moment.min.js"></script>
<?php <?php
?> ?>
<script nonce="<?php echo $cspNonce; ?>"> <script nonce="<?php echo $cspNonce; ?>">var $j = jQuery.noConflict();
<?php <?php
if ( $skinJsPhpFile ) { if ( $skinJsPhpFile ) {
require_once( $skinJsPhpFile ); require_once( $skinJsPhpFile );

View File

@ -781,7 +781,7 @@ function logAjaxFail(jqxhr, textStatus, error) {
} }
// Load the Modal HTML via Ajax call // Load the Modal HTML via Ajax call
function getModal(id, parameters) { function getModal(id, parameters, buttonconfig=null) {
$j.getJSON(thisUrl + '?request=modal&modal='+id+'&'+parameters) $j.getJSON(thisUrl + '?request=modal&modal='+id+'&'+parameters)
.done(function(data) { .done(function(data) {
if ( !data ) { if ( !data ) {
@ -790,7 +790,7 @@ function getModal(id, parameters) {
} }
insertModalHtml(id, data.html); insertModalHtml(id, data.html);
manageModalBtns(id); buttonconfig ? buttonconfig() : manageModalBtns(id);
modal = $j('#'+id+'Modal'); modal = $j('#'+id+'Modal');
if ( ! modal.length ) { if ( ! modal.length ) {
console.log('No modal found'); console.log('No modal found');
@ -800,6 +800,14 @@ function getModal(id, parameters) {
.fail(logAjaxFail); .fail(logAjaxFail);
} }
function showModal(id, buttonconfig=null) {
var div = $j('#'+id+'Modal');
if ( ! div.length ) {
getModal(id, buttonconfig);
}
div.modal('show');
}
function manageModalBtns(id) { function manageModalBtns(id) {
// Manage the CANCEL modal button, note data-dismiss="modal" would work better // Manage the CANCEL modal button, note data-dismiss="modal" would work better
var cancelBtn = document.getElementById(id+"CancelBtn"); var cancelBtn = document.getElementById(id+"CancelBtn");

View File

@ -291,8 +291,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<td class="colId"><a <?php echo ($stream_available ? 'href="?view=watch&amp;mid='.$monitor['Id'].'">' : '>') . $monitor['Id'] ?></a></td> <td class="colId"><a <?php echo ($stream_available ? 'href="?view=watch&amp;mid='.$monitor['Id'].'">' : '>') . $monitor['Id'] ?></a></td>
<?php <?php
} }
$imgHTML=''; $imgHTML = '';
if (ZM_WEB_LIST_THUMBS && ($monitor['Status'] == 'Connected') && $running && canView('Stream')) { if (ZM_WEB_LIST_THUMBS && $monitor['Function'] != 'None' && ($monitor['Status'] == 'Connected') && $running && canView('Stream')) {
$options = array(); $options = array();
$ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth();

View File

@ -195,7 +195,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
if ( $video_tag ) { if ( $video_tag ) {
?> ?>
<div id="videoFeed"> <div id="videoFeed">
<video id="videoobj" class="video-js vjs-default-skin" <video autoplay id="videoobj" class="video-js vjs-default-skin"
style="transform: matrix(1, 0, 0, 1, 0, 0);" style="transform: matrix(1, 0, 0, 1, 0, 0);"
<?php echo $scale ? 'width="'.reScale($Event->Width(), $scale).'"' : '' ?> <?php echo $scale ? 'width="'.reScale($Event->Width(), $scale).'"' : '' ?>
<?php echo $scale ? 'height="'.reScale($Event->Height(), $scale).'"' : '' ?> <?php echo $scale ? 'height="'.reScale($Event->Height(), $scale).'"' : '' ?>

View File

@ -195,7 +195,7 @@ echo $navbar = getNavBarHTML();
<form name="selectForm" id="selectForm" method="get" action="?"> <form name="selectForm" id="selectForm" method="get" action="?">
<input type="hidden" name="view" value="filter"/> <input type="hidden" name="view" value="filter"/>
<hr/> <hr/>
<div id="filterSelector"><label for="<?php echo 'Id' ?>"><?php echo translate('UseFilter') ?></label> <div id="filterSelector"><label for="Id"><?php echo translate('UseFilter') ?></label>
<?php <?php
if ( count($filterNames) > 1 ) { if ( count($filterNames) > 1 ) {
echo htmlSelect('Id', $filterNames, $filter->Id(), array('data-on-change-this'=>'selectFilter')); echo htmlSelect('Id', $filterNames, $filter->Id(), array('data-on-change-this'=>'selectFilter'));
@ -210,8 +210,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )
?> ?>
</div> </div>
</form> </form>
<form name="contentForm" id="contentForm" method="post" class="validateFormOnSubmit" action="?view=filter"> <form name="contentForm" id="contentForm" method="post" class="validateFormOnSubmit" action="?view=filter&Id=<?php echo $filter->Id() ?>">
<input type="hidden" name="Id" value="<?php echo $filter->Id() ?>"/>
<input type="hidden" name="action"/> <input type="hidden" name="action"/>
<input type="hidden" name="object" value="filter"/> <input type="hidden" name="object" value="filter"/>
@ -397,7 +396,7 @@ echo htmlSelect( 'filter[Query][sort_asc]', $sort_dirns, $filter->sort_asc() );
</tr> </tr>
</tbody> </tbody>
</table> </table>
<hr/> <div id="ActionsAndOptions">
<div id="actionsTable" class="filterTable"> <div id="actionsTable" class="filterTable">
<fieldset><legend><?php echo translate('Actions') ?></legend> <fieldset><legend><?php echo translate('Actions') ?></legend>
<p> <p>
@ -502,17 +501,17 @@ if ( ZM_OPT_EMAIL ) {
?> ?>
</fieldset> </fieldset>
</div> </div>
<hr/> </div><!--ActionsAndOptions-->
<div id="contentButtons"> <div id="contentButtons">
<button type="button" data-on-click-this="submitToEvents"><?php echo translate('ListMatches') ?></button> <button type="button" data-on-click-this="submitToEvents"><?php echo translate('ListMatches') ?></button>
<button type="button" data-on-click-this="submitToMontageReview"><?php echo translate('ViewMatches') ?></button> <button type="button" data-on-click-this="submitToMontageReview"><?php echo translate('ViewMatches') ?></button>
<button type="button" data-on-click-this="submitToExport"><?php echo translate('ExportMatches') ?></button> <button type="button" data-on-click-this="submitToExport"><?php echo translate('ExportMatches') ?></button>
<button type="button" name="executeButton" id="executeButton" data-on-click-this="executeFilter"><?php echo translate('Execute') ?></button> <button type="submit" name="action" value="execute" id="executeButton"><?php echo translate('Execute') ?></button>
<?php <?php
if ( canEdit('Events') ) { if ( canEdit('Events') ) {
?> ?>
<button type="submit" name="Save" value="Save" data-on-click-this="saveFilter"><?php echo translate('Save') ?></button> <button type="submit" name="action" value="Save" id="Save"><?php echo translate('Save') ?></button>
<button type="submit" name="SaveAs" value="SaveAs" data-on-click-this="saveFilter"><?php echo translate('SaveAs') ?></button> <button type="submit" name="action" value="SaveAs" id="SaveAs"><?php echo translate('SaveAs') ?></button>
<?php <?php
if ( $filter->Id() ) { if ( $filter->Id() ) {
?> ?>

View File

@ -34,54 +34,53 @@ function startDownload(file) {
} }
function exportProgress() { function exportProgress() {
if ( exportTimer ) { if (exportTimer) {
var tickerText = $j('#exportProgressTicker').text(); var tickerText = $j('#exportProgressTicker').text();
if ( tickerText.length < 1 || tickerText.length > 4 ) { if ( tickerText.length < 1 || tickerText.length > 4 ) {
$j('#exportProgressTicker').text('.'); $j('#exportProgressTicker').text('.');
} else { } else {
$j('#exportProgressTicker').append('.'); $j('#exportProgressTicker').append('.');
} }
} else {
console.log("No timer");
} }
} }
function exportResponse(respObj, respText) { function exportResponse(respObj, respText) {
clearInterval(exportTimer); clearInterval(exportTimer);
if ( respObj.result != 'Ok' ) { if (respObj.result != 'Ok') {
$j('#exportProgressTicker').text(respObj.message); $j('#exportProgressTicker').text(respObj.message);
} else { } else {
$j('#exportProgressTicker').text(exportSucceededString); $j('#exportProgressTicker').text(exportSucceededString);
setTimeout(startDownload, 1500, decodeURIComponent(respObj.exportFile)); setTimeout(startDownload, 1500, decodeURIComponent(respObj.exportFile));
} }
return; return;
if ( 0 ) {
var eids = new Array();
for (var i = 0, len=form.elements.length; i < len; i++) {
if ( form.elements[i].name == 'eids[]' ) {
eids[eids.length] = 'eids[]='+form.elements[i].value;
}
}
}
form.submit();
//window.location.replace( thisUrl+'?view='+currentView+'&'+eids.join('&')+'&exportFile='+respObj.exportFile+'&generated='+((respObj.result=='Ok')?1:0) );
} }
function exportEvents( ) { function exportEvents( ) {
var formData = $j('#contentForm').serialize(); var formData = $j('#contentForm').serialize();
$j.ajaxSetup({
timeout: 0
});
$j.getJSON(thisUrl + '?view=event&request=event&action=export', formData) $j.getJSON(thisUrl + '?view=event&request=event&action=export', formData)
.done(exportResponse) .done(exportResponse)
.fail(logAjaxFail); .fail(exportFail);
$j('#exportProgress').removeClass('hidden'); $j('#exportProgress').removeClass('hidden');
$j('#exportProgress').addClass('warnText'); $j('#exportProgress').addClass('warnText');
$j('#exportProgress').text(exportProgressString); $j('#exportProgressText').text(exportProgressString);
//exportProgress();
exportTimer = setInterval(exportProgress, 500); exportTimer = setInterval(exportProgress, 500);
} }
function exportFail() {
clearInterval(exportTimer);
$j('#exportProgress').addClass('errorText');
$j('#exportProgressTicker').text('Failed export');
logAjaxFail();
}
function getEventDetailModal(eid) { function getEventDetailModal(eid) {
$j.getJSON(thisUrl + '?request=modal&modal=eventdetail&eids[]=' + eid) $j.getJSON(thisUrl + '?request=modal&modal=eventdetail&eids[]=' + eid)
.done(function(data) { .done(function(data) {

View File

@ -57,8 +57,8 @@ function validateForm(form) {
form.elements['filter[AutoUnarchive]'].checked || form.elements['filter[AutoUnarchive]'].checked ||
form.elements['filter[UpdateDiskSpace]'].checked || form.elements['filter[UpdateDiskSpace]'].checked ||
form.elements['filter[AutoVideo]'].checked || form.elements['filter[AutoVideo]'].checked ||
form.elements['filter[AutoEmail]'].checked || (form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked) ||
form.elements['filter[AutoMessage]'].checked || (form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked) ||
form.elements['filter[AutoExecute]'].checked || form.elements['filter[AutoExecute]'].checked ||
form.elements['filter[AutoDelete]'].checked || form.elements['filter[AutoDelete]'].checked ||
form.elements['filter[AutoCopy]'].checked || form.elements['filter[AutoCopy]'].checked ||
@ -97,13 +97,13 @@ function updateButtons(element) {
} else if ( form.elements['filter[UpdateDiskSpace]'].checked ) { } else if ( form.elements['filter[UpdateDiskSpace]'].checked ) {
canExecute = true; canExecute = true;
} }
form.elements['executeButton'].disabled = !canExecute; document.getElementById('executeButton').disabled = !canExecute;
if ( form.elements['filter[Name]'].value ) { if ( form.elements['filter[Name]'].value ) {
form.elements['Save'].disabled = false; document.getElementById('Save').disabled = false;
form.elements['SaveAs'].disabled = false; document.getElementById('SaveAs').disabled = false;
} else { } else {
form.elements['Save'].disabled = true; document.getElementById('Save').disabled = true;
form.elements['SaveAs'].disabled = true; document.getElementById('SaveAs').disabled = true;
} }
} }
@ -151,11 +151,6 @@ function resetFilter( element ) {
function submitToEvents(element) { function submitToEvents(element) {
var form = element.form; var form = element.form;
//form.action = '?view=events';
//form.submit();
//console.log(form);
//console.log($j(form).serialize());
//history.replaceState(null, null, '?view=filter&' + $j(form).serialize());
window.location.assign('?view=events&'+$j(form).serialize()); window.location.assign('?view=events&'+$j(form).serialize());
} }
@ -171,23 +166,6 @@ function submitToExport(element) {
window.location.assign('?view=export&'+$j(form).serialize()); window.location.assign('?view=export&'+$j(form).serialize());
} }
function executeFilter( element ) {
var form = element.form;
form.action = thisUrl + '?view=filter';
form.elements['action'].value = 'execute';
form.submit();
//history.replaceState(null, null, '?view=filter&' + $j(form).serialize());
}
function saveFilter( element ) {
var form = element.form;
form.target = window.name;
form.elements['action'].value = element.value;
form.action = thisUrl + '?view=filter';
//form.submit();
// Submit is done by the button type="submit"
}
function deleteFilter( element ) { function deleteFilter( element ) {
var form = element.form; var form = element.form;
if ( confirm( deleteSavedFilterString+" '"+form.elements['filter[Name]'].value+"'?" ) ) { if ( confirm( deleteSavedFilterString+" '"+form.elements['filter[Name]'].value+"'?" ) ) {
@ -350,7 +328,8 @@ function parseRows(rows) {
inputTds.eq(2).children().eq(0).attr('name', 'filter'+stringFilter(term)); inputTds.eq(2).children().eq(0).attr('name', 'filter'+stringFilter(term));
inputTds.eq(2).children().eq(0).attr('id', 'filter'+stringFilter(term)); inputTds.eq(2).children().eq(0).attr('id', 'filter'+stringFilter(term));
} //End for each term/row } //End for each term/row
history.replaceState(null, null, '?view=filter&' + $j('#contentForm').serialize()); // ICON This populates the url bar with contents of the form. I'm not sure why
// history.replaceState(null, null, '?view=filter&' + $j('#contentForm').serialize());
} // parseRows } // parseRows
function stringFilter(term) { function stringFilter(term) {
@ -415,4 +394,4 @@ function initPage() {
parseRows($j('#fieldsTable tbody').children()); parseRows($j('#fieldsTable tbody').children());
} }
$j(document).ready(initPage ); $j(document).ready(initPage);

View File

@ -1,6 +1,8 @@
function submitCamera( element ) { function submitCamera( element ) {
var form = element.form; var form = element.form;
form.target = opener.name; if (opener) {
form.target = opener.name;
}
form.view.value = 'monitor'; form.view.value = 'monitor';
form.submit(); form.submit();
} }

View File

@ -7,23 +7,23 @@ function selectLayout(element) {
var ddm = $j('#zmMontageLayout'); var ddm = $j('#zmMontageLayout');
layout = ddm.val(); layout = ddm.val();
if ( layout_id = parseInt(layout) ) { if (layout_id = parseInt(layout)) {
layout = layouts[layout]; layout = layouts[layout];
for ( var i = 0, length = monitors.length; i < length; i++ ) { for (var i = 0, length = monitors.length; i < length; i++) {
monitor = monitors[i]; monitor = monitors[i];
// Need to clear the current positioning, and apply the new // Need to clear the current positioning, and apply the new
monitor_frame = $j('#monitorFrame'+monitor.id); monitor_frame = $j('#monitorFrame'+monitor.id);
if ( !monitor_frame ) { if (!monitor_frame) {
console.log('Error finding frame for ' + monitor.id); console.log('Error finding frame for ' + monitor.id);
continue; continue;
} }
// Apply default layout options, like float left // Apply default layout options, like float left
if ( layout.Positions['default'] ) { if (layout.Positions['default'] ) {
styles = layout.Positions['default']; styles = layout.Positions['default'];
for ( style in styles ) { for (style in styles) {
console.log("Applying " + style + ' ' + styles[style]); console.log("Applying " + style + ' ' + styles[style]);
monitor_frame.css(style, styles[style]); monitor_frame.css(style, styles[style]);
} }
@ -31,61 +31,72 @@ function selectLayout(element) {
console.log("No default styles to apply" + layout.Positions); console.log("No default styles to apply" + layout.Positions);
} // end if default styles } // end if default styles
if ( layout.Positions['mId'+monitor.id] ) { if (layout.Positions['mId'+monitor.id]) {
styles = layout.Positions['mId'+monitor.id]; styles = layout.Positions['mId'+monitor.id];
for ( style in styles ) { for (style in styles) {
monitor_frame.css(style, styles[style]); monitor_frame.css(style, styles[style]);
} }
} else {
console.log("No Monitor styles to apply");
} // end if specific monitor style } // end if specific monitor style
} // end foreach monitor } // end foreach monitor
setCookie('zmMontageLayout', layout_id, 3600);
if (layouts[layout_id].Name != 'Freeform') { // 'montage_freeform.css' ) {
// For freeform, we don't touch the width/height/scale settings, but we may need to update sizing and scales
setCookie('zmMontageScale', '', 3600);
$j('#scale').val('');
$j('#width').val('0');
}
} // end if a stored layout } // end if a stored layout
if ( ! layout ) { if (!layout) {
console.log('No layout?');
return; return;
} }
setCookie('zmMontageLayout', layout_id, 3600);
if ( layouts[layout_id].Name != 'Freeform' ) { // 'montage_freeform.css' ) {
setCookie('zmMontageScale', '', 3600);
$j('#scale').val('');
$j('#width').val('0');
} else {
// Is freeform, we don't touch the width/height/scale settings, but we may need to update sizing and scales
}
var width = parseInt($j('#width').val()); var width = parseInt($j('#width').val());
var height = parseInt($j('#height').val()); var height = parseInt($j('#height').val());
var scale = $j('#scale').val(); var scale = $j('#scale').val();
for ( var i = 0, length = monitors.length; i < length; i++ ) { for (var i = 0, length = monitors.length; i < length; i++) {
var monitor = monitors[i]; var monitor = monitors[i];
if ( scale ) { var stream_scale = 0;
if (scale) {
stream_scale = scale; stream_scale = scale;
} else if ( width ) { } else if (width) {
stream_scale = parseInt(100*width/monitor.width); stream_scale = parseInt(100*width/monitor.width);
} else if ( height ) { } else if (height) {
stream_scale = parseInt(100*height/monitor.height); stream_scale = parseInt(100*height/monitor.height);
} } else if (layouts[layout_id].Name != 'Freeform') {
var streamImg = document.getElementById('liveStream'+monitor.id); monitor_frame = $j('#monitorFrame'+monitor.id);
if ( streamImg ) { console.log("Monitor frame width : " + monitor_frame.width() + " monitor Width: " + monitor.width);
if ( streamImg.nodeName == 'IMG' ) { if (monitor_frame.width() < monitor.width) {
var src = streamImg.src; stream_scale = parseInt(100 * monitor_frame.width() / monitor.width);
src = src.replace(/scale=\d*/i, 'scale='+scale); // Round to a multiple of 5, so 53 become 50% etc
if ( height == '0' ) { stream_scale = Math.floor(stream_scale/5)*5;
streamImg.style.height = 'auto';
}
if ( src != streamImg.src ) {
streamImg.src = '';
streamImg.src = src;
}
} else if ( streamImg.nodeName == 'APPLET' || streamImg.nodeName == 'OBJECT' ) {
// APPLET's and OBJECTS need to be re-initialized
} }
streamImg.style.width = '100%';
} }
setStreamScale('liveStream'+monitor.id, stream_scale, width, height);
} // end foreach monitor } // end foreach monitor
} // end function selectLayout(element) } // end function selectLayout(element)
function setStreamScale(element_id, scale, width, height) {
var streamImg = document.getElementById(element_id);
if (streamImg) {
if (streamImg.nodeName == 'IMG') {
var src = streamImg.src;
src = src.replace(/scale=\d*/i, 'scale='+scale);
if (height == '0') {
streamImg.style.height = 'auto';
}
if (src != streamImg.src) {
streamImg.src = '';
streamImg.src = src;
}
} else if (streamImg.nodeName == 'APPLET' || streamImg.nodeName == 'OBJECT') {
// APPLET's and OBJECTS need to be re-initialized
}
//streamImg.style.width = '100%';
}
}
/** /**
* called when the widthControl|heightControl select elements are changed * called when the widthControl|heightControl select elements are changed
*/ */

View File

@ -275,17 +275,16 @@ function timerFire() {
clearInterval(timerObj); clearInterval(timerObj);
timerObj = null; timerObj = null;
timerInterval = currentDisplayInterval; timerInterval = currentDisplayInterval;
console.log("Turn off nterrupts timerInterfave" + timerInterval); console.log("Turn off interrupts timerInterfave" + timerInterval);
} }
if ( (currentSpeed > 0 || liveMode != 0) && ! timerObj ) { if ( (currentSpeed > 0 || liveMode != 0) && ! timerObj ) {
timerObj = setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero timerObj = setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero
} }
if ( liveMode ) { if (liveMode) {
console.log("liveMode");
outputUpdate(currentTimeSecs); // In live mode we basically do nothing but redisplay outputUpdate(currentTimeSecs); // In live mode we basically do nothing but redisplay
} else if ( currentTimeSecs + playSecsPerInterval >= maxTimeSecs ) { } else if (currentTimeSecs + playSecsPerInterval >= maxTimeSecs) {
// beyond the end just stop // beyond the end just stop
console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval + " >= " + maxTimeSecs + " so stopping"); console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval + " >= " + maxTimeSecs + " so stopping");
setSpeed(0); setSpeed(0);
@ -499,8 +498,8 @@ function redrawScreen() {
drawGraph(); drawGraph();
} }
var monitors = $j('#monitors');
if ( fitMode == 1 ) { if ( fitMode == 1 ) {
var monitors = $j('#monitors');
var fps = $j('#fps'); var fps = $j('#fps');
var vh = window.innerHeight; var vh = window.innerHeight;
var mh = (vh - monitors.position().top - fps.outerHeight()); var mh = (vh - monitors.position().top - fps.outerHeight());
@ -637,7 +636,7 @@ function showSpeed(val) {
} }
function setSpeed(speed_index) { function setSpeed(speed_index) {
if ( liveMode == 1 ) { if (liveMode == 1) {
console.log("setSpeed in liveMode?"); console.log("setSpeed in liveMode?");
return; // we shouldn't actually get here but just in case return; // we shouldn't actually get here but just in case
} }

View File

@ -1,6 +1,3 @@
var backBtn = $j('#backBtn');
var saveBtn = $j('#saveBtn');
var deleteBtn = $j('#deleteBtn');
// Manage the DELETE CONFIRMATION modal button // Manage the DELETE CONFIRMATION modal button
function manageDelConfirmModalBtns() { function manageDelConfirmModalBtns() {
@ -26,6 +23,31 @@ function manageDelConfirmModalBtns() {
}); });
} }
function downloadResponse(respObj, respText) {
clearInterval(downloadTimer);
if (respObj.result != 'Ok' ) {
$j('#downloadProgressTicker').text(respObj.message);
} else {
$j('#downloadProgressTicker').text(downloadSucceededString);
setTimeout(startDownload, 1500, decodeURIComponent(respObj.exportFile));
}
return;
}
function startDownload(file) {
window.location.replace(file);
}
function downloadProgress() {
if (downloadTimer) {
var tickerText = $j('#downloadProgressTicker').text();
if (tickerText.length < 1 || tickerText.length > 4) {
$j('#downloadProgressTicker').text('.');
} else {
$j('#downloadProgressTicker').append('.');
}
}
}
function initPage() { function initPage() {
// enable or disable buttons based on current selection and user rights // enable or disable buttons based on current selection and user rights
/* /*
@ -33,15 +55,9 @@ function initPage() {
archiveBtn.prop('disabled', !(!eventData.Archived && canEdit.Events)); archiveBtn.prop('disabled', !(!eventData.Archived && canEdit.Events));
unarchiveBtn.prop('disabled', !(eventData.Archived && canEdit.Events)); unarchiveBtn.prop('disabled', !(eventData.Archived && canEdit.Events));
*/ */
saveBtn.prop('disabled', !(canEdit.Events || (snapshot.CreatedBy == user.Id) ));
/*
exportBtn.prop('disabled', !canView.Events);
downloadBtn.prop('disabled', !canView.Events);
*/
deleteBtn.prop('disabled', !canEdit.Events);
// Don't enable the back button if there is no previous zm page to go back to // Don't enable the back button if there is no previous zm page to go back to
backBtn.prop('disabled', !document.referrer.length); $j('#backBtn').prop('disabled', !document.referrer.length);
// Manage the BACK button // Manage the BACK button
bindButton('#backBtn', 'click', null, function onBackClick(evt) { bindButton('#backBtn', 'click', null, function onBackClick(evt) {
@ -56,6 +72,7 @@ function initPage() {
}); });
// Manage the EDIT button // Manage the EDIT button
$j('#saveBtn').prop('disabled', !(canEdit.Events || (snapshot.CreatedBy == user.Id) ));
bindButton('#saveBtn', 'click', null, function onSaveClick(evt) { bindButton('#saveBtn', 'click', null, function onSaveClick(evt) {
/* /*
if ( ! canEdit.Events ) { if ( ! canEdit.Events ) {
@ -63,17 +80,44 @@ function initPage() {
return; return;
} }
*/ */
console.log(evt);
evt.target.form.submit(); evt.target.form.submit();
}); });
/*
// Manage the EXPORT button // Manage the EXPORT button
bindButton('#exportBtn', 'click', null, function onExportClick(evt) { $j('#downloadBtn').prop('disabled', !canView.Snapshots);
bindButton('#downloadBtn', 'click', null, function onDownloadClick(evt) {
evt.preventDefault(); evt.preventDefault();
window.location.assign('?view=export&eids[]='+eventData.Id); formData = {
eids: snapshot.EventIds,
exportImages: 0,
exportVideo: 0,
exportFrames: 0,
exportDetail: 0,
exportMisc: 1,
exportFormat: 'zip',
exportCompress: 0,
exportStructure: 'flat',
exportFile: 'Snapshot'+snapshot.Id
};
$j.getJSON(thisUrl + '?view=event&request=event&action=export', formData)
.done(downloadResponse)
.fail(logAjaxFail);
$j('#downloadProgress').removeClass('hidden');
$j('#downloadProgress').addClass('warnText');
$j('#downloadProgress').text(downloadProgressString);
downloadTimer = setInterval(downloadProgress, 500);
}); });
$j('#exportBtn').prop('disabled', !canView.Snapshots);
bindButton('#exportBtn', 'click', null, function onExportClick(evt) {
console.log('export clicked');
evt.preventDefault();
window.location.assign('?view=export&eids[]='+snapshot.EventIds.join('&eids[]='));
});
/*
// Manage the DOWNLOAD VIDEO button // Manage the DOWNLOAD VIDEO button
bindButton('#downloadBtn', 'click', null, function onDownloadClick(evt) { bindButton('#downloadBtn', 'click', null, function onDownloadClick(evt) {
evt.preventDefault(); evt.preventDefault();
@ -88,6 +132,7 @@ function initPage() {
}); });
*/ */
// Manage the DELETE button // Manage the DELETE button
$j('#deleteBtn').prop('disabled', !canEdit.Events);
bindButton('#deleteBtn', 'click', null, function onDeleteClick(evt) { bindButton('#deleteBtn', 'click', null, function onDeleteClick(evt) {
if ( !canEdit.Events ) { if ( !canEdit.Events ) {
enoperm(); enoperm();

View File

@ -26,5 +26,9 @@ var eventDataStrings = {
// //
var deleteString = "<?php echo validJsStr(translate('Delete')) ?>"; var deleteString = "<?php echo validJsStr(translate('Delete')) ?>";
var causeString = "<?php echo validJsStr(translate('AttrCause')) ?>"; var causeString = "<?php echo validJsStr(translate('AttrCause')) ?>";
var downloadProgressString = "<?php echo validJsStr(translate('Downloading')) ?>";
var downloadFailedString = '<?php echo translate('Download Failed') ?>';
var downloadSucceededString = '<?php echo translate('Download Succeeded') ?>';
var WEB_LIST_THUMB_WIDTH = '<?php echo ZM_WEB_LIST_THUMB_WIDTH ?>'; var WEB_LIST_THUMB_WIDTH = '<?php echo ZM_WEB_LIST_THUMB_WIDTH ?>';
var WEB_LIST_THUMB_HEIGHT = '<?php echo ZM_WEB_LIST_THUMB_HEIGHT ?>'; var WEB_LIST_THUMB_HEIGHT = '<?php echo ZM_WEB_LIST_THUMB_HEIGHT ?>';

View File

@ -90,7 +90,7 @@ function getDelConfirmModal() {
// Manage the DELETE CONFIRMATION modal button // Manage the DELETE CONFIRMATION modal button
function manageDelConfirmModalBtns() { function manageDelConfirmModalBtns() {
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) { document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
if ( ! canEdit.Events ) { if (!canEdit.Events) {
enoperm(); enoperm();
return; return;
} }
@ -98,7 +98,7 @@ function manageDelConfirmModalBtns() {
var selections = getIdSelections(); var selections = getIdSelections();
evt.preventDefault(); evt.preventDefault();
$j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+selections.join('&eids[]=')) $j.getJSON(thisUrl + '?request=snapshots&task=delete&ids[]='+selections.join('&ids[]='))
.done( function(data) { .done( function(data) {
$j('#snapshotTable').bootstrapTable('refresh'); $j('#snapshotTable').bootstrapTable('refresh');
$j('#deleteConfirm').modal('hide'); $j('#deleteConfirm').modal('hide');

View File

@ -73,10 +73,10 @@ function processRows(rows) {
function showEvents() { function showEvents() {
$j('#ptzControls').addClass('hidden'); $j('#ptzControls').addClass('hidden');
$j('#events').removeClass('hidden'); $j('#events').removeClass('hidden');
if ( $j('#eventsControl') ) { if ($j('#eventsControl')) {
$j('#eventsControl').addClass('hidden'); $j('#eventsControl').addClass('hidden');
} }
if ( $j('#controlControl') ) { if ($j('#controlControl')) {
$j('#controlControl').removeClass('hidden'); $j('#controlControl').removeClass('hidden');
} }
showMode = 'events'; showMode = 'events';
@ -85,10 +85,10 @@ function showEvents() {
function showPtzControls() { function showPtzControls() {
$j('#events').addClass('hidden'); $j('#events').addClass('hidden');
$j('#ptzControls').removeClass('hidden'); $j('#ptzControls').removeClass('hidden');
if ( $j('#eventsControl') ) { if ($j('#eventsControl')) {
$j('#eventsControl').removeClass('hidden'); $j('#eventsControl').removeClass('hidden');
} }
if ( $j('#controlControl') ) { if ($j('#controlControl')) {
$j('#controlControl').addClass('hidden'); $j('#controlControl').addClass('hidden');
} }
showMode = 'control'; showMode = 'control';
@ -102,7 +102,7 @@ function changeScale() {
// Always turn it off, we will re-add it below. I don't know if you can add a callback multiple // Always turn it off, we will re-add it below. I don't know if you can add a callback multiple
// times and what the consequences would be // times and what the consequences would be
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active $j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
if ( scale == '0' || scale == 'auto' ) { if (scale == '0' || scale == 'auto') {
var newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus')); var newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus'));
newWidth = newSize.width; newWidth = newSize.width;
newHeight = newSize.height; newHeight = newSize.height;
@ -132,13 +132,13 @@ function setAlarmState(currentAlarmState) {
alarmState = currentAlarmState; alarmState = currentAlarmState;
var stateClass = ''; var stateClass = '';
if ( alarmState == STATE_ALARM ) { if (alarmState == STATE_ALARM) {
stateClass = 'alarm'; stateClass = 'alarm';
} else if ( alarmState == STATE_ALERT ) { } else if (alarmState == STATE_ALERT) {
stateClass = 'alert'; stateClass = 'alert';
} }
$j('#stateValue').text(stateStrings[alarmState]); $j('#stateValue').text(stateStrings[alarmState]);
if ( stateClass ) { if (stateClass) {
$j('#stateValue').addClass(stateClass); $j('#stateValue').addClass(stateClass);
} else { } else {
$j('#stateValue').removeClass(); $j('#stateValue').removeClass();
@ -150,25 +150,25 @@ function setAlarmState(currentAlarmState) {
var newAlarm = ( isAlarmed && !wasAlarmed ); var newAlarm = ( isAlarmed && !wasAlarmed );
var oldAlarm = ( !isAlarmed && wasAlarmed ); var oldAlarm = ( !isAlarmed && wasAlarmed );
if ( newAlarm ) { if (newAlarm) {
table.bootstrapTable('refresh'); table.bootstrapTable('refresh');
if ( SOUND_ON_ALARM ) { if (SOUND_ON_ALARM) {
// Enable the alarm sound // Enable the alarm sound
if ( !msieVer ) { if (!msieVer) {
$j('#alarmSound').removeClass('hidden'); $j('#alarmSound').removeClass('hidden');
} else { } else {
$j('#MediaPlayer').trigger('play'); $j('#MediaPlayer').trigger('play');
} }
} }
if ( POPUP_ON_ALARM ) { if (POPUP_ON_ALARM) {
window.focus(); window.focus();
} }
} }
if ( oldAlarm ) { // done with an event do a refresh if (oldAlarm) { // done with an event do a refresh
table.bootstrapTable('refresh'); table.bootstrapTable('refresh');
if ( SOUND_ON_ALARM ) { if (SOUND_ON_ALARM) {
// Disable alarm sound // Disable alarm sound
if ( !msieVer ) { if (!msieVer) {
$j('#alarmSound').addClass('hidden'); $j('#alarmSound').addClass('hidden');
} else { } else {
$j('#MediaPlayer').trigger('pause'); $j('#MediaPlayer').trigger('pause');
@ -188,12 +188,12 @@ function getStreamCmdError(text, error) {
function getStreamCmdResponse(respObj, respText) { function getStreamCmdResponse(respObj, respText) {
watchdogOk('stream'); watchdogOk('stream');
if ( streamCmdTimer ) { if (streamCmdTimer) {
streamCmdTimer = clearTimeout(streamCmdTimer); streamCmdTimer = clearTimeout(streamCmdTimer);
} }
if ( respObj.result == 'Ok' ) { if (respObj.result == 'Ok') {
// The get status command can get backed up, in which case we won't be able to get the semaphore and will exit. // The get status command can get backed up, in which case we won't be able to get the semaphore and will exit.
if ( respObj.status ) { if (respObj.status) {
streamStatus = respObj.status; streamStatus = respObj.status;
$j('#fpsValue').text(streamStatus.fps); $j('#fpsValue').text(streamStatus.fps);
$j('#capturefpsValue').text(streamStatus.capturefps); $j('#capturefpsValue').text(streamStatus.capturefps);
@ -203,9 +203,9 @@ function getStreamCmdResponse(respObj, respText) {
$j('#levelValue').text(streamStatus.level); $j('#levelValue').text(streamStatus.level);
var newClass = 'ok'; var newClass = 'ok';
if ( streamStatus.level > 95 ) { if (streamStatus.level > 95) {
newClass = 'alarm'; newClass = 'alarm';
} else if ( streamStatus.level > 80 ) { } else if (streamStatus.level > 80) {
newClass = 'alert'; newClass = 'alert';
} }
$j('#levelValue').removeClass(); $j('#levelValue').removeClass();
@ -213,30 +213,30 @@ function getStreamCmdResponse(respObj, respText) {
var delayString = secsToTime(streamStatus.delay); var delayString = secsToTime(streamStatus.delay);
if ( streamStatus.paused == true ) { if (streamStatus.paused == true) {
$j('#modeValue').text('Paused'); $j('#modeValue').text('Paused');
$j('#rate').addClass('hidden'); $j('#rate').addClass('hidden');
$j('#delayValue').text(delayString); $j('#delayValue').text(delayString);
$j('#delay').removeClass('hidden'); $j('#delay').removeClass('hidden');
$j('#level').removeClass('hidden'); $j('#level').removeClass('hidden');
streamCmdPause(false); streamCmdPause(false);
} else if ( streamStatus.delayed == true ) { } else if (streamStatus.delayed == true) {
$j('#modeValue').text('Replay'); $j('#modeValue').text('Replay');
$j('#rateValue').text(streamStatus.rate); $j('#rateValue').text(streamStatus.rate);
$j('#rate').removeClass('hidden'); $j('#rate').removeClass('hidden');
$j('#delayValue').text(delayString); $j('#delayValue').text(delayString);
$j('#delay').removeClass('hidden'); $j('#delay').removeClass('hidden');
$j('#level').removeClass('hidden'); $j('#level').removeClass('hidden');
if ( streamStatus.rate == 1 ) { if (streamStatus.rate == 1) {
streamCmdPlay(false); streamCmdPlay(false);
} else if ( streamStatus.rate > 0 ) { } else if (streamStatus.rate > 0) {
if ( streamStatus.rate < 1 ) { if (streamStatus.rate < 1) {
streamCmdSlowFwd(false); streamCmdSlowFwd(false);
} else { } else {
streamCmdFastFwd(false); streamCmdFastFwd(false);
} }
} else { } else {
if ( streamStatus.rate > -1 ) { if (streamStatus.rate > -1) {
streamCmdSlowRev(false); streamCmdSlowRev(false);
} else { } else {
streamCmdFastRev(false); streamCmdFastRev(false);
@ -251,17 +251,17 @@ function getStreamCmdResponse(respObj, respText) {
} // end if paused or delayed } // end if paused or delayed
$j('#zoomValue').text(streamStatus.zoom); $j('#zoomValue').text(streamStatus.zoom);
if ( streamStatus.zoom == '1.0' ) { if (streamStatus.zoom == '1.0') {
setButtonState('zoomOutBtn', 'unavail'); setButtonState('zoomOutBtn', 'unavail');
} else { } else {
setButtonState('zoomOutBtn', 'inactive'); setButtonState('zoomOutBtn', 'inactive');
} }
if ( canEdit.Monitors ) { if (canEdit.Monitors) {
if ( streamStatus.enabled ) { if (streamStatus.enabled) {
enableAlmBtn.addClass('disabled'); enableAlmBtn.addClass('disabled');
enableAlmBtn.prop('title', disableAlarmsStr); enableAlmBtn.prop('title', disableAlarmsStr);
if ( streamStatus.forced ) { if (streamStatus.forced) {
forceAlmBtn.addClass('disabled'); forceAlmBtn.addClass('disabled');
forceAlmBtn.prop('title', cancelForcedAlarmStr); forceAlmBtn.prop('title', cancelForcedAlarmStr);
} else { } else {
@ -277,16 +277,18 @@ function getStreamCmdResponse(respObj, respText) {
enableAlmBtn.prop('disabled', false); enableAlmBtn.prop('disabled', false);
} // end if canEdit.Monitors } // end if canEdit.Monitors
if ( streamStatus.auth ) { if (streamStatus.auth) {
auth_hash = streamStatus.auth; auth_hash = streamStatus.auth;
// Try to reload the image stream. // Try to reload the image stream.
var streamImg = $j('#liveStream'+monitorId); var streamImg = $j('#liveStream'+monitorId);
if ( streamImg ) { if (streamImg) {
var oldSrc = streamImg.attr('src'); var oldSrc = streamImg.attr('src');
var newSrc = oldSrc.replace(/auth=\w+/i, 'auth='+streamStatus.auth); var newSrc = oldSrc.replace(/auth=\w+/i, 'auth='+streamStatus.auth);
streamImg.attr('src', newSrc); if (oldSrc != newSrc) {
streamImg.attr('src', newSrc);
table.bootstrapTable('refresh');
}
} }
table.bootstrapTable('refresh');
} // end if have a new auth hash } // end if have a new auth hash
} // end if respObj.status } // end if respObj.status
} else { } else {
@ -295,22 +297,20 @@ function getStreamCmdResponse(respObj, respText) {
// If it's an auth error, we should reload the whole page. // If it's an auth error, we should reload the whole page.
console.log("have error"); console.log("have error");
//window.location.reload(); //window.location.reload();
if ( 1 ) { var streamImg = $j('#liveStream'+monitorId);
var streamImg = $j('#liveStream'+monitorId); if (streamImg) {
if ( streamImg ) { var oldSrc = streamImg.attr('src');
var oldSrc = streamImg.attr('src'); var newSrc = oldSrc.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
var newSrc = oldSrc.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
streamImg.attr('src', newSrc); streamImg.attr('src', newSrc);
console.log('Changing livestream src to ' + newSrc); console.log('Changing livestream src to ' + newSrc);
} else { } else {
console.log('Unable to find streamImg liveStream'); console.log('Unable to find streamImg liveStream');
}
} }
} }
var streamCmdTimeout = statusRefreshTimeout; var streamCmdTimeout = statusRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { if (alarmState == STATE_ALARM || alarmState == STATE_ALERT) {
streamCmdTimeout = streamCmdTimeout/5; streamCmdTimeout = streamCmdTimeout/5;
} }
streamCmdTimer = setTimeout(streamCmdQuery, streamCmdTimeout); streamCmdTimer = setTimeout(streamCmdQuery, streamCmdTimeout);
@ -320,15 +320,15 @@ function streamCmdPause(action) {
setButtonState('pauseBtn', 'active'); setButtonState('pauseBtn', 'active');
setButtonState('playBtn', 'inactive'); setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive'); setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive'); setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive');
} }
if ( action ) { if (action) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_PAUSE; data.command = CMD_PAUSE;
streamCmdReq(data); streamCmdReq(data);
} }
@ -337,9 +337,9 @@ function streamCmdPause(action) {
function streamCmdPlay(action) { function streamCmdPlay(action) {
setButtonState('pauseBtn', 'inactive'); setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'active'); setButtonState('playBtn', 'active');
if ( streamStatus.delayed == true ) { if (streamStatus.delayed == true) {
setButtonState('stopBtn', 'inactive'); setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive'); setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive');
@ -347,16 +347,16 @@ function streamCmdPlay(action) {
} }
} else { } else {
setButtonState('stopBtn', 'unavail'); setButtonState('stopBtn', 'unavail');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'unavail'); setButtonState('fastFwdBtn', 'unavail');
setButtonState('slowFwdBtn', 'unavail'); setButtonState('slowFwdBtn', 'unavail');
setButtonState('slowRevBtn', 'unavail'); setButtonState('slowRevBtn', 'unavail');
setButtonState('fastRevBtn', 'unavail'); setButtonState('fastRevBtn', 'unavail');
} }
} }
if ( action ) { if (action) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_PLAY; data.command = CMD_PLAY;
streamCmdReq(data); streamCmdReq(data);
} }
@ -374,15 +374,15 @@ function streamCmdStop(action) {
setButtonState('pauseBtn', 'inactive'); setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'unavail'); setButtonState('playBtn', 'unavail');
setButtonState('stopBtn', 'active'); setButtonState('stopBtn', 'active');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'unavail'); setButtonState('fastFwdBtn', 'unavail');
setButtonState('slowFwdBtn', 'unavail'); setButtonState('slowFwdBtn', 'unavail');
setButtonState('slowRevBtn', 'unavail'); setButtonState('slowRevBtn', 'unavail');
setButtonState('fastRevBtn', 'unavail'); setButtonState('fastRevBtn', 'unavail');
} }
if ( action ) { if (action) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_STOP; data.command = CMD_STOP;
streamCmdReq(data); streamCmdReq(data);
} }
@ -394,15 +394,15 @@ function streamCmdFastFwd(action) {
setButtonState('pauseBtn', 'inactive'); setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive'); setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive'); setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive'); setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive');
} }
if ( action ) { if (action) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_FASTFWD; data.command = CMD_FASTFWD;
streamCmdReq(data); streamCmdReq(data);
} }
@ -412,20 +412,20 @@ function streamCmdSlowFwd(action) {
setButtonState('pauseBtn', 'inactive'); setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive'); setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive'); setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive'); setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'active'); setButtonState('slowFwdBtn', 'active');
setButtonState('slowRevBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive');
} }
if ( action ) { if (action) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_SLOWFWD; data.command = CMD_SLOWFWD;
streamCmdReq(data); streamCmdReq(data);
} }
setButtonState('pauseBtn', 'active'); setButtonState('pauseBtn', 'active');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive');
} }
} }
@ -434,20 +434,20 @@ function streamCmdSlowRev(action) {
setButtonState('pauseBtn', 'inactive'); setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive'); setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive'); setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive'); setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'active'); setButtonState('slowRevBtn', 'active');
setButtonState('fastRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive');
} }
if ( action ) { if (action) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_SLOWREV; data.command = CMD_SLOWREV;
streamCmdReq(data); streamCmdReq(data);
} }
setButtonState('pauseBtn', 'active'); setButtonState('pauseBtn', 'active');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('slowRevBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive');
} }
} }
@ -456,23 +456,23 @@ function streamCmdFastRev(action) {
setButtonState('pauseBtn', 'inactive'); setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive'); setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive'); setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) { if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive'); setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive');
} }
if ( action ) { if (action) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_FASTREV; data.command = CMD_FASTREV;
streamCmdReq(data); streamCmdReq(data);
} }
} }
function streamCmdZoomIn( x, y ) { function streamCmdZoomIn(x, y) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.x = x; data.x = x;
data.y = y; data.y = y;
data.command = CMD_ZOOMIN; data.command = CMD_ZOOMIN;
@ -481,22 +481,22 @@ function streamCmdZoomIn( x, y ) {
function streamCmdZoomOut() { function streamCmdZoomOut() {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_ZOOMOUT; data.command = CMD_ZOOMOUT;
streamCmdReq(data); streamCmdReq(data);
} }
function streamCmdScale( scale ) { function streamCmdScale(scale) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_SCALE; data.command = CMD_SCALE;
data.scale = scale; data.scale = scale;
streamCmdReq(data); streamCmdReq(data);
} }
function streamCmdPan( x, y ) { function streamCmdPan(x, y) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.x = x; data.x = x;
data.y = y; data.y = y;
data.command = CMD_PAN; data.command = CMD_PAN;
@ -505,18 +505,18 @@ function streamCmdPan( x, y ) {
function streamCmdQuery() { function streamCmdQuery() {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = CMD_QUERY; data.command = CMD_QUERY;
streamCmdReq(data); streamCmdReq(data);
} }
function getStatusCmdResponse(respObj, respText) { function getStatusCmdResponse(respObj, respText) {
watchdogOk('status'); watchdogOk('status');
if ( statusCmdTimer ) { if (statusCmdTimer) {
statusCmdTimer = clearTimeout(statusCmdTimer); statusCmdTimer = clearTimeout(statusCmdTimer);
} }
if ( respObj.result == 'Ok' ) { if (respObj.result == 'Ok') {
$j('#fpsValue').text(respObj.monitor.FrameRate); $j('#fpsValue').text(respObj.monitor.FrameRate);
setAlarmState(respObj.monitor.Status); setAlarmState(respObj.monitor.Status);
} else { } else {
@ -556,20 +556,20 @@ function getAlarmCmdResponse(respObj, respText) {
function cmdDisableAlarms() { function cmdDisableAlarms() {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = 'disableAlarms'; data.command = 'disableAlarms';
alarmCmdReq(data); alarmCmdReq(data);
} }
function cmdEnableAlarms() { function cmdEnableAlarms() {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = 'enableAlarms'; data.command = 'enableAlarms';
alarmCmdReq(data); alarmCmdReq(data);
} }
function cmdAlarm() { function cmdAlarm() {
if ( enableAlmBtn.hasClass('disabled') ) { if (enableAlmBtn.hasClass('disabled')) {
cmdEnableAlarms(); cmdEnableAlarms();
} else { } else {
cmdDisableAlarms(); cmdDisableAlarms();
@ -578,23 +578,23 @@ function cmdAlarm() {
function cmdForceAlarm() { function cmdForceAlarm() {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = 'forceAlarm'; data.command = 'forceAlarm';
alarmCmdReq(data); alarmCmdReq(data);
if ( window.event ) window.event.preventDefault(); if (window.event) window.event.preventDefault();
} }
function cmdCancelForcedAlarm() { function cmdCancelForcedAlarm() {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.command = 'cancelForcedAlarm'; data.command = 'cancelForcedAlarm';
alarmCmdReq(data); alarmCmdReq(data);
if ( window.event ) window.event.preventDefault(); if (window.event) window.event.preventDefault();
return false; return false;
} }
function cmdForce() { function cmdForce() {
if ( forceAlmBtn.hasClass('disabled') ) { if (forceAlmBtn.hasClass('disabled')) {
cmdCancelForcedAlarm(); cmdCancelForcedAlarm();
} else { } else {
cmdForceAlarm(); cmdForceAlarm();
@ -608,11 +608,11 @@ function controlReq(data) {
} }
function getControlResponse(respObj, respText) { function getControlResponse(respObj, respText) {
if ( !respObj ) { if (!respObj) {
return; return;
} }
//console.log( respText ); //console.log( respText );
if ( respObj.result != 'Ok' ) { if (respObj.result != 'Ok') {
alert("Control response was status = "+respObj.status+"\nmessage = "+respObj.message); alert("Control response was status = "+respObj.status+"\nmessage = "+respObj.message);
} }
} }
@ -633,7 +633,7 @@ function controlCmd(event) {
var data = {}; var data = {};
if ( event && (xtell || ytell) ) { if (event && (xtell || ytell)) {
var target = event.target; var target = event.target;
var offset = $j(target).offset(); var offset = $j(target).offset();
var width = $j(target).width(); var width = $j(target).width();
@ -642,45 +642,45 @@ function controlCmd(event) {
var x = event.pageX - offset.left; var x = event.pageX - offset.left;
var y = event.pageY - offset.top; var y = event.pageY - offset.top;
if ( xtell ) { if (xtell) {
var xge = parseInt((x*100)/width); var xge = parseInt((x*100)/width);
if ( xtell == -1 ) { if (xtell == -1) {
xge = 100 - xge; xge = 100 - xge;
} else if ( xtell == 2 ) { } else if (xtell == 2) {
xge = 2*(50 - xge); xge = 2*(50 - xge);
} }
data.xge = xge; data.xge = xge;
} }
if ( ytell ) { if (ytell) {
var yge = parseInt((y*100)/height); var yge = parseInt((y*100)/height);
if ( ytell == -1 ) { if (ytell == -1) {
yge = 100 - yge; yge = 100 - yge;
} else if ( ytell == 2 ) { } else if (ytell == 2) {
yge = 2*(50 - yge); yge = 2*(50 - yge);
} }
data.yge = yge; data.yge = yge;
} }
} }
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.control = control; data.control = control;
controlReq(data); controlReq(data);
if ( streamMode == 'single' ) { if (streamMode == 'single') {
setTimeout(fetchImage, 1000, $j('#imageFeed img')); setTimeout(fetchImage, 1000, $j('#imageFeed img'));
} }
} }
function controlCmdImage( x, y ) { function controlCmdImage(x, y) {
var data = {}; var data = {};
if ( auth_hash ) data.auth = auth_hash; if (auth_hash) data.auth = auth_hash;
data.scale = scale; data.scale = scale;
data.control = imageControlMode; data.control = imageControlMode;
data.x = x; data.x = x;
data.y = y; data.y = y;
controlReq(data); controlReq(data);
if ( streamMode == 'single' ) { if (streamMode == 'single') {
setTimeout(fetchImage, 1000, $j('#imageFeed img')); setTimeout(fetchImage, 1000, $j('#imageFeed img'));
} }
} }
@ -701,10 +701,10 @@ function handleClick(event) {
var x = parseInt((event.pageX - pos.left) * scaleX); var x = parseInt((event.pageX - pos.left) * scaleX);
var y = parseInt((event.pageY - pos.top) * scaleY); var y = parseInt((event.pageY - pos.top) * scaleY);
if ( showMode == 'events' || !imageControlMode ) { if (showMode == 'events' || !imageControlMode) {
if ( event.shift ) { if ( event.shift ) {
streamCmdPan(x, y); streamCmdPan(x, y);
} else if ( event.ctrlKey ) { } else if (event.ctrlKey) {
streamCmdZoomOut(); streamCmdZoomOut();
} else { } else {
streamCmdZoomIn(x, y); streamCmdZoomIn(x, y);
@ -715,16 +715,16 @@ function handleClick(event) {
} }
function appletRefresh() { function appletRefresh() {
if ( streamStatus && (!streamStatus.paused && !streamStatus.delayed) ) { if (streamStatus && (!streamStatus.paused && !streamStatus.delayed)) {
var streamImg = $j('#liveStream'+monitorId); var streamImg = $j('#liveStream'+monitorId);
if ( streamImg ) { if (streamImg) {
var parent = streamImg.parent(); var parent = streamImg.parent();
streamImg.remove(); streamImg.remove();
streamImg.append(parent); streamImg.append(parent);
} else { } else {
console.error("Nothing found for liveStream"+monitorId); console.error("Nothing found for liveStream"+monitorId);
} }
if ( appletRefreshTime ) { if (appletRefreshTime) {
setTimeout(appletRefresh, appletRefreshTime*1000); setTimeout(appletRefresh, appletRefreshTime*1000);
} }
} else { } else {
@ -743,8 +743,8 @@ var watchdogFunctions = {
}; };
//Make sure the various refreshes are still taking effect //Make sure the various refreshes are still taking effect
function watchdogCheck( type ) { function watchdogCheck(type) {
if ( watchdogInactive[type] ) { if (watchdogInactive[type]) {
console.log("Detected streamWatch of type: " + type + " stopped, restarting"); console.log("Detected streamWatch of type: " + type + " stopped, restarting");
watchdogFunctions[type](); watchdogFunctions[type]();
watchdogInactive[type] = false; watchdogInactive[type] = false;
@ -753,7 +753,7 @@ function watchdogCheck( type ) {
} }
} }
function watchdogOk( type ) { function watchdogOk(type) {
watchdogInactive[type] = false; watchdogInactive[type] = false;
} }
@ -797,7 +797,7 @@ function getSettingsModal() {
} }
function processClicks(event, field, value, row, $element) { function processClicks(event, field, value, row, $element) {
if ( field == 'Delete' ) { if (field == 'Delete') {
$j.getJSON(monitorUrl + '?request=modal&modal=delconfirm') $j.getJSON(monitorUrl + '?request=modal&modal=delconfirm')
.done(function(data) { .done(function(data) {
insertModalHtml('deleteConfirm', data.html); insertModalHtml('deleteConfirm', data.html);
@ -812,7 +812,7 @@ function processClicks(event, field, value, row, $element) {
// Manage the DELETE CONFIRMATION modal button // Manage the DELETE CONFIRMATION modal button
function manageDelConfirmModalBtns() { function manageDelConfirmModalBtns() {
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) { document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
if ( ! canEdit.Events ) { if (!canEdit.Events) {
enoperm(); enoperm();
return; return;
} }
@ -821,7 +821,7 @@ function manageDelConfirmModalBtns() {
evt.preventDefault(); evt.preventDefault();
$j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+eid) $j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+eid)
.done( function(data) { .done(function(data) {
table.bootstrapTable('refresh'); table.bootstrapTable('refresh');
$j('#deleteConfirm').modal('hide'); $j('#deleteConfirm').modal('hide');
}) })
@ -838,7 +838,7 @@ function msieVer() {
var ua = window.navigator.userAgent; var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE "); var msie = ua.indexOf("MSIE ");
if ( msie >= 0 ) { // If Internet Explorer, return version number if (msie >= 0) { // If Internet Explorer, return version number
return msie; return msie;
} else { // If another browser, return 0 } else { // If another browser, return 0
return 0; return 0;
@ -846,31 +846,31 @@ function msieVer() {
} }
function initPage() { function initPage() {
if ( canView.Control ) { if (canView.Control) {
// Load the PTZ Preset modal into the DOM // Load the PTZ Preset modal into the DOM
if ( monitorControllable ) getCtrlPresetModal(); if (monitorControllable) getCtrlPresetModal();
// Load the settings modal into the DOM // Load the settings modal into the DOM
if ( monitorType == "Local" ) getSettingsModal(); if (monitorType == "Local") getSettingsModal();
} }
if ( monitorType != 'WebSite' ) { if (monitorType != 'WebSite') {
if ( streamMode == 'single' ) { if (streamMode == 'single') {
statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout ); statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'status'); setInterval(watchdogCheck, statusRefreshTimeout*2, 'status');
} else { } else {
streamCmdTimer = setTimeout(streamCmdQuery, (Math.random()+0.1)*statusRefreshTimeout ); streamCmdTimer = setTimeout(streamCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream'); setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream');
} }
if ( canStreamNative || (streamMode == 'single') ) { if (canStreamNative || (streamMode == 'single')) {
var streamImg = $j('#imageFeed img'); var streamImg = $j('#imageFeed img');
if ( !streamImg ) { if (!streamImg) {
streamImg = $j('#imageFeed object'); streamImg = $j('#imageFeed object');
} }
if ( !streamImg ) { if (!streamImg) {
console.error('No streamImg found for imageFeed'); console.error('No streamImg found for imageFeed');
} else { } else {
if ( streamMode == 'single' ) { if (streamMode == 'single') {
streamImg.click(streamImg, fetchImage); streamImg.click(streamImg, fetchImage);
setInterval(fetchImage, imageRefreshTimeout, $j('#imageFeed img')); setInterval(fetchImage, imageRefreshTimeout, $j('#imageFeed img'));
} else { } else {
@ -881,17 +881,17 @@ function initPage() {
} // end if have streamImg } // end if have streamImg
} // streamMode native or single } // streamMode native or single
if ( refreshApplet && appletRefreshTime ) { if (refreshApplet && appletRefreshTime) {
setTimeout(appletRefresh, appletRefreshTime*1000); setTimeout(appletRefresh, appletRefreshTime*1000);
} }
if ( window.history.length == 1 ) { if (window.history.length == 1) {
$j('#closeControl').html(''); $j('#closeControl').html('');
} }
document.querySelectorAll('select[name="scale"]').forEach(function(el) { document.querySelectorAll('select[name="scale"]').forEach(function(el) {
el.onchange = window['changeScale']; el.onchange = window['changeScale'];
}); });
changeScale(); changeScale();
} else if ( monitorRefresh > 0 ) { } else if (monitorRefresh > 0) {
setInterval(reloadWebSite, monitorRefresh*1000); setInterval(reloadWebSite, monitorRefresh*1000);
} }
@ -920,7 +920,7 @@ function initPage() {
settingsBtn.prop('disabled', !(canView.Control && monitorType == 'Local')); settingsBtn.prop('disabled', !(canView.Control && monitorType == 'Local'));
// Init the bootstrap-table // Init the bootstrap-table
if ( monitorType != 'WebSite' ) table.bootstrapTable({icons: icons}); if (monitorType != 'WebSite') table.bootstrapTable({icons: icons});
// Update table rows each time after new data is loaded // Update table rows each time after new data is loaded
table.on('post-body.bs.table', function(data) { table.on('post-body.bs.table', function(data) {

View File

@ -18,7 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// //
if ( !canEdit('Monitors') ) { if (!canEdit('Monitors')) {
$view = 'error'; $view = 'error';
return; return;
} }
@ -31,11 +31,9 @@ function probeV4L() {
$command = getZmuCommand(' --query --device'); $command = getZmuCommand(' --query --device');
if ( !empty($_REQUEST['device']) ) if ( !empty($_REQUEST['device']) )
$command .= '='.escapeshellarg($_REQUEST['device']); $command .= '='.escapeshellarg($_REQUEST['device']);
$result = exec(escapeshellcmd($command), $output, $status); $result = exec(escapeshellcmd($command), $output, $status);
if ( $status ) { if ($status) {
ZM\Error("Unable to probe local cameras using $command, status is '$status' " . implode("\n",$output)); ZM\Warning("Errors while probe local cameras using $command, status is '$status' " . implode("\n", $output));
return $cameras;
} }
$monitors = array(); $monitors = array();
@ -325,15 +323,15 @@ xhtmlHeaders(__FILE__, translate('MonitorProbe') );
<div id="page"> <div id="page">
<h2><?php echo translate('MonitorProbe') ?></h2> <h2><?php echo translate('MonitorProbe') ?></h2>
<div id="content"> <div id="content">
<form name="contentForm" id="contentForm" method="post" action="?"> <form name="contentForm" id="contentForm" method="get" action="?">
<input type="hidden" name="view" value="none"/> <input type="hidden" name="view" value="none"/>
<input type="hidden" name="mid" value="<?php echo validNum($_REQUEST['mid']) ?>"/> <input type="hidden" name="mid" value="<?php echo isset($_REQUEST['mid'])?validNum($_REQUEST['mid']):'' ?>"/>
<p> <p>
<?php echo translate('MonitorProbeIntro') ?> <?php echo translate('MonitorProbeIntro') ?>
</p> </p>
<p> <p>
<label for="probe"><?php echo translate('DetectedCameras') ?></label> <label for="probe"><?php echo translate('DetectedCameras') ?></label>
<?php echo htmlSelect('probe', $cameras, null, array('data-on-change-this'=>'configureButtons(this)')); ?> <?php echo htmlSelect('probe', $cameras, null, array('data-on-change-this'=>'configureButtons')); ?>
</p> </p>
<div id="contentButtons"> <div id="contentButtons">
<button type="button" name="saveBtn" value="Save" data-on-click-this="submitCamera" disabled="disabled"> <button type="button" name="saveBtn" value="Save" data-on-click-this="submitCamera" disabled="disabled">

View File

@ -231,7 +231,7 @@ foreach ( $monitors as $monitor ) {
> >
<?php <?php
$monitor_options = $options; $monitor_options = $options;
$monitor_options['width'] = $monitor_options['width'].'px'; $monitor_options['width'] = $monitor_options['width']?$monitor_options['width'].'px' : null;
$monitor_options['height'] = $monitor_options['height']?$monitor_options['height'].'px' : null; $monitor_options['height'] = $monitor_options['height']?$monitor_options['height'].'px' : null;
$monitor_options['connkey'] = $monitor->connKey(); $monitor_options['connkey'] = $monitor->connKey();

View File

@ -59,9 +59,8 @@ if ( !$snapshot->Id() ) {
<button id="editBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Edit') ?>" disabled><i class="fa fa-pencil"></i></button> <button id="editBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Edit') ?>" disabled><i class="fa fa-pencil"></i></button>
--> -->
<button id="saveBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Save') ?>"><i class="fa fa-save"></i></button> <button id="saveBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Save') ?>"><i class="fa fa-save"></i></button>
<!--
<button id="exportBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Export') ?>"><i class="fa fa-external-link"></i></button> <button id="exportBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Export') ?>"><i class="fa fa-external-link"></i></button>
--> <button id="downloadBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Download') ?>" disabled><i class="fa fa-download"></i></button>
<button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>"><i class="fa fa-trash"></i></button> <button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>"><i class="fa fa-trash"></i></button>
<?php } // end if snapshot->Id ?> <?php } // end if snapshot->Id ?>
</div> </div>
@ -96,6 +95,27 @@ if ( !$snapshot->Id() ) {
?> ?>
</div><!--content--> </div><!--content-->
<?php } // end if snapshot->Id() ?> <?php } // end if snapshot->Id() ?>
</form> </form>
</div><!--page--> <h2 id="downloadProgress" class="<?php
if ( isset($_REQUEST['generated']) ) {
if ( $_REQUEST['generated'] )
echo 'infoText';
else
echo 'errorText';
} else {
echo 'hidden warnText';
}
?>">
<span id="downloadProgressText">
<?php
if ( isset($_REQUEST['generated']) ) {
if ( $_REQUEST['generated'] )
echo translate('Download Succeeded');
else
echo translate('Download Failed');
}
?></span>
<span id="downloadProgressTicker"></span>
</h2>
</div><!--page-->
<?php xhtmlFooter() ?> <?php xhtmlFooter() ?>

View File

@ -18,7 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// //
if ( !canView('Events') ) { if (!(canView('Events') or canView('Snapshots'))) {
$view = 'error'; $view = 'error';
return; return;
} }
@ -53,9 +53,11 @@ if ( !$mimetype ) {
} }
$connkey = isset($_REQUEST['connkey'])?$_REQUEST['connkey']:''; $connkey = isset($_REQUEST['connkey'])?$_REQUEST['connkey']:'';
$filename = "zmExport_$connkey.$file_ext"; $filename = isset($_REQUEST['file'])?$_REQUEST['file']:"zmExport_$connkey.$file_ext";
$filename = str_replace('/', '', $filename); # protect system files. must be a filename, not a path
$filename_path = ZM_DIR_EXPORTS.'/'.$filename; $filename_path = ZM_DIR_EXPORTS.'/'.$filename;
ZM\Debug("downloading archive from $filename_path"); ZM\Debug('downloading archive from '.$filename_path);
if ( is_readable($filename_path) ) { if ( is_readable($filename_path) ) {
while (ob_get_level()) { while (ob_get_level()) {
ob_end_clean(); ob_end_clean();

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