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

This commit is contained in:
Isaac Connor 2020-06-25 16:07:22 -04:00
commit b060e0835c
29 changed files with 753 additions and 391 deletions

View File

@ -282,6 +282,7 @@ DROP TABLE IF EXISTS `Filters`;
CREATE TABLE `Filters` (
`Id` int(10) unsigned NOT NULL auto_increment,
`Name` varchar(64) NOT NULL default '',
`UserId` int(10) unsigned,
`Query_json` text NOT NULL,
`AutoArchive` tinyint(3) unsigned NOT NULL default '0',
`AutoVideo` tinyint(3) unsigned NOT NULL default '0',
@ -787,6 +788,7 @@ INSERT INTO `Filters`
`AutoCopy`,
`AutoCopyTo`,
`UpdateDiskSpace`,
`UserId`,
`Background`,
`Concurrent`
)
@ -807,6 +809,7 @@ INSERT INTO `Filters`
0/*AutoMove*/,0/*MoveTo*/,
0/*AutoCopy*/,0/*CopyTo*/,
0/*UpdateDiskSpace*/,
1/*UserId = admin*/,
1/*Background*/,
0/*Concurrent*/
);
@ -830,6 +833,7 @@ INSERT INTO `Filters`
`AutoCopy`,
`AutoCopyTo`,
`UpdateDiskSpace`,
`UserId`,
`Background`,
`Concurrent`
)
@ -849,6 +853,7 @@ VALUES (
0/*AutoMove*/,0/*MoveTo*/,
0/*AutoCopy*/,0/*CopyTo*/,
1/*UpdateDiskSpace*/,
1/*UserId=admin*/,
1/*Background*/,
0/*Concurrent*/
);

11
db/zm_update-1.35.5.sql Normal file
View File

@ -0,0 +1,11 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'UserId'
) > 0,
"SELECT 'Column UserId already exists in Filters'",
"ALTER TABLE `Filters` ADD `UserId` int(10) unsigned AFTER `Name`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -28,7 +28,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.35.4
Version: 1.35.5
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons

View File

@ -83,7 +83,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,libssl | libssl1.0.0 | libssl1.1
,libcrypt-eksblowfish-perl
,libdata-entropy-perl
,libvncclient1
,libvncclient1|libvncclient0
Recommends: ${misc:Recommends}
,libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm
,mysql-server | mariadb-server | virtual-mysql-server

View File

@ -352,6 +352,11 @@ sub GenerateVideo {
sub delete {
my $event = $_[0];
if ( !$event->canEdit() ) {
Warning('No permission to delete event.');
return 'No permission to delete event.';
}
my $in_zmaudit = ( $0 =~ 'zmaudit.pl$');
if ( ! $in_zmaudit ) {
@ -402,6 +407,11 @@ sub delete {
sub delete_files {
my $event = shift;
if ( !$event->canEdit() ) {
Warning('No permission to delete event.');
return 'No permission to delete event.';
}
foreach my $Storage (
@_ ? ($_[0]) : (
new ZoneMinder::Storage($$event{StorageId}),
@ -570,6 +580,11 @@ sub DiskSpace {
sub CopyTo {
my ( $self, $NewStorage ) = @_;
if ( !$self->canEdit() ) {
Warning('No permission to copy event.');
return 'No permission to copy event.';
}
my $OldStorage = $self->Storage(undef);
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
if ( ! -e $OldPath ) {
@ -734,8 +749,13 @@ sub CopyTo {
} # end sub CopyTo
sub MoveTo {
my ( $self, $NewStorage ) = @_;
if ( !$self->canEdit() ) {
Warning('No permission to move event.');
return 'No permission to move event.';
}
my $OldStorage = $self->Storage(undef);
my $error = $self->CopyTo($NewStorage);
@ -857,16 +877,32 @@ sub files {
sub has_capture_jpegs {
@{$_[0]{capture_jpegs}} = grep(/^\d+\-capture\.jpg$/, $_[0]->files());
Debug("have " . @{$_[0]{capture_jpegs}} . " capture jpegs");
Debug('have ' . @{$_[0]{capture_jpegs}} . ' capture jpegs');
return @{$_[0]{capture_jpegs}} ? 1 : 0;
}
sub has_analyse_jpegs {
@{$_[0]{analyse_jpegs}} = grep(/^\d+\-analyse\.jpg$/, $_[0]->files());
Debug("have " . @{$_[0]{analyse_jpegs}} . " analyse jpegs");
Debug('have ' . @{$_[0]{analyse_jpegs}} . ' analyse jpegs');
return @{$_[0]{analyse_jpegs}} ? 1 : 0;
}
sub canEdit {
my $self = shift;
if ( !$ZoneMinder::user ) {
# No user loaded... assume running as system
return 1;
}
if ( !$$ZoneMinder::user{MonitorIds} ) {
# User has no monitor limitations
return 1;
}
if ( $$ZoneMinder::user{Events} eq 'Edit' ) {
return 1;
}
return 0;
} # end sub canEdit
1;
__END__

View File

@ -49,49 +49,34 @@ use ZoneMinder::Database qw(:all);
require ZoneMinder::Storage;
require ZoneMinder::Server;
sub Name {
if ( @_ > 1 ) {
$_[0]{Name} = $_[1];
}
return $_[0]{Name};
} # end sub Path
use vars qw/ $table $primary_key %fields /;
$table = 'Users';
$primary_key = 'Id';
sub find {
shift if $_[0] eq 'ZoneMinder::Filter';
my %sql_filters = @_;
my $sql = 'SELECT * FROM Filters';
my @sql_filters;
my @sql_values;
if ( exists $sql_filters{Name} ) {
push @sql_filters , ' Name = ? ';
push @sql_values, $sql_filters{Name};
}
$sql .= ' WHERE ' . join(' AND ', @sql_filters ) if @sql_filters;
$sql .= ' LIMIT ' . $sql_filters{limit} if $sql_filters{limit};
my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr());
my $res = $sth->execute(@sql_values)
or Fatal("Can't execute '$sql': ".$sth->errstr());
my @results;
while( my $db_filter = $sth->fetchrow_hashref() ) {
my $filter = new ZoneMinder::Filter($$db_filter{Id}, $db_filter);
push @results, $filter;
} # end while
$sth->finish();
return @results;
}
sub find_one {
my @results = find(@_);
return $results[0] if @results;
}
%fields = map { $_ => $_ } qw(
Id
Name
Query_json
AutoArchive
AutoVideo
AutoUpload
AutoEmail
EmailTo
EmailSubject
EmailBody
AutoMessage
AutoExecute
AutoExecuteCmd
AutoDelete
AutoMove
AutoMoveTo
AutoCopy
AutoCopyTo
UpdateDiskSpace
UserId
Background
Concurrent
);
sub Execute {
my $self = $_[0];
@ -324,14 +309,9 @@ sub Sql {
} # end if terms
if ( $self->{Sql} ) {
if ( $self->{AutoMessage} ) {
# Include all events, including events that are still ongoing
# and have no EndTime yet
$sql .= ' WHERE ( '.$self->{Sql}.' )';
} else {
# Only include closed events (events with valid EndTime)
$sql .= ' WHERE (E.EndTime IS NOT NULL) AND ( '.$self->{Sql}.' )';
}
}
my @auto_terms;
if ( $self->{AutoArchive} ) {
@ -458,6 +438,15 @@ sub DateTimeToSQL {
return POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($dt_val));
}
sub User {
my $self = shift;
$$self{User} = shift if @_;
if ( ! $$self{User} and $$self{UserId} ) {
$$self{User} = ZoneMinder::User->find_one(Id=>$$self{UserId});
}
return $$self{User};
}
1;
__END__
# Below is stub documentation for your module. You'd better edit it!

View File

@ -28,6 +28,9 @@ our %EXPORT_TAGS = (
makePath
jsonEncode
jsonDecode
systemStatus
packageControl
daemonControl
) ]
);
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
@ -531,6 +534,38 @@ sub jsonDecode {
return $result;
}
sub packageControl {
my $command = shift;
my $string = $Config{ZM_PATH_BIN}.'/zmpkg.pl '.$command;
$string .= ' 2>/dev/null >&- <&- >/dev/null';
executeShellCommand($string);
}
sub daemonControl {
my ($command, $daemon, $args) = @_;
my $string = $Config{ZM_PATH_BIN}.'/zmdc.pl '.$command;
if ( $daemon ) {
$string .= ' ' . $daemon;
if ( $args ) {
$string .= ' ' . $args;
}
}
#$string .= ' 2>/dev/null >&- <&- >/dev/null';
executeShellCommand($string);
}
sub systemStatus {
my $command = $Config{ZM_PATH_BIN}.'/zmdc.pl check';
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() ) {
$output = '' if !defined($output);
chomp($output);
Debug("Command: $command Output: $output");
}
return $output;
}
1;
__END__
# Below is stub documentation for your module. You'd better edit it!
@ -542,7 +577,6 @@ ZoneMinder::General - Utility Functions for ZoneMinder
=head1 SYNOPSIS
use ZoneMinder::General;
blah blah blah
=head1 DESCRIPTION
@ -561,6 +595,9 @@ of the ZoneMinder scripts
makePath
jsonEncode
jsonDecode
packageControl
daemonControl
systemStatus
) ]

View File

@ -0,0 +1,80 @@
# ==========================================================================
#
# ZoneMinder User Module
# Copyright (C) 2020 ZoneMinder LLC
#
# This program 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 program 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.
#
# ==========================================================================
package ZoneMinder::Frame;
use 5.006;
use strict;
use warnings;
require ZoneMinder::Base;
require ZoneMinder::Object;
use parent qw(ZoneMinder::Object);
use vars qw/ $table $primary_key %fields /;
$table = 'Users';
$primary_key = 'Id';
%fields = map { $_ => $_ } qw(
Id
Username
Password
Language
Enabled
Stream
Events
Control
Monitors
Groups
Devices
System
MaxBandwidth
MonitorIds
TokenMinExpiry
APIEnabled
);
1;
__END__
=head1 NAME
ZoneMinder::User - Perl Class for Users
=head1 SYNOPSIS
use ZoneMinder::User;
=head1 AUTHOR
Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2001-2017 ZoneMinder LLC
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.3 or,
at your option, any later version of Perl 5 you may have available.
=cut

View File

@ -119,25 +119,30 @@ GetOptions(
) or pod2usage(-exitstatus => -1);
my $dbh = zmDbConnect(undef, { mysql_multi_statements=>1 } );
if ( !$dbh ) {
die "Unable to connect to db\n";
}
$Config{ZM_DB_USER} = $dbUser;
$Config{ZM_DB_PASS} = $dbPass;
# we escape dbpass with single quotes so that $ in the password has no effect, but dbpass could have a ' in it.
$dbPass =~ s/'/\\'/g;
if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version) ) {
if ( $Config{ZM_DYN_DB_VERSION} ) {
$version = $Config{ZM_DYN_DB_VERSION};
} else {
print( STDERR "Please give a valid option\n" );
print(STDERR "Please give a valid option\n");
pod2usage(-exitstatus => -1);
}
}
if ( ($check + $freshen + $rename + $zoneFix + $migrateEvents + ($version?1:0)) > 1 ) {
print( STDERR "Please give only one option\n" );
print(STDERR "Please give only one option\n");
pod2usage(-exitstatus => -1);
}
if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) {
print( "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
print('Update agent starting at '.strftime('%y/%m/%d %H:%M:%S', localtime() )."\n");
my $currVersion = $Config{ZM_DYN_CURR_VERSION};
my $lastVersion = $Config{ZM_DYN_LAST_VERSION};
@ -147,23 +152,23 @@ if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) {
$currVersion = $Config{ZM_VERSION};
my $sql = "update Config set Value = ? where Name = 'ZM_DYN_CURR_VERSION'";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( "$currVersion" ) or die( "Can't execute: ".$sth->errstr() );
my $sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($currVersion) or die("Can't execute: ".$sth->errstr());
$sth->finish();
}
while( 1 ) {
while ( 1 ) {
my $now = time();
if ( !$lastVersion || !$lastCheck || (($now-$lastCheck) > CHECK_INTERVAL) ) {
Info( "Checking for updates\n" );
Info('Checking for updates');
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->agent( "ZoneMinder Update Agent/".ZM_VERSION );
$ua->agent('ZoneMinder Update Agent/'.ZM_VERSION);
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
$ua->proxy( 'http', $Config{ZM_UPDATE_CHECK_PROXY} );
$ua->proxy('http', $Config{ZM_UPDATE_CHECK_PROXY});
}
my $req = HTTP::Request->new( GET=>'https://update.zoneminder.com/version.txt' );
my $req = HTTP::Request->new(GET=>'https://update.zoneminder.com/version.txt');
my $res = $ua->request($req);
if ( $res->is_success ) {
@ -171,63 +176,63 @@ if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) {
chomp($lastVersion);
$lastCheck = $now;
Info( "Got version: '".$lastVersion."'\n" );
Info('Got version: '.$lastVersion);
my $lv_sql = "update Config set Value = ? where Name = 'ZM_DYN_LAST_VERSION'";
my $lv_sth = $dbh->prepare_cached( $lv_sql ) or die( "Can't prepare '$lv_sql': ".$dbh->errstr() );
my $lv_res = $lv_sth->execute( $lastVersion ) or die( "Can't execute: ".$lv_sth->errstr() );
my $lv_sql = 'UPDATE Config SET Value = ? WHERE Name = \'ZM_DYN_LAST_VERSION\'';
my $lv_sth = $dbh->prepare_cached($lv_sql) or die("Can't prepare '$lv_sql': ".$dbh->errstr());
my $lv_res = $lv_sth->execute($lastVersion) or die("Can't execute: ".$lv_sth->errstr());
$lv_sth->finish();
my $lc_sql = "update Config set Value = ? where Name = 'ZM_DYN_LAST_CHECK'";
my $lc_sth = $dbh->prepare_cached( $lc_sql ) or die( "Can't prepare '$lc_sql': ".$dbh->errstr() );
my $lc_res = $lc_sth->execute( $lastCheck ) or die( "Can't execute: ".$lc_sth->errstr() );
my $lc_sql = 'UPDATE Config SET Value = ? WHERE Name = \'ZM_DYN_LAST_CHECK\'';
my $lc_sth = $dbh->prepare_cached($lc_sql) or die("Can't prepare '$lc_sql': ".$dbh->errstr());
my $lc_res = $lc_sth->execute($lastCheck) or die("Can't execute: ".$lc_sth->errstr());
$lc_sth->finish();
} else {
Error( "Error check failed: '".$res->status_line()."'\n" );
Error('Error check failed: \''.$res->status_line().'\'');
}
}
sleep( 3600 );
sleep(3600);
}
print( "Update agent exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
print('Update agent exiting at '.strftime('%y/%m/%d %H:%M:%S', localtime())."\n");
}
if ( $rename ) {
require File::Find;
chdir( EVENT_PATH );
chdir(EVENT_PATH);
sub renameImage {
my $file = $_;
# Ignore directories
if ( -d $file ) {
print( "Checking directory '$file'\n" );
print("Checking directory '$file'\n");
return;
}
if ( $file !~ /(capture|analyse)-(\d+)(\.jpg)/ ) {
return;
}
my $newFile = "$2-$1$3";
my $newFile = $2.'-'.$1.$3;
print( "Renaming '$file' to '$newFile'\n" );
rename( $file, $newFile ) or warn( "Can't rename '$file' to '$newFile'" );
print("Renaming '$file' to '$newFile'\n");
rename($file, $newFile) or warn("Can't rename '$file' to '$newFile'");
}
File::Find::find( \&renameImage, '.' );
}
if ( $zoneFix ) {
File::Find::find(\&renameImage, '.');
} # end if rename
my $sql = "select Z.*, M.Width as MonitorWidth, M.Height as MonitorHeight from Zones as Z inner join Monitors as M on Z.MonitorId = M.Id where Z.Units = 'Percent'";
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() );
if ( $zoneFix ) {
my $sql = "SELECT Z.*, M.Width AS MonitorWidth, M.Height AS MonitorHeight FROM Zones AS Z INNER JOIN Monitors AS M ON Z.MonitorId = M.Id WHERE Z.Units = 'Percent'";
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 @zones;
while( my $zone = $sth->fetchrow_hashref() ) {
push( @zones, $zone );
while ( my $zone = $sth->fetchrow_hashref() ) {
push(@zones, $zone);
}
$sth->finish();
$sql = 'update Zones set MinAlarmPixels = ?, MaxAlarmPixels = ?, MinFilterPixels = ?, MaxFilterPixels = ?, MinBlobPixels = ?, MaxBlobPixels = ? where Id = ?';
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$sql = 'UPDATE Zones SET MinAlarmPixels = ?, MaxAlarmPixels = ?, MinFilterPixels = ?, MaxFilterPixels = ?, MinBlobPixels = ?, MaxBlobPixels = ? WHERE Id = ?';
$sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr());
foreach my $zone ( @zones ) {
my $zone_width = (($zone->{HiX}*$zone->{MonitorWidth})-($zone->{LoX}*$zone->{MonitorWidth}))/100;
my $zone_height = (($zone->{HiY}*$zone->{MonitorHeight})-($zone->{LoY}*$zone->{MonitorHeight}))/100;
@ -241,17 +246,18 @@ if ( $zoneFix ) {
($zone->{MinBlobPixels}*$monitor_area)/$zone_area,
($zone->{MaxBlobPixels}*$monitor_area)/$zone_area,
$zone->{Id}
) or die( "Can't execute: ".$sth->errstr() );
) or die("Can't execute: ".$sth->errstr());
}
$sth->finish();
}
} # end if zoneFix
if ( $migrateEvents ) {
my $webUid = (getpwnam( $Config{ZM_WEB_USER} ))[2];
my $webGid = (getgrnam( $Config{ZM_WEB_USER} ))[2];
my $webUid = (getpwnam($Config{ZM_WEB_USER}))[2];
my $webGid = (getgrnam($Config{ZM_WEB_USER}))[2];
if ( !(($> == 0) || ($> == $webUid)) ) {
print( "Error, migrating events can only be done as user root or ".$Config{ZM_WEB_USER}.".\n" );
exit( -1 );
print("Error, migrating events can only be done as user root or ".$Config{ZM_WEB_USER}.".\n");
exit(-1);
}
# Run as web user/group
@ -260,59 +266,64 @@ if ( $migrateEvents ) {
$< = $webUid;
$> = $webUid;
print( "\nAbout to convert saved events to deep storage, please ensure that ZoneMinder is fully stopped before proceeding.\nThis process is not easily reversible. Are you sure you wish to proceed?\n\nPress 'y' to continue or 'n' to abort : " );
print('
About to convert saved events to deep storage, please ensure that ZoneMinder is fully stopped before proceeding.
This process is not easily reversible. Are you sure you wish to proceed?
Press \'y\' to continue or \'n\' to abort : ');
my $response = <STDIN>;
chomp( $response );
chomp($response);
while ( $response !~ /^[yYnN]$/ ) {
print( "Please press 'y' to continue or 'n' to abort only : " );
print("Please press 'y' to continue or 'n' to abort only : ");
$response = <STDIN>;
chomp( $response );
chomp($response);
}
if ( $response =~ /^[yY]$/ ) {
print( "Converting all events to deep storage.\n" );
print("Converting all events to deep storage.\n");
chdir( $Config{ZM_PATH_WEB} );
my $sql = "select *, unix_timestamp(StartTime) as UnixStartTime from Events";
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
chdir($Config{ZM_PATH_WEB});
my $sql = 'SELECT *, unix_timestamp(StartTime) AS UnixStartTime FROM Events';
my $sth = $dbh->prepare_cached($sql) or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute();
if ( !$res ) {
Fatal( "Can't fetch Events: ".$sth->errstr() );
Fatal("Can't fetch Events: ".$sth->errstr());
}
while( my $event = $sth->fetchrow_hashref() ) {
my $oldEventPath = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.$event->{Id};
if ( !-d $oldEventPath ) {
print( "Warning, can't find old event path '$oldEventPath', already converted?\n" );
print("Warning, can't find old event path '$oldEventPath', already converted?\n");
next;
}
print( "Converting event ".$event->{Id}."\n" );
my $newDatePath = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.strftime( "%y/%m/%d", localtime($event->{UnixStartTime}) );
my $newTimePath = strftime( "%H/%M/%S", localtime($event->{UnixStartTime}) );
print('Converting event '.$event->{Id}."\n");
my $newDatePath = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.strftime('%y/%m/%d', localtime($event->{UnixStartTime}));
my $newTimePath = strftime('%H/%M/%S', localtime($event->{UnixStartTime}));
my $newEventPath = $newDatePath.'/'.$newTimePath;
( my $truncEventPath = $newEventPath ) =~ s|/\d+$||;
makePath( $truncEventPath, $Config{ZM_PATH_WEB} );
makePath($truncEventPath, $Config{ZM_PATH_WEB});
my $idLink = $newDatePath.'/.'.$event->{Id};
symlink( $newTimePath, $idLink ) or die( "Can't symlink $newTimePath -> $idLink: $!" );
rename( $oldEventPath, $newEventPath ) or die( "Can't move $oldEventPath -> $newEventPath: $!" );
symlink($newTimePath, $idLink) or die("Can't symlink $newTimePath -> $idLink: $!");
rename($oldEventPath, $newEventPath) or die("Can't move $oldEventPath -> $newEventPath: $!");
}
$sth->finish();
print( "Updating configuration.\n" );
print("Updating configuration.\n");
$sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_USE_DEEP_STORAGE'";
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( 1 ) or die( "Can't execute: ".$sth->errstr() );
$sth = $dbh->prepare_cached($sql) or die( "Can't prepare '$sql': ".$dbh->errstr());
$res = $sth->execute(1) or die("Can't execute: ".$sth->errstr());
$sth->finish();
print( "All events converted.\n\n" );
print("All events converted.\n\n");
} else {
print( "Aborting event conversion.\n\n" );
print("Aborting event conversion.\n\n");
}
}
if ( $freshen ) {
print( "\nFreshening configuration in database\n" );
print("\nFreshening configuration in database\n");
migratePaths();
migratePasswords();
ZoneMinder::Config::loadConfigFromDB();
@ -324,8 +335,8 @@ if ( $interactive ) {
# Now check for MyISAM Tables
my @MyISAM_Tables;
my $sql = "SELECT `table_name` FROM INFORMATION_SCHEMA.TABLES WHERE `table_schema`='zm' AND `engine` = 'MyISAM'";
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 $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 $dbTable = $sth->fetchrow() ) {
push @MyISAM_Tables, $dbTable;
@ -333,17 +344,22 @@ if ( $interactive ) {
$sth->finish();
if ( @MyISAM_Tables ) {
print( "\nPrevious versions of ZoneMinder used the MyISAM database engine.\nHowever, the recommended database engine is InnoDB.\n");
print( "\nHint: InnoDB tables are much less likely to be corrupted during an unclean shutdown.\n\nPress 'y' to convert your tables to InnoDB or 'n' to skip : ");
print('
Previous versions of ZoneMinder used the MyISAM database engine.
However, the recommended database engine is InnoDB.
Hint: InnoDB tables are much less likely to be corrupted during an unclean shutdown.
Press \'y\' to convert your tables to InnoDB or \'n\' to skip : ');
my $response = <STDIN>;
chomp( $response );
if ( $response =~ /^[yY]$/ ) {
$dbh->do(q|SET sql_mode='traditional'|); # Elevate warnings to errors
print "\nConverting MyISAM tables to InnoDB. Please wait.\n";
foreach (@MyISAM_Tables) {
foreach ( @MyISAM_Tables ) {
my $sql = "ALTER TABLE `$_` ENGINE = InnoDB";
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 $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();
}
$dbh->do(q|SET sql_mode=''|); # Set mode back to default
@ -360,23 +376,31 @@ if ( $version ) {
exit(0);
}
print( "\nInitiating database upgrade to version ".ZM_VERSION." from version $version\n" );
my $start_zm = 0;
print("\nInitiating database upgrade to version ".ZM_VERSION." from version $version\n");
if ( $interactive ) {
if ( $Config{ZM_DYN_DB_VERSION} && $Config{ZM_DYN_DB_VERSION} ne $version ) {
print( "\nWARNING - You have specified an upgrade from version $version but the database version found is ".$Config{ZM_DYN_DB_VERSION}.". Is this correct?\nPress enter to continue or ctrl-C to abort : " );
if ( $Config{ZM_DYN_DB_VERSION} && ($Config{ZM_DYN_DB_VERSION} ne $version) ) {
print("\nWARNING - You have specified an upgrade from version $version but the database version found is $Config{ZM_DYN_DB_VERSION}. Is this correct?\nPress enter to continue or ctrl-C to abort : ");
my $response = <STDIN>;
}
print( "\nPlease ensure that ZoneMinder is stopped on your system prior to upgrading the database.\nPress enter to continue or ctrl-C to stop : " );
if ( systemStatus() eq 'running' ) {
print"\nZoneMinder system appears to be running. While not strictly required, it is advised to stop ZM during the update process. Would you like to stop ZM now? [Yn]:";
my $response = <STDIN>;
chomp($response);
if ( $response !~ /Yy/ ) {
packageControl('stop');
$start_zm = 1;
}
}
print( "\nDo you wish to take a backup of your database prior to upgrading?\nThis may result in a large file in @ZM_TMPDIR@ if you have a lot of events.\nPress 'y' for a backup or 'n' to continue : " );
$response = <STDIN>;
chomp( $response );
print("\nDo you wish to take a backup of your database prior to upgrading?\nThis may result in a large file in @ZM_TMPDIR@ if you have a lot of events.\nPress 'y' for a backup or 'n' to continue : ");
my $response = <STDIN>;
chomp($response);
while ( $response !~ /^[yYnN]$/ ) {
print( "Please press 'y' for a backup or 'n' to continue only : " );
print("Please press 'y' for a backup or 'n' to continue only : ");
$response = <STDIN>;
chomp( $response );
chomp($response);
}
if ( $response =~ /^[yY]$/ ) {
@ -384,21 +408,22 @@ if ( $version ) {
my $command = 'mysqldump';
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
$command .= " -S".$portOrSocket;
$command .= ' -S'.$portOrSocket;
} else {
$command .= " -h".$host." -P".$portOrSocket;
$command .= ' -h'.$host.' -P'.$portOrSocket;
}
} else {
$command .= " -h".$host;
$command .= ' -h'.$host;
}
if ( $dbUser ) {
$command .= ' -u'.$dbUser;
$command .= ' -p"'.$dbPass.'"' if $dbPass;
$command .= ' -p\''.$dbPass.'\'' if $dbPass;
}
my $backup = "@ZM_TMPDIR@/".$Config{ZM_DB_NAME}."-".$version.".dump";
$command .= " --add-drop-table --databases ".$Config{ZM_DB_NAME}." > ".$backup;
print( "Creating backup to $backup. This may take several minutes.\n" );
print( "Executing '$command'\n" ) if ( logDebugging() );
my $backup = '@ZM_TMPDIR@/'.$Config{ZM_DB_NAME}.'-'.$version.'.dump';
$command .= ' --add-drop-table --databases '.$Config{ZM_DB_NAME}.' > '.$backup;
print("Creating backup to $backup. This may take several minutes.\n");
($command) = $command =~ /(.*)/; # detaint
print("Executing '$command'\n") if logDebugging();
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() ) {
@ -933,7 +958,12 @@ 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");
if ( $start_zm ) {
print("Starting ZM since we stopped it for the update\n");
packageControl('start');
}
} # end if version
zmDbDisconnect();
@ -969,7 +999,7 @@ sub patchDB {
my $dbh = shift;
my $version = shift;
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ) if $Config{ZM_DB_HOST};
my $command = 'mysql';
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
@ -977,12 +1007,12 @@ sub patchDB {
} else {
$command .= ' -h'.$host.' -P'.$portOrSocket;
}
} else {
} elsif ( $host ) {
$command .= ' -h'.$host;
}
if ( $dbUser ) {
$command .= ' -u'.$dbUser;
$command .= ' -p"'.$dbPass.'"' if $dbPass;
$command .= ' -p\''.$dbPass.'\'' if $dbPass;
}
$command .= ' '.$Config{ZM_DB_NAME}.' < ';
if ( $updateDir ) {
@ -993,6 +1023,7 @@ sub patchDB {
$command .= '/zm_update-'.$version.'.sql';
print("Executing '$command'\n") if logDebugging();
($command) = $command =~ /(.*)/; # detaint
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() ) {

View File

@ -976,10 +976,12 @@ int FfmpegCamera::CaptureAndRecord(
return -1;
}
#if HAVE_LIBAVUTIL_HWCONTEXT_H
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
if ( (ret == AVERROR_INVALIDDATA ) && (hw_pix_fmt != AV_PIX_FMT_NONE) ) {
use_hwaccel = false;
return -1;
}
#endif
#endif
}
zm_av_packet_unref(&packet);

View File

@ -1905,11 +1905,11 @@ void Image::MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour
/* RGB32 compatible: complete */
void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int size, const Rgb fg_colour, const Rgb bg_colour )
{
strncpy( text, p_text, sizeof(text)-1 );
strncpy(text, p_text, sizeof(text)-1);
unsigned int index = 0;
unsigned int line_no = 0;
unsigned int text_len = strlen( text );
unsigned int text_len = strlen(text);
unsigned int line_len = 0;
const char *line = text;
@ -1928,10 +1928,10 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
const bool bg_trans = (bg_colour == RGB_TRANSPARENT);
int zm_text_bitmask = 0x80;
if (size == 2)
if ( size == 2 )
zm_text_bitmask = 0x8000;
while ( (index < text_len) && (line_len = strcspn( line, "\n" )) ) {
while ( (index < text_len) && (line_len = strcspn(line, "\n")) ) {
unsigned int line_width = line_len * ZM_CHAR_WIDTH * size;
@ -1967,10 +1967,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
unsigned char *temp_ptr = ptr;
for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) {
int f;
if (size == 2)
if ( size == 2 ) {
if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) {
Warning("Unsupported character %c in %s", line[c], line);
continue;
}
f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r];
else
} else {
if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) {
Warning("Unsupported character %c in %s", line[c], line);
continue;
}
f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r];
}
for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr++ ) {
if ( f & (zm_text_bitmask >> i) ) {
if ( !fg_trans )
@ -1989,10 +1998,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
unsigned char *temp_ptr = ptr;
for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) {
int f;
if (size == 2)
if ( size == 2 ) {
if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) {
Warning("Unsupported character %c in %s", line[c], line);
continue;
}
f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r];
else
} else {
if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) {
Warning("Unsupported character %c in %s", line[c], line);
continue;
}
f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r];
}
for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr += colours ) {
if ( f & (zm_text_bitmask >> i) ) {
if ( !fg_trans ) {
@ -2016,10 +2034,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
Rgb* temp_ptr = (Rgb*)ptr;
for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) {
int f;
if (size == 2)
if ( size == 2 ) {
if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) {
Warning("Unsupported character %c in %s", line[c], line);
continue;
}
f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r];
else
} else {
if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) {
Warning("Unsupported character %c in %s", line[c], line);
continue;
}
f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r];
}
for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr++ ) {
if ( f & (zm_text_bitmask >> i) ) {
if ( !fg_trans ) {

View File

@ -1274,56 +1274,62 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
#define capString(test,prefix,yesString,noString,capability) \
(test) ? (prefix yesString " " capability "\n") : (prefix noString " " capability "\n")
bool LocalCamera::GetCurrentSettings( const char *device, char *output, int version, bool verbose ) {
bool LocalCamera::GetCurrentSettings(const char *device, char *output, int version, bool verbose) {
output[0] = 0;
char *output_ptr = output;
char queryDevice[PATH_MAX] = "";
int devIndex = 0;
do {
if ( device )
if ( device ) {
strncpy(queryDevice, device, sizeof(queryDevice)-1);
else
} else {
sprintf(queryDevice, "/dev/video%d", devIndex);
}
if ( (vid_fd = open(queryDevice, O_RDWR)) <= 0 ) {
if ( device ) {
Error("Failed to open video device %s: %s", queryDevice, strerror(errno));
if ( verbose )
sprintf(output+strlen(output), "Error, failed to open video device %s: %s\n",
output_ptr += sprintf(output_ptr, "Error, failed to open video device %s: %s\n",
queryDevice, strerror(errno));
else
sprintf(output+strlen(output), "error%d\n", errno);
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
} else {
return true;
}
}
if ( verbose )
sprintf(output+strlen(output), "Video Device: %s\n", queryDevice);
else
sprintf(output+strlen(output), "d:%s|", queryDevice);
if ( verbose ) {
output_ptr += sprintf(output_ptr, "Video Device: %s\n", queryDevice);
} else {
output_ptr += sprintf(output_ptr, "d:%s|", queryDevice);
}
#if ZM_HAS_V4L2
if ( version == 2 ) {
struct v4l2_capability vid_cap;
if ( vidioctl(vid_fd, VIDIOC_QUERYCAP, &vid_cap) < 0 ) {
Error("Failed to query video device: %s", strerror(errno));
if ( verbose )
sprintf(output, "Error, failed to query video capabilities %s: %s\n",
if ( verbose ) {
output_ptr += sprintf(output_ptr, "Error, failed to query video capabilities %s: %s\n",
queryDevice, strerror(errno));
else
sprintf(output, "error%d\n", errno);
} else {
output_ptr += sprintf(output_ptr, "error%d\n", errno);
}
if ( device )
return false;
}
if ( verbose ) {
sprintf(output+strlen(output), "General Capabilities\n");
sprintf(output+strlen(output), " Driver: %s\n", vid_cap.driver);
sprintf(output+strlen(output), " Card: %s\n", vid_cap.card);
sprintf(output+strlen(output), " Bus: %s\n", vid_cap.bus_info);
sprintf(output+strlen(output), " Version: %u.%u.%u\n",
(vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff);
sprintf(output+strlen(output), " Type: 0x%x\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
output_ptr += sprintf(output_ptr, "General Capabilities\n"
" Driver: %s\n"
" Card: %s\n"
" Bus: %s\n"
" Version: %u.%u.%u\n"
" Type: 0x%x\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
vid_cap.driver, vid_cap.card, vid_cap.bus_info,
(vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff,
vid_cap.capabilities,
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_CAPTURE, " ", "Supports", "Does not support", "video capture (X)"),
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OUTPUT, " ", "Supports", "Does not support", "video output"),
@ -1345,17 +1351,16 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
capString(vid_cap.capabilities&V4L2_CAP_STREAMING, " ", "Supports", "Does not support", "streaming i/o (X)")
);
} else {
sprintf(output+strlen(output), "D:%s|", vid_cap.driver);
sprintf(output+strlen(output), "C:%s|", vid_cap.card);
sprintf(output+strlen(output), "B:%s|", vid_cap.bus_info);
sprintf(output+strlen(output), "V:%u.%u.%u|", (vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff);
sprintf(output+strlen(output), "T:0x%x|", vid_cap.capabilities);
output_ptr += sprintf(output_ptr, "D:%s|C:%s|B:%s|V:%u.%u.%u|T:0x%x|"
, vid_cap.driver
, vid_cap.card
, vid_cap.bus_info
, (vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff
, vid_cap.capabilities);
}
if ( verbose )
sprintf(output+strlen(output), " Standards:\n");
else
sprintf(output+strlen(output), "S:");
output_ptr += sprintf(output_ptr, verbose ? " Standards:\n" : "S:");
struct v4l2_standard standard;
int standardIndex = 0;
do {
@ -1370,25 +1375,20 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
} else {
Error("Failed to enumerate standard %d: %d %s", standard.index, errno, strerror(errno));
if ( verbose )
sprintf(output, "Error, failed to enumerate standard %d: %d %s\n", standard.index, errno, strerror(errno));
output_ptr += sprintf(output_ptr, "Error, failed to enumerate standard %d: %d %s\n", standard.index, errno, strerror(errno));
else
sprintf(output, "error%d\n", errno);
output_ptr += sprintf(output_ptr, "error%d\n", errno);
// Why return? Why not continue trying other things?
return false;
}
}
if ( verbose )
sprintf(output+strlen(output), " %s\n", standard.name);
else
sprintf(output+strlen(output), "%s/", standard.name);
}
while ( standardIndex++ >= 0 );
if ( !verbose && output[strlen(output)-1] == '/')
output[strlen(output)-1] = '|';
output_ptr += sprintf(output_ptr, (verbose ? " %s\n" : "%s/"), standard.name);
} while ( standardIndex++ >= 0 );
if ( verbose )
sprintf(output+strlen(output), " Formats:\n");
else
sprintf(output+strlen(output), "F:");
if ( !verbose && (*(output_ptr-1) == '/') )
*(output_ptr-1) = '|';
output_ptr += sprintf(output_ptr, verbose ? " Formats:\n" : "F:");
struct v4l2_fmtdesc format;
int formatIndex = 0;
do {
@ -1403,15 +1403,15 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
} else {
Error("Failed to enumerate format %d: %s", format.index, strerror(errno));
if ( verbose )
sprintf(output, "Error, failed to enumerate format %d: %s\n", format.index, strerror(errno));
output_ptr += sprintf(output_ptr, "Error, failed to enumerate format %d: %s\n", format.index, strerror(errno));
else
sprintf(output, "error%d\n", errno);
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
}
if ( verbose )
sprintf(
output+strlen(output),
output_ptr += sprintf(
output_ptr,
" %s (0x%02hhx%02hhx%02hhx%02hhx)\n",
format.description,
(format.pixelformat>>24)&0xff,
@ -1419,33 +1419,34 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
(format.pixelformat>>8)&0xff,
format.pixelformat&0xff);
else
sprintf(
output+strlen(output),
output_ptr += sprintf(
output_ptr,
"0x%02hhx%02hhx%02hhx%02hhx/",
(format.pixelformat>>24)&0xff,
(format.pixelformat>>16)&0xff,
(format.pixelformat>>8)&0xff,
(format.pixelformat)&0xff);
} while ( formatIndex++ >= 0 );
if ( !verbose )
output[strlen(output)-1] = '|';
*(output_ptr-1) = '|';
else
sprintf(output+strlen(output), "Crop Capabilities\n");
output_ptr += sprintf(output_ptr, "Crop Capabilities\n");
struct v4l2_cropcap cropcap;
memset(&cropcap, 0, sizeof(cropcap));
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( vidioctl( vid_fd, VIDIOC_CROPCAP, &cropcap ) < 0 ) {
if ( vidioctl(vid_fd, VIDIOC_CROPCAP, &cropcap) < 0 ) {
if ( errno != EINVAL ) {
/* Failed querying crop capability, write error to the log and continue as if crop is not supported */
Error("Failed to query crop capabilities: %s", strerror(errno));
}
if ( verbose ) {
sprintf(output+strlen(output), " Cropping is not supported\n");
output_ptr += sprintf(output_ptr, " Cropping is not supported\n");
} else {
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
sprintf(output+strlen(output), "B:%dx%d|",0,0);
output_ptr += sprintf(output_ptr, "B:%dx%d|", 0, 0);
}
} else {
struct v4l2_crop crop;
@ -1459,19 +1460,23 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
}
if ( verbose ) {
sprintf(output+strlen(output), " Cropping is not supported\n");
output_ptr += sprintf(output_ptr, " Cropping is not supported\n");
} else {
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
sprintf(output+strlen(output), "B:%dx%d|",0,0);
output_ptr += sprintf(output_ptr, "B:%dx%d|",0,0);
}
} else {
/* Cropping supported */
if ( verbose ) {
sprintf(output+strlen(output), " Bounds: %d x %d\n", cropcap.bounds.width, cropcap.bounds.height);
sprintf(output+strlen(output), " Default: %d x %d\n", cropcap.defrect.width, cropcap.defrect.height);
sprintf(output+strlen(output), " Current: %d x %d\n", crop.c.width, crop.c.height);
output_ptr += sprintf(output_ptr,
" Bounds: %d x %d\n"
" Default: %d x %d\n"
" Current: %d x %d\n"
, cropcap.bounds.width, cropcap.bounds.height
, cropcap.defrect.width, cropcap.defrect.height
, crop.c.width, crop.c.height);
} else {
sprintf(output+strlen(output), "B:%dx%d|", cropcap.bounds.width, cropcap.bounds.height);
output_ptr += sprintf(output_ptr, "B:%dx%d|", cropcap.bounds.width, cropcap.bounds.height);
}
}
} /* Crop code */
@ -1488,17 +1493,14 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
}
Error("Failed to enumerate input %d: %s", input.index, strerror(errno));
if ( verbose )
sprintf(output, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
output_ptr += sprintf(output_ptr, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
else
sprintf(output, "error%d\n", errno);
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
} while ( inputIndex++ >= 0 );
if ( verbose )
sprintf(output+strlen(output), "Inputs: %d\n", inputIndex);
else
sprintf(output+strlen(output), "I:%d|", inputIndex);
output_ptr += sprintf(output_ptr, verbose?"Inputs: %d\n":"I:%d|", inputIndex);
inputIndex = 0;
do {
@ -1512,65 +1514,84 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
}
Error("Failed to enumerate input %d: %s", input.index, strerror(errno));
if ( verbose )
sprintf(output, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
output_ptr += sprintf(output_ptr, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
else
sprintf(output, "error%d\n", errno);
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &input.index) < 0 ) {
Error("Failed to set video input %d: %s", input.index, strerror(errno));
if ( verbose )
sprintf(output, "Error, failed to switch to input %d: %s\n", input.index, strerror(errno));
output_ptr += sprintf(output_ptr, "Error, failed to switch to input %d: %s\n", input.index, strerror(errno));
else
sprintf(output, "error%d\n", errno);
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
if ( verbose ) {
sprintf( output+strlen(output), " Input %d\n", input.index );
sprintf( output+strlen(output), " Name: %s\n", input.name );
sprintf( output+strlen(output), " Type: %s\n", input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown") );
sprintf( output+strlen(output), " Audioset: %08x\n", input.audioset );
sprintf( output+strlen(output), " Standards: 0x%llx\n", input.std );
output_ptr += sprintf( output,
" Input %d\n"
" Name: %s\n"
" Type: %s\n"
" Audioset: %08x\n"
" Standards: 0x%llx\n"
, input.index
, input.name
, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
, input.audioset
, input.std );
} else {
sprintf( output+strlen(output), "i%d:%s|", input.index, input.name );
sprintf( output+strlen(output), "i%dT:%s|", input.index, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown") );
sprintf( output+strlen(output), "i%dS:%llx|", input.index, input.std );
output_ptr += sprintf( output_ptr, "i%d:%s|i%dT:%s|i%dS:%llx|"
, input.index, input.name
, input.index, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
, input.index, input.std);
}
if ( verbose ) {
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_POWER, "Power ", "off", "on", " (X)" ) );
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_SIGNAL, "Signal ", "not detected", "detected", " (X)" ) );
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_COLOR, "Colour Signal ", "not detected", "detected", "" ) );
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_H_LOCK, "Horizontal Lock ", "not detected", "detected", "" ) );
output_ptr += sprintf( output_ptr, " %s %s %s %s"
, capString(input.status&V4L2_IN_ST_NO_POWER, "Power ", "off", "on", " (X)")
, capString(input.status&V4L2_IN_ST_NO_SIGNAL, "Signal ", "not detected", "detected", " (X)")
, capString(input.status&V4L2_IN_ST_NO_COLOR, "Colour Signal ", "not detected", "detected", "")
, capString(input.status&V4L2_IN_ST_NO_H_LOCK, "Horizontal Lock ", "not detected", "detected", ""));
} else {
sprintf( output+strlen(output), "i%dSP:%d|", input.index, (input.status&V4L2_IN_ST_NO_POWER)?0:1 );
sprintf( output+strlen(output), "i%dSS:%d|", input.index, (input.status&V4L2_IN_ST_NO_SIGNAL)?0:1 );
sprintf( output+strlen(output), "i%dSC:%d|", input.index, (input.status&V4L2_IN_ST_NO_COLOR)?0:1 );
sprintf( output+strlen(output), "i%dHP:%d|", input.index, (input.status&V4L2_IN_ST_NO_H_LOCK)?0:1 );
output_ptr += sprintf( output_ptr, "i%dSP:%d|i%dSS:%d|i%dSC:%d|i%dHP:%d|"
, input.index, (input.status&V4L2_IN_ST_NO_POWER)?0:1
, input.index, (input.status&V4L2_IN_ST_NO_SIGNAL)?0:1
, input.index, (input.status&V4L2_IN_ST_NO_COLOR)?0:1
, input.index, (input.status&V4L2_IN_ST_NO_H_LOCK)?0:1 );
}
} while ( inputIndex++ >= 0 );
if ( !verbose )
output[strlen(output)-1] = '\n';
*(output_ptr-1) = '\n';
}
#endif // ZM_HAS_V4L2
#if ZM_HAS_V4L1
if ( version == 1 ) {
struct video_capability vid_cap;
memset( &vid_cap, 0, sizeof(video_capability) );
if ( ioctl( vid_fd, VIDIOCGCAP, &vid_cap ) < 0 ) {
Error( "Failed to get video capabilities: %s", strerror(errno) );
memset(&vid_cap, 0, sizeof(video_capability));
if ( ioctl(vid_fd, VIDIOCGCAP, &vid_cap) < 0 ) {
Error("Failed to get video capabilities: %s", strerror(errno));
if ( verbose )
sprintf( output, "Error, failed to get video capabilities %s: %s\n", queryDevice, strerror(errno) );
output_ptr += sprintf(output_ptr,
"Error, failed to get video capabilities %s: %s\n",
queryDevice, strerror(errno));
else
sprintf( output, "error%d\n", errno );
return( false );
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
if ( verbose ) {
sprintf( output+strlen(output), "Video Capabilities\n" );
sprintf( output+strlen(output), " Name: %s\n", vid_cap.name );
sprintf( output+strlen(output), " Type: %d\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s", vid_cap.type,
output_ptr += sprintf( output_ptr, "Video Capabilities\n"
" Name: %s\n"
" Type: %d\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" Video Channels: %d\n"
" Audio Channels: %d\n"
" Maximum Width: %d\n"
" Maximum Height: %d\n"
" Minimum Width: %d\n"
" Minimum Height: %d\n",
vid_cap.name,
vid_cap.type,
(vid_cap.type&VID_TYPE_CAPTURE)?" Can capture\n":"",
(vid_cap.type&VID_TYPE_TUNER)?" Can tune\n":"",
(vid_cap.type&VID_TYPE_TELETEXT)?" Does teletext\n":"",
@ -1584,63 +1605,72 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
(vid_cap.type&VID_TYPE_MPEG_DECODER)?" Can decode MPEG streams\n":"",
(vid_cap.type&VID_TYPE_MPEG_ENCODER)?" Can encode MPEG streams\n":"",
(vid_cap.type&VID_TYPE_MJPEG_DECODER)?" Can decode MJPEG streams\n":"",
(vid_cap.type&VID_TYPE_MJPEG_ENCODER)?" Can encode MJPEG streams\n":""
);
sprintf( output+strlen(output), " Video Channels: %d\n", vid_cap.channels );
sprintf( output+strlen(output), " Audio Channels: %d\n", vid_cap.audios );
sprintf( output+strlen(output), " Maximum Width: %d\n", vid_cap.maxwidth );
sprintf( output+strlen(output), " Maximum Height: %d\n", vid_cap.maxheight );
sprintf( output+strlen(output), " Minimum Width: %d\n", vid_cap.minwidth );
sprintf( output+strlen(output), " Minimum Height: %d\n", vid_cap.minheight );
}
else
{
sprintf( output+strlen(output), "N:%s|", vid_cap.name );
sprintf( output+strlen(output), "T:%d|", vid_cap.type );
sprintf( output+strlen(output), "nC:%d|", vid_cap.channels );
sprintf( output+strlen(output), "nA:%d|", vid_cap.audios );
sprintf( output+strlen(output), "mxW:%d|", vid_cap.maxwidth );
sprintf( output+strlen(output), "mxH:%d|", vid_cap.maxheight );
sprintf( output+strlen(output), "mnW:%d|", vid_cap.minwidth );
sprintf( output+strlen(output), "mnH:%d|", vid_cap.minheight );
(vid_cap.type&VID_TYPE_MJPEG_ENCODER)?" Can encode MJPEG streams\n":"",
vid_cap.channels,
vid_cap.audios,
vid_cap.maxwidth,
vid_cap.maxheight,
vid_cap.minwidth,
vid_cap.minheight );
} else {
output_ptr += sprintf(output_ptr, "N:%s|T:%d|nC:%d|nA:%d|mxW:%d|mxH:%d|mnW:%d|mnH:%d|"
, vid_cap.name
, vid_cap.type
, vid_cap.channels
, vid_cap.audios
, vid_cap.maxwidth
, vid_cap.maxheight
, vid_cap.minwidth
, vid_cap.minheight);
}
struct video_window vid_win;
memset( &vid_win, 0, sizeof(video_window) );
if ( ioctl( vid_fd, VIDIOCGWIN, &vid_win ) < 0 ) {
Error( "Failed to get window attributes: %s", strerror(errno) );
memset(&vid_win, 0, sizeof(video_window));
if ( ioctl(vid_fd, VIDIOCGWIN, &vid_win) < 0 ) {
Error("Failed to get window attributes: %s", strerror(errno));
if ( verbose )
sprintf( output, "Error, failed to get window attributes: %s\n", strerror(errno) );
output_ptr += sprintf(output_ptr, "Error, failed to get window attributes: %s\n", strerror(errno));
else
sprintf( output, "error%d\n", errno );
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
if ( verbose ) {
sprintf( output+strlen(output), "Window Attributes\n" );
sprintf( output+strlen(output), " X Offset: %d\n", vid_win.x );
sprintf( output+strlen(output), " Y Offset: %d\n", vid_win.y );
sprintf( output+strlen(output), " Width: %d\n", vid_win.width );
sprintf( output+strlen(output), " Height: %d\n", vid_win.height );
output_ptr += sprintf(output_ptr,
"Window Attributes\n"
" X Offset: %d\n"
" Y Offset: %d\n"
" Width: %d\n"
" Height: %d\n"
, vid_win.x
, vid_win.y
, vid_win.width
, vid_win.height );
} else {
sprintf( output+strlen(output), "X:%d|", vid_win.x );
sprintf( output+strlen(output), "Y:%d|", vid_win.y );
sprintf( output+strlen(output), "W:%d|", vid_win.width );
sprintf( output+strlen(output), "H:%d|", vid_win.height );
output_ptr += sprintf(output_ptr, "X:%d|Y:%d|W:%d|H:%d|",
vid_win.height, vid_win.x, vid_win.y, vid_win.width);
}
struct video_picture vid_pic;
memset( &vid_pic, 0, sizeof(video_picture) );
if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic ) < 0 ) {
Error( "Failed to get picture attributes: %s", strerror(errno) );
memset(&vid_pic, 0, sizeof(video_picture));
if ( ioctl(vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) {
Error("Failed to get picture attributes: %s", strerror(errno));
if ( verbose )
sprintf( output, "Error, failed to get picture attributes: %s\n", strerror(errno) );
output_ptr += sprintf(output_ptr, "Error, failed to get picture attributes: %s\n", strerror(errno));
else
sprintf( output, "error%d\n", errno );
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
if ( verbose ) {
sprintf( output+strlen(output), "Picture Attributes\n" );
sprintf( output+strlen(output), " Palette: %d - %s\n", vid_pic.palette,
output_ptr += sprintf(output_ptr,
"Picture Attributes\n"
" Palette: %d - %s\n"
" Colour Depth: %d\n"
" Brightness: %d\n"
" Hue: %d\n"
" Colour :%d\n"
" Contrast: %d\n"
" Whiteness: %d\n"
, vid_pic.palette,
vid_pic.palette==VIDEO_PALETTE_GREY?"Linear greyscale":(
vid_pic.palette==VIDEO_PALETTE_HI240?"High 240 cube (BT848)":(
vid_pic.palette==VIDEO_PALETTE_RGB565?"565 16 bit RGB":(
@ -1659,66 +1689,77 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
vid_pic.palette==VIDEO_PALETTE_YUV411P?"YUV 4:1:1 Planar":(
vid_pic.palette==VIDEO_PALETTE_YUV420P?"YUV 4:2:0 Planar":(
vid_pic.palette==VIDEO_PALETTE_YUV410P?"YUV 4:1:0 Planar":"Unknown"
))))))))))))))))));
sprintf( output+strlen(output), " Colour Depth: %d\n", vid_pic.depth );
sprintf( output+strlen(output), " Brightness: %d\n", vid_pic.brightness );
sprintf( output+strlen(output), " Hue: %d\n", vid_pic.hue );
sprintf( output+strlen(output), " Colour :%d\n", vid_pic.colour );
sprintf( output+strlen(output), " Contrast: %d\n", vid_pic.contrast );
sprintf( output+strlen(output), " Whiteness: %d\n", vid_pic.whiteness );
))))))))))))))))),
vid_pic.depth,
vid_pic.brightness,
vid_pic.hue,
vid_pic.colour,
vid_pic.contrast,
vid_pic.whiteness
);
} else {
sprintf( output+strlen(output), "P:%d|", vid_pic.palette );
sprintf( output+strlen(output), "D:%d|", vid_pic.depth );
sprintf( output+strlen(output), "B:%d|", vid_pic.brightness );
sprintf( output+strlen(output), "h:%d|", vid_pic.hue );
sprintf( output+strlen(output), "Cl:%d|", vid_pic.colour );
sprintf( output+strlen(output), "Cn:%d|", vid_pic.contrast );
sprintf( output+strlen(output), "w:%d|", vid_pic.whiteness );
output_ptr += sprintf(output_ptr, "P:%d|D:%d|B:%d|h:%d|Cl:%d|Cn:%d|w:%d|",
vid_pic.palette,
vid_pic.depth,
vid_pic.brightness,
vid_pic.hue,
vid_pic.colour,
vid_pic.contrast,
vid_pic.whiteness
);
}
for ( int chan = 0; chan < vid_cap.channels; chan++ ) {
struct video_channel vid_src;
memset( &vid_src, 0, sizeof(video_channel) );
memset(&vid_src, 0, sizeof(video_channel));
vid_src.channel = chan;
if ( ioctl( vid_fd, VIDIOCGCHAN, &vid_src ) < 0 ) {
Error( "Failed to get channel %d attributes: %s", chan, strerror(errno) );
if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) {
Error("Failed to get channel %d attributes: %s", chan, strerror(errno));
if ( verbose )
sprintf( output, "Error, failed to get channel %d attributes: %s\n", chan, strerror(errno) );
output_ptr += sprintf(output_ptr, "Error, failed to get channel %d attributes: %s\n", chan, strerror(errno));
else
sprintf( output, "error%d\n", errno );
output_ptr += sprintf(output_ptr, "error%d\n", errno);
return false;
}
if ( verbose ) {
sprintf( output+strlen(output), "Channel %d Attributes\n", chan );
sprintf( output+strlen(output), " Name: %s\n", vid_src.name );
sprintf( output+strlen(output), " Channel: %d\n", vid_src.channel );
sprintf( output+strlen(output), " Flags: %d\n%s%s", vid_src.flags,
(vid_src.flags&VIDEO_VC_TUNER)?" Channel has a tuner\n":"",
(vid_src.flags&VIDEO_VC_AUDIO)?" Channel has audio\n":""
);
sprintf( output+strlen(output), " Type: %d - %s\n", vid_src.type,
output_ptr += sprintf(output_ptr,
"Channel %d Attributes\n"
" Name: %s\n"
" Channel: %d\n"
" Flags: %d\n%s%s"
" Type: %d - %s\n"
" Format: %d - %s\n"
, chan
, vid_src.name
, vid_src.channel
, vid_src.flags
, (vid_src.flags&VIDEO_VC_TUNER)?" Channel has a tuner\n":""
, (vid_src.flags&VIDEO_VC_AUDIO)?" Channel has audio\n":""
, vid_src.type,
vid_src.type==VIDEO_TYPE_TV?"TV":(
vid_src.type==VIDEO_TYPE_CAMERA?"Camera":"Unknown"
));
sprintf( output+strlen(output), " Format: %d - %s\n", vid_src.norm,
)
, vid_src.norm,
vid_src.norm==VIDEO_MODE_PAL?"PAL":(
vid_src.norm==VIDEO_MODE_NTSC?"NTSC":(
vid_src.norm==VIDEO_MODE_SECAM?"SECAM":(
vid_src.norm==VIDEO_MODE_AUTO?"AUTO":"Unknown"
))));
} else {
sprintf( output+strlen(output), "n%d:%s|", chan, vid_src.name );
sprintf( output+strlen(output), "C%d:%d|", chan, vid_src.channel );
sprintf( output+strlen(output), "Fl%d:%x|", chan, vid_src.flags );
sprintf( output+strlen(output), "T%d:%d|", chan, vid_src.type );
sprintf( output+strlen(output), "F%d:%d%s|", chan, vid_src.norm, chan==(vid_cap.channels-1)?"":"," );
output_ptr += sprintf(output_ptr, "n%d:%s|C%d:%d|Fl%d:%x|T%d:%d|F%d:%d%s|"
, chan, vid_src.name
, chan, vid_src.channel
, chan, vid_src.flags
, chan, vid_src.type
, chan, vid_src.norm, chan==(vid_cap.channels-1)?"":","
);
}
}
if ( !verbose )
output[strlen(output)-1] = '\n';
*output_ptr = '\n';
}
#endif // ZM_HAS_V4L1
close( vid_fd );
close(vid_fd);
if ( device )
break;
} while ( ++devIndex < 32 );

View File

@ -1 +1 @@
1.35.4
1.35.5

View File

@ -24,6 +24,7 @@ class Filter extends ZM_Object {
'AutoCopy' => 0,
'AutoCopyTo' => 0,
'UpdateDiskSpace' => 0,
'UserId' => 0,
'Background' => 0,
'Concurrent' => 0,
'Query_json' => '',

View File

@ -19,9 +19,9 @@ class Group extends ZM_Object {
public function delete() {
if ( property_exists($this, 'Id') ) {
dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}));
dbQuery('UPDATE Groups SET ParentId=NULL WHERE ParentId=?', array($this->{'Id'}));
dbQuery('DELETE FROM Groups WHERE Id=?', array($this->{'Id'}));
dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($this->{'Id'}));
dbQuery('UPDATE `Groups` SET `ParentId`=NULL WHERE `ParentId`=?', array($this->{'Id'}));
dbQuery('DELETE FROM `Groups` WHERE Id=?', array($this->{'Id'}));
if ( isset($_COOKIE['zmGroup']) ) {
if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) {
unset($_COOKIE['zmGroup']);
@ -47,7 +47,7 @@ class Group extends ZM_Object {
public function MonitorIds( ) {
if ( ! property_exists($this, 'MonitorIds') ) {
$this->{'MonitorIds'} = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}));
$this->{'MonitorIds'} = dbFetchAll('SELECT `MonitorId` FROM `Groups_Monitors` WHERE `GroupId`=?', 'MonitorId', array($this->{'Id'}));
}
return $this->{'MonitorIds'};
}
@ -65,7 +65,7 @@ class Group extends ZM_Object {
session_write_close();
}
return htmlSelect( 'GroupId[]', Group::get_dropdown_options(), isset($_SESSION['GroupId'])?$_SESSION['GroupId']:null, array(
return htmlSelect('GroupId[]', Group::get_dropdown_options(), isset($_SESSION['GroupId'])?$_SESSION['GroupId']:null, array(
'data-on-change' => 'submitThisForm',
'class'=>'chosen',
'multiple'=>'multiple',

View File

@ -306,7 +306,7 @@ class ZM_Object {
$fields = array_keys($fields);
if ( $this->Id() ) {
$sql = 'UPDATE '.$table.' SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?';
$sql = 'UPDATE `'.$table.'` SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?';
$values = array_map(function($field){ return $this->{$field};}, $fields);
$values[] = $this->{'Id'};
if ( dbQuery($sql, $values) )
@ -314,8 +314,8 @@ class ZM_Object {
} else {
unset($fields['Id']);
$sql = 'INSERT INTO '.$table.
' ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)).
$sql = 'INSERT INTO `'.$table.
'` ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)).
') VALUES ('.
implode(', ', array_map(function($field){return '?';}, $fields)).')';
@ -331,7 +331,7 @@ class ZM_Object {
public function delete() {
$class = get_class($this);
$table = $class::$table;
dbQuery("DELETE FROM $table WHERE Id=?", array($this->{'Id'}));
dbQuery("DELETE FROM `$table` WHERE Id=?", array($this->{'Id'}));
if ( isset($object_cache[$class]) and isset($object_cache[$class][$this->{'Id'}]) )
unset($object_cache[$class][$this->{'Id'}]);
}

50
web/includes/User.php Normal file
View File

@ -0,0 +1,50 @@
<?php
namespace ZM;
require_once('database.php');
require_once('Object.php');
class User extends ZM_Object {
protected static $table = 'Users';
protected $defaults = array(
'Id' => null,
'Username' => '',
'Password' => '',
'Language' => '',
'Enabled' => 1,
'Stream' => 'None',
'Events' => 'None',
'Control' => 'None',
'Monitors' => 'None',
'Groups' => 'None',
'Devices' => 'None',
'System'=> 'None',
'MaxBandwidth' =>'',
'MonitorIds' =>'',
'TokenMinExpiry' => 0,
'APIEnabled'=> 1,
);
public static function find( $parameters = array(), $options = array() ) {
return ZM_Object::_find(get_class(), $parameters, $options);
}
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(get_class(), $parameters, $options);
}
public function Name( ) {
return $this->{'Username'};
}
public static function Indexed_By_Id() {
$results = array();
foreach ( ZM_Object::_find('ZM\User', null, array('order'=>'lower(Username)')) as $Object ) {
$results[$Object->Id()] = $Object;
}
return $results;
}
} # end class User
?>

View File

@ -25,21 +25,28 @@ define('DB_LOG_DEBUG', 2);
$GLOBALS['dbLogLevel'] = DB_LOG_OFF;
$GLOBALS['dbConn'] = false;
require_once('logger.php');
function dbConnect() {
global $dbConn;
$dsn = ZM_DB_TYPE;
if ( ZM_DB_HOST ) {
if ( strpos(ZM_DB_HOST, ':') ) {
// Host variable may carry a port or socket.
list($host, $portOrSocket) = explode(':', ZM_DB_HOST, 2);
if ( ctype_digit($portOrSocket) ) {
$socket = ':host='.$host . ';port='.$portOrSocket;
$dsn .= ':host='.$host.';port='.$portOrSocket.';';
} else {
$socket = ':unix_socket='.$portOrSocket;
$dsn .= ':unix_socket='.$portOrSocket.';';
}
} else {
$socket = ':host='.ZM_DB_HOST;
$dsn .= ':host='.ZM_DB_HOST.';';
}
} else {
$dsn .= ':host=localhost;';
}
$dsn .= 'dbname='.ZM_DB_NAME;
try {
$dbOptions = null;
@ -49,21 +56,24 @@ function dbConnect() {
PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY,
PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT,
);
$dbConn = new PDO(ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions);
$dbConn = new PDO($dsn, ZM_DB_USER, ZM_DB_PASS, $dbOptions);
} else {
$dbConn = new PDO(ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS);
$dbConn = new PDO($dsn, ZM_DB_USER, ZM_DB_PASS);
}
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $ex) {
echo 'Unable to connect to ZM db.' . $ex->getMessage();
echo "Unable to connect to ZM db using dsn $dsn host".ZM_DB_HOST.' user: ('.ZM_DB_USER.') password ('.ZM_DB_PASS.': '.$ex->getMessage();
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
$dbConn = null;
}
}
return $dbConn;
} // end function dbConnect
dbConnect();
if ( !dbConnect() ) {
ZM\Fatal('Failed db connection');
}
function dbDisconnect() {
global $dbConn;

View File

@ -1505,15 +1505,15 @@ function getLoad() {
function getDiskPercent($path = ZM_DIR_EVENTS) {
$total = disk_total_space($path);
if ( $total === false ) {
Error('disk_total_space returned false. Verify the web account user has access to ' . $path);
ZM\Error('disk_total_space returned false. Verify the web account user has access to ' . $path);
return 0;
} elseif ( $total == 0 ) {
Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path);
ZM\Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path);
return 100;
}
$free = disk_free_space($path);
if ( $free === false ) {
Error('disk_free_space returned false. Verify the web account user has access to ' . $path);
ZM\Error('disk_free_space returned false. Verify the web account user has access to ' . $path);
}
$space = round((($total - $free) / $total) * 100);
return $space;
@ -2069,7 +2069,7 @@ function logState() {
if ( $count['Level'] <= ZM\Logger::PANIC )
$count['Level'] = ZM\Logger::FATAL;
if ( !($levelCount = $levelCounts[$count['Level']]) ) {
Error('Unexpected Log level '.$count['Level']);
ZM\Error('Unexpected Log level '.$count['Level']);
next;
}
if ( $levelCount[1] && $count['LevelCount'] >= $levelCount[1] ) {

View File

@ -100,14 +100,17 @@ class Logger {
$tempDatabaseLevel = $options['databaseLevel'];
else
$tempDatabaseLevel = ZM_LOG_LEVEL_DATABASE;
if ( isset($options['fileLevel']) )
$tempFileLevel = $options['fileLevel'];
else
$tempFileLevel = ZM_LOG_LEVEL_FILE;
if ( isset($options['weblogLevel']) )
$tempWeblogLevel = $options['weblogLevel'];
else
$tempWeblogLevel = ZM_LOG_LEVEL_WEBLOG;
if ( isset($options['syslogLevel']) )
$tempSyslogLevel = $options['syslogLevel'];
else

View File

@ -376,6 +376,7 @@ $SLANG = array(
'Filters' => 'Filters',
'FilterUnset' => 'You must specify a filter width and height',
'FilterUploadEvents' => 'Upload all matches',
'FilterUser' => 'User to run filter as',
'FilterVideoEvents' => 'Create video for all matches',
'First' => 'First',
'FlippedHori' => 'Flipped Horizontally',

View File

@ -205,6 +205,7 @@ getBodyTopHTML();
<?php
ob_start();
?>
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed consoleTable">
<thead class="thead-highlight">
<tr>
@ -394,5 +395,6 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
</tfoot>
</table>
</div>
</div>
</form>
<?php xhtmlFooter() ?>

View File

@ -27,6 +27,7 @@ require_once('includes/Storage.php');
require_once('includes/Filter.php');
require_once('includes/Monitor.php');
require_once('includes/Zone.php');
require_once('includes/User.php');
parseSort();
$filterNames = array(''=>translate('ChooseFilter'));
@ -200,6 +201,18 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )
<label for="filter[Name]"><?php echo translate('Name') ?></label>
<input type="text" id="filter[Name]" name="filter[Name]" value="<?php echo validHtmlStr($filter->Name()) ?>" data-on-input-this="updateButtons"/>
</p>
<?php if ( ZM_OPT_USE_AUTH ) { ?>
<p><label><?php echo translate('FilterUser') ?></label>
<?php
global $user;
echo htmlSelect('filter[UserId]',
ZM\User::Indexed_By_Id(),
//ZM\User::find(),
$filter->UserId() ? $filter->UserId() : $user['Id']
); ?>
</p>
<?php } ?>
<p>
<table id="fieldsTable" class="filterTable">
<tbody>
<?php

View File

@ -308,7 +308,7 @@ function pauseClicked() {
streamPause();
}
function streamPause( ) {
function streamPause() {
$j('#modeValue').html('Paused');
setButtonState( $('pauseBtn'), 'active' );
setButtonState( $('playBtn'), 'inactive' );

View File

@ -747,9 +747,11 @@ function fetchImage( streamImage ) {
}
function handleClick( event ) {
var target = event.target;
var x = event.page.x - $(target).getLeft();
var y = event.page.y - $(target).getTop();
var $target = $(event.target);
var scaleX = parseInt(monitorWidth / $target.getWidth());
var scaleY = parseInt(monitorHeight / $target.getHeight());
var x = (event.page.x - $target.getLeft()) * scaleX;
var y = (event.page.y - $target.getTop()) * scaleY;
if ( showMode == 'events' || !imageControlMode ) {
if ( event.shift ) {
@ -848,7 +850,7 @@ function initPage() {
if ( refreshApplet && appletRefreshTime ) {
appletRefresh.delay(appletRefreshTime*1000);
}
if ( scale == 'auto' ) changeScale();
if ( scale == '0' || scale == 'auto' ) changeScale();
if ( window.history.length == 1 ) {
$j('#closeControl').html('');
}

View File

@ -179,12 +179,16 @@ function toPixels(field, maxValue) {
if ( field.value != '' ) {
field.value = Math.round((field.value*maxValue)/100);
}
field.setAttribute('step', 1);
field.setAttribute('max', monitorArea);
}
function toPercent(field, maxValue) {
if ( field.value != '' ) {
field.value = Math.round((100*100*field.value)/maxValue)/100;
}
field.setAttribute('step', 0.01);
field.setAttribute('max', 100);
}
function applyZoneUnits() {
@ -384,7 +388,7 @@ function saveChanges(element) {
if ( validateForm(form) ) {
submitForm(form);
if ( form.elements['newZone[Type]'].value == 'Privacy' ) {
alert( 'Capture process for this monitor will be restarted for the Privacy zone changes to take effect.' );
alert('Capture process for this monitor will be restarted for the Privacy zone changes to take effect.');
}
return true;
}

View File

@ -151,11 +151,11 @@ if ( $showControl ) {
}
if ( $showZones ) {
?>
<a id="ShowZones" href="?view=montage&amp;showZones=0">Hide Zones</a>
<a id="HideZones" href="?view=montage&amp;showZones=0"><?php echo translate('Hide Zones')?></a>
<?php
} else {
?>
<a id="ShowZones" href="?view=montage&amp;showZones=1">Show Zones</a>
<a id="ShowZones" href="?view=montage&amp;showZones=1"><?php echo translate('Show Zones')?></a>
<?php
}
?>

View File

@ -96,12 +96,14 @@ function probeProfiles($device_ep, $soapversion, $username, $password) {
if ( $lines = @execONVIF("profiles $device_ep $soapversion $username $password") ) {
foreach ( $lines as $line ) {
$line = rtrim( $line );
if ( preg_match('|^(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+)\s*$|', $line, $matches) ) {
$stream_uri = $matches[7];
if ( preg_match('|^([^,]+),\s*([^,]+),\s*([^,]+),\s*(\d+),\s*(\d+),\s*(\d+),\s*([^,]+),\s*(.+)\s*$|', $line, $matches) ) {
$stream_uri = $matches[8];
// add user@pass to URI
if ( preg_match('|^(\S+://)(.+)$|', $stream_uri, $tokens) ) {
$stream_uri = $tokens[1].$username.':'.$password.'@'.$tokens[2];
}
ZM\Warning(print_r($matches,1));
$profile = array( # 'monitor' part of camera
'Type' => 'Ffmpeg',
@ -113,6 +115,7 @@ function probeProfiles($device_ep, $soapversion, $username, $password) {
'Profile' => $matches[1],
'Name' => $matches[2],
'Encoding' => $matches[3],
'Transport' => $matches[7],
);
$profiles[] = $profile;
} else {
@ -261,10 +264,17 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
$monitor = $camera['monitor'];
$sourceString = "${profile['Name']} : ${profile['Encoding']}" .
" (${profile['Width']}x${profile['Height']} @ ${profile['MaxFPS']}fps)";
" (${profile['Width']}x${profile['Height']} @ ${profile['MaxFPS']}fps ${profile['Transport']})";
// copy technical details
$monitor['Width'] = $profile['Width'];
$monitor['Height'] = $profile['Height'];
if ( $profile['Transport'] == 'RTP-Multicast' ) {
$monitor['Method'] = 'rtpMulti';
} else if ( $profile['Transport'] == 'RTP-Unicast' ) {
$monitor['Method'] = 'rtpUni';
} else {
$monitor['Method'] = 'rtpRtsp';
}
// The maxfps fields do not work for ip streams. Can re-enable if that is fixed.
// $monitor['MaxFPS'] = $profile['MaxFPS'];
// $monitor['AlarmMaxFPS'] = $profile['AlarmMaxFPS'];

View File

@ -174,29 +174,36 @@ xhtmlHeaders(__FILE__, translate('Zone'));
<tr>
<th scope="row"><?php echo translate('Type') ?></th>
<td colspan="2"><?php echo htmlSelect('newZone[Type]', $optTypes, $newZone['Type'],
array('onchange'=>'applyZoneType()')); ?></td>
array('data-on-change'=>'applyZoneType')); ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Preset') ?></th>
<td colspan="2">
<?php echo htmlSelect('presetSelector', $presetNames,
( isset($_REQUEST['presetSelector']) ? $_REQUEST['presetSelector'] : null),
array('onchange'=>'applyPreset()', 'onblur'=>'this.selectedIndex=0') )
array('data-on-change'=>'applyPreset', 'onblur'=>'this.selectedIndex=0') )
?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Units') ?></th>
<td colspan="2"><?php echo htmlSelect('newZone[Units]', $optUnits, $newZone['Units'],
array('onchange'=>'applyZoneUnits()') ) ?></td>
<td colspan="2">
<?php
echo htmlSelect('newZone[Units]', $optUnits, $newZone['Units'],
array('data-on-change'=>'applyZoneUnits')
);
# Used later for number inputs
$step = $newZone['Units'] == 'Percent' ? ' step="0.01" max="100"' : '';
?>
</td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneAlarmColour') ?></th>
<td colspan="2">
<input type="number" name="newAlarmRgbR" value="<?php echo ($newZone['AlarmRGB']>>16)&0xff ?>" size="3"/>
<input type="number" name="newAlarmRgbR" value="<?php echo ($newZone['AlarmRGB']>>16)&0xff ?>" min="0" max="255"/>
/
<input type="number" name="newAlarmRgbG" value="<?php echo ($newZone['AlarmRGB']>>8)&0xff ?>" size="3"/>
<input type="number" name="newAlarmRgbG" value="<?php echo ($newZone['AlarmRGB']>>8)&0xff ?>" min="0" max="255"/>
/
<input type="number" name="newAlarmRgbB" value="<?php echo $newZone['AlarmRGB']&0xff ?>" size="3"/>
<input type="number" name="newAlarmRgbB" value="<?php echo $newZone['AlarmRGB']&0xff ?>" min="0" max="255"/>
</td>
</tr>
<tr>
@ -205,45 +212,45 @@ xhtmlHeaders(__FILE__, translate('Zone'));
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneMinMaxPixelThres') ?></th>
<td><input type="number" name="newZone[MinPixelThreshold]" value="<?php echo $newZone['MinPixelThreshold'] ?>" size="4"/></td>
<td><input type="number" name="newZone[MaxPixelThreshold]" value="<?php echo $newZone['MaxPixelThreshold'] ?>" size="4"/></td>
<td><input type="number" name="newZone[MinPixelThreshold]" value="<?php echo $newZone['MinPixelThreshold'] ?>"/></td>
<td><input type="number" name="newZone[MaxPixelThreshold]" value="<?php echo $newZone['MaxPixelThreshold'] ?>"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneFilterSize') ?></th>
<td><input type="number" name="newZone[FilterX]" value="<?php echo $newZone['FilterX'] ?>" size="4"/></td>
<td><input type="number" name="newZone[FilterY]" value="<?php echo $newZone['FilterY'] ?>" size="4"/></td>
<td><input type="number" name="newZone[FilterX]" value="<?php echo $newZone['FilterX'] ?>"/></td>
<td><input type="number" name="newZone[FilterY]" value="<?php echo $newZone['FilterY'] ?>"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneArea') ?></th>
<td colspan="2"><input type="number" name="newZone[TempArea]" value="<?php echo $newZone['Area'] ?>" size="7" disabled="disabled"/></td>
<td colspan="2"><input type="number" name="newZone[TempArea]" value="<?php echo $newZone['Area'] ?>" disabled="disabled"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneMinMaxAlarmArea') ?></th>
<td><input type="number" name="newZone[MinAlarmPixels]" value="<?php echo $newZone['MinAlarmPixels'] ?>" size="6"/></td>
<td><input type="number" name="newZone[MaxAlarmPixels]" value="<?php echo $newZone['MaxAlarmPixels'] ?>" size="6"/></td>
<td><input type="number" name="newZone[MinAlarmPixels]" value="<?php echo $newZone['MinAlarmPixels'] ?>"<?php echo $step ?> min="0"/></td>
<td><input type="number" name="newZone[MaxAlarmPixels]" value="<?php echo $newZone['MaxAlarmPixels'] ?>"<?php echo $step ?> min="0"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneMinMaxFiltArea') ?></th>
<td><input type="number" name="newZone[MinFilterPixels]" value="<?php echo $newZone['MinFilterPixels'] ?>" size="6"/></td>
<td><input type="number" name="newZone[MaxFilterPixels]" value="<?php echo $newZone['MaxFilterPixels'] ?>" size="6"/></td>
<td><input type="number" name="newZone[MinFilterPixels]" value="<?php echo $newZone['MinFilterPixels'] ?>"<?php echo $step ?> min="0"/></td>
<td><input type="number" name="newZone[MaxFilterPixels]" value="<?php echo $newZone['MaxFilterPixels'] ?>"<?php echo $step ?> min="0"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneMinMaxBlobArea') ?></th>
<td><input type="number" name="newZone[MinBlobPixels]" value="<?php echo $newZone['MinBlobPixels'] ?>" size="6"/></td>
<td><input type="number" name="newZone[MaxBlobPixels]" value="<?php echo $newZone['MaxBlobPixels'] ?>" size="6"/></td>
<td><input type="number" name="newZone[MinBlobPixels]" value="<?php echo $newZone['MinBlobPixels'] ?>"<?php echo $step ?> min="0"/></td>
<td><input type="number" name="newZone[MaxBlobPixels]" value="<?php echo $newZone['MaxBlobPixels'] ?>"<?php echo $step ?> min="0"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneMinMaxBlobs') ?></th>
<td><input type="number" name="newZone[MinBlobs]" value="<?php echo $newZone['MinBlobs'] ?>" size="4"/></td>
<td><input type="number" name="newZone[MaxBlobs]" value="<?php echo $newZone['MaxBlobs'] ?>" size="4"/></td>
<td><input type="number" name="newZone[MinBlobs]" value="<?php echo $newZone['MinBlobs'] ?>" min="0"/></td>
<td><input type="number" name="newZone[MaxBlobs]" value="<?php echo $newZone['MaxBlobs'] ?>" min="0"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneOverloadFrames') ?></th>
<td colspan="2"><input type="number" name="newZone[OverloadFrames]" value="<?php echo $newZone['OverloadFrames'] ?>" size="4"/></td>
<td colspan="2"><input type="number" name="newZone[OverloadFrames]" value="<?php echo $newZone['OverloadFrames'] ?>" min="0"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ZoneExtendAlarmFrames') ?></th>
<td colspan="2"><input type="number" name="newZone[ExtendAlarmFrames]" value="<?php echo $newZone['ExtendAlarmFrames'] ?>" size="4"/></td>
<td colspan="2"><input type="number" name="newZone[ExtendAlarmFrames]" value="<?php echo $newZone['ExtendAlarmFrames'] ?>" min="0"/></td>
</tr>
</tbody>
</table>