Merge branch 'master' of github.com:/ZoneMinder/ZoneMinder

This commit is contained in:
Isaac Connor 2018-10-22 16:14:36 -04:00
commit 9938346752
50 changed files with 1321 additions and 865 deletions

View File

@ -42,7 +42,7 @@ This is the recommended method to install ZoneMinder onto your system. ZoneMinde
If a repository that hosts ZoneMinder packages is not available for your distro, then you are encouraged to build your own package, rather than build from source. While each distro is different in ways that set it apart from all the others, they are often similar enough to allow you to adapt another distro's package building instructions to your own.
### Building a ZoneMinder Package
### Building a ZoneMinder Package ###
Building ZoneMinder into a package is not any harder than building from source. As a matter of fact, if you have successfully built ZoneMinder from source in the past, then you may find these steps to be easier.
@ -55,7 +55,7 @@ Please visit our [ReadtheDocs site](https://zoneminder.readthedocs.org/en/stable
### Package Maintainers
Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source.
For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script:
For example, let's say I have created a new ZoneMinder package that contains the cambozola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script:
```bash
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
```

View File

@ -781,6 +781,7 @@ INSERT INTO `Controls` VALUES (NULL,'D-LINK DCS-3415','Remote','DCS3415',0,0,0,1
INSERT INTO `Controls` VALUES (NULL,'IOS Camera','Ffmpeg','IPCAMIOS',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
INSERT INTO `Controls` VALUES (NULL,'Dericam P2','Ffmpeg','DericamP2',0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,10,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,45,0,0,1,0,0,0,0,1,1,45,0,0,0,0);
INSERT INTO `Controls` VALUES (NULL,'Trendnet','Remote','Trendnet',1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
INSERT INTO `Controls` VALUES (NULL,'PSIA','Remote','PSIA',0,0,0,1,0,0,1,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,1,0,1,0,0,0,0,1,-100,100,0,0,1,0,0,0,0,1,-100,100,0,0,0,0);
INSERT INTO `Controls` VALUES (NULL,'Dahua','Remote','Dahua',0,0,0,1,0,0,1,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,8,0,0,1,0,0,0,0,1,1,8,0,0,0,0);
--
@ -808,6 +809,7 @@ INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, unicast','Remote','rtsp
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, multicast','Remote','rtsp',0,255,'rtsp','rtpMulti','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, RTP/RTSP','Remote','rtsp',0,255,'rtsp','rtpRtsp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, RTP/RTSP/HTTP','Remote',NULL,NULL,NULL,'rtsp','rtpRtspHttp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'D-link DCS-930L, 640x480, mjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/mjpeg.cgi',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);

5
db/zm_update-1.32.2.sql Normal file
View File

@ -0,0 +1,5 @@
--
-- This updates a 1.32.1 database to 1.32.2
--
-- No changes required
--

9
db/zm_update-1.32.3.sql Normal file
View File

@ -0,0 +1,9 @@
--
-- This updates a 1.32.2 database to 1.32.3
--
--
-- Add some additional monitor preset values
--
INSERT INTO MonitorPresets VALUES (NULL,'D-link DCS-930L, 640x480, mjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/mjpeg.cgi',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);

View File

@ -25,7 +25,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.32.1
Version: 1.32.2
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons
@ -320,6 +320,13 @@ EOF
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder
%changelog
* Sat Oct 13 2018 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.32.2-1
- 1.32.2 release
- Bug fix release
* Thu Oct 04 2018 Sérgio Basto <sergio@serjux.com> - 1.32.1-2
- Mass rebuild for x264 and/or x265
* Tue Oct 2 2018 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.32.1-1
- 1.32.1 release
- Bug fix release

View File

@ -13,6 +13,13 @@ The API is built in CakePHP and lives under the ``/api`` directory. It
provides a RESTful service and supports CRUD (create, retrieve, update, delete)
functions for Monitors, Events, Frames, Zones and Config.
Enabling API
^^^^^^^^^^^^
A default ZoneMinder installs with APIs enabled. You can explictly enable/disable the APIs
via the Options->System menu by enabling/disabling ``OPT_USE_API``. Note that if you intend
to use APIs with 3rd party apps, such as zmNinja or others that use APIs, you should also
enable ``AUTH_HASH_LOGINS``.
Login, Logout & API Security
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The APIs tie into ZoneMinder's existing security model. This means if you have

View File

@ -0,0 +1,365 @@
package ZoneMinder::Control::PSIA;
use 5.006;
use strict;
use warnings;
require ZoneMinder::Base;
require ZoneMinder::Control;
our @ISA = qw(ZoneMinder::Control);
our $REALM = 'TV-IP450PI';
our $USERNAME = 'admin';
our $PASSWORD = '';
our $ADDRESS = '';
our $PROTOCOL = 'http://';
use ZoneMinder::Logger qw(:all);
use ZoneMinder::Config qw(:all);
use ZoneMinder::Database qw(zmDbConnect);
sub open
{
my $self = shift;
$self->loadMonitor();
if ( ( $self->{Monitor}->{ControlAddress} =~ /^(?<PROTOCOL>https?:\/\/)?(?<USERNAME>[^:@]+)?:?(?<PASSWORD>[^\/@]+)?@?(?<ADDRESS>.*)$/ ) ) {
$PROTOCOL = $+{PROTOCOL} if $+{PROTOCOL};
$USERNAME = $+{USERNAME} if $+{USERNAME};
$PASSWORD = $+{PASSWORD} if $+{PASSWORD};
$ADDRESS = $+{ADDRESS} if $+{ADDRESS};
} else {
Error('Failed to parse auth from address ' . $self->{Monitor}->{ControlAddress});
$ADDRESS = $self->{Monitor}->{ControlAddress};
}
if ( !($ADDRESS =~ /:/) ) {
Error('You generally need to also specify the port. I will append :80');
$ADDRESS .= ':80';
}
use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new;
$self->{ua}->agent( "ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION );
$self->{state} = 'closed';
Debug( "sendCmd credentials control address:'".$ADDRESS
."' realm:'" . $REALM
. "' username:'" . $USERNAME
. "' password:'".$PASSWORD
."'"
);
$self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD);
# Detect REALM
my $req = HTTP::Request->new(GET=>$PROTOCOL . $ADDRESS . "/PSIA/PTZ/channels");
my $res = $self->{ua}->request($req);
if ($res->is_success) {
$self->{state} = 'open';
return;
} elsif (! $res->is_success) {
Debug("Need newer REALM");
if ( $res->status_line() eq '401 Unauthorized' ) {
my $headers = $res->headers();
foreach my $k ( keys %$headers ) {
Debug("Initial Header $k => $$headers{$k}");
} # end foreach
if ( $$headers{'www-authenticate'} ) {
my ($auth, $tokens) = $$headers{'www-authenticate'} =~ /^(\w+)\s+(.*)$/;
if ($tokens =~ /\w+="([^"]+)"/i) {
$REALM = $1;
Debug("Changing REALM to $REALM");
$self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD);
} # end if
} else {
Debug("No WWW-Authenticate header");
} # end if www-authenticate header
} # end if $res->status_line() eq '401 Unauthorized'
} # end elsif ! $res->is_success
}
sub close
{
my $self = shift;
$self->{state} = 'closed';
}
sub printMsg
{
my $self = shift;
my $msg = shift;
my $msg_len = length($msg);
Debug( $msg."[".$msg_len."]" );
}
sub sendGetRequest {
my $self = shift;
my $url_path = shift;
my $result = undef;
my $url = $PROTOCOL . $ADDRESS . $url_path;
my $req = HTTP::Request->new(GET=>$url);
my $res = $self->{ua}->request($req);
if ($res->is_success) {
$result = !undef;
} else {
if ( $res->status_line() eq '401 Unauthorized' ) {
Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
Error("Content was " . $res->content() );
my $res = $self->{ua}->request($req);
if ( $res->is_success ) {
$result = !undef;
} else {
Error("Content was " . $res->content() );
}
}
if ( ! $result ) {
Error("Error check failed: '".$res->status_line());
}
}
return($result);
}
sub sendPutRequest {
my $self = shift;
my $url_path = shift;
my $content = shift;
my $result = undef;
my $url = $PROTOCOL . $ADDRESS . $url_path;
my $req = HTTP::Request->new(PUT=>$url);
if(defined($content)) {
$req->content_type("application/x-www-form-urlencoded; charset=UTF-8");
$req->content('<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $content);
}
my $res = $self->{ua}->request($req);
if ($res->is_success) {
$result = !undef;
} else {
if ( $res->status_line() eq '401 Unauthorized' ) {
Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
Error("Content was " . $res->content() );
my $res = $self->{ua}->request($req);
if ( $res->is_success ) {
$result = !undef;
} else {
Error("Content was " . $res->content() );
}
}
if ( ! $result ) {
Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
}
}
return($result);
}
sub sendDeleteRequest {
my $self = shift;
my $url_path = shift;
my $result = undef;
my $url = $PROTOCOL . $ADDRESS . $url_path;
my $req = HTTP::Request->new(DELETE=>$url);
my $res = $self->{ua}->request($req);
if ($res->is_success) {
$result = !undef;
} else {
if ( $res->status_line() eq '401 Unauthorized' ) {
Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
Error("Content was " . $res->content() );
my $res = $self->{ua}->request($req);
if ( $res->is_success ) {
$result = !undef;
} else {
Error("Content was " . $res->content() );
}
}
if ( ! $result ) {
Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
}
}
return($result);
}
sub move
{
my $self = shift;
my $panPercentage = shift;
my $tiltPercentage = shift;
my $zoomPercentage = shift;
my $cmd = "set_relative_pos&posX=$panSteps&posY=$tiltSteps";
my $ptzdata = '<PTZData version="1.0" xmlns="urn:psialliance-org">';
$ptzdata .= '<pan>' . $panPercentage . '</pan>';
$ptzdata .= '<tilt>' . $tiltPercentage . '</tilt>';
$ptzdata .= '<zoom>' . $zoomPercentage . '</zoom>';
$ptzdata .= '<Momentary><duration>500</duration></Momentary>';
$ptzdata .= '</PTZData>';
$self->sendPutRequest("/PSIA/PTZ/channels/1/momentary", $ptzdata);
}
sub moveRelUpLeft
{
my $self = shift;
Debug( "Move Up Left" );
$self->move(-50, 50, 0);
}
sub moveRelUp
{
my $self = shift;
Debug( "Move Up" );
$self->move(0, 50, 0);
}
sub moveRelUpRight
{
my $self = shift;
Debug( "Move Up Right" );
$self->move(50, 50, 0);
}
sub moveRelLeft
{
my $self = shift;
Debug( "Move Left" );
$self->move(-50, 0, 0);
}
sub moveRelRight
{
my $self = shift;
Debug( "Move Right" );
$self->move(50, 0, 0);
}
sub moveRelDownLeft
{
my $self = shift;
Debug( "Move Down Left" );
$self->move(-50, -50, 0);
}
sub moveRelDown
{
my $self = shift;
Debug( "Move Down" );
$self->move(0, -50, 0);
}
sub moveRelDownRight
{
my $self = shift;
Debug( "Move Down Right" );
$self->move(50, -50, 0);
}
sub zoomRelTele
{
my $self = shift;
Debug("Zoom Relative Tele");
$self->move(0, 0, 50);
}
sub zoomRelWide
{
my $self = shift;
Debug("Zoom Relative Wide");
$self->move(0, 0, -50);
}
sub presetClear
{
my $self = shift;
my $params = shift;
my $preset_id = $self->getParam($params, 'preset');
my $url_path = "/PSIA/PTZ/channels/1/presets/" . $preset_id;
$self->sendDeleteRequest($url_path);
}
sub presetSet
{
my $self = shift;
my $params = shift;
my $preset_id = $self->getParam($params, 'preset');
my $dbh = zmDbConnect(1);
my $sql = 'SELECT * FROM ControlPresets WHERE MonitorId = ? AND Preset = ?';
my $sth = $dbh->prepare($sql)
or Fatal("Can't prepare sql '$sql': " . $dbh->errstr());
my $res = $sth->execute($self->{Monitor}->{Id}, $preset_id)
or Fatal("Can't execute sql '$sql': " . $sth->errstr());
my $control_preset_row = $sth->fetchrow_hashref();
my $new_label_name = $control_preset_row->{'Label'};
my $url_path = "/PSIA/PTZ/channels/1/presets/" . $preset_id;
my $ptz_preset_data = '<PTZPreset>';
$ptz_preset_data .= '<id>' . $preset_id . '</id>';
$ptz_preset_data .= '<presetName>' . $new_label_name . '</presetName>';
$ptz_preset_data .= '</PTZPreset>';
$self->sendPutRequest($url_path, $ptz_preset_data);
}
sub presetGoto
{
my $self = shift;
my $params = shift;
my $preset_id = $self->getParam($params, 'preset');
my $url_path = '/PSIA/PTZ/channels/1/presets/' . $preset_id . '/goto';
$self->sendPutRequest($url_path);
}
1;
__END__
=head1 NAME
ZoneMinder::Control::PSIA - Perl module for cameras implementing the PSIA
(Physical Security Interoperability Alliance), IP Media Devices API
specification
=head1 SYNOPSIS
use ZoneMinder::Control::PSIA;
place this in /usr/share/perl5/ZoneMinder/Control
=head1 DESCRIPTION
This has so far been tested with:
- Trendnet TV-IP450PI
=head2 EXPORT
None by default.
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2018 ZoneMinder LLC
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
=cut

View File

@ -704,6 +704,8 @@ sub Fatal( @ ) {
if ( $SIG{TERM} and ( $SIG{TERM} ne 'DEFAULT' ) ) {
$SIG{TERM}();
}
# I think if we don't disconnect we will leave sockets around in TIME_WAIT
zmDbDisconnect();
exit(-1);
}

View File

@ -69,6 +69,7 @@ use Time::HiRes qw/gettimeofday/;
use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage);
use autouse 'Data::Dumper'=>qw(Dumper);
use File::Path qw(make_path);
my $daemon = 0;
my $filter_name = '';
@ -162,7 +163,7 @@ my $delay = $Config{ZM_FILTER_EXECUTE_INTERVAL};
my $event_id = 0;
if ( ! EVENT_PATH ) {
Error("No event path defined. Config was $Config{ZM_DIR_EVENTS}\n");
Error("No event path defined. Config was $Config{ZM_DIR_EVENTS}");
die;
}
@ -173,11 +174,11 @@ chdir( EVENT_PATH );
my $dbh = zmDbConnect();
if ( $filter_name ) {
Info("Scanning for events using filter '$filter_name'\n");
Info("Scanning for events using filter '$filter_name'");
} elsif ( $filter_id ) {
Info("Scanning for events using filter id '$filter_id'\n");
Info("Scanning for events using filter id '$filter_id'");
} else {
Info("Scanning for events using all filters\n");
Info("Scanning for events using all filters");
}
if ( ! ( $filter_name or $filter_id ) ) {
@ -191,7 +192,7 @@ my $last_action = 0;
while( !$zm_terminate ) {
my $now = time;
if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} ) {
Debug("Reloading filters\n");
Debug("Reloading filters");
$last_action = $now;
@filters = getFilters({ Name=>$filter_name, Id=>$filter_id });
}
@ -211,7 +212,7 @@ while( !$zm_terminate ) {
last if (!$daemon and ($filter_name or $filter_id)) or $zm_terminate;
Debug("Sleeping for $delay seconds\n");
Debug("Sleeping for $delay seconds");
sleep($delay);
}
@ -292,48 +293,48 @@ sub checkFilter {
last if $zm_terminate;
my $Event = new ZoneMinder::Event($$event{Id}, $event);
Debug("Checking event $event->{Id}");
Debug("Checking event $Event->{Id}");
my $delete_ok = !undef;
$dbh->ping();
if ( $filter->{AutoArchive} ) {
Info("Archiving event $event->{Id}");
Info("Archiving event $Event->{Id}");
# Do it individually to avoid locking up the table for new events
my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql )
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $event->{Id} )
my $res = $sth->execute( $Event->{Id} )
or Error("Unable to execute '$sql': ".$dbh->errstr());
}
if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) {
if ( !$event->{Videoed} ) {
$delete_ok = undef if !generateVideo($filter, $event);
if ( !$Event->{Videoed} ) {
$delete_ok = undef if !generateVideo($filter, $Event);
}
}
if ( $Config{ZM_OPT_EMAIL} && $filter->{AutoEmail} ) {
if ( !$event->{Emailed} ) {
if ( !$Event->{Emailed} ) {
$delete_ok = undef if !sendEmail($filter, $Event);
}
}
if ( $Config{ZM_OPT_MESSAGE} && $filter->{AutoMessage} ) {
if ( !$event->{Messaged} ) {
if ( !$Event->{Messaged} ) {
$delete_ok = undef if !sendMessage($filter, $Event);
}
}
if ( $Config{ZM_OPT_UPLOAD} && $filter->{AutoUpload} ) {
if ( !$event->{Uploaded} ) {
if ( !$Event->{Uploaded} ) {
$delete_ok = undef if !uploadArchFile($filter, $Event);
}
}
if ( $filter->{AutoExecute} ) {
if ( !$event->{Executed} ) {
$delete_ok = undef if !executeCommand($filter, $event);
if ( !$Event->{Executed} ) {
$delete_ok = undef if !executeCommand($filter, $Event);
}
}
if ( $filter->{AutoDelete} ) {
if ( $delete_ok ) {
$Event->delete();
} else {
Error("Unable toto delete event $event->{Id} as previous operations failed");
Error("Unable to delete event $Event->{Id} as previous operations failed");
}
} # end if AutoDelete
@ -364,11 +365,11 @@ sub checkFilter {
sub generateVideo {
my $filter = shift;
my $event = shift;
my $Event = shift;
my $phone = shift;
my $rate = $event->{DefaultRate}/100;
my $scale = $event->{DefaultScale}/100;
my $rate = $Event->{DefaultRate}/100;
my $scale = $Event->{DefaultScale}/100;
my $format;
my @ffmpeg_formats = split(/\s+/, $Config{ZM_FFMPEG_FORMATS});
@ -393,7 +394,7 @@ sub generateVideo {
my $command = join('',
$Config{ZM_PATH_BIN},
'/zmvideo.pl -e ',
$event->{Id},
$Event->{Id},
' -r ',
$rate,
' -s ',
@ -405,10 +406,10 @@ sub generateVideo {
chomp($output);
my $status = $? >> 8;
if ( $status || logDebugging() ) {
Debug("Output: $output\n");
Debug("Output: $output");
}
if ( $status ) {
Error("Video generation '$command' failed with status: $status\n");
Error("Video generation '$command' failed with status: $status");
if ( wantarray() ) {
return( undef, undef );
}
@ -417,8 +418,8 @@ sub generateVideo {
my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($event->{Id})
or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
if ( wantarray() ) {
return( $format, $output );
}
@ -453,7 +454,7 @@ sub generateImage {
chomp( $output );
my $status = $? >> 8;
if ( $status || logDebugging() ) {
Debug("Output: $output\n");
Debug("Output: $output");
}
if ( $status ) {
Error("Failed $command status $status");
@ -467,22 +468,30 @@ sub generateImage {
sub uploadArchFile {
my $filter = shift;
my $event = shift;
my $Event = shift;
if ( ! $Config{ZM_UPLOAD_HOST} ) {
Error('Cannot upload archive as no upload host defined');
return( 0 );
}
my $archFile = $event->{MonitorName}.'-'.$event->{Id};
my $archImagePath = $event->Path()
# Try to make the path to the upload folder if it doesn't already exist
make_path( $Config{ZM_UPLOAD_LOC_DIR} );
# Complain if the upload folder is still not writable
if ( ! -w $Config{ZM_UPLOAD_LOC_DIR} ) {
Error("Upload folder either does not exist or is not writable: $Config{ZM_UPLOAD_LOC_DIR}");
return(0);
}
my $archFile = $Event->{MonitorName}.'-'.$Event->{Id};
my $archImagePath = $Event->Path()
.'/'
.(
( $Config{ZM_UPLOAD_ARCH_ANALYSE} )
? '{*analyse,*capture}'
: '*capture'
? '{*analyse.jpg,*capture.jpg,snapshot.jpg,*.mp4}'
: '{*capture.jpg,snapshot.jpg,*.mp4}'
)
.'.jpg'
;
my @archImageFiles = glob($archImagePath);
my $archLocPath;
@ -492,11 +501,11 @@ sub uploadArchFile {
$archFile .= '.zip';
$archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile;
my $zip = Archive::Zip->new();
Info("Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n");
Info("Creating upload file '$archLocPath', ".int(@archImageFiles).' files');
my $status = &AZ_OK;
foreach my $imageFile ( @archImageFiles ) {
Debug("Adding $imageFile\n");
Debug("Adding $imageFile");
my $member = $zip->addFile($imageFile);
if ( !$member ) {
Error("Unable toto add image file $imageFile to zip archive $archLocPath");
@ -524,7 +533,7 @@ sub uploadArchFile {
$archFile .= '.tar';
}
$archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile;
Info("Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n");
Info("Creating upload file '$archLocPath', ".int(@archImageFiles).' files');
if ( $archError = !Archive::Tar->create_archive(
$archLocPath,
@ -540,7 +549,7 @@ sub uploadArchFile {
return( 0 );
} else {
if ( $Config{ZM_UPLOAD_PROTOCOL} eq 'ftp' ) {
Info('Uploading to '.$Config{ZM_UPLOAD_HOST}." using FTP");
Info('Uploading to '.$Config{ZM_UPLOAD_HOST}.' using FTP');
my $ftp = Net::FTP->new(
$Config{ZM_UPLOAD_HOST},
Timeout=>$Config{ZM_UPLOAD_TIMEOUT},
@ -548,24 +557,24 @@ sub uploadArchFile {
Debug=>$Config{ZM_UPLOAD_DEBUG}
);
if ( !$ftp ) {
Error("Unable tocreate FTP connection: $@");
Error("Unable to create FTP connection: $@");
return 0;
}
$ftp->login($Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS})
or Error("FTP - Unable tologin");
or Error("FTP - Unable to login");
$ftp->binary()
or Error("FTP - Unable togo binary");
or Error("FTP - Unable to go binary");
$ftp->cwd($Config{ZM_UPLOAD_REM_DIR})
or Error("FTP - Unable tocwd")
or Error("FTP - Unable to cwd")
if ( $Config{ZM_UPLOAD_REM_DIR} );
$ftp->put( $archLocPath )
or Error("FTP - Unable toupload '$archLocPath'");
or Error("FTP - Unable to upload '$archLocPath'");
$ftp->quit()
or Error("FTP - Unable toquit");
or Error("FTP - Unable to quit");
} else {
my $host = $Config{ZM_UPLOAD_HOST};
$host .= ':'.$Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT};
Info('Uploading to '.$host." using SFTP\n");
Info('Uploading to '.$host.' using SFTP');
my %sftpOptions = (
host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER}
($Config{ZM_UPLOAD_PASS} ? (password=>$Config{ZM_UPLOAD_PASS}) : ()),
@ -580,7 +589,7 @@ sub uploadArchFile {
$sftpOptions{more} = [@more_ssh_args];
my $sftp = Net::SFTP::Foreign->new($Config{ZM_UPLOAD_HOST}, %sftpOptions);
if ( $sftp->error ) {
Error("Unable tocreate SFTP connection: ".$sftp->error);
Error("Unable to create SFTP connection: ".$sftp->error);
return 0;
}
$sftp->setcwd($Config{ZM_UPLOAD_REM_DIR})
@ -592,9 +601,9 @@ sub uploadArchFile {
unlink($archLocPath);
my $sql = 'UPDATE Events SET Uploaded = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($event->{Id})
or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
}
return 1;
} # end sub uploadArchFile
@ -622,9 +631,9 @@ sub substituteTags {
WHERE EventId = ? AND Type = 'Alarm'
ORDER BY FrameId`;
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
or Fatal( "Unable toexecute '$sql': ".$dbh->errstr());
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
my $rows = 0;
while( my $frame = $sth->fetchrow_hashref() ) {
if ( !$first_alarm_frame ) {
@ -796,7 +805,7 @@ sub sendEmail {
$ssmtp_location = qx('which ssmtp');
}
if ( !$ssmtp_location ) {
Debug('Unable tofind ssmtp, trying MIME::Lite->send');
Debug('Unable to find ssmtp, trying MIME::Lite->send');
MIME::Lite->send('smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60);
$mail->send();
} else {
@ -828,16 +837,16 @@ sub sendEmail {
}
};
if ( $@ ) {
Error("Unable tosend email: $@");
Error("Unable to send email: $@");
return 0;
} else {
Info('Notification email sent');
}
my $sql = 'UPDATE Events SET Emailed = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
return 1;
}
@ -898,7 +907,7 @@ sub sendMessage {
$ssmtp_location = qx('which ssmtp');
}
if ( !$ssmtp_location ) {
Debug('Unable tofind ssmtp, trying MIME::Lite->send');
Debug('Unable to find ssmtp, trying MIME::Lite->send');
MIME::Lite->send(smtp=>$Config{ZM_EMAIL_HOST}, Timeout=>60);
$mail->send();
} else {
@ -933,29 +942,29 @@ sub sendMessage {
}
};
if ( $@ ) {
Error("Unable tosend email: $@");
Error("Unable to send email: $@");
return 0;
} else {
Info('Notification message sent');
}
my $sql = 'UPDATE Events SET Messaged = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable toprepare '$sql': ".$dbh->errstr());
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
or Fatal("Unable toexecute '$sql': ".$dbh->errstr());
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
return 1;
} # end sub sendMessage
sub executeCommand {
my $filter = shift;
my $event = shift;
my $Event = shift;
my $event_path = $event->Path();
my $event_path = $Event->Path();
my $command = $filter->{AutoExecuteCmd};
$command .= " $event_path";
$command = substituteTags($command, $filter, $event);
$command = substituteTags($command, $filter, $Event);
Info("Executing '$command'");
my $output = qx($command);
@ -971,7 +980,7 @@ sub executeCommand {
my $sql = 'UPDATE Events SET Executed = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $event->{Id} )
my $res = $sth->execute( $Event->{Id} )
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
}
return( 1 );

View File

@ -44,7 +44,6 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
my $store_state=''; # PP - will remember state name passed
logInit();
Info("Aftere LogInit");
my $command = $ARGV[0]||'';
if ( $command eq 'version' ) {

View File

@ -88,13 +88,13 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
logInit();
logSetSignal();
Info( "Trigger daemon starting\n" );
Info( "Trigger daemon starting" );
my $dbh = zmDbConnect();
my $base_rin = '';
foreach my $connection ( @connections ) {
Info( "Opening connection '$connection->{name}'\n" );
Info( "Opening connection '$connection->{name}'" );
$connection->open();
}
@ -109,7 +109,7 @@ foreach my $connection ( @in_select_connections ) {
my %spawned_connections;
my %monitors;
my $monitor_reload_time = 0;
my $needsReload = 0;
my @needsReload;
loadMonitors();
$! = undef;
@ -127,14 +127,14 @@ while( 1 ) {
my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout );
if ( $nfound > 0 ) {
Debug( "Got input from $nfound connections\n" );
Debug( "Got input from $nfound connections" );
foreach my $connection ( @in_select_connections ) {
if ( vec( $rout, $connection->fileno(), 1 ) ) {
Debug( 'Got input from connection '
.$connection->name()
.' ('
.$connection->fileno()
.")\n"
.")"
);
if ( $connection->spawns() ) {
my $new_connection = $connection->accept();
@ -143,7 +143,7 @@ while( 1 ) {
.$new_connection->fileno()
.'), '
.int(keys(%spawned_connections))
." spawned connections\n"
." spawned connections"
);
} else {
my $messages = $connection->getMessages();
@ -162,7 +162,7 @@ while( 1 ) {
.$connection->name()
.' ('
.$connection->fileno()
.")\n"
.")"
);
my $messages = $connection->getMessages();
if ( defined($messages) ) {
@ -175,7 +175,7 @@ while( 1 ) {
.$connection->fileno()
.'), '
.int(keys(%spawned_connections))
." spawned connections\n"
." spawned connections"
);
$connection->close();
}
@ -206,7 +206,7 @@ while( 1 ) {
if ( ! zmMemVerify($monitor) ) {
# Our attempt to verify the memory handle failed. We should reload the monitors.
# Don't need to zmMemInvalidate because the monitor reload will do it.
$needsReload = 1;
push @needsReload, $monitor;
next;
}
@ -217,8 +217,8 @@ while( 1 ) {
]
);
#print( "$monitor->{Id}: S:$state, LE:$last_event\n" );
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" );
#print( "$monitor->{Id}: S:$state, LE:$last_event" );
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}" );
if ( $state == STATE_ALARM || $state == STATE_ALERT ) {
# In alarm state
if ( !defined($monitor->{LastEvent})
@ -261,14 +261,14 @@ while( 1 ) {
}
if ( my @action_times = keys(%actions) ) {
Debug( "Checking for timed actions\n" );
Debug( "Checking for timed actions" );
my $now = time();
foreach my $action_time ( sort( grep { $_ < $now } @action_times ) ) {
Info( "Found actions expiring at $action_time\n" );
Info( "Found actions expiring at $action_time" );
foreach my $action ( @{$actions{$action_time}} ) {
my $connection = $action->{connection};
my $message = $action->{message};
Info( "Found action '$message'\n" );
Info( "Found action '$message'" );
handleMessage( $connection, $message );
}
delete( $actions{$action_time} );
@ -293,23 +293,41 @@ while( 1 ) {
}
}
# If necessary reload monitors
if ( $needsReload || ((time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )) {
# Reload all monitors from the dB every MONITOR_RELOAD_INTERVAL
if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ) {
foreach my $monitor ( values(%monitors) ) {
# Free up any used memory handle
zmMemInvalidate( $monitor );
zmMemInvalidate( $monitor ); # Free up any used memory handle
}
loadMonitors();
$needsReload = 0;
@needsReload = (); # We just reloaded all monitors so no need reload a specific monitor
# If we have NOT just reloaded all monitors, reload a specific monitor if its shared mem changed
} elsif ( @needsReload ) {
foreach my $monitor ( @needsReload ) {
loadMonitor($monitor);
}
@needsReload = ();
}
# zmDbConnect will ping and reconnect if neccessary
$dbh = zmDbConnect();
} # end while ( 1 )
Info( "Trigger daemon exiting\n" );
Info( "Trigger daemon exiting" );
exit;
sub loadMonitor {
my $monitor = shift;
Debug( "Loading monitor $monitor" );
zmMemInvalidate( $monitor );
if ( zmMemVerify( $monitor ) ) { # This will re-init shared memory
$monitor->{LastState} = zmGetMonitorState( $monitor );
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
}
}
sub loadMonitors {
Debug( "Loading monitors\n" );
Debug( "Loading monitors" );
$monitor_reload_time = time();
my %new_monitors = ();
@ -323,7 +341,7 @@ sub loadMonitors {
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
or Fatal( "Can't execute: ".$sth->errstr() );
while( my $monitor = $sth->fetchrow_hashref() ) {
if ( zmMemVerify( $monitor ) ) {
if ( zmMemVerify( $monitor ) ) { # This will re-init shared memory
$monitor->{LastState} = zmGetMonitorState( $monitor );
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
}
@ -344,14 +362,14 @@ sub handleMessage {
my $monitor = $monitors{$id};
if ( !$monitor ) {
Warning( "Can't find monitor '$id' for message '$message'\n" );
Warning( "Can't find monitor '$id' for message '$message'" );
return;
}
Debug( "Found monitor for id '$id'\n" );
Debug( "Found monitor for id '$id'" );
next if ( !zmMemVerify( $monitor ) );
Debug( "Handling action '$action'\n" );
Debug( "Handling action '$action'" );
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) {
my $state = $1;
my $delay = $2;
@ -362,7 +380,7 @@ sub handleMessage {
}
# Force a reload
$monitor_reload_time = 0;
Info( "Set monitor to $state\n" );
Info( "Set monitor to $state" );
if ( $delay ) {
my $action_text = $id.'|'.( ($state eq 'enable')
? 'disable'
@ -379,7 +397,7 @@ sub handleMessage {
if ( $trigger eq 'on' ) {
zmTriggerEventOn( $monitor, $score, $cause, $text );
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
Info( "Trigger '$trigger' '$cause'\n" );
Info( "Trigger '$trigger' '$cause'" );
if ( $delay ) {
my $action_text = $id.'|cancel';
handleDelay($delay, $connection, $action_text);
@ -392,7 +410,7 @@ sub handleMessage {
my $last_event = zmGetLastEvent( $monitor );
zmTriggerEventOff( $monitor );
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
Info( "Trigger '$trigger'\n" );
Info( "Trigger '$trigger'" );
# Wait til it's finished
while( zmInAlarm( $monitor )
&& ($last_event == zmGetLastEvent( $monitor ))
@ -406,12 +424,12 @@ sub handleMessage {
} elsif( $action eq 'cancel' ) {
zmTriggerEventCancel( $monitor );
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
Info( "Cancelled event\n" );
Info( "Cancelled event" );
} elsif( $action eq 'show' ) {
zmTriggerShowtext( $monitor, $showtext );
Info( "Updated show text to '$showtext'\n" );
Info( "Updated show text to '$showtext'" );
} else {
Error( "Unrecognised action '$action' in message '$message'\n" );
Error( "Unrecognised action '$action' in message '$message'" );
}
} # end sub handleMessage
@ -426,7 +444,7 @@ sub handleDelay {
$action_array = $actions{$action_time} = [];
}
push( @$action_array, { connection=>$connection, message=>$action_text } );
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)" );
}
1;
__END__

View File

@ -755,6 +755,12 @@ void EventStream::runStream() {
// commands may set send_frame to true
while(checkCommandQueue());
// Update modified time of the socket .lock file so that we can tell which ones are stale.
if ( now.tv_sec - last_comm_update.tv_sec > 3600 ) {
touch(sock_path_lock);
last_comm_update = now;
}
if ( step != 0 )
curr_frame_id += step;

File diff suppressed because it is too large Load Diff

View File

@ -274,6 +274,7 @@ void std_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result,
void std_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void std_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void std_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
void neon32_armv7_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);

View File

@ -531,6 +531,12 @@ void MonitorStream::runStream() {
Debug(2, "Have checking command Queue for connkey: %d", connkey );
got_command = true;
}
// Update modified time of the socket .lock file so that we can tell which ones are stale.
if ( now.tv_sec - last_comm_update.tv_sec > 3600 ) {
touch(sock_path_lock);
last_comm_update = now;
}
}
if ( paused ) {

View File

@ -332,6 +332,8 @@ void StreamBase::openComms() {
snprintf(rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", staticConfig.PATH_SOCKS.c_str(), connkey);
strncpy(rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path)-1);
rem_addr.sun_family = AF_UNIX;
gettimeofday(&last_comm_update, NULL);
} // end if connKey > 0
Debug(2, "comms open");
} // end void StreamBase::openComms()

View File

@ -85,6 +85,7 @@ protected:
int step;
struct timeval now;
struct timeval last_comm_update;
double base_fps;
double effective_fps;

View File

@ -24,6 +24,8 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>
#if defined(__arm__)
#include <sys/auxv.h>
#endif
@ -414,3 +416,22 @@ Warning("ZM Compiled without LIBCURL. UriDecoding not implemented.");
#endif
}
void touch(const char *pathname) {
int fd = open(pathname,
O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK,
0666);
if ( fd < 0 ) {
// Couldn't open that path.
Error("Couldn't open() path \"%s in touch", pathname);
return;
}
int rc = utimensat(AT_FDCWD,
pathname,
nullptr,
0);
if ( rc ) {
Error("Couldn't utimensat() path %s in touch", pathname);
return;
}
}

View File

@ -63,5 +63,5 @@ extern unsigned int neonversion;
char *timeval_to_string( struct timeval tv );
std::string UriDecode( const std::string &encoded );
void touch( const char *pathname );
#endif // ZM_UTILS_H

View File

@ -23,7 +23,7 @@ case $i in
shift # past argument=value
;;
-d=*|--distro=*)
DISTRO="${i#*=}"
DISTROS="${i#*=}"
shift # past argument=value
;;
-i=*|--interactive=*)
@ -74,11 +74,15 @@ else
echo "Doing $TYPE build"
fi;
if [ "$DISTRO" == "" ]; then
DISTRO=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
echo "Defaulting to $DISTRO for distribution";
if [ "$DISTROS" == "" ]; then
if [ "$RELEASE" != "" ]; then
DISTROS="xenial,bionic,trusty"
else
DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
fi;
echo "Defaulting to $DISTROS for distribution";
else
echo "Building for $DISTRO";
echo "Building for $DISTROS";
fi;
# Release is a special mode... it uploads to the release ppa and cannot have a snapshot
@ -116,6 +120,18 @@ else
fi;
fi
PPA="";
if [ "$RELEASE" != "" ]; then
# We need to use our official tarball for the original source, so grab it and overwrite our generated one.
IFS='.' read -r -a VERSION <<< "$RELEASE"
PPA="ppa:iconnor/zoneminder-${VERSION[0]}.${VERSION[1]}"
else
if [ "$BRANCH" == "" ]; then
PPA="ppa:iconnor/zoneminder-master";
else
PPA="ppa:iconnor/zoneminder-$BRANCH";
fi;
fi;
# Instead of cloning from github each time, if we have a fork lying around, update it and pull from there instead.
if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then
@ -154,6 +170,11 @@ if [ "$SNAPSHOT" != "stable" ] && [ "$SNAPSHOT" != "" ]; then
fi;
DIRECTORY="zoneminder_$VERSION";
if [ -d "$DIRECTORY.orig" ]; then
echo "$DIRECTORY.orig already exists. Please delete it."
exit 0;
fi;
echo "Doing $TYPE release $DIRECTORY";
mv "${GITHUB_FORK}_zoneminder_release" "$DIRECTORY.orig";
if [ $? -ne 0 ]; then
@ -161,6 +182,7 @@ if [ $? -ne 0 ]; then
echo "Setting up build dir failed.";
exit $?;
fi;
cd "$DIRECTORY.orig";
# Init submodules
@ -172,36 +194,45 @@ rm -rf .git
rm .gitignore
cd ../
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
cd $DIRECTORY.orig
if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
fi;
# Generate Changlog
if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]; then
mv distros/ubuntu1204 debian
else
if [ "$DISTRO" == "wheezy" ]; then
mv distros/debian debian
else
mv distros/ubuntu1604 debian
IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
echo "Generating package for $DISTRO";
cd $DIRECTORY.orig
if [ -e "debian" ]; then
rm -rf debian
fi;
fi;
if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then
AUTHOR="$DEBFULLNAME <$DEBEMAIL>"
else
if [ -z `hostname -d` ] ; then
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`.local>"
# Generate Changlog
if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]; then
cp -Rpd distros/ubuntu1204 debian
else
if [ "$DISTRO" == "wheezy" ]; then
cp -Rpd distros/debian debian
else
cp -Rpd distros/ubuntu1604 debian
fi;
fi;
if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then
AUTHOR="$DEBFULLNAME <$DEBEMAIL>"
else
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`>"
if [ -z `hostname -d` ] ; then
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`.local>"
else
AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`>"
fi
fi
fi
if [ "$URGENCY" = "" ]; then
URGENCY="medium"
fi;
if [ "$URGENCY" = "" ]; then
URGENCY="medium"
fi;
if [ "$SNAPSHOT" == "stable" ]; then
cat <<EOF > debian/changelog
if [ "$SNAPSHOT" == "stable" ]; then
cat <<EOF > debian/changelog
zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
* Release $VERSION
@ -209,59 +240,92 @@ zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
-- $AUTHOR $DATE
EOF
cat <<EOF > debian/NEWS
cat <<EOF > debian/NEWS
zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
* Release $VERSION
-- $AUTHOR $DATE
EOF
else
cat <<EOF > debian/changelog
else
cat <<EOF > debian/changelog
zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
*
-- $AUTHOR $DATE
EOF
cat <<EOF > debian/changelog
cat <<EOF > debian/changelog
zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY
*
-- $AUTHOR $DATE
EOF
fi;
fi;
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
else
if [ $TYPE == "local" ]; then
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 -i -us -uc -b"
else
# Source build, don't need build depends.
DEBUILD="debuild -S -sa"
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;
fi;
if [ "$DEBSIGN_KEYID" != "" ]; then
DEBUILD="$DEBUILD -k$DEBSIGN_KEYID"
fi
eval $DEBUILD
if [ $? -ne 0 ]; then
echo "Error status code is: $?"
echo "Build failed.";
exit $?;
fi;
fi;
if [ "$DEBSIGN_KEYID" != "" ]; then
DEBUILD="$DEBUILD -k$DEBSIGN_KEYID"
fi
$DEBUILD
if [ $? -ne 0 ]; then
echo "Error status code is: $?"
echo "Build failed.";
exit $?;
fi;
cd ../
cd ../
if [ $TYPE == "binary" ]; then
if [ "$INTERACTIVE" != "no" ]; then
read -p "Not doing dput since it's a binary release. Do you want to install it? (y/N)"
if [[ $REPLY == [yY] ]]; then
sudo dpkg -i $DIRECTORY*.deb
fi;
read -p "Do you want to upload this binary to zmrepo? (y/N)"
if [[ $REPLY == [yY] ]]; then
if [ "$RELEASE" != "" ]; then
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/"
else
if [ "$BRANCH" == "" ]; then
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/"
else
scp "$DIRECTORY-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/"
fi;
fi;
fi;
fi;
else
SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes";
dput="Y";
if [ "$INTERACTIVE" != "no" ]; then
read -p "Ready to dput $SC to $PPA ? Y/N...";
if [[ "$REPLY" == [yY] ]]; then
dput $PPA $SC
fi;
fi;
fi;
done; # foreach distro
if [ "$INTERACTIVE" != "no" ]; then
read -p "Do you want to keep the checked out version of Zoneminder (incase you want to modify it later) [y/N]"
[[ $REPLY == [yY] ]] && { mv "$DIRECTORY.orig" zoneminder_release; echo "The checked out copy is preserved in zoneminder_release"; } || { rm -fr "$DIRECTORY.orig"; echo "The checked out copy has been deleted"; }
@ -270,53 +334,4 @@ else
rm -fr "$DIRECTORY.orig"; echo "The checked out copy has been deleted";
fi
if [ $TYPE == "binary" ]; then
if [ "$INTERACTIVE" != "no" ]; then
read -p "Not doing dput since it's a binary release. Do you want to install it? (y/N)"
if [[ $REPLY == [yY] ]]; then
sudo dpkg -i $DIRECTORY*.deb
fi;
read -p "Do you want to upload this binary to zmrepo? (y/N)"
if [[ $REPLY == [yY] ]]; then
if [ "$RELEASE" != "" ]; then
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/"
else
if [ "$BRANCH" == "" ]; then
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/"
else
scp "$DIRECTORY-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/"
fi;
fi;
fi;
fi;
else
SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes";
PPA="";
if [ "$RELEASE" != "" ]; then
# We need to use our official tarball for the original source, so grab it and overwrite our generated one.
if [ ! -e "$RELEASE.tar.gz" ]; then
echo "Grabbing official source tarball from github."
wget "https://github.com/ZoneMinder/zoneminder/archive/$RELEASE.tar.gz"
fi;
echo "Overwriting generated zoneminder_${VERSION}.orig.tar.gz with source tarball from github";
cp "$RELEASE.tar.gz" "zoneminder_${VERSION}.orig.tar.gz"
IFS='.' read -r -a VERSION <<< "$RELEASE"
PPA="ppa:iconnor/zoneminder-${VERSION[0]}.${VERSION[1]}"
else
if [ "$BRANCH" == "" ]; then
PPA="ppa:iconnor/zoneminder-master";
else
PPA="ppa:iconnor/zoneminder-$BRANCH";
fi;
fi;
dput="Y";
if [ "$INTERACTIVE" != "no" ]; then
read -p "Ready to dput $SC to $PPA ? Y/N...";
if [[ "$REPLY" == [yY] ]]; then
dput $PPA $SC
fi;
fi;
fi;

View File

@ -1 +1 @@
1.32.1
1.32.2

View File

@ -69,7 +69,7 @@ class HostController extends AppController {
$this->Session->read('user'); # this is needed for command line/curl to recognize a session
$zmAuthRelay = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY')))['Config']['Value'];
if ( $zmAuthRelay == 'hashed' ) {
$zmAuthHashIps= $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_IPS')))['Config']['Value'];
$zmAuthHashIps = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_IPS')))['Config']['Value'];
$credentials = 'auth='.generateAuthHash($zmAuthHashIps);
} else if ( $zmAuthRelay == 'plain' ) {
// user will need to append the store password here
@ -101,27 +101,25 @@ class HostController extends AppController {
$this->loadModel('Monitor');
// If $mid is passed, see if it is valid
if ($mid) {
if (!$this->Monitor->exists($mid)) {
if ( $mid ) {
if ( !$this->Monitor->exists($mid) ) {
throw new NotFoundException(__('Invalid monitor'));
}
}
$zm_dir_events = $this->Config->find('list', array(
'conditions' => array('Name' => 'ZM_DIR_EVENTS'),
'fields' => array('Name', 'Value')
));
$zm_dir_events = $zm_dir_events['ZM_DIR_EVENTS' ];
$zm_dir_events = ZM_DIR_EVENTS;
// Test to see if $zm_dir_events is relative or absolute
if ('/' === "" || strrpos($zm_dir_events, '/', -strlen($zm_dir_events)) !== TRUE) {
#if ('/' === "" || strrpos($zm_dir_events, '/', -strlen($zm_dir_events)) !== TRUE) {
if ( substr($zm_dir_events, 0, 1) != '/' ) {
// relative - so add the full path
$zm_dir_events = Configure::read('ZM_PATH_WEB') . '/' . $zm_dir_events;
$zm_dir_events = ZM_PATH_WEB . '/' . $zm_dir_events;
}
if ($mid) {
if ( $mid ) {
// Get disk usage for $mid
$usage = shell_exec ("du -sh0 $zm_dir_events/$mid | awk '{print $1}'");
Logger::Debug("Executing du -s0 $zm_dir_events/$mid | awk '{print $1}'");
$usage = shell_exec("du -s0 $zm_dir_events/$mid | awk '{print $1}'");
} else {
$monitors = $this->Monitor->find('all', array(
'fields' => array('Id', 'Name', 'WebColour')

View File

@ -0,0 +1,157 @@
<?php
App::uses('AppController', 'Controller');
/**
* Storage Controller
*
* @property Storage $Storage
* @property PaginatorComponent $Paginator
*/
class StorageController extends AppController {
/**
* Components
*
* @var array
*/
public $components = array('Paginator', 'RequestHandler');
public function beforeFilter() {
parent::beforeFilter();
global $user;
$canView = (!$user) || ($user['System'] != 'None');
if ( !$canView ) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
*
* @return void
*/
public function index() {
$this->Storage->recursive = 0;
$options = '';
$storage_areas = $this->Storage->find('all',$options);
$this->set(array(
'storage' => $storage_areas,
'_serialize' => array('storage')
));
}
/**
* view method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function view($id = null) {
$this->Storage->recursive = 0;
if (!$this->Storage->exists($id)) {
throw new NotFoundException(__('Invalid storage area'));
}
$restricted = '';
$options = array('conditions' => array(
array('Storage.' . $this->Storage->primaryKey => $id),
$restricted
)
);
$storage = $this->Storage->find('first', $options);
$this->set(array(
'storage' => $storage,
'_serialize' => array('storage')
));
}
/**
* add method
*
* @return void
*/
public function add() {
if ( $this->request->is('post') ) {
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Storage->create();
if ( $this->Storage->save($this->request->data) ) {
# Might be nice to send it a start request
#$this->daemonControl($this->Storage->id, 'start', $this->request->data);
return $this->flash(__('The storage area has been saved.'), array('action' => 'index'));
}
}
}
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
$this->Storage->id = $id;
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ( !$this->Storage->exists($id) ) {
throw new NotFoundException(__('Invalid storage area'));
}
if ( $this->Storage->save($this->request->data) ) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
// - restart this storage area after change
#$this->daemonControl($this->Storage->id, 'restart', $this->request->data);
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if ( !$canEdit ) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Storage->id = $id;
if ( !$this->Storage->exists() ) {
throw new NotFoundException(__('Invalid storage area'));
}
$this->request->allowMethod('post', 'delete');
#$this->daemonControl($this->Storage->id, 'stop');
if ( $this->Storage->delete() ) {
return $this->flash(__('The storage area has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The storage area could not be deleted. Please, try again.'), array('action' => 'index'));
}
}
}

View File

@ -19,7 +19,7 @@
.overlayHeader {
float: left;
background-color: #dddddd;
background-color: #853131;
width: 100%;
border-bottom: 1px solid #666666;
color: black;

View File

@ -55,7 +55,7 @@ class Frame {
#return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'Id'}.'&show='.$show.'&filename='.$this->Event()->MonitorId().'_'.$this->{'EventId'}.'_'.$this->{'FrameId'}.'.jpg';
} // end function getImageSrc
public static function find( $parameters = array(), $limit = NULL ) {
public static function find( $parameters = array(), $options = NULL ) {
$sql = 'SELECT * FROM Frames';
$values = array();
if ( sizeof($parameters) ) {
@ -65,17 +65,23 @@ class Frame {
) );
$values = array_values( $parameters );
}
if ( $limit ) {
if ( is_integer( $limit ) or ctype_digit( $limit ) ) {
$sql .= ' LIMIT ' . $limit;
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Invalid value for limit($limit) passed to Frame::find from $file:$line");
return array();
}
}
if ( $options ) {
if ( isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
}
if ( isset($options['limit']) ) {
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
$sql .= ' LIMIT ' . $options['limit'];
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Invalid value for limit(".$options['limit'].") passed to Frame::find from $file:$line");
return array();
}
}
}
$results = dbFetchAll($sql, NULL, $values);
if ( $results ) {
return array_map( function($id){ return new Frame($id); }, $results );
@ -83,8 +89,9 @@ class Frame {
return array();
}
public static function find_one( $parameters = array() ) {
$results = Frame::find( $parameters, 1 );
public static function find_one( $parameters = array(), $options = null ) {
$options['limit'] = 1;
$results = Frame::find($parameters, $options);
if ( ! sizeof($results) ) {
return;
}

View File

@ -152,19 +152,23 @@ private $control_fields = array(
}
if ( $this->{'Controllable'} ) {
$s = dbFetchOne('SELECT * FROM Controls WHERE Id=?', NULL, array($this->{'ControlId'}) );
foreach ($s as $k => $v) {
if ( $k == 'Id' ) {
continue;
# The reason for these is that the name overlaps Monitor fields.
} else if ( $k == 'Protocol' ) {
$this->{'ControlProtocol'} = $v;
} else if ( $k == 'Name' ) {
$this->{'ControlName'} = $v;
} else if ( $k == 'Type' ) {
$this->{'ControlType'} = $v;
} else {
$this->{$k} = $v;
if ( $s ) {
foreach ($s as $k => $v) {
if ( $k == 'Id' ) {
continue;
# The reason for these is that the name overlaps Monitor fields.
} else if ( $k == 'Protocol' ) {
$this->{'ControlProtocol'} = $v;
} else if ( $k == 'Name' ) {
$this->{'ControlName'} = $v;
} else if ( $k == 'Type' ) {
$this->{'ControlType'} = $v;
} else {
$this->{$k} = $v;
}
}
} else {
Warning('No Controls found for monitor '.$this->{'Id'} . ' ' . $this->{'Name'}.' althrough it is marked as controllable');
}
}
global $monitor_cache;
@ -381,7 +385,7 @@ private $control_fields = array(
} else if ( $this->ServerId() ) {
$Server = $this->Server();
$url = $Server->Url() . '/zm/api/monitors/'.$this->{'Id'}.'.json';
$url = ZM_BASE_PROTOCOL . '://'.$Server->Hostname().'/zm/api/monitors/'.$this->{'Id'}.'.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
@ -547,7 +551,7 @@ private $control_fields = array(
} // end function Source
public function Url() {
return $this->Server()->Url() .':'. ( ZM_MIN_STREAMING_PORT ? (ZM_MIN_STREAMING_PORT+$this->Id()) : $_SERVER['SERVER_PORT'] );
return $this->Server()->Url( ZM_MIN_STREAMING_PORT ? (ZM_MIN_STREAMING_PORT+$this->Id()) : null );
}
} // end class Monitor

View File

@ -38,13 +38,20 @@ class Server {
}
}
public function Url() {
public function Url( $port = null ) {
$url = ZM_BASE_PROTOCOL . '://';
if ( $this->Id() ) {
return ZM_BASE_PROTOCOL . '://'. $this->Hostname();
$url .= $this->Hostname();
} else {
return ZM_BASE_PROTOCOL . '://'. $_SERVER['SERVER_NAME'];
return '';
$url .= $_SERVER['SERVER_NAME'];
}
if ( $port ) {
$url .= ':'.$port;
} else {
$url .= ':'.$_SERVER['SERVER_PORT'];
}
$url .= $_SERVER['PHP_SELF'];
return $url;
}
public function Hostname() {
if ( isset( $this->{'Hostname'} ) and ( $this->{'Hostname'} != '' ) ) {

View File

@ -116,7 +116,7 @@ function generateAuthHash($useRemoteAddr, $force=false) {
$time = time();
$mintime = $time - ( ZM_AUTH_HASH_TTL * 1800 );
if ( $force or ( !isset($_SESSION['AuthHash']) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime ) ) {
if ( $force or ( !isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime ) ) {
# Don't both regenerating Auth Hash if an hour hasn't gone by yet
$local_time = localtime();
$authKey = '';
@ -133,7 +133,7 @@ function generateAuthHash($useRemoteAddr, $force=false) {
session_start();
$close_session = 1;
}
$_SESSION['AuthHash'] = $auth;
$_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
$_SESSION['AuthHashGeneratedAt'] = $time;
session_write_close();
} else {
@ -143,7 +143,7 @@ function generateAuthHash($useRemoteAddr, $force=false) {
#} else {
#Logger::Debug("Using cached auth " . $_SESSION['AuthHash'] ." beacuse generatedat:" . $_SESSION['AuthHashGeneratedAt'] . ' < now:'. $time . ' - ' . ZM_AUTH_HASH_TTL . ' * 1800 = '. $mintime);
} # end if AuthHash is not cached
return $_SESSION['AuthHash'];
return $_SESSION['AuthHash'.$_SESSION['remoteAddr']];
} # end if using AUTH and AUTH_RELAY
return '';
}

View File

@ -40,15 +40,16 @@ function CORSHeaders() {
# The following is left for future reference/use.
$valid = false;
$servers = dbFetchAll('SELECT * FROM Servers');
if ( sizeof($servers) <= 1 ) {
$Servers = Server::find();
if ( sizeof($Servers) <= 1 ) {
# Only need CORSHeaders in the event that there are multiple servers in use.
# ICON: Might not be true. multi-port?
return;
}
foreach( $servers as $row ) {
$Server = new Server($row);
if ( preg_match('/^'.preg_quote($Server->Url(),'/').'/', $_SERVER['HTTP_ORIGIN']) ) {
foreach( $Servers as $Server ) {
if ( preg_match('/^(https?:\/\/)?'.preg_quote($Server->Hostname(),'/').'/', $_SERVER['HTTP_ORIGIN']) ) {
$valid = true;
Logger::Debug("Setting Access-Controll-Allow-Origin from " . $_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Headers: x-requested-with,x-request');
break;

View File

@ -183,14 +183,13 @@ foreach ( getSkinIncludes('skin.php') as $includeFile )
require_once $includeFile;
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_HASH_LOGINS ) {
if ( empty($user) && ! empty($_REQUEST['auth']) ) {
if ( ZM_AUTH_HASH_LOGINS && empty($user) && ! empty($_REQUEST['auth']) ) {
if ( $authUser = getAuthUser($_REQUEST['auth']) ) {
userLogin($authUser['Username'], $authUser['Password'], true);
}
}
} else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) {
userLogin($_REQUEST['username'], $_REQUEST['password'], false);
else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) {
userLogin($_REQUEST['username'], $_REQUEST['password'], false);
}
if ( !empty($user) ) {
// generate it once here, while session is open. Value will be cached in session and return when called later on

View File

@ -41,4 +41,3 @@ $DLANG = array(
);
?>

View File

@ -1,2 +1,3 @@
User-agent: *
Disallow: /
###

View File

@ -21,7 +21,7 @@
}
.ptzControls input[type=image] {
border: 0px;
border: 0;
}
.ptzControls .controlsPanel .arrowControl {
@ -115,7 +115,7 @@
}
.ptzControls .controlsPanel .pantiltPanel .pantiltControls .centerBtn {
background: url("../skins/classic/graphics/graphics/center.png") no-repeat 0 0;
background: url("../skins/classic/graphics/center.png") no-repeat 0 0;
}
.ptzControls .controlsPanel .pantiltPanel .pantiltControls .rightBtn {

View File

@ -124,6 +124,7 @@ echo output_link_if_exists( array(
jQuery("#flip").click(function(){
jQuery("#panel").slideToggle("slow");
jQuery("#flip").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up');
Cookie.write( 'zmHeaderFlip', jQuery('#flip').hasClass('glyphicon-menu-up') ? 'up' : 'down', { duration: 10*365 } );
});
});
</script>
@ -208,6 +209,9 @@ echo output_link_if_exists( array(
} // end function xhtmlHeaders( $file, $title )
function getNavBarHTML($reload = null) {
# Provide a facility to turn off the headers if you put headers=0 into the url
if ( isset($_REQUEST['navbar']) and $_REQUEST['navbar']=='0' )
return '';
$versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText':'';
global $running;
@ -303,7 +307,7 @@ if (isset($_REQUEST['filter']['Query']['terms']['attr'])) {
}
?>
<li><a href="?view=report_event_audit"<?php echo $view=='report_event_audit'?' class="selected"':''?>><?php echo translate('ReportEventAudit') ?></a></li>
<li><a href="#"><span id="flip" class="glyphicon glyphicon-menu-up pull-right"></span></a></li>
<li><a href="#"><span id="flip" class="glyphicon glyphicon-menu-<?php echo ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down') ? 'down' : 'up' ?> pull-right"></span></a></li>
</ul>
<?php } // end if canView('Monitors') ?>
@ -321,7 +325,7 @@ if (isset($_REQUEST['filter']['Query']['terms']['attr'])) {
</div>
</div><!-- End .navbar-collapse -->
</div> <!-- End .container-fluid -->
<div id="panel">
<div id="panel"<?php echo ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down' ) ? 'style="display:none;"' : '' ?>>
<?php
}//end reload null. Runs on full page load
@ -378,13 +382,13 @@ if ($reload == 'reload') ob_start();
<?php } ?>
<!-- End .footer/reload --></div>
<?php
if ($reload == 'reload') return( ob_get_clean() );
if ($reload == 'reload') return ob_get_clean();
} // end if (!ZM_OPT_USE_AUTH) or $user )
?>
</div>
</div><!-- End .navbar .navbar-default -->
<?php
return( ob_get_clean() );
return ob_get_clean();
} // end function getNavBarHTML()
function xhtmlFooter() {

View File

@ -195,11 +195,12 @@ if ( currentView != 'none' && currentView != 'login' ) {
$j.getJSON(thisUrl + '?view=request&request=status&entity=navBar')
.done(setNavBar)
.fail(function( jqxhr, textStatus, error ) {
var err = textStatus + ", " + error;
console.log( "Request Failed: " + err );
// The idea is that this should only fail due to auth, so reload the page
// which should go to login if it can't stay logged in.
window.location.reload( true );
console.log( "Request Failed: " + textStatus + ", " + error);
if ( textStatus != "timeout" ) {
// The idea is that this should only fail due to auth, so reload the page
// which should go to login if it can't stay logged in.
window.location.reload( true );
}
});
}

View File

@ -56,7 +56,7 @@ foreach ( Group::find() as $G ) {
$groupSql = '';
if ( count($GroupsById) ) {
$html .= '<span id="groupControl"><label>'. translate('Group') .':</label>';
$html .= '<span id="groupControl"><label>'. translate('Group') .'</label>';
# This will end up with the group_id of the deepest selection
$group_id = isset($_SESSION['Group']) ? $_SESSION['Group'] : null;
$html .= Group::get_group_dropdown();
@ -114,7 +114,7 @@ $html .= htmlSelect('Function[]', $Functions,
$html .= '</span>';
if ( count($ServersById) > 1 ) {
$html .= '<span class="ServerFilter"><label>'. translate('Server').':</label>';
$html .= '<span class="ServerFilter"><label>'. translate('Server').'</label>';
$html .= htmlSelect('ServerId[]', $ServersById,
(isset($_SESSION['ServerId'])?$_SESSION['ServerId']:''),
array(
@ -128,7 +128,7 @@ if ( count($ServersById) > 1 ) {
} # end if have Servers
if ( count($StorageById) > 1 ) {
$html .= '<span class="StorageFilter"><label>'.translate('Storage').':</label>';
$html .= '<span class="StorageFilter"><label>'.translate('Storage').'</label>';
$html .= htmlSelect('StorageId[]', $StorageById,
(isset($_SESSION['StorageId'])?$_SESSION['StorageId']:''),
array(
@ -140,7 +140,7 @@ if ( count($StorageById) > 1 ) {
$html .= '</span>';
} # end if have Storage Areas
$html .= '<span class="StatusFilter"><label>'. translate('Status') . ':</label>';
$html .= '<span class="StatusFilter"><label>'. translate('Status') . '</label>';
$status_options = array(
'Unknown' => translate('StatusUnknown'),
'NotRunning' => translate('StatusNotRunning'),
@ -157,7 +157,7 @@ $html .= htmlSelect( 'Status[]', $status_options,
) );
$html .= '</span>';
$html .= '<span class="SourceFilter"><label>'.translate('Source').':</label>';
$html .= '<span class="SourceFilter"><label>'.translate('Source').'</label>';
$html .= '<input type="text" name="Source" value="'.(isset($_SESSION['Source'])?$_SESSION['Source']:'').'" onkeydown="if(event&&event.keyCode==13){this.form.submit();}" placeholder="text or regular expression"/>';
$html .= '</span>';
@ -232,7 +232,7 @@ $html .= htmlSelect( 'Status[]', $status_options,
$displayMonitors[] = $monitors[$i];
} # end foreach monitor
$html .= '<span class="MonitorFilter"><label>'.translate('Monitor').':</label>';
$html .= '<span class="MonitorFilter"><label>'.translate('Monitor').'</label>';
$html .= htmlSelect('MonitorId[]', $monitors_dropdown, $selected_monitor_ids,
array(
'onchange'=>'this.form.submit();',

View File

@ -217,7 +217,7 @@ ob_start();
echo '<th class="colEvents">'. $j .'</th>';
}
?>
<th class="colZones"><a href="<?php echo $_SERVER['PHP_SELF'] ?>?view=zones_overview"><?php echo translate('Zones') ?></a></th>
<th class="colZones"><?php echo translate('Zones') ?></th>
<?php if ( canEdit('Monitors') ) { ?>
<th class="colMark"><input type="checkbox" name="toggleCheck" value="1" onclick="toggleCheckbox(this, 'markMids[]');setButtonStates(this);"/> <?php echo translate('All') ?></th>
<?php } ?>

View File

@ -191,7 +191,8 @@ while ( $event_row = dbFetchNext($results) ) {
<td class="colId"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1"> '.$event->Id().($event->Archived()?'*':'') ?></a></td>
<td class="colName"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1"> '.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a></td>
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?></td>
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?>
<?php if ($event->Notes() && ($event->Notes() != 'Forced Web: ')) echo "<br/><div class=\"small text-nowrap text-muted\">".$event->Notes()."</div>" ?></td>
<td class="colTime"><?php echo strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime())) .
( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?>
</td>

View File

@ -253,7 +253,7 @@ for ( $i=0; $i < count($terms); $i++ ) {
<td><?php echo htmlSelect( "filter[Query][terms][$i][op]", $opTypes, $term['op'] ); ?></td>
<td>
<input type="text" name="filter[Query][terms][<?php echo $i ?>][val]" id="filter[Query][terms][<?php echo $i ?>][val]" value="<?php echo isset($term['val'])?validHtmlStr(str_replace('T', ' ', $term['val'])):'' ?>"/>
<script type="text/javascript">$j("[name$='\\[<?php echo $i ?>\\]\\[val\\]']").timepicker({timeFormat: "HH:mm:ss", constrainInput: falsepi}); </script>
<script type="text/javascript">$j("[name$='\\[<?php echo $i ?>\\]\\[val\\]']").timepicker({timeFormat: "HH:mm:ss", constrainInput: false}); </script>
</td>
<?php
} elseif ( $term['attr'] == 'StateId' ) {

View File

@ -3,11 +3,11 @@ var requestQueue = new Request.Queue( { concurrent: monitorData.length, stopOnFa
function Monitor( monitorData ) {
this.id = monitorData.id;
this.connKey = monitorData.connKey;
this.server_url = monitorData.server_url;
this.url = monitorData.url;
this.status = null;
this.alarmState = STATE_IDLE;
this.lastAlarmState = STATE_IDLE;
this.streamCmdParms = this.server_url+'?view=request&request=stream&connkey='+this.connKey;
this.streamCmdParms = 'view=request&request=stream&connkey='+this.connKey;
this.onclick = monitorData.onclick;
if ( auth_hash )
this.streamCmdParms += '&auth='+auth_hash;
@ -38,14 +38,14 @@ function Monitor( monitorData ) {
console.log('onerror: ' + text + ' error:'+error);
// Requeue, but want to wait a while.
var streamCmdTimeout = 1000*statusRefreshTimeout;
this.streamCmdTimer = this.streamCmdQuery.delay( streamCmdTimeout, this );
this.streamCmdTimer = this.streamCmdQuery.delay(streamCmdTimeout, this);
};
this.onFailure = function( xhr ) {
console.log('onFailure: ' + this.connKey);
console.log(xhr );
console.log(xhr);
if ( ! requestQueue.hasNext("cmdReq"+this.id) ) {
console.log("Not requeuing because there is one already");
requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq );
requestQueue.addRequest("cmdReq"+this.id, this.streamCmdReq);
}
if ( 0 ) {
// Requeue, but want to wait a while.
@ -153,7 +153,7 @@ function Monitor( monitorData ) {
if ( this.type != 'WebSite' ) {
this.streamCmdReq = new Request.JSON( {
url: this.server_url,
url: this.url,
method: 'get',
timeout: 1000+AJAX_TIMEOUT,
onSuccess: this.getStreamCmdResponse.bind( this ),
@ -402,8 +402,14 @@ function initPage() {
jQuery("#hdrbutton").click(function(){
jQuery("#flipMontageHeader").slideToggle("slow");
jQuery("#hdrbutton").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up');
Cookie.write( 'zmMontageHeaderFlip', jQuery('#hdrbutton').hasClass('glyphicon-menu-up') ? 'up' : 'down', { duration: 10*365 } );
});
});
if ( Cookie.read('zmMontageHeaderFlip') == 'down' ) {
// The chosen dropdowns require the selects to be visible, so once chosen has initialized, we can hide the header
jQuery("#flipMontageHeader").slideToggle("fast");
jQuery("#hdrbutton").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up');
}
for ( var i = 0; i < monitorData.length; i++ ) {
monitors[i] = new Monitor(monitorData[i]);
@ -416,6 +422,9 @@ function initPage() {
}
selectLayout('#zmMontageLayout');
if ( 0 ) {
// What is the purpose of this code? I think it just starts up a second ajax thread,
//increasing the load on the server.
for ( var i = 0; i < monitorData.length; i++ ) {
if ( monitors[i].type == 'WebSite' )
continue;
@ -424,6 +433,7 @@ function initPage() {
monitors[i].streamCmdQuery.delay( delay, monitors[i] );
//monitors[i].zm_startup(delay);
}
}
}
// Kick everything off
window.addEvent( 'domready', initPage );

View File

@ -35,7 +35,7 @@ monitorData[monitorData.length] = {
'connKey': <?php echo $monitor->connKey() ?>,
'width': <?php echo $monitor->Width() ?>,
'height':<?php echo $monitor->Height() ?>,
'server_url': '<?php echo $monitor->Url() ?>',
'url': '<?php echo $monitor->Url() ?>',
'onclick': function(){createPopup( '?view=watch&mid=<?php echo $monitor->Id() ?>', 'zmWatch<?php echo $monitor->Id() ?>', 'watch', <?php echo reScale( $monitor->Width(), $monitor->PopupScale() ); ?>, <?php echo reScale( $monitor->Height(), $monitor->PopupScale() ); ?> );},
'type': '<?php echo $monitor->Type() ?>',
'refresh': '<?php echo $monitor->Refresh() ?>'

View File

@ -110,7 +110,7 @@ if ( monitorType != 'WebSite' ) {
if ( auth_hash )
streamCmdParms += '&auth='+auth_hash;
var streamCmdReq = new Request.JSON( {
url: monitorUrl+thisUrl,
url: monitorUrl,
method: 'get',
timeout: AJAX_TIMEOUT,
link: 'chain',
@ -367,7 +367,7 @@ if ( monitorType != 'WebSite' ) {
var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate";
if ( auth_hash )
statusCmdParms += '&auth='+auth_hash;
var statusCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'get', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } );
var statusCmdReq = new Request.JSON( { url: monitorUrl, method: 'get', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } );
var statusCmdTimer = null;
}
@ -397,8 +397,8 @@ if ( monitorType != 'WebSite' ) {
if ( auth_hash )
alarmCmdParms += '&auth='+auth_hash;
var alarmCmdReq = new Request.JSON( {
url: monitorUrl+thisUrl,
method: 'post',
url: monitorUrl,
method: 'get',
timeout: AJAX_TIMEOUT,
link: 'cancel',
onSuccess: getAlarmCmdResponse,
@ -455,7 +455,15 @@ if ( monitorType != 'WebSite' ) {
var eventCmdParms = "view=request&request=status&entity=events&id="+monitorId+"&count="+maxDisplayEvents+"&sort=Id%20desc";
if ( auth_hash )
eventCmdParms += '&auth='+auth_hash;
var eventCmdReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, data: eventCmdParms, link: 'cancel', onSuccess: getEventCmdResponse, onTimeout: eventCmdQuery } );
var eventCmdReq = new Request.JSON( {
url: monitorUrl,
method: 'get',
timeout: AJAX_TIMEOUT,
data: eventCmdParms,
link: 'cancel',
onSuccess: getEventCmdResponse,
onTimeout: eventCmdQuery
} );
var eventCmdTimer = null;
var eventCmdFirst = true;
}
@ -565,7 +573,7 @@ if ( monitorType != 'WebSite' ) {
var controlParms = "view=request&request=control&id="+monitorId;
if ( auth_hash )
controlParms += '&auth='+auth_hash;
var controlReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getControlResponse } );
var controlReq = new Request.JSON( { url: monitorUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getControlResponse } );
}
function getControlResponse( respObj, respText ) {
@ -617,7 +625,7 @@ function controlCmdImage( x, y ) {
controlReq.send( imageControlParms+"&x="+x+"&y="+y );
if ( streamMode == "single" )
fetchImage.pass( $('imageFeed').getElement('img') ).delay( 1000 );
}
}
function fetchImage( streamImage ) {
streamImage.src = streamImage.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));

View File

@ -471,7 +471,13 @@ function setAlarmState( currentAlarmState ) {
}
var streamCmdParms = "view=request&request=stream&connkey="+connKey;
var streamCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStreamCmdResponse } );
var streamCmdReq = new Request.JSON( {
url: monitorUrl,
method: 'get',
timeout: AJAX_TIMEOUT,
link: 'cancel',
onSuccess: getStreamCmdResponse
} );
var streamCmdTimer = null;
var streamStatus;
@ -546,7 +552,14 @@ function streamCmdQuery() {
}
var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate";
var statusCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } );
var statusCmdReq = new Request.JSON( {
url: monitorUrl,
method: 'get',
data: statusCmdParms,
timeout: AJAX_TIMEOUT,
link: 'cancel',
onSuccess: getStatusCmdResponse
} );
var statusCmdTimer = null;
function getStatusCmdResponse( respObj, respText ) {
@ -652,11 +665,13 @@ function initPage() {
// Imported from watch.js and modified for new zone edit view
//
var delay = (Math.random()+0.1)*statusRefreshTimeout;
//console.log("Delay for status updates is: " + delay );
if ( streamMode == "single" ) {
statusCmdTimer = statusCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
statusCmdTimer = statusCmdQuery.delay( delay );
watchdogCheck.pass('status').periodical(statusRefreshTimeout*2);
} else {
streamCmdTimer = streamCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
streamCmdTimer = streamCmdQuery.delay( delay );
watchdogCheck.pass('stream').periodical(statusRefreshTimeout*2);
}

View File

@ -101,7 +101,7 @@ var streamMode = "<?php echo $streamMode ?>";
var connKey = '<?php echo $connkey ?>';
var monitorId = <?php echo $monitor->Id() ?>;
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
var monitorUrl = '<?php echo ( $monitor->Url() ) ?>';
var streamSrc = "<?php echo preg_replace( '/&amp;/', '&', $streamSrc ) ?>";

View File

@ -1,5 +1,5 @@
var streamCmdParms = "view=request&request=stream&connkey="+connKey;
var streamCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel' } );
var streamCmdReq = new Request.JSON( { url: monitorUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel' } );
function streamCmdQuit( action ) {
if ( action )

View File

@ -1,4 +1,4 @@
var connKey = '<?php echo $connkey ?>';
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
var monitorUrl = '<?php echo ( $monitor->Url() ) ?>';
var CMD_QUIT = <?php echo CMD_QUIT ?>;

View File

@ -45,17 +45,16 @@ xhtmlHeaders(__FILE__, translate('SystemLog') );
<tr class="row">
<td class="col text-center">
<div class="btn-group">
<button type="button" class="btn btn-sm" onclick="expandLog()"> <?php echo translate('More') ?></button>
<button type="button" class="btn btn-sm" onclick="clearLog()"> <?php echo translate('Clear') ?></button>
<button type="button" class="btn btn-sm" onclick="refreshLog()"> <?php echo translate('Refresh') ?></button>
<button type="button" class="btn btn-sm" onclick="exportLog()"> <?php echo translate('Export') ?></button>
<button type="button" class="btn btn-sm" onclick="closeWindow()"> <?php echo translate('Close') ?></button>
<button type="button" onclick="expandLog()"><?php echo translate('More') ?></button>
<button type="button" onclick="clearLog()"><?php echo translate('Clear') ?></button>
<button type="button" onclick="refreshLog()"><?php echo translate('Refresh') ?></button>
<button type="button" onclick="exportLog()"><?php echo translate('Export') ?></button>
<button type="button" onclick="closeWindow()"><?php echo translate('Close') ?></button>
</div> <!--btn-->
</td>
</tr>
</table>
</div> <!--header-->
</tr>
</table>
</div> <!--header-->
<div id="content">
<div id="filters">
@ -89,7 +88,7 @@ xhtmlHeaders(__FILE__, translate('SystemLog') );
</td>
</tr>
</table>
<input type="reset" value="<?php echo translate('Reset') ?>" onclick="resetLog()"/>
<button type="reset" onclick="resetLog()"><?php echo translate('Reset') ?></button>
</div>
<form name="logForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
@ -137,8 +136,8 @@ xhtmlHeaders(__FILE__, translate('SystemLog') );
<div id="exportError">
<?php echo translate('ExportFailed') ?>: <span id="exportErrorText"></span>
</div>
<input type="button" id="exportButton" value="<?php echo translate('Export') ?>" onclick="exportRequest()"/>
<input type="button" value="<?php echo translate('Cancel') ?>" class="overlayCloser"/>
<button type="button" id="exportButton" value="Export" onclick="exportRequest()"><?php echo translate('Export') ?></button>
<button type="button" value="Cancel" class="overlayCloser"><?php echo translate('Cancel') ?></button>
</form>
</div>
</div>

View File

@ -135,7 +135,7 @@ xhtmlHeaders(__FILE__, translate('Montage'));
<div id="page">
<?php echo getNavBarHTML() ?>
<div id="header">&nbsp;&nbsp;
<a href="#"><span id="hdrbutton" class="glyphicon glyphicon-menu-up pull-right"></span></a>
<a href="#"><span id="hdrbutton" class="glyphicon glyphicon-menu-up pull-right" title="Toggle Filters"></span></a>
<div id="flipMontageHeader">
<div id="headerButtons">
<?php

View File

@ -225,7 +225,7 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
<?php echo getNavBarHTML() ?>
<form id="montagereview_form" action="<?php echo $_SERVER['PHP_SELF'] ?>" method="get">
<input type="hidden" name="view" value="montagereview"/>
<div id="header">&nbsp&nbsp
<div id="header">&nbsp;&nbsp;
<a href="#"><span id="hdrbutton" class="glyphicon glyphicon-menu-up pull-right"></span></a>
<div id="flipMontageHeader">
<?php echo $filter_bar ?>

View File

@ -77,6 +77,23 @@ Logger::Debug("Loading by eid");
return;
}
# if alarm, get the fid of the first alarmed frame if available and let the
# fid= code continue processing it. Sort it to get the first alarmed frame
if ( $_REQUEST['fid'] == 'alarm' ) {
$Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'),
array('order'=>'FrameId ASC'));
if ( !$Frame ) # no alarms
$Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'])); # first frame
if ( !$Frame ) {
Warning("No frame found for event " + $_REQUEST['eid']);
$Frame = new Frame();
$Frame->Delta(1);
$Frame->FrameId('snapshot');
}
$_REQUEST['fid']=$Frame->FrameId();
}
if ( $_REQUEST['fid'] == 'snapshot' ) {
$Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Score'=>$Event->MaxScore()));
if ( !$Frame )