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]
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
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

View File

@ -9,7 +9,7 @@ on:
jobs:
build:
runs-on: ubuntu-16.04
runs-on: zm-xenial-ci
steps:
- 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)
- RHEL/CentOS and clones 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
- Arch via the [AUR](https://aur.archlinux.org/packages/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),
`RTSPServer` BOOLEAN NOT NULL DEFAULT FALSE,
`RTSPStreamName` varchar(255) NOT NULL default '',
`Importance` enum('Not','Less','Normal'),
`Importance` enum('Normal','Less','Not') NOT NULL default 'Normal',
PRIMARY KEY (`Id`)
) 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
Name: zoneminder
Version: 1.36.5
Version: 1.36.9
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
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
%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
- 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
---------------------------------------------------------
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?
---------------------------------------

View File

@ -56,13 +56,13 @@ Add the following to the /etc/apt/sources.list.d/zoneminder.list file
::
# 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:
.. 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.
::
@ -158,7 +158,7 @@ You are now ready to go with ZoneMinder. Open a browser and type either ``localh
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
@ -204,7 +204,7 @@ Add the following to the bottom of the file
::
# 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+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.

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:
* 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
* 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
@ -179,12 +179,12 @@ Storage Tab
The storage section allows for each monitor to configure if and how video and audio are recorded.
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.
* 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.
* 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.
* 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 individual JPEG frames with analysis information overlaid.
Video Writer
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.
* 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.
* 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.
* 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.

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`.
* **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`.
* **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.
* **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.

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``.
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
- 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
- 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
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
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
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.
@ -3093,7 +3093,7 @@ Returns a L<ONVIF::Device::Elements::SetRelayOutputStateResponse|ONVIF::Device::
=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.
@ -3288,7 +3288,7 @@ Returns a L<ONVIF::Device::Elements::GetSystemUrisResponse|ONVIF::Device::Elemen
=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.
@ -3298,7 +3298,7 @@ Returns a L<ONVIF::Device::Elements::StartFirmwareUpgradeResponse|ONVIF::Device:
=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.

View File

@ -147,7 +147,7 @@ This attribute is of type L<SOAP::WSDL::XSD::Typelib::Builtin::integer|SOAP::WSD
=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
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.

View File

@ -44,7 +44,7 @@ not checked yet.
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>
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
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,
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
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.

View File

@ -44,7 +44,7 @@ not checked yet.
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>
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
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,
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,
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,
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
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
ref - this may result in invalid XML if used improperly, though. Note that
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,
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,
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,
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,
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,
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,
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.
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)
Please visit the ZoneMinder [SSMTP Wiki page](https://wiki.zoneminder.com/How_to_get_ssmtp_working_with_Zoneminder)
for setup and configuration help.
`,
type => $types{boolean},

View File

@ -220,14 +220,14 @@ sub moveConUpRight {
my $self = shift;
Debug('Move Diagonally Up Right');
$$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});
}
sub moveConDownRight {
my $self = shift;
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->sendCmd('cgi-bin/ptz.cgi?action=start&'.$$self{LastCmd});
}
@ -236,7 +236,7 @@ sub moveConUpLeft {
my $self = shift;
Debug('Move Diagonally Up Left');
$$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});
}
@ -244,7 +244,7 @@ sub moveConDownLeft {
my $self = shift;
Debug('Move Diagonally Down Left');
$$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});
}

View File

@ -283,7 +283,7 @@ None by default.
=head1 SEE ALSO
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

View File

@ -283,7 +283,7 @@ sub presetSet
my $self = shift;
my $params = shift;
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 );
}
@ -294,7 +294,7 @@ sub presetGoto
my $self = shift;
my $params = shift;
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 );
}

View File

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

View File

@ -127,9 +127,11 @@ sub Execute {
foreach my $term ( @{$$self{PostSQLConditions}} ) {
if ( $$term{attr} eq 'ExistsInFileSystem' ) {
foreach my $row ( @results ) {
my $event = new ZoneMinder::Event($row);
my $event = new ZoneMinder::Event($$row{Id}, $row);
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}) ) {
$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_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
} elsif ( $term->{attr} eq 'EndDateTime' ) {
$self->{Sql} .= 'E.EndDateTime';
} elsif ( $term->{attr} eq 'EndDate' ) {
$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' ) {
$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 )';
if ( $term->{attr} eq 'ExistsInFileSystem' ) {
# PostCondition, so no further SQL
} else {
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
# EndTIme options
} elsif ( $term->{attr} eq 'EndDateTime' ) {
$self->{Sql} .= 'E.EndDateTime';
} elsif ( $term->{attr} eq 'EndDate' ) {
$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' ) {
$value = '(SELECT * FROM Stats WHERE EventId=E.Id AND Score > 0 AND ZoneId='.$value.')';
} elsif ( $term->{attr} =~ /^MonitorName/ ) {
$value = "'$temp_value'";
} elsif ( $term->{attr} =~ /ServerId/) {
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
if ( $temp_value eq 'ZM_SERVER_ID' ) {
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
# This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server($ZoneMinder::Config::Config{ZM_SERVER_ID});
} elsif ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = "'$temp_value'";
# This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server($temp_value);
}
} 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 {
if ( $term->{attr} eq 'ExistsInFileSystem' ) {
# PostCondition, so no further SQL
} else {
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
if ( $term->{attr} eq 'AlarmedZoneId' ) {
$value = '(SELECT * FROM Stats WHERE EventId=E.Id AND Score > 0 AND ZoneId='.$value.')';
} elsif ( $term->{attr} =~ /^MonitorName/ ) {
$value = "'$temp_value'";
} elsif ( $term->{attr} =~ /ServerId/) {
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
if ( $temp_value eq 'ZM_SERVER_ID' ) {
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
# This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server($ZoneMinder::Config::Config{ZM_SERVER_ID});
} elsif ( $temp_value eq 'NULL' ) {
$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;
} # end foreach temp_value
} # end if has an attr
} 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;
}
push @value_list, $value;
} # end foreach temp_value
if ( $term->{op} ) {
if ( $term->{op} eq '=~' ) {

View File

@ -136,8 +136,8 @@ $serial = $primary_key = 'Id';
%defaults = (
ServerId => 0,
StorageId => 0,
Type => 'Ffmpeg',
Function => 'Mocord',
Type => q`'Ffmpeg'`,
Function => q`'Mocord'`,
Enabled => 1,
LinkedMonitors => undef,
Device => '',
@ -166,15 +166,15 @@ $serial = $primary_key = 'Id';
VideoWriter => 0,
OutputCodec => 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,
RTSPDescribe=>0,
Brightness => -1,
Contrast => -1,
Hue => -1,
Colour => -1,
EventPrefix => 'Event-',
LabelFormat => '%N - %d/%m/%y %H:%M:%S',
EventPrefix => q`'Event-'`,
LabelFormat => '',
LabelX => 0,
LabelY => 0,
LabelSize => 1,
@ -208,13 +208,13 @@ $serial = $primary_key = 'Id';
DefaultRate => 100,
DefaultScale => 100,
SignalCheckPoints => 0,
SignalCheckColour => '#0000BE',
WebColour => '#ff0000',
SignalCheckColour => q`'#0000BE'`,
WebColour => q`'#ff0000'`,
Exif => 0,
Sequence => undef,
ZoneCount => 0,
Refresh => undef,
DefaultCodec => 'auto',
DefaultCodec => q`'auto'`,
Latitude => undef,
Longitude => undef,
);
@ -279,21 +279,37 @@ sub disconnect {
sub suspendMotionDetection {
my $self = shift;
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::Memory::zmMonitorSuspend($self);
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 {
my $self = shift;
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::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;
}

View File

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

View File

@ -61,12 +61,12 @@ GetOptions(
'autostop' =>\$options{autostop},
) or pod2usage(-exitstatus => -1);
if ( !$id ) {
if (!$id) {
print(STDERR "Please give a valid monitor id\n");
pod2usage(-exitstatus => -1);
}
( $id ) = $id =~ /^(\w+)$/;
($id) = $id =~ /^(\w+)$/;
logInit($id?(id=>'zmcontrol_'.$id):());
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);
if ( $options{command} ) {
if ($options{command}) {
# Have a command, so we are the client, connect to the server and send it.
my $tries = 10;
@ -101,18 +101,16 @@ if ( $options{command} ) {
Error("Unable to connect to zmcontrol server at $sock_file");
}
} else {
# The server isn't there
my $monitor = zmDbGetMonitorAndControl($id);
if ( !$monitor ) {
Fatal("Unable to load control data for monitor $id");
}
Fatal("Unable to load control data for monitor $id") if !$monitor;
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');
}
if ( -x $protocol ) {
if (-x $protocol) {
# Protocol is actually a script!
# Holdover from previous versions
my $command .= $protocol.' '.$arg_string;
@ -120,11 +118,11 @@ if ( $options{command} ) {
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() ) {
if ($status || logDebugging()) {
chomp($output);
Debug("Output: $output");
}
if ( $status ) {
if ($status) {
Error("Command '$command' exited with status: $status");
exit($status);
}
@ -134,7 +132,7 @@ if ( $options{command} ) {
Info("Starting control server $id/$protocol");
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");
}
@ -159,7 +157,7 @@ if ( $options{command} ) {
$control->open();
# If we have a command when starting up, then do it.
if ( $options{command} ) {
if ($options{command}) {
my $command = $options{command};
$control->$command(\%options);
}

View File

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

View File

@ -27,7 +27,7 @@ zmupdate.pl - check and upgrade ZoneMinder database
=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

View File

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

View File

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

View File

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

View File

@ -89,7 +89,7 @@ std::string load_monitor_sql =
"`SectionLength`, `MinSectionLength`, `FrameSkip`, `MotionFrameSkip`, "
"`FPSReportInterval`, `RefBlendPerc`, `AlarmRefBlendPerc`, `TrackMotion`, `Exif`,"
"`RTSPServer`, `RTSPStreamName`,"
"`SignalCheckPoints`, `SignalCheckColour`, `Importance`-2 FROM `Monitors`";
"`SignalCheckPoints`, `SignalCheckColour`, `Importance`-1 FROM `Monitors`";
std::string CameraType_Strings[] = {
"Local",
@ -151,12 +151,12 @@ bool Monitor::MonitorLink::connect() {
Debug(1, "link.mem.size=%jd", mem_size);
#if ZM_MEM_MAPPED
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));
disconnect();
return false;
}
while ( map_fd <= 2 ) {
while (map_fd <= 2) {
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);
close(map_fd);
@ -164,31 +164,31 @@ bool Monitor::MonitorLink::connect() {
}
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));
disconnect();
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));
disconnect();
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);
disconnect();
return false;
}
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));
disconnect();
return false;
}
#else // ZM_MEM_MAPPED
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));
connected = false;
return false;
@ -444,7 +444,7 @@ Monitor::Monitor()
"SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, "
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif,"
"`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) {
@ -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());
col++;
function = (Function)atoi(dbrow[col]); col++;
enabled = dbrow[col] ? atoi(dbrow[col]) : 0; col++;
decoding_enabled = dbrow[col] ? atoi(dbrow[col]) : 0; col++;
enabled = dbrow[col] ? atoi(dbrow[col]) : false; 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++;
@ -594,7 +604,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
rtsp_server = (*dbrow[col] != '0'); 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_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 */
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
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));
}
// 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_fifo ) {
diag_path_ref = stringtf("%s/diagpipe-r-%d.jpg", staticConfig.PATH_SOCKS.c_str(), id);
@ -1061,7 +1060,13 @@ bool Monitor::disconnect() {
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
msync(mem_ptr, mem_size, MS_ASYNC);
munmap(mem_ptr, mem_size);
@ -1071,9 +1076,6 @@ bool Monitor::disconnect() {
mem_ptr = 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
struct shmid_ds shm_data;
if (shmctl(shm_id, IPC_STAT, &shm_data) < 0) {
@ -1094,7 +1096,7 @@ bool Monitor::disconnect() {
}
#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.
delete image_buffer[i];
image_buffer[i] = nullptr;
@ -1108,10 +1110,6 @@ Monitor::~Monitor() {
if (mem_ptr != nullptr) {
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);
} // end if purpose != query
disconnect();
@ -1744,10 +1742,6 @@ bool Monitor::Analyse() {
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
bool signal = shared_data->signal;
bool signal_change = (signal != last_signal);
@ -1857,7 +1851,14 @@ bool Monitor::Analyse() {
while (!snap->decoded and !zm_terminate and !analysis_thread->Stopped()) {
// Need to wait for the decoder thread.
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) {
Debug(1, "No image but was decoded, giving up");
delete packet_lock;
@ -1960,14 +1961,14 @@ bool Monitor::Analyse() {
// Must start on a keyframe so rewind. Only for passthrough though I guess.
// FIXME this iterator is not protected from invalidation
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
ZMLockedPacket *starting_packet_lock = 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);
if (!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);
// 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);
// Have added the packet, don't want to unlock it until we have locked the next
packetqueue.increment_it(start_it);
if ((*start_it) == snap_it) {
if ((*start_it) == *analysis_it) {
if (starting_packet_lock) delete starting_packet_lock;
break;
}
@ -2025,8 +2026,7 @@ bool Monitor::Analyse() {
} // end if ! event
} // end if RECORDING
if (score) {
if (score and (function != MONITOR)) {
if ((state == IDLE) || (state == TAPE) || (state == PREALARM)) {
// If we should end then previous continuous event and start a new non-continuous event
if (event && event->Frames()
@ -2064,12 +2064,12 @@ bool Monitor::Analyse() {
if (!event) {
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)
);
ZMLockedPacket *starting_packet_lock = 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);
if (!starting_packet_lock) return false;
starting_packet = starting_packet_lock->packet_;
@ -2084,11 +2084,11 @@ bool Monitor::Analyse() {
shared_data->state = state = ALARM;
// 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);
packetqueue.increment_it(start_it);
if ( (*start_it) == snap_it ) {
if ( (*start_it) == (*analysis_it) ) {
if (starting_packet_lock) delete starting_packet_lock;
break;
}
@ -2279,6 +2279,7 @@ bool Monitor::Analyse() {
if (function == MODECT or function == MOCORD)
UpdateAnalysisFPS();
}
packetqueue.increment_it(analysis_it);
packetqueue.unlock(packet_lock);
shared_data->last_read_time = time(nullptr);
@ -3057,7 +3058,7 @@ int Monitor::PrimeCapture() {
Debug(1, "Creating decoder thread");
decoder = ZM::make_unique<DecoderThread>(this);
} else {
Debug(1, "Restartg decoder thread");
Debug(1, "Restarting decoder thread");
decoder->Start();
}
}

View File

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

View File

@ -41,7 +41,6 @@ class MonitorStream : public StreamBase {
time_t ttl;
int playback_buffer;
bool delayed;
int frame_count;
protected:
bool checkSwapPath(const char *path, bool create_path);
@ -62,9 +61,9 @@ class MonitorStream : public StreamBase {
temp_write_index(0),
ttl(0),
playback_buffer(0),
delayed(false),
frame_count(0) {
}
delayed(false)
{}
void setStreamBuffer(int 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) {
while (packet_counts[video_stream_id] > max_video_packet_count) {
Error("Unable to free up older packets. Waiting.");
condition.notify_all();
condition.wait(lck);
if (deleting or zm_terminate)
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.
// Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them.
if (deleting) return;
if (!pktQueue.size()) return;
if (keep_keyframes and ! (
add_packet->packet.stream_index == video_stream_id
@ -197,7 +199,6 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
return;
}
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
int tail_count = 0;
@ -257,15 +258,12 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
++it;
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
while (*it != add_packet) {
zm_packet = *it;
lp = new ZMLockedPacket(zm_packet);
if (!lp->trylock()) {
Debug(3, "Failed locking packet %d", zm_packet->image_index);
delete lp;
break;
}
@ -282,17 +280,16 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
next_front = it;
}
++video_packets_to_delete;
Debug(4, "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);
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);
if (packet_counts[video_stream_id] - video_packets_to_delete <= pre_event_video_packet_count + tail_count) {
break;
}
}
++it;
} // end while
}
} // 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 ),
( next_front == pktQueue.begin() )
);
@ -325,6 +322,8 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
void PacketQueue::clear() {
deleting = true;
condition.notify_all();
if (!packet_counts) // special case, not initialised
return;
Debug(1, "Clearing packetqueue");
std::unique_lock<std::mutex> lck(mutex);
@ -662,3 +661,12 @@ void PacketQueue::setPreEventVideoPackets(int p) {
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
}
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);
void unlock(ZMLockedPacket *lp);
void notify_all();
void wait();
};
#endif /* ZM_PACKETQUEUE_H */

View File

@ -100,7 +100,8 @@ void RemoteCamera::Initialise() {
int ret = getaddrinfo(host.c_str(), port.c_str(), &hints, &hp);
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;
int addr_count = 0;

View File

@ -144,6 +144,14 @@ void RemoteCameraHttp::Initialise() {
int RemoteCameraHttp::Connect() {
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 ) {
sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if ( sd < 0 ) {

View File

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

View File

@ -102,7 +102,6 @@ protected:
int last_scale;
int zoom;
int last_zoom;
double maxfps;
int bitrate;
unsigned short last_x, last_y;
unsigned short x, y;
@ -122,8 +121,14 @@ protected:
struct timeval now;
struct timeval last_comm_update;
double base_fps;
double effective_fps;
double maxfps;
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;
double last_frame_sent;
@ -154,7 +159,6 @@ public:
last_scale(DEFAULT_SCALE),
zoom(DEFAULT_ZOOM),
last_zoom(DEFAULT_ZOOM),
maxfps(DEFAULT_MAXFPS),
bitrate(DEFAULT_BITRATE),
last_x(0),
last_y(0),
@ -166,7 +170,15 @@ public:
sd(-1),
lock_fd(0),
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_addr, 0, sizeof(loc_addr));
@ -174,12 +186,8 @@ public:
memset(&rem_addr, 0, sizeof(rem_addr));
memset(&sock_path_lock, 0, sizeof(sock_path_lock));
base_fps = 0.0;
effective_fps = 0.0;
frame_mod = 1;
#if HAVE_LIBAVCODEC
vid_stream = 0;
vid_stream = nullptr;
#endif // HAVE_LIBAVCODEC
last_frame_sent = 0.0;
last_frame_timestamp = {};

View File

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

View File

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

View File

@ -223,7 +223,7 @@ setdebpkgname () {
if [ "" == "$VERSION" ]; then
export VERSION="${versionfile}~${thedate}.${numcommits}"
fi
export RELEASE="${DIST}"
export RELEASE="${DIST}${PACKAGE_VERSION}"
checkvars
@ -369,7 +369,7 @@ elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ] || [ "${OS}" == "raspbia
setdebpkgname
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
elif [ "${DIST}" == "beowulf" ]; then
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');
}
if ( canView('Events') ) {
if ( canView('Events') or canView('Snapshots') ) {
switch ( $_REQUEST['action'] ) {
case 'video' :
if ( empty($_REQUEST['videoFormat']) ) {
@ -74,10 +74,15 @@ if ( canView('Events') ) {
else
$exportCompress = false;
if ( !empty($_REQUEST['exportStructure']) )
$exportStructure = $_SESSION['export']['structure'] = $_REQUEST['exportStructure'];
else
$exportStructure = false;
session_write_close();
$exportIds = !empty($_REQUEST['eids']) ? $_REQUEST['eids'] : $_REQUEST['id'];
if ( $exportFile = exportEvents(
if ($exportFile = exportEvents(
$exportIds,
(isset($_REQUEST['connkey'])?$_REQUEST['connkey']:''),
$exportDetail,
@ -86,11 +91,14 @@ if ( canView('Events') ) {
$exportVideo,
$exportMisc,
$exportFormat,
$exportCompress
) )
ajaxResponse(array('exportFile'=>$exportFile));
else
$exportCompress,
$exportStructure,
(!empty($_REQUEST['exportFile'])?$_REQUEST['exportFile']:'zmExport'),
)) {
ajaxResponse(array('exportFile'=>$exportFile));
} else {
ajaxError('Export Failed');
}
break;
case 'download' :
require_once(ZM_SKIN_PATH.'/includes/export_functions.php');
@ -104,7 +112,7 @@ if ( canView('Events') ) {
false,#detail
false,#frames
false,#images
$exportVideo,
true, #$exportVideo,
false,#Misc
$exportFormat,
false#,#Compress

View File

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

View File

@ -266,7 +266,7 @@ class MonitorsController extends AppController {
if ($mToken) {
$auth = ' -T '.$mToken;
} 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') {
# 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');;

View File

@ -627,6 +627,29 @@ class Event extends ZM_Object {
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
?>

View File

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

View File

@ -434,6 +434,11 @@ class ZM_Object {
$row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($this->Id()));
if ( !$row ) {
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() {

View File

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

View File

@ -29,6 +29,7 @@ class Snapshot extends ZM_Object {
public function delete() {
if ( property_exists($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;
// Event scope actions, view permissions only required
if ( !canView('Events') ) {
if (!canView('Events')) {
$error_message = 'You do not have permission to view Events.';
ZM\Warning($error_message);
return;
}
if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
if ( $action == 'addterm' ) {
if (isset($_REQUEST['object']) and ($_REQUEST['object'] == 'filter')) {
if ($action == 'addterm') {
$_REQUEST['filter'] = addFilterTerm($_REQUEST['filter'], $_REQUEST['line']);
} elseif ( $action == 'delterm' ) {
} else if ($action == 'delterm') {
$_REQUEST['filter'] = delFilterTerm($_REQUEST['filter'], $_REQUEST['line']);
} else if ( canEdit('Events') ) {
} else if (canEdit('Events')) {
require_once('includes/Filter.php');
$filter = new ZM\Filter($_REQUEST['Id']);
if ( $action == 'delete' ) {
if ( !empty($_REQUEST['Id']) ) {
if ( $filter->Background() ) {
if ($action == 'delete') {
if (!empty($_REQUEST['Id'])) {
if ($filter->Background()) {
$filter->control('stop');
}
$filter->delete();
} else {
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_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
$_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']['AutoMoveTo'] = empty($_REQUEST['filter']['AutoMoveTo']) ? 0 : $_REQUEST['filter']['AutoMoveTo'];
$_REQUEST['filter']['AutoArchive'] = empty($_REQUEST['filter']['AutoArchive']) ? 0 : 1;
$_REQUEST['filter']['AutoVideo'] = empty($_REQUEST['filter']['AutoVideo']) ? 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']['Concurrent'] = empty($_REQUEST['filter']['Concurrent']) ? 0 : 1;
$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 ($filter->Background()) $filter->control('stop');
if (!$filter->save($changes)) {
$error_message = $filter->get_last_error();
return;
}
} else {
if ( $action == 'execute' ) {
if ( count($changes) ) {
$filter->Name('_TempFilter'.time());
$filter->Id(null);
}
} else if ( $action == 'SaveAs' ) {
$filter->Id(null);
}
if (!$filter->save($changes)) {
$error_message = $filter->get_last_error();
return;
}
if (count($changes)) {
if ($filter->Id() and ($action == 'Save') and $filter->Background()) {
$filter->control('stop');
} else if ($action == 'execute') {
# If there are changes use a temp filter to do the execute
$filter->Name('_TempFilter'.time());
$filter->Id(null);
} else if ($action == 'SaveAs') {
$filter->Id(null);
}
if (!$filter->save($changes)) {
$error_message = $filter->get_last_error();
return;
}
// We update the request id so that the newly saved filter is auto-selected
$_REQUEST['Id'] = $filter->Id();
} # end if changes
// We update the request id so that the newly saved filter is auto-selected
$_REQUEST['Id'] = $filter->Id();
}
if ( $action == 'execute' ) {
if ($action == 'execute') {
$filter->execute();
if ( count($changes) )
if (count($changes)) {
$filter->delete();
$view = 'events';
} else if ( $filter->Background() ) {
$filter->Id(null);
}
} else if ($filter->Background()) {
$filter->control('start');
}
global $redirect;
$redirect = '?view=filter'.$filter->querystring('filter', '&');
} else if ( $action == 'control' ) {
} else if ($action == 'control') {
if ( $_REQUEST['command'] == 'start'
or $_REQUEST['command'] == 'stop'
or $_REQUEST['command'] == 'restart'
@ -114,5 +108,4 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
} // end if save or execute
} // end if canEdit(Events)
} // end if object == filter
?>

View File

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

View File

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

View File

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

View File

@ -348,16 +348,16 @@ $SLANG = array(
'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08
'File' => 'Fichier',
'Filter' => 'Filtre', // Added - 2015-04-18
'FilterArchiveEvents' => 'Archiver',
'FilterDeleteEvents' => 'Effacer',
'FilterEmailEvents' => 'Envoyer les détails par email',
'FilterArchiveEvents' => 'Archiver les évènements',
'FilterDeleteEvents' => 'Effacer les évènements',
'FilterEmailEvents' => 'Envoyer les évènements par email',
'FilterExecuteEvents' => 'Exécuter une commande',
'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
'FilterPx' => 'Filtre Px',
'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',
'FilterVideoEvents' => 'Créer vidéo',
'Filters' => 'Filtres',

View File

@ -84,7 +84,7 @@ $SLANG = array(
'AddNewControl' => 'Aggiungi nuovo Controllo',
'AddNewMonitor' => 'Aggiungi nuovo Monitor',
'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',
'AddNewZone' => 'Aggiungi nuova Zona',
'Alarm' => 'Allarme',
@ -95,49 +95,49 @@ $SLANG = array(
'AlarmMaximumFPS' => 'FPS massimi durante l\'allarme',
'AlarmPx' => 'Pixel 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',
'All' => 'Tutto',
'AnalysisFPS' => 'Analysis FPS', // Added - 2015-07-22
'AnalysisUpdateDelay' => 'Analysis Update Delay', // Added - 2015-07-23
'AnalysisFPS' => 'Analisi FPS', // Added - 2015-07-22
'AnalysisUpdateDelay' => 'Intervallo aggiornamento analisi', // Added - 2015-07-23
'Apply' => 'Applica',
'ApplyingStateChange' => 'Sto applicando le modifiche',
'ArchArchived' => 'Archiviato',
'ArchUnarchived' => 'Non archiviato',
'ArchUnarchived' => 'Non Archiviato',
'Archive' => 'Archivio',
'Archived' => 'Archiviato',
'Area' => 'Area',
'AreaUnits' => 'Area (px/%)',
'AttrAlarmFrames' => 'Immagini in Allarme',
'AttrAlarmFrames' => 'Immagini Allarme',
'AttrArchiveStatus' => 'Stato Archivio',
'AttrAvgScore' => 'Punteggio medio',
'AttrAvgScore' => 'Punteggio Medio',
'AttrCause' => 'Causa',
'AttrDiskBlocks' => 'Blocchi del Disco',
'AttrDiskPercent' => 'Percentuale del Disco',
'AttrDiskSpace' => 'Disk Space', // Added - 2018-08-30
'AttrDiskBlocks' => 'Blocchi disco',
'AttrDiskPercent' => 'Percentuale disco',
'AttrDiskSpace' => 'Spazio disco', // Added - 2018-08-30
'AttrDuration' => 'Durata',
'AttrEndDate' => 'End Date', // Added - 2018-08-30
'AttrEndDateTime' => 'End Date/Time', // Added - 2018-08-30
'AttrEndTime' => 'End Time', // 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',
'AttrId' => 'Id',
'AttrMaxScore' => 'Punteggio massimo',
'AttrMaxScore' => 'Punteggio Massimo',
'AttrMonitorId' => 'Id 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',
'AttrNotes' => 'Note',
'AttrStartDate' => 'Start Date', // Added - 2018-08-30
'AttrStartDateTime' => 'Start Date/Time', // Added - 2018-08-30
'AttrStartTime' => 'Start Time', // Added - 2018-08-30
'AttrStartWeekday' => 'Start Weekday', // Added - 2018-08-30
'AttrStateId' => 'Run State', // Added - 2018-08-30
'AttrStorageArea' => 'Storage Area', // Added - 2018-08-30
'AttrStorageServer' => 'Server Hosting Storage', // Added - 2018-08-30
'AttrSystemLoad' => 'System Load',
'AttrTotalScore' => 'Punteggio totale',
'AttrStartDate' => 'Inizio - Data', // Added - 2018-08-30
'AttrStartDateTime' => 'Inizio - Data/orario', // Added - 2018-08-30
'AttrStartTime' => 'Inizio - Orario', // Added - 2018-08-30
'AttrStartWeekday' => 'Inizio - Giorno della settimana', // Added - 2018-08-30
'AttrStateId' => 'Stato Esecuzione', // Added - 2018-08-30
'AttrStorageArea' => 'Area Archiviazione', // Added - 2018-08-30
'AttrStorageServer' => 'Server Archiviazione remota', // Added - 2018-08-30
'AttrSystemLoad' => 'Carico Sistema',
'AttrTotalScore' => 'Punteggio Totale',
'Auto' => 'Auto',
'AutoStopTimeout' => 'Auto Stop Timeout',
'Available' => 'Disponibile', // Added - 2009-03-31
@ -181,56 +181,56 @@ $SLANG = array(
'BlobPx' => 'Blob Px',
'BlobSizes' => 'Dimensioni Blob',
'Blobs' => 'Blobs',
'Brightness' => 'Luminosit&agrave;',
'Brightness' => 'Luminosità',
'Buffer' => 'Buffer', // Added - 2015-04-18
'Buffers' => 'Buffers',
'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18
'CanAutoFocus' => 'Puo\' Auto Focus',
'CanAutoGain' => 'Puo\' Auto Gains',
'CanAutoIris' => 'Puo\' Auto Iris',
'CanAutoWhite' => 'Puo\' Auto bil bianco',
'CanAutoZoom' => 'Puo\' Auto Zoom',
'CanFocus' => 'Puo\' Fuoco',
'CanFocusAbs' => 'Puo\' Fuoco Assoluto',
'CanFocusCon' => 'Puo\' Fuoco Continuo ',
'CanFocusRel' => 'Puo\' Fuoco Relativo',
'CanGain' => 'Puo\' Gain ',
'CanGainAbs' => 'Puo\' Gain Assoluto',
'CanGainCon' => 'Puo\' Gain Continuo ',
'CanGainRel' => 'Puo\' Gain Relativo',
'CanIris' => 'Puo\' Iris',
'CanIrisAbs' => 'Puo\' Iris Assoluto',
'CanIrisCon' => 'Puo\' Iris Continuo ',
'CanIrisRel' => 'Puo\' Iris Relativo',
'CanMove' => 'Puo\' Mov.',
'CanMoveAbs' => 'Puo\' Mov. Assoluto',
'CanMoveCon' => 'Puo\' Mov. Continuo ',
'CanMoveDiag' => 'Puo\' Mov. Diagonale ',
'CanMoveMap' => 'Puo\' Mov Mappato',
'CanMoveRel' => 'Puo\' Mov. Relativo',
'CanPan' => 'Puo\' Pan' ,
'CanReset' => 'Puo\' Reset',
'CanReboot' => 'Can Reboot',
'CanSetPresets' => 'Puo\' impostare preset',
'CanSleep' => 'Puo\' andare in sleep',
'CanTilt' => 'Puo\' Tilt',
'CanWake' => 'Puo\' essere riattivato',
'CanWhite' => 'Puo\' bilanciare il bianco',
'CanWhiteAbs' => 'Puo\' bilanciare il bianco assoluto',
'CanWhiteBal' => 'Puo\' bilanciare il bianco',
'CanWhiteCon' => 'Puo\' bilanciare il bianco Continuo',
'CanWhiteRel' => 'Puo\' bilanciare il bianco Relativo',
'CanZoom' => 'Puo\' Zoom',
'CanZoomAbs' => 'Puo\' Zoom Assoluto',
'CanZoomCon' => 'Puo\' Zoom Continuo',
'CanZoomRel' => 'Puo\' Zoom Relativo',
'CanAutoFocus' => 'Può Auto Focus',
'CanAutoGain' => 'Può Auto Gains',
'CanAutoIris' => 'Può Auto Iris',
'CanAutoWhite' => 'Può Auto bil bianco',
'CanAutoZoom' => 'Può Auto Zoom',
'CanFocus' => 'Può Fuoco',
'CanFocusAbs' => 'Può Fuoco Assoluto',
'CanFocusCon' => 'Può Fuoco Continuo ',
'CanFocusRel' => 'Può Fuoco Relativo',
'CanGain' => 'Può Gain ',
'CanGainAbs' => 'Può Gain Assoluto',
'CanGainCon' => 'Può Gain Continuo ',
'CanGainRel' => 'Può Gain Relativo',
'CanIris' => 'Può Iris',
'CanIrisAbs' => 'Può Iris Assoluto',
'CanIrisCon' => 'Può Iris Continuo ',
'CanIrisRel' => 'Può Iris Relativo',
'CanMove' => 'Può Mov.',
'CanMoveAbs' => 'Può Mov. Assoluto',
'CanMoveCon' => 'Può Mov. Continuo ',
'CanMoveDiag' => 'Può Mov. Diagonale ',
'CanMoveMap' => 'Può Mov Mappato',
'CanMoveRel' => 'Può Mov. Relativo',
'CanPan' => 'Può Pan' ,
'CanReset' => 'Può Reset',
'CanReboot' => 'Può Riavviare',
'CanSetPresets' => 'Può impostare preset',
'CanSleep' => 'Può andare in sleep',
'CanTilt' => 'Può inclinare',
'CanWake' => 'Può essere riattivato',
'CanWhite' => 'Può bilanciare il bianco',
'CanWhiteAbs' => 'Può bilanciare il bianco assoluto',
'CanWhiteBal' => 'Può bilanciare il bianco',
'CanWhiteCon' => 'Può bilanciare il bianco Continuo',
'CanWhiteRel' => 'Può bilanciare il bianco Relativo',
'CanZoom' => 'Può Zoom',
'CanZoomAbs' => 'Può Zoom Assoluto',
'CanZoomCon' => 'Può Zoom Continuo',
'CanZoomRel' => 'Può Zoom Relativo',
'Cancel' => 'Annulla',
'CancelForcedAlarm' => 'Annulla Allarme Forzato',
'CaptureHeight' => 'Altezza img catturata',
'CaptureMethod' => 'Metodo di cattura', // Added - 2009-02-08
'CapturePalette' => 'Paletta img catturata',
'CaptureResolution' => 'Risoluzione di cattura', // Added - 2015-04-18
'CaptureWidth' => 'Larghezza img Catturata',
'CaptureHeight' => 'Altezza Cattura Immagine',
'CaptureMethod' => 'Metodo Cattura Immagine', // Added - 2009-02-08
'CapturePalette' => 'Tavolozza Cattura Immagine',
'CaptureResolution' => 'Risoluzione Cattura Immagine', // Added - 2015-04-18
'CaptureWidth' => 'Larghezza Cattura Immagine',
'Cause' => 'Causa',
'CheckMethod' => 'Metodo di Controllo Allarme',
'ChooseDetectedCamera' => 'Scegli telecamera rilevata', // Added - 2009-03-31
@ -238,13 +238,13 @@ $SLANG = array(
'ChooseLogFormat' => 'Scegli un formato di registro', // Added - 2011-06-17
'ChooseLogSelection' => 'Scegli una selezione del registro', // Added - 2011-06-17
'ChoosePreset' => 'Scegli Preset',
'Clear' => 'Clear', // Added - 2011-06-16
'CloneMonitor' => 'Clone', // Added - 2018-08-30
'Clear' => 'Pulisci', // Added - 2011-06-16
'CloneMonitor' => 'Clona', // Added - 2018-08-30
'Close' => 'Chiudi',
'Colour' => 'Colori',
'Command' => 'Comando',
'Component' => 'Component', // Added - 2011-06-16
'ConcurrentFilter' => 'Run filter concurrently', // Added - 2018-08-30
'ConcurrentFilter' => 'Esegui filtro contemporaneamente', // Added - 2018-08-30
'Config' => 'Configura',
'ConfiguredFor' => 'Configurato per',
'ConfirmDeleteEvents' => 'Sei sicuro di voler cancellare gli eventi selezionati',
@ -257,29 +257,29 @@ $SLANG = array(
'Contrast' => 'Contrasto',
'Control' => 'Controllo',
'ControlAddress' => 'Indirizzo di controllo',
'ControlCap' => 'Capacita\' di controllo',
'ControlCaps' => 'Capacita\' di controllo',
'ControlCap' => 'Capacità di controllo',
'ControlCaps' => 'Capacità di controllo',
'ControlDevice' => 'Dispositivo di controllo',
'ControlType' => 'Tipo Controllo',
'Controllable' => 'Controllabile',
'Current' => 'Current', // Added - 2015-04-18
'Current' => 'Corrente', // Added - 2015-04-18
'Cycle' => 'Cicla',
'CycleWatch' => 'Vista Ciclica',
'DateTime' => 'Date/Time', // Added - 2011-06-16
'DateTime' => 'Data/Orario', // Added - 2011-06-16
'Day' => 'Giorno',
'Debug' => 'Debug',
'DefaultRate' => 'Default Rate',
'DefaultRate' => 'Rateo predefinito',
'DefaultScale' => 'Scala di default',
'DefaultView' => 'Visualizzazione di default',
'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18
'Delay' => 'Delay', // Added - 2015-04-18
'DefaultView' => 'Visualizzazione predefinita',
'Deinterlacing' => 'Deinterlacciamento', // Added - 2015-04-18
'Delay' => 'Ritardo', // Added - 2015-04-18
'Delete' => 'Elimina',
'DeleteAndNext' => 'Elimina &amp; Prossimo',
'DeleteAndPrev' => 'Elimina &amp; Precedente',
'DeleteAndNext' => 'Elimina e Prossimo',
'DeleteAndPrev' => 'Elimina e Precedente',
'DeleteSavedFilter' => 'Elimina il filtro salvato',
'Description' => 'Descrizione',
'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
'DeviceChannel' => 'Canale Periferica',
'DeviceFormat' => 'Formato',
@ -287,18 +287,18 @@ $SLANG = array(
'DevicePath' => 'Percorso Dispositivo',
'Devices' => 'Dispositivi',
'Dimensions' => 'Dimensioni',
'DisableAlarms' => 'Disabil Allarme',
'DisableAlarms' => 'Disabilita Allarme',
'Disk' => 'Utilizzo Disco',
'Display' => 'Display', // Added - 2011-01-30
'Displaying' => 'Displaying', // Added - 2011-06-16
'DoNativeMotionDetection'=> 'Do Native Motion Detection',
'Display' => 'Mostra', // Added - 2011-01-30
'Displaying' => 'Visualizzazione', // Added - 2011-06-16
'DoNativeMotionDetection'=> 'Attiva Motion Detection Nativo',
'Donate' => 'Donate,per favore',
'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',
'DonateRemindHour' => 'Non ancora, ricordamelo ancora tra 1 ora',
'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',
'DonateYes' => 'Si,mi piacerebbe donare qualcosa ora',
'Download' => 'Scarica',
@ -325,24 +325,24 @@ $SLANG = array(
'Execute' => 'Esegui',
'Exif' => 'Includi dati EXIF nell\'immagine', // Added - 2018-08-30
'Export' => 'Esporta',
'ExportDetails' => 'Esp. dettagli eventi',
'ExportFailed' => 'Esp. Fallita ',
'ExportFormat' => 'Formato File Esp. ',
'ExportDetails' => 'Esporta dettagli eventi',
'ExportFailed' => 'Esportazione Fallita ',
'ExportFormat' => 'Formato File Esportazione',
'ExportFormatTar' => 'Tar',
'ExportFormatZip' => 'Zip',
'ExportFrames' => 'Dettagli frame espo.',
'ExportFrames' => 'Esporta dettagli immagini',
'ExportImageFiles' => 'Esporta le immagini',
'ExportLog' => 'Export Log', // Added - 2011-06-17
'ExportMiscFiles' => 'Esporto Altri file (se presenti)',
'ExportLog' => 'Esporta Log', // Added - 2011-06-17
'ExportMiscFiles' => 'Esporta Altri file (se presenti)',
'ExportOptions' => 'Opzioni Esportazione',
'ExportSucceeded' => 'Export completata con successo', // Added - 2009-02-08
'ExportVideoFiles' => 'Esporto File Video (se presenti)',
'Exporting' => 'In corso.',
'ExportSucceeded' => 'Esportazione completata con successo', // Added - 2009-02-08
'ExportVideoFiles' => 'Esporta File Video (se presenti)',
'Exporting' => 'In corso',
'FPS' => 'fps',
'FPSReportInterval' => 'Intervallo Report FPS',
'FTP' => 'FTP',
'Far' => 'Lontano',
'FastForward' => 'Fast Forward',
'FastForward' => 'Avanzamento veloce',
'Feed' => 'Feed',
'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08
'File' => 'File',
@ -351,7 +351,7 @@ $SLANG = array(
'FilterDeleteEvents' => 'Elimina gli eventi',
'FilterEmailEvents' => 'Invia dettagli via email',
'FilterExecuteEvents' => 'Esegui un comando',
'FilterLog' => 'Filter log', // Added - 2015-04-18
'FilterLog' => 'Filtra log', // Added - 2015-04-18
'FilterMessageEvents' => 'Invia dettagli tramite messaggio',
'FilterMoveEvents' => 'Sposta tutti gli eventi', // Added - 2018-08-30
'FilterPx' => 'Px Filtro',
@ -363,12 +363,12 @@ $SLANG = array(
'First' => 'Primo',
'FlippedHori' => 'ribaltato orizzontale',
'FlippedVert' => 'ribaltato verticale',
'FnMocord' => 'Mocord', // Added 2013.08.16.
'FnModect' => 'Modect', // Added 2013.08.16.
'FnMonitor' => 'Monitor', // Added 2013.08.16.
'FnNodect' => 'Nodect', // Added 2013.08.16.
'FnNone' => 'None', // Added 2013.08.16.
'FnRecord' => 'Record', // Added 2013.08.16.
'FnMocord' => 'Mocord - Registrazione continua (con evidenziazione eventi)', // Added 2013.08.16.
'FnModect' => 'Modect - MOtion DEteCTtion (registrazione su rilevamento movimento)', // Added 2013.08.16.
'FnMonitor' => 'Monitor - Visualizza Live', // Added 2013.08.16.
'FnNodect' => 'Nodect - No DEteCTtion (registrazione su evento esterno)', // Added 2013.08.16.
'FnNone' => 'None - Nessuno (Monitor disabilitato)', // Added 2013.08.16.
'FnRecord' => 'Record - Registrazione continua', // Added 2013.08.16.
'Focus' => 'Focus',
'ForceAlarm' => 'Forza Allarme',
'Format' => 'Formato',
@ -379,7 +379,7 @@ $SLANG = array(
'Frames' => 'Immagini',
'Func' => 'Funz',
'Function' => 'Funzione',
'Gain' => 'Gain',
'Gain' => 'Guadagno',
'General' => 'Generale',
'GenerateDownload' => 'Genera download', // Added - 2018-08-30
'GenerateVideo' => 'Genera video',
@ -388,19 +388,19 @@ $SLANG = array(
'Grey' => 'Grigio',
'Group' => 'Gruppo',
'Groups' => 'Gruppi',
'HasFocusSpeed' => 'Ha velocita\' di focus',
'HasGainSpeed' => 'Ha velocita\' di guadagno',
'HasFocusSpeed' => 'Ha velocità di focus',
'HasGainSpeed' => 'Ha velocità di guadagno',
'HasHomePreset' => 'Ha posizioni di present',
'HasIrisSpeed' => 'Ha velocota\' di iris',
'HasPanSpeed' => 'Ha velocita\' di Pan',
'HasIrisSpeed' => 'Ha velocità di iris',
'HasPanSpeed' => 'Ha velocità di Pan',
'HasPresets' => 'Ha preset',
'HasTiltSpeed' => 'Ha velocita\' di Tilt',
'HasTiltSpeed' => 'Ha velocità di Tilt',
'HasTurboPan' => 'Ha il Turbo Pan',
'HasTurboTilt' => 'Ha il Turbo Tilt',
'HasWhiteSpeed' => 'Ha velocita\' di bilanciamento del bianco',
'HasZoomSpeed' => 'Ha velocita\' di zoom',
'HasWhiteSpeed' => 'Ha velocità di bilanciamento del bianco',
'HasZoomSpeed' => 'Ha velocità di zoom',
'High' => 'Alta',
'HighBW' => 'Banda&nbsp;Alta',
'HighBW' => 'Banda Alta',
'Home' => 'Home',
'Hostname' => 'Nome Host', // Added - 2018-08-30
'Hour' => 'Ora',
@ -414,7 +414,7 @@ $SLANG = array(
'In' => 'In',
'Include' => 'Includi',
'Inverted' => 'Invertito',
'Iris' => 'Iris',
'Iris' => 'Iride',
'KeyString' => 'Stringa Chiave',
'Label' => 'Etichetta',
'Language' => 'Linguaggio',
@ -438,39 +438,39 @@ $SLANG = array(
'Logout' => 'Logout',
'Logs' => 'Logs', // Added - 2011-06-17
'Low' => 'Bassa',
'LowBW' => 'Banda&nbsp;Bassa',
'LowBW' => 'Banda Bassa',
'Main' => 'Principale',
'Man' => 'Man',
'Manual' => 'Manuale',
'Mark' => 'Seleziona',
'Max' => 'Massima',
'MaxBandwidth' => 'Banda Massima',
'MaxBrScore' => 'Punteggio<br/>Massimo',
'MaxBrScore' => 'Punteggio Massimo',
'MaxFocusRange' => 'Massimo range del focus',
'MaxFocusSpeed' => 'Massima velocita\' del focus',
'MaxFocusSpeed' => 'Massima velocità del focus',
'MaxFocusStep' => 'Massimo step del focus',
'MaxGainRange' => 'Massimo range del guadagno',
'MaxGainSpeed' => 'Massima velocita\' del guadagno',
'MaxGainSpeed' => 'Massima velocità del guadagno',
'MaxGainStep' => 'Massimo step del guadagno',
'MaxIrisRange' => 'Massima range dell\'Iris',
'MaxIrisSpeed' => 'Massima velocita\' dell\'Iris',
'MaxIrisStep' => 'Massimo step dell\'Iris',
'MaxIrisRange' => 'Massima range dell\'Iride',
'MaxIrisSpeed' => 'Massima velocità dell\'Iride',
'MaxIrisStep' => 'Massimo step dell\'Iride',
'MaxPanRange' => 'Massimo range del pan',
'MaxPanSpeed' => 'Massima velocita\' del tilt',
'MaxPanSpeed' => 'Massima velocità del tilt',
'MaxPanStep' => 'Massimo step del pan',
'MaxTiltRange' => 'Massimo range del tilt',
'MaxTiltSpeed' => 'Massima velocita\' del tilt',
'MaxTiltSpeed' => 'Massima velocità del tilt',
'MaxTiltStep' => 'Massimo passo del tilt',
'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',
'MaxZoomRange' => 'Massimo range dello zoom',
'MaxZoomSpeed' => 'Massima velocita\' dello zoom',
'MaxZoomSpeed' => 'Massima velocità dello zoom',
'MaxZoomStep' => 'Massimo step dello zoom',
'MaximumFPS' => 'Massimi FPS',
'Medium' => 'Media',
'MediumBW' => 'Banda&nbsp;Media',
'Message' => 'Message', // Added - 2011-06-16
'MediumBW' => 'Larghezza Banda Media',
'Message' => 'Messaggio', // Added - 2011-06-16
'MinAlarmAreaLtMax' => 'L\'area minima dell\'allarme deve essere minore di quella massima',
'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',
@ -482,47 +482,47 @@ $SLANG = array(
'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',
'MinFocusRange' => 'Range minimo del Focus',
'MinFocusSpeed' => 'Velocita\' minima del Focus',
'MinFocusSpeed' => 'Velocità minima del Focus',
'MinFocusStep' => 'Minimo step del Focus',
'MinGainRange' => 'Minimo range del Guadagno',
'MinGainSpeed' => 'Velocita\' minima del Guadagno',
'MinGainSpeed' => 'Velocità minima del Guadagno',
'MinGainStep' => 'Step minimo del guadagno',
'MinIrisRange' => 'Range minimo dell\'Iris',
'MinIrisSpeed' => 'Velocita\' minima dell\'Iris',
'MinIrisStep' => 'Step minimo dell\'Iris',
'MinPanRange' => 'Range minimo del pan',
'MinPanSpeed' => 'Velocita\' minima del Pan',
'MinIrisRange' => 'Range minimo dell\'Iride',
'MinIrisSpeed' => 'Velocità minima dell\'Iride',
'MinIrisStep' => 'Step minimo dell\'Iride',
'MinPanRange' => 'Range minimo del Pan',
'MinPanSpeed' => 'Velocità minima del Pan',
'MinPanStep' => 'Step minimo del Pan',
'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
'MinTiltRange' => 'Range minimo del Tilt',
'MinTiltSpeed' => 'Velocita\' minima del Tilt',
'MinTiltSpeed' => 'Velocità minima del Tilt',
'MinTiltStep' => 'Step minimo del Tilt',
'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',
'MinZoomRange' => 'Range minimo dello zoom',
'MinZoomSpeed' => 'Velocita\' minima dello zoom',
'MinZoomSpeed' => 'Velocità minima dello zoom',
'MinZoomStep' => 'Step minimo dello zoom',
'Misc' => 'Altro',
'Mode' => 'Modalità', // Added - 2015-04-18
'Monitor' => 'Monitor',
'MonitorIds' => 'Monitor&nbsp;Ids',
'MonitorIds' => 'Monitor Ids',
'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>',
'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
'Monitors' => 'Monitors',
'Montage' => 'Montaggio',
'MontageReview' => 'Montage Review', // Added - 2018-08-30
'MontageReview' => 'Revisione del montaggio', // Added - 2018-08-30
'Month' => 'Mese',
'More' => 'More', // Added - 2011-06-16
'MotionFrameSkip' => 'Motion Frame Skip',
'More' => 'Più', // Added - 2011-06-16
'MotionFrameSkip' => 'Salta/scarta fotogramma',
'Move' => 'Sposta',
'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15.
'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15.
'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15.
'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15.
'Mtg2widgrd' => 'Griglia 2 colonne', // Added 2013.08.15.
'Mtg3widgrd' => 'Griglia 3 colonne', // Added 2013.08.15.
'Mtg3widgrx' => 'Griglia 3 colonne, scalata, ingrandita su allarme', // Added 2013.08.15.
'Mtg4widgrd' => 'Griglia 4 colonne', // Added 2013.08.15.
'MtgDefault' => 'Predefinito', // Added 2013.08.15.
'MustBeGe' => 'deve essere superiore a',
'MustBeLe' => 'deve essere inferiore o pari a',
@ -550,7 +550,7 @@ $SLANG = array(
'NoneAvailable' => 'Nessuno disponibile',
'Normal' => 'Normale',
'Notes' => 'Note',
'NumPresets' => 'Num Presets',
'NumPresets' => 'Num redefiniti',
'Off' => 'Off',
'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
@ -589,7 +589,7 @@ $SLANG = array(
'Paths' => 'Percorsi',
'Pause' => 'Pause',
'Phone' => 'Telefono',
'PhoneBW' => 'Banda&nbsp;Tel',
'PhoneBW' => 'Banda Tel',
'Pid' => 'PID', // Added - 2011-06-16
'PixelDiff' => 'Pixel Diff',
'Pixels' => 'pixels',
@ -598,18 +598,18 @@ $SLANG = array(
'PleaseWait' => 'Attendere prego',
'Plugins' => 'Plugins',
'Point' => 'Punto',
'PostEventImageBuffer' => 'Buffer di immagini Dopo Evento',
'PreEventImageBuffer' => 'Buffer di immagini Pre Evento',
'PostEventImageBuffer' => 'Buffer immagini Dopo Evento',
'PreEventImageBuffer' => 'Buffer immagini Pre Evento',
'PreserveAspect' => 'Preserve Aspect Ratio',
'Preset' => 'Preset',
'Presets' => 'Presets',
'Presets' => 'Predefiniti',
'Prev' => 'Prec',
'Probe' => 'Prova la telecamera', // Added - 2009-03-31
'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
'Progress' => 'Progresso', // Added - 2015-04-18
'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
'Rate' => 'Velocità',
'Real' => 'Reale',
@ -622,18 +622,18 @@ $SLANG = array(
'RemoteHostName' => 'Nome dell\'Host Remoto',
'RemoteHostPath' => 'Percorso 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',
'RemoteMethod' => 'Metodo Remoto', // Added - 2009-02-08
'RemoteProtocol' => 'Protocollo Remoto', // Added - 2009-02-08
'Rename' => 'Rinomina',
'Replay' => 'Replay',
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'ReportEventAudit' => 'Rapporto Eventi di controllo', // Added - 2018-08-30
'Reset' => 'Resetta',
'ResetEventCounts' => 'Resetta Contatore Eventi',
'Replay' => 'Riproduci',
'ReplayAll' => 'Tutti gli Eventi',
'ReplayGapless' => 'Eventi continui',
'ReplaySingle' => 'Evento singolo',
'ReportEventAudit' => 'Controllo Eventi', // Added - 2018-08-30
'Reset' => 'Reset',
'ResetEventCounts' => 'Reset Contatore Eventi',
'Restart' => 'Riavvia',
'Restarting' => 'Sto riavviando',
'RestrictedCameraIds' => 'Camera Ids Riservati',
@ -644,7 +644,7 @@ $SLANG = array(
'RotateLeft' => 'Ruota a Sinista',
'RotateRight' => 'Ruota a Destra',
'RunLocalUpdate' => 'Eseguire zmupdate.pl per l\'aggiornamento', // Added - 2011-05-25
'RunMode' => 'Modalita\' funzionamento',
'RunMode' => 'Modalità funzionamento',
'RunState' => 'Stato di funzionamento',
'Running' => 'Attivo',
'Save' => 'Salva',
@ -671,69 +671,69 @@ $SLANG = array(
'Size' => 'grandezza',
'SkinDescription' => 'Cambia la skin predefinita per questo computer', // Added - 2011-01-30
'Sleep' => 'Sleep',
'SortAsc' => 'Cresc',
'SortAsc' => 'Crescente',
'SortBy' => 'Ordina per',
'SortDesc' => 'Decr',
'SortDesc' => 'Decrescente',
'Source' => 'Sorgente',
'SourceColours' => 'Colori della Sorgente', // Added - 2009-02-08
'SourcePath' => 'Percorso della Sorgente', // Added - 2009-02-08
'SourceType' => 'Tipo Sorgente',
'Speed' => 'Velocita\'',
'SpeedHigh' => 'Alta Velocita\'',
'SpeedLow' => 'Bassa Velocita\'',
'SpeedMedium' => 'Media Velocita\'',
'SpeedTurbo' => 'Turbo Velocita\'',
'Speed' => 'Velocità',
'SpeedHigh' => 'Alta Velocità',
'SpeedLow' => 'Bassa Velocità',
'SpeedMedium' => 'Media Velocità',
'SpeedTurbo' => 'Turbo Velocità',
'Start' => 'Avvia',
'State' => 'Stato',
'Stats' => 'Statistiche',
'Status' => 'Stato',
'StatusConnected' => 'Capturing', // Added - 2018-08-30
'StatusNotRunning' => 'Not Running', // Added - 2018-08-30
'StatusRunning' => 'Not Capturing', // Added - 2018-08-30
'StatusUnknown' => 'Unknown', // Added - 2018-08-30
'StatusConnected' => 'Registrazione in corso', // Added - 2018-08-30
'StatusNotRunning' => 'Non in esecuzione', // Added - 2018-08-30
'StatusRunning' => 'Registrazione in pausa', // Added - 2018-08-30
'StatusUnknown' => 'Sconosciuto', // Added - 2018-08-30
'Step' => 'Passo',
'StepBack' => 'Passo indietro',
'StepForward' => 'Passo avanti',
'StepLarge' => 'Lungo passo',
'StepMedium' => 'Medio passo',
'StepNone' => 'No passo',
'StepSmall' => 'Piccolo passo',
'Stills' => 'Foto',
'StepLarge' => 'Passo lungo',
'StepMedium' => 'Passo medio',
'StepNone' => 'Nessun passo',
'StepSmall' => 'Passo piccolo',
'Stills' => 'Immagini fisse',
'Stop' => 'Stop',
'Stopped' => 'Inattivo',
'StorageArea' => 'Area di salvataggio', // Added - 2018-08-30
'StorageScheme' => 'Scheme', // Added - 2018-08-30
'Stream' => 'Flusso',
'StreamReplayBuffer' => 'Stream Replay Image Buffer',
'StorageArea' => 'Area Archiviazione', // Added - 2018-08-30
'StorageScheme' => 'Schema Archiviazione', // Added - 2018-08-30
'Stream' => 'Stream',
'StreamReplayBuffer' => 'Buffer immagini riproduzione stream',
'Submit' => 'Accetta',
'System' => 'Sistema',
'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',
'Thumbnail' => 'Anteprima',
'Tilt' => 'Tilt',
'Tilt' => 'Tilt (Inclinazione)',
'Time' => 'Ora',
'TimeDelta' => 'Tempo di Delta',
'TimeStamp' => 'Time Stamp',
'TimeDelta' => 'Differenza orario',
'TimeStamp' => 'Sovraimpressione data/orario',
'Timeline' => 'Linea Temporale',
'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.
'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.
'Timestamp' => 'Timestamp',
'TimestampLabelFormat' => 'Formato etichetta timestamp',
'Timestamp' => 'Sovraimpressione data/orario',
'TimestampLabelFormat' => 'Formato etichetta Sovraimpressione data/orario',
'TimestampLabelSize' => 'Dimensione carattere', // Added - 2018-08-30
'TimestampLabelX' => 'coordinata X etichetta',
'TimestampLabelY' => 'coordinata Y etichetta',
'Today' => 'Oggi ',
'Tools' => 'Strumenti',
'Total' => 'Totale', // Added - 2011-06-16
'TotalBrScore' => 'Punteggio<br/>Totale',
'TrackDelay' => 'Track Delay',
'TrackMotion' => 'Track Motion',
'Triggers' => 'Triggers',
'TurboPanSpeed' => 'Velocita\' Turbo Pan',
'TurboTiltSpeed' => 'Velocita\' Turbo Tilt',
'TotalBrScore' => 'Punteggio Totale',
'TrackDelay' => 'Ritardo traccia',
'TrackMotion' => 'Segui movimento',
'Triggers' => 'Inneschi/Interruttori',
'TurboPanSpeed' => 'Velocità Turbo Pan',
'TurboTiltSpeed' => 'Velocità Turbo Tilt',
'Type' => 'Tipo',
'Unarchive' => 'Togli dall\'archivio',
'Undefined' => 'Non specificato', // Added - 2009-02-08
@ -742,17 +742,17 @@ $SLANG = array(
'Update' => 'Aggiorna',
'UpdateAvailable' => 'Un aggiornamento di ZoneMinder è disponibilie.',
'UpdateNotNecessary' => 'Nessun aggiornamento necessario.',
'Updated' => 'Updated', // Added - 2011-06-16
'Upload' => 'Upload', // Added - 2011-08-23
'Updated' => 'Aggiornato', // Added - 2011-06-16
'Upload' => 'Carica', // Added - 2011-08-23
'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'
'UsedPlugins' => 'Used Plugins',
'UsedPlugins' => 'Plugins in uso',
'User' => 'Utente',
'Username' => 'Nome Utente',
'Users' => 'Utenti',
'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
'Value' => 'Valore',
'Version' => 'Versione',
@ -767,9 +767,9 @@ $SLANG = array(
'VideoGenFiles' => 'File Video Esistenti',
'VideoGenNoFiles' => 'Non ho trovato file ',
'VideoGenParms' => 'Parametri Generazione Video',
'VideoGenSucceeded' => 'Successo: Generato Video !',
'VideoGenSucceeded' => 'Successo: Video Generato!',
'VideoSize' => 'Dimensioni Video',
'VideoWriter' => 'Scrittore video', // Added - 2018-08-30
'VideoWriter' => 'Scrittore Video', // Added - 2018-08-30
'View' => 'Vedi',
'ViewAll' => 'Vedi Tutto',
'ViewEvent' => 'Vedi Evento',
@ -782,20 +782,20 @@ $SLANG = array(
'WebSiteUrl' => 'Website URL', // Added - 2018-08-30
'Week' => 'Settimana',
'White' => 'Bianco',
'WhiteBalance' => 'Bil. Bianco ',
'WhiteBalance' => 'Bilanciamento del Bianco',
'Wide' => 'Larghezza',
'X' => 'X',
'X10' => 'X10',
'X10ActivationString' => 'Stringa attivazione X10',
'X10InputAlarmString' => 'Stringa allarme input X10',
'X10OutputAlarmString' => 'Stringa allarme output X10',
'Y' => 'Y',
'Y' => 'S',
'Yes' => 'Si',
'YouNoPerms' => 'Non hai i permessi per accedere a questa risorsa.',
'Zone' => 'Zona',
'ZoneAlarmColour' => 'Colore Allarme (RGB)',
'ZoneArea' => 'Zone Area',
'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count',
'ZoneExtendAlarmFrames' => 'Estendi conteggio immagini allarme',
'ZoneFilterSize' => 'Larghezza/Altezza Filtro (pixels)',
'ZoneMinMaxAlarmArea' => 'Min/Max Area Allarmata',
'ZoneMinMaxBlobArea' => 'Min/Max Area di Blob',
@ -803,7 +803,7 @@ $SLANG = array(
'ZoneMinMaxFiltArea' => 'Min/Max Area Filtrata',
'ZoneMinMaxPixelThres' => 'Min/Max Soglia Pixel (0-255)',
'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17
'ZoneOverloadFrames' => 'Overload Frame Ignore Count',
'ZoneOverloadFrames' => 'Sovraccarico - contatore immagini ignorate',
'Zones' => 'Zone',
'Zoom' => 'Zoom',
'ZoomIn' => 'Ingrandisci',

View File

@ -746,3 +746,9 @@ a.flip {
#modalLogout .modal-body {
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[EmailTo]"],
textarea[name="filter[EmailBody]"] {
width: 500px;
width: 100%;
}
select#Id {
min-width: 500px;
@ -71,3 +71,16 @@ min-width: 500px;
.Name input {
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
*
* This program is free software; you can redistribute it and/or
@ -47,7 +47,7 @@ p {
}
th {
color: #117AAd;
color: #10a4e8;
}
img.normal {
@ -147,9 +147,9 @@ fieldset {
border-bottom: 1px solid #000000;
}
input {
input, textarea, select, button, .btn-primary {
background-color: rgb(68,68,68);
color: #999;
color: #dddddd;
}
/* PP - make it easy to identify disabled buttons */
@ -185,7 +185,8 @@ input[type=submit]:disabled,
}
.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 {
@ -216,6 +217,14 @@ li.search-choice {
}
/* end chosen override */
modal-content {
background-color: #222222;
.modal-content {
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>
<?php
if ( $event->DefaultVideo() ) {
if ($event->DefaultVideo()) {
// videojs zoomrotate only when direct recording
$Zoom = 1;
$Rotation = 0;
$Monitor = $event->Monitor();
if ( $Monitor->VideoWriter() == '2' ) {
if ($Monitor->VideoWriter() == '2') {
# Passthrough
$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();
} # end if passthrough
?>
@ -242,7 +242,7 @@ function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist) {
width="<?php echo $event->Width() ?>"
height="<?php echo $event->Height() ?>"
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>
Your browser does not support the video tag.
</video>
@ -250,7 +250,7 @@ function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist) {
<?php
} 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>
</ilayer>
<div id="imagevideo" align="center"></div>
@ -570,30 +570,24 @@ else if (document.layers) window.onload=start_slider;
return ob_get_clean();
} # end function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist)
function eventlist_html($Event, $exportDetail, $exportFrames) {
$html = '<div class="event">
';
if ( $Event->SaveJPEGs() ) {
function eventlist_html($Event, $exportDetail, $exportFrames, $exportStructure) {
$html = '';
if ($Event->SaveJPEGs()) {
$html .= '<a href="#" onclick="switchevent(\''.$Event->Id().'/zmEventImages.html\');return false;">
';
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/>
';
} # end if has jpegs
if ( $Event->DefaultVideo() ) {
if ( ZM_WEB_LIST_THUMBS ) {
$html .= '<a href="'.$Event->Id().'/'.$Event->DefaultVideo() .'">';
$html .= '<img width="'.ZM_WEB_LIST_THUMB_WIDTH.'" src="'. $Event->Id().'/snapshot.jpg" alt="'.$Event->Id().'"/>';
$html .= '</a><br/>
';
}
if ($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 .= '</a><br/>'.PHP_EOL;
}
if ( $exportDetail ) {
if ($exportDetail) {
$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 .= '</div><!--event-->
';
if (!$html) $html = $Event->Id();
$html = '<div class="event">'.PHP_EOL.$html.PHP_EOL.'</div><!--event-->'.PHP_EOL;
return $html;
} // end function eventlist_html
function exportEventImagesMaster($eids, $exportDetail, $exportFrames) {
function exportEventImagesMaster($eids, $exportDetail, $exportFrames, $exportStructure) {
ob_start();
exportHeader(translate('Images').' Master');
?>
@ -615,7 +609,7 @@ function exportEventImagesMaster($eids, $exportDetail, $exportFrames) {
<?php
$events = ZM\Event::find(array('Id'=>$eids));
foreach ( $events as $event ) {
foreach ($events as $event) {
//get monitor id and event id
$eventMonitorId[$event->Id()] = $event->MonitorId();
$eventPath[$event->Id()] = $event->Relative_Path();
@ -625,7 +619,7 @@ function exportEventImagesMaster($eids, $exportDetail, $exportFrames) {
$monitorNames = array();
//*
if ( !empty($monitors) ) {
if (!empty($monitors)) {
$tmp = dbFetchAll('SELECT Id, Name FROM Monitors WHERE Id IN ('.implode(',', $monitors).') ');
foreach ( $tmp as $row ) { $monitorNames[$row['Id']] = $row['Name']; }
}
@ -641,31 +635,31 @@ function exportEventImagesMaster($eids, $exportDetail, $exportFrames) {
?>
</ul>
</div>
<table>
<table style="width: 100%;">
<tr>
<td valign="top" bgcolor="#dddddd" style="padding:10px;">
<div class="tab_content" id="all">
<h2> All </h2>
<?php
foreach($events as $event) {
echo eventlist_html($event, $exportDetail, $exportFrames);
foreach ($events as $event) {
echo eventlist_html($event, $exportDetail, $exportFrames, $exportStructure);
} # end foreach event
?>
</div>
<?php
foreach ( $monitors as $monitor_id ) {
foreach ($monitors as $monitor_id) {
echo '<div class="tab_content" id="tab'.$monitor_id.'">';
echo '<h2>Monitor: '.$monitorNames[$monitor_id].'</h2>';
foreach ( $events as $event ) {
if ( $event->MonitorId() == $monitor_id ) {
echo eventlist_html($event, $exportDetail, $exportFrames);
foreach ($events as $event) {
if ($event->MonitorId() == $monitor_id) {
echo eventlist_html($event, $exportDetail, $exportFrames, $exportStructure);
} # end if its the right monitor
} # end foreach event
echo '</div>';
} # end foreach monitor
?>
</td><td valign="top">
</td><td valign="top" style="height: 100%;">
<iframe id="myframe" onload="resizeCaller();" name="myframe" src="about:blank"
scrolling="no" marginwidth="0" marginheight="0" frameborder="0"
vspace="0" hspace="0" style="overflow:visible; width:100%; display:none">
@ -772,53 +766,64 @@ function exportFileList(
$exportVideo,
$exportMisc
) {
if ( !canView('Events') or !$event ) {
if (!$event) {
ZM\Error("Empty event passed to exportFileList");
return;
}
if (!$event->canView()) {
ZM\Error('Can\'t view event '.$event->Id());
return;
}
$eventPath = $event->Path();
$eventRelativePath = $event->Relative_Path();
$files = array();
if ( $dir = opendir($eventPath) ) {
while ( ($file = readdir($dir)) !== false ) {
if ( is_file($eventPath.'/'.$file) ) {
if ($dir = opendir($eventPath)) {
while (($file = readdir($dir)) !== false) {
if (is_file($eventPath.'/'.$file)) {
$files[$file] = $file;
}
}
closedir($dir);
}
ZM\Debug(print_r($files, true));
$exportFileList = array();
if ( $exportDetail ) {
if ($exportDetail) {
$file = 'zmEventDetail.html';
if ( $fp = fopen($eventPath.'/'.$file, 'w') ) {
if ($fp = fopen($eventPath.'/'.$file, 'w')) {
fwrite($fp, exportEventDetail($event, $exportFrames, $exportImages));
fclose($fp);
$exportFileList[$file] = $file;
} 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';
if ( $fp = fopen($eventPath.'/'.$file, 'w') ) {
if ($fp = fopen($eventPath.'/'.$file, 'w')) {
fwrite($fp, exportEventFrames($event, $exportDetail, $exportImages));
fclose($fp);
$exportFileList[$file] = $file;
} 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();
$myfilelist = array();
foreach ( $files as $file ) {
if ( preg_match('/-(?:capture|analyse).jpg$/', $file) ) {
foreach ($files as $file) {
if (preg_match('/-(?:capture|analyse).jpg$/', $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 {
$filesLeft[$file] = $file;
}
@ -826,36 +831,27 @@ function exportFileList(
$files = $filesLeft;
// create an image slider
if ( !empty($myfilelist) ) {
$file = 'zmEventImages.html';
if ( $fp = fopen($eventPath.'/'.$file, 'w') ) {
fwrite($fp, exportEventImages($event, $exportDetail, $exportFrames, $myfilelist));
fclose($fp);
$exportFileList[$file] = $file;
} else {
ZM\Error("Can't open event images export file '$file'");
}
$file = 'zmEventImages.html';
if ($fp = fopen($eventPath.'/'.$file, 'w')) {
fwrite($fp, exportEventImages($event, $exportDetail, $exportFrames, $myfilelist));
fclose($fp);
$exportFileList[$file] = $file;
} else {
ZM\Error("Can't open event images export file '$file'");
}
} else {
ZM\Debug('Not including frame images');
} # end if exportImages
if ( $exportVideo ) {
$filesLeft = array();
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 ) {
if ($exportMisc) {
foreach ($files as $file) {
$exportFileList[$file] = $file;
}
$files = array();
} else {
ZM\Debug('Not including misc');
}
ZM\Debug(print_r($exportFileList, true));
return array_values($exportFileList);
} # end exportFileList()
@ -869,76 +865,89 @@ function exportEvents(
$exportMisc,
$exportFormat,
$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.');
return false;
} else if ( empty($eids) ) {
} else if (empty($eids)) {
ZM\Error('Attempt to export an empty list of events.');
return false;
}
if ( !($exportFormat == 'tar' or $exportFormat == 'zip') ) {
if (!($exportFormat == 'tar' or $exportFormat == 'zip')) {
ZM\Error("None or invalid exportFormat specified $exportFormat.");
return false;
}
# 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.'\'');
}
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.
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'");
return false;
}
ZM\Debug("Successfully created dir '$export_dir'");
chmod($export_dir, 0700);
if ( !chdir($export_dir) ) {
if (!chdir($export_dir)) {
ZM\Error("Can't chdir to $export_dir");
return;
}
$export_root = 'zmExport';
$export_listFile = 'zmFileList.txt';
$exportFileList = array();
$html_eventMaster = '';
if ( !is_array($eids) ) {
if (!is_array($eids)) {
$eids = array($eids);
}
foreach ( $eids as $eid ) {
foreach ($eids as $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();
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");
}
$event_exportFileList = exportFileList($event, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc);
$exportFileList = array_merge($exportFileList, $event_exportFileList);
foreach ( $event_exportFileList as $file ) {
foreach ($event_exportFileList as $file) {
#if ( preg_match('/\.html$/', $file) )
#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);
ZM\Debug($cmd.' return code: '.$return.' output: '.print_r($output,true));
} # end foreach event_exportFile
} # end foreach event
if ( !symlink(ZM_PATH_WEB.'/'.ZM_SKIN_PATH.'/js/jquery.min.js', $export_dir.'/jquery.min.js') )
ZM\Error('Failed linking jquery.min.js');
if (!(
@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') )
//Error("Failed linking video.js");
$html_eventMaster_file = 'zmEventImagesMaster.html';
$html_eventMaster_path = $export_dir.'/'.$html_eventMaster_file;
if ( ($fp = fopen($html_eventMaster_path, 'w')) ) {
fwrite($fp, exportEventImagesMaster($eids, $exportDetail, $exportFrames));
if (($fp = fopen($html_eventMaster_path, 'w'))) {
fwrite($fp, exportEventImagesMaster($eids, $exportDetail, $exportFrames, $exportStructure));
fclose($fp);
$exportFileList[] = $html_eventMaster_file;
} else {
@ -946,58 +955,63 @@ function exportEvents(
}
$listFile = $export_dir.'/'.$export_listFile;
if ( !($fp = fopen($listFile, 'w')) ) {
ZM\Fatal("Can't open event export list file '$listFile'");
if (!($fp = fopen($listFile, 'w'))) {
ZM\Error("Can't open event export list file '$listFile'");
return false;
}
foreach ( $exportFileList as $exportFile ) {
$exportFile = 'zmExport'.$connkey.'/'.$exportFile;
fwrite($fp, "$exportFile\n");
foreach ($exportFileList as $exportFile) {
$exportFile = $export_root.$connkey.'/'.$exportFile;
fwrite($fp, $exportFile.PHP_EOL);
}
fwrite($fp, "$listFile\n");
fwrite($fp, $listFile.PHP_EOL);
fclose($fp);
chdir(ZM_DIR_EXPORTS);
$archive = '';
if ( $exportFormat == 'tar' ) {
$archive = ZM_DIR_EXPORTS.'/'.$export_root.($connkey?'_'.$connkey:'').'.tar';
$version = shell_exec('tar -v');
if ($exportFormat == 'tar') {
$archive = $export_root.($connkey?'_'.$connkey:'').'.tar';
$version = @shell_exec('tar --version');
ZM\Debug("Version $version");
$command = 'tar --create --dereference';
if ( $exportCompressed ) {
if ($exportCompressed) {
$archive .= '.gz';
$command .= ' --gzip';
$exportFormat .= '.gz';
}
if ( $exportStructure == 'flat' ) {
if ( preg_match('/BSD/i', $version) ) {
if ($exportStructure == 'flat') {
if (preg_match('/BSD/i', $version)) {
$command .= ' -s \'#^.*/##\'';
} else {
$command .= ' --xform=\'s#^.+/##x\'';
}
}
$command .= ' --file='.escapeshellarg($archive);
} elseif ( $exportFormat == 'zip' ) {
$archive = ZM_DIR_EXPORTS.'/'.$export_root.($connkey?'_'.$connkey:'').'.zip';
$command = 'zip ';
$command .= ($exportStructure == 'flat' ? ' -j ' : ' -r ' ).escapeshellarg($archive);
$archive_path = ZM_DIR_EXPORTS.'/'.$archive;
$command .= ' --file='.escapeshellarg($archive_path);
} else if ($exportFormat == 'zip') {
$archive = $export_root.($connkey?'_'.$connkey:'').'.zip';
$archive_path = ZM_DIR_EXPORTS.'/'.$archive;
$command = 'zip -r ';
$command .= ($exportStructure == 'flat' ? ' -j ' : '').escapeshellarg($archive_path);
$command .= $exportCompressed ? ' -9' : ' -0';
} // if $exportFormat
@unlink($archive);
$command .= ' zmExport_' . $connkey.'/';
@unlink($archive_path);
$command .= ' '.$export_root.($connkey?'_'.$connkey:'').'/';
ZM\Debug($command);
exec($command, $output, $status);
if ( $status ) {
if ($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].'\'');
}
return false;
}
// clean up temporary files
if ( !empty($html_eventMaster) ) {
if (!empty($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

View File

@ -766,25 +766,23 @@ function getAccountCircleHTML($skin, $user=null) {
function getStatusBtnHTML($status) {
$result = '';
if ( canEdit('System') ) {
//$result .= '<li class="nav-item dropdown">'.PHP_EOL;
if (canEdit('System')) {
$result .= '<li id="getStatusBtnHTML">'.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;
if ( ZM_SYSTEM_SHUTDOWN ) {
$result .= '<li class="navbar-text pr-2 align-self-center">'.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;
if (ZM_SYSTEM_SHUTDOWN) {
$result .= '<li class="pr-2">'.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;
}
} else if ( canView('System') ) {
} else if (canView('System')) {
$result .= '<li id="getStatusBtnHTML" class="navbar-text">'.PHP_EOL;
$result .= $status.PHP_EOL;
$result .= '</li>'.PHP_EOL;
}
return $result;
}
@ -900,7 +898,6 @@ function xhtmlFooter() {
'js/Server.js',
), true );
?>
<script nonce="<?php echo $cspNonce; ?>">var $j = jQuery.noConflict();</script>
<?php
if ( $view == 'event' ) {
?>
@ -914,7 +911,7 @@ function xhtmlFooter() {
<script src="skins/<?php echo $skin ?>/js/moment.min.js"></script>
<?php
?>
<script nonce="<?php echo $cspNonce; ?>">
<script nonce="<?php echo $cspNonce; ?>">var $j = jQuery.noConflict();
<?php
if ( $skinJsPhpFile ) {
require_once( $skinJsPhpFile );

View File

@ -781,7 +781,7 @@ function logAjaxFail(jqxhr, textStatus, error) {
}
// 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)
.done(function(data) {
if ( !data ) {
@ -790,7 +790,7 @@ function getModal(id, parameters) {
}
insertModalHtml(id, data.html);
manageModalBtns(id);
buttonconfig ? buttonconfig() : manageModalBtns(id);
modal = $j('#'+id+'Modal');
if ( ! modal.length ) {
console.log('No modal found');
@ -800,6 +800,14 @@ function getModal(id, parameters) {
.fail(logAjaxFail);
}
function showModal(id, buttonconfig=null) {
var div = $j('#'+id+'Modal');
if ( ! div.length ) {
getModal(id, buttonconfig);
}
div.modal('show');
}
function manageModalBtns(id) {
// Manage the CANCEL modal button, note data-dismiss="modal" would work better
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>
<?php
}
$imgHTML='';
if (ZM_WEB_LIST_THUMBS && ($monitor['Status'] == 'Connected') && $running && canView('Stream')) {
$imgHTML = '';
if (ZM_WEB_LIST_THUMBS && $monitor['Function'] != 'None' && ($monitor['Status'] == 'Connected') && $running && canView('Stream')) {
$options = array();
$ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth();

View File

@ -195,7 +195,7 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
if ( $video_tag ) {
?>
<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);"
<?php echo $scale ? 'width="'.reScale($Event->Width(), $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="?">
<input type="hidden" name="view" value="filter"/>
<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
if ( count($filterNames) > 1 ) {
echo htmlSelect('Id', $filterNames, $filter->Id(), array('data-on-change-this'=>'selectFilter'));
@ -210,8 +210,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )
?>
</div>
</form>
<form name="contentForm" id="contentForm" method="post" class="validateFormOnSubmit" action="?view=filter">
<input type="hidden" name="Id" value="<?php echo $filter->Id() ?>"/>
<form name="contentForm" id="contentForm" method="post" class="validateFormOnSubmit" action="?view=filter&Id=<?php echo $filter->Id() ?>">
<input type="hidden" name="action"/>
<input type="hidden" name="object" value="filter"/>
@ -397,7 +396,7 @@ echo htmlSelect( 'filter[Query][sort_asc]', $sort_dirns, $filter->sort_asc() );
</tr>
</tbody>
</table>
<hr/>
<div id="ActionsAndOptions">
<div id="actionsTable" class="filterTable">
<fieldset><legend><?php echo translate('Actions') ?></legend>
<p>
@ -502,17 +501,17 @@ if ( ZM_OPT_EMAIL ) {
?>
</fieldset>
</div>
<hr/>
</div><!--ActionsAndOptions-->
<div id="contentButtons">
<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="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
if ( canEdit('Events') ) {
?>
<button type="submit" name="Save" value="Save" data-on-click-this="saveFilter"><?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="Save" id="Save"><?php echo translate('Save') ?></button>
<button type="submit" name="action" value="SaveAs" id="SaveAs"><?php echo translate('SaveAs') ?></button>
<?php
if ( $filter->Id() ) {
?>

View File

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

View File

@ -57,8 +57,8 @@ function validateForm(form) {
form.elements['filter[AutoUnarchive]'].checked ||
form.elements['filter[UpdateDiskSpace]'].checked ||
form.elements['filter[AutoVideo]'].checked ||
form.elements['filter[AutoEmail]'].checked ||
form.elements['filter[AutoMessage]'].checked ||
(form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked) ||
(form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked) ||
form.elements['filter[AutoExecute]'].checked ||
form.elements['filter[AutoDelete]'].checked ||
form.elements['filter[AutoCopy]'].checked ||
@ -97,13 +97,13 @@ function updateButtons(element) {
} else if ( form.elements['filter[UpdateDiskSpace]'].checked ) {
canExecute = true;
}
form.elements['executeButton'].disabled = !canExecute;
document.getElementById('executeButton').disabled = !canExecute;
if ( form.elements['filter[Name]'].value ) {
form.elements['Save'].disabled = false;
form.elements['SaveAs'].disabled = false;
document.getElementById('Save').disabled = false;
document.getElementById('SaveAs').disabled = false;
} else {
form.elements['Save'].disabled = true;
form.elements['SaveAs'].disabled = true;
document.getElementById('Save').disabled = true;
document.getElementById('SaveAs').disabled = true;
}
}
@ -151,11 +151,6 @@ function resetFilter( element ) {
function submitToEvents(element) {
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());
}
@ -171,23 +166,6 @@ function submitToExport(element) {
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 ) {
var form = element.form;
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('id', 'filter'+stringFilter(term));
} //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
function stringFilter(term) {
@ -415,4 +394,4 @@ function initPage() {
parseRows($j('#fieldsTable tbody').children());
}
$j(document).ready(initPage );
$j(document).ready(initPage);

View File

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

View File

@ -7,23 +7,23 @@ function selectLayout(element) {
var ddm = $j('#zmMontageLayout');
layout = ddm.val();
if ( layout_id = parseInt(layout) ) {
if (layout_id = parseInt(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];
// Need to clear the current positioning, and apply the new
monitor_frame = $j('#monitorFrame'+monitor.id);
if ( !monitor_frame ) {
if (!monitor_frame) {
console.log('Error finding frame for ' + monitor.id);
continue;
}
// Apply default layout options, like float left
if ( layout.Positions['default'] ) {
if (layout.Positions['default'] ) {
styles = layout.Positions['default'];
for ( style in styles ) {
for (style in styles) {
console.log("Applying " + 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);
} // end if default styles
if ( layout.Positions['mId'+monitor.id] ) {
if (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]);
}
} else {
console.log("No Monitor styles to apply");
} // end if specific monitor style
} // 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
if ( ! layout ) {
if (!layout) {
console.log('No layout?');
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 height = parseInt($j('#height').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];
if ( scale ) {
var stream_scale = 0;
if (scale) {
stream_scale = scale;
} else if ( width ) {
} else if (width) {
stream_scale = parseInt(100*width/monitor.width);
} else if ( height ) {
} else if (height) {
stream_scale = parseInt(100*height/monitor.height);
}
var streamImg = document.getElementById('liveStream'+monitor.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
} else if (layouts[layout_id].Name != 'Freeform') {
monitor_frame = $j('#monitorFrame'+monitor.id);
console.log("Monitor frame width : " + monitor_frame.width() + " monitor Width: " + monitor.width);
if (monitor_frame.width() < monitor.width) {
stream_scale = parseInt(100 * monitor_frame.width() / monitor.width);
// Round to a multiple of 5, so 53 become 50% etc
stream_scale = Math.floor(stream_scale/5)*5;
}
streamImg.style.width = '100%';
}
setStreamScale('liveStream'+monitor.id, stream_scale, width, height);
} // end foreach monitor
} // 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
*/

View File

@ -275,17 +275,16 @@ function timerFire() {
clearInterval(timerObj);
timerObj = null;
timerInterval = currentDisplayInterval;
console.log("Turn off nterrupts timerInterfave" + timerInterval);
console.log("Turn off interrupts timerInterfave" + timerInterval);
}
if ( (currentSpeed > 0 || liveMode != 0) && ! timerObj ) {
timerObj = setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero
}
if ( liveMode ) {
console.log("liveMode");
if (liveMode) {
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
console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval + " >= " + maxTimeSecs + " so stopping");
setSpeed(0);
@ -499,8 +498,8 @@ function redrawScreen() {
drawGraph();
}
var monitors = $j('#monitors');
if ( fitMode == 1 ) {
var monitors = $j('#monitors');
var fps = $j('#fps');
var vh = window.innerHeight;
var mh = (vh - monitors.position().top - fps.outerHeight());
@ -637,7 +636,7 @@ function showSpeed(val) {
}
function setSpeed(speed_index) {
if ( liveMode == 1 ) {
if (liveMode == 1) {
console.log("setSpeed in liveMode?");
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
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() {
// enable or disable buttons based on current selection and user rights
/*
@ -33,15 +55,9 @@ function initPage() {
archiveBtn.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
backBtn.prop('disabled', !document.referrer.length);
$j('#backBtn').prop('disabled', !document.referrer.length);
// Manage the BACK button
bindButton('#backBtn', 'click', null, function onBackClick(evt) {
@ -56,6 +72,7 @@ function initPage() {
});
// Manage the EDIT button
$j('#saveBtn').prop('disabled', !(canEdit.Events || (snapshot.CreatedBy == user.Id) ));
bindButton('#saveBtn', 'click', null, function onSaveClick(evt) {
/*
if ( ! canEdit.Events ) {
@ -63,17 +80,44 @@ function initPage() {
return;
}
*/
console.log(evt);
evt.target.form.submit();
});
/*
// 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();
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
bindButton('#downloadBtn', 'click', null, function onDownloadClick(evt) {
evt.preventDefault();
@ -88,6 +132,7 @@ function initPage() {
});
*/
// Manage the DELETE button
$j('#deleteBtn').prop('disabled', !canEdit.Events);
bindButton('#deleteBtn', 'click', null, function onDeleteClick(evt) {
if ( !canEdit.Events ) {
enoperm();

View File

@ -26,5 +26,9 @@ var eventDataStrings = {
//
var deleteString = "<?php echo validJsStr(translate('Delete')) ?>";
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_HEIGHT = '<?php echo ZM_WEB_LIST_THUMB_HEIGHT ?>';

View File

@ -90,7 +90,7 @@ function getDelConfirmModal() {
// Manage the DELETE CONFIRMATION modal button
function manageDelConfirmModalBtns() {
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
if ( ! canEdit.Events ) {
if (!canEdit.Events) {
enoperm();
return;
}
@ -98,7 +98,7 @@ function manageDelConfirmModalBtns() {
var selections = getIdSelections();
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) {
$j('#snapshotTable').bootstrapTable('refresh');
$j('#deleteConfirm').modal('hide');

View File

@ -73,10 +73,10 @@ function processRows(rows) {
function showEvents() {
$j('#ptzControls').addClass('hidden');
$j('#events').removeClass('hidden');
if ( $j('#eventsControl') ) {
if ($j('#eventsControl')) {
$j('#eventsControl').addClass('hidden');
}
if ( $j('#controlControl') ) {
if ($j('#controlControl')) {
$j('#controlControl').removeClass('hidden');
}
showMode = 'events';
@ -85,10 +85,10 @@ function showEvents() {
function showPtzControls() {
$j('#events').addClass('hidden');
$j('#ptzControls').removeClass('hidden');
if ( $j('#eventsControl') ) {
if ($j('#eventsControl')) {
$j('#eventsControl').removeClass('hidden');
}
if ( $j('#controlControl') ) {
if ($j('#controlControl')) {
$j('#controlControl').addClass('hidden');
}
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
// times and what the consequences would be
$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'));
newWidth = newSize.width;
newHeight = newSize.height;
@ -132,13 +132,13 @@ function setAlarmState(currentAlarmState) {
alarmState = currentAlarmState;
var stateClass = '';
if ( alarmState == STATE_ALARM ) {
if (alarmState == STATE_ALARM) {
stateClass = 'alarm';
} else if ( alarmState == STATE_ALERT ) {
} else if (alarmState == STATE_ALERT) {
stateClass = 'alert';
}
$j('#stateValue').text(stateStrings[alarmState]);
if ( stateClass ) {
if (stateClass) {
$j('#stateValue').addClass(stateClass);
} else {
$j('#stateValue').removeClass();
@ -150,25 +150,25 @@ function setAlarmState(currentAlarmState) {
var newAlarm = ( isAlarmed && !wasAlarmed );
var oldAlarm = ( !isAlarmed && wasAlarmed );
if ( newAlarm ) {
if (newAlarm) {
table.bootstrapTable('refresh');
if ( SOUND_ON_ALARM ) {
if (SOUND_ON_ALARM) {
// Enable the alarm sound
if ( !msieVer ) {
if (!msieVer) {
$j('#alarmSound').removeClass('hidden');
} else {
$j('#MediaPlayer').trigger('play');
}
}
if ( POPUP_ON_ALARM ) {
if (POPUP_ON_ALARM) {
window.focus();
}
}
if ( oldAlarm ) { // done with an event do a refresh
if (oldAlarm) { // done with an event do a refresh
table.bootstrapTable('refresh');
if ( SOUND_ON_ALARM ) {
if (SOUND_ON_ALARM) {
// Disable alarm sound
if ( !msieVer ) {
if (!msieVer) {
$j('#alarmSound').addClass('hidden');
} else {
$j('#MediaPlayer').trigger('pause');
@ -188,12 +188,12 @@ function getStreamCmdError(text, error) {
function getStreamCmdResponse(respObj, respText) {
watchdogOk('stream');
if ( streamCmdTimer ) {
if (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.
if ( respObj.status ) {
if (respObj.status) {
streamStatus = respObj.status;
$j('#fpsValue').text(streamStatus.fps);
$j('#capturefpsValue').text(streamStatus.capturefps);
@ -203,9 +203,9 @@ function getStreamCmdResponse(respObj, respText) {
$j('#levelValue').text(streamStatus.level);
var newClass = 'ok';
if ( streamStatus.level > 95 ) {
if (streamStatus.level > 95) {
newClass = 'alarm';
} else if ( streamStatus.level > 80 ) {
} else if (streamStatus.level > 80) {
newClass = 'alert';
}
$j('#levelValue').removeClass();
@ -213,30 +213,30 @@ function getStreamCmdResponse(respObj, respText) {
var delayString = secsToTime(streamStatus.delay);
if ( streamStatus.paused == true ) {
if (streamStatus.paused == true) {
$j('#modeValue').text('Paused');
$j('#rate').addClass('hidden');
$j('#delayValue').text(delayString);
$j('#delay').removeClass('hidden');
$j('#level').removeClass('hidden');
streamCmdPause(false);
} else if ( streamStatus.delayed == true ) {
} else if (streamStatus.delayed == true) {
$j('#modeValue').text('Replay');
$j('#rateValue').text(streamStatus.rate);
$j('#rate').removeClass('hidden');
$j('#delayValue').text(delayString);
$j('#delay').removeClass('hidden');
$j('#level').removeClass('hidden');
if ( streamStatus.rate == 1 ) {
if (streamStatus.rate == 1) {
streamCmdPlay(false);
} else if ( streamStatus.rate > 0 ) {
if ( streamStatus.rate < 1 ) {
} else if (streamStatus.rate > 0) {
if (streamStatus.rate < 1) {
streamCmdSlowFwd(false);
} else {
streamCmdFastFwd(false);
}
} else {
if ( streamStatus.rate > -1 ) {
if (streamStatus.rate > -1) {
streamCmdSlowRev(false);
} else {
streamCmdFastRev(false);
@ -251,17 +251,17 @@ function getStreamCmdResponse(respObj, respText) {
} // end if paused or delayed
$j('#zoomValue').text(streamStatus.zoom);
if ( streamStatus.zoom == '1.0' ) {
if (streamStatus.zoom == '1.0') {
setButtonState('zoomOutBtn', 'unavail');
} else {
setButtonState('zoomOutBtn', 'inactive');
}
if ( canEdit.Monitors ) {
if ( streamStatus.enabled ) {
if (canEdit.Monitors) {
if (streamStatus.enabled) {
enableAlmBtn.addClass('disabled');
enableAlmBtn.prop('title', disableAlarmsStr);
if ( streamStatus.forced ) {
if (streamStatus.forced) {
forceAlmBtn.addClass('disabled');
forceAlmBtn.prop('title', cancelForcedAlarmStr);
} else {
@ -277,16 +277,18 @@ function getStreamCmdResponse(respObj, respText) {
enableAlmBtn.prop('disabled', false);
} // end if canEdit.Monitors
if ( streamStatus.auth ) {
if (streamStatus.auth) {
auth_hash = streamStatus.auth;
// Try to reload the image stream.
var streamImg = $j('#liveStream'+monitorId);
if ( streamImg ) {
if (streamImg) {
var oldSrc = streamImg.attr('src');
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 respObj.status
} else {
@ -295,22 +297,20 @@ function getStreamCmdResponse(respObj, respText) {
// If it's an auth error, we should reload the whole page.
console.log("have error");
//window.location.reload();
if ( 1 ) {
var streamImg = $j('#liveStream'+monitorId);
if ( streamImg ) {
var oldSrc = streamImg.attr('src');
var newSrc = oldSrc.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
var streamImg = $j('#liveStream'+monitorId);
if (streamImg) {
var oldSrc = streamImg.attr('src');
var newSrc = oldSrc.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
streamImg.attr('src', newSrc);
console.log('Changing livestream src to ' + newSrc);
} else {
console.log('Unable to find streamImg liveStream');
}
streamImg.attr('src', newSrc);
console.log('Changing livestream src to ' + newSrc);
} else {
console.log('Unable to find streamImg liveStream');
}
}
var streamCmdTimeout = statusRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) {
if (alarmState == STATE_ALARM || alarmState == STATE_ALERT) {
streamCmdTimeout = streamCmdTimeout/5;
}
streamCmdTimer = setTimeout(streamCmdQuery, streamCmdTimeout);
@ -320,15 +320,15 @@ function streamCmdPause(action) {
setButtonState('pauseBtn', 'active');
setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) {
if (action) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_PAUSE;
streamCmdReq(data);
}
@ -337,9 +337,9 @@ function streamCmdPause(action) {
function streamCmdPlay(action) {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'active');
if ( streamStatus.delayed == true ) {
if (streamStatus.delayed == true) {
setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive');
@ -347,16 +347,16 @@ function streamCmdPlay(action) {
}
} else {
setButtonState('stopBtn', 'unavail');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'unavail');
setButtonState('slowFwdBtn', 'unavail');
setButtonState('slowRevBtn', 'unavail');
setButtonState('fastRevBtn', 'unavail');
}
}
if ( action ) {
if (action) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_PLAY;
streamCmdReq(data);
}
@ -374,15 +374,15 @@ function streamCmdStop(action) {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'unavail');
setButtonState('stopBtn', 'active');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'unavail');
setButtonState('slowFwdBtn', 'unavail');
setButtonState('slowRevBtn', 'unavail');
setButtonState('fastRevBtn', 'unavail');
}
if ( action ) {
if (action) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_STOP;
streamCmdReq(data);
}
@ -394,15 +394,15 @@ function streamCmdFastFwd(action) {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) {
if (action) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_FASTFWD;
streamCmdReq(data);
}
@ -412,20 +412,20 @@ function streamCmdSlowFwd(action) {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'active');
setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) {
if (action) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_SLOWFWD;
streamCmdReq(data);
}
setButtonState('pauseBtn', 'active');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('slowFwdBtn', 'inactive');
}
}
@ -434,20 +434,20 @@ function streamCmdSlowRev(action) {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'active');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) {
if (action) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_SLOWREV;
streamCmdReq(data);
}
setButtonState('pauseBtn', 'active');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('slowRevBtn', 'inactive');
}
}
@ -456,23 +456,23 @@ function streamCmdFastRev(action) {
setButtonState('pauseBtn', 'inactive');
setButtonState('playBtn', 'inactive');
setButtonState('stopBtn', 'inactive');
if ( monitorStreamReplayBuffer ) {
if (monitorStreamReplayBuffer) {
setButtonState('fastFwdBtn', 'inactive');
setButtonState('slowFwdBtn', 'inactive');
setButtonState('slowRevBtn', 'inactive');
setButtonState('fastRevBtn', 'inactive');
}
if ( action ) {
if (action) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_FASTREV;
streamCmdReq(data);
}
}
function streamCmdZoomIn( x, y ) {
function streamCmdZoomIn(x, y) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.x = x;
data.y = y;
data.command = CMD_ZOOMIN;
@ -481,22 +481,22 @@ function streamCmdZoomIn( x, y ) {
function streamCmdZoomOut() {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_ZOOMOUT;
streamCmdReq(data);
}
function streamCmdScale( scale ) {
function streamCmdScale(scale) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_SCALE;
data.scale = scale;
streamCmdReq(data);
}
function streamCmdPan( x, y ) {
function streamCmdPan(x, y) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.x = x;
data.y = y;
data.command = CMD_PAN;
@ -505,18 +505,18 @@ function streamCmdPan( x, y ) {
function streamCmdQuery() {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = CMD_QUERY;
streamCmdReq(data);
}
function getStatusCmdResponse(respObj, respText) {
watchdogOk('status');
if ( statusCmdTimer ) {
if (statusCmdTimer) {
statusCmdTimer = clearTimeout(statusCmdTimer);
}
if ( respObj.result == 'Ok' ) {
if (respObj.result == 'Ok') {
$j('#fpsValue').text(respObj.monitor.FrameRate);
setAlarmState(respObj.monitor.Status);
} else {
@ -556,20 +556,20 @@ function getAlarmCmdResponse(respObj, respText) {
function cmdDisableAlarms() {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = 'disableAlarms';
alarmCmdReq(data);
}
function cmdEnableAlarms() {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = 'enableAlarms';
alarmCmdReq(data);
}
function cmdAlarm() {
if ( enableAlmBtn.hasClass('disabled') ) {
if (enableAlmBtn.hasClass('disabled')) {
cmdEnableAlarms();
} else {
cmdDisableAlarms();
@ -578,23 +578,23 @@ function cmdAlarm() {
function cmdForceAlarm() {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = 'forceAlarm';
alarmCmdReq(data);
if ( window.event ) window.event.preventDefault();
if (window.event) window.event.preventDefault();
}
function cmdCancelForcedAlarm() {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.command = 'cancelForcedAlarm';
alarmCmdReq(data);
if ( window.event ) window.event.preventDefault();
if (window.event) window.event.preventDefault();
return false;
}
function cmdForce() {
if ( forceAlmBtn.hasClass('disabled') ) {
if (forceAlmBtn.hasClass('disabled')) {
cmdCancelForcedAlarm();
} else {
cmdForceAlarm();
@ -608,11 +608,11 @@ function controlReq(data) {
}
function getControlResponse(respObj, respText) {
if ( !respObj ) {
if (!respObj) {
return;
}
//console.log( respText );
if ( respObj.result != 'Ok' ) {
if (respObj.result != 'Ok') {
alert("Control response was status = "+respObj.status+"\nmessage = "+respObj.message);
}
}
@ -633,7 +633,7 @@ function controlCmd(event) {
var data = {};
if ( event && (xtell || ytell) ) {
if (event && (xtell || ytell)) {
var target = event.target;
var offset = $j(target).offset();
var width = $j(target).width();
@ -642,45 +642,45 @@ function controlCmd(event) {
var x = event.pageX - offset.left;
var y = event.pageY - offset.top;
if ( xtell ) {
if (xtell) {
var xge = parseInt((x*100)/width);
if ( xtell == -1 ) {
if (xtell == -1) {
xge = 100 - xge;
} else if ( xtell == 2 ) {
} else if (xtell == 2) {
xge = 2*(50 - xge);
}
data.xge = xge;
}
if ( ytell ) {
if (ytell) {
var yge = parseInt((y*100)/height);
if ( ytell == -1 ) {
if (ytell == -1) {
yge = 100 - yge;
} else if ( ytell == 2 ) {
} else if (ytell == 2) {
yge = 2*(50 - yge);
}
data.yge = yge;
}
}
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.control = control;
controlReq(data);
if ( streamMode == 'single' ) {
if (streamMode == 'single') {
setTimeout(fetchImage, 1000, $j('#imageFeed img'));
}
}
function controlCmdImage( x, y ) {
function controlCmdImage(x, y) {
var data = {};
if ( auth_hash ) data.auth = auth_hash;
if (auth_hash) data.auth = auth_hash;
data.scale = scale;
data.control = imageControlMode;
data.x = x;
data.y = y;
controlReq(data);
if ( streamMode == 'single' ) {
if (streamMode == 'single') {
setTimeout(fetchImage, 1000, $j('#imageFeed img'));
}
}
@ -701,10 +701,10 @@ function handleClick(event) {
var x = parseInt((event.pageX - pos.left) * scaleX);
var y = parseInt((event.pageY - pos.top) * scaleY);
if ( showMode == 'events' || !imageControlMode ) {
if (showMode == 'events' || !imageControlMode) {
if ( event.shift ) {
streamCmdPan(x, y);
} else if ( event.ctrlKey ) {
} else if (event.ctrlKey) {
streamCmdZoomOut();
} else {
streamCmdZoomIn(x, y);
@ -715,16 +715,16 @@ function handleClick(event) {
}
function appletRefresh() {
if ( streamStatus && (!streamStatus.paused && !streamStatus.delayed) ) {
if (streamStatus && (!streamStatus.paused && !streamStatus.delayed)) {
var streamImg = $j('#liveStream'+monitorId);
if ( streamImg ) {
if (streamImg) {
var parent = streamImg.parent();
streamImg.remove();
streamImg.append(parent);
} else {
console.error("Nothing found for liveStream"+monitorId);
}
if ( appletRefreshTime ) {
if (appletRefreshTime) {
setTimeout(appletRefresh, appletRefreshTime*1000);
}
} else {
@ -743,8 +743,8 @@ var watchdogFunctions = {
};
//Make sure the various refreshes are still taking effect
function watchdogCheck( type ) {
if ( watchdogInactive[type] ) {
function watchdogCheck(type) {
if (watchdogInactive[type]) {
console.log("Detected streamWatch of type: " + type + " stopped, restarting");
watchdogFunctions[type]();
watchdogInactive[type] = false;
@ -753,7 +753,7 @@ function watchdogCheck( type ) {
}
}
function watchdogOk( type ) {
function watchdogOk(type) {
watchdogInactive[type] = false;
}
@ -797,7 +797,7 @@ function getSettingsModal() {
}
function processClicks(event, field, value, row, $element) {
if ( field == 'Delete' ) {
if (field == 'Delete') {
$j.getJSON(monitorUrl + '?request=modal&modal=delconfirm')
.done(function(data) {
insertModalHtml('deleteConfirm', data.html);
@ -812,7 +812,7 @@ function processClicks(event, field, value, row, $element) {
// Manage the DELETE CONFIRMATION modal button
function manageDelConfirmModalBtns() {
document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) {
if ( ! canEdit.Events ) {
if (!canEdit.Events) {
enoperm();
return;
}
@ -821,7 +821,7 @@ function manageDelConfirmModalBtns() {
evt.preventDefault();
$j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+eid)
.done( function(data) {
.done(function(data) {
table.bootstrapTable('refresh');
$j('#deleteConfirm').modal('hide');
})
@ -838,7 +838,7 @@ function msieVer() {
var ua = window.navigator.userAgent;
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;
} else { // If another browser, return 0
return 0;
@ -846,31 +846,31 @@ function msieVer() {
}
function initPage() {
if ( canView.Control ) {
if (canView.Control) {
// Load the PTZ Preset modal into the DOM
if ( monitorControllable ) getCtrlPresetModal();
if (monitorControllable) getCtrlPresetModal();
// Load the settings modal into the DOM
if ( monitorType == "Local" ) getSettingsModal();
if (monitorType == "Local") getSettingsModal();
}
if ( monitorType != 'WebSite' ) {
if ( streamMode == 'single' ) {
statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout );
if (monitorType != 'WebSite') {
if (streamMode == 'single') {
statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'status');
} else {
streamCmdTimer = setTimeout(streamCmdQuery, (Math.random()+0.1)*statusRefreshTimeout );
streamCmdTimer = setTimeout(streamCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream');
}
if ( canStreamNative || (streamMode == 'single') ) {
if (canStreamNative || (streamMode == 'single')) {
var streamImg = $j('#imageFeed img');
if ( !streamImg ) {
if (!streamImg) {
streamImg = $j('#imageFeed object');
}
if ( !streamImg ) {
if (!streamImg) {
console.error('No streamImg found for imageFeed');
} else {
if ( streamMode == 'single' ) {
if (streamMode == 'single') {
streamImg.click(streamImg, fetchImage);
setInterval(fetchImage, imageRefreshTimeout, $j('#imageFeed img'));
} else {
@ -881,17 +881,17 @@ function initPage() {
} // end if have streamImg
} // streamMode native or single
if ( refreshApplet && appletRefreshTime ) {
if (refreshApplet && appletRefreshTime) {
setTimeout(appletRefresh, appletRefreshTime*1000);
}
if ( window.history.length == 1 ) {
if (window.history.length == 1) {
$j('#closeControl').html('');
}
document.querySelectorAll('select[name="scale"]').forEach(function(el) {
el.onchange = window['changeScale'];
});
changeScale();
} else if ( monitorRefresh > 0 ) {
} else if (monitorRefresh > 0) {
setInterval(reloadWebSite, monitorRefresh*1000);
}
@ -920,7 +920,7 @@ function initPage() {
settingsBtn.prop('disabled', !(canView.Control && monitorType == 'Local'));
// 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
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.
//
if ( !canEdit('Monitors') ) {
if (!canEdit('Monitors')) {
$view = 'error';
return;
}
@ -31,11 +31,9 @@ function probeV4L() {
$command = getZmuCommand(' --query --device');
if ( !empty($_REQUEST['device']) )
$command .= '='.escapeshellarg($_REQUEST['device']);
$result = exec(escapeshellcmd($command), $output, $status);
if ( $status ) {
ZM\Error("Unable to probe local cameras using $command, status is '$status' " . implode("\n",$output));
return $cameras;
if ($status) {
ZM\Warning("Errors while probe local cameras using $command, status is '$status' " . implode("\n", $output));
}
$monitors = array();
@ -325,15 +323,15 @@ xhtmlHeaders(__FILE__, translate('MonitorProbe') );
<div id="page">
<h2><?php echo translate('MonitorProbe') ?></h2>
<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="mid" value="<?php echo validNum($_REQUEST['mid']) ?>"/>
<input type="hidden" name="mid" value="<?php echo isset($_REQUEST['mid'])?validNum($_REQUEST['mid']):'' ?>"/>
<p>
<?php echo translate('MonitorProbeIntro') ?>
</p>
<p>
<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>
<div id="contentButtons">
<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
$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['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="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="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>
<?php } // end if snapshot->Id ?>
</div>
@ -96,6 +95,27 @@ if ( !$snapshot->Id() ) {
?>
</div><!--content-->
<?php } // end if snapshot->Id() ?>
</form>
</div><!--page-->
</form>
<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() ?>

View File

@ -18,7 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canView('Events') ) {
if (!(canView('Events') or canView('Snapshots'))) {
$view = 'error';
return;
}
@ -53,9 +53,11 @@ if ( !$mimetype ) {
}
$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;
ZM\Debug("downloading archive from $filename_path");
ZM\Debug('downloading archive from '.$filename_path);
if ( is_readable($filename_path) ) {
while (ob_get_level()) {
ob_end_clean();

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