From a7b553cdbe63a55838f88a3aab476913bfad4d29 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Mar 2020 10:32:26 -0400 Subject: [PATCH 01/70] code style and correct license. Author was contacted and ok'd the change. Fies #2883 --- .../lib/ZoneMinder/Control/DCS5020L.pm | 388 ++++++++---------- 1 file changed, 171 insertions(+), 217 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm index 59d9e3550..4f14e787a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm @@ -46,243 +46,187 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); -sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; +sub open { + my $self = shift; + + $self->loadMonitor(); + + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->agent('ZoneMinder Control Agent/' . ZoneMinder::Base::ZM_VERSION); + $self->{state} = 'open'; } -our $AUTOLOAD; - -sub AUTOLOAD -{ - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); +sub close { + my $self = shift; + $self->{state} = 'closed'; } -sub open -{ - my $self = shift; +sub sendCmd { + my $self = shift; + my $cmd = shift; + my $cgi = shift; - $self->loadMonitor(); + my $result = undef; - use LWP::UserAgent; - $self->{ua} = LWP::UserAgent->new; - $self->{ua}->agent( "ZoneMinder Control Agent/" . ZoneMinder::Base::ZM_VERSION ); - $self->{state} = 'open'; + printMsg($cmd, 'Tx'); + + my $req = HTTP::Request->new( POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi" ); + $req->content($cmd); + my $res = $self->{ua}->request($req); + + if ( $res->is_success ) { + $result = !undef; + } else { + Error("Error check failed: '".$res->status_line()."'"); + } + + return $result; } -sub close -{ - my $self = shift; - $self->{state} = 'closed'; +sub move { + my $self = shift; + my $dir = shift; + my $panStep = shift; + my $tiltStep = shift; + my $cmd = "PanSingleMoveDegree=$panStep&TiltSingleMoveDegree=$tiltStep&PanTiltSingleMove=$dir"; + $self->sendCmd($cmd, 'pantiltcontrol'); } -sub printMsg -{ - my $self = shift; - my $msg = shift; - my $msg_len = length($msg); - - Debug( $msg."[".$msg_len."]" ); +sub moveRel { + my $self = shift; + my $params = shift; + my $panStep = $self->getParam($params, 'panstep', 0); + my $tiltStep = $self->getParam($params, 'tiltstep', 0); + my $dir = shift; + $self->move( $dir, $panStep, $tiltStep ); } -sub sendCmd -{ - my $self = shift; - my $cmd = shift; - my $cgi = shift; - - my $result = undef; - - printMsg( $cmd, "Tx" ); - - my $req = HTTP::Request->new( POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi" ); - $req->content($cmd); - my $res = $self->{ua}->request($req); - - if ( $res->is_success ) - { - $result = !undef; - } - else - { - Error( "Error check failed: '".$res->status_line()."'" ); - } - - return( $result ); +sub moveRelUpLeft { + my $self = shift; + my $params = shift; + $self->moveRel($params, 0); } -sub move -{ - my $self = shift; - my $dir = shift; - my $panStep = shift; - my $tiltStep = shift; - my $cmd = "PanSingleMoveDegree=$panStep&TiltSingleMoveDegree=$tiltStep&PanTiltSingleMove=$dir"; - $self->sendCmd( $cmd, 'pantiltcontrol' ); +sub moveRelUp { + my $self = shift; + my $params = shift; + $self->moveRel($params, 1); } -sub moveRel -{ - my $self = shift; - my $params = shift; - my $panStep = $self->getParam($params, 'panstep', 0); - my $tiltStep = $self->getParam($params, 'tiltstep', 0); - my $dir = shift; - $self->move( $dir, $panStep, $tiltStep ); +sub moveRelUpRight { + my $self = shift; + my $params = shift; + $self->moveRel($params, 2); } -sub moveRelUpLeft -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 0 ); +sub moveRelLeft { + my $self = shift; + my $params = shift; + $self->moveRel($params, 3); } -sub moveRelUp -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 1 ); +sub moveRelRight { + my $self = shift; + my $params = shift; + $self->moveRel($params, 5); } -sub moveRelUpRight -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 2 ); +sub moveRelDownLeft { + my $self = shift; + my $params = shift; + $self->moveRel($params, 6); } -sub moveRelLeft -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 3 ); +sub moveRelDown { + my $self = shift; + my $params = shift; + $self->moveRel($params, 7); } -sub moveRelRight -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 5 ); -} - -sub moveRelDownLeft -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 6 ); -} - -sub moveRelDown -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 7 ); -} - -sub moveRelDownRight -{ - my $self = shift; - my $params = shift; - $self->moveRel( $params, 8 ); +sub moveRelDownRight { + my $self = shift; + my $params = shift; + $self->moveRel($params, 8); } # moves the camera to center on the point that the user clicked on in the video image. # This isn't extremely accurate but good enough for most purposes -sub moveMap -{ - # if the camera moves too much or too little, try increasing or decreasing this value - my $f = 11; +sub moveMap { + # if the camera moves too much or too little, try increasing or decreasing this value + my $f = 11; - my $self = shift; - my $params = shift; - my $xcoord = $self->getParam( $params, 'xcoord' ); - my $ycoord = $self->getParam( $params, 'ycoord' ); + my $self = shift; + my $params = shift; + my $xcoord = $self->getParam( $params, 'xcoord' ); + my $ycoord = $self->getParam( $params, 'ycoord' ); - my $hor = $xcoord * 100 / $self->{Monitor}->{Width}; - my $ver = $ycoord * 100 / $self->{Monitor}->{Height}; - - my $direction; - my $horSteps; - my $verSteps; - if ($hor < 50 && $ver < 50) { - # up left - $horSteps = (50 - $hor) / $f; - $verSteps = (50 - $ver) / $f; - $direction = 0; - } elsif ($hor >= 50 && $ver < 50) { - # up right - $horSteps = ($hor - 50) / $f; - $verSteps = (50 - $ver) / $f; - $direction = 2; - } elsif ($hor < 50 && $ver >= 50) { - # down left - $horSteps = (50 - $hor) / $f; - $verSteps = ($ver - 50) / $f; - $direction = 6; - } elsif ($hor >= 50 && $ver >= 50) { - # down right - $horSteps = ($hor - 50) / $f; - $verSteps = ($ver - 50) / $f; - $direction = 8; - } - my $v = int($verSteps + .5); - my $h = int($horSteps + .5); - Debug( "Move Map to $xcoord,$ycoord, hor=$h, ver=$v with direction $direction" ); - $self->move( $direction, $h, $v ); + my $hor = $xcoord * 100 / $self->{Monitor}->{Width}; + my $ver = $ycoord * 100 / $self->{Monitor}->{Height}; + + my $direction; + my $horSteps; + my $verSteps; + if ($hor < 50 && $ver < 50) { + # up left + $horSteps = (50 - $hor) / $f; + $verSteps = (50 - $ver) / $f; + $direction = 0; + } elsif ($hor >= 50 && $ver < 50) { + # up right + $horSteps = ($hor - 50) / $f; + $verSteps = (50 - $ver) / $f; + $direction = 2; + } elsif ($hor < 50 && $ver >= 50) { + # down left + $horSteps = (50 - $hor) / $f; + $verSteps = ($ver - 50) / $f; + $direction = 6; + } elsif ($hor >= 50 && $ver >= 50) { + # down right + $horSteps = ($hor - 50) / $f; + $verSteps = ($ver - 50) / $f; + $direction = 8; + } + my $v = int($verSteps + .5); + my $h = int($horSteps + .5); + Debug("Move Map to $xcoord,$ycoord, hor=$h, ver=$v with direction $direction"); + $self->move($direction, $h, $v); } -sub presetClear -{ - my $self = shift; - my $params = shift; - my $preset = $self->getParam( $params, 'preset' ); - Debug( "Clear Preset $preset" ); - my $cmd = "ClearPosition=$preset"; - $self->sendCmd( $cmd, 'pantiltcontrol' ); +sub presetClear { + my $self = shift; + my $params = shift; + my $preset = $self->getParam( $params, 'preset' ); + Debug( "Clear Preset $preset" ); + my $cmd = "ClearPosition=$preset"; + $self->sendCmd( $cmd, 'pantiltcontrol' ); } -sub presetSet -{ - my $self = shift; - my $params = shift; - my $preset = $self->getParam( $params, 'preset' ); - Debug( "Set Preset $preset" ); - my $cmd = "SetCurrentPosition=$preset&SetName=preset_$preset"; - $self->sendCmd( $cmd, 'pantiltcontrol' ); +sub presetSet { + my $self = shift; + my $params = shift; + my $preset = $self->getParam( $params, 'preset' ); + Debug( "Set Preset $preset" ); + my $cmd = "SetCurrentPosition=$preset&SetName=preset_$preset"; + $self->sendCmd( $cmd, 'pantiltcontrol' ); } -sub presetGoto -{ - my $self = shift; - my $params = shift; - my $preset = $self->getParam( $params, 'preset' ); - Debug( "Goto Preset $preset" ); - my $cmd = "PanTiltPresetPositionMove=$preset"; - $self->sendCmd( $cmd, 'pantiltcontrol' ); +sub presetGoto { + my $self = shift; + my $params = shift; + my $preset = $self->getParam( $params, 'preset' ); + Debug( "Goto Preset $preset" ); + my $cmd = "PanTiltPresetPositionMove=$preset"; + $self->sendCmd( $cmd, 'pantiltcontrol' ); } -sub presetHome -{ - my $self = shift; - Debug( "Home Preset" ); - $self->move( 4, 0, 0 ); +sub presetHome { + my $self = shift; + Debug( "Home Preset" ); + $self->move( 4, 0, 0 ); } - # IR Controls # # wake = IR on @@ -290,40 +234,36 @@ sub presetHome # reset = IR auto sub setDayNightMode { - my $self = shift; - my $mode = shift; - my $cmd = "DayNightMode=$mode&ConfigReboot=No"; - $self->sendCmd( $cmd, 'daynight' ); + my $self = shift; + my $mode = shift; + my $cmd = "DayNightMode=$mode&ConfigReboot=No"; + $self->sendCmd($cmd, 'daynight'); } -sub wake -{ - my $self = shift; - Debug( "Wake - IR on" ); - $self->setDayNightMode(2); +sub wake { + my $self = shift; + Debug('Wake - IR on'); + $self->setDayNightMode(2); } -sub sleep -{ - my $self = shift; - Debug( "Sleep - IR off" ); - $self->setDayNightMode(3); +sub sleep { + my $self = shift; + Debug('Sleep - IR off'); + $self->setDayNightMode(3); } -sub reset -{ - my $self = shift; - Debug( "Reset - IR auto" ); - $self->setDayNightMode(0); +sub reset { + my $self = shift; + Debug('Reset - IR auto'); + $self->setDayNightMode(0); } 1; __END__ -# Below is stub documentation for your module. You'd better edit it! =head1 NAME -ZoneMinder::Database - Perl extension for DCS-5020L +ZoneMinder::Control::DCS5020L - Perl extension for DCS-5020L =head1 SYNOPSIS @@ -351,6 +291,20 @@ Art Scheel ascheel (at) gmail =head1 COPYRIGHT AND LICENSE -LGPLv3 +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 From 67b35967d494161c817f7f326e72259be608f401 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Mar 2020 13:06:10 -0400 Subject: [PATCH 02/70] MOstly spaces and quotes, remove duplicated db version update and only prepare the sth once. --- scripts/zmupdate.pl.in | 107 +++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index b0b63757a..3662b6655 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -847,9 +847,9 @@ if ( $version ) { } $cascade = !undef; } - if ( $cascade || $version eq "1.24.4" ) { + if ( $cascade || $version eq '1.24.4' ) { # Patch the database - patchDB( $dbh, "1.24.4" ); + patchDB($dbh, '1.24.4'); # Copy the FTP specific values to the new general config my $fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'"; @@ -863,12 +863,12 @@ if ( $version ) { } $cascade = !undef; } - if ( $cascade || $version lt "1.26.0" ) { - my $sth = $dbh->prepare_cached( 'select * from Monitors LIMIT 0,1' ); + if ( $cascade || $version lt '1.26.0' ) { + my $sth = $dbh->prepare_cached('SELECT * FROM Monitors LIMIT 0,1'); die "Error: " . $dbh->errstr . "\n" unless ($sth); die "Error: " . $sth->errstr . "\n" unless ($sth->execute); - my $columns = $sth->{'NAME'}; + my $columns = $sth->{NAME}; if ( ! grep(/^Colours$/, @$columns ) ) { $dbh->do(q{alter table Monitors add column `Colours` tinyint(3) unsigned NOT NULL default '1' after `Height`;}); } # end if @@ -898,28 +898,31 @@ if ( $version ) { die "Should have found upgrade scripts at $updateDir\n"; } # end if + my $sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_DYN_DB_VERSION'"; + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + foreach my $patch ( @files ) { my ( $v ) = $patch =~ /^zm_update\-([\d\.]+)\.sql$/; #PP make sure we use version compare - if ( version->parse('v' . $v) > version->parse('v' . $version) ) { - print( "Upgrading DB to $v from $version\n" ); - patchDB( $dbh, $v ); - my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + if ( version->parse('v'.$v) > version->parse('v'.$version) ) { + print("Upgrading DB to $v from $version\n"); + if ( patchDB($dbh, $v) ) { + my $res = $sth->execute($version) or die( "Can't execute: ".$sth->errstr() ); + } #patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch ); } # end if newer version } # end foreach patchfile + + $sth->finish(); $cascade = !undef; } # end if if ( $cascade ) { - my $installed_version = ZM_VERSION; - my $sql = 'update Config set Value = ? where Name = ?'; + # This is basically here so that we don't need zm-update-blah.sql files for versions without db changes + my $sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( "$installed_version", 'ZM_DYN_DB_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); - $res = $sth->execute( "$installed_version", 'ZM_DYN_CURR_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); + $sth->execute(ZM_VERSION, 'ZM_DYN_DB_VERSION') or die( "Can't execute: ".$sth->errstr() ); + $sth->execute(ZM_VERSION, 'ZM_DYN_CURR_VERSION') or die( "Can't execute: ".$sth->errstr() ); $sth->finish(); } else { zmDbDisconnect(); @@ -930,41 +933,42 @@ if ( $version ) { #my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); #my $res = $sth->execute( ) or die( "Can't execute: ".$sth->errstr() ); #$sth->finish(); - print( "\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n" ); -} + print("\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n"); +} # end if version + zmDbDisconnect(); -exit( 0 ); +exit(0); sub patchDB_using_do { my ( $dbh, $version, $file ) = @_; - open( my $fh, '<', $file ) or die "Unable to open $file $!"; + open(my $fh, '<', $file) or die "Unable to open $file $!"; $/ = undef; my $sql = <$fh>; close $fh; if ( $sql ) { - $dbh->{'AutoCommit'} = 0; + $dbh->{AutoCommit} = 0; $dbh->do($sql); if ( $dbh->errstr() ) { $dbh->rollback(); - die "Error: " . $dbh->errstr(). ". Rolled back.\n"; + die 'Error: '.$dbh->errstr().". Rolled back.\n"; } # end if error - my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); + my $sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = \'ZM_DYN_DB_VERSION\''; + my $sth = $dbh->prepare_cached($sql) or die "Can't prepare '$sql': ".$dbh->errstr(); + my $res = $sth->execute($version) or die 'Can\'t execute: '.$sth->errstr(); $sth->finish(); - $dbh->{'AutoCommit'} = 1; + $dbh->{AutoCommit} = 1; } else { Warning("Empty db update file at $file"); } -} +} # end sub patchDB_using_do + sub patchDB { my $dbh = shift; my $version = shift; - my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my $command = 'mysql'; if ( defined($portOrSocket) ) { @@ -988,39 +992,38 @@ sub patchDB { } $command .= '/zm_update-'.$version.'.sql'; - print( "Executing '$command'\n" ) if ( logDebugging() ); + print("Executing '$command'\n") if logDebugging(); my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { - chomp( $output ); - print( "Output: $output\n" ); + chomp($output); + print("Output: $output\n"); } if ( $status ) { - die( "Command '$command' exited with status: $status\n" ); + die("Command '$command' exited with status: $status\n"); } - print( "\nDatabase successfully upgraded to version $version.\n" ); - -} + print("\nDatabase successfully upgraded to version $version.\n"); +} # end sub patchDB sub migratePasswords { - print ("Migratings passwords, if any...\n"); - my $sql = "select * from Users"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); - while( my $user = $sth->fetchrow_hashref() ) { - my $scheme = substr($user->{Password}, 0, 1); - if ($scheme eq "*") { - print ("-->".$user->{Username}. " password will be migrated\n"); - my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8)); - my $settings = '$2a$10$'.$salt; - my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings); - my $new_pass_hash = "-ZM-".$pass_hash; - $sql = "UPDATE Users SET PASSWORD=? WHERE Username=?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($new_pass_hash, $user->{Username}) or die( "Can't execute: ".$sth->errstr() ); - } + print ("Migratings passwords, if any...\n"); + my $sql = 'SELECT * FROM `Users`'; + my $sth = $dbh->prepare_cached($sql) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() or die("Can't execute: ".$sth->errstr()); + while( my $user = $sth->fetchrow_hashref() ) { + my $scheme = substr($user->{Password}, 0, 1); + if ($scheme eq '*') { + print ('-->'.$user->{Username}." password will be migrated\n"); + my $salt = Crypt::Eksblowfish::Bcrypt::en_base64(rand_bits(16*8)); + my $settings = '$2a$10$'.$salt; + my $pass_hash = Crypt::Eksblowfish::Bcrypt::bcrypt($user->{Password},$settings); + my $new_pass_hash = '-ZM-'.$pass_hash; + $sql = 'UPDATE Users SET `Password`=? WHERE `Username`=?'; + my $sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($new_pass_hash, $user->{Username}) or die("Can't execute: ".$sth->errstr()); } -} + } +} # end sub migratePasswords sub migratePaths { From 7046612b65f801c271d6c3e267ded45c9d29a611 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Mar 2020 09:48:55 -0500 Subject: [PATCH 03/70] Code style updates. Quote the word Function in SQL for newer mysql --- scripts/zmx10.pl.in | 1144 +++++++++++++++++++------------------------ 1 file changed, 514 insertions(+), 630 deletions(-) diff --git a/scripts/zmx10.pl.in b/scripts/zmx10.pl.in index 89dee5d00..de1f74929 100644 --- a/scripts/zmx10.pl.in +++ b/scripts/zmx10.pl.in @@ -83,72 +83,64 @@ my $unit_code; my $version; GetOptions( - 'command=s' =>\$command, - 'unit-code=i' =>\$unit_code, - 'version' =>\$version + 'command=s' =>\$command, + 'unit-code=i' =>\$unit_code, + 'version' =>\$version ) or pod2usage(-exitstatus => -1); if ( $version ) { - print ZoneMinder::Base::ZM_VERSION; - exit(0); + print ZoneMinder::Base::ZM_VERSION; + exit(0); } -die( 'No command given' ) unless( $command ); -die( 'No unit code given' ) - unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) ); +die 'No command given' unless $command; +die 'No unit code given' +unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) ); -if ( $command eq 'start' ) -{ +if ( $command eq 'start' ) { + X10Server::runServer(); + exit(); +} + +socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) + or Fatal("Can't open socket: $!"); + +my $saddr = sockaddr_un(SOCK_FILE); + +if ( !connect(CLIENT, $saddr) ) { + # The server isn't there + print("Unable to connect, starting server\n"); + close(CLIENT); + + if ( my $cpid = fork() ) { + # Parent process just sleep and fall through + sleep(2); + logReinit(); + socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) + or Fatal("Can't open socket: $!"); + connect(CLIENT, $saddr) + or Fatal("Can't connect: $!"); + } elsif ( defined($cpid) ) { + setpgrp(); + + logReinit(); X10Server::runServer(); - exit(); -} - -socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) - or Fatal( "Can't open socket: $!" ); - -my $saddr = sockaddr_un( SOCK_FILE ); - -if ( !connect( CLIENT, $saddr ) ) -{ - # The server isn't there - print( "Unable to connect, starting server\n" ); - close( CLIENT ); - - if ( my $cpid = fork() ) - { - # Parent process just sleep and fall through - sleep( 2 ); - logReinit(); - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) - or Fatal( "Can't open socket: $!" ); - connect( CLIENT, $saddr ) - or Fatal( "Can't connect: $!" ); - } - elsif ( defined($cpid) ) - { - setpgrp(); - - logReinit(); - X10Server::runServer(); - } - else - { - Fatal( "Can't fork: $!" ); - } + } else { + Fatal("Can't fork: $!"); + } } # The server is there, connect to it #print( "Writing commands\n" ); CLIENT->autoflush(); -my $message = "$command"; -$message .= ";$unit_code" if ( $unit_code ); -print( CLIENT $message ); -shutdown( CLIENT, 1 ); -while ( my $line = ) -{ - chomp( $line ); - print( "$line\n" ); +my $message = $command; +$message .= ';'.$unit_code if $unit_code; +print(CLIENT $message); +shutdown(CLIENT, 1); +while ( my $line = ) { + chomp($line); + print("$line\n"); } -close( CLIENT ); +close(CLIENT); #print( "Finished writing, bye\n" ); exit; @@ -178,605 +170,497 @@ our %monitor_hash; our %device_hash; our %pending_tasks; -sub runServer -{ - Info( "X10 server starting\n" ); +sub runServer { + Info('X10 server starting'); - socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) - or Fatal( "Can't open socket: $!" ); - unlink( main::SOCK_FILE ); - my $saddr = sockaddr_un( main::SOCK_FILE ); - bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); - listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); + socket(SERVER, PF_UNIX, SOCK_STREAM, 0) + or Fatal("Can't open socket: $!"); + unlink(main::SOCK_FILE); + my $saddr = sockaddr_un(main::SOCK_FILE); + bind(SERVER, $saddr) or Fatal("Can't bind: $!"); + listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); - $dbh = zmDbConnect(); + $dbh = zmDbConnect(); - $x10 = new X10::ActiveHome( port=>$Config{ZM_X10_DEVICE}, house_code=>$Config{ZM_X10_HOUSE_CODE}, debug=>0 ); + $x10 = new X10::ActiveHome( + port=>$Config{ZM_X10_DEVICE}, + house_code=>$Config{ZM_X10_HOUSE_CODE}, + debug=>0 + ); - loadTasks(); + loadTasks(); - $x10->register_listener( \&x10listen ); + $x10->register_listener(\&x10listen); - my $rin = ''; - vec( $rin, fileno(SERVER),1) = 1; - vec( $rin, $x10->select_fds(),1) = 1; - my $timeout = 0.2; - #print( 'F:'.fileno(SERVER)."\n" ); - my $reload = undef; - my $reload_count = 0; - my $reload_limit = $Config{ZM_X10_DB_RELOAD_INTERVAL} / $timeout; - while( 1 ) - { - my $nfound = select( my $rout = $rin, undef, undef, $timeout ); - #print( "Off select, NF:$nfound, ER:$!\n" ); - #print( vec( $rout, fileno(SERVER),1)."\n" ); - #print( vec( $rout, $x10->select_fds(),1)."\n" ); - if ( $nfound > 0 ) - { - if ( vec( $rout, fileno(SERVER),1) ) - { - my $paddr = accept( CLIENT, SERVER ); - my $message = ; + my $rin = ''; + vec($rin, fileno(SERVER),1) = 1; + vec($rin, $x10->select_fds(),1) = 1; + my $timeout = 0.2; + #print( 'F:'.fileno(SERVER)."\n" ); + my $reload = undef; + my $reload_count = 0; + my $reload_limit = $Config{ZM_X10_DB_RELOAD_INTERVAL} / $timeout; + while( 1 ) { + my $nfound = select(my $rout = $rin, undef, undef, $timeout); + #print( "Off select, NF:$nfound, ER:$!\n" ); + #print( vec( $rout, fileno(SERVER),1)."\n" ); + #print( vec( $rout, $x10->select_fds(),1)."\n" ); + if ( $nfound > 0 ) { + if ( vec($rout, fileno(SERVER),1) ) { + my $paddr = accept(CLIENT, SERVER); + my $message = ; - my ( $command, $unit_code ) = split( /;/, $message ); + my ($command, $unit_code) = split(';', $message); - my $device; - if ( defined($unit_code) ) - { - if ( $unit_code < 1 || $unit_code > 16 ) - { - dPrint( ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n" ); - next; - } + my $device; + if ( defined($unit_code) ) { + if ( $unit_code < 1 || $unit_code > 16 ) { + dPrint(ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n"); + next; + } - $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), - status=>'unknown' - }; - } - } + $device = $device_hash{$unit_code}; + if ( !$device ) { + $device = $device_hash{$unit_code} = { + appliance=>$x10->Appliance(unit_code=>$unit_code), + status=>'unknown' + }; + } + } # end if defined($unit_code) - my $result; - if ( $command eq 'on' ) - { - $result = $device->{appliance}->on(); - } - elsif ( $command eq 'off' ) - { - $result = $device->{appliance}->off(); - } - #elsif ( $command eq 'dim' ) - #{ - #$result = $device->{appliance}->dim(); - #} - #elsif ( $command eq 'bright' ) - #{ - #$result = $device->{appliance}->bright(); - #} - elsif ( $command eq 'status' ) - { - if ( $device ) - { - dPrint( ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n" ); - } - else - { - foreach my $unit_code ( sort( keys(%device_hash) ) ) - { - my $device = $device_hash{$unit_code}; - dPrint( ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n" ); - } - } - } - elsif ( $command eq 'shutdown' ) - { - last; - } - else - { - dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); - } - if ( defined($result) ) - { - if ( 1 || $result ) - { - $device->{status} = uc($command); - dPrint( ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n" ); - #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); - } - else - { - dPrint( ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n" ); - } - } - close( CLIENT ); - } - elsif ( vec( $rout, $x10->select_fds(),1) ) - { - $x10->handle_input(); - } - else - { - Fatal( 'Bogus descriptor' ); - } + my $result; + if ( $command eq 'on' ) { + $result = $device->{appliance}->on(); + } elsif ( $command eq 'off' ) { + $result = $device->{appliance}->off(); } - elsif ( $nfound < 0 ) - { - if ( $! != EINTR ) - { - Fatal( "Can't select: $!" ); + #elsif ( $command eq 'dim' ) + #{ + #$result = $device->{appliance}->dim(); + #} + #elsif ( $command eq 'bright' ) + #{ + #$result = $device->{appliance}->bright(); + #} + elsif ( $command eq 'status' ) { + if ( $device ) { + dPrint(ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n"); + } else { + foreach my $unit_code ( sort( keys(%device_hash) ) ) { + my $device = $device_hash{$unit_code}; + dPrint(ZoneMinder::Logger::DEBUG, $unit_code.' '.$device->{status}."\n"); } + } + } elsif ( $command eq 'shutdown' ) { + last; + } else { + dPrint(ZoneMinder::Logger::ERROR, "Invalid command '$command'\n"); } - else - { - #print( "Select timed out\n" ); - # Check for state changes - foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) - { - my $monitor = $monitor_hash{$monitor_id}; - my $state = zmGetMonitorState( $monitor ); - if ( !defined($state) ) - { - $reload = !undef; - next; - } - if ( defined( $monitor->{LastState} ) ) - { - my $task_list; - if ( ($state == STATE_ALARM || $state == STATE_ALERT) - && ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE) - ) # Gone into alarm state - { - Debug( "Applying ON_list for $monitor_id\n" ); - $task_list = $monitor->{'ON_list'}; - } - elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) - || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) - ) # Come out of alarm state - { - Debug( "Applying OFF_list for $monitor_id\n" ); - $task_list = $monitor->{'OFF_list'}; - } - if ( $task_list ) - { - foreach my $task ( @$task_list ) - { - processTask( $task ); - } - } - } - $monitor->{LastState} = $state; - } - - # Check for pending tasks - my $now = time(); - foreach my $activation_time ( sort(keys(%pending_tasks) ) ) - { - last if ( $activation_time > $now ); - my $pending_list = $pending_tasks{$activation_time}; - foreach my $task ( @$pending_list ) - { - processTask( $task ); - } - delete( $pending_tasks{$activation_time} ); - } - if ( $reload || ++$reload_count >= $reload_limit ) - { - loadTasks(); - $reload = undef; - $reload_count = 0; - } - } - } - Info( "X10 server exiting\n" ); - close( SERVER ); - exit(); -} - -sub addToDeviceList -{ - my $unit_code = shift; - my $event = shift; - my $monitor = shift; - my $function = shift; - my $limit = shift; - - Debug( "Adding to device list, uc:$unit_code, ev:$event, mo:" - .$monitor->{Id}.", fu:$function, li:$limit\n" - ); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), - status=>'unknown' - }; - } - - my $task = { type=>'device', - monitor=>$monitor, - address=>$device->{appliance}->address(), - function=>$function - }; - if ( $limit ) - { - $task->{limit} = $limit - } - - my $task_list = $device->{$event.'_list'}; - if ( !$task_list ) - { - $task_list = $device->{$event.'_list'} = []; - } - push( @$task_list, $task ); -} - -sub addToMonitorList -{ - my $monitor = shift; - my $event = shift; - my $unit_code = shift; - my $function = shift; - my $limit = shift; - - Debug( "Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id} - .", fu:$function, li:$limit\n" - ); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), - status=>'unknown' - }; - } - - my $task = { type=>'monitor', - device=>$device, - id=>$monitor->{Id}, - function=>$function - }; - if ( $limit ) - { - $task->{limit} = $limit; - } - - my $task_list = $monitor->{$event.'_list'}; - if ( !$task_list ) - { - $task_list = $monitor->{$event.'_list'} = []; - } - push( @$task_list, $task ); -} - -sub loadTasks -{ - %monitor_hash = (); - - Debug( "Loading tasks\n" ); - # Clear out all old device task lists - foreach my $unit_code ( sort( keys(%device_hash) ) ) - { - my $device = $device_hash{$unit_code}; - $device->{ON_list} = []; - $device->{OFF_list} = []; - } - - my $sql = "SELECT M.*,T.* from Monitors as M - INNER JOIN TriggersX10 as T on (M.Id = T.MonitorId) - WHERE find_in_set( M.Function, 'Modect,Record,Mocord,Nodect' ) - AND M.Enabled = 1 - AND find_IN_set( 'X10', M.Triggers )" - ; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() - or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { -# Check shared memory ok - if ( !zmMemVerify( $monitor ) ) { - zmMemInvalidate( $monitor ); - next ; + if ( defined($result) ) { + # FIXME + if ( 1 || $result ) { + $device->{status} = uc($command); + dPrint(ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n"); + #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); + } else { + dPrint(ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n"); + } + } # end if defined result + close(CLIENT); + } elsif ( vec($rout, $x10->select_fds(),1) ) { + $x10->handle_input(); + } else { + Fatal('Bogus descriptor'); } - - $monitor_hash{$monitor->{Id}} = $monitor; - - if ( $monitor->{Activation} ) - { - Debug( "$monitor->{Name} has active string '$monitor->{Activation}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{Activation} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) - = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToDeviceList( $unit_code, - 'ON', - $monitor, - !$invert ? 'start_active' - : 'stop_active', - $limit - ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToDeviceList( $unit_code, - 'OFF', - $monitor, - !$invert ? 'stop_active' - : 'start_active', - $limit - ); - } - } - } + } elsif ( $nfound < 0 ) { + if ( $! != EINTR ) { + Fatal("Can't select: $!"); + } + } else { + #print( "Select timed out\n" ); + # Check for state changes + foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) { + my $monitor = $monitor_hash{$monitor_id}; + my $state = zmGetMonitorState($monitor); + if ( !defined($state) ) { + $reload = !undef; + next; } - if ( $monitor->{AlarmInput} ) - { - Debug( "$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{AlarmInput} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) - = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToDeviceList( $unit_code, - 'ON', - $monitor, - !$invert ? 'start_alarm' - : 'stop_alarm', - $limit - ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToDeviceList( $unit_code, - 'OFF', - $monitor, - !$invert ? 'stop_alarm' - : 'start_alarm', - $limit - ); - } - } + if ( defined( $monitor->{LastState} ) ) { + my $task_list; + if ( ($state == STATE_ALARM || $state == STATE_ALERT) + && ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE) + ) # Gone into alarm state + { + Debug("Applying ON_list for $monitor_id"); + $task_list = $monitor->{ON_list}; + } elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) + || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) + ) # Come out of alarm state + { + Debug("Applying OFF_list for $monitor_id"); + $task_list = $monitor->{OFF_list}; + } + if ( $task_list ) { + foreach my $task ( @$task_list ) { + processTask($task); } - } - if ( $monitor->{AlarmOutput} ) - { - Debug( "$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{AlarmOutput} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) - = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToMonitorList( $monitor, - 'ON', - $unit_code, - !$invert ? 'on' - : 'off', - $limit - ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToMonitorList( $monitor, - 'OFF', - $unit_code, - !$invert ? 'off' - : 'on', - $limit - ); - } - } - } - } - zmMemInvalidate( $monitor ); - } -} + } + } # end if defined laststate + $monitor->{LastState} = $state; + } # end foreach monitor -sub addPendingTask -{ - my $task = shift; - - # Check whether we are just extending a previous pending task - # and remove it if it's there - foreach my $activation_time ( sort(keys(%pending_tasks) ) ) - { + # Check for pending tasks + my $now = time(); + foreach my $activation_time ( sort(keys(%pending_tasks) ) ) { + last if ( $activation_time > $now ); my $pending_list = $pending_tasks{$activation_time}; - my $new_pending_list = []; - foreach my $pending_task ( @$pending_list ) - { - if ( $task->{type} ne $pending_task->{type} ) - { - push( @$new_pending_list, $pending_task ) - } - elsif ( $task->{type} eq 'device' ) - { - if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} ) - || ( $task->{function} ne $pending_task->{function} )) - { - push( @$new_pending_list, $pending_task ) - } - } - elsif ( $task->{type} eq 'monitor' ) - { - if (( $task->{device}->{appliance}->unit_code() - != $pending_task->{device}->{appliance}->unit_code() - ) - || ( $task->{function} ne $pending_task->{function} ) - ) - { - push( @$new_pending_list, $pending_task ) - } - } - } - if ( @$new_pending_list ) - { - $pending_tasks{$activation_time} = $new_pending_list; - } - else - { - delete( $pending_tasks{$activation_time} ); + foreach my $task ( @$pending_list ) { + processTask($task); } + delete $pending_tasks{$activation_time}; + } + if ( $reload or (++$reload_count >= $reload_limit) ) { + loadTasks(); + $reload = undef; + $reload_count = 0; + } + } + } + Info("X10 server exiting"); + close(SERVER); + exit(); +} + +sub addToDeviceList { + my $unit_code = shift; + my $event = shift; + my $monitor = shift; + my $function = shift; + my $limit = shift; + + Debug("Adding to device list, uc:$unit_code, ev:$event, mo:" + .$monitor->{Id}.", fu:$function, li:$limit" + ); + my $device = $device_hash{$unit_code}; + if ( !$device ) { + $device = $device_hash{$unit_code} = { + appliance=>$x10->Appliance(unit_code=>$unit_code), + status=>'unknown' + }; + } + + my $task = { + type=>'device', + monitor=>$monitor, + address=>$device->{appliance}->address(), + function=>$function + }; + + if ( $limit ) { + $task->{limit} = $limit + } + + my $task_list = $device->{$event.'_list'}; + if ( !$task_list ) { + $task_list = $device->{$event.'_list'} = []; + } + push @$task_list, $task; +} # end sub addToDeviceList + +sub addToMonitorList { + my $monitor = shift; + my $event = shift; + my $unit_code = shift; + my $function = shift; + my $limit = shift; + + Debug("Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id} + .", fu:$function, li:$limit" + ); + my $device = $device_hash{$unit_code}; + if ( !$device ) { + $device = $device_hash{$unit_code} = { + appliance=>$x10->Appliance(unit_code=>$unit_code), + status=>'unknown' + }; + } + + my $task = { + type=>'monitor', + device=>$device, + id=>$monitor->{Id}, + function=>$function + }; + if ( $limit ) { + $task->{limit} = $limit; + } + + my $task_list = $monitor->{$event.'_list'}; + if ( !$task_list ) { + $task_list = $monitor->{$event.'_list'} = []; + } + push @$task_list, $task; +} # end sub addToMonitorList + +sub loadTasks { + %monitor_hash = (); + + Debug('Loading tasks'); + # Clear out all old device task lists + foreach my $unit_code ( sort keys(%device_hash) ) { + my $device = $device_hash{$unit_code}; + $device->{ON_list} = []; + $device->{OFF_list} = []; + } + + my $sql = 'SELECT M.*,T.* FROM Monitors as M + INNER JOIN TriggersX10 as T on (M.Id = T.MonitorId) + WHERE find_in_set(M.`Function`, \'Modect,Record,Mocord,Nodect\') + AND M.`Enabled` = 1 + AND find_IN_set(\'X10\', M.Triggers)'; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute() + or Fatal("Can't execute: ".$sth->errstr()); + while( my $monitor = $sth->fetchrow_hashref() ) { + # Check shared memory ok + if ( !zmMemVerify($monitor) ) { + zmMemInvalidate($monitor); + next; } - my $end_time = time() + $task->{limit}; - my $pending_list = $pending_tasks{$end_time}; - if ( !$pending_list ) - { - $pending_list = $pending_tasks{$end_time} = []; + $monitor_hash{$monitor->{Id}} = $monitor; + + if ( $monitor->{Activation} ) { + Debug("$monitor->{Name} has active string '$monitor->{Activation}'"); + foreach my $code_string ( split(',', $monitor->{Activation}) ) { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if !$limit; + if ( $unit_code ) { + if ( !$modifier || $modifier eq '+' ) { + addToDeviceList( $unit_code, + 'ON', + $monitor, + (!$invert ? 'start_active' : 'stop_active'), + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) { + addToDeviceList( $unit_code, + 'OFF', + $monitor, + (!$invert ? 'stop_active' : 'start_active'), + $limit + ); + } + } # end if unit_code + } # end foreach code_string } - my $pending_task; - if ( $task->{type} eq 'device' ) - { - $pending_task = { type=>$task->{type}, - monitor=>$task->{monitor}, - function=>$task->{function} + if ( $monitor->{AlarmInput} ) { + Debug("$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'"); + foreach my $code_string ( split(',', $monitor->{AlarmInput}) ) { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if !$limit; + if ( $unit_code ) { + if ( !$modifier || $modifier eq '+' ) { + addToDeviceList( $unit_code, + 'ON', + $monitor, + (!$invert ? 'start_alarm' : 'stop_alarm'), + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) { + addToDeviceList( $unit_code, + 'OFF', + $monitor, + (!$invert ? 'stop_alarm' : 'start_alarm'), + $limit + ); + } + } # end if unit_code + } # end foreach code_string + } # end if AlarmInput + if ( $monitor->{AlarmOutput} ) { + Debug("$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'"); + foreach my $code_string ( split( ',', $monitor->{AlarmOutput} ) ) { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if !$limit; + if ( $unit_code ) { + if ( !$modifier || $modifier eq '+' ) { + addToMonitorList( $monitor, + 'ON', + $unit_code, + (!$invert ? 'on' : 'off'), + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) { + addToMonitorList( $monitor, + 'OFF', + $unit_code, + (!$invert ? 'off' : 'on'), + $limit + ); + } + } # end if unit_code + } # end foreach code_string + } # end if AlarmOutput + zmMemInvalidate($monitor); + } +} # end sub loadTasks + +sub addPendingTask { + my $task = shift; + + # Check whether we are just extending a previous pending task + # and remove it if it's there + foreach my $activation_time ( sort keys(%pending_tasks) ) { + my $pending_list = $pending_tasks{$activation_time}; + my $new_pending_list = []; + foreach my $pending_task ( @$pending_list ) { + if ( $task->{type} ne $pending_task->{type} ) { + push( @$new_pending_list, $pending_task ) + } elsif ( $task->{type} eq 'device' ) { + if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} ) + || ( $task->{function} ne $pending_task->{function} )) + { + push @$new_pending_list, $pending_task; + } + } elsif ( $task->{type} eq 'monitor' ) { + if (( $task->{device}->{appliance}->unit_code() + != $pending_task->{device}->{appliance}->unit_code() + ) + || ( $task->{function} ne $pending_task->{function} ) + ) { + push @$new_pending_list, $pending_task; + } + } # end switch task->type + } # end foreach pending_task + + if ( @$new_pending_list ) { + $pending_tasks{$activation_time} = $new_pending_list; + } else { + delete $pending_tasks{$activation_time}; + } + } # end foreach activation_time + + my $end_time = time() + $task->{limit}; + my $pending_list = $pending_tasks{$end_time}; + if ( !$pending_list ) { + $pending_list = $pending_tasks{$end_time} = []; + } + my $pending_task; + if ( $task->{type} eq 'device' ) { + $pending_task = { + type=>$task->{type}, + monitor=>$task->{monitor}, + function=>$task->{function} + }; + $pending_task->{function} =~ s/start/stop/; + } elsif ( $task->{type} eq 'monitor' ) { + $pending_task = { + type=>$task->{type}, + device=>$task->{device}, + function=>$task->{function} + }; + $pending_task->{function} =~ s/on/off/; + } + push @$pending_list, $pending_task; +} # end sub addPendingTask + +sub processTask { + my $task = shift; + + if ( $task->{type} eq 'device' ) { + my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ ); + + if ( $class eq 'active' ) { + if ( $instruction eq 'start' ) { + zmMonitorEnable($task->{monitor}); + if ( $task->{limit} ) { + addPendingTask($task); + } + } elsif( $instruction eq 'stop' ) { + zmMonitorDisable($task->{monitor}); + } + } elsif( $class eq 'alarm' ) { + if ( $instruction eq 'start' ) { + zmTriggerEventOn( + $task->{monitor}, + 0, + main::CAUSE_STRING, + $task->{address} + ); + if ( $task->{limit} ) { + addPendingTask($task); + } + } elsif( $instruction eq 'stop' ) { + zmTriggerEventCancel($task->{monitor}); + } + } # end switch class + } elsif( $task->{type} eq 'monitor' ) { + if ( $task->{function} eq 'on' ) { + $task->{device}->{appliance}->on(); + if ( $task->{limit} ) { + addPendingTask($task); + } + } elsif ( $task->{function} eq 'off' ) { + $task->{device}->{appliance}->off(); + } + } +} + +sub dPrint { + my $dbg_level = shift; + if ( fileno(CLIENT) ) { + print CLIENT @_ + } + if ( $dbg_level == ZoneMinder::Logger::DEBUG ) { + Debug(@_); + } elsif ( $dbg_level == ZoneMinder::Logger::INFO ) { + Info(@_); + } elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) { + Warning(@_); + } + elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) { + Error( @_ ); + } elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) { + Fatal( @_ ); + } +} + +sub x10listen { + foreach my $event ( @_ ) { + #print( Data::Dumper( $_ )."\n" ); + if ( $event->house_code() eq $Config{ZM_X10_HOUSE_CODE} ) { + my $unit_code = $event->unit_code(); + my $device = $device_hash{$unit_code}; + if ( !$device ) { + $device = $device_hash{$unit_code} = { + appliance=>$x10->Appliance(unit_code=>$unit_code), + status=>'unknown' }; - $pending_task->{function} =~ s/start/stop/; - } - elsif ( $task->{type} eq 'monitor' ) - { - $pending_task = { type=>$task->{type}, - device=>$task->{device}, - function=>$task->{function} - }; - $pending_task->{function} =~ s/on/off/; - } - push( @$pending_list, $pending_task ); -} - -sub processTask -{ - my $task = shift; - - if ( $task->{type} eq 'device' ) - { - my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ ); - - if ( $class eq 'active' ) - { - if ( $instruction eq 'start' ) - { - zmMonitorEnable( $task->{monitor} ); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif( $instruction eq 'stop' ) - { - zmMonitorDisable( $task->{monitor} ); - } + } + next if ( $event->func() !~ /(?:ON|OFF)/ ); + $device->{status} = $event->func(); + my $task_list = $device->{$event->func().'_list'}; + if ( $task_list ) { + foreach my $task ( @$task_list ) { + processTask($task); } - elsif( $class eq 'alarm' ) - { - if ( $instruction eq 'start' ) - { - zmTriggerEventOn( $task->{monitor}, - 0, - main::CAUSE_STRING, - $task->{address} - ); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif( $instruction eq 'stop' ) - { - zmTriggerEventCancel( $task->{monitor} ); - } - } - } - elsif( $task->{type} eq 'monitor' ) - { - if ( $task->{function} eq 'on' ) - { - $task->{device}->{appliance}->on(); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif ( $task->{function} eq 'off' ) - { - $task->{device}->{appliance}->off(); - } - } -} - -sub dPrint -{ - my $dbg_level = shift; - if ( fileno(CLIENT) ) - { - print CLIENT @_ - } - if ( $dbg_level == ZoneMinder::Logger::DEBUG ) - { - Debug( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::INFO ) - { - Info( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) - { - Warning( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) - { - Error( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) - { - Fatal( @_ ); - } -} - -sub x10listen -{ - foreach my $event ( @_ ) - { - #print( Data::Dumper( $_ )."\n" ); - if ( $event->house_code() eq $Config{ZM_X10_HOUSE_CODE} ) - { - my $unit_code = $event->unit_code(); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), - status=>'unknown' - }; - } - next if ( $event->func() !~ /(?:ON|OFF)/ ); - $device->{status} = $event->func(); - my $task_list = $device->{$event->func().'_list'}; - if ( $task_list ) - { - foreach my $task ( @$task_list ) - { - processTask( $task ); - } - } - } - Info( "Got event - ".$event->as_string()."\n" ); - } -} + } + } # end if correct house code + Info('Got event - '.$event->as_string()); + } +} # end sub x10listen 1; +__END__ From 576e3149d66918c3a0f059e7fe6e0cf8d241de12 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Mar 2020 17:29:31 -0500 Subject: [PATCH 04/70] escape table columns for mysql8 --- scripts/zmtelemetry.pl.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/zmtelemetry.pl.in b/scripts/zmtelemetry.pl.in index 82ceeac96..a3debabdb 100644 --- a/scripts/zmtelemetry.pl.in +++ b/scripts/zmtelemetry.pl.in @@ -214,7 +214,7 @@ sub getUUID { $uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array(); $sth->finish(); - $sql = q`UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`; + $sql = q`UPDATE Config SET Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`; $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); $res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() ); $sth->finish(); @@ -250,9 +250,9 @@ sub countQuery { my $dbh = shift; my $table = shift; - my $sql = "SELECT count(*) FROM $table"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); + my $sql = "SELECT count(*) FROM `$table`"; + my $sth = $dbh->prepare_cached($sql) or die "Can't prepare '$sql': ".$dbh->errstr(); + my $res = $sth->execute() or die 'Can\'t execute: '.$sth->errstr(); my $count = $sth->fetchrow_array(); $sth->finish(); @@ -263,7 +263,7 @@ sub countQuery { sub getMonitorRef { my $dbh = shift; - my $sql = 'SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors'; + my $sql = 'SELECT `Id`,`Name`,`Type`,`Function`,`Width`,`Height`,`Colours`,`MaxFPS`,`AlarmMaxFPS` FROM `Monitors`'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); my $arrayref = $sth->fetchall_arrayref({}); From 57141fddeb4bba8917a3459d1c96400699e1d9c0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 26 Feb 2020 09:42:17 -0500 Subject: [PATCH 05/70] handle additional atributes on the html tag in html detection --- scripts/zmfilter.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index be9996fe2..77dfd1e08 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -860,7 +860,7 @@ sub sendEmail { From => $Config{ZM_FROM_EMAIL}, To => $Config{ZM_EMAIL_ADDRESS}, Subject => $subject, - Type => (($body=~//)?'text/html':'text/plain'), + Type => (($body=~/ $body ); @@ -962,7 +962,7 @@ sub sendMessage { From => $Config{ZM_FROM_EMAIL}, To => $Config{ZM_MESSAGE_ADDRESS}, Subject => $subject, - Type => (($body=~//)?'text/html':'text/plain'), + Type => (($body=~/ $body ); From 3ac6dc267b42878e1622b8bcac1ceb642ca711cc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 19 Feb 2020 09:42:54 -0500 Subject: [PATCH 06/70] out an error if name contains invalid characters --- scripts/zmcamtool.pl.in | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/zmcamtool.pl.in b/scripts/zmcamtool.pl.in index 7e345b79d..3d68b1408 100644 --- a/scripts/zmcamtool.pl.in +++ b/scripts/zmcamtool.pl.in @@ -352,9 +352,13 @@ sub exportsql { } my $name = $ARGV[0]; - if ($name && $name =~ /^([A-Za-z0-9 ,.&()\/\-]+)$/) { # Allow alphanumeric and " ,.&()/-" - $name = $1; - $command .= qq( --where="Name = '$name'"); + if ( $name ) { + if ( $name =~ /^([A-Za-z0-9 ,.&()\/\-]+)$/ ) { # Allow alphanumeric and " ,.&()/-" + $name = $1; + $command .= qq( --where="Name = '$name'"); + } else { + print "Invalid characters in Name\n"; + } } $command .= " zm Controls MonitorPresets"; From 59f9f37fffb11175b9b340a45218363e70d03433 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:10:57 -0400 Subject: [PATCH 07/70] cleanup. Don't output errors that break json response --- web/ajax/log.php | 142 +++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 72 deletions(-) diff --git a/web/ajax/log.php b/web/ajax/log.php index 36a29adc3..d5483b7ca 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -1,14 +1,15 @@ $value ) { if ( !in_array($field, $filterFields) ) { - ZM\Error("'$field' is not in valid filter fields " . print_r($filterField,true)); + ZM\Error("'$field' is not in valid filter fields " . print_r($filterField, true)); continue; } - if ( $field == 'Level' ){ + if ( $field == 'Level' ) { $where[] = $field.' <= ?'; $values[] = $value; } else { @@ -69,8 +70,8 @@ switch ( $_REQUEST['task'] ) { $string = $_POST['message']; - $file = !empty($_POST['file']) ? preg_replace( '/\w+:\/\/[\w.:]+\//', '', $_POST['file'] ) : ''; - if ( !empty( $_POST['line'] ) ) { + $file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : ''; + if ( !empty($_POST['line']) ) { $line = validInt($_POST['line']); } else { $line = NULL; @@ -82,6 +83,8 @@ switch ( $_REQUEST['task'] ) { } $level = $levels[$_POST['level']]; ZM\Logger::fetch()->logPrint($level, $string, $file, $line); + } else { + ZM\Error('Invalid log create: '.print_r($_POST, true)); } ajaxResponse(); break; @@ -93,12 +96,7 @@ switch ( $_REQUEST['task'] ) { $query = buildLogQuery('DELETE'); $result = dbQuery($query['sql'], $query['values']); - ajaxResponse( array( - 'result'=>'Ok', - 'deleted'=>$result->rowCount(), - ) ); - - + ajaxResponse(array('result'=>'Ok', 'deleted'=>$result->rowCount())); } case 'query' : { @@ -107,10 +105,12 @@ switch ( $_REQUEST['task'] ) { $total = dbFetchOne('SELECT count(*) AS Total FROM Logs', 'Total'); $query = buildLogQuery('SELECT *'); - $servers = ZM\Server::find(); + global $Servers; + if ( !$Servers ) + $Servers = ZM\Server::find(); $servers_by_Id = array(); # There is probably a better way to do this. - foreach ( $servers as $server ) { + foreach ( $Servers as $server ) { $servers_by_Id[$server->Id()] = $server; } @@ -120,11 +120,9 @@ switch ( $_REQUEST['task'] ) { foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $log ) { $log['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($log['TimeKey'])); - #Warning("TimeKey: " . $log['TimeKey'] . 'Intval:'.intval($log['TimeKey']).' DateTime:'.$log['DateTime']); - #$log['DateTime'] = preg_replace('/^\d+/', strftime('%Y-%m-%d %H:%M:%S', intval($log['TimeKey'])), $log['TimeKey']); $log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : ''; $log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message']); - foreach( $filterFields as $field ) { + foreach ( $filterFields as $field ) { if ( !isset($options[$field]) ) $options[$field] = array(); $value = $log[$field]; @@ -141,21 +139,21 @@ switch ( $_REQUEST['task'] ) { } } $logs[] = $log; - } + } # end foreach log db row foreach ( $options as $field => $values ) { asort($options[$field]); } $available = count($logs); - ajaxResponse( array( - 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG)?strftime(DATE_FMT_CONSOLE_LONG):date(DATE_FMT_CONSOLE_LONG), + ajaxResponse(array( + 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG), 'total' => $total, 'available' => isset($available) ? $available : $total, 'logs' => $logs, 'state' => logState(), 'options' => $options, - ) ); + )); break; } case 'export' : @@ -163,9 +161,9 @@ switch ( $_REQUEST['task'] ) { if ( !canView('System') ) ajaxError('Insufficient permissions to export logs'); - $minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL; - $maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL; - if ( !is_null($minTime) && !is_null($maxTime) && $minTime > $maxTime ) { + $minTime = isset($_POST['minTime']) ? $_POST['minTime'] : NULL; + $maxTime = isset($_POST['maxTime']) ? $_POST['maxTime'] : NULL; + if ( !is_null($minTime) && !is_null($maxTime) && ($minTime > $maxTime) ) { $tempTime = $minTime; $minTime = $maxTime; $maxTime = $tempTime; @@ -174,15 +172,17 @@ switch ( $_REQUEST['task'] ) { $filter = isset($_POST['filter'])?$_POST['filter']:array(); $sortField = 'TimeKey'; if ( isset($_POST['sortField']) ) { - if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) { - ZM\Error("Invalid sort field " . $_POST['sortField'] ); + if ( !in_array($_POST['sortField'], $filterFields) and ($_POST['sortField'] != 'TimeKey') ) { + ZM\Error('Invalid sort field '.$_POST['sortField']); } else { $sortField = $_POST['sortField']; } } - $sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc'; + $sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc' : 'desc'; - $servers = ZM\Server::find(); + global $Servers; + if ( !$Servers ) + $Servers = ZM\Server::find(); $servers_by_Id = array(); # There is probably a better way to do this. foreach ( $servers as $server ) { @@ -193,11 +193,9 @@ switch ( $_REQUEST['task'] ) { $where = array(); $values = array(); if ( $minTime ) { - ZM\Logger::Debug("MinTime: $minTime"); if ( preg_match('/(.+)(\.\d+)/', $minTime, $matches) ) { # This handles sub second precision $minTime = strtotime($matches[1]).$matches[2]; - ZM\Logger::Debug("MinTime: $minTime"); } else { $minTime = strtotime($minTime); } @@ -225,11 +223,11 @@ switch ( $_REQUEST['task'] ) { } } if ( count($where) ) - $sql.= ' WHERE '.join( ' AND ', $where ); + $sql.= ' WHERE '.join(' AND ', $where); $sql .= ' ORDER BY '.$sortField.' '.$sortOrder; //$sql .= " limit ".dbEscape($limit); - $format = isset($_POST['format'])?$_POST['format']:'text'; - switch( $format ) { + $format = isset($_POST['format']) ? $_POST['format'] : 'text'; + switch ( $format ) { case 'text' : $exportExt = 'txt'; break; @@ -245,43 +243,40 @@ switch ( $_REQUEST['task'] ) { default : ZM\Fatal("Unrecognised log export format '$format'"); } - $exportKey = substr(md5(rand()),0,8); - $exportFile = "zm-log.$exportExt"; - if ( ! file_exists(ZM_DIR_EXPORTS) ) { - ZM\Logger::Debug('Creating ' . ZM_DIR_EXPORTS); - if ( ! mkdir(ZM_DIR_EXPORTS) ) { - ZM\Fatal("Can't create exports dir at '".ZM_DIR_EXPORTS."'"); - } + $exportKey = substr(md5(rand()), 0, 8); + $exportFile = 'zm-log.'.$exportExt; + if ( ! ( mkdir(ZM_DIR_EXPORTS) || file_exists(ZM_DIR_EXPORTS) ) ) { + ZM\Fatal('Can\'t create exports dir at \''.ZM_DIR_EXPORTS.'\''); } - $exportPath = ZM_DIR_EXPORTS."/zm-log-$exportKey.$exportExt"; + $exportPath = ZM_DIR_EXPORTS.'/zm-log-'.$exportKey.$exportExt; ZM\Logger::Debug("Exporting to $exportPath"); if ( !($exportFP = fopen($exportPath, 'w')) ) ZM\Fatal("Unable to open log export file $exportPath"); $logs = array(); foreach ( dbFetchAll($sql, NULL, $values) as $log ) { - $log['DateTime'] = preg_replace('/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey']); + $log['DateTime'] = preg_replace('/^\d+/', strftime('%Y-%m-%d %H:%M:%S', intval($log['TimeKey'])), $log['TimeKey']); $log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : ''; $logs[] = $log; } - ZM\Logger::Debug(count($logs)." lines being exported by $sql " . implode(',',$values)); + ZM\Logger::Debug(count($logs).' lines being exported by '.$sql.implode(',', $values)); switch( $format ) { case 'text' : { foreach ( $logs as $log ) { if ( $log['Line'] ) - fprintf( $exportFP, "%s %s[%d].%s-%s/%d [%s]\n", - $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message'] ); + fprintf($exportFP, "%s %s[%d].%s-%s/%d [%s]\n", + $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Line'], $log['Message']); else - fprintf( $exportFP, "%s %s[%d].%s-%s [%s]\n", - $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message'] ); + fprintf($exportFP, "%s %s[%d].%s-%s [%s]\n", + $log['DateTime'], $log['Component'], $log['Pid'], $log['Code'], $log['File'], $log['Message']); } break; } case 'tsv' : { # This line doesn't need fprintf, it could use fwrite - fprintf( $exportFP, join( "\t", + fprintf($exportFP, join("\t", translate('DateTime'), translate('Component'), translate('Server'), @@ -290,17 +285,17 @@ switch ( $_REQUEST['task'] ) { translate('Message'), translate('File'), translate('Line') - )."\n" ); + )."\n"); foreach ( $logs as $log ) { - fprintf( $exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); + fprintf($exportFP, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n", + $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line']); } break; } case 'html' : { - fwrite( $exportFP, - ' - + fwrite($exportFP, +' '.translate('ZoneMinderLog').' @@ -339,34 +334,36 @@ switch ( $_REQUEST['task'] ) {

'.translate('ZoneMinderLog').'

-

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

+

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

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

- ' ); + '); foreach ( $logs as $log ) { $classLevel = $log['Level']; - if ( $classLevel < ZM\Logger::FATAL ) + if ( $classLevel < ZM\Logger::FATAL ) { $classLevel = ZM\Logger::FATAL; - elseif ( $classLevel > ZM\Logger::DEBUG ) + } else if ( $classLevel > ZM\Logger::DEBUG ) { $classLevel = ZM\Logger::DEBUG; + } $logClass = 'log-'.strtolower(ZM\Logger::$codes[$classLevel]); - fprintf( $exportFP, " \n", $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line'] ); + fprintf($exportFP, ' + ', $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line']); } - fwrite( $exportFP, + fwrite($exportFP, '
'.translate('DateTime').''.translate('Component').''.translate('Server').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').'
%s%s%s%d%s%s%s%s
%s%s%s%d%s%s%s%s
- ' ); + '); break; } case 'xml' : { - fwrite( $exportFP, + fwrite($exportFP, ' - - '.$_POST['selector'].'' ); + + '.$_POST['selector'].''); foreach ( $filter as $field=>$value ) if ( $value != '' ) fwrite( $exportFP, @@ -381,7 +378,7 @@ switch ( $_REQUEST['task'] ) { ' ); foreach ( $logs as $log ) { fprintf( $exportFP, - " + ' %s %s %s @@ -390,7 +387,8 @@ switch ( $_REQUEST['task'] ) { %s %d - \n", $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); + +', $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); } fwrite( $exportFP, ' @@ -419,7 +417,7 @@ switch ( $_REQUEST['task'] ) { ZM\Fatal('No log export format given'); $format = $_REQUEST['format']; - switch( $format ) { + switch ( $format ) { case 'text' : $exportExt = 'txt'; break; @@ -436,15 +434,15 @@ switch ( $_REQUEST['task'] ) { ZM\Fatal("Unrecognised log export format '$format'"); } - $exportFile = "zm-log.$exportExt"; - $exportPath = ZM_DIR_EXPORTS."/zm-log-$exportKey.$exportExt"; + $exportFile = 'zm-log.'.$exportExt; + $exportPath = ZM_DIR_EXPORTS.'/zm-log-'.$exportKey.$exportExt; header('Pragma: public'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Cache-Control: private', false ); // required by certain browsers + header('Cache-Control: private', false); // required by certain browsers header('Content-Description: File Transfer'); - header('Content-Disposition: attachment; filename="'.$exportFile.'"' ); + header('Content-Disposition: attachment; filename="'.$exportFile.'"'); header('Content-Transfer-Encoding: binary'); header('Content-Type: application/force-download'); header('Content-Length: '.filesize($exportPath)); @@ -452,6 +450,6 @@ switch ( $_REQUEST['task'] ) { exit(0); break; } -} +} // end switch ( $_REQUEST['task'] ) ajaxError('Unrecognised action or insufficient permissions'); ?> From c3a80e7e401712c0a3b0b5599210382ef6869eee Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:11:24 -0400 Subject: [PATCH 08/70] Add MonitorId to event data returned for status request --- web/ajax/status.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/ajax/status.php b/web/ajax/status.php index 1b1fb19a3..fea5943ca 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -96,6 +96,7 @@ $statusData = array( 'selector' => 'Events.MonitorId', 'elements' => array( 'Id' => true, + 'MonitorId' => true, 'Name' => true, 'Cause' => true, 'Notes' => true, From 9b77f77ac3db973312a81aea248ee20217683d7f Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Sun, 1 Mar 2020 14:02:44 -0500 Subject: [PATCH 09/70] better logs --- src/zm_user.cpp | 2 +- web/api/app/Controller/HostController.php | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 1c0eb6d51..0ad9f0672 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -200,7 +200,7 @@ User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { return NULL; } - Debug (1,"Got stored expiry time of %u",stored_iat); + Debug (1,"Got last token revoke time of: %u",stored_iat); Debug (1,"Authenticated user '%s' via token", username.c_str()); mysql_free_result(result); return user; diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index 7ddba57df..cf6e99b53 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -50,8 +50,10 @@ class HostController extends AppController { $cred_depr = []; if ( $username && $password ) { + ZM\Logger::Debug('Username and password provided, generating access and refresh tokens'); $cred = $this->_getCredentials(true, '', $username); // generate refresh } else { + ZM\Logger::Debug('Only generating access token'); $cred = $this->_getCredentials(false, $token); // don't generate refresh } @@ -69,6 +71,8 @@ class HostController extends AppController { $cred_depr = $this->_getCredentialsDeprecated(); $login_array['credentials'] = $cred_depr[0]; $login_array['append_password'] = $cred_depr[1]; + } else { + ZM\Logger::Debug('Legacy Auth is disabled, not generating auth= credentials'); } $login_array['version'] = $ver[0]; @@ -108,8 +112,11 @@ class HostController extends AppController { private function _getCredentials($generate_refresh_token=false, $token='', $username='') { - if ( !ZM_OPT_USE_AUTH ) + if ( !ZM_OPT_USE_AUTH ) { + ZM\Error('OPT_USE_AUTH is turned off. Tokens will be null'); return; + } + if ( !ZM_AUTH_HASH_SECRET ) throw new ForbiddenException(__('Please create a valid AUTH_HASH_SECRET in ZoneMinder')); From daff14df9b36886177e2be0fab5cb271a830b37e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Mar 2020 16:39:12 -0500 Subject: [PATCH 10/70] Allow users without System::View to read servers.json --- web/api/app/Controller/ServersController.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/web/api/app/Controller/ServersController.php b/web/api/app/Controller/ServersController.php index c30de038f..c3ac6fad7 100644 --- a/web/api/app/Controller/ServersController.php +++ b/web/api/app/Controller/ServersController.php @@ -17,12 +17,17 @@ class ServersController extends AppController { public function beforeFilter() { parent::beforeFilter(); + /* + * A user needs the server data to calculate how to view a monitor, and there really isn't anything sensitive in this data. + * So it has been decided for now to just let everyone read it. + global $user; $canView = (!$user) || ($user['System'] != 'None'); if ( !$canView ) { throw new UnauthorizedException(__('Insufficient Privileges')); return; } + */ } /** @@ -34,7 +39,7 @@ class ServersController extends AppController { $this->Server->recursive = 0; $options = ''; - $servers = $this->Server->find('all',$options); + $servers = $this->Server->find('all', $options); $this->set(array( 'servers' => $servers, '_serialize' => array('servers') @@ -50,13 +55,13 @@ class ServersController extends AppController { */ public function view($id = null) { $this->Server->recursive = 0; - if (!$this->Server->exists($id)) { + if ( !$this->Server->exists($id) ) { throw new NotFoundException(__('Invalid server')); } $restricted = ''; $options = array('conditions' => array( - array('Server.' . $this->Server->primaryKey => $id), + array('Server.'.$this->Server->primaryKey => $id), $restricted ) ); From 6f08322f7f28c803b3a80191b976b8b2c152786e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 12:17:09 -0400 Subject: [PATCH 11/70] add ability to set a filter_regexp in the defaults for an object to have new values be altered before saving --- web/includes/Object.php | 42 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/web/includes/Object.php b/web/includes/Object.php index cc595cd74..9d037c014 100644 --- a/web/includes/Object.php +++ b/web/includes/Object.php @@ -39,10 +39,13 @@ class ZM_Object { public function __call($fn, array $args){ $type = (array_key_exists($fn, $this->defaults) && is_array($this->defaults[$fn])) ? $this->defaults[$fn]['type'] : 'scalar'; if ( count($args) ) { - if ( $type == 'set' and is_array($args[0]) ) + if ( $type == 'set' and is_array($args[0]) ) { $this->{$fn} = implode(',', $args[0]); - else + } else if ( array_key_exists($fn, $this->defaults) && is_array($this->defaults[$fn]) && isset($this->defaults[$fn]['filter_regexp']) ) { + $this->{$fn} = preg_replace($this->defaults[$fn]['filter_regexp'], '', $args[0]); + } else { $this->{$fn} = $args[0]; + } } if ( property_exists($this, $fn) ) { @@ -63,7 +66,7 @@ class ZM_Object { public static function _find($class, $parameters = null, $options = null ) { $table = $class::$table; $filters = array(); - $sql = "SELECT * FROM `$table` "; + $sql = 'SELECT * FROM `'.$table.'` '; $values = array(); if ( $parameters ) { @@ -164,24 +167,11 @@ class ZM_Object { # perhaps should turn into a comma-separated string $this->{$k} = implode(',', $v); } else if ( is_string($v) ) { -if ( 0 ) { -# Remarking this out. We are setting a value, not asking for a default to be set. -# So don't do defaults here, do them somewhere else - if ( ($v == null) and array_key_exists($k, $this->defaults) ) { -Logger::Debug("$k => Have default for $v: "); - if ( is_array($this->defaults[$k]) ) { - $this->{$k} = $this->defaults[$k]['default']; - } else { - $this->{$k} = $this->defaults[$k]; - Logger::Debug("$k => Have default for $v: " . $this->{$k}); - } - } else { + if ( array_key_exists($k, $this->defaults) && is_array($this->defaults[$k]) && isset($this->defaults[$k]['filter_regexp']) ) { + $this->{$k} = preg_replace($this->defaults[$k]['filter_regexp'], '', trim($v)); + } else { $this->{$k} = trim($v); } -} else { - $this->{$k} = trim($v); -} - } else if ( is_integer($v) ) { $this->{$k} = $v; } else if ( is_bool($v) ) { @@ -250,6 +240,9 @@ Logger::Debug("$k => Have default for $v: "); # Input might be a command separated string, or an array } else { + if ( array_key_exists($field, $this->defaults) && is_array($this->defaults[$field]) && isset($this->defaults[$field]['filter_regexp']) ) { + $value = preg_replace($this->defaults[$field]['filter_regexp'], '', trim($value)); + } if ( $this->{$field} != $value ) { $changes[$field] = $value; } @@ -270,17 +263,6 @@ Logger::Debug("$k => Have default for $v: "); $changes[$field] = $value; } } - - #if ( (!array_key_exists($field, $this)) or ( $this->{$field} != $new_values[$field] ) ) { - #Logger::Debug("Checking default $field => $default_value changes becaause" . $new_values[$field].' != '.$new_values[$field]); - #$changes[$field] = $new_values[$field]; - ##} else if { - #Logger::Debug("Checking default $field => $default_value changes becaause " . $new_values[$field].' != '.$new_values[$field]); - ##array_push( $changes, [$field=>$defaults[$field]] ); - #} - #} else { - #Logger::Debug("Checking default $field => $default_value not in new_values"); - #} } # end foreach newvalue From f5bf474ba6d8e4f8952f4036313ce6c7a81cfbe6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 23 Apr 2020 14:59:21 -0400 Subject: [PATCH 12/70] filter bad characters out of Monitor Name --- web/includes/Monitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 8c45c0d27..c788b5fb8 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -11,7 +11,7 @@ class Monitor extends ZM_Object { protected $defaults = array( 'Id' => null, - 'Name' => '', + 'Name' => array('type'=>'text','filter_regexp'=>'/[^\w\-\.\(\)\:\/ ]/'), 'Notes' => '', 'ServerId' => 0, 'StorageId' => 0, From eb26c5f7981b560ff9ea7fdb30aa5cfc92c22bb1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 11:09:12 -0500 Subject: [PATCH 13/70] Fix use of array_key_exists instead of property_exists --- web/includes/Object.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Object.php b/web/includes/Object.php index 9d037c014..e83aa1080 100644 --- a/web/includes/Object.php +++ b/web/includes/Object.php @@ -281,7 +281,7 @@ class ZM_Object { # Set defaults. Note that we only replace "" with null, not other values # because for example if we want to clear TimestampFormat, we clear it, but the default is a string value foreach ( $this->defaults as $field => $default ) { - if ( (!array_key_exists($field, $this)) or ($this->{$field} == '') ) { + if ( (!property_exists($this, $field)) or ($this->{$field} == '') ) { if ( is_array($default) ) { $this->{$field} = $default['default']; } else if ( $default == null ) { From b05916fc50af913e080346bbc11aafc2dcc37139 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 9 Mar 2020 14:39:22 -0400 Subject: [PATCH 14/70] Use === when testing for empty value and setting defaults --- web/includes/Object.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/includes/Object.php b/web/includes/Object.php index e83aa1080..1668a7767 100644 --- a/web/includes/Object.php +++ b/web/includes/Object.php @@ -206,7 +206,8 @@ class ZM_Object { } } } # end foreach default - } + } # end if defaults + foreach ( $new_values as $field => $value ) { if ( method_exists($this, $field) ) { @@ -281,7 +282,7 @@ class ZM_Object { # Set defaults. Note that we only replace "" with null, not other values # because for example if we want to clear TimestampFormat, we clear it, but the default is a string value foreach ( $this->defaults as $field => $default ) { - if ( (!property_exists($this, $field)) or ($this->{$field} == '') ) { + if ( (!property_exists($this, $field)) or ($this->{$field} === '') ) { if ( is_array($default) ) { $this->{$field} = $default['default']; } else if ( $default == null ) { From f06dc3f1718aee437f04d3d0b2598f21d33d1154 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 28 Mar 2020 10:09:13 -0400 Subject: [PATCH 15/70] Update group save action, using Group object methods. Fixes errors on new MariaDB --- web/includes/actions/group.php | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/web/includes/actions/group.php b/web/includes/actions/group.php index 9aa988540..b23659d18 100644 --- a/web/includes/actions/group.php +++ b/web/includes/actions/group.php @@ -21,42 +21,31 @@ // Group edit actions # Should probably verify that each monitor id is a valid monitor, that we have access to. # However at the moment, you have to have System permissions to do this -if ( ! canEdit('Groups') ) { +if ( !canEdit('Groups') ) { ZM\Warning('Need group edit permissions to edit groups'); return; } if ( $action == 'Save' ) { - $monitors = empty($_POST['newGroup']['MonitorIds']) ? '' : implode(',', $_POST['newGroup']['MonitorIds']); $group_id = null; - if ( !empty($_POST['gid']) ) { + if ( !empty($_POST['gid']) ) $group_id = $_POST['gid']; - dbQuery( - 'UPDATE Groups SET Name=?, ParentId=? WHERE Id=?', + $group = new ZM\Group($group_id); + $group->save( array( - $_POST['newGroup']['Name'], - ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), - $group_id, + 'Name'=> $_POST['newGroup']['Name'], + 'ParentId'=>( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), ) ); - dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($group_id)); - } else { - dbQuery( - 'INSERT INTO Groups (Name,ParentId) VALUES (?,?)', - array( - $_POST['newGroup']['Name'], - ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), - ) - ); - $group_id = dbInsertId(); - } + dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($group_id)); + $group_id = $group->Id(); if ( $group_id ) { foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) { - dbQuery('INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($group_id, $mid)); + dbQuery('INSERT INTO `Groups_Monitors` (`GroupId`,`MonitorId`) VALUES (?,?)', array($group_id, $mid)); } } $view = 'none'; $refreshParent = true; $closePopup = true; -} +} ?> From 54995ab0d10c5a4436219e53076360745359a023 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:13:30 -0400 Subject: [PATCH 16/70] handle sort_asc not being set. Handle term['val'] not being set. --- web/includes/functions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index e8adbdb5c..e616e2c8f 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1063,7 +1063,7 @@ function parseSort($saveToSession=false, $querySep='&') { $sortColumn = 'E.StartTime'; break; } - if ( !$_REQUEST['sort_asc'] ) + if ( !isset($_REQUEST['sort_asc']) ) $_REQUEST['sort_asc'] = 0; $sortOrder = $_REQUEST['sort_asc'] ? 'asc' : 'desc'; $sortQuery = $querySep.'sort_field='.validHtmlStr($_REQUEST['sort_field']).$querySep.'sort_asc='.validHtmlStr($_REQUEST['sort_asc']); @@ -1230,6 +1230,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') { break; } $valueList = array(); + if ( !isset($term['val']) ) $term['val'] = ''; foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) { switch ( $term['attr'] ) { case 'MonitorName': From 17896b656a019ad19d69a22a9fcfe6b59d26966c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:14:46 -0400 Subject: [PATCH 17/70] cleanup and revert adding Event stack trace --- web/js/logger.js | 55 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/web/js/logger.js b/web/js/logger.js index 0a1195043..bf5444268 100644 --- a/web/js/logger.js +++ b/web/js/logger.js @@ -53,12 +53,13 @@ function logReport( level, message, file, line ) { /* eslint-enable no-caller */ if ( !debugReq ) { + debugParms = "view=request&request=log&task=create"; if ( Browser ) { - debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+(Browser.Platform?Browser.Platform.name:'unknown'); + debugParms += "&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+(Browser.Platform?Browser.Platform.name:'unknown'); } else { - debugParms = "view=request&request=log&task=create&browser[name]=unknown&browser[version]=unknown&browser[platform]=unknown"; + debugParms += "&browser[name]=unknown&browser[version]=unknown&browser[platform]=unknown"; } - debugReq = new Request.JSON( {url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain'} ); + debugReq = new Request.JSON({url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain'}); } var requestParms = debugParms; requestParms += "&level="+level+"&message="+encodeURIComponent(message); @@ -71,57 +72,57 @@ function logReport( level, message, file, line ) { if ( line ) { requestParms += "&line="+line; } - debugReq.send( requestParms ); + debugReq.send(requestParms); } -function Panic( message ) { - console.error( message ); - logReport( "PNC", message ); - alert( "PANIC: "+message ); +function Panic(message) { + console.error(message); + logReport("PNC", message); + alert("PANIC: "+message); } -function Fatal( message ) { - console.error( message ); +function Fatal(message) { + console.error(message); logReport( "FAT", message ); alert( "FATAL: "+message ); } -function Error( message ) { - console.error( message ); - logReport( "ERR", message ); +function Error(message) { + console.error(message); + logReport("ERR", message); } -function Warning( message ) { - console.warn( message ); - logReport( "WAR", message ); +function Warning(message) { + console.warn(message); + logReport("WAR", message); } -function Info( message ) { - console.info( message ); - logReport( "INF", message ); +function Info(message) { + console.info(message); + logReport("INF", message); } -function Debug( message ) { - console.debug( message ); - //logReport( "DBG", message ); +function Debug(message) { + console.debug(message); + //logReport("DBG", message); } -function Dump( value, label ) { +function Dump(value, label) { if ( label ) { - console.debug( label+" => " ); + console.debug(label+" => "); } - console.debug( value ); + console.debug(value); } window.onerror = function( message, url, line ) { - logReport( "ERR", message, url, line ); + logReport("ERR", message, url, line); }; window.addEventListener("securitypolicyviolation", function logCSP(evt) { var level = evt.disposition == "enforce" ? "ERR" : "DBG"; var message = evt.blockedURI + " violated CSP " + evt.violatedDirective; - if (evt.sample) { + if ( evt.sample ) { message += " (Sample: " + evt.sample + ")"; } logReport(level, message, evt.sourceFile, evt.lineNumber); From c0b7aad2c839e5e16246cf13bb6513bd3bc093d1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 5 Mar 2020 14:10:35 -0500 Subject: [PATCH 18/70] add passive to addEventListener --- web/js/overlay.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/js/overlay.js b/web/js/overlay.js index 6517d2d7d..84547c53f 100644 --- a/web/js/overlay.js +++ b/web/js/overlay.js @@ -51,8 +51,8 @@ var Overlay = new Class({ }, show: function() { this.mask.show(); - window.addEventListener( 'resize', this.update.bind(this) ); - window.addEventListener( 'scroll', this.update.bind(this) ); + window.addEventListener( 'resize', this.update.bind(this), {passive: true} ); + window.addEventListener( 'scroll', this.update.bind(this), {passive: true} ); this.element.tween( 'opacity', [0, 1.0] ); this.element.show(); this.element.position(); @@ -80,8 +80,8 @@ var Overlay = new Class({ } updateOverlayLoading(); this.loading.setStyle( 'display', 'block' ); - window.addEventListener( 'resize', this.update.bind(this) ); - window.addEventListener( 'scroll', this.update.bind(this) ); + window.addEventListener( 'resize', this.update.bind(this), {passive: true} ); + window.addEventListener( 'scroll', this.update.bind(this), {passive: true} ); }, hideAnimation: function() { if ( this.loading ) { From a7e49bd62adc7dea0a77bc8bff2d1b4516c14111 Mon Sep 17 00:00:00 2001 From: out Date: Thu, 9 Apr 2020 15:30:43 +0800 Subject: [PATCH 19/70] =?UTF-8?q?update=20chinese=20translation=20(?= =?UTF-8?q?=EF=BD=9E=EF=BF=A3=E2=96=BD=EF=BF=A3)=EF=BD=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/lang/cn_zh.php | 285 ++++++++++++++++++++++++++------------------- 1 file changed, 163 insertions(+), 122 deletions(-) diff --git a/web/lang/cn_zh.php b/web/lang/cn_zh.php index 0a751023e..dec44eb95 100644 --- a/web/lang/cn_zh.php +++ b/web/lang/cn_zh.php @@ -74,12 +74,14 @@ $SLANG = array( '24BitColour' => '24 位彩色', '32BitColour' => '32 位彩色', // Added - 2011-06-15 '8BitGrey' => '8 位灰度', + 'API' => 'API', // Added - 2020-04-09 + 'APIEnabled' => 'API已启用', // Added - 2020-04-09 'Action' => '活动动作', 'Actual' => '实际', 'AddNewControl' => '新建控制', 'AddNewMonitor' => '新建监视器', - 'AddNewServer' => 'Add New Server', // Added - 2018-08-30 - 'AddNewStorage' => 'Add New Storage', // Added - 2018-08-30 + 'AddNewServer' => '新建服务器', // Added - 2018-08-30 + 'AddNewStorage' => '新建存储', // Added - 2018-08-30 'AddNewUser' => '新建用户', 'AddNewZone' => '新建区域', 'Alarm' => '报警', @@ -90,11 +92,12 @@ $SLANG = array( 'AlarmMaximumFPS' => '报警最大帧率FPS', 'AlarmPx' => '报警像素', 'AlarmRGBUnset' => '你必须设置一个报警颜色(RGB)', - 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 + 'AlarmRefImageBlendPct'=> '报警参考影像混合 %ge', // Added - 2015-04-18 'Alert' => '警报', 'All' => '全部', - 'AnalysisFPS' => 'Analysis FPS', // Added - 2015-07-22 - 'AnalysisUpdateDelay' => 'Analysis Update Delay', // Added - 2015-07-23 + 'AllTokensRevoked' => '已撤销所有tokens', // Added - 2020-04-09 + 'AnalysisFPS' => '分析帧率 FPS', // Added - 2015-07-22 + 'AnalysisUpdateDelay' => '分析更新延迟', // Added - 2015-07-23 'Apply' => '应用', 'ApplyingStateChange' => '状态改变生效', 'ArchArchived' => '仅限于存档', @@ -107,30 +110,31 @@ $SLANG = array( 'AttrArchiveStatus' => '存档状态', 'AttrAvgScore' => '平均分数', 'AttrCause' => '原因', - 'AttrDiskBlocks' => '磁碟区块', - 'AttrDiskPercent' => '磁碟百分比', - 'AttrDiskSpace' => 'Disk Space', // Added - 2018-08-30 + 'AttrDiskBlocks' => '磁盘区块', + 'AttrDiskPercent' => '磁盘百分比', + 'AttrDiskSpace' => '磁盘空间', // Added - 2018-08-30 'AttrDuration' => '过程', - '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 + 'AttrEndDate' => '结束日期', // Added - 2018-08-30 + 'AttrEndDateTime' => '结束日期/时间', // Added - 2018-08-30 + 'AttrEndTime' => '结束时间', // Added - 2018-08-30 + 'AttrEndWeekday' => '结束星期', // Added - 2018-08-30 + 'AttrFilterServer' => '过滤服务正运行在', // Added - 2018-08-30 'AttrFrames' => '帧', 'AttrId' => 'Id', 'AttrMaxScore' => '最大分数', 'AttrMonitorId' => '监视器 Id', 'AttrMonitorName' => '监视器名称', - 'AttrMonitorServer' => 'Server Monitor is Running On', // Added - 2018-08-30 + 'AttrMonitorServer' => '监控服务正运行在', // Added - 2018-08-30 'AttrName' => '名称', 'AttrNotes' => '备注', - '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 + 'AttrSecondaryStorageArea'=> '第二存储区域', // Added - 2020-04-09 + 'AttrStartDate' => '开始日期', // Added - 2018-08-30 + 'AttrStartDateTime' => '开始日期/时间', // Added - 2018-08-30 + 'AttrStartTime' => '开始时间', // Added - 2018-08-30 + 'AttrStartWeekday' => '开始星期', // Added - 2018-08-30 + 'AttrStateId' => '运行状态', // Added - 2018-08-30 + 'AttrStorageArea' => '存储区域', // Added - 2018-08-30 + 'AttrStorageServer' => '存储服务器', // Added - 2018-08-30 'AttrSystemLoad' => '系统负载', 'AttrTotalScore' => '总分数', 'Auto' => '自动', @@ -141,10 +145,10 @@ $SLANG = array( 'BackgroundFilter' => '在后台运行筛选器', 'BadAlarmFrameCount' => '报警帧数必须设为大于1的整数', 'BadAlarmMaxFPS' => '报警最大帧率必须是正整数或正浮点数', - 'BadAnalysisFPS' => 'Analysis FPS must be a positive integer or floating point value', // Added - 2015-07-22 - 'BadAnalysisUpdateDelay'=> 'Analysis update delay must be set to an integer of zero or more', // Added - 2015-07-23 + 'BadAnalysisFPS' => '分析帧率 FPS 必须是正整数或正浮点数', // Added - 2015-07-22 + 'BadAnalysisUpdateDelay'=> '分析更新延迟必须设为大于零的整数', // Added - 2015-07-23 'BadChannel' => '通道必须设为大于零的整数', - 'BadColours' => 'Target colour must be set to a valid value', // Added - 2011-06-15 + 'BadColours' => '颜色必须设置为有效值', // Added - 2011-06-15 'BadDevice' => '必须为器件设置有效值', 'BadFPSReportInterval' => 'FPS帧数报告间隔缓冲数必须是0以上整数', 'BadFormat' => '格式必须设为大于零的整数', @@ -155,9 +159,10 @@ $SLANG = array( 'BadLabelX' => '标签 X 坐标必须设为大于零的整数', 'BadLabelY' => '标签 Y 坐标必须设为大于零的整数', 'BadMaxFPS' => '最大帧数FPS必须设为正整数或着浮点数', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', + 'BadMotionFrameSkip' => '运动跳帧数必须设为大于零的整数', 'BadNameChars' => '名称只可以包含字母,数字,波折号和下划线', - 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 + 'BadNoSaveJPEGsOrVideoWriter'=> '保存为JPEGs和保存为视频同时禁用后。不会有任何记录 ', // Added - 2020-04-09 + 'BadPalette' => '调色板必须设为有效值', // Added - 2009-03-31 'BadPath' => '路径必须设为有效值', 'BadPort' => '端口必须设为有效数字', 'BadPostEventCount' => '之后事件影像数目必须设为大于零的整数', @@ -165,11 +170,11 @@ $SLANG = array( 'BadRefBlendPerc' => '参考混合百分比必须设为一个正整数', 'BadSectionLength' => '节长度必须设为30的整数倍', 'BadSignalCheckColour' => '信号检查颜色必须设为有效的RGB颜色字符', - 'BadSourceType' => 'Source Type \"Web Site\" requires the Function to be set to \"Monitor\"', // Added - 2018-08-30 + 'BadSourceType' => '源类型 \"网站\" 要求 功能 设置为 \"监视\"', // Added - 2018-08-30 'BadStreamReplayBuffer' => '流重放缓冲必须为零或更多整数', 'BadWarmupCount' => '预热帪必须设为零或更多整数', 'BadWebColour' => 'Web颜色必须设为有效Web颜色字符', - 'BadWebSitePath' => 'Please enter a complete website url, including the http:// or https:// prefix.', // Added - 2018-08-30 + 'BadWebSitePath' => '请输入一个完整的网站链接,包括http://或https://前缀。', // Added - 2018-08-30 'BadWidth' => '宽度必须设为有效值', 'Bandwidth' => '带宽', 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing @@ -177,9 +182,9 @@ $SLANG = array( 'BlobSizes' => 'Blob大小', 'Blobs' => 'Blobs', 'Brightness' => '亮度', - 'Buffer' => 'Buffer', // Added - 2015-04-18 + 'Buffer' => '缓冲', // Added - 2015-04-18 'Buffers' => '缓冲器', - 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 + 'CSSDescription' => '改变本机默认css', // Added - 2015-04-18 'CanAutoFocus' => '可以自动对焦', 'CanAutoGain' => '可以自动增益控制', 'CanAutoIris' => '可以自动光圈', @@ -204,8 +209,8 @@ $SLANG = array( 'CanMoveMap' => '可以映射网格移动', 'CanMoveRel' => '可以相对移动', 'CanPan' => '可以平移' , + 'CanReboot' => '可以重启', 'CanReset' => '可以复位', - 'CanReboot' => 'Can Reboot', 'CanSetPresets' => '可以进行预设', 'CanSleep' => '可以休眠', 'CanTilt' => '可以倾斜', @@ -224,22 +229,23 @@ $SLANG = array( 'CaptureHeight' => '捕获高度', 'CaptureMethod' => '捕获方式', 'CapturePalette' => '捕获调色板', - 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 + 'CaptureResolution' => '捕获分辨率', // Added - 2015-04-18 'CaptureWidth' => '捕获宽度', 'Cause' => '原因', 'CheckMethod' => '报警检查方式', - 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 + 'ChooseDetectedCamera' => '选择检测到的摄像头', // Added - 2009-03-31 + 'ChooseDetectedProfile'=> '选择检测到的流媒体', // Added - 2020-04-09 'ChooseFilter' => '选择筛选器', - 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogFormat' => '选择日志格式', // Added - 2011-06-17 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => '选择预置', - 'Clear' => 'Clear', // Added - 2011-06-16 - 'CloneMonitor' => 'Clone', // Added - 2018-08-30 + 'Clear' => '清除', // Added - 2011-06-16 + 'CloneMonitor' => '克隆', // Added - 2018-08-30 'Close' => '关闭', 'Colour' => '彩色', 'Command' => '命令', - 'Component' => 'Component', // Added - 2011-06-16 - 'ConcurrentFilter' => 'Run filter concurrently', // Added - 2018-08-30 + 'Component' => '组件', // Added - 2011-06-16 + 'ConcurrentFilter' => '同时应用筛选器', // Added - 2018-08-30 'Config' => '配置', 'ConfiguredFor' => '配置标的', 'ConfirmDeleteEvents' => '确认希望删除所选事件?', @@ -257,24 +263,25 @@ $SLANG = array( 'ControlDevice' => '控制设备', 'ControlType' => '控制类型', 'Controllable' => '可控', - 'Current' => 'Current', // Added - 2015-04-18 + 'Current' => '现在', // Added - 2015-04-18 'Cycle' => '循环', 'CycleWatch' => '循环监视', - 'DateTime' => 'Date/Time', // Added - 2011-06-16 + 'DateTime' => '日期', // Added - 2011-06-16 'Day' => '日', 'Debug' => '调试', + 'DefaultCodec' => '默认即时观看方法', // Added - 2020-04-09 'DefaultRate' => '缺省速率', 'DefaultScale' => '缺省缩放', 'DefaultView' => '缺省视角', - 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 - 'Delay' => 'Delay', // Added - 2015-04-18 + 'Deinterlacing' => '去隔行', // Added - 2015-04-18 + 'Delay' => '延迟', // Added - 2015-04-18 'Delete' => '删除', 'DeleteAndNext' => '删除并下一个', 'DeleteAndPrev' => '删除并前一个', 'DeleteSavedFilter' => '删除存储过滤器', 'Description' => '描述', - 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 - 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 + 'DetectedCameras' => '检测到的摄像头', // Added - 2009-03-31 + 'DetectedProfiles' => '检测到的流媒体', // Added - 2015-04-18 'Device' => '设备', 'DeviceChannel' => '设备通道', 'DeviceFormat' => '设备格式', @@ -283,10 +290,10 @@ $SLANG = array( 'Devices' => '设备', 'Dimensions' => '维度', 'DisableAlarms' => '关闭警报', - 'Disk' => '磁碟', - 'Display' => 'Display', // Added - 2011-01-30 - 'Displaying' => 'Displaying', // Added - 2011-06-16 - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', + 'Disk' => '磁盘', + 'Display' => '显示', // Added - 2011-01-30 + 'Displaying' => '正在显示', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> '在本机进行运动检测', 'Donate' => '请捐款', 'DonateAlready' => '不,我已经捐赠过了', 'DonateEnticement' => '迄今,您已经运行ZoneMinder有一阵子了,希望它能够有助于增强您家或者办公区域的安全。尽管ZoneMinder是,并将保持免费和开源,该项目依然在研发和支持中投入了资金和精力。如果您愿意支持今后的开发和新功能,那么请考虑为该项目捐款。捐款不是必须的,任何数量的捐赠,我们都很感谢。

如果您愿意捐款,请选择下列选项,或者访问 https://zoneminder.com/donate/ 捐赠主页。

感谢您使用ZoneMinder,并且不要忘记访问访问ZoneMinder.com的论坛以获得支持或建议,这可以提升您的ZoneMinder的体验。', @@ -297,11 +304,11 @@ $SLANG = array( 'DonateRemindWeek' => '现在不,1星期内再次提醒我', 'DonateYes' => '好,我现在就捐款', 'Download' => '下载', - 'DownloadVideo' => 'Download Video', // Added - 2018-08-30 + 'DownloadVideo' => '下载视频', // Added - 2018-08-30 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Duration', 'Edit' => '编辑', - 'EditLayout' => 'Edit Layout', // Added - 2018-08-30 + 'EditLayout' => '编辑布局', // Added - 2018-08-30 'Email' => 'Email', 'EnableAlarms' => '启动报警', 'Enabled' => '已启动', @@ -318,8 +325,9 @@ $SLANG = array( 'Events' => '事件', 'Exclude' => '排除', 'Execute' => '执行', - 'Exif' => 'Embed EXIF data into image', // Added - 2018-08-30 + 'Exif' => '嵌入EXIF信息到图片', // Added - 2018-08-30 'Export' => '导出', + 'ExportCompress' => '使用压缩', // Added - 2020-04-09 'ExportDetails' => '导出时间详情', 'ExportFailed' => '导出失败', 'ExportFormat' => '导出文件格式', @@ -327,7 +335,8 @@ $SLANG = array( 'ExportFormatZip' => 'Zip', 'ExportFrames' => '导出帧详情', 'ExportImageFiles' => '导出影像文件', - 'ExportLog' => 'Export Log', // Added - 2011-06-17 + 'ExportLog' => '导出日志', // Added - 2011-06-17 + 'ExportMatches' => '导出匹配项', // Added - 2020-04-09 'ExportMiscFiles' => '导出其他文件 (如果存在)', 'ExportOptions' => '导出选项', 'ExportSucceeded' => '导出成功', @@ -341,29 +350,30 @@ $SLANG = array( 'Feed' => '转送源', 'Ffmpeg' => 'Ffmpeg', 'File' => '文件', - 'Filter' => 'Filter', // Added - 2015-04-18 - 'FilterArchiveEvents' => '将全部匹配项存档', - 'FilterDeleteEvents' => '将全部匹配项删除', - 'FilterEmailEvents' => '将全部匹配项详情电邮出去', + 'Filter' => '过滤器', // Added - 2015-04-18 + 'FilterArchiveEvents' => '存档全部匹配项', + 'FilterCopyEvents' => '复制全部匹配项', // Added - 2020-04-09 + 'FilterDeleteEvents' => '删除全部匹配项', + 'FilterEmailEvents' => '邮件发送全部匹配项详情', 'FilterExecuteEvents' => '执行全部匹配项命令', - 'FilterLog' => 'Filter log', // Added - 2015-04-18 + 'FilterLog' => '过滤日志', // Added - 2015-04-18 'FilterMessageEvents' => '全部匹配项的信息详情', - 'FilterMoveEvents' => 'Move all matches', // Added - 2018-08-30 + 'FilterMoveEvents' => '移除全部匹配项', // Added - 2018-08-30 'FilterPx' => '过滤器像素', 'FilterUnset' => '您必须指定过滤器宽度和高度', - 'FilterUpdateDiskSpace'=> 'Update used disk space', // Added - 2018-08-30 + 'FilterUpdateDiskSpace'=> '刷新磁盘空间', // Added - 2018-08-30 'FilterUploadEvents' => '上传全部匹配项', 'FilterVideoEvents' => '为全部匹配项创建视频', 'Filters' => '过滤器', 'First' => '首先', 'FlippedHori' => '水平翻转', 'FlippedVert' => '垂直翻转', - 'FnMocord' => 'Mocord', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. + 'FnMocord' => '运动侦测并录制', // Added 2013.08.16. + 'FnModect' => '运动侦测', // Added 2013.08.16. + 'FnMonitor' => '监视', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. - 'FnNone' => 'None', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. + 'FnNone' => '无', // Added 2013.08.16. + 'FnRecord' => '录制', // Added 2013.08.16. 'Focus' => '聚焦', 'ForceAlarm' => '强制报警', 'Format' => '格式', @@ -376,7 +386,7 @@ $SLANG = array( 'Function' => '功能', 'Gain' => '增益', 'General' => '一般', - 'GenerateDownload' => 'Generate Download', // Added - 2018-08-30 + 'GenerateDownload' => '创建下载项', // Added - 2018-08-30 'GenerateVideo' => '创建视频', 'GeneratingVideo' => '正在创建视频', 'GoToZoneMinder' => '访问 ZoneMinder.com', @@ -397,7 +407,7 @@ $SLANG = array( 'High' => '高', 'HighBW' => '高 B/W', 'Home' => '主页', - 'Hostname' => 'Hostname', // Added - 2018-08-30 + 'Hostname' => '主机名', // Added - 2018-08-30 'Hour' => '小时', 'Hue' => '色调', 'Id' => 'Id', @@ -408,6 +418,7 @@ $SLANG = array( 'Images' => '影像', 'In' => '在', 'Include' => '包含', + 'InvalidateTokens' => '使所有创建的tokens无效', // Added - 2020-04-09 'Inverted' => '反向', 'Iris' => '光圈', 'KeyString' => '密钥字符', @@ -415,19 +426,19 @@ $SLANG = array( 'Language' => '语言', 'Last' => '最后', 'Layout' => '布局', - 'Level' => 'Level', // Added - 2011-06-16 + 'Level' => '级别', // Added - 2011-06-16 'Libvlc' => 'Libvlc', 'LimitResultsPost' => '个结果', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => '仅限于开始', // This is used at the beginning of the phrase 'Limit to first N results only' - 'Line' => 'Line', // Added - 2011-06-16 + 'Line' => '行', // Added - 2011-06-16 'LinkedMonitors' => '管理监视器', 'List' => '列表', - 'ListMatches' => 'List Matches', // Added - 2018-08-30 + 'ListMatches' => '列出匹配项', // Added - 2018-08-30 'Load' => '加载', 'Local' => '本地', - 'Log' => 'Log', // Added - 2011-06-16 + 'Log' => '日志', // Added - 2011-06-16 'LoggedInAs' => '登录为', - 'Logging' => 'Logging', // Added - 2011-06-16 + 'Logging' => '日志', // Added - 2011-06-16 'LoggingIn' => '登录', 'Login' => '登入', 'Logout' => '登出', @@ -465,7 +476,7 @@ $SLANG = array( 'MaximumFPS' => '最大帧率 FPS', 'Medium' => '中等', 'MediumBW' => '中等 B/W', - 'Message' => 'Message', // Added - 2011-06-16 + 'Message' => '消息', // Added - 2011-06-16 'MinAlarmAreaLtMax' => '最小报警区域应该小于最大区域', 'MinAlarmAreaUnset' => '您必须指定最小报警像素数量', 'MinBlobAreaLtMax' => '最小blob区必须小数最大区域', @@ -500,25 +511,25 @@ $SLANG = array( 'MinZoomSpeed' => '最小缩放速度', 'MinZoomStep' => '最小缩放步进', 'Misc' => '杂项', - 'Mode' => 'Mode', // Added - 2015-04-18 + 'Mode' => '模式', // Added - 2015-04-18 'Monitor' => '监视器', 'MonitorIds' => '监视器 Ids', 'MonitorPreset' => '监视器预设值', 'MonitorPresetIntro' => '从以下列表中选择一个合适的预设值.

请注意该方式可能覆盖您为该监视器配置的数值.

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

Select the desired entry from the list below.

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

', // Added - 2009-03-31 + 'MonitorProbe' => '监视器探测', // Added - 2009-03-31 + 'MonitorProbeIntro' => '以下列表显示了检测到的模拟和网络摄像头,以及其可用状态

请从列表中选择你想要的项

请注意可能有些摄像头并没有检测到,而且选择一个摄像头可能覆盖一些你已经设置的配置。

', // Added - 2009-03-31 'Monitors' => '监视器', 'Montage' => '镜头组接', 'MontageReview' => 'Montage Review', // Added - 2018-08-30 'Month' => '月', - 'More' => 'More', // Added - 2011-06-16 - 'MotionFrameSkip' => 'Motion Frame Skip', + 'More' => '更多', // Added - 2011-06-16 + 'MotionFrameSkip' => '运动侦测跳帧', 'Move' => '移动', 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. - 'MtgDefault' => 'Default', // Added 2013.08.15. + 'MtgDefault' => '默认', // Added 2013.08.15. 'MustBeGe' => '必须大于等于', 'MustBeLe' => '必须小于等于', 'MustConfirmPassword' => '您必须确认密码', @@ -534,9 +545,10 @@ $SLANG = array( 'NewState' => '新状态', 'NewUser' => '新用户', 'Next' => '下一个', + 'NextMonitor' => '下一个监视器', // Added - 2020-04-09 'No' => '不', - 'NoDetectedCameras' => 'No Detected Cameras', // Added - 2009-03-31 - 'NoDetectedProfiles' => 'No Detected Profiles', // Added - 2018-08-30 + 'NoDetectedCameras' => '没有检测到摄像头', // Added - 2009-03-31 + 'NoDetectedProfiles' => '没有检测到流媒体', // Added - 2018-08-30 'NoFramesRecorded' => '该事件没有相关帧的记录', 'NoGroup' => '无组', 'NoSavedFilters' => '没有保存过滤器', @@ -548,25 +560,27 @@ $SLANG = array( 'NumPresets' => '数值预置', 'Off' => '关', 'On' => '开', - 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifCredentialsIntro'=> '请为所选摄像头提供用户名和密码。
如果还没有为这台摄像头创建过用户,那么将会使用提供的用户名和密码创建用户

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

Select the desired entry from the list below.

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

', // Added - 2015-04-18 + 'OnvifProbeIntro' => '以下列表显示了检测到的ONVIF摄像头和其可用状态。

选择一个你想要的项

请注意可能有些摄像头并没有检测到,而且选择一个摄像头可能覆盖一些你已经设置的配置。

', // Added - 2015-04-18 'OpEq' => '等于', 'OpGt' => '大于', 'OpGtEq' => '大于等于', 'OpIn' => '在集', - 'OpIs' => 'is', // Added - 2018-08-30 - 'OpIsNot' => 'is not', // Added - 2018-08-30 + 'OpIs' => '是', // Added - 2018-08-30 + 'OpIsNot' => '不是', // Added - 2018-08-30 + 'OpLike' => '包含', // Added - 2020-04-09 'OpLt' => '小于', 'OpLtEq' => '小于等于', 'OpMatches' => '匹配', 'OpNe' => '不等于', 'OpNotIn' => '未在集', + 'OpNotLike' => '未包含', // Added - 2020-04-09 'OpNotMatches' => '不匹配', 'Open' => '打开', 'OptionHelp' => '选项帮助', 'OptionRestartWarning' => '这些改动在系统运行时可以不会完全生效.\n 当你设置完毕改动后\n请确认\n您重新启动 ZoneMinder.', - 'OptionalEncoderParam' => 'Optional Encoder Parameters', // Added - 2018-08-30 + 'OptionalEncoderParam' => '编码参数(可选)', // Added - 2018-08-30 'Options' => '选项', 'OrEnterNewName' => '或输入新名词', 'Order' => '次序', @@ -579,8 +593,12 @@ $SLANG = array( 'PanRight' => '向右平移', 'PanTilt' => '平移/倾斜', 'Parameter' => '参数', + 'ParentGroup' => '父组', // Added - 2020-04-09 'Password' => '密码', 'PasswordsDifferent' => '新建密码和确认密码不一致', + 'PathToApi' => 'Api路径', // Added - 2020-04-09 + 'PathToIndex' => 'Index路径', // Added - 2020-04-09 + 'PathToZMS' => 'ZMS路径', // Added - 2020-04-09 'Paths' => '路径', 'Pause' => '暂停', 'Phone' => '电话', @@ -591,7 +609,7 @@ $SLANG = array( 'Play' => '播放', 'PlayAll' => '播放全部', 'PleaseWait' => '请等待', - 'Plugins' => 'Plugins', + 'Plugins' => '插件', 'Point' => '点', 'PostEventImageBuffer' => '事件之后影像数', 'PreEventImageBuffer' => '时间之前影像数', @@ -599,18 +617,31 @@ $SLANG = array( 'Preset' => '预置', 'Presets' => '预置', 'Prev' => '前', - 'Probe' => 'Probe', // Added - 2009-03-31 - 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 - 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

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

', // Added - 2015-04-18 + 'PreviousMonitor' => '前一个监视器', // Added - 2020-04-09 + 'Privacy' => 'Privacy', // Added - 2020-04-09 + 'PrivacyAbout' => '关于', // Added - 2020-04-09 + 'PrivacyAboutText' => 'Since 2002, ZoneMinder has been the premier free and open-source Video Management System (VMS) solution for Linux platforms. ZoneMinder is supported by the community and is managed by those who choose to volunteer their spare time to the project. The best way to improve ZoneMinder is to get involved.', // Added - 2020-04-09 + 'PrivacyConclusionText'=> 'We are NOT collecting any image specific data from your cameras. We don’t know what your cameras are watching. This data will not be sold or used for any purpose not stated herein. By clicking accept, you agree to send us this data to help make ZoneMinder a better product. By clicking decline, you can still freely use ZoneMinder and all its features.', // Added - 2020-04-09 + 'PrivacyContact' => '联系', // Added - 2020-04-09 + 'PrivacyContactText' => 'Please contact us here for any questions regarding our privacy policy or to have your information removed.

For support, there are three primary ways to engage with the community:

Our Github forum is only for bug reporting. Please use our user forum or slack channel for all other questions or comments.

', // Added - 2020-04-09 + 'PrivacyCookies' => 'Cookies', // Added - 2020-04-09 + 'PrivacyCookiesText' => 'Whether you use a web browser or a mobile app to communicate with the ZoneMinder server, a ZMSESSID cookie is created on the client to uniquely identify a session with the ZoneMinder server. ZmCSS and zmSkin cookies are created to remember your style and skin choices.', // Added - 2020-04-09 + 'PrivacyMonitorList' => 'The following configuration parameters from each monitor are collected:
  • Id
  • Name
  • Type
  • Function
  • Width
  • Height
  • Colours
  • MaxFPS
  • AlarmMaxFPS
', // Added - 2020-04-09 + 'PrivacyTelemetry' => 'Telemetry', // Added - 2020-04-09 + 'PrivacyTelemetryList' => 'The ZoneMinder Telemetry daemon collects the following data about your system:
  • A unique identifier (UUID)
  • City based location is gathered by querying ipinfo.io. City, region, country, latitude, and longitude parameters are saved. The latitude and longitude coordinates are accurate down to the city or town level only!
  • Current time
  • Total number of monitors
  • Total number of events
  • System architecture
  • Operating system kernel, distro, and distro version
  • Version of ZoneMinder
  • Total amount of memory
  • Number of cpu cores
', // Added - 2020-04-09 + 'PrivacyTelemetryText' => 'Because ZoneMinder is open-source, anyone can install it without registering. This makes it difficult to answer questions such as: how many systems are out there, what is the largest system out there, what kind of systems are out there, or where are these systems located? Knowing the answers to these questions, helps users who ask us these questions, and it helps us set priorities based on the majority user base.', // Added - 2020-04-09 + 'Probe' => '探测', // Added - 2009-03-31 + 'ProfileProbe' => '流媒体探测', // Added - 2015-04-18 + 'ProfileProbeIntro' => '以下列表显示了所选摄像头可用的流媒体。

从列表中选择一个你想要的项

请注意ZoneMinder不能设置额外的配置并且选择摄像头可能会覆盖一些你已设置的配置。

', // Added - 2015-04-18 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => '协议', - 'RTSPDescribe' => 'Use RTSP Response Media URL', // Added - 2018-08-30 - 'RTSPTransport' => 'RTSP Transport Protocol', // Added - 2018-08-30 + 'RTSPDescribe' => '使用 RTSP Response 媒体链接', // Added - 2018-08-30 + 'RTSPTransport' => 'RTSP传输协议', // Added - 2018-08-30 'Rate' => '速率', 'Real' => '实际', - 'RecaptchaWarning' => 'Your reCaptcha secret key is invalid. Please correct it, or reCaptcha will not work', // Added - 2018-08-30 + 'RecaptchaWarning' => '你的reCaptcha秘匙无效。 请更正,否则reCaptcha无法工作', // Added - 2018-08-30 'Record' => '记录', - 'RecordAudio' => 'Whether to store the audio stream when saving an event.', // Added - 2018-08-30 + 'RecordAudio' => '记录事件时保存音频.', // Added - 2018-08-30 'RefImageBlendPct' => '参考影像混合 %ge', 'Refresh' => '刷新', 'Remote' => '远程', @@ -626,7 +657,7 @@ $SLANG = array( 'ReplayAll' => '全部事件', 'ReplayGapless' => '无间隙事件', 'ReplaySingle' => '单一事件', - 'ReportEventAudit' => 'Audit Events Report', // Added - 2018-08-30 + 'ReportEventAudit' => '事件报表', // Added - 2018-08-30 'Reset' => '重置', 'ResetEventCounts' => '重置事件数', 'Restart' => '重启动', @@ -635,24 +666,29 @@ $SLANG = array( 'RestrictedMonitors' => '受限监视器', 'ReturnDelay' => '返回延时', 'ReturnLocation' => '返回位置', + 'RevokeAllTokens' => '撤销所有Tokens', // Added - 2020-04-09 'Rewind' => '重绕', 'RotateLeft' => '向左旋转', 'RotateRight' => '向右旋转', - 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 + 'RunAudit' => '审计', // Added - 2020-04-09 + 'RunEventNotification' => '事件提醒', // Added - 2020-04-09 + 'RunLocalUpdate' => '请运行zmupdate.pl来更新', // Added - 2011-05-25 'RunMode' => '运行模式', 'RunState' => '运行状态', + 'RunStats' => '状态检测', // Added - 2020-04-09 + 'RunTrigger' => '触发', // Added - 2020-04-09 'Running' => '运行', 'Save' => '保存', 'SaveAs' => '另存为', 'SaveFilter' => '存储过滤器', - 'SaveJPEGs' => 'Save JPEGs', // Added - 2018-08-30 + 'SaveJPEGs' => '保存为JPEGs', // Added - 2018-08-30 'Scale' => '比例', 'Score' => '分数', 'Secs' => '秒', 'Sectionlength' => '段长度', 'Select' => '选择', - 'SelectFormat' => 'Select Format', // Added - 2011-06-17 - 'SelectLog' => 'Select Log', // Added - 2011-06-17 + 'SelectFormat' => '选择格式', // Added - 2011-06-17 + 'SelectLog' => '选择日志', // Added - 2011-06-17 'SelectMonitors' => '选择监视器', 'SelfIntersecting' => '多边形边线不得交叉', 'Set' => '设置', @@ -661,10 +697,11 @@ $SLANG = array( 'Settings' => '设置', 'ShowFilterWindow' => '显示过滤器视窗', 'ShowTimeline' => '显示时间轴', - 'SignalCheckColour' => '型号检查颜色', - 'SignalCheckPoints' => 'Signal Check Points', // Added - 2018-08-30 + 'Shutdown' => '关机', // Added - 2020-04-09 + 'SignalCheckColour' => '信号检查颜色', + 'SignalCheckPoints' => '信号检测点数目', // Added - 2018-08-30 'Size' => '大小', - 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 + 'SkinDescription' => '改变本机默认皮肤', // Added - 2011-01-30 'Sleep' => '睡眠', 'SortAsc' => '升序', 'SortBy' => '排序', @@ -682,10 +719,10 @@ $SLANG = array( 'State' => '状态', 'Stats' => '统计', 'Status' => '状况', - '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' => '正在捕获', // Added - 2018-08-30 + 'StatusNotRunning' => '未运行', // Added - 2018-08-30 + 'StatusRunning' => '未捕获', // Added - 2018-08-30 + 'StatusUnknown' => '未知', // Added - 2018-08-30 'Step' => '步进', 'StepBack' => '单步后退', 'StepForward' => '单步前进', @@ -696,14 +733,16 @@ $SLANG = array( 'Stills' => '静止', 'Stop' => '停止', 'Stopped' => '已停止', - 'StorageArea' => 'Storage Area', // Added - 2018-08-30 - 'StorageScheme' => 'Scheme', // Added - 2018-08-30 + 'StorageArea' => '存储区域', // Added - 2018-08-30 + 'StorageDoDelete' => '开始删除', // Added - 2020-04-09 + 'StorageScheme' => '存储方案', // Added - 2018-08-30 'Stream' => '流', 'StreamReplayBuffer' => '流重放影像缓冲', 'Submit' => '发送', 'System' => '系统', - 'SystemLog' => 'System Log', // Added - 2011-06-16 - 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 + 'SystemLog' => '系统日志', // Added - 2011-06-16 + 'TZUnset' => '未设置 - 使用php.ini的配置', // Added - 2020-04-09 + 'TargetColorspace' => '色彩空间', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => '缩略图', 'Tilt' => '倾斜', @@ -711,18 +750,18 @@ $SLANG = array( 'TimeDelta' => '相对时间', 'TimeStamp' => '时间戳', 'Timeline' => '时间轴', - 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. - 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. + 'TimelineTip1' => '移动你的鼠标到图表上来查看快照图片和事件详情。', // Added 2013.08.15. + 'TimelineTip2' => '单击图形或图像的彩色部分来查看事件。', // Added 2013.08.15. 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. 'Timestamp' => '时间戳', 'TimestampLabelFormat' => '时间戳标签格式', - 'TimestampLabelSize' => 'Font Size', // Added - 2018-08-30 + 'TimestampLabelSize' => '字体大小', // Added - 2018-08-30 'TimestampLabelX' => '时间戳标签 X', 'TimestampLabelY' => '时间戳标签 Y', 'Today' => '今天', 'Tools' => '工具', - 'Total' => 'Total', // Added - 2011-06-16 + 'Total' => '总', // Added - 2011-06-16 'TotalBrScore' => '总
分数', 'TrackDelay' => '轨迹延时', 'TrackMotion' => '轨迹运动', @@ -737,23 +776,24 @@ $SLANG = array( 'Update' => '更新', 'UpdateAvailable' => '有新版本的ZoneMinder.', 'UpdateNotNecessary' => '无须更新', - 'Updated' => 'Updated', // Added - 2011-06-16 - 'Upload' => 'Upload', // Added - 2011-08-23 + 'Updated' => '已更新', // Added - 2011-06-16 + 'Upload' => '上传', // Added - 2011-08-23 'UseFilter' => '使用筛选器', 'UseFilterExprsPost' => ' 筛选器 表达式', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => '使用 ', // This is used at the beginning of the phrase 'use N filter expressions' - 'UsedPlugins' => 'Used Plugins', + 'UsedPlugins' => '已使用的插件', 'User' => '用户', 'Username' => '用户名', 'Users' => '用户', 'V4L' => 'V4L', // Added - 2015-04-18 - 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 - 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => '每帧捕获', // Added - 2015-04-18 + 'V4LMultiBuffer' => '多缓冲', // Added - 2015-04-18 'Value' => '数值', 'Version' => '版本', 'VersionIgnore' => '忽略该版本', 'VersionRemindDay' => '一天内再次提醒', 'VersionRemindHour' => '一小时内再次提醒', + 'VersionRemindMonth' => '一个月内再次提醒', // Added - 2020-04-09 'VersionRemindNever' => '不再提醒新版本', 'VersionRemindWeek' => '一周内再次提醒', 'Video' => '视频', @@ -764,17 +804,18 @@ $SLANG = array( 'VideoGenParms' => '视频产生参数', 'VideoGenSucceeded' => '视频产生成功!', 'VideoSize' => '视频尺寸', - 'VideoWriter' => 'Video Writer', // Added - 2018-08-30 + 'VideoWriter' => '保存为视频', // Added - 2018-08-30 'View' => '查看', 'ViewAll' => '查看全部', 'ViewEvent' => '查看事件', + 'ViewMatches' => '查看匹配项', // Added - 2020-04-09 'ViewPaged' => '查看分页', 'Wake' => '唤醒', 'WarmupFrames' => '预热帪', 'Watch' => '观察', 'Web' => 'Web', 'WebColour' => 'Web颜色', - 'WebSiteUrl' => 'Website URL', // Added - 2018-08-30 + 'WebSiteUrl' => '网站链接', // Added - 2018-08-30 'Week' => '周', 'White' => '白', 'WhiteBalance' => '白平衡', @@ -797,7 +838,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => '最小/最大污渍区数 Blobs', 'ZoneMinMaxFiltArea' => '最小/最大过滤区域', 'ZoneMinMaxPixelThres' => '最小/最大像素阈值(0-255)', - 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 + 'ZoneMinderLog' => 'ZoneMinder日志', // Added - 2011-06-17 'ZoneOverloadFrames' => '忽略过载帪数', 'Zones' => '区域', 'Zoom' => '缩放', @@ -814,7 +855,7 @@ $CLANG = array( 'MonitorCount' => '%1$s %2$s', // For example '4 Monitors' (from Vlang below) 'MonitorFunction' => '监视器 %1$s 功能', 'RunningRecentVer' => '您运行的是最新版的 ZoneMinder, v%s.', - 'VersionMismatch' => 'Version mismatch, system is version %1$s, database is %2$s.', // Added - 2011-05-25 + 'VersionMismatch' => '版本不匹配, 系统版本是 %1$s, 数据库版本是 %2$s.', // Added - 2011-05-25 ); // The next section allows you to describe a series of word ending and counts used to From 617b74b8bbabea21668ae00b3db4947ccd831524 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 23 Apr 2020 15:28:38 -0400 Subject: [PATCH 20/70] fix botched merge --- web/lang/cn_zh.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/lang/cn_zh.php b/web/lang/cn_zh.php index dec44eb95..9cdd9c4f1 100644 --- a/web/lang/cn_zh.php +++ b/web/lang/cn_zh.php @@ -601,6 +601,7 @@ $SLANG = array( 'PathToZMS' => 'ZMS路径', // Added - 2020-04-09 'Paths' => '路径', 'Pause' => '暂停', + 'PauseCycle' => 'Pause Cycle', // Added - 2020-04-09 'Phone' => '电话', 'PhoneBW' => '电话 B/W', 'Pid' => 'PID', // Added - 2011-06-16 @@ -608,6 +609,7 @@ $SLANG = array( 'Pixels' => '像素', 'Play' => '播放', 'PlayAll' => '播放全部', + 'PlayCycle' => 'Play Cycle', // Added - 2020-04-09 'PleaseWait' => '请等待', 'Plugins' => '插件', 'Point' => '点', From 042086b5650603bd3bb546c90ad08444502b4104 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 21 Feb 2020 09:30:31 -0500 Subject: [PATCH 21/70] Extend width of ControlDevice and Address to full width --- web/skins/classic/css/base/views/monitor.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/css/base/views/monitor.css b/web/skins/classic/css/base/views/monitor.css index 217b2f374..c0f4a36d9 100644 --- a/web/skins/classic/css/base/views/monitor.css +++ b/web/skins/classic/css/base/views/monitor.css @@ -10,7 +10,9 @@ } textarea, -input[name="newMonitor[Name]"] { +input[name="newMonitor[Name]"], +input[name="newMonitor[ControlDevice]"], +input[name="newMonitor[ControlAddress]"] { width: 100%; } input[name="newMonitor[Width]"], From 96774bd03868e475069938a3366586857c853514 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:30:30 -0400 Subject: [PATCH 22/70] fix inline javascript in ptz buttons --- .../classic/includes/control_functions.php | 72 +++++++++---------- web/skins/classic/views/js/watch.js | 13 ++-- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index 80cfe4aff..6f1399786 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -25,15 +25,15 @@ function controlFocus($monitor, $cmds) { ?>
- - - + + +
CanAutoFocus() ) { ?> - - + + @@ -48,15 +48,15 @@ function controlZoom($monitor, $cmds) { ?>
- - - + + +
CanAutoZoom() ) { ?> - - + + @@ -70,15 +70,15 @@ function controlIris($monitor, $cmds) { ?>
- - - + + +
CanAutoIris() ) { ?> - - + + @@ -93,15 +93,15 @@ function controlWhite($monitor, $cmds) { ?>
- - - + + +
CanAutoWhite() ) { ?> - - + + @@ -122,19 +122,19 @@ function controlPanTilt($monitor, $cmds) { $hasTilt = $control->CanTilt(); $hasDiag = $hasPan && $hasTilt && $control->CanMoveDiag(); ?> - - - - + + + + - + - - - - + + + +
Id() ) ) as $row ) { + foreach ( dbFetchAll($sql, NULL, array($monitor->Id())) as $row ) { $labels[$row['Preset']] = $row['Label']; } @@ -162,7 +162,7 @@ function controlPresets($monitor, $cmds) { NumPresets(); $i++ ) { ?> - + @@ -171,7 +171,7 @@ function controlPresets($monitor, $cmds) { HasHomePreset() ) { ?> - + CanSetPresets() ) { @@ -196,22 +196,22 @@ function controlPower($monitor, $cmds) { CanWake() ) { ?> - + CanSleep() ) { ?> - + CanReset() ) { ?> - + CanReboot() ) { ?> - + diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 83eae3475..0ad3a5536 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -651,8 +651,13 @@ function getControlResponse( respObj, respText ) { } } -function controlCmd( control, event, xtell, ytell ) { - var locParms = ""; +function controlCmd(button) { + + control = button.getAttribute('value'); + xtell = button.getAttribute('xtell'); + ytell = button.getAttribute('ytell'); + + var locParms = ''; if ( event && (xtell || ytell) ) { console.log(event); var target = event.target; @@ -668,7 +673,7 @@ function controlCmd( control, event, xtell, ytell ) { } else if ( xtell == 2 ) { xge = 2*(50 - xge); } - locParms += "&xge="+xge; + locParms += '&xge='+xge; } if ( ytell ) { var yge = parseInt( (y*100)/coords.height ); @@ -677,7 +682,7 @@ function controlCmd( control, event, xtell, ytell ) { } else if ( ytell == 2 ) { yge = 2*(50 - yge); } - locParms += "&yge="+yge; + locParms += '&yge='+yge; } } controlReq.send( controlParms+"&control="+control+locParms ); From ced36a533365912e260c25a3f32f235aa3c72320 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 11:08:23 -0500 Subject: [PATCH 23/70] remove debug and spacing --- web/includes/Event.php | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 340894379..f1ba99626 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -417,31 +417,27 @@ class Event extends ZM_Object { } } // end if capture file exists } // end if analyze file exists - } + } // end if frame or snapshot $captPath = $eventPath.'/'.$captImage; if ( ! file_exists($captPath) ) { Error("Capture file does not exist at $captPath"); } - //echo "CI:$captImage, CP:$captPath, TCP:$captPath
"; - $analImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyse.jpg', $frame['FrameId']); $analPath = $eventPath.'/'.$analImage; - //echo "AI:$analImage, AP:$analPath, TAP:$analPath
"; - $alarmFrame = $frame['Type']=='Alarm'; $hasAnalImage = $alarmFrame && file_exists($analPath) && filesize($analPath); $isAnalImage = $hasAnalImage && !$captureOnly; - if ( !ZM_WEB_SCALE_THUMBS || $scale >= SCALE_BASE || !function_exists('imagecreatefromjpeg') ) { + if ( !ZM_WEB_SCALE_THUMBS || ($scale >= SCALE_BASE) || !function_exists('imagecreatefromjpeg') ) { $imagePath = $thumbPath = $isAnalImage ? $analPath : $captPath; $imageFile = $imagePath; $thumbFile = $thumbPath; } else { - if ( version_compare( phpversion(), '4.3.10', '>=') ) + if ( version_compare(phpversion(), '4.3.10', '>=') ) $fraction = sprintf('%.3F', $scale/SCALE_BASE); else $fraction = sprintf('%.3f', $scale/SCALE_BASE); @@ -459,19 +455,19 @@ class Event extends ZM_Object { } $thumbFile = $thumbPath; - if ( $overwrite || ! file_exists( $thumbFile ) || ! filesize( $thumbFile ) ) { + if ( $overwrite || ! file_exists($thumbFile) || ! filesize($thumbFile) ) { // Get new dimensions - list( $imageWidth, $imageHeight ) = getimagesize( $imagePath ); + list( $imageWidth, $imageHeight ) = getimagesize($imagePath); $thumbWidth = $imageWidth * $fraction; $thumbHeight = $imageHeight * $fraction; // Resample - $thumbImage = imagecreatetruecolor( $thumbWidth, $thumbHeight ); - $image = imagecreatefromjpeg( $imagePath ); - imagecopyresampled( $thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight ); + $thumbImage = imagecreatetruecolor($thumbWidth, $thumbHeight); + $image = imagecreatefromjpeg($imagePath); + imagecopyresampled($thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight); - if ( !imagejpeg( $thumbImage, $thumbPath ) ) - Error( "Can't create thumbnail '$thumbPath'" ); + if ( !imagejpeg($thumbImage, $thumbPath) ) + Error("Can't create thumbnail '$thumbPath'"); } } # Create thumbnails @@ -555,7 +551,7 @@ class Event extends ZM_Object { $Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server(); if ( $Server->Id() != ZM_SERVER_ID ) { - $url = $Server->UrlToApi() . '/events/'.$this->{'Id'}.'.json'; + $url = $Server->UrlToApi().'/events/'.$this->{'Id'}.'.json'; if ( ZM_OPT_USE_AUTH ) { if ( ZM_AUTH_RELAY == 'hashed' ) { $url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS); From a6f5ae260129ca3f12cab1e6a10cae46be3f910d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 13:17:02 -0500 Subject: [PATCH 24/70] fix cyclePlay button not working. Move SetButtonState into skin.js --- web/skins/classic/js/skin.js | 13 +++++++++++++ web/skins/classic/views/js/event.js | 12 ------------ web/skins/classic/views/js/watch.js | 6 ------ 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 2c21c0503..9e9e80764 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -557,3 +557,16 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { autoScale = closest; return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale}; } + +function setButtonState(element, butClass) { + if ( element ) { + element.className = butClass; + if (butClass == 'unavail' || (butClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) { + element.disabled = true; + } else { + element.disabled = false; + } + } else { + console.log('Element was null in setButtonState'); + } +} diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index f7da1341a..58a700bfb 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -130,18 +130,6 @@ function renderAlarmCues(containerEl) { return alarmHtml; } -function setButtonState( element, butClass ) { - if ( element ) { - element.className = butClass; - if (butClass == 'unavail' || (butClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) { - element.disabled = true; - } else { - element.disabled = false; - } - } else { - console.log('Element was null in setButtonState'); - } -} function changeCodec() { location.replace(thisUrl + '?view=event&eid=' + eventData.Id + filterQuery + sortQuery+'&codec='+$j('#codec').val()); diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 0ad3a5536..7fd25d603 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -1,9 +1,3 @@ -function setButtonState(element, butClass) { - if ( element ) { - element.className = butClass; - element.disabled = (butClass != 'inactive'); - } -} function showEvents() { $('ptzControls').addClass( 'hidden' ); From 91b1d7bbeb8cd726a26dea8b0ea4f7e3e9cc38f0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Mar 2020 11:52:32 -0500 Subject: [PATCH 25/70] alter setButtonState to take either an id or an element so that we can log the missing element --- web/skins/classic/js/skin.js | 5 +- web/skins/classic/views/js/watch.js | 136 ++++++++++++++-------------- 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 9e9e80764..dd965a39f 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -558,7 +558,8 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) { return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale}; } -function setButtonState(element, butClass) { +function setButtonState(element_id, butClass) { + var element = $(element_id); if ( element ) { element.className = butClass; if (butClass == 'unavail' || (butClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) { @@ -567,6 +568,6 @@ function setButtonState(element, butClass) { element.disabled = false; } } else { - console.log('Element was null in setButtonState'); + console.log('Element was null or not found in setButtonState. id:'+element_id); } } diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 7fd25d603..d4ee2dc34 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -197,9 +197,9 @@ function getStreamCmdResponse(respObj, respText) { $('zoomValue').set('text', streamStatus.zoom); if ( streamStatus.zoom == '1.0' ) { - setButtonState($('zoomOutBtn'), 'unavail'); + setButtonState('zoomOutBtn', 'unavail'); } else { - setButtonState($('zoomOutBtn'), 'inactive'); + setButtonState('zoomOutBtn', 'inactive'); } if ( canEditMonitors ) { @@ -260,107 +260,107 @@ function getStreamCmdResponse(respObj, respText) { } function streamCmdPause( action ) { - setButtonState( $('pauseBtn'), 'active' ); - setButtonState( $('playBtn'), 'inactive' ); - setButtonState( $('stopBtn'), 'inactive' ); - setButtonState( $('fastFwdBtn'), 'inactive' ); - setButtonState( $('slowFwdBtn'), 'inactive' ); - setButtonState( $('slowRevBtn'), 'inactive' ); - setButtonState( $('fastRevBtn'), 'inactive' ); + setButtonState('pauseBtn', 'active'); + setButtonState('playBtn', 'inactive'); + setButtonState('stopBtn', 'inactive'); + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); if ( action ) { streamCmdReq.send( streamCmdParms+"&command="+CMD_PAUSE ); } } function streamCmdPlay( action ) { - setButtonState( $('pauseBtn'), 'inactive' ); - setButtonState( $('playBtn'), 'active' ); + setButtonState('pauseBtn', 'inactive'); + setButtonState('playBtn', 'active'); if ( streamStatus.delayed == true ) { - setButtonState( $('stopBtn'), 'inactive' ); - setButtonState( $('fastFwdBtn'), 'inactive' ); - setButtonState( $('slowFwdBtn'), 'inactive' ); - setButtonState( $('slowRevBtn'), 'inactive' ); - setButtonState( $('fastRevBtn'), 'inactive' ); + setButtonState('stopBtn', 'inactive'); + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); } else { - setButtonState( $('stopBtn'), 'unavail' ); - setButtonState( $('fastFwdBtn'), 'unavail' ); - setButtonState( $('slowFwdBtn'), 'unavail' ); - setButtonState( $('slowRevBtn'), 'unavail' ); - setButtonState( $('fastRevBtn'), 'unavail' ); + setButtonState('stopBtn', 'unavail'); + setButtonState('fastFwdBtn', 'unavail'); + setButtonState('slowFwdBtn', 'unavail'); + setButtonState('slowRevBtn', 'unavail'); + setButtonState('fastRevBtn', 'unavail'); } if ( action ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_PLAY ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_PLAY); } } function streamCmdStop( action ) { - setButtonState( $('pauseBtn'), 'inactive' ); - setButtonState( $('playBtn'), 'unavail' ); - setButtonState( $('stopBtn'), 'active' ); - setButtonState( $('fastFwdBtn'), 'unavail' ); - setButtonState( $('slowFwdBtn'), 'unavail' ); - setButtonState( $('slowRevBtn'), 'unavail' ); - setButtonState( $('fastRevBtn'), 'unavail' ); + setButtonState('pauseBtn', 'inactive'); + setButtonState('playBtn', 'unavail'); + setButtonState('stopBtn', 'active'); + setButtonState('fastFwdBtn', 'unavail'); + setButtonState('slowFwdBtn', 'unavail'); + setButtonState('slowRevBtn', 'unavail'); + setButtonState('fastRevBtn', 'unavail'); if ( action ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_STOP ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_STOP); } - setButtonState( $('stopBtn'), 'unavail' ); - setButtonState( $('playBtn'), 'active' ); + setButtonState('stopBtn', 'unavail'); + setButtonState('playBtn', 'active'); } function streamCmdFastFwd( action ) { - setButtonState( $('pauseBtn'), 'inactive' ); - setButtonState( $('playBtn'), 'inactive' ); - setButtonState( $('stopBtn'), 'inactive' ); - setButtonState( $('fastFwdBtn'), 'inactive' ); - setButtonState( $('slowFwdBtn'), 'inactive' ); - setButtonState( $('slowRevBtn'), 'inactive' ); - setButtonState( $('fastRevBtn'), 'inactive' ); + setButtonState('pauseBtn', 'inactive'); + setButtonState('playBtn', 'inactive'); + setButtonState('stopBtn', 'inactive'); + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); if ( action ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_FASTFWD ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_FASTFWD); } } function streamCmdSlowFwd( action ) { - setButtonState( $('pauseBtn'), 'inactive' ); - setButtonState( $('playBtn'), 'inactive' ); - setButtonState( $('stopBtn'), 'inactive' ); - setButtonState( $('fastFwdBtn'), 'inactive' ); - setButtonState( $('slowFwdBtn'), 'active' ); - setButtonState( $('slowRevBtn'), 'inactive' ); - setButtonState( $('fastRevBtn'), 'inactive' ); + setButtonState('pauseBtn', 'inactive'); + setButtonState('playBtn', 'inactive'); + setButtonState('stopBtn', 'inactive'); + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'active'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); if ( action ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_SLOWFWD ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_SLOWFWD); } - setButtonState( $('pauseBtn'), 'active' ); - setButtonState( $('slowFwdBtn'), 'inactive' ); + setButtonState('pauseBtn', 'active'); + setButtonState('slowFwdBtn', 'inactive'); } function streamCmdSlowRev( action ) { - setButtonState( $('pauseBtn'), 'inactive' ); - setButtonState( $('playBtn'), 'inactive' ); - setButtonState( $('stopBtn'), 'inactive' ); - setButtonState( $('fastFwdBtn'), 'inactive' ); - setButtonState( $('slowFwdBtn'), 'inactive' ); - setButtonState( $('slowRevBtn'), 'active' ); - setButtonState( $('fastRevBtn'), 'inactive' ); + setButtonState('pauseBtn', 'inactive'); + setButtonState('playBtn', 'inactive'); + setButtonState('stopBtn', 'inactive'); + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'active'); + setButtonState('fastRevBtn', 'inactive'); if ( action ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_SLOWREV ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_SLOWREV); } - setButtonState( $('pauseBtn'), 'active' ); - setButtonState( $('slowRevBtn'), 'inactive' ); + setButtonState('pauseBtn', 'active'); + setButtonState('slowRevBtn', 'inactive'); } function streamCmdFastRev( action ) { - setButtonState( $('pauseBtn'), 'inactive' ); - setButtonState( $('playBtn'), 'inactive' ); - setButtonState( $('stopBtn'), 'inactive' ); - setButtonState( $('fastFwdBtn'), 'inactive' ); - setButtonState( $('slowFwdBtn'), 'inactive' ); - setButtonState( $('slowRevBtn'), 'inactive' ); - setButtonState( $('fastRevBtn'), 'inactive' ); + setButtonState('pauseBtn', 'inactive'); + setButtonState('playBtn', 'inactive'); + setButtonState('stopBtn', 'inactive'); + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); if ( action ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_FASTREV ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_FASTREV); } } From 8d2ce341498f4504b79a9d43d78cbbd871fbd034 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Mar 2020 16:59:38 -0500 Subject: [PATCH 26/70] include id in monitors dropdown so that it is searchable --- web/skins/classic/views/_monitor_filters.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index a88c1d437..62a91d7f3 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -233,7 +233,7 @@ $html .= ' } } - $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name']; + $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Id'].' '.$monitors[$i]['Name']; if ( count($selected_monitor_ids) and ! in_array($monitors[$i]['Id'], $selected_monitor_ids) ) { continue; From b6c1a328a80e4cd6325299a6237c82ef3243c8d3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 12:42:41 -0400 Subject: [PATCH 27/70] Fix XSS from monitor Name, group Name, storage Name, server Name --- web/skins/classic/views/console.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index aa0484997..71c60b6f0 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -280,7 +280,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { ?> lens - ' : '>') . $monitor['Name'] ?>
+ ' : '>') . validHtmlStr($monitor['Name']) ?>
', @@ -290,7 +290,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $Groups = $Group->Parents(); array_push( $Groups, $Group ); } - return implode(' > ', array_map(function($Group){ return ''.$Group->Name().''; }, $Groups )); + return implode(' > ', array_map(function($Group){ return ''.validHtmlStr($Group->Name()).''; }, $Groups )); }, $Monitor->GroupIds() ) ); ?>
@@ -315,13 +315,13 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
- Name(); ?> + Name()); ?> '. makePopupLink( '?view=monitor&mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', ''.validHtmlStr($Monitor->Source()).'', canEdit('Monitors') ).''; if ( $show_storage_areas ) { ?> - Name(); } ?> + Name()); } ?> Date: Fri, 10 Apr 2020 11:05:12 -0400 Subject: [PATCH 28/70] defend against XSS in Monitor Name --- web/skins/classic/views/event.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 947bd3972..eb4f2ad1a 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -128,16 +128,16 @@ if ( ! $Event->Id() ) { ?>
Id() ?> - Id() . ' ' . $Monitor->Name() ?> + Id().' '.validHtmlStr($Monitor->Name()) ?> Cause()) ?> - StartTime() ) ) ?> + StartTime())) ?> Length().'s' ?> Frames() ?>/AlarmFrames() ?> TotScore() ?>/AvgScore() ?>/MaxScore() ?> DiskSpace(null)) . ' on ' . $Event->Storage()->Name(). - ( $Event->SecondaryStorageId() ? ', ' . $Event->SecondaryStorage()->Name() :'' ) + human_filesize($Event->DiskSpace(null)) . ' on ' . validHtmlStr($Event->Storage()->Name()). + ( $Event->SecondaryStorageId() ? ', '.validHtmlStr($Event->SecondaryStorage()->Name()) : '' ) ?>
From bab609426d4a24aa12695e48856c70d7bee78398 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Apr 2020 09:46:10 -0400 Subject: [PATCH 29/70] spacing in views/event.php --- web/skins/classic/views/event.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index eb4f2ad1a..6ed41b319 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -24,7 +24,7 @@ if ( !canView('Events') ) { } $eid = validInt($_REQUEST['eid']); -$fid = !empty($_REQUEST['fid'])?validInt($_REQUEST['fid']):1; +$fid = !empty($_REQUEST['fid']) ? validInt($_REQUEST['fid']) : 1; $Event = new ZM\Event($eid); if ( $user['MonitorIds'] ) { @@ -79,7 +79,7 @@ $replayModes = array( 'gapless' => translate('ReplayGapless'), ); -if ( isset( $_REQUEST['streamMode'] ) ) +if ( isset($_REQUEST['streamMode']) ) $streamMode = validHtmlStr($_REQUEST['streamMode']); else $streamMode = 'video'; @@ -104,7 +104,16 @@ if ( $Monitor->VideoWriter() == '2' ) { $Zoom = $Event->Height()/$Event->Width(); } -// These are here to figure out the next/prev event +// These are here to figure out the next/prev event, however if there is no filter, then default to one that specifies the Monitor +if ( !isset($_REQUEST['filter']) ) { + $_REQUEST['filter'] = array( + 'Query'=>array( + 'terms'=>array( + array('attr'=>'MonitorId', 'op'=>'=', 'val'=>$Event->MonitorId()) + ) + ) + ); +} parseSort(); parseFilter($_REQUEST['filter']); $filterQuery = $_REQUEST['filter']['query']; From b7fd4e26a5a636e36aa848540ee815dc51852dc3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:05:19 -0400 Subject: [PATCH 30/70] defend against XSS in Monitor Name --- web/skins/classic/views/groups.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/groups.php b/web/skins/classic/views/groups.php index 4ffe47f7d..9840d87f7 100644 --- a/web/skins/classic/views/groups.php +++ b/web/skins/classic/views/groups.php @@ -73,7 +73,7 @@ function group_line( $Group ) { } else { $html .= validHtmlStr($Group->Name()); } - $html .= ''. monitorIdsToNames($Group->MonitorIds(), 30).''; + $html .= ''. validHtmlStr(monitorIdsToNames($Group->MonitorIds(), 30)).''; if ( canEdit('Groups') ) { $html .= ''; } From 7347ef403044082847c307c80362892614516012 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 11:18:02 -0500 Subject: [PATCH 31/70] Handle a zero value for scale --- web/skins/classic/views/js/cycle.js | 38 ++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/web/skins/classic/views/js/cycle.js b/web/skins/classic/views/js/cycle.js index 4e6de5320..f9b1d19fc 100644 --- a/web/skins/classic/views/js/cycle.js +++ b/web/skins/classic/views/js/cycle.js @@ -46,7 +46,7 @@ function changeSize() { // Scale the frame monitor_frame = $j('#imageFeed'); if ( !monitor_frame ) { - console.log("Error finding frame"); + console.log('Error finding frame'); return; } if ( width ) { @@ -92,14 +92,20 @@ function changeScale() { // Scale the frame monitor_frame = $j('#imageFeed'); if ( !monitor_frame ) { - console.log("Error finding frame"); + console.log('Error finding frame'); return; } - if ( newWidth ) { - monitor_frame.css('width', newWidth+'px'); - } - if ( newHeight ) { - monitor_frame.css('height', newHeight+'px'); + + if ( scale != '0' ) { + if ( newWidth ) { + monitor_frame.css('width', newWidth+'px'); + } + if ( newHeight ) { + monitor_frame.css('height', newHeight+'px'); + } + } else { + monitor_frame.css('width', '100%'); + monitor_frame.css('height', 'auto'); } /*Stream could be an applet so can't use moo tools*/ var streamImg = $j('#liveStream'+monitorData[monIdx].id)[0]; @@ -110,12 +116,22 @@ function changeScale() { //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) )); src = src.replace(/scale=[\.\d]+/i, 'scale='+scale); - src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); - src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); + if ( scale != '0' ) { + src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); + src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); + } else { + src = src.replace(/width=[\.\d]+/i, 'width='+monitorData[monIdx].width); + src = src.replace(/height=[\.\d]+/i, 'height='+monitorData[monIdx].height); + } streamImg.src = src; } - streamImg.style.width = newWidth + 'px'; - streamImg.style.height = newHeight + 'px'; + if ( scale != '0' ) { + streamImg.style.width = newWidth+'px'; + streamImg.style.height = newHeight+'px'; + } else { + streamImg.style.width = '100%'; + streamImg.style.height = 'auto'; + } } else { console.log("Did not find liveStream"+monitorData[monIdx].id); } From 12252f1f377e28bb08b7f319ebd9fc22756332af Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:05:48 -0400 Subject: [PATCH 32/70] defend against XSS in Monitor Name --- web/skins/classic/views/js/event.js.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/js/event.js.php b/web/skins/classic/views/js/event.js.php index 3dae5abfe..7ba03b621 100644 --- a/web/skins/classic/views/js/event.js.php +++ b/web/skins/classic/views/js/event.js.php @@ -34,7 +34,7 @@ var eventData = { StartTime: 'StartTime() ?>', EndTime: 'EndTime() ?>', Frames: 'Frames() ?>', - MonitorName: 'Name() ?>' + MonitorName: 'Name()) ?>' }; var monitorUrl = 'Storage()->Server()->UrlToIndex(); ?>'; @@ -46,7 +46,7 @@ var rate = ''; // really only used when setting up initial pl var scale = ""; var LabelFormat = "LabelFormat())?>"; -var canEditEvents = ; +var canEditEvents = ; var streamTimeout = ; var canStreamNative = ; @@ -55,8 +55,8 @@ var streamMode = ''; // // Strings // -var deleteString = ""; -var causeString = ""; +var deleteString = ""; +var causeString = ""; var WEB_LIST_THUMB_WIDTH = ''; var WEB_LIST_THUMB_HEIGHT = ''; var popup = ''; From 6a9a8f1d5ff6b1bc94da969fd91635a77cdf49e2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 6 Apr 2020 11:59:27 -0400 Subject: [PATCH 33/70] check length of returned tr array to prevent errors in js log --- web/skins/classic/views/js/log.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js index 811fa5f28..f0aee7c00 100644 --- a/web/skins/classic/views/js/log.js +++ b/web/skins/classic/views/js/log.js @@ -175,7 +175,7 @@ function clearLog() { var clearReq = new Request.JSON({url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: clearResponse}); var tbody = $(logTable).getElement('tbody'); var rows = tbody.getElements('tr'); - if ( rows ) { + if ( rows && rows.length ) { var minTime = rows[0].getElement('td').get('text'); clearParms += "&minTime="+encodeURIComponent(minTime); var maxTime = rows[rows.length-1].getElement('td').get('text'); From 63aaf76f0d58105bcfe8eae1a16e63cfc4150110 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 12:13:05 -0500 Subject: [PATCH 34/70] handle a 0 value for scale as the scale to fit value --- web/skins/classic/views/js/montage.js | 31 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 68a2acf2c..b88833db0 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -334,7 +334,7 @@ function changeScale() { Cookie.write('zmMontageScale', scale, {duration: 10*365}); Cookie.write('zmMontageWidth', '', {duration: 10*365}); Cookie.write('zmMontageHeight', '', {duration: 10*365}); - if ( !scale ) { + if ( scale == '' ) { selectLayout('#zmMontageLayout'); return; } @@ -349,8 +349,12 @@ function changeScale() { console.log("Error finding frame for " + monitor.id); continue; } - if ( newWidth ) { - monitor_frame.css('width', newWidth); + if ( scale != '0' ) { + if ( newWidth ) { + monitor_frame.css('width', newWidth); + } + } else { + monitor_frame.css('width', '100%'); } // We don't set the frame height because it has the status bar as well //if ( height ) { @@ -364,13 +368,24 @@ function changeScale() { streamImg.src = ''; //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) )); - src = src.replace(/scale=[\.\d]+/i, 'scale='+scale); - src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); - src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); + if ( scale != '0' ) { + src = src.replace(/scale=[\.\d]+/i, 'scale='+scale); + src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); + src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); + } else { + src = src.replace(/scale=[\.\d]+/i, 'scale=100'); + src = src.replace(/width=[\.\d]+/i, 'width='+monitorData[i].width); + src = src.replace(/height=[\.\d]+/i, 'height='+monitorData[i].height); + } streamImg.src = src; } - streamImg.style.width = newWidth + "px"; - streamImg.style.height = newHeight + "px"; + if ( scale != '0' ) { + streamImg.style.width = newWidth + "px"; + streamImg.style.height = newHeight + "px"; + } else { + streamImg.style.width = '100%'; + streamImg.style.height = 'auto'; + } } } } From 8e2c76df61653b072ea2c6c8b820f8728b15a322 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 24 Mar 2020 16:16:32 -0400 Subject: [PATCH 35/70] minor code cleanup, adding monitor click event in a previous for loop instead of iterating again --- web/skins/classic/views/js/montagereview.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index 46f9b1ab2..9c7592ae3 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -967,6 +967,7 @@ function initPage() { imagedone(this, this.monId, false); }; loadImage2Monitor(monId, monitorImageURL[monId]); + monitorCanvasObj[monId].addEventListener('click', clickMonitor, false); } } // end foreach monitor @@ -982,15 +983,6 @@ function initPage() { ctx = canvas.getContext('2d'); drawGraph(); } - for ( i=0, len=monitorPtr.length; i < len; i += 1 ) { - var monitor_id = monitorPtr[i]; - monitor_canvas = $('Monitor'+monitor_id); - if ( ! monitor_canvas ) { - console.log("No canvas found for monitor " + monitor_id); - continue; - } - monitor_canvas.addEventListener('click', clickMonitor, false); - } setSpeed(speedIndex); //setFit(fitMode); // will redraw //setLive(liveMode); // will redraw From 93a37671c2c08c3636f39929c96ed690b2fede24 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 18:22:55 -0500 Subject: [PATCH 36/70] Merge branch 'release-1.34' --- web/skins/classic/views/js/video.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/skins/classic/views/js/video.js b/web/skins/classic/views/js/video.js index 0aea4482c..24c5474b1 100644 --- a/web/skins/classic/views/js/video.js +++ b/web/skins/classic/views/js/video.js @@ -23,7 +23,11 @@ function generateVideoResponse( respObj, respText ) { window.location.replace( thisUrl+'?view='+currentView+'&eid='+eventId+'&generated='+((respObj.result=='Ok')?1:0) ); } +<<<<<<< HEAD function generateVideo() { +======= +function generateVideo( ) { +>>>>>>> bf9ba39aa... Merge branch 'release-1.34' form = $j('#contentForm')[0]; var parms = 'view=request&request=event&action=video'; parms += '&'+$(form).toQueryString(); From 7d0421a02c97988fae63bf3bfb2b5d6c25576e12 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:06:39 -0400 Subject: [PATCH 37/70] defend against XSS in Monitor Name --- .../classic/views/js/montagereview.js.php | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php index d8850c06b..90ba28b2a 100644 --- a/web/skins/classic/views/js/montagereview.js.php +++ b/web/skins/classic/views/js/montagereview.js.php @@ -3,7 +3,7 @@ var server_utc_offset = getOffset($now); -echo $offset . '; // ' . floor($offset / 3600) . ' hours '; +echo $offset.'; // '.floor($offset / 3600).' hours '; ?> var currentScale=; @@ -182,18 +182,18 @@ foreach ( $monitors as $m ) { echo " monitorLoading[" . $m->Id() . "]=false;\n"; echo " monitorImageURL[" . $m->Id() . "]='".$m->getStreamSrc( array('mode'=>'single','scale'=>$defaultScale*100), '&' )."';\n"; echo " monitorLoadingStageURL[" . $m->Id() . "] = '';\n"; - echo " monitorColour[" . $m->Id() . "]=\"" . $m->WebColour() . "\";\n"; - echo " monitorWidth[" . $m->Id() . "]=" . $m->ViewWidth() . ";\n"; - echo " monitorHeight[" . $m->Id() . "]=" . $m->ViewHeight() . ";\n"; + echo " monitorColour[" . $m->Id() . "]=\"" . validHtmlStr($m->WebColour()) . "\";\n"; + echo " monitorWidth[" . $m->Id() . "]=" . validHtmlStr($m->ViewWidth()) . ";\n"; + echo " monitorHeight[" . $m->Id() . "]=" . validHtmlStr($m->ViewHeight()) . ";\n"; echo " monitorIndex[" . $m->Id() . "]=" . $numMonitors . ";\n"; echo " monitorServerId[" . $m->Id() . "]='" .($m->ServerId() ? $m->ServerId() : '0'). "';\n"; - echo " monitorName[" . $m->Id() . "]=\"" . $m->Name() . "\";\n"; + echo " monitorName[" . $m->Id() . "]=\"" . validHtmlStr($m->Name()) . "\";\n"; echo " monitorLoadStartTimems[" . $m->Id() . "]=0;\n"; echo " monitorLoadEndTimems[" . $m->Id() . "]=0;\n"; echo " monitorNormalizeScale[" . $m->Id() . "]=" . sqrt($avgArea / ($m->Width() * $m->Height() )) . ";\n"; $zoomScale=1.0; - if(isset($_REQUEST[ 'z' . $m->Id() ]) ) - $zoomScale = floatval( validHtmlStr($_REQUEST[ 'z' . $m->Id() ]) ); + if ( isset($_REQUEST['z'.$m->Id()]) ) + $zoomScale = floatval(validHtmlStr($_REQUEST['z'.$m->Id()])); echo " monitorZoomScale[" . $m->Id() . "]=" . $zoomScale . ";\n"; echo " monitorPtr[" . $numMonitors . "]=" . $m->Id() . ";\n"; $numMonitors += 1; @@ -205,14 +205,14 @@ var maxTimeSecs=parseInt($maxTimeSecs); var minTime='$minTime'; var maxTime='$maxTime'; "; -echo "var rangeTimeSecs=" . ( $maxTimeSecs - $minTimeSecs + 1) . ";\n"; -if(isset($defaultCurrentTime)) - echo "var currentTimeSecs=parseInt(" . strtotime($defaultCurrentTime) . ");\n"; +echo "var rangeTimeSecs=".($maxTimeSecs - $minTimeSecs + 1).";\n"; +if ( isset($defaultCurrentTime) ) + echo "var currentTimeSecs=parseInt(".strtotime($defaultCurrentTime).");\n"; else - echo "var currentTimeSecs=parseInt(" . ($minTimeSecs + $maxTimeSecs)/2 . ");\n"; + echo "var currentTimeSecs=parseInt(".($minTimeSecs + $maxTimeSecs)/2.");\n"; echo 'var speeds=['; -for ($i=0; $i0)?', ':'') . $speeds[$i]; echo "];\n"; ?> From d3f2dd4d6ab95d6d45c50ab5486cadf84fb90429 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:09:46 -0400 Subject: [PATCH 38/70] fix --- web/skins/classic/views/js/montagereview.js.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php index 90ba28b2a..8ff77f317 100644 --- a/web/skins/classic/views/js/montagereview.js.php +++ b/web/skins/classic/views/js/montagereview.js.php @@ -205,11 +205,11 @@ var maxTimeSecs=parseInt($maxTimeSecs); var minTime='$minTime'; var maxTime='$maxTime'; "; -echo "var rangeTimeSecs=".($maxTimeSecs - $minTimeSecs + 1).";\n"; +echo 'var rangeTimeSecs='.($maxTimeSecs - $minTimeSecs + 1).";\n"; if ( isset($defaultCurrentTime) ) - echo "var currentTimeSecs=parseInt(".strtotime($defaultCurrentTime).");\n"; + echo 'var currentTimeSecs=parseInt('.strtotime($defaultCurrentTime).");\n"; else - echo "var currentTimeSecs=parseInt(".($minTimeSecs + $maxTimeSecs)/2.");\n"; + echo 'var currentTimeSecs=parseInt('.(($minTimeSecs + $maxTimeSecs)/2).");\n"; echo 'var speeds=['; for ( $i=0; $i < count($speeds); $i++ ) From 9a3f699644ab5183f8eff1a1c9f51120e7a48d7c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 16:52:45 -0500 Subject: [PATCH 39/70] Use a little less ram by passing by reference --- web/skins/classic/views/js/montagereview.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php index 8ff77f317..4e3db5665 100644 --- a/web/skins/classic/views/js/montagereview.js.php +++ b/web/skins/classic/views/js/montagereview.js.php @@ -68,7 +68,7 @@ if ( !$liveMode ) { $frame['NextFrameId'] = $next_frames[$frame['EventId']]['Id']; } $event['FramesById'] += array($frame['Id']=>$frame); - $next_frames[$frame['EventId']] = $frame; + $next_frames[$frame['EventId']] = &$event['FramesById'][$frame['Id']]; } } // end if dbQuery From 91e78410a9469a8c397afb6ee9e483393362e936 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 16:53:08 -0500 Subject: [PATCH 40/70] Stop the montagereview update while we reload the page --- web/skins/classic/views/js/montagereview.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index 9c7592ae3..fe9ccd3cd 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -936,6 +936,10 @@ function changeDateTime(e) { } } + // Reloading can take a while, so stop interrupts to reduce load + clearInterval(timerObj); + timerObj = null; + var uri = "?view=" + currentView + fitStr + minStr + maxStr + liveStr + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value]; window.location = uri; } From 81d329af2f644d92caa1bd1dcb14bca9f95392fd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 29 Feb 2020 09:28:04 -0500 Subject: [PATCH 41/70] spacing, eslint --- web/skins/classic/views/js/video.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/web/skins/classic/views/js/video.js b/web/skins/classic/views/js/video.js index 0aea4482c..5f2df6ee3 100644 --- a/web/skins/classic/views/js/video.js +++ b/web/skins/classic/views/js/video.js @@ -1,11 +1,11 @@ -function deleteVideo( e ) { +function deleteVideo(e) { index = e.getAttribute('data-file-index'); - window.location.replace( thisUrl+'?view='+currentView+'&eid='+eventId+'&deleteIndex='+index ); + window.location.replace(thisUrl+'?view='+currentView+'&eid='+eventId+'&deleteIndex='+index); } -function downloadVideo( e ) { +function downloadVideo(e) { index = e.getAttribute('data-file-index'); - window.location.replace( thisUrl+'?view='+currentView+'&eid='+eventId+'&downloadIndex='+index ); + window.location.replace(thisUrl+'?view='+currentView+'&eid='+eventId+'&downloadIndex='+index); } var generateVideoTimer = null; @@ -13,25 +13,25 @@ var generateVideoTimer = null; function generateVideoProgress() { var tickerText = $('videoProgressTicker').get('text'); if ( tickerText.length < 1 || tickerText.length > 4 ) { - $('videoProgressTicker').set( 'text', '.' ); + $('videoProgressTicker').set('text', '.'); } else { - $('videoProgressTicker').appendText( '.' ); + $('videoProgressTicker').appendText('.'); } } function generateVideoResponse( respObj, respText ) { - window.location.replace( thisUrl+'?view='+currentView+'&eid='+eventId+'&generated='+((respObj.result=='Ok')?1:0) ); + window.location.replace(thisUrl+'?view='+currentView+'&eid='+eventId+'&generated='+((respObj.result=='Ok')?1:0)); } function generateVideo() { form = $j('#contentForm')[0]; var parms = 'view=request&request=event&action=video'; parms += '&'+$(form).toQueryString(); - var query = new Request.JSON( {url: thisUrl, method: 'post', data: parms, onSuccess: generateVideoResponse} ); + var query = new Request.JSON({url: thisUrl, method: 'post', data: parms, onSuccess: generateVideoResponse}); query.send(); - $('videoProgress').removeClass( 'hidden' ); - $('videoProgress').setProperty( 'class', 'warnText' ); - $('videoProgressText').set( 'text', videoGenProgressString ); + $('videoProgress').removeClass('hidden'); + $('videoProgress').setProperty('class', 'warnText'); + $('videoProgressText').set('text', videoGenProgressString); generateVideoProgress(); - generateVideoTimer = generateVideoProgress.periodical( 500 ); + generateVideoTimer = generateVideoProgress.periodical(500); } From 908e892d4890f5b61f77b2c7573d9f76ef39d19d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Mar 2020 11:22:08 -0500 Subject: [PATCH 42/70] Merge branch 'fix_auth_timeouts' --- web/skins/classic/views/js/watch.js | 155 ++++++++++++++-------------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index d4ee2dc34..7d4ba5e4b 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -1,33 +1,33 @@ function showEvents() { - $('ptzControls').addClass( 'hidden' ); - $('events').removeClass( 'hidden' ); + $('ptzControls').addClass('hidden'); + $('events').removeClass('hidden'); if ( $('eventsControl') ) { $('eventsControl').addClass('hidden'); } if ( $('controlControl') ) { $('controlControl').removeClass('hidden'); } - showMode = "events"; + showMode = 'events'; } function showPtzControls() { - $('events').addClass( 'hidden' ); - $('ptzControls').removeClass( 'hidden' ); + $('events').addClass('hidden'); + $('ptzControls').removeClass('hidden'); if ( $('eventsControl') ) { $('eventsControl').removeClass('hidden'); } if ( $('controlControl') ) { $('controlControl').addClass('hidden'); } - showMode = "control"; + showMode = 'control'; } function changeScale() { var scale = $('scale').get('value'); var newWidth; var newHeight; - if (scale == "auto") { + if ( scale == '0' || scale == 'auto' ) { var newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus')); newWidth = newSize.width; newHeight = newSize.height; @@ -81,7 +81,7 @@ function setAlarmState( currentAlarmState ) { if ( SOUND_ON_ALARM ) { // Enable the alarm sound if ( !canPlayPauseAudio ) { - $('alarmSound').removeClass( 'hidden' ); + $('alarmSound').removeClass('hidden'); } else { $('MediaPlayer').Play(); } @@ -90,22 +90,20 @@ function setAlarmState( currentAlarmState ) { window.focus(); } } - if ( SOUND_ON_ALARM ) { - if ( oldAlarm ) { + if ( oldAlarm ) { // done with an event do a refresh + if ( SOUND_ON_ALARM ) { // Disable alarm sound if ( !canPlayPauseAudio ) { - $('alarmSound').addClass( 'hidden' ); + $('alarmSound').addClass('hidden'); } else { $('MediaPlayer').Stop(); } } - } - if (oldAlarm) { // done with an event do a refresh eventCmdQuery(); } lastAlarmState = alarmState; -} +} // end function setAlarmState( currentAlarmState ) if ( monitorType != 'WebSite' ) { var streamCmdParms = 'view=request&request=stream&connkey='+connKey; @@ -149,11 +147,11 @@ function getStreamCmdResponse(respObj, respText) { $('levelValue').set('text', streamStatus.level); if ( streamStatus.level > 95 ) { - $('levelValue').className = "alarm"; + $('levelValue').className = 'alarm'; } else if ( streamStatus.level > 80 ) { - $('levelValue').className = "alert"; + $('levelValue').className = 'alert'; } else { - $('levelValue').className = "ok"; + $('levelValue').className = 'ok'; } var delayString = secsToTime(streamStatus.delay); @@ -188,7 +186,7 @@ function getStreamCmdResponse(respObj, respText) { } } // rate } else { - $('modeValue').set( 'text', "Live" ); + $('modeValue').set( 'text', 'Live' ); $('rate').addClass( 'hidden' ); $('delay').addClass( 'hidden' ); $('level').addClass( 'hidden' ); @@ -224,7 +222,6 @@ function getStreamCmdResponse(respObj, respText) { if ( streamStatus.auth ) { auth_hash = streamStatus.auth; - console.log("Have a new auth hash" + streamStatus.auth); // Try to reload the image stream. var streamImg = $('liveStream'); if ( streamImg ) { @@ -237,7 +234,7 @@ function getStreamCmdResponse(respObj, respText) { } // end if have a new auth hash } // end if respObj.status } else { - checkStreamForErrors("getStreamCmdResponse", respObj);//log them + checkStreamForErrors('getStreamCmdResponse', respObj);//log them // Try to reload the image stream. // If it's an auth error, we should reload the whole page. window.location.reload(); @@ -245,9 +242,9 @@ function getStreamCmdResponse(respObj, respText) { var streamImg = $('liveStream'+monitorId); if ( streamImg ) { streamImg.src = streamImg.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); - console.log("Changing livestream src to " + streamImg.src); + console.log('Changing livestream src to ' + streamImg.src); } else { - console.log("Unable to find streamImg liveStream"); + console.log('Unable to find streamImg liveStream'); } } } @@ -256,7 +253,7 @@ function getStreamCmdResponse(respObj, respText) { if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { streamCmdTimeout = streamCmdTimeout/5; } - streamCmdTimer = streamCmdQuery.delay( streamCmdTimeout ); + streamCmdTimer = streamCmdQuery.delay(streamCmdTimeout); } function streamCmdPause( action ) { @@ -268,7 +265,7 @@ function streamCmdPause( action ) { setButtonState('slowRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive'); if ( action ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_PAUSE ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_PAUSE); } } @@ -365,23 +362,23 @@ function streamCmdFastRev( action ) { } function streamCmdZoomIn( x, y ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_ZOOMIN+"&x="+x+"&y="+y ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_ZOOMIN+"&x="+x+"&y="+y); } function streamCmdZoomOut() { - streamCmdReq.send( streamCmdParms+"&command="+CMD_ZOOMOUT ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_ZOOMOUT); } function streamCmdScale( scale ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_SCALE+"&scale="+scale ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_SCALE+"&scale="+scale); } function streamCmdPan( x, y ) { - streamCmdReq.send( streamCmdParms+"&command="+CMD_PAN+"&x="+x+"&y="+y ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_PAN+"&x="+x+"&y="+y); } function streamCmdQuery() { - streamCmdReq.send( streamCmdParms+"&command="+CMD_QUERY ); + streamCmdReq.send(streamCmdParms+"&command="+CMD_QUERY); } if ( monitorType != 'WebSite' ) { @@ -389,12 +386,18 @@ if ( monitorType != 'WebSite' ) { if ( auth_hash ) { statusCmdParms += '&auth='+auth_hash; } - var statusCmdReq = new Request.JSON( {url: monitorUrl, method: 'get', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse} ); + var statusCmdReq = new Request.JSON( { + url: monitorUrl, + method: 'get', + timeout: AJAX_TIMEOUT, + link: 'cancel', + onSuccess: getStatusCmdResponse + } ); var statusCmdTimer = null; } function getStatusCmdResponse(respObj, respText) { - watchdogOk("status"); + watchdogOk('status'); if ( statusCmdTimer ) { statusCmdTimer = clearTimeout(statusCmdTimer); } @@ -403,22 +406,22 @@ function getStatusCmdResponse(respObj, respText) { $('fpsValue').set('text', respObj.monitor.FrameRate); setAlarmState(respObj.monitor.Status); } else { - checkStreamForErrors("getStatusCmdResponse", respObj); + checkStreamForErrors('getStatusCmdResponse', respObj); } var statusCmdTimeout = statusRefreshTimeout; if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { statusCmdTimeout = statusCmdTimeout/5; } - statusCmdTimer = statusCmdQuery.delay( statusCmdTimeout ); + statusCmdTimer = statusCmdQuery.delay(statusCmdTimeout); } function statusCmdQuery() { - statusCmdReq.send(); + statusCmdReq.send(statusCmdParms); } if ( monitorType != 'WebSite' ) { - var alarmCmdParms = "view=request&request=alarm&id="+monitorId; + var alarmCmdParms = 'view=request&request=alarm&id='+monitorId; if ( auth_hash ) { alarmCmdParms += '&auth='+auth_hash; } @@ -433,8 +436,8 @@ if ( monitorType != 'WebSite' ) { var alarmCmdFirst = true; } -function getAlarmCmdResponse( respObj, respText ) { - checkStreamForErrors("getAlarmCmdResponse", respObj); +function getAlarmCmdResponse(respObj, respText) { + checkStreamForErrors('getAlarmCmdResponse', respObj); } function cmdDisableAlarms() { @@ -447,14 +450,14 @@ function cmdEnableAlarms() { function cmdForceAlarm() { alarmCmdReq.send(alarmCmdParms+"&command=forceAlarm"); - if (window.event) { + if ( window.event ) { window.event.preventDefault(); } } function cmdCancelForcedAlarm() { alarmCmdReq.send(alarmCmdParms+"&command=cancelForcedAlarm"); - if (window.event) { + if ( window.event ) { window.event.preventDefault(); } return false; @@ -470,8 +473,8 @@ function getActResponse( respObj, respText ) { eventCmdQuery(); } -function deleteEvent( event, eventId ) { - var actParms = "view=request&request=event&action=delete&id="+eventId; +function deleteEvent(event, eventId) { + var actParms = 'view=request&request=event&action=delete&id='+eventId; if ( auth_hash ) { actParms += '&auth='+auth_hash; } @@ -479,10 +482,9 @@ function deleteEvent( event, eventId ) { url: thisUrl, method: 'post', timeout: 3000, - data: actParms, onSuccess: getActResponse } ); - actReq.send(); + actReq.send(actParms); event.stop(); } @@ -495,7 +497,6 @@ if ( monitorType != 'WebSite' ) { url: monitorUrl, method: 'get', timeout: AJAX_TIMEOUT, - data: eventCmdParms, link: 'cancel', onSuccess: getEventCmdResponse, onTimeout: eventCmdQuery @@ -509,19 +510,19 @@ function highlightRow( row ) { } function getEventCmdResponse( respObj, respText ) { - watchdogOk("event"); + watchdogOk('event'); if ( eventCmdTimer ) { - eventCmdTimer = clearTimeout( eventCmdTimer ); + eventCmdTimer = clearTimeout(eventCmdTimer); } if ( respObj.result == 'Ok' ) { var dbEvents = respObj.events.reverse(); var eventList = $('eventList'); - var eventListBody = $(eventList).getElement( 'tbody' ); - var eventListRows = $(eventListBody).getElements( 'tr' ); + var eventListBody = $(eventList).getElement('tbody'); + var eventListRows = $(eventListBody).getElements('tr'); - eventListRows.each( function( row ) { - row.removeClass( 'updated' ); + eventListRows.each( function(row) { + row.removeClass('updated'); } ); for ( var i = 0; i < dbEvents.length; i++ ) { @@ -575,30 +576,30 @@ function getEventCmdResponse( respObj, respText ) { 'mouseout': highlightRow.pass(row) } }); - link.set( 'text', 'X' ); - link.inject( row.getElement( 'td.colDelete' ) ); + link.set('text', 'X'); + link.inject(row.getElement('td.colDelete')); if ( i == 0 ) { - row.inject( $(eventListBody) ); + row.inject($(eventListBody)); } else { - row.inject( $(eventListBody), 'top' ); + row.inject($(eventListBody), 'top'); if ( !eventCmdFirst ) { - row.addClass( 'recent' ); + row.addClass('recent'); } } } else { - row.getElement( 'td.colName a' ).set( 'text', event.Name ); - row.getElement( 'td.colSecs' ).set( 'text', event.Length ); - row.getElement( 'td.colFrames a' ).set( 'text', event.Frames+'/'+event.AlarmFrames ); - row.getElement( 'td.colScore a' ).set( 'text', event.AvgScore+'/'+event.MaxScore ); - row.removeClass( 'recent' ); + row.getElement('td.colName a').set('text', event.Name); + row.getElement('td.colSecs').set('text', event.Length); + row.getElement('td.colFrames a').set('text', event.Frames+'/'+event.AlarmFrames); + row.getElement('td.colScore a').set('text', event.AvgScore+'/'+event.MaxScore); + row.removeClass('recent'); } - row.addClass( 'updated' ); + row.addClass('updated'); } - var rows = $(eventListBody).getElements( 'tr' ); + var rows = $(eventListBody).getElements('tr'); for ( var i = 0; i < rows.length; i++ ) { - if ( !rows[i].hasClass( 'updated' ) ) { + if ( !rows[i].hasClass('updated') ) { rows[i].destroy(); rows.splice( i, 1 ); i--; @@ -609,39 +610,39 @@ function getEventCmdResponse( respObj, respText ) { rows.length--; } } else { - checkStreamForErrors("getEventCmdResponse", respObj); + checkStreamForErrors('getEventCmdResponse', respObj); } var eventCmdTimeout = eventsRefreshTimeout; if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { eventCmdTimeout = eventCmdTimeout/5; } - eventCmdTimer = eventCmdQuery.delay( eventCmdTimeout ); + eventCmdTimer = eventCmdQuery.delay(eventCmdTimeout); eventCmdFirst = false; } function eventCmdQuery() { if ( eventCmdTimer ) { // avoid firing another if we are firing one - eventCmdTimer = clearTimeout( eventCmdTimer ); + eventCmdTimer = clearTimeout(eventCmdTimer); } eventCmdReq.send(); } if ( monitorType != 'WebSite' ) { - var controlParms = "view=request&request=control&id="+monitorId; + var controlParms = 'view=request&request=control&id='+monitorId; if ( auth_hash ) { controlParms += '&auth='+auth_hash; } var controlReq = new Request.JSON( {url: monitorUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getControlResponse} ); } -function getControlResponse( respObj, respText ) { +function getControlResponse(respObj, respText) { if ( !respObj ) { return; } //console.log( respText ); if ( respObj.result != 'Ok' ) { - alert( "Control response was status = "+respObj.status+"\nmessage = "+respObj.message ); + alert("Control response was status = "+respObj.status+"\nmessage = "+respObj.message); } } @@ -679,19 +680,19 @@ function controlCmd(button) { locParms += '&yge='+yge; } } - controlReq.send( controlParms+"&control="+control+locParms ); - if ( streamMode == "single" ) { - fetchImage.pass( $('imageFeed').getElement('img') ).delay( 1000 ); + controlReq.send(controlParms+"&control="+control+locParms); + if ( streamMode == 'single' ) { + fetchImage.pass($('imageFeed').getElement('img')).delay(1000); } } function controlCmdImage( x, y ) { var imageControlParms = controlParms; - imageControlParms += "&scale="+scale; - imageControlParms += "&control="+imageControlMode; + imageControlParms += '&scale='+scale; + imageControlParms += '&control='+imageControlMode; controlReq.send( imageControlParms+"&x="+x+"&y="+y ); - if ( streamMode == "single" ) { + if ( streamMode == 'single' ) { fetchImage.pass( $('imageFeed').getElement('img') ).delay( 1000 ); } } @@ -705,7 +706,7 @@ function handleClick( event ) { var x = event.page.x - $(target).getLeft(); var y = event.page.y - $(target).getTop(); - if ( showMode == "events" || !imageControlMode ) { + if ( showMode == 'events' || !imageControlMode ) { if ( event.shift ) { streamCmdPan( x, y ); } else if ( event.event.ctrlKey ) { @@ -802,7 +803,7 @@ function initPage() { if ( refreshApplet && appletRefreshTime ) { appletRefresh.delay(appletRefreshTime*1000); } - if ( scale == "auto" ) changeScale(); + if ( scale == 'auto' ) changeScale(); if ( window.history.length == 1 ) { $j('#closeControl').html(''); } From da79f761ad619702d355dcf116d87700e05ad45f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Mar 2020 12:43:07 -0500 Subject: [PATCH 43/70] add monitorStreamReplayBuffer to javascript vars. Use it to determine whether to update fast forward and reverse buttons --- web/skins/classic/views/js/watch.js | 88 +++++++++++++++---------- web/skins/classic/views/js/watch.js.php | 8 +-- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 7d4ba5e4b..3ecf6f5d6 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -260,10 +260,12 @@ function streamCmdPause( action ) { setButtonState('pauseBtn', 'active'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); - setButtonState('fastFwdBtn', 'inactive'); - setButtonState('slowFwdBtn', 'inactive'); - setButtonState('slowRevBtn', 'inactive'); - setButtonState('fastRevBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); + } if ( action ) { streamCmdReq.send(streamCmdParms+"&command="+CMD_PAUSE); } @@ -274,16 +276,20 @@ function streamCmdPlay( action ) { setButtonState('playBtn', 'active'); if ( streamStatus.delayed == true ) { setButtonState('stopBtn', 'inactive'); - setButtonState('fastFwdBtn', 'inactive'); - setButtonState('slowFwdBtn', 'inactive'); - setButtonState('slowRevBtn', 'inactive'); - setButtonState('fastRevBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); + } } else { setButtonState('stopBtn', 'unavail'); - setButtonState('fastFwdBtn', 'unavail'); - setButtonState('slowFwdBtn', 'unavail'); - setButtonState('slowRevBtn', 'unavail'); - setButtonState('fastRevBtn', 'unavail'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'unavail'); + setButtonState('slowFwdBtn', 'unavail'); + setButtonState('slowRevBtn', 'unavail'); + setButtonState('fastRevBtn', 'unavail'); + } } if ( action ) { streamCmdReq.send(streamCmdParms+"&command="+CMD_PLAY); @@ -294,10 +300,12 @@ function streamCmdStop( action ) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'unavail'); setButtonState('stopBtn', 'active'); - setButtonState('fastFwdBtn', 'unavail'); - setButtonState('slowFwdBtn', 'unavail'); - setButtonState('slowRevBtn', 'unavail'); - setButtonState('fastRevBtn', 'unavail'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'unavail'); + setButtonState('slowFwdBtn', 'unavail'); + setButtonState('slowRevBtn', 'unavail'); + setButtonState('fastRevBtn', 'unavail'); + } if ( action ) { streamCmdReq.send(streamCmdParms+"&command="+CMD_STOP); } @@ -309,10 +317,12 @@ function streamCmdFastFwd( action ) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); - setButtonState('fastFwdBtn', 'inactive'); - setButtonState('slowFwdBtn', 'inactive'); - setButtonState('slowRevBtn', 'inactive'); - setButtonState('fastRevBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); + } if ( action ) { streamCmdReq.send(streamCmdParms+"&command="+CMD_FASTFWD); } @@ -322,40 +332,50 @@ function streamCmdSlowFwd( action ) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); - setButtonState('fastFwdBtn', 'inactive'); - setButtonState('slowFwdBtn', 'active'); - setButtonState('slowRevBtn', 'inactive'); - setButtonState('fastRevBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'active'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); + } if ( action ) { streamCmdReq.send(streamCmdParms+"&command="+CMD_SLOWFWD); } setButtonState('pauseBtn', 'active'); - setButtonState('slowFwdBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('slowFwdBtn', 'inactive'); + } } function streamCmdSlowRev( action ) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); - setButtonState('fastFwdBtn', 'inactive'); - setButtonState('slowFwdBtn', 'inactive'); - setButtonState('slowRevBtn', 'active'); - setButtonState('fastRevBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'active'); + setButtonState('fastRevBtn', 'inactive'); + } if ( action ) { streamCmdReq.send(streamCmdParms+"&command="+CMD_SLOWREV); } setButtonState('pauseBtn', 'active'); - setButtonState('slowRevBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('slowRevBtn', 'inactive'); + } } function streamCmdFastRev( action ) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); - setButtonState('fastFwdBtn', 'inactive'); - setButtonState('slowFwdBtn', 'inactive'); - setButtonState('slowRevBtn', 'inactive'); - setButtonState('fastRevBtn', 'inactive'); + if ( monitorStreamReplayBuffer ) { + setButtonState('fastFwdBtn', 'inactive'); + setButtonState('slowFwdBtn', 'inactive'); + setButtonState('slowRevBtn', 'inactive'); + setButtonState('fastRevBtn', 'inactive'); + } if ( action ) { streamCmdReq.send(streamCmdParms+"&command="+CMD_FASTREV); } diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index 5e3e3a718..3140c65bc 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -44,13 +44,13 @@ var showMode = "'; var maxDisplayEvents = ; - var monitorId = Id() ?>; var monitorWidth = ViewWidth() ?>; var monitorHeight = ViewHeight() ?>; -var monitorUrl = 'UrlToIndex(); ?>'; -var monitorType = 'Type() ) ?>'; -var monitorRefresh = 'Refresh() ) ?>'; +var monitorUrl = 'UrlToIndex() ?>'; +var monitorType = 'Type() ?>'; +var monitorRefresh = 'Refresh() ?>'; +var monitorStreamReplayBuffer = StreamReplayBuffer() ?>; var scale = ''; From 25cd13f8ad2dc5443dedc7ea114add196d523c07 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Mar 2020 14:38:36 -0500 Subject: [PATCH 44/70] When sending eventCmdReq, pass eventCmdParms since it might have been updated. --- web/skins/classic/views/js/event.js | 10 ++++------ web/skins/classic/views/js/watch.js | 11 ++++++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index f786c52c4..d8b6d5c3c 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -151,7 +151,7 @@ function changeScale() { } else { eventViewer = $j(vid ? '#videoobj' : '#evtStream'); } - if ( scale == 'auto' ) { + if ( scale == '0' || scale == 'auto' ) { var newSize = scaleToFit(eventData.Width, eventData.Height, eventViewer, bottomEl); newWidth = newSize.width; newHeight = newSize.height; @@ -163,10 +163,10 @@ function changeScale() { } if ( !(streamMode == 'stills') ) { eventViewer.width(newWidth); - } //stills handles its own width + } // stills handles its own width eventViewer.height(newHeight); if ( !vid ) { // zms needs extra sizing - streamScale(scale == "auto" ? autoScale : scale); + streamScale((scale == '0' || scale == 'auto' ) ? autoScale : scale); drawProgressBar(); } if ( streamMode == 'stills' ) { @@ -175,7 +175,7 @@ function changeScale() { } else { alarmCue.html(renderAlarmCues(eventViewer));//just re-render alarmCues. skip ajax call } - if ( scale == "auto" ) { + if ( scale = '0' || scale == 'auto' ) { Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365}); } else { Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365}); @@ -209,7 +209,6 @@ function changeRate() { } }, 500); //500ms is a compromise between smooth reverse and realistic performance } // end if vid - } else { // Forward rate if ( vid ) { vid.playbackRate(rate/100); @@ -310,7 +309,6 @@ function pauseClicked() { } function streamPause( ) { - $j('#modeValue').html('Paused'); setButtonState( $('pauseBtn'), 'active' ); setButtonState( $('playBtn'), 'inactive' ); diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 3ecf6f5d6..e8977ddd6 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -645,7 +645,7 @@ function eventCmdQuery() { if ( eventCmdTimer ) { // avoid firing another if we are firing one eventCmdTimer = clearTimeout(eventCmdTimer); } - eventCmdReq.send(); + eventCmdReq.send(eventCmdParms); } if ( monitorType != 'WebSite' ) { @@ -653,7 +653,13 @@ if ( monitorType != 'WebSite' ) { if ( auth_hash ) { controlParms += '&auth='+auth_hash; } - var controlReq = new Request.JSON( {url: monitorUrl, 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) { @@ -667,7 +673,6 @@ function getControlResponse(respObj, respText) { } function controlCmd(button) { - control = button.getAttribute('value'); xtell = button.getAttribute('xtell'); ytell = button.getAttribute('ytell'); From 8ef70f9080dfc120ce5bd4dc1c1455a34683f69c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Apr 2020 11:06:20 -0400 Subject: [PATCH 45/70] defend against XSS in Monitor Name --- web/skins/classic/views/js/filter.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index 5144c4734..5b01d150f 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -141,6 +141,11 @@ function deleteFilter( element ) { form.submit(); } } +var escape = document.createElement('textarea'); +function escapeHTML(html) { + escape.textContent = html; + return escape.innerHTML; +} function parseRows(rows) { for ( var rowNum = 0; rowNum < rows.length; rowNum++ ) { //Each row is a term @@ -221,8 +226,8 @@ function parseRows(rows) { inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"}); } else if ( attr == 'MonitorName' ) { //Monitor names var monitorSelect = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); - for (var key in monitors) { - monitorSelect.append(''); + for ( var monitor_id in monitors ) { + monitorSelect.append(''); } var monitorVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(monitorSelect).children().val(monitorVal); From 010b230804c62418a42e6219662140b26c786d03 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 11:14:12 -0500 Subject: [PATCH 46/70] Fix value of auto in width dropdown. Allow a 0 value for scale. --- web/skins/classic/views/cycle.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/cycle.php b/web/skins/classic/views/cycle.php index b7281a719..6795e16a2 100644 --- a/web/skins/classic/views/cycle.php +++ b/web/skins/classic/views/cycle.php @@ -40,7 +40,7 @@ if ( empty($_REQUEST['mode']) ) { } $widths = array( - '' => translate('auto'), + 'auto' => translate('auto'), '100%' => '100%', '160px' => '160px', '320px' => '320px', @@ -62,13 +62,11 @@ session_start(); if ( isset($_REQUEST['scale']) ) { $options['scale'] = validInt($_REQUEST['scale']); - ZM\Logger::Debug('Setting scale from request to '.$options['scale']); } else if ( isset($_COOKIE['zmCycleScale']) ) { $options['scale'] = $_COOKIE['zmCycleScale']; - ZM\Logger::Debug('Setting scale from cookie to '.$options['scale']); } -if ( !(isset($options['scale']) and $options['scale']) ) +if ( !isset($options['scale']) ) $options['scale'] = 100; if ( isset($_COOKIE['zmCycleWidth']) and $_COOKIE['zmCycleWidth'] ) { From 550345887495be52c4a7bd78c12d013a5afb1446 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Mar 2020 18:34:43 -0400 Subject: [PATCH 47/70] correct label_size array and add translations --- web/skins/classic/views/monitor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index a78c6f615..303e335ee 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -367,8 +367,8 @@ $fastblendopts_alarm = array( ); $label_size = array( - 'Default' => 1, - 'Large' => 2 + 1 => translate('Default'), + 2 => translate('Large'), ); $codecs = array( From bf99daf49431c9c5eb12a4224192e57d31bda8fd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 10 Mar 2020 18:47:19 -0400 Subject: [PATCH 48/70] Merge branch 'rate_dropdown' --- web/skins/classic/views/js/event.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index d8b6d5c3c..69b34d055 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -309,6 +309,7 @@ function pauseClicked() { } function streamPause( ) { + $j('#modeValue').html('Paused'); setButtonState( $('pauseBtn'), 'active' ); setButtonState( $('playBtn'), 'inactive' ); @@ -1106,7 +1107,7 @@ function initPage() { } nearEventsQuery(eventData.Id); initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues - if ( scale == 'auto' ) changeScale(); + if ( scale == '0' || scale == 'auto' ) changeScale(); document.querySelectorAll('select[name="rate"]').forEach(function(el) { el.onchange = window['changeRate']; }); From 56a43741c53822e780768f1b024edab1d96b10b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 25 Feb 2020 11:17:46 -0500 Subject: [PATCH 49/70] Handle a zero value for scale --- web/skins/classic/views/event.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 51dfcf640..f8bceb837 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -48,7 +48,7 @@ if ( isset($_REQUEST['scale']) ) { $scale = validInt($_REQUEST['scale']); } else if ( isset($_COOKIE['zmEventScaleAuto']) ) { // If we're using scale to fit use it on all monitors - $scale = 'auto'; + $scale = '0'; } else if ( isset($_COOKIE['zmEventScale'.$Event->MonitorId()]) ) { $scale = $_COOKIE['zmEventScale'.$Event->MonitorId()]; } else { @@ -85,9 +85,9 @@ else $streamMode = 'video'; $replayMode = ''; -if ( isset( $_REQUEST['replayMode'] ) ) +if ( isset($_REQUEST['replayMode']) ) $replayMode = validHtmlStr($_REQUEST['replayMode']); -if ( isset( $_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) ) +if ( isset($_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) ) $replayMode = validHtmlStr($_COOKIE['replayMode']); if ( ( ! $replayMode ) or ( ! $replayModes[$replayMode] ) ) { @@ -131,7 +131,7 @@ xhtmlHeaders(__FILE__, translate('Event'));