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

pull/2704/head
Isaac Connor 2019-09-09 17:09:26 -04:00
commit 02eb222f17
46 changed files with 881 additions and 836 deletions

View File

@ -37,8 +37,16 @@ env:
- SMPFLAGS=-j4 OS=fedora DIST=29 DOCKER_REPO=knnniggett/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic
- SMPFLAGS=-j4 OS=ubuntu DIST=disco
- SMPFLAGS=-j4 OS=debian DIST=buster
- SMPFLAGS=-j4 OS=debian DIST=stretch
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty ARCH=i386
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial ARCH=i386
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic ARCH=i386
- SMPFLAGS=-j4 OS=ubuntu DIST=disco ARCH=i386
- SMPFLAGS=-j4 OS=debian DIST=buster ARCH=i386
- SMPFLAGS=-j4 OS=debian DIST=stretch ARCH=i386
- SMPFLAGS=-j4 OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack
compiler:

View File

@ -31,7 +31,7 @@ Better methods exist today that do much of this for you. The current development
This is the recommended method to install ZoneMinder onto your system. ZoneMinder packages are maintained for the following distros:
- Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder)
- Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor)
- Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder)
- RHEL/CentOS and clones via [RPM Fusion](http://rpmfusion.org)
- Fedora via [RPM Fusion](http://rpmfusion.org)

View File

@ -293,6 +293,8 @@ CREATE TABLE `Filters` (
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
`AutoMove` tinyint(3) unsigned NOT NULL default '0',
`AutoMoveTo` smallint(5) unsigned NOT NULL default 0,
`AutoCopy` tinyint(3) unsigned NOT NULL default '0',
`AutoCopyTo` smallint(5) unsigned NOT NULL default 0,
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
`Background` tinyint(1) unsigned NOT NULL default '0',
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
@ -756,8 +758,18 @@ insert into Users VALUES (NULL,'admin','$2b$12$NHZsm6AM2f2LQVROriz79ul3D6DnmFiZC
-- Add a sample filter to purge the oldest 100 events when the disk is 95% full
--
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0/*AutoArchive*/,0/*AutoVideo*/,0/*AutoUpload*/,0/*AutoEmail*/,0/*AutoMessage*/,0/*AutoExecute*/,'',1/*AutoDelete*/,0/*AutoMove*/,0/*MoveTo*/,0/*UpdateDiskSpace*/,1/*Background*/,0/*Concurrent*/);
insert into Filters values (NULL,'Update DiskSpace','{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',0,0,0,0,0,0,'',0,0,0,1,1,0);
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',
0/*AutoArchive*/,
0/*AutoVideo*/,
0/*AutoUpload*/,
0/*AutoEmail*/,
0/*AutoMessage*/,
0/*AutoExecute*/,'',
1/*AutoDelete*/,
0/*AutoMove*/,0/*MoveTo*/,
0/*AutoCopy*/,0/*CopyTo*/,
0/*UpdateDiskSpace*/,1/*Background*/,0/*Concurrent*/);
insert into Filters values (NULL,'Update DiskSpace','{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',0,0,0,0,0,0,'',0,0,0,0,0,1,1,0);
--
-- Add in some sample control protocol definitions

View File

@ -3,8 +3,8 @@ Ubuntu
.. contents::
Easy Way: Ubuntu 18.04
----------------------
Easy Way: Ubuntu 18.04 (Bionic)
-------------------------------
These instructions are for a brand new ubuntu 18.04 system which does not have ZM
installed.
@ -15,6 +15,7 @@ achieve the same result by running:
::
sudo apt-get install tasksel
sudo tasksel install lamp-server
During installation it will ask you to set up a master/root password for the MySQL.
@ -39,19 +40,10 @@ guide you with a quick search.
following a new release of ZoneMinder. To use this repository instead of the
official Ubuntu repository, enter the following from the command line:
::
add-apt-repository ppa:iconnor/zoneminder
Please note that as of 1.32.0 We are creating a new PPA for each major version, as a means to prevent automatic upgrades from one major version to another. So instead of the above ppa line use the following:
::
add-apt-repository ppa:iconnor/zoneminder-1.32
If you are on Trusty or Xenial, you may want to add both, as there are some packages for dependencies included in the old ppa.
Update repo and upgrade.
::
@ -202,8 +194,8 @@ CTRL+x to exit
PPA install may need some tweaking of ZMS_PATH in ZoneMinder options. `Socket_sendto or no live streaming`_
Easy Way: Ubuntu 16.04
----------------------
Easy Way: Ubuntu 16.04 (Xenial)
-------------------------------
These instructions are for a brand new ubuntu 16.04 system which does not have ZM
installed.
@ -241,16 +233,8 @@ guide you with a quick search.
::
add-apt-repository ppa:iconnor/zoneminder
Please note that as of 1.32.0 We are creating a new PPA for each major version, as a means to prevent automatic upgrades from one major version to another. So instead of the above ppa line use the following:
::
add-apt-repository ppa:iconnor/zoneminder-1.32
If you are on Trusty or Xenial, you may want to add both, as there are some packages for dependencies included in the old ppa.
Update repo and upgrade.
::
@ -401,8 +385,8 @@ CTRL+x to exit
PPA install may need some tweaking of ZMS_PATH in ZoneMinder options. `Socket_sendto or no live streaming`_
Easy Way: Ubuntu 14.x
---------------------
Easy Way: Ubuntu 14.x (Trusty)
------------------------------
**These instructions are for a brand new ubuntu 14.x system which does not have ZM installed.**
**Step 1:** Either run commands in this install using sudo or use the below to become root

View File

@ -56,7 +56,8 @@ use ZoneMinder::Config qw(:all);
use ZoneMinder::Logger qw(:all);
use ZoneMinder::Database qw(:all);
use vars qw/ $table $primary_key %fields $serial @identified_by %defaults/;
use vars qw/ $table $primary_key %fields $serial @identified_by %defaults $debug/;
$debug = 0;
$table = 'Events';
@identified_by = ('Id');
$serial = $primary_key = 'Id';
@ -133,7 +134,11 @@ sub Path {
if ( ! $$event{Path} ) {
my $Storage = $event->Storage();
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
if ( defined $Storage->Id() ) {
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
} else {
Error("Storage area for $$event{StorageId} no longer exists in db.");
}
}
return $$event{Path};
}
@ -365,7 +370,7 @@ sub delete {
if ( $$event{Id} ) {
# Need to have an event Id if we are to delete from the db.
Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime}");
Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime} from ".$event->Path());
$ZoneMinder::Database::dbh->ping();
$ZoneMinder::Database::dbh->begin_work();
@ -421,20 +426,24 @@ sub delete_files {
my $deleted = 0;
if ( $$Storage{Type} and ( $$Storage{Type} eq 's3fs' ) ) {
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$Storage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
my $url = $$Storage{Url};
$url =~ s/^(s3|s3fs):\/\///ig;
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket, $subpath ) = ( $url =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/([^\/]+)(\/.+)?\s*$/ );
Debug("S3 url parsed to id:$aws_id secret:$aws_secret host:$aws_host, bucket:$aws_bucket, subpath:$subpath\n from $url");
eval {
require Net::Amazon::S3;
my $s3 = Net::Amazon::S3->new( {
aws_access_key_id => $aws_id,
aws_secret_access_key => $aws_secret,
( $aws_host ? ( host => $aws_host ) : () ),
authorization_method => 'Net::Amazon::S3::Signature::V4',
});
my $bucket = $s3->bucket($aws_bucket);
if ( ! $bucket ) {
Error("S3 bucket $bucket not found.");
die;
}
if ( $bucket->delete_key($event_path) ) {
if ( $bucket->delete_key($subpath.$event_path) ) {
$deleted = 1;
} else {
Error('Failed to delete from S3:'.$s3->err . ': ' . $s3->errstr);
@ -464,7 +473,7 @@ sub StorageId {
if ( @_ ) {
$$event{StorageId} = shift;
delete $$event{Storage};
delete $$event{Path};
$event->Path(undef);
}
return $$event{StorageId};
}
@ -474,7 +483,7 @@ sub Storage {
$_[0]{Storage} = $_[1];
if ( $_[0]{Storage} ) {
$_[0]{StorageId} = $_[0]{Storage}->Id();
delete $_[0]{Path};
$_[0]->Path(undef);
}
}
if ( ! $_[0]{Storage} ) {
@ -534,7 +543,7 @@ sub CopyTo {
my $OldStorage = $self->Storage(undef);
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
if ( ! -e $OldPath ) {
return "Old path $OldPath does not exist.";
return "Src path $OldPath does not exist.";
}
# First determine if we can move it to the dest.
# We do this before bothering to lock the event
@ -545,8 +554,12 @@ sub CopyTo {
return 'Event is already located at ' . $NewPath;
} elsif ( !$NewPath ) {
return "New path ($NewPath) is empty.";
} elsif ( ! -e $NewPath ) {
return "New path $NewPath does not exist.";
} elsif ( ($$NewStorage{Type} ne 's3fs' ) and ! -e $NewPath ) {
if ( ! mkdir($NewPath) ) {
return "New path $NewPath does not exist.";
}
} else {
Debug("$NewPath is good");
}
$ZoneMinder::Database::dbh->begin_work();
@ -562,8 +575,9 @@ sub CopyTo {
return 'Old Storage path changed, Event has moved somewhere else.';
}
$NewPath .= $self->Relative_Path();
$NewPath = ( $NewPath =~ /^(.*)$/ ); # De-taint
Debug("Relative Path: " . $self->RelativePath());
$NewPath .= '/'.$self->RelativePath();
($NewPath) = ( $NewPath =~ /^(.*)$/ ); # De-taint
if ( $NewPath eq $OldPath ) {
$ZoneMinder::Database::dbh->commit();
return "New path and old path are the same! $NewPath";
@ -574,7 +588,10 @@ sub CopyTo {
if ( $$NewStorage{Type} eq 's3fs' ) {
if ( $$NewStorage{Url} ) {
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$NewStorage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
my $url = $$NewStorage{Url};
$url =~ s/^(s3|s3fs):\/\///ig;
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket, $subpath ) = ( $url =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/([^\/]+)(\/.+)?\s*$/ );
Debug("S3 url parsed to id:$aws_id secret:$aws_secret host:$aws_host, bucket:$aws_bucket, subpath:$subpath\n from $url");
if ( $aws_id and $aws_secret and $aws_host and $aws_bucket ) {
eval {
require Net::Amazon::S3;
@ -583,6 +600,7 @@ sub CopyTo {
aws_access_key_id => $aws_id,
aws_secret_access_key => $aws_secret,
( $aws_host ? ( host => $aws_host ) : () ),
authorization_method => 'Net::Amazon::S3::Signature::V4',
});
my $bucket = $s3->bucket($aws_bucket);
if ( !$bucket ) {
@ -590,10 +608,12 @@ sub CopyTo {
die;
}
my $event_path = $self->RelativePath();
Debug("Making directory $event_path/");
if ( ! $bucket->add_key($event_path.'/', '') ) {
die "Unable to add key for $event_path/";
my $event_path = $subpath.$self->RelativePath();
if ( 0 ) { # Not neccessary
Debug("Making directory $event_path/");
if ( !$bucket->add_key($event_path.'/', '') ) {
Warning("Unable to add key for $event_path/ :". $s3->err . ': '. $s3->errstr());
}
}
my @files = glob("$OldPath/*");
@ -607,15 +627,23 @@ sub CopyTo {
if ( ! $size ) {
Info('Not moving file with 0 size');
}
my $file_contents = File::Slurp::read_file($file);
if ( ! $file_contents ) {
die 'Loaded empty file, but it had a size. Giving up';
if ( 0 ) {
my $file_contents = File::Slurp::read_file($file);
if ( ! $file_contents ) {
die 'Loaded empty file, but it had a size. Giving up';
}
my $filename = $event_path.'/'.File::Basename::basename($file);
if ( ! $bucket->add_key($filename, $file_contents) ) {
die "Unable to add key for $filename : ".$s3->err . ': ' . $s3->errstr;
}
} else {
my $filename = $event_path.'/'.File::Basename::basename($file);
if ( ! $bucket->add_key_filename($filename, $file) ) {
die "Unable to add key for $filename " . $s3->err . ': '. $s3->errstr;
}
}
my $filename = $event_path.'/'.File::Basename::basename($file);
if ( ! $bucket->add_key($filename, $file_contents) ) {
die "Unable to add key for $filename";
}
my $duration = tv_interval($starttime);
Debug('PUT to S3 ' . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($duration?$size/$duration:$size) . '/sec');
} # end foreach file.
@ -782,6 +810,33 @@ sub recover_timestamps {
}
}
sub files {
my $self = shift;
if ( ! $$self{files} ) {
if ( ! opendir(DIR, $self->Path() ) ) {
Error("Can't open directory '$$self{Path}': $!");
return;
}
@{$$self{files}} = readdir(DIR);
Debug('Have ' . @{$$self{files}} . " files in $$self{Path}");
closedir(DIR);
}
return @{$$self{files}};
}
sub has_capture_jpegs {
@{$_[0]{capture_jpegs}} = grep(/^\d+\-capture\.jpg$/, $_[0]->files());
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");
return @{$_[0]{analyse_jpegs}} ? 1 : 0;
}
1;
__END__

View File

@ -95,32 +95,32 @@ sub new {
sub load {
my ( $self, $data ) = @_;
my $type = ref $self;
if ( ! $data ) {
if ( !$data ) {
no strict 'refs';
my $table = ${$type.'::table'};
if ( ! $table ) {
Error( 'NO table for type ' . $type );
Error('No table for type '.$type);
return;
} # end if
my $primary_key = ${$type.'::primary_key'};
if ( ! $primary_key ) {
Error( 'NO primary_key for type ' . $type );
if ( !$primary_key ) {
Error('No primary_key for type '.$type);
return;
} # end if
if ( ! $$self{$primary_key} ) {
my ( $caller, undef, $line ) = caller;
Error( (ref $self) . "::load called without $primary_key from $caller:$line");
Error("$type ::load called without $primary_key from $caller:$line");
} else {
#$log->debug("Object::load Loading from db $type");
Debug("Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
$data = $ZoneMinder::Database::dbh->selectrow_hashref( "SELECT * FROM $table WHERE $primary_key=?", {}, $$self{$primary_key} );
if ( ! $data ) {
$data = $ZoneMinder::Database::dbh->selectrow_hashref("SELECT * FROM `$table` WHERE `$primary_key`=?", {}, $$self{$primary_key});
if ( !$data ) {
if ( $ZoneMinder::Database::dbh->errstr ) {
Error( "Failure to load Object record for $$self{$primary_key}: Reason: " . $ZoneMinder::Database::dbh->errstr );
} else {
Debug("No Results Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
} # end if
delete $$self{$primary_key};
} # end if
} # end if
} # end if ! $data
@ -137,26 +137,26 @@ sub lock_and_load {
no strict 'refs';
my $table = ${$type.'::table'};
if ( ! $table ) {
Error('NO table for type ' . $type);
Error('NO table for type '.$type);
return;
} # end if
my $primary_key = ${$type.'::primary_key'};
if ( ! $primary_key ) {
Error('NO primary_key for type ' . $type);
if ( !$primary_key ) {
Error('No primary_key for type ' . $type);
return;
} # end if
if ( ! $$self{$primary_key} ) {
if ( !$$self{$primary_key} ) {
my ( $caller, undef, $line ) = caller;
Error("$type ::lock_and_load called without $primary_key from $caller:$line");
return;
}
Debug("Lock and Load $type from $table WHERE $primary_key = $$self{$primary_key}");
my $data = $ZoneMinder::Database::dbh->selectrow_hashref("SELECT * FROM $table WHERE $primary_key=? FOR UPDATE", {}, $$self{$primary_key});
my $data = $ZoneMinder::Database::dbh->selectrow_hashref("SELECT * FROM `$table` WHERE `$primary_key`=? FOR UPDATE", {}, $$self{$primary_key});
if ( ! $data ) {
if ( $ZoneMinder::Database::dbh->errstr ) {
Error("Failure to load Object record for $$self{$primary_key}: Reason: " . $ZoneMinder::Database::dbh->errstr);
Error("Failure to load Object record for $$self{$primary_key}: Reason: ".$ZoneMinder::Database::dbh->errstr);
} else {
Debug("No Results Lock and Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
} # end if
@ -216,12 +216,12 @@ sub save {
$log->debug("No serial") if $debug;
# No serial columns defined, which means that we will do saving by delete/insert instead of insert/update
if ( @identified_by ) {
my $where = join(' AND ', map { $$fields{$_}.'=?' } @identified_by );
my $where = join(' AND ', map { '`'.$$fields{$_}.'`=?' } @identified_by );
if ( $debug ) {
$log->debug("DELETE FROM $table WHERE $where");
$log->debug("DELETE FROM `$table` WHERE $where");
} # end if
if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM $table WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) {
if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM `$table` WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) {
$where =~ s/\?/\%s/g;
$log->error("Error deleting: DELETE FROM $table WHERE " . sprintf($where, map { defined $_ ? $_ : 'undef' } ( @$self{@identified_by}) ).'):' . $local_dbh->errstr);
$local_dbh->rollback();
@ -240,7 +240,7 @@ $log->debug("No serial") if $debug;
next;
}
if ( ! $$self{$id} ) {
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'};
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE `table_name` = '$table'};
($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( $s );
#($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} );
@ -252,7 +252,7 @@ $log->debug("No serial") if $debug;
if ( $insert ) {
my @keys = keys %sql;
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
my $command = "INSERT INTO `$table` (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
if ( ! ( ( $_ = $local_dbh->prepare($command) ) and $_->execute( @sql{@keys} ) ) ) {
my $error = $local_dbh->errstr;
$command =~ s/\?/\%s/g;
@ -267,7 +267,7 @@ $log->debug("No serial") if $debug;
} # end if
} else {
my @keys = keys %sql;
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $_ . ' = ?' } @$fields{@identified_by} );
my $command = "UPDATE `$table` SET " . join(',', map { '`'.$_ . '` = ?' } @keys ) . ' WHERE ' . join(' AND ', map { '`'.$_ . '` = ?' } @$fields{@identified_by} );
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys,@$fields{@identified_by}} ) ) ) {
my $error = $local_dbh->errstr;
$command =~ s/\?/\%s/g;
@ -293,12 +293,12 @@ $log->debug("No serial") if $debug;
if ( $need_serial ) {
if ( $serial ) {
$log->debug("Getting auto_increments");
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'};
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE `table_name` = '$table'};
@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( $s );
#@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} );
if ( $local_dbh->errstr() ) {
$log->error("Error getting next id. " . $local_dbh->errstr() );
$log->error("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
$log->error("Error getting next id. " . $local_dbh->errstr() ."\n".
"SQL statement execution $s returned ".join(',',@$self{@identified_by}));
} elsif ( $debug or DEBUG_ALL ) {
$log->debug("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
} # end if
@ -306,7 +306,7 @@ $log->debug("No serial") if $debug;
} # end if
my @keys = keys %sql;
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
my $command = "INSERT INTO `$table` (" . join(',', map { '`'.$_.'`' } @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys} ) ) ) {
$command =~ s/\?/\%s/g;
my $error = $local_dbh->errstr;
@ -325,7 +325,7 @@ $log->debug("No serial") if $debug;
my %identified_by = map { $_, $_ } @identified_by;
@keys = map { $identified_by{$_} ? () : $$fields{$_} } @keys;
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $$fields{$_} .'= ?' } @identified_by );
my $command = "UPDATE `$table` SET " . join(',', map { '`'.$_ . '` = ?' } @keys ) . ' WHERE ' . join(' AND ', map { '`'.$$fields{$_} .'`= ?' } @identified_by );
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys}, @sql{@$fields{@identified_by}} ) ) ) {
my $error = $local_dbh->errstr;
$command =~ s/\?/\%s/g;

View File

@ -201,12 +201,12 @@ MAIN: while( $loop ) {
my %Monitors;
my $db_monitors;
my $monitorSelectSql = $monitor_id ? 'SELECT * FROM Monitors WHERE Id=?' : 'SELECT * FROM Monitors ORDER BY Id';
my $monitorSelectSql = $monitor_id ? 'SELECT * FROM `Monitors` WHERE `Id`=?' : 'SELECT * FROM `Monitors` ORDER BY `Id`';
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql )
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
my $eventSelectSql = 'SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) AS Age
FROM Events WHERE MonitorId = ?'.(@Storage_Areas ? ' AND StorageId IN ('.join(',',map { '?'} @Storage_Areas).')' : '' ). ' ORDER BY Id';
my $eventSelectSql = 'SELECT `Id`, (unix_timestamp() - unix_timestamp(`StartTime`)) AS Age
FROM `Events` WHERE `MonitorId` = ?'.(@Storage_Areas ? ' AND `StorageId` IN ('.join(',',map { '?'} @Storage_Areas).')' : '' ). ' ORDER BY `Id`';
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() );
@ -222,7 +222,7 @@ MAIN: while( $loop ) {
while ( my $event = $eventSelectSth->fetchrow_hashref() ) {
$db_events->{$event->{Id}} = $event->{Age};
}
Debug( 'Got '.int(keys(%$db_events))." events for monitor $monitor->{Id}" );
Debug('Got '.int(keys(%$db_events))." events for monitor $monitor->{Id} using $eventSelectSql");
} # end while monitors
my $fs_monitors;
@ -245,7 +245,7 @@ MAIN: while( $loop ) {
next;
}
Debug( "Found filesystem monitor '$monitor'" );
Debug("Found filesystem monitor '$monitor'");
$fs_monitors->{$monitor} = {} if ! $fs_monitors->{$monitor};
my $fs_events = $fs_monitors->{$monitor};
@ -256,19 +256,19 @@ MAIN: while( $loop ) {
my @day_dirs = glob("$monitor_dir/[0-9][0-9]/[0-9][0-9]/[0-9][0-9]");
Debug(qq`Checking for Deep Events under $$Storage{Path} using glob("$monitor_dir/[0-9][0-9]/[0-9][0-9]/[0-9][0-9]") returned `. scalar @day_dirs . ' events');
foreach my $day_dir ( @day_dirs ) {
Debug( "Checking day dir $day_dir" );
Debug("Checking day dir $day_dir");
( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint
if ( !chdir($day_dir) ) {
Error("Can't chdir to '$$Storage{Path}/$day_dir': $!");
next;
}
if ( ! opendir(DIR, '.') ) {
if ( !opendir(DIR, '.') ) {
Error("Can't open directory '$$Storage{Path}/$day_dir': $!");
next;
}
my %event_ids_by_path;
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR );
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir(DIR);
Debug("Have " . @event_links . ' event links');
closedir(DIR);
@ -280,9 +280,9 @@ MAIN: while( $loop ) {
Warning("Non-event link found $event_link in $day_dir, skipping");
next;
}
Debug("Checking link $event_link");
#Event path is hour/minute/sec
my $event_path = readlink($event_link);
Debug("Checking link $event_link points to: $event_path");
if ( !($event_path and -e $event_path) ) {
aud_print("Event link $day_dir/$event_link does not point to valid target at $event_path");
@ -294,15 +294,50 @@ MAIN: while( $loop ) {
} else {
$event_ids_by_path{$event_path} = $event_id;
Debug("Checking link $event_link points to $event_path ");
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
$$Event{Id} = $event_id;
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_path);
$$Event{RelativePath} = join('/', $day_dir, $event_path);
$$Event{Scheme} = 'Deep';
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
$Event->DiskSpace( undef );
my $Event = $fs_events->{$event_id} = ZoneMinder::Event->find_one(Id=>$event_id);
if ( ! $Event ) {
$Event = $fs_events->{$event_id} = new ZoneMinder::Event();
$$Event{Id} = $event_id;
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_path);
$$Event{RelativePath} = join('/', $day_dir, $event_path);
$$Event{Scheme} = 'Deep';
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
$Event->DiskSpace( undef );
} else {
my $full_path = join('/', $Storage->Path(), $day_dir, $event_path);
# Check storage id
if ( !$Event->Storage()->Id() ) {
Info("Correcting StorageId for event $$Event{Id} from $$Event{StorageId} $$Event{Path} to $$Storage{Id} $full_path");
$Event->save({ StorageId=>$Storage->Id() });
$Event->Path(undef);
} else {
if ( $Event->Path() ne $full_path ) {
if ( ! (-e $Event->Path()) ) {
if ( $Event->StorageId() != $Storage->Id() ) {
Info("Correcting Storge Id for event $$Event{Id} from $$Event{StorageId} $$Event{Path} to $$Storage{Id} $full_path");
$Event->save({ StorageId=>$Storage->Id() });
$Event->Path(undef);
}
} else {
Info("Not updating path to event due to it existing at both $$Event{Path} and $event_path");
}
} # end if change of storage id
} # end if valid storage id
} # end if event found
if ( ! $Event->SaveJPEGs() ) {
my $saveJPegs = ( $Event->has_capture_jpegs() ? 1 : 0 ) | ( $Event->has_analyse_jpegs() ? 2 : 0 );
if ( $Event->SaveJPEGs(
( $Event->has_capture_jpegs() ? 1 : 0 ) | ( $Event->has_analyse_jpegs() ? 2 : 0 )
) ) {
Info("Updated Event $$Event{Id} SaveJPEGs to " . $Event->SaveJPEGs());
$Event->save();
}
}
} # event path exists
} # end foreach event_link
@ -314,14 +349,11 @@ MAIN: while( $loop ) {
( $event_dir ) = ( $event_dir =~ /^(.*)$/ ); # De-taint
my $event_id = undef;
my $Event = new ZoneMinder::Event();
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_dir);
if ( ! opendir(DIR, $event_dir) ) {
Error("Can't open directory '$$Storage{Path}/$day_dir': $!");
next;
}
my @contents = readdir( DIR );
my @contents = $Event->files();
Debug("Have " . @contents . " files in $day_dir/$event_dir");
closedir(DIR);
my @mp4_files = grep( /^\d+\-video.mp4$/, @contents);
foreach my $mp4_file ( @mp4_files ) {
@ -332,25 +364,27 @@ MAIN: while( $loop ) {
last;
}
}
if ( ! $event_id ) {
# Look for .id file
my @hidden_files = grep( /^\.\d+$/, @contents);
Debug("Have " . @hidden_files . ' hidden files');
Debug('Have ' . @hidden_files . ' hidden files');
if ( @hidden_files ) {
( $event_id ) = $hidden_files[0] =~ /^.(\d+)$/;
}
}
if ( $event_id and ! $fs_events->{$event_id} ) {
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
$fs_events->{$event_id} = $Event;
$$Event{Id} = $event_id;
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_dir);
$$Event{RelativePath} = join('/', $day_dir, $event_dir);
$$Event{Scheme} = 'Deep';
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
$Event->DiskSpace( undef );
$Event->SaveJPEGs(
( $Event->has_capture_jpegs() ? 1 : 0 ) | ( $Event->has_analyse_jpegs() ? 2 : 0 )
);
if ( ! $event_ids_by_path{$event_dir} ) {
Warning("No event link found at ".$Event->LinkPath() ." for " . $Event->to_string());
}
@ -373,8 +407,7 @@ MAIN: while( $loop ) {
}
aud_print("Deleting event directories with no event id information at $day_dir/$event_dir");
if ( confirm() ) {
my $command = "rm -rf $event_dir";
executeShellCommand( $command );
executeShellCommand("rm -rf $event_dir");
$cleaned = 1;
}
} # end if able to find id
@ -399,12 +432,12 @@ MAIN: while( $loop ) {
}
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
$$Event{Id} = $event_id;
$$Event{Path} = join('/', $Storage->Path(), $event_dir );
Debug("Have event $$Event{Id} at $$Event{Path}");
$$Event{Scheme} = 'Medium';
$$Event{RelativePath} = $event_dir;
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
$Event->Path();
Debug("Have event $$Event{Id} at $$Event{Path}");
$Event->StartTime( POSIX::strftime('%Y-%m-%d %H:%M:%S', gmtime(time_of_youngest_file($Event->Path())) ) );
} # end foreach event
}
@ -476,11 +509,10 @@ MAIN: while( $loop ) {
} # end if ! in db events
} # end foreach fs event
} else {
aud_print( "Filesystem monitor '$monitor_id' in $$Storage{Path} does not exist in database" );
aud_print("Filesystem monitor '$monitor_id' in $$Storage{Path} does not exist in database");
if ( confirm() ) {
my $command = "rm -rf $monitor_id";
executeShellCommand( $command );
executeShellCommand("rm -rf $monitor_id");
$cleaned = 1;
}
}
@ -494,8 +526,7 @@ MAIN: while( $loop ) {
aud_print("Filesystem monitor link '$link' does not point to valid monitor directory");
if ( confirm() ) {
( $link ) = ( $link =~ /^(.*)$/ ); # De-taint
my $command = qq`rm "$link"`;
executeShellCommand($command);
executeShellCommand(qq`rm "$link"`);
$cleaned = 1;
}
} # end foreach monitor link
@ -508,17 +539,17 @@ MAIN: while( $loop ) {
$cleaned = 0;
my $deleteMonitorSql = 'DELETE LOW_PRIORITY FROM Monitors WHERE Id = ?';
my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql )
or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() );
my $deleteMonitorSth = $dbh->prepare_cached($deleteMonitorSql)
or Fatal("Can't prepare '$deleteMonitorSql': ".$dbh->errstr());
my $deleteEventSql = 'DELETE LOW_PRIORITY FROM Events WHERE Id = ?';
my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql )
or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$deleteEventSql': ".$dbh->errstr());
my $deleteFramesSql = 'DELETE LOW_PRIORITY FROM Frames WHERE EventId = ?';
my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql )
or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$deleteFramesSql': ".$dbh->errstr());
my $deleteStatsSql = 'DELETE LOW_PRIORITY FROM Stats WHERE EventId = ?';
my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql )
or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$deleteStatsSql': ".$dbh->errstr());
# Foreach database monitor and it's list of events.
while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) ) {
@ -631,21 +662,21 @@ if ( $level > 1 ) {
# Shouldn't be possible anymore with FOREIGN KEYS in place
$cleaned = 0;
Debug("Checking for Orphaned Events");
my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name
FROM Events LEFT JOIN Monitors ON (Events.MonitorId = Monitors.Id)
WHERE isnull(Monitors.Id)';
my $selectOrphanedEventsSql = 'SELECT `Events`.`Id`, `Events`.`Name`
FROM `Events` LEFT JOIN `Monitors` ON (`Events`.`MonitorId` = `Monitors`.`Id`)
WHERE isnull(`Monitors`.`Id`)';
my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql )
or Error( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() );
or Error("Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr());
$res = $selectOrphanedEventsSth->execute()
or Error( "Can't execute: ".$selectOrphanedEventsSth->errstr() );
or Error("Can't execute: ".$selectOrphanedEventsSth->errstr());
while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() ) {
aud_print( "Found orphaned event with no monitor '$event->{Id}'" );
aud_print("Found orphaned event with no monitor '$event->{Id}'");
if ( confirm() ) {
if ( $res = $deleteEventSth->execute( $event->{Id} ) ) {
if ( $res = $deleteEventSth->execute($event->{Id}) ) {
$cleaned = 1;
} else {
Error( "Can't execute: ".$deleteEventSth->errstr() );
Error("Can't execute: ".$deleteEventSth->errstr());
}
}
}
@ -655,42 +686,42 @@ if ( $level > 1 ) {
# Remove empty events (with no frames)
$cleaned = 0;
Debug("Checking for Events with no Frames");
my $selectEmptyEventsSql = 'SELECT E.Id AS Id, E.StartTime, F.EventId FROM Events as E LEFT JOIN Frames as F ON (E.Id = F.EventId)
WHERE isnull(F.EventId) AND now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second > E.StartTime';
my $selectEmptyEventsSql = 'SELECT `E`.`Id` AS `Id`, `E`.`StartTime`, `F`.`EventId` FROM `Events` AS E LEFT JOIN `Frames` AS F ON (`E`.`Id` = `F`.`EventId`)
WHERE isnull(`F`.`EventId`) AND now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second > `E`.`StartTime`';
if ( my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) ) {
if ( $res = $selectEmptyEventsSth->execute() ) {
while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) {
aud_print( "Found empty event with no frame records '$event->{Id}' at $$event{StartTime}" );
aud_print("Found empty event with no frame records '$event->{Id}' at $$event{StartTime}");
if ( confirm() ) {
if ( $res = $deleteEventSth->execute( $event->{Id} ) ) {
if ( $res = $deleteEventSth->execute($event->{Id}) ) {
$cleaned = 1;
} else {
Error( "Can't execute: ".$deleteEventSth->errstr() );
Error("Can't execute: ".$deleteEventSth->errstr());
}
}
} # end foreach row
} else {
Error( "Can't execute: ".$selectEmptyEventsSth->errstr() );
Error("Can't execute: ".$selectEmptyEventsSth->errstr());
}
} else {
Error( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() );
Error("Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr());
}
redo MAIN if $cleaned;
# Remove orphaned frame records
$cleaned = 0;
Debug("Checking for Orphaned Frames");
my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames
WHERE (SELECT COUNT(*) FROM Events WHERE Events.Id=EventId)=0';
Debug('Checking for Orphaned Frames');
my $selectOrphanedFramesSql = 'SELECT DISTINCT `EventId` FROM `Frames`
WHERE (SELECT COUNT(*) FROM `Events` WHERE `Events`.`Id`=`EventId`)=0';
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql )
or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr());
$res = $selectOrphanedFramesSth->execute()
or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() );
or Fatal("Can't execute: ".$selectOrphanedFramesSth->errstr());
while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() ) {
aud_print( "Found orphaned frame records for event '$frame->{EventId}'" );
aud_print("Found orphaned frame records for event '$frame->{EventId}'");
if ( confirm() ) {
$res = $deleteFramesSth->execute( $frame->{EventId} )
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
$res = $deleteFramesSth->execute($frame->{EventId})
or Fatal("Can't execute: ".$deleteFramesSth->errstr());
$cleaned = 1;
}
}
@ -699,18 +730,18 @@ if ( $level > 1 ) {
if ( $level > 1 ) {
# Remove orphaned stats records
$cleaned = 0;
Debug("Checking for Orphaned Stats");
my $selectOrphanedStatsSql = 'SELECT DISTINCT EventId FROM Stats
WHERE EventId NOT IN (SELECT Id FROM Events)';
Debug('Checking for Orphaned Stats');
my $selectOrphanedStatsSql = 'SELECT DISTINCT `EventId` FROM `Stats`
WHERE `EventId` NOT IN (SELECT `Id` FROM `Events`)';
my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql )
or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr());
$res = $selectOrphanedStatsSth->execute()
or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() );
or Fatal("Can't execute: ".$selectOrphanedStatsSth->errstr());
while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() ) {
aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" );
aud_print("Found orphaned statistic records for event '$stat->{EventId}'");
if ( confirm() ) {
$res = $deleteStatsSth->execute( $stat->{EventId} )
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
or Fatal("Can't execute: ".$deleteStatsSth->errstr());
$cleaned = 1;
}
}
@ -732,44 +763,44 @@ if ( $level > 1 ) {
#WHERE isnull(E.Frames) or isnull(E.EndTime)
#GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}.' second)'
#;
'SELECT *, unix_timestamp(StartTime) AS TimeStamp FROM Events WHERE EndTime IS NULL AND StartTime < (now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second)';
'SELECT *, unix_timestamp(`StartTime`) AS `TimeStamp` FROM `Events` WHERE `EndTime` IS NULL AND `StartTime` < (now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second)';
my $selectFrameDataSql = '
SELECT
max(TimeStamp) as EndTime,
unix_timestamp(max(TimeStamp)) AS EndTimeStamp,
max(FrameId) as Frames,
count(if(Score>0,1,NULL)) as AlarmFrames,
sum(Score) as TotScore,
max(Score) as MaxScore
FROM Frames WHERE EventId=?';
max(`TimeStamp`) AS `EndTime`,
unix_timestamp(max(`TimeStamp`)) AS `EndTimeStamp`,
max(`FrameId`) AS `Frames`,
count(if(`Score`>0,1,NULL)) AS `AlarmFrames`,
sum(`Score`) AS `TotScore`,
max(`Score`) AS `MaxScore`
FROM `Frames` WHERE `EventId`=?';
my $selectFrameDataSth = $dbh->prepare_cached($selectFrameDataSql)
or Fatal( "Can't prepare '$selectFrameDataSql': ".$dbh->errstr() );
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql )
or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr());
my $updateUnclosedEventsSql =
"UPDATE low_priority Events
SET Name = ?,
EndTime = ?,
Length = ?,
Frames = ?,
AlarmFrames = ?,
TotScore = ?,
AvgScore = ?,
MaxScore = ?,
Notes = concat_ws( ' ', Notes, ? )
WHERE Id = ?"
"UPDATE low_priority `Events`
SET `Name` = ?,
`EndTime` = ?,
`Length` = ?,
`Frames` = ?,
`AlarmFrames` = ?,
`TotScore` = ?,
`AvgScore` = ?,
`MaxScore` = ?,
`Notes` = concat_ws( ' ', `Notes`, ? )
WHERE `Id` = ?"
;
my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql )
or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr());
$res = $selectUnclosedEventsSth->execute()
or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() );
or Fatal("Can't execute: ".$selectUnclosedEventsSth->errstr());
while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() ) {
aud_print( "Found open event '$event->{Id}' on Monitor $event->{MonitorId} at $$event{StartTime}" );
if ( confirm( 'close', 'closing' ) ) {
aud_print("Found open event '$event->{Id}' on Monitor $event->{MonitorId} at $$event{StartTime}");
if ( confirm('close', 'closing') ) {
if ( ! ( $res = $selectFrameDataSth->execute($event->{Id}) ) ) {
Error( "Can't execute: $selectFrameDataSql:".$selectFrameDataSth->errstr() );
Error("Can't execute: $selectFrameDataSql:".$selectFrameDataSth->errstr());
next;
}
my $frame = $selectFrameDataSth->fetchrow_hashref();
@ -802,7 +833,7 @@ FROM Frames WHERE EventId=?';
# Now delete any old image files
if ( my @old_files = grep { -M > $max_image_age } <$image_path/*.{jpg,gif,wbmp}> ) {
aud_print( 'Deleting '.int(@old_files)." old images\n" );
aud_print('Deleting '.int(@old_files)." old images\n");
my $untainted_old_files = join( ';', @old_files );
( $untainted_old_files ) = ( $untainted_old_files =~ /^(.*)$/ );
unlink( split( /;/, $untainted_old_files ) );
@ -816,21 +847,21 @@ FROM Frames WHERE EventId=?';
if ( $Config{ZM_LOG_DATABASE_LIMIT} ) {
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) {
# Number of rows
my $selectLogRowCountSql = 'SELECT count(*) AS Rows FROM Logs';
my $selectLogRowCountSql = 'SELECT count(*) AS `Rows` FROM `Logs`';
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$selectLogRowCountSql': ".$dbh->errstr());
$res = $selectLogRowCountSth->execute()
or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() );
or Fatal("Can't execute: ".$selectLogRowCountSth->errstr());
my $row = $selectLogRowCountSth->fetchrow_hashref();
my $logRows = $row->{Rows};
if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) {
my $deleteLogByRowsSql = 'DELETE low_priority FROM Logs ORDER BY TimeKey ASC LIMIT ?';
my $deleteLogByRowsSql = 'DELETE low_priority FROM `Logs` ORDER BY `TimeKey` ASC LIMIT ?';
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr());
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() );
or Fatal("Can't execute: ".$deleteLogByRowsSth->errstr());
if ( $deleteLogByRowsSth->rows() ) {
aud_print( 'Deleted '.$deleteLogByRowsSth->rows() ." log table entries by count\n" );
aud_print('Deleted '.$deleteLogByRowsSth->rows() ." log table entries by count\n");
}
}
} else {
@ -843,67 +874,67 @@ FROM Frames WHERE EventId=?';
my $deleted_rows;
do {
my $deleteLogByTimeSql =
'DELETE FROM Logs
WHERE TimeKey < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 10';
'DELETE FROM `Logs`
WHERE `TimeKey` < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 10';
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() );
or Fatal("Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr());
$res = $deleteLogByTimeSth->execute()
or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() );
or Fatal("Can't execute: ".$deleteLogByTimeSth->errstr());
$deleted_rows = $deleteLogByTimeSth->rows();
aud_print( "Deleted $deleted_rows log table entries by time\n" );
aud_print("Deleted $deleted_rows log table entries by time\n");
} while ( $deleted_rows );
}
} # end if ZM_LOG_DATABASE_LIMIT
$loop = $continuous;
my $eventcounts_sql = q`
UPDATE Monitors SET
TotalEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id),
TotalEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND DiskSpace IS NOT NULL),
ArchivedEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1),
ArchivedEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1 AND DiskSpace IS NOT NULL)
`;
my $eventcounts_sql = '
UPDATE `Monitors` SET
`TotalEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id`),
`TotalEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `DiskSpace` IS NOT NULL),
`ArchivedEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `Archived`=1),
`ArchivedEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `Archived`=1 AND `DiskSpace` IS NOT NULL)
';
my $eventcounts_sth = $dbh->prepare_cached( $eventcounts_sql );
$eventcounts_sth->execute();
$eventcounts_sth->finish();
my $eventcounts_hour_sql = q`
UPDATE Monitors INNER JOIN (
SELECT MonitorId, COUNT(*) AS HourEvents, SUM(COALESCE(DiskSpace,0)) AS HourEventDiskSpace
FROM Events_Hour GROUP BY MonitorId
) AS E ON E.MonitorId=Monitors.Id SET
Monitors.HourEvents = E.HourEvents,
Monitors.HourEventDiskSpace = E.HourEventDiskSpace
`;
my $eventcounts_hour_sql = '
UPDATE `Monitors` INNER JOIN (
SELECT `MonitorId`, COUNT(*) AS `HourEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `HourEventDiskSpace`
FROM `Events_Hour` GROUP BY `MonitorId`
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
`Monitors`.`HourEvents` = `E`.`HourEvents`,
`Monitors`.`HourEventDiskSpace` = `E`.`HourEventDiskSpace`
';
my $eventcounts_day_sql = q`
UPDATE Monitors INNER JOIN (
SELECT MonitorId, COUNT(*) AS DayEvents, SUM(COALESCE(DiskSpace,0)) AS DayEventDiskSpace
FROM Events_Day GROUP BY MonitorId
) AS E ON E.MonitorId=Monitors.Id SET
Monitors.DayEvents = E.DayEvents,
Monitors.DayEventDiskSpace = E.DayEventDiskSpace
`;
my $eventcounts_day_sql = '
UPDATE `Monitors` INNER JOIN (
SELECT `MonitorId`, COUNT(*) AS `DayEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `DayEventDiskSpace`
FROM `Events_Day` GROUP BY `MonitorId`
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
`Monitors`.`DayEvents` = `E`.`DayEvents`,
`Monitors`.`DayEventDiskSpace` = `E`.`DayEventDiskSpace`
';
my $eventcounts_week_sql = q`
UPDATE Monitors INNER JOIN (
SELECT MonitorId, COUNT(*) AS WeekEvents, SUM(COALESCE(DiskSpace,0)) AS WeekEventDiskSpace
FROM Events_Week GROUP BY MonitorId
) AS E ON E.MonitorId=Monitors.Id SET
Monitors.WeekEvents = E.WeekEvents,
Monitors.WeekEventDiskSpace = E.WeekEventDiskSpace
`;
my $eventcounts_week_sql = '
UPDATE `Monitors` INNER JOIN (
SELECT `MonitorId`, COUNT(*) AS `WeekEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `WeekEventDiskSpace`
FROM `Events_Week` GROUP BY `MonitorId`
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
`Monitors`.`WeekEvents` = `E`.`WeekEvents`,
`Monitors`.`WeekEventDiskSpace` = `E`.`WeekEventDiskSpace`
';
my $eventcounts_month_sql = q`
UPDATE Monitors INNER JOIN (
SELECT MonitorId, COUNT(*) AS MonthEvents, SUM(COALESCE(DiskSpace,0)) AS MonthEventDiskSpace
FROM Events_Month GROUP BY MonitorId
) AS E ON E.MonitorId=Monitors.Id SET
Monitors.MonthEvents = E.MonthEvents,
Monitors.MonthEventDiskSpace = E.MonthEventDiskSpace
`;
my $eventcounts_month_sql = '
UPDATE `Monitors` INNER JOIN (
SELECT `MonitorId`, COUNT(*) AS `MonthEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `MonthEventDiskSpace`
FROM `Events_Month` GROUP BY `MonitorId`
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
`Monitors`.`MonthEvents` = `E`.`MonthEvents`,
`Monitors`.`MonthEventDiskSpace` = `E`.`MonthEventDiskSpace`
';
my $eventcounts_hour_sth = $dbh->prepare_cached($eventcounts_hour_sql);
my $eventcounts_day_sth = $dbh->prepare_cached($eventcounts_day_sql);
my $eventcounts_week_sth = $dbh->prepare_cached($eventcounts_week_sql);

View File

@ -175,8 +175,12 @@ my $dbh = zmDbConnect();
if ( $filter_name ) {
Info("Scanning for events using filter '$filter_name'");
} elsif ( $filter_id ) {
Info("Scanning for events using filter id '$filter_id'");
} elsif ( defined($filter_id) ) {
if ( $filter_id ) {
Info("Scanning for events using filter id '$filter_id'");
} else {
Fatal("No filter_id specified");
}
} else {
Info("Scanning for events using all filters");
}
@ -221,27 +225,27 @@ sub getFilters {
my @sql_values;
my @filters;
my $sql = 'SELECT * FROM Filters WHERE';
my $sql = 'SELECT * FROM `Filters` WHERE';
if ( $$sql_filters{Name} ) {
$sql .= ' Name = ? AND';
$sql .= ' `Name` = ? AND';
push @sql_values, $$sql_filters{Name};
} elsif ( $$sql_filters{Id} ) {
$sql .= ' Id = ? AND';
$sql .= ' `Id` = ? AND';
push @sql_values, $$sql_filters{Id};
} else {
$sql .= ' Background = 1 AND';
$sql .= ' `Background` = 1 AND';
}
$sql .= '( AutoArchive = 1
or AutoVideo = 1
or AutoUpload = 1
or AutoEmail = 1
or AutoMessage = 1
or AutoExecute = 1
or AutoDelete = 1
or UpdateDiskSpace = 1
or AutoMove = 1
or AutoCopy = 1
) ORDER BY Name';
$sql .= '( `AutoArchive` = 1
or `AutoVideo` = 1
or `AutoUpload` = 1
or `AutoEmail` = 1
or `AutoMessage` = 1
or `AutoExecute` = 1
or `AutoDelete` = 1
or `UpdateDiskSpace` = 1
or `AutoMove` = 1
or `AutoCopy` = 1
) ORDER BY `Name`';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute(@sql_values)
@ -301,7 +305,7 @@ sub checkFilter {
if ( $filter->{AutoArchive} ) {
Info("Archiving event $Event->{Id}");
# Do it individually to avoid locking up the table for new events
my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
my $sql = 'UPDATE `Events` SET `Archived` = 1 WHERE `Id` = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
@ -434,7 +438,7 @@ sub generateVideo {
}
return 0;
} else {
my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?';
my $sql = 'UPDATE `Events` SET `Videoed` = 1 WHERE `Id` = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
@ -619,7 +623,7 @@ sub uploadArchFile {
or Error("SFTP - Unable to upload '$archLocPath': ".$sftp->error);
}
unlink($archLocPath);
my $sql = 'UPDATE Events SET Uploaded = 1 WHERE Id = ?';
my $sql = 'UPDATE `Events` SET `Uploaded` = 1 WHERE `Id` = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
@ -647,12 +651,10 @@ sub substituteTags {
my $max_alarm_frame;
my $max_alarm_score = 0;
if ( $need_images ) {
my $sql = q`SELECT * FROM Frames
WHERE EventId = ? AND Type = 'Alarm'
ORDER BY FrameId`;
my $sql = 'SELECT * FROM `Frames` WHERE `EventId`=? AND `Type`=? ORDER BY `FrameId`';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
my $res = $sth->execute($Event->{Id},'Alarm')
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
my $rows = 0;
while( my $frame = $sth->fetchrow_hashref() ) {
@ -879,7 +881,7 @@ sub sendEmail {
} else {
Info('Notification email sent');
}
my $sql = 'UPDATE Events SET Emailed = 1 WHERE Id = ?';
my $sql = 'UPDATE `Events` SET `Emailed` = 1 WHERE `Id` = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
@ -984,7 +986,7 @@ sub sendMessage {
} else {
Info('Notification message sent');
}
my $sql = 'UPDATE Events SET Messaged = 1 WHERE Id = ?';
my $sql = 'UPDATE `Events` SET `Messaged` = 1 WHERE `Id` = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Event->{Id})
@ -1014,7 +1016,7 @@ sub executeCommand {
Error("Command '$command' exited with status: $status");
return 0;
} else {
my $sql = 'UPDATE Events SET Executed = 1 WHERE Id = ?';
my $sql = 'UPDATE `Events` SET `Executed` = 1 WHERE `Id` = ?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute( $Event->{Id} )

View File

@ -57,7 +57,7 @@ my $dbh = zmDbConnect();
Debug("Command: $command");
if ( $command and ( $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) ) {
# Check to see if it's a valid run state
my $sql = 'SELECT * FROM States WHERE Name=?';
my $sql = 'SELECT * FROM `States` WHERE `Name`=?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($command)
@ -98,7 +98,7 @@ my $retval = 0;
if ( $command eq 'state' ) {
Info("Updating DB: $state->{Name}");
my $sql = 'SELECT * FROM Monitors' . ($Config{ZM_SERVER_ID} ? ' WHERE ServerId=?' : '' ) .' ORDER BY Id ASC';
my $sql = 'SELECT * FROM `Monitors`' . ($Config{ZM_SERVER_ID} ? ' WHERE `ServerId`=?' : '' ) .' ORDER BY `Id` ASC';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: ())
@ -118,7 +118,7 @@ if ( $command eq 'state' ) {
if ( $monitor->{Function} ne $monitor->{NewFunction}
|| $monitor->{Enabled} ne $monitor->{NewEnabled}
) {
my $sql = 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?';
my $sql = 'UPDATE `Monitors` SET `Function`=?, `Enabled`=? WHERE `Id`=?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id})
@ -130,7 +130,7 @@ if ( $command eq 'state' ) {
# PP - Now mark a specific state as active
resetStates();
Info("Marking $store_state as Enabled");
$sql = 'UPDATE States SET IsActive = 1 WHERE Name = ?';
$sql = 'UPDATE `States` SET `IsActive` = 1 WHERE `Name` = ?';
$sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
$res = $sth->execute($store_state)
@ -197,11 +197,11 @@ if ( $command =~ /^(?:start|restart)$/ ) {
require ZoneMinder::Server;
Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}");
$Server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
$sql = 'SELECT * FROM Monitors WHERE ServerId=?';
$sql = 'SELECT * FROM `Monitors` WHERE `ServerId`=?';
@values = ( $Config{ZM_SERVER_ID} );
} else {
Info('Single server configuration detected. Starting up services.');
$sql = 'SELECT * FROM Monitors';
$sql = 'SELECT * FROM `Monitors`';
}
{
@ -237,7 +237,7 @@ if ( $command =~ /^(?:start|restart)$/ ) {
}
{
my $sql = 'SELECT Id FROM Filters WHERE Background=1';
my $sql = 'SELECT `Id` FROM `Filters` WHERE `Background`=1';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute()
@ -311,25 +311,25 @@ sub isActiveSanityCheck {
$dbh = zmDbConnect() if ! $dbh;
# PP - First, make sure default exists and there is only one
my $sql = q`SELECT Name FROM States WHERE Name='default'`;
my $sql = 'SELECT `Name` FROM `States` WHERE `Name`=?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute()
my $res = $sth->execute('default')
or Fatal("Can't execute: ".$sth->errstr());
if ( $sth->rows != 1 ) {
# PP - no row, or too many rows. Either case is an error
Info('Fixing States table - either no default state or duplicate default states');
if ( $sth->rows ) {
$dbh->do(q`DELETE FROM States WHERE Name='default'`) or Fatal("Can't execute: ".$dbh->errstr());
$dbh->do('DELETE FROM `States` WHERE `Name`=\'default\'') or Fatal("Can't execute: ".$dbh->errstr());
}
$dbh->do(q`INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1');`)
$dbh->do('INSERT INTO `States` (`Name`,`Definition`,`IsActive`) VALUES (\'default\',\'\',\'1\');')
or Fatal("Can't execute: ".$dbh->errstr());
}
$sth->finish();
# PP - Now make sure no two states have IsActive=1
$sql = 'SELECT Name FROM States WHERE IsActive = 1';
$sql = 'SELECT `Name` FROM `States` WHERE `IsActive`=1';
$sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
$res = $sth->execute()
@ -338,7 +338,7 @@ sub isActiveSanityCheck {
if ( $sth->rows != 1 ) {
Info('Fixing States table so only one run state is active');
resetStates();
$dbh->do(q`UPDATE States SET IsActive=1 WHERE Name='default'`)
$dbh->do('UPDATE `States` SET `IsActive`=1 WHERE `Name`=\'default\'')
or Fatal("Can't execute: ".$dbh->errstr());
}
$sth->finish();
@ -347,7 +347,7 @@ sub isActiveSanityCheck {
# PP - zeroes out isActive for all states
sub resetStates {
$dbh = zmDbConnect() if ! $dbh;
$dbh->do('UPDATE States SET IsActive=0')
$dbh->do('UPDATE `States` SET `IsActive`=0')
or Fatal("Can't execute: ".$dbh->errstr());
}

View File

@ -301,7 +301,7 @@ if ( $migrateEvents ) {
$sth->finish();
print( "Updating configuration.\n" );
$sql = "update Config set Value = ? where Name = 'ZM_USE_DEEP_STORAGE'";
$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->finish();
@ -323,7 +323,7 @@ if ( $freshen ) {
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 $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() );
@ -341,7 +341,7 @@ if ( $interactive ) {
$dbh->do(q|SET sql_mode='traditional'|); # Elevate warnings to errors
print "\nConverting MyISAM tables to InnoDB. Please wait.\n";
foreach (@MyISAM_Tables) {
my $sql = "ALTER TABLE $_ ENGINE = InnoDB";
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() );
$sth->finish();
@ -447,7 +447,7 @@ if ( $version ) {
# Rename the event directories and create a new symlink for the names
chdir( EVENT_PATH );
my $sql = "select * from Monitors order by Id";
my $sql = "SELECT * FROM `Monitors` ORDER BY `Id`";
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 $monitor = $sth->fetchrow_hashref() ) {

View File

@ -1,12 +1,11 @@
#include "zm.h"
# include "zm_crypt.h"
#include "zm_crypt.h"
#include "BCrypt.hpp"
#include "jwt.h"
#include <algorithm>
#include <openssl/sha.h>
#include <string.h>
// returns username if valid, "" if not
std::pair <std::string, unsigned int> verifyToken(std::string jwt_token_str, std::string key) {
std::string username = "";
@ -22,47 +21,42 @@ std::pair <std::string, unsigned int> verifyToken(std::string jwt_token_str, std
verifier.verify(decoded);
// make sure it has fields we need
if (decoded.has_payload_claim("type")) {
if ( decoded.has_payload_claim("type") ) {
std::string type = decoded.get_payload_claim("type").as_string();
if (type != "access") {
Error ("Only access tokens are allowed. Please do not use refresh tokens");
return std::make_pair("",0);
if ( type != "access" ) {
Error("Only access tokens are allowed. Please do not use refresh tokens");
return std::make_pair("", 0);
}
}
else {
} else {
// something is wrong. All ZM tokens have type
Error ("Missing token type. This should not happen");
Error("Missing token type. This should not happen");
return std::make_pair("",0);
}
if (decoded.has_payload_claim("user")) {
if ( decoded.has_payload_claim("user") ) {
username = decoded.get_payload_claim("user").as_string();
Debug (1, "Got %s as user claim from token", username.c_str());
}
else {
Error ("User not found in claim");
return std::make_pair("",0);
Debug(1, "Got %s as user claim from token", username.c_str());
} else {
Error("User not found in claim");
return std::make_pair("", 0);
}
if (decoded.has_payload_claim("iat")) {
if ( decoded.has_payload_claim("iat") ) {
token_issued_at = (unsigned int) (decoded.get_payload_claim("iat").as_int());
Debug (1,"Got IAT token=%u", token_issued_at);
}
else {
Error ("IAT not found in claim. This should not happen");
return std::make_pair("",0);
Debug(1, "Got IAT token=%u", token_issued_at);
} else {
Error("IAT not found in claim. This should not happen");
return std::make_pair("", 0);
}
} // try
catch (const std::exception &e) {
catch ( const std::exception &e ) {
Error("Unable to verify token: %s", e.what());
return std::make_pair("",0);
return std::make_pair("", 0);
}
catch (...) {
Error ("unknown exception");
return std::make_pair("",0);
Error("unknown exception");
return std::make_pair("", 0);
}
return std::make_pair(username,token_issued_at);
return std::make_pair(username, token_issued_at);
}
bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) {
@ -102,7 +96,7 @@ bool verifyPassword(const char *username, const char *input_password, const char
} else if (
(db_password_hash[0] == '$')
&&
(db_password_hash[1]== '2')
(db_password_hash[1] == '2')
&&
(db_password_hash[3] == '$')
) {

View File

@ -246,11 +246,13 @@ Event::~Event() {
DELTA_TIMEVAL(delta_time, end_time, start_time, DT_PREC_2);
Debug(2, "start_time:%d.%d end_time%d.%d", start_time.tv_sec, start_time.tv_usec, end_time.tv_sec, end_time.tv_usec);
#if 0 // This closing frame has no image. There is no point in adding a db record for it, I think. ICON
if ( frames > last_db_frame ) {
frames ++;
Debug(1, "Adding closing frame %d to DB", frames);
frame_data.push(new Frame(id, frames, NORMAL, end_time, delta_time, 0));
}
#endif
if ( frame_data.size() )
WriteDbFrames();

View File

@ -510,7 +510,7 @@ int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
int ret;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( (ret = avcodec_send_frame(ctx, frame)) < 0 ) {
Error("Could not send frame (error '%s')",
av_make_error_string(ret).c_str());

View File

@ -299,21 +299,6 @@ void zm_dump_codec(const AVCodecContext *codec);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
void zm_dump_codecpar(const AVCodecParameters *par);
#endif
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \
" duration %" PRId64 \
" layout %d pts %" PRId64,\
text, \
frame->format, \
av_get_sample_fmt_name((AVSampleFormat)frame->format), \
frame->sample_rate, \
frame->nb_samples, \
frame->channels, \
frame->pkt_duration, \
frame->channel_layout, \
frame->pts \
);
#else
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \
" duration %" PRId64 \
" layout %d pts %" PRId64, \
@ -327,8 +312,6 @@ void zm_dump_codecpar(const AVCodecParameters *par);
frame->pts \
);
#endif
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
text, \
frame->format, \

View File

@ -1102,10 +1102,11 @@ int FfmpegCamera::transfer_to_image(
mConvertContext, input_frame->data, input_frame->linesize,
0, mVideoCodecContext->height,
output_frame->data, output_frame->linesize) <= 0 ) {
Error("Unable to convert format %u to format %u at frame %d codec %u",
input_frame->format,
imagePixFormat, frameCount,
mVideoCodecContext->pix_fmt
Error("Unable to convert format %u %s to format %u %s at frame %d codec %u %s",
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
av_get_pix_fmt_name(imagePixFormat),
frameCount,
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt)
);
return -1;
}

View File

@ -3237,7 +3237,7 @@ void neon32_armv7_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* r
__asm__ __volatile__ (
"mov r12, %4\n\t"
"vdup.8 q12, r12\n\t"
"neon32_armv7_fastblend_iter:\n\t"
"neon32_armv7_fastblend_iter%=:\n\t"
"vldm %0!, {q0,q1,q2,q3}\n\t"
"vldm %1!, {q4,q5,q6,q7}\n\t"
"pld [%0, #256]\n\t"
@ -3260,7 +3260,7 @@ void neon32_armv7_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* r
"vadd.i8 q7, q7, q3\n\t"
"vstm %2!, {q4,q5,q6,q7}\n\t"
"subs %3, %3, #64\n\t"
"bne neon32_armv7_fastblend_iter\n\t"
"bne neon32_armv7_fastblend_iter%=\n\t"
:
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (divider)
: "%r12", "%q0", "%q1", "%q2", "%q3", "%q4", "%q5", "%q6", "%q7", "%q8", "%q9", "%q10", "%q11", "%q12", "cc", "memory"
@ -3318,7 +3318,7 @@ __attribute__((noinline)) void neon64_armv8_fastblend(const uint8_t* col1, const
__asm__ __volatile__ (
"mov x12, %4\n\t"
"dup v28.16b, w12\n\t"
"neon64_armv8_fastblend_iter:\n\t"
"neon64_armv8_fastblend_iter%=:\n\t"
"ldp q16, q17, [%0], #32\n\t"
"ldp q18, q19, [%0], #32\n\t"
"ldp q20, q21, [%1], #32\n\t"
@ -3344,7 +3344,7 @@ __attribute__((noinline)) void neon64_armv8_fastblend(const uint8_t* col1, const
"stp q20, q21, [%2], #32\n\t"
"stp q22, q23, [%2], #32\n\t"
"subs %3, %3, #64\n\t"
"bne neon64_armv8_fastblend_iter\n\t"
"bne neon64_armv8_fastblend_iter%=\n\t"
:
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (divider)
: "%x12", "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", "%v24", "%v25", "%v26", "%v27", "%v28", "cc", "memory"
@ -3702,7 +3702,7 @@ void neon32_armv7_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t
/* Q7(D14,D15) = col2+48 */
__asm__ __volatile__ (
"neon32_armv7_delta8_gray8_iter:\n\t"
"neon32_armv7_delta8_gray8_iter%=:\n\t"
"vldm %0!, {q0,q1,q2,q3}\n\t"
"vldm %1!, {q4,q5,q6,q7}\n\t"
"pld [%0, #512]\n\t"
@ -3713,7 +3713,7 @@ void neon32_armv7_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t
"vabd.u8 q3, q3, q7\n\t"
"vstm %2!, {q0,q1,q2,q3}\n\t"
"subs %3, %3, #64\n\t"
"bne neon32_armv7_delta8_gray8_iter\n\t"
"bne neon32_armv7_delta8_gray8_iter%=\n\t"
:
: "r" (col1), "r" (col2), "r" (result), "r" (count)
: "%q0", "%q1", "%q2", "%q3", "%q4", "%q5", "%q6", "%q7", "cc", "memory"
@ -3737,7 +3737,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_gray8(const uint8_t* col1, co
/* V23 = col2+48 */
__asm__ __volatile__ (
"neon64_armv8_delta8_gray8_iter:\n\t"
"neon64_armv8_delta8_gray8_iter%=:\n\t"
"ldp q16, q17, [%0], #32\n\t"
"ldp q18, q19, [%0], #32\n\t"
"ldp q20, q21, [%1], #32\n\t"
@ -3751,7 +3751,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_gray8(const uint8_t* col1, co
"stp q16, q17, [%2], #32\n\t"
"stp q18, q19, [%2], #32\n\t"
"subs %3, %3, #64\n\t"
"bne neon64_armv8_delta8_gray8_iter\n\t"
"bne neon64_armv8_delta8_gray8_iter%=\n\t"
:
: "r" (col1), "r" (col2), "r" (result), "r" (count)
: "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", "cc", "memory"
@ -3781,7 +3781,7 @@ void neon32_armv7_delta8_rgb32(const uint8_t* col1, const uint8_t* col2, uint8_t
__asm__ __volatile__ (
"mov r12, %4\n\t"
"vdup.32 q8, r12\n\t"
"neon32_armv7_delta8_rgb32_iter:\n\t"
"neon32_armv7_delta8_rgb32_iter%=:\n\t"
"vldm %0!, {q0,q1,q2,q3}\n\t"
"vldm %1!, {q4,q5,q6,q7}\n\t"
"pld [%0, #256]\n\t"
@ -3808,7 +3808,7 @@ void neon32_armv7_delta8_rgb32(const uint8_t* col1, const uint8_t* col2, uint8_t
"vpadd.i8 d3, d6, d6\n\t"
"vst4.32 {d0[0],d1[0],d2[0],d3[0]}, [%2]!\n\t"
"subs %3, %3, #16\n\t"
"bne neon32_armv7_delta8_rgb32_iter\n\t"
"bne neon32_armv7_delta8_rgb32_iter%=\n\t"
:
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (multiplier)
: "%r12", "%q0", "%q1", "%q2", "%q3", "%q4", "%q5", "%q6", "%q7", "%q8", "cc", "memory"
@ -3835,7 +3835,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_rgb32(const uint8_t* col1, co
__asm__ __volatile__ (
"mov x12, %4\n\t"
"dup v24.4s, w12\n\t"
"neon64_armv8_delta8_rgb32_iter:\n\t"
"neon64_armv8_delta8_rgb32_iter%=:\n\t"
"ldp q16, q17, [%0], #32\n\t"
"ldp q18, q19, [%0], #32\n\t"
"ldp q20, q21, [%1], #32\n\t"
@ -3864,7 +3864,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_rgb32(const uint8_t* col1, co
"addp v19.16b, v19.16b, v19.16b\n\t"
"st4 {v16.s, v17.s, v18.s, v19.s}[0], [%2], #16\n\t"
"subs %3, %3, #16\n\t"
"bne neon64_armv8_delta8_rgb32_iter\n\t"
"bne neon64_armv8_delta8_rgb32_iter%=\n\t"
:
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (multiplier)
: "%x12", "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", "%v24", "cc", "memory"

View File

@ -58,32 +58,32 @@ inline void zm_freealigned(void* ptr) {
#endif
}
inline char *mempbrk( register const char *s, const char *accept, size_t limit ) {
inline char *mempbrk(const char *s, const char *accept, size_t limit) {
if ( limit == 0 || !s || !accept || !*accept )
return 0;
register unsigned int i,j;
size_t acc_len = strlen( accept );
unsigned int i,j;
size_t acc_len = strlen(accept);
for ( i = 0; i < limit; s++, i++ ) {
for ( j = 0; j < acc_len; j++ ) {
if ( *s == accept[j] ) {
return( (char *)s );
return (char *)s;
}
}
}
return( 0 );
return 0;
}
inline char *memstr( register const char *s, const char *n, size_t limit ) {
inline char *memstr(const char *s, const char *n, size_t limit) {
if ( limit == 0 || !s || !n )
return( 0 );
return 0;
if ( !*n )
return( (char *)s );
return (char *)s;
register unsigned int i,j,k;
size_t n_len = strlen( n );
unsigned int i,j,k;
size_t n_len = strlen(n);
for ( i = 0; i < limit; i++, s++ ) {
if ( *s != *n )
@ -92,23 +92,23 @@ inline char *memstr( register const char *s, const char *n, size_t limit ) {
k = 1;
while ( true ) {
if ( k >= n_len )
return( (char *)s );
return (char *)s;
if ( s[j++] != n[k++] )
break;
}
}
return( 0 );
return 0;
}
inline size_t memspn( register const char *s, const char *accept, size_t limit ) {
inline size_t memspn(const char *s, const char *accept, size_t limit) {
if ( limit == 0 || !s || !accept || !*accept )
return( 0 );
return 0;
register unsigned int i,j;
size_t acc_len = strlen( accept );
unsigned int i,j;
size_t acc_len = strlen(accept);
for ( i = 0; i < limit; s++, i++ ) {
register bool found = false;
bool found = false;
for ( j = 0; j < acc_len; j++ ) {
if ( *s == accept[j] ) {
found = true;
@ -116,30 +116,30 @@ inline size_t memspn( register const char *s, const char *accept, size_t limit )
}
}
if ( !found ) {
return( i );
return i;
}
}
return( limit );
return limit;
}
inline size_t memcspn( register const char *s, const char *reject, size_t limit ) {
inline size_t memcspn(const char *s, const char *reject, size_t limit) {
if ( limit == 0 || !s || !reject )
return( 0 );
return 0;
if ( !*reject )
return( limit );
return limit;
register unsigned int i,j;
unsigned int i,j;
size_t rej_len = strlen( reject );
for ( i = 0; i < limit; s++, i++ ) {
for ( j = 0; j < rej_len; j++ ) {
if ( *s == reject[j] ) {
return( i );
return i;
}
}
}
return( limit );
return limit;
}
#endif // ZM_MEM_UTILS_H

View File

@ -27,6 +27,18 @@
#include <string.h>
#include <time.h>
#if HAVE_GNUTLS_OPENSSL_H
#include <gnutls/openssl.h>
#endif
#if HAVE_GNUTLS_GNUTLS_H
#include <gnutls/gnutls.h>
#endif
#if HAVE_GCRYPT_H
#include <gcrypt.h>
#elif HAVE_LIBCRYPTO
#include <openssl/md5.h>
#endif // HAVE_L || HAVE_LIBCRYPTO
#include "zm_utils.h"
#include "zm_crypt.h"
@ -38,22 +50,22 @@ User::User() {
stream = events = control = monitors = system = PERM_NONE;
}
User::User( MYSQL_ROW &dbrow ) {
User::User(const MYSQL_ROW &dbrow) {
int index = 0;
id = atoi( dbrow[index++] );
strncpy( username, dbrow[index++], sizeof(username)-1 );
strncpy( password, dbrow[index++], sizeof(password)-1 );
enabled = (bool)atoi( dbrow[index++] );
stream = (Permission)atoi( dbrow[index++] );
events = (Permission)atoi( dbrow[index++] );
control = (Permission)atoi( dbrow[index++] );
monitors = (Permission)atoi( dbrow[index++] );
system = (Permission)atoi( dbrow[index++] );
id = atoi(dbrow[index++]);
strncpy(username, dbrow[index++], sizeof(username)-1);
strncpy(password, dbrow[index++], sizeof(password)-1);
enabled = (bool)atoi(dbrow[index++]);
stream = (Permission)atoi(dbrow[index++]);
events = (Permission)atoi(dbrow[index++]);
control = (Permission)atoi(dbrow[index++]);
monitors = (Permission)atoi(dbrow[index++]);
system = (Permission)atoi(dbrow[index++]);
char *monitor_ids_str = dbrow[index++];
if ( monitor_ids_str && *monitor_ids_str ) {
StringVector ids = split(monitor_ids_str, ",");
for( StringVector::iterator i = ids.begin(); i < ids.end(); ++i ) {
monitor_ids.push_back( atoi( (*i).c_str()) );
monitor_ids.push_back(atoi((*i).c_str()));
}
}
}
@ -62,10 +74,10 @@ User::~User() {
monitor_ids.clear();
}
void User::Copy( const User &u ) {
void User::Copy(const User &u) {
id=u.id;
strncpy( username, u.username, sizeof(username)-1 );
strncpy( password, u.password, sizeof(password)-1 );
strncpy(username, u.username, sizeof(username)-1);
strncpy(password, u.password, sizeof(password)-1);
enabled = u.enabled;
stream = u.stream;
events = u.events;
@ -75,7 +87,7 @@ void User::Copy( const User &u ) {
monitor_ids = u.monitor_ids;
}
bool User::canAccess( int monitor_id ) {
bool User::canAccess(int monitor_id) {
if ( monitor_ids.empty() )
return true;
@ -89,54 +101,52 @@ bool User::canAccess( int monitor_id ) {
// Function to load a user from username and password
// Please note that in auth relay mode = none, password is NULL
User *zmLoadUser( const char *username, const char *password ) {
User *zmLoadUser(const char *username, const char *password) {
char sql[ZM_SQL_MED_BUFSIZ] = "";
int username_length = strlen(username);
char *safer_username = new char[(username_length * 2) + 1];
// According to docs, size of safer_whatever must be 2*length+1 due to unicode conversions + null terminator.
mysql_real_escape_string(&dbconn, safer_username, username, username_length );
mysql_real_escape_string(&dbconn, safer_username, username, username_length);
snprintf(sql, sizeof(sql),
"SELECT `Id`, `Username`, `Password`, `Enabled`, `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0, `MonitorIds`"
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", safer_username );
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", safer_username);
if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
delete safer_username;
MYSQL_RES *result = mysql_store_result(&dbconn);
if ( !result ) {
Error("Can't use query result: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
int n_users = mysql_num_rows(result);
if ( n_users != 1 ) {
if ( mysql_num_rows(result) != 1 ) {
mysql_free_result(result);
Warning("Unable to authenticate user %s", username);
return NULL;
}
MYSQL_ROW dbrow = mysql_fetch_row(result);
User *user = new User(dbrow);
if (verifyPassword(username, password, user->getPassword())) {
Info("Authenticated user '%s'", user->getUsername());
mysql_free_result(result);
delete safer_username;
mysql_free_result(result);
if ( !password ) {
// relay type must be none
return user;
}
else {
Warning("Unable to authenticate user %s", username);
mysql_free_result(result);
return NULL;
}
if ( verifyPassword(username, password, user->getPassword()) ) {
Info("Authenticated user '%s'", user->getUsername());
return user;
}
Warning("Unable to authenticate user %s", username);
return NULL;
}
User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) {

View File

@ -23,25 +23,14 @@
#ifndef ZM_USER_H
#define ZM_USER_H
#if HAVE_GNUTLS_OPENSSL_H
#include <gnutls/openssl.h>
#endif
#if HAVE_GNUTLS_GNUTLS_H
#include <gnutls/gnutls.h>
#endif
#if HAVE_GCRYPT_H
#include <gcrypt.h>
#elif HAVE_LIBCRYPTO
#include <openssl/md5.h>
#endif // HAVE_L || HAVE_LIBCRYPTO
#include <string>
#include <vector>
class User {
public:
typedef enum { PERM_NONE=1, PERM_VIEW, PERM_EDIT } Permission;
protected:
class User {
public:
typedef enum { PERM_NONE = 1, PERM_VIEW, PERM_EDIT } Permission;
protected:
int id;
char username[32+1];
char password[64+1];
@ -53,32 +42,32 @@ protected:
Permission system;
std::vector<int> monitor_ids;
public:
public:
User();
explicit User( MYSQL_ROW &dbrow );
explicit User(const MYSQL_ROW &dbrow);
~User();
User( User &u ) { Copy(u); }
void Copy( const User &u );
User(User &u) { Copy(u); }
void Copy(const User &u);
User& operator=(const User &u) {
Copy(u); return *this;
}
const int Id() const { return id; }
const char *getUsername() const { return( username ); }
const char *getPassword() const { return( password ); }
bool isEnabled() const { return( enabled ); }
Permission getStream() const { return( stream ); }
Permission getEvents() const { return( events ); }
Permission getControl() const { return( control ); }
Permission getMonitors() const { return( monitors ); }
Permission getSystem() const { return( system ); }
bool canAccess( int monitor_id );
const char *getUsername() const { return username; }
const char *getPassword() const { return password; }
bool isEnabled() const { return enabled; }
Permission getStream() const { return stream; }
Permission getEvents() const { return events; }
Permission getControl() const { return control; }
Permission getMonitors() const { return monitors; }
Permission getSystem() const { return system; }
bool canAccess(int monitor_id);
};
User *zmLoadUser( const char *username, const char *password=0 );
User *zmLoadAuthUser( const char *auth, bool use_remote_addr );
User *zmLoadTokenUser( std::string jwt, bool use_remote_addr);
bool checkUser ( const char *username);
bool checkPass (const char *password);
User *zmLoadUser(const char *username, const char *password=0);
User *zmLoadAuthUser(const char *auth, bool use_remote_addr);
User *zmLoadTokenUser(std::string jwt, bool use_remote_addr);
bool checkUser(const char *username);
bool checkPass(const char *password);
#endif // ZM_USER_H

View File

@ -20,13 +20,14 @@
#define __STDC_FORMAT_MACROS 1
#include <cinttypes>
#include <stdlib.h>
#include <string.h>
#include "zm.h"
#include "zm_videostore.h"
#include <stdlib.h>
#include <string.h>
#include <cinttypes>
extern "C" {
#include "libavutil/time.h"
}
@ -60,7 +61,7 @@ VideoStore::VideoStore(
Info("Opening video storage stream %s format: %s", filename, format);
ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
int ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
if ( ret < 0 ) {
Warning(
"Could not create video storage stream %s as no out ctx"
@ -91,7 +92,7 @@ VideoStore::VideoStore(
oc->metadata = pmetadata;
out_format = oc->oformat;
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
if ( !video_out_codec ) {
@ -136,7 +137,7 @@ VideoStore::VideoStore(
video_out_ctx->time_base = video_in_ctx->time_base;
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
Debug(2,"No timebase found in video in context, defaulting to Q");
video_out_ctx->time_base = AV_TIME_BASE_Q;
video_out_ctx->time_base = AV_TIME_BASE_Q;
}
zm_dump_codec(video_out_ctx);
@ -162,7 +163,7 @@ VideoStore::VideoStore(
if ( !video_out_ctx->codec_tag ) {
Debug(2, "No codec_tag");
if (
if (
!oc->oformat->codec_tag
||
av_codec_get_id(oc->oformat->codec_tag, video_in_ctx->codec_tag) == video_out_ctx->codec_id
@ -178,34 +179,21 @@ VideoStore::VideoStore(
video_out_stream->time_base = video_in_stream->time_base;
if ( video_in_stream->avg_frame_rate.num ) {
Debug(3,"Copying avg_frame_rate (%d/%d)",
video_in_stream->avg_frame_rate.num,
video_in_stream->avg_frame_rate.den
video_in_stream->avg_frame_rate.num,
video_in_stream->avg_frame_rate.den
);
video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate;
}
if ( video_in_stream->r_frame_rate.num ) {
Debug(3,"Copying r_frame_rate (%d/%d) to out (%d/%d)",
video_in_stream->r_frame_rate.num,
video_in_stream->r_frame_rate.num,
video_in_stream->r_frame_rate.den ,
video_out_stream->r_frame_rate.num,
video_out_stream->r_frame_rate.den
video_out_stream->r_frame_rate.num,
video_out_stream->r_frame_rate.den
);
video_out_stream->r_frame_rate = video_in_stream->r_frame_rate;
}
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
#if 0
if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) {
//video_out_ctx->level = 32;I//
video_out_ctx->bit_rate = 400*1024;
video_out_ctx->max_b_frames = 1;
if ( video_out_ctx->priv_data ) {
av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN);
av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0);
} else {
Debug(2, "Not setting priv_data");
}
}
#endif
ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx);
if ( ret < 0 ) {
Error("Could not initialize video_out_ctx parameters");
@ -314,7 +302,7 @@ VideoStore::VideoStore(
audio_out_stream = NULL;
return;
}
#else
#else
audio_out_stream = avformat_new_stream(oc, audio_out_codec);
audio_out_ctx = audio_out_stream->codec;
#endif
@ -388,6 +376,7 @@ VideoStore::VideoStore(
} // VideoStore::VideoStore
bool VideoStore::open() {
int ret;
/* open the out file, if needed */
if ( !(out_format->flags & AVFMT_NOFILE) ) {
ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL);
@ -424,20 +413,13 @@ bool VideoStore::open() {
//avformat_free_context(oc);
return false;
}
Debug(3,
"Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out "
"stream: (%d/%d) out codec (%d/%d)",
video_in_stream->time_base.num, video_in_stream->time_base.den,
video_in_ctx->time_base.num, video_in_ctx->time_base.den,
video_out_stream->time_base.num, video_out_stream->time_base.den,
video_out_ctx->time_base.num,
video_out_ctx->time_base.den);
return true;
} // end VideoStore::open()
VideoStore::~VideoStore() {
if ( oc->pb ) {
int ret;
if ( audio_out_codec ) {
// The codec queues data. We need to send a flush command and out
@ -476,6 +458,7 @@ VideoStore::~VideoStore() {
}
#endif
dumpPacket(&pkt, "raw from encoder");
// Need to adjust pts and dts and duration
pkt.stream_index = audio_out_stream->index;
@ -486,6 +469,7 @@ VideoStore::~VideoStore() {
audio_out_stream->time_base);
// Scale the PTS of the outgoing packet to be the correct time base
if ( pkt.pts != AV_NOPTS_VALUE ) {
#if 0
pkt.pts = av_rescale_q(
pkt.pts,
audio_out_ctx->time_base,
@ -496,6 +480,12 @@ VideoStore::~VideoStore() {
pkt.pts,
audio_in_stream->time_base,
audio_out_stream->time_base);
#else
pkt.pts = av_rescale_q(
pkt.pts,
audio_out_ctx->time_base,
audio_out_stream->time_base);
#endif
Debug(2, "audio pkt.pts = %" PRId64 " from first_pts(%" PRId64 ")",
pkt.pts, audio_first_pts);
@ -505,6 +495,7 @@ VideoStore::~VideoStore() {
}
if ( pkt.dts != AV_NOPTS_VALUE ) {
#if 0
pkt.dts = av_rescale_q(
pkt.dts,
audio_out_ctx->time_base,
@ -514,6 +505,12 @@ VideoStore::~VideoStore() {
pkt.dts,
audio_in_stream->time_base,
audio_out_stream->time_base);
#else
pkt.dts = av_rescale_q(
pkt.dts,
audio_out_ctx->time_base,
audio_out_stream->time_base);
#endif
Debug(2, "pkt.dts = %" PRId64 " - first_dts(%" PRId64 ")",
pkt.dts, audio_first_dts);
} else {
@ -638,6 +635,7 @@ bool VideoStore::setup_resampler() {
"Cannot do audio conversion to AAC");
return false;
#else
int ret;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Newer ffmpeg wants to keep everything separate... so have to lookup our own
@ -656,7 +654,7 @@ bool VideoStore::setup_resampler() {
#else
// codec is already open in ffmpeg_camera
audio_in_ctx = audio_in_stream->codec;
audio_in_codec = (AVCodec *)audio_in_ctx->codec;
audio_in_codec = reinterpret_cast<const AVCodec *>(audio_in_ctx->codec);
//audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id);
#endif
@ -790,9 +788,9 @@ bool VideoStore::setup_resampler() {
}
#if defined(HAVE_LIBSWRESAMPLE)
if (!(fifo = av_audio_fifo_alloc(
if ( !(fifo = av_audio_fifo_alloc(
audio_out_ctx->sample_fmt,
audio_out_ctx->channels, 1))) {
audio_out_ctx->channels, 1)) ) {
Error("Could not allocate FIFO");
return false;
}
@ -870,7 +868,7 @@ bool VideoStore::setup_resampler() {
NULL, audio_out_ctx->channels,
audio_out_ctx->frame_size,
audio_out_ctx->sample_fmt, 0);
converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size);
converted_in_samples = reinterpret_cast<uint8_t *>(av_malloc(audioSampleBuffer_size));
if ( !converted_in_samples ) {
Error("Could not allocate converted in sample pointers");
@ -924,7 +922,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
duration
);
if ( duration <= 0 ) {
// Why are we setting the duration to 1?
// Why are we setting the duration to 1?
duration = ipkt->duration ? ipkt->duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base);
}
}
@ -966,15 +964,15 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
//AV_NOPTS_VALUE;
}
// Just because the in stream wraps, doesn't mean the out needs to.
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
// So need to handle in wrap, without causing out wrap.
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
// So need to handle in wrap, without causing out wrap.
if ( ipkt->dts != AV_NOPTS_VALUE ) {
if ( !video_first_dts ) {
// && ( ipkt->dts >= 0 ) ) {
// This is the first packet.
opkt.dts = 0;
Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
Debug(2, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
video_first_dts = ipkt->dts;
#if 1
if ( audio_in_stream ) {
@ -1008,49 +1006,27 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
opkt.dts = video_out_stream->cur_dts;
}
# if 1
if ( opkt.dts < video_out_stream->cur_dts ) {
Debug(1, "Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
opkt.dts, opkt.pts, video_out_stream->cur_dts);
opkt.dts = video_out_stream->cur_dts;
if ( opkt.dts > opkt.pts ) {
opkt.pts = opkt.dts;
}
}
#endif
if ( opkt.dts < video_out_stream->cur_dts ) {
Debug(1, "Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
opkt.dts, opkt.pts, video_out_stream->cur_dts);
opkt.dts = video_out_stream->cur_dts;
if ( opkt.dts > opkt.pts ) {
opkt.pts = opkt.dts;
}
}
opkt.flags = ipkt->flags;
opkt.pos = -1;
opkt.data = ipkt->data;
opkt.size = ipkt->size;
opkt.stream_index = video_out_stream->index;
dumpPacket(video_out_stream, &opkt, "writing video packet");
if ( (opkt.data == NULL) || (opkt.size < 1) ) {
Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__);
dumpPacket(video_in_stream, ipkt,"In Packet");
dumpPacket(video_out_stream, &opkt);
} else {
ret = av_interleaved_write_frame(oc, &opkt);
if ( ret < 0 ) {
// There's nothing we can really do if the frame is rejected, just drop it
// and get on with the next
Warning(
"%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d)",
__FILE__, __LINE__, av_make_error_string(ret).c_str(), ret);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
zm_dump_codecpar(video_in_stream->codecpar);
zm_dump_codecpar(video_out_stream->codecpar);
#endif
}
}
write_packet(&opkt, video_out_stream);
zm_av_packet_unref(&opkt);
return 0;
} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
int ret;
if ( !audio_out_stream ) {
Debug(1, "Called writeAudioFramePacket when no audio_out_stream");
@ -1066,6 +1042,20 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
}
zm_dump_frame(in_frame, "In frame from decode");
if ( in_frame->pts != AV_NOPTS_VALUE ) {
if ( !audio_first_pts ) {
audio_first_pts = in_frame->pts;
Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts);
in_frame->pts = 0;
} else {
// out_frame_pts is in codec->timebase, audio_first_pts is in packet timebase.
in_frame->pts = in_frame->pts - audio_first_pts;
zm_dump_frame(in_frame, "in frame after pts adjustment");
}
} else {
// sending AV_NOPTS_VALUE doesn't really work but we seem to get it in ffmpeg 2.8
in_frame->pts = audio_next_pts;
}
if ( !resample_audio() ) {
//av_frame_unref(in_frame);
@ -1099,12 +1089,19 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
}
dumpPacket(audio_out_stream, &opkt, "raw opkt");
Debug(1, "Duration before %d in %d/%d", opkt.duration,
audio_out_ctx->time_base.num,
audio_out_ctx->time_base.den);
opkt.duration = av_rescale_q(
opkt.duration,
audio_out_ctx->time_base,
audio_out_stream->time_base);
Debug(1, "Duration after %d in %d/%d", opkt.duration,
audio_out_stream->time_base.num,
audio_out_stream->time_base.den);
// Scale the PTS of the outgoing packet to be the correct time base
#if 0
if ( ipkt->pts != AV_NOPTS_VALUE ) {
if ( !audio_first_pts ) {
opkt.pts = 0;
@ -1134,19 +1131,62 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
audio_out_ctx->time_base,
audio_out_stream->time_base);
opkt.dts -= audio_first_dts;
Debug(2, "opkt.dts = %" PRId64 " from first_dts %" PRId64,
Debug(2, "audio opkt.dts = %" PRId64 " from first_dts %" PRId64,
opkt.dts, audio_first_dts);
}
audio_last_dts = opkt.dts;
} else {
opkt.dts = AV_NOPTS_VALUE;
}
#else
opkt.pts = av_rescale_q(
opkt.pts,
audio_out_ctx->time_base,
audio_out_stream->time_base);
opkt.dts = av_rescale_q(
opkt.dts,
audio_out_ctx->time_base,
audio_out_stream->time_base);
#endif
write_packet(&opkt, audio_out_stream);
zm_av_packet_unref(&opkt);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// While the encoder still has packets for us
while ( !avcodec_receive_packet(audio_out_ctx, &opkt) ) {
opkt.pts = av_rescale_q(
opkt.pts,
audio_out_ctx->time_base,
audio_out_stream->time_base);
opkt.dts = av_rescale_q(
opkt.dts,
audio_out_ctx->time_base,
audio_out_stream->time_base);
dumpPacket(audio_out_stream, &opkt, "raw opkt");
Debug(1, "Duration before %d in %d/%d", opkt.duration,
audio_out_ctx->time_base.num,
audio_out_ctx->time_base.den);
opkt.duration = av_rescale_q(
opkt.duration,
audio_out_ctx->time_base,
audio_out_stream->time_base);
Debug(1, "Duration after %d in %d/%d", opkt.duration,
audio_out_stream->time_base.num,
audio_out_stream->time_base.den);
write_packet(&opkt, audio_out_stream);
}
#endif
zm_av_packet_unref(&opkt);
} else {
Debug(2,"copying");
av_init_packet(&opkt);
opkt.data = ipkt->data;
opkt.size = ipkt->size;
opkt.flags = ipkt->flags;
if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) {
opkt.duration = av_rescale_q(
@ -1189,43 +1229,47 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
} else {
opkt.dts = AV_NOPTS_VALUE;
}
} // end if encoding or copying
write_packet(&opkt, audio_out_stream);
zm_av_packet_unref(&opkt);
} // end if encoding or copying
opkt.pos = -1;
opkt.stream_index = audio_out_stream->index;
opkt.flags = ipkt->flags;
return 0;
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
if ( opkt.dts < audio_out_stream->cur_dts ) {
int VideoStore::write_packet(AVPacket *pkt, AVStream *stream) {
pkt->pos = -1;
pkt->stream_index = stream->index;
if ( pkt->dts < stream->cur_dts ) {
Warning("non increasing dts, fixing");
opkt.dts = audio_out_stream->cur_dts;
if ( opkt.dts > opkt.pts ) {
pkt->dts = stream->cur_dts;
if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
Debug(1,
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 ")."
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
"Decompression must happen before presentation.",
opkt.dts, opkt.pts);
opkt.pts = opkt.dts;
pkt->dts, pkt->pts);
pkt->pts = pkt->dts;
}
} else if ( opkt.dts > opkt.pts ) {
} else if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
Debug(1,
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 ")."
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
"Decompression must happen before presentation.",
opkt.dts, opkt.pts);
opkt.dts = opkt.pts;
pkt->dts, pkt->pts);
pkt->dts = pkt->pts;
}
dumpPacket(audio_out_stream, &opkt, "finished opkt");
dumpPacket(stream, pkt, "finished pkt");
ret = av_interleaved_write_frame(oc, &opkt);
int ret = av_interleaved_write_frame(oc, pkt);
if ( ret != 0 ) {
Error("Error writing audio frame packet: %s",
Error("Error writing packet: %s",
av_make_error_string(ret).c_str());
} else {
Debug(2, "Success writing audio frame");
Debug(2, "Success writing packet");
}
zm_av_packet_unref(&opkt);
return 0;
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
return ret;
} // end int VideoStore::write_packet(AVPacket *pkt, AVStream *stream)
int VideoStore::resample_audio() {
// Resample the in_frame into the audioSampleBuffer until we process the whole
@ -1234,7 +1278,7 @@ int VideoStore::resample_audio() {
#if defined(HAVE_LIBSWRESAMPLE)
Debug(2, "Converting %d to %d samples using swresample",
in_frame->nb_samples, out_frame->nb_samples);
ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
int ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
if ( ret < 0 ) {
Error("Could not resample frame (error '%s')",
av_make_error_string(ret).c_str());
@ -1261,6 +1305,8 @@ int VideoStore::resample_audio() {
// AAC requires 1024 samples per encode. Our input tends to be something else, so need to buffer them.
if ( frame_size > av_audio_fifo_size(fifo) ) {
Debug(1, "Not enough samples in fifo for AAC codec frame_size %d > fifo size %d",
frame_size, av_audio_fifo_size(fifo));
return 0;
}
@ -1310,4 +1356,4 @@ int VideoStore::resample_audio() {
return 0;
#endif
return 1;
} // end int VideoStore::resample_audio
} // end int VideoStore::resample_audio

View File

@ -40,7 +40,6 @@ private:
AVCodecContext *video_in_ctx;
AVCodec *audio_in_codec;
AVCodecContext *audio_in_ctx;
int ret;
// The following are used when encoding the audio stream to AAC
AVStream *audio_out_stream;
@ -79,6 +78,8 @@ private:
bool setup_resampler();
int resample_audio();
int write_packet(AVPacket *pkt, AVStream *stream);
public:
VideoStore(
const char *filename_in,

View File

@ -86,31 +86,9 @@ commonprep () {
git -C packpack pull origin master
else
echo "Cloning packpack github repo..."
git clone https://github.com/packpack/packpack.git packpack
git clone https://github.com/zoneminder/packpack.git packpack
fi
# Rpm builds are broken in latest packpack master. Temporarily roll back.
#git -C packpack checkout 7cf23ee
# Patch packpack
patch --dry-run --silent -f -p1 < utils/packpack/packpack-rpm.patch
if [ $? -eq 0 ]; then
patch -p1 < utils/packpack/packpack-rpm.patch
fi
# Skip deb lintian checks to speed up the build
patch --dry-run --silent -f -p1 < utils/packpack/nolintian.patch
if [ $? -eq 0 ]; then
patch -p1 < utils/packpack/nolintian.patch
fi
# fix 32bit rpm builds
# FIXME: breaks arm rpm builds
#patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch
#if [ $? -eq 0 ]; then
# patch -p1 < utils/packpack/setarch.patch
#fi
# The rpm specfile requires we download each submodule as a tarball then manually move it into place
# Might as well do this for Debian as well, rather than git submodule init
CRUDVER="3.1.0-zm"
@ -177,9 +155,13 @@ installtrusty () {
if [ -e $pkgname ]; then
sudo gdebi --quiet --non-interactive $pkgname
echo "Return code from installing $?"
mysql -uzmuser -pzmpass zm < db/test.monitor.sql
echo "Return code from adding test monitor $?"
sudo /usr/bin/zmpkg.pl start
sudo /usr/bin/zmfilter.pl -f purgewhenfull
echo "Return code from starting $?"
sudo /usr/bin/zmfilter.pl --filter=purgewhenfull
echo "Return code from running purgewhenfull $?"
else
echo
echo "ERROR: The script cannot find the package $pkgname"
@ -241,9 +223,9 @@ setrpmchangelog () {
setdebchangelog () {
DATE=`date -R`
cat <<EOF > debian/changelog
zoneminder ($VERSION-${DIST}-1) unstable; urgency=low
zoneminder ($VERSION-${DIST}) ${DIST}; urgency=low
*
-- Isaac Connor <iconnor@connortechnology.com> $DATE
-- Isaac Connor <isaac@zoneminder.com> $DATE
EOF
}
@ -312,7 +294,7 @@ checksanity
# We don't want to build packages for all supported distros after every commit
# Only build all packages when executed via cron
# See https://docs.travis-ci.com/user/cron-jobs/
if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
commonprep
# Steps common to Redhat distros

View File

@ -31,7 +31,7 @@
* In production mode, flash messages redirect after a time interval.
* In development mode, you need to click the flash message to continue.
*/
Configure::write('debug', 2);
Configure::write('debug', 0);
/**
* Configure the Error handler used to handle errors for your application. By default

View File

@ -91,7 +91,6 @@ class AppController extends Controller {
require_once __DIR__ .'/../../../includes/session.php';
$stateful = $this->request->query('stateful') ? $this->request->query('stateful') : $this->request->data('stateful');
if ( $stateful ) {
zm_session_start();
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
$_SESSION['username'] = $user['Username'];
@ -99,6 +98,15 @@ class AppController extends Controller {
// Need to save this in session, can't use the value in User because it is hashed
$_SESSION['password'] = $_REQUEST['password'];
}
generateAuthHash(ZM_AUTH_HASH_IPS);
session_write_close();
} else if ( $_COOKIE['ZMSESSID'] and !$user ) {
# Have a cookie set, try to load user by session
if ( ! is_session_started() )
zm_session_start();
ZM\Logger::Debug(print_r($_SESSION, true));
$user = userFromSession();
session_write_close();
}
}
@ -142,10 +150,7 @@ class AppController extends Controller {
return;
}
} # end if ! login or logout
if ($user['APIEnabled'] == 0 ) {
throw new UnauthorizedException(__('API Disabled'));
return;
}
} # end if ZM_OPT_AUTH
// make sure populated user object has APIs enabled
} # end function beforeFilter()

View File

@ -2,76 +2,50 @@
namespace ZM;
require_once('Storage.php');
require_once('functions.php');
require_once('Object.php');
$event_cache = array();
class Event extends ZM_Object {
protected static $table = 'Events';
class Event {
private $fields = array(
'Id',
'Name',
'MonitorId',
'StorageId',
'SecondaryStorageId',
'Name',
'Cause',
'StartTime',
'EndTime',
'Width',
'Height',
'Length',
'Frames',
'AlarmFrames',
'DefaultVideo',
'SaveJPEGs',
'TotScore',
'AvgScore',
'MaxScore',
'Archived',
'Videoed',
'Uploaded',
'Emailed',
'Messaged',
'Executed',
'Notes',
'StateId',
'Orientation',
'DiskSpace',
'Scheme',
'Locked',
protected $defaults = array(
'Id' => null,
'Name' => '',
'MonitorId' => null,
'StorageId' => null,
'SecondaryStorageId' => null,
'Cause' => '',
'StartTime' => null,
'EndTime' => null,
'Width' => null,
'Height' => null,
'Length' => null,
'Frames' => null,
'AlarmFrames' => null,
'DefaultVideo' => '',
'SaveJPEGs' => 0,
'TotScore' => 0,
'AvgScore' => 0,
'MaxScore' => 0,
'Archived' => 0,
'Videoed' => 0,
'Uploaded' => 0,
'Emailed' => 0,
'Messaged' => 0,
'Executed' => 0,
'Notes' => '',
'StateId' => 0,
'Orientation' => 0,
'DiskSpace' => null,
'Scheme' => 0,
'Locked' => 0,
);
public function __construct( $IdOrRow = null ) {
$row = NULL;
if ( $IdOrRow ) {
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
$row = dbFetchOne('SELECT *,unix_timestamp(StartTime) AS Time FROM Events WHERE Id=?', NULL, array($IdOrRow));
if ( ! $row ) {
Error('Unable to load Event record for Id=' . $IdOrRow);
}
} elseif ( is_array($IdOrRow) ) {
$row = $IdOrRow;
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Unknown argument passed to Event Constructor from $file:$line) Id was $IdOrRow");
return;
}
public static function find( $parameters = array(), $options = array() ) {
return ZM_Object::_find(get_class(), $parameters, $options);
}
if ( $row ) {
foreach ($row as $k => $v) {
$this->{$k} = $v;
}
global $event_cache;
$event_cache[$row['Id']] = $this;
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error('No row for Event ' . $IdOrRow . " from $file:$line");
}
} # end if isset($IdOrRow)
} // end function __construct
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(get_class(), $parameters, $options);
}
public function Storage( $new = null ) {
if ( $new ) {
@ -108,24 +82,6 @@ class Event {
return new Monitor();
}
public function __call($fn, array $args){
if ( count($args) ) {
$this->{$fn} = $args[0];
}
if ( array_key_exists($fn, $this) ) {
return $this->{$fn};
$backTrace = debug_backtrace();
$file = $backTrace[0]['file'];
$line = $backTrace[0]['line'];
Warning("Unknown function call Event->$fn from $file:$line");
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Warning("Unknown function call Event->$fn from $file:$line");
Warning(print_r($this, true));
}
}
public function Time() {
if ( ! isset($this->{'Time'}) ) {
$this->{'Time'} = strtotime($this->{'StartTime'});
@ -170,35 +126,40 @@ class Event {
Error('Event delete on event with empty Id');
return;
}
if ( !ZM_OPT_FAST_DELETE ) {
if ( ZM_OPT_FAST_DELETE ) {
dbQuery('DELETE FROM Events WHERE Id = ?', array($this->{'Id'}));
return;
}
global $dbConn;
$dbConn->beginTransaction();
try {
$this->lock();
dbQuery('DELETE FROM Stats WHERE EventId = ?', array($this->{'Id'}));
dbQuery('DELETE FROM Frames WHERE EventId = ?', array($this->{'Id'}));
if ( $this->{'Scheme'} == 'Deep' ) {
# Assumption: All events have a start time
# Assumption: All events have a start time
$start_date = date_parse($this->{'StartTime'});
if ( ! $start_date ) {
Error('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
return;
throw new Exception('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
}
$start_date['year'] = $start_date['year'] % 100;
# So this is because ZM creates a link under the day pointing to the time that the event happened.
# So this is because ZM creates a link under the day pointing to the time that the event happened.
$link_path = $this->Link_Path();
if ( ! $link_path ) {
Error('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
return;
throw new Exception('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
}
$Storage = $this->Storage();
$eventlink_path = $Storage->Path().'/'.$link_path;
if ( $id_files = glob($eventlink_path) ) {
if ( ! $eventPath = readlink($id_files[0]) ) {
Error("Unable to read link at $id_files[0]");
return;
throw new Exception("Unable to read link at $id_files[0]");
}
# I know we are using arrays here, but really there can only ever be 1 in the array
# I know we are using arrays here, but really there can only ever be 1 in the array
$eventPath = preg_replace('/\.'.$this->{'Id'}.'$/', $eventPath, $id_files[0]);
deletePath($eventPath);
deletePath($id_files[0]);
@ -215,13 +176,29 @@ class Event {
} else {
$eventPath = $this->Path();
if ( ! $eventPath ) {
Error('No event Path in Event delete. Not deleting');
return;
throw new Exception('No event Path in Event delete. Not deleting');
}
deletePath($eventPath);
if ( $this->SecondaryStorageId() ) {
$Storage = $this->SecondaryStorage();
if ( $Storage->Id() ) {
$eventPath = $Storage->Path().'/'.$this->Relative_Path();
if ( ! $eventPath ) {
Error('No event Path in Event delete. Not deleting');
} else {
deletePath($eventPath);
}
} # end if Storage
} # end if has Secondary Storage
} # USE_DEEP_STORAGE OR NOT
} # ! ZM_OPT_FAST_DELETE
dbQuery('DELETE FROM Events WHERE Id = ?', array($this->{'Id'}));
dbQuery('DELETE FROM Events WHERE Id = ?', array($this->{'Id'}));
$dbConn->commit();
} catch (PDOException $e) {
$dbConn->rollback();
} catch (Exception $e) {
Error($e->getMessage());
$dbConn->rollback();
}
} # end Event->delete
public function getStreamSrc( $args=array(), $querySep='&' ) {
@ -509,81 +486,6 @@ class Event {
return $imageData;
}
public static function find_one( $parameters = null, $options = null ) {
global $event_cache;
if (
( count($parameters) == 1 ) and
isset($parameters['Id']) and
isset($event_cache[$parameters['Id']]) ) {
return $event_cache[$parameters['Id']];
}
$results = Event::find( $parameters, $options );
if ( count($results) > 1 ) {
Error("Event Returned more than 1");
return $results[0];
} else if ( count($results) ) {
return $results[0];
} else {
return null;
}
}
public static function find( $parameters = null, $options = null ) {
$sql = 'SELECT * FROM Events ';
$values = array();
if ( $parameters ) {
$fields = array();
$sql .= 'WHERE ';
foreach ( $parameters as $field => $value ) {
if ( $value == null ) {
$fields[] = $field.' IS NULL';
} else if ( is_array( $value ) ) {
$func = function(){return '?';};
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
$values += $value;
} else {
$fields[] = $field.'=?';
$values[] = $value;
}
}
$sql .= implode(' AND ', $fields );
}
if ( $options ) {
if ( isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
}
if ( isset($options['limit']) ) {
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
$sql .= ' LIMIT ' . $options['limit'];
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Error("Invalid value for limit(".$options['limit'].") passed to Event::find from $file:$line");
return array();
}
}
}
$filters = array();
$result = dbQuery($sql, $values);
if ( $result ) {
$results = $result->fetchALL();
foreach ( $results as $row ) {
$filters[] = new Event($row);
}
}
return $filters;
}
public function save( ) {
$sql = 'UPDATE Events SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $this->fields ) ) . ' WHERE Id=?';
$values = array_map( function($field){return $this->{$field};}, $this->fields );
$values[] = $this->{'Id'};
dbQuery( $sql, $values );
}
public function link_to($text=null) {
if ( !$text )
$text = $this->{'Id'};
@ -686,18 +588,14 @@ class Event {
public function can_delete() {
if ( $this->Archived() ) {
Logger::Debug("Am archived, can't delete");
return false;
}
if ( !$this->EndTime() ) {
Logger::Debug("No EndTime can't delete");
return false;
}
if ( !canEdit('Events') ) {
Logger::Debug("No permission to edit events, can't delete");
return false;
}
Logger::Debug("Can delete: archived: " . $this->Archived() . " endtime: " . $this->EndTime() );
return true;
}

View File

@ -167,6 +167,12 @@ class Filter extends ZM_Object {
} # end if local or remote
} # end foreach erver
} # end function control
public function execute() {
$command = ZM_PATH_BIN.'/zmfilter.pl --filter_id='.escapeshellarg($this->Id());
$result = exec($command, $output, $status);
Logger::Debug("$command status:$status output:".implode("\n", $output));
return $status;
}
} # end class Filter

View File

@ -252,5 +252,13 @@ class ZM_Object {
unset($object_cache[$class][$this->{'Id'}]);
}
} # end class Sensor Action
public function lock() {
$class = get_class($this);
$table = $class::$table;
$row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($this->Id()));
if ( !$row ) {
Error("Unable to lock $class record for Id=".$this->Id());
}
}
} # end class Object
?>

View File

@ -44,11 +44,9 @@ if ( $action == 'archive' ) {
$dbConn->commit();
$refreshParent = true;
} else if ( $action == 'delete' ) {
$dbConn->beginTransaction();
foreach ( getAffectedIds('eids') as $markEid ) {
deleteEvent($markEid);
}
$dbConn->commit();
$refreshParent = true;
}
?>

View File

@ -50,14 +50,6 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
$_REQUEST['filter']['Query']['sort_field'] = validStr($_REQUEST['filter']['Query']['sort_field']);
$_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
if ( $action == 'execute' ) {
$_REQUEST['filter']['Name'] = '_TempFilter'.time();
unset($_REQUEST['Id']);
#$tempFilterName = '_TempFilter'.time();
#$sql .= ' Name = \''.$tempFilterName.'\'';
#} else {
#$sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
}
$_REQUEST['filter']['AutoCopy'] = empty($_REQUEST['filter']['AutoCopy']) ? 0 : 1;
$_REQUEST['filter']['AutoMove'] = empty($_REQUEST['filter']['AutoMove']) ? 0 : 1;
@ -102,19 +94,28 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
if ( $filter->Background() )
$filter->control('stop');
} else {
# COuld be execute
if ( 0 ) {
dbQuery('INSERT INTO Filters SET'.$sql);
$_REQUEST['Id'] = dbInsertId();
$filter = new ZM\Filter($_REQUEST['Id']);
}
if ( $action == 'execute' ) {
if ( count($changes) ) {
$filter->Name('_TempFilter'.time());
$filter->Id(null);
}
} else if ( $action == 'SaveAs' ) {
$filter->Id(null);
}
$filter->save($changes);
// We update the request id so that the newly saved filter is auto-selected
$_REQUEST['Id'] = $filter->Id();
}
if ( $filter->Background() )
$filter->control('start');
if ( $action == 'execute' ) {
executeFilter($_REQUEST['Id']);
$filter->execute();
if ( count($changes) )
$filter->delete();
$view = 'events';
}

View File

@ -83,6 +83,9 @@ if ( $action == 'monitor' ) {
dbQuery('UPDATE Monitors SET '.implode(', ', $changes).' WHERE Id=?', array($mid));
// Groups will be added below
if ( isset($changes['Name']) or isset($changes['StorageId']) ) {
// creating symlinks when symlink already exists reports errors, but is perfectly ok
error_reporting(0);
$OldStorage = new ZM\Storage($monitor['StorageId']);
$saferOldName = basename($monitor['Name']);
if ( file_exists($OldStorage->Path().'/'.$saferOldName) )
@ -95,8 +98,11 @@ if ( $action == 'monitor' ) {
}
}
$saferNewName = basename($_REQUEST['newMonitor']['Name']);
if ( !symlink($NewStorage->Path().'/'.$mid, $NewStorage->Path().'/'.$saferNewName) ) {
ZM\Warning('Unable to symlink ' . $NewStorage->Path().'/'.$mid . ' to ' . $NewStorage->Path().'/'.$saferNewName);
$link_path = $NewStorage->Path().'/'.$saferNewName;
if ( !symlink($NewStorage->Path().'/'.$mid, $link_path) ) {
if ( ! ( file_exists($link_path) and is_link($link_path) ) ) {
ZM\Warning('Unable to symlink ' . $NewStorage->Path().'/'.$mid . ' to ' . $NewStorage->Path().'/'.$saferNewName);
}
}
}
if ( isset($changes['Width']) || isset($changes['Height']) ) {

View File

@ -188,7 +188,7 @@ function getAuthUser($auth) {
if ( $auth == $authHash ) {
return $user;
} // en dif $auth == $authHash
} // end if $auth == $authHash
} // end foreach hour
} // end foreach user
} // end if using auth hash
@ -243,6 +243,27 @@ function canEdit($area, $mid=false) {
return ( $user[$area] == 'Edit' && ( !$mid || visibleMonitor($mid) ));
}
function userFromSession() {
$user = null; // Not global
if ( isset($_SESSION['username']) ) {
if ( ZM_AUTH_HASH_LOGINS and (ZM_AUTH_RELAY == 'hashed') ) {
# Extra validation, if logged in, then the auth hash will be set in the session, so we can validate it.
# This prevent session modification to switch users
if ( isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) )
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
else
ZM\Logger::Debug("No auth hash in session, there should have been");
} else {
# Need to refresh permissions and validate that the user still exists
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
$user = dbFetchOne($sql, NULL, array($_SESSION['username']));
}
} else {
ZM\Logger::Debug('No username in session');
}
return $user;
}
if ( ZM_OPT_USE_AUTH ) {
if ( !empty($_REQUEST['token']) ) {
$ret = validateToken($_REQUEST['token'], 'access');
@ -250,23 +271,7 @@ if ( ZM_OPT_USE_AUTH ) {
} else {
// Non token based auth
if ( isset($_SESSION['username']) ) {
if ( ZM_AUTH_HASH_LOGINS and (ZM_AUTH_RELAY == 'hashed') ) {
# Extra validation, if logged in, then the auth hash will be set in the session, so we can validate it.
# This prevent session modification to switch users
if ( isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) )
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
else
ZM\Logger::Debug("No auth hash in session, there should have been");
} else {
# Need to refresh permissions and validate that the user still exists
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
$user = dbFetchOne($sql, NULL, array($_SESSION['username']));
}
} else {
ZM\Logger::Debug("No username in session");
}
$user = userFromSession();
if ( ZM_AUTH_HASH_LOGINS && empty($user) && !empty($_REQUEST['auth']) ) {
$user = getAuthUser($_REQUEST['auth']);

View File

@ -56,7 +56,7 @@ function dbConnect() {
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $ex ) {
} catch(PDOException $ex) {
echo 'Unable to connect to ZM db.' . $ex->getMessage();
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
$dbConn = null;

View File

@ -414,6 +414,7 @@ function getEventDefaultVideoPath( $event ) {
}
function deletePath( $path ) {
ZM\Logger::Debug("Deleting $path");
if ( is_dir( $path ) ) {
system( escapeshellcmd( 'rm -rf '.$path ) );
} else if ( file_exists($path) ) {
@ -973,13 +974,6 @@ Logger::Debug("generating Video $command: result($result outptu:(".implode("\n",
return( $status?"":rtrim($result) );
}
function executeFilter( $filter_id ) {
$command = ZM_PATH_BIN.'/zmfilter.pl --filter_id '.escapeshellarg($filter_id);
$result = exec($command, $output, $status);
dbQuery('DELETE FROM Filters WHERE Id=?', array($filter_id));
return $status;
}
# This takes more than one scale amount, so it runs through each and alters dimension.
# I can't imagine why you would want to do that.
function reScale( $dimension, $dummy ) {
@ -1213,6 +1207,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
case 'DiskSpace':
case 'MonitorId':
case 'StorageId':
case 'SecondaryStorageId':
case 'Length':
case 'Frames':
case 'AlarmFrames':

View File

@ -21,11 +21,18 @@ function zm_session_start() {
session_start();
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
$now = time();
// Do not allow to use expired session ID
if ( !empty($_SESSION['last_time']) && ($_SESSION['last_time'] < (time() - 180)) ) {
if ( !empty($_SESSION['last_time']) && ($_SESSION['last_time'] < ($now - 180)) ) {
ZM\Info('Destroying session due to timeout. ');
session_destroy();
session_start();
} else if ( !empty($_SESSION['generated_at']) ) {
ZM\Logger::Debug("Have generated_at: " . $_SESSION['generated_at']);
if ( $_SESSION['generated_at']<($now-(ZM_COOKIE_LIFETIME/2)) ) {
ZM\Logger::Debug("Regenerating session because generated_at " . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
zm_session_regenerate_id();
}
}
} // function zm_session_start()
@ -44,6 +51,7 @@ function zm_session_regenerate_id() {
session_start();
session_regenerate_id();
unset($_SESSION['last_time']);
$_SESSION['generated_at'] = time();
} // function zm_session_regenerate_id()
function is_session_started() {

View File

@ -143,7 +143,6 @@ if (
# Only one request can open the session file at a time, so let's close the session here to improve concurrency.
# Any file/page that sets session variables must re-open it.
session_write_close();
require_once('includes/lang.php');
@ -176,6 +175,7 @@ if ( isset($_REQUEST['request']) )
$request = detaintPath($_REQUEST['request']);
require_once('includes/auth.php');
session_write_close();
foreach ( getSkinIncludes('skin.php') as $includeFile ) {
require_once $includeFile;
@ -210,7 +210,7 @@ if (
}
# Need to include actions because it does auth
if ( $action ) {
if ( $action and !$request ) {
if ( file_exists('includes/actions/'.$view.'.php') ) {
ZM\Logger::Debug("Including includes/actions/$view.php");
require_once('includes/actions/'.$view.'.php');

View File

@ -1,3 +1,5 @@
input[type="url"] {
input[name="newStorage[Name]"],
input[name="newStorage[Path]"],
input[name="newStorage[Url]"] {
width: 100%;
}

View File

@ -152,8 +152,8 @@ if ( canEdit('Events') ) {
?>
<div id="deleteEvent"><button type="button" data-on-click="deleteEvent" <?php echo $Event->can_delete() ? '' : ' disabled="disabled" title="'.$Event->cant_delete_reason().'"' ?>><?php echo translate('Delete') ?></button></div>
<div id="editEvent"><button type="button" data-on-click="editEvent"><?php echo translate('Edit') ?></button></div>
<div id="archiveEvent"<?php echo $Event->Archived == 1 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="archiveEvent"><?php echo translate('Archive') ?></button></div>
<div id="unarchiveEvent"<?php echo $Event->Archived == 0 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="unarchiveEvent"><?php echo translate('Unarchive') ?></button></div>
<div id="archiveEvent"<?php echo $Event->Archived() == 1 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="archiveEvent"><?php echo translate('Archive') ?></button></div>
<div id="unarchiveEvent"<?php echo $Event->Archived() == 0 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="unarchiveEvent"><?php echo translate('Unarchive') ?></button></div>
<?php
} // end if can edit Events
?>

View File

@ -28,9 +28,9 @@ require_once('includes/Event.php');
$countSql = 'SELECT count(E.Id) AS EventCount FROM Monitors AS M INNER JOIN Events AS E ON (M.Id = E.MonitorId) WHERE';
$eventsSql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultScale FROM Monitors AS M INNER JOIN Events AS E on (M.Id = E.MonitorId) WHERE';
if ( $user['MonitorIds'] ) {
$user_monitor_ids = ' M.Id in ('.$user['MonitorIds'].')';
$countSql .= $user_monitor_ids;
$eventsSql .= $user_monitor_ids;
$user_monitor_ids = ' M.Id in ('.$user['MonitorIds'].')';
$countSql .= $user_monitor_ids;
$eventsSql .= $user_monitor_ids;
} else {
$countSql .= ' 1';
$eventsSql .= ' 1';
@ -192,24 +192,23 @@ while ( $event_row = dbFetchNext($results) ) {
<tr<?php if ($event->Archived()) echo ' class="archived"' ?>>
<td class="colId"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.$event->Id().($event->Archived()?'*':'') ?></a></td>
<td class="colName"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a></td>
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->MonitorId(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?>
<?php
# display notes as small text
if ($event->Notes()) {
# if notes include detection objects, then link it to objdetect.jpg
if (strpos($event->Notes(),"detected:")!== false){
# make a link
echo makePopupLink( '?view=image&amp;eid='.$event->Id().'&amp;fid=objdetect', 'zmImage',
array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)),
"<div class=\"small text-nowrap text-muted\"><u>".$event->Notes()."</u></div>");
}
elseif ($event->Notes() != 'Forced Web: ') {
echo "<br/><div class=\"small text-nowrap text-muted\">".$event->Notes()."</div>";
}
}
?>
<?php
# display notes as small text
if ($event->Notes()) {
# if notes include detection objects, then link it to objdetect.jpg
if (strpos($event->Notes(),'detected:')!== false){
# make a link
echo makePopupLink( '?view=image&amp;eid='.$event->Id().'&amp;fid=objdetect', 'zmImage',
array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)),
"<div class=\"small text-nowrap text-muted\"><u>".$event->Notes()."</u></div>");
}
elseif ($event->Notes() != 'Forced Web: ') {
echo "<br/><div class=\"small text-nowrap text-muted\">".$event->Notes()."</div>";
}
}
?>
</td>
<td class="colTime"><?php echo strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime())) .
( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?>
@ -230,7 +229,18 @@ while ( $event_row = dbFetchNext($results) ) {
<?php
if ( count($storage_areas) > 1 ) {
?>
<td class="colStorage"><?php echo isset($StorageById[$event->StorageId()]) ? $StorageById[$event->StorageId()]->Name() : '' ?></td>
<td class="colStorage">
<?php
if ( $event->StorageId() ) {
echo isset($StorageById[$event->StorageId()]) ? $StorageById[$event->StorageId()]->Name() : 'Unknown Storage Id: '.$event->StorageId();
} else {
echo 'Default';
}
if ( $event->SecondaryStorageId() ) {
echo '<br/>'.(isset($StorageById[$event->SecondaryStorageId()]) ? $StorageById[$event->SecondaryStorageId()]->Name() : 'Unknown Storage Id '.$event->SecondaryStorageId());
}
?>
</td>
<?php
}
@ -247,7 +257,7 @@ while ( $event_row = dbFetchNext($results) ) {
$streamSrc = $event->getStreamSrc(array(
'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single'));
$imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($event->ThumbnailWidth()) .'px;height:'. validInt($event->ThumbnailHeight()).'px;" stream_src="'.$streamSrc.'" still_src="'.$imgSrc.'"/>';
$imgHtml = '<img id="thumbnail'.$event->Id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($event->ThumbnailWidth()) .'px;height:'. validInt($event->ThumbnailHeight()).'px;" stream_src="'.$streamSrc.'" still_src="'.$imgSrc.'"/>';
echo '<a href="?view=event&amp;eid='. $event->Id().$filterQuery.$sortQuery.'&amp;page=1">'.$imgHtml.'</a>';
echo '</td>';
} // end if ZM_WEB_LIST_THUMBS

View File

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

View File

@ -201,8 +201,9 @@ function changeReplayMode() {
}
var streamParms = "view=request&request=stream&connkey="+connKey;
if ( auth_hash )
streamCmdParms += '&auth='+auth_hash;
if ( auth_hash ) {
streamParms += '&auth='+auth_hash;
}
var streamCmdTimer = null;
var streamStatus = null;
@ -312,7 +313,6 @@ function playClicked( ) {
vjsPlay(); //handles fast forward and rewind
}
} else {
console.log("sending"+streamParms+"&command="+CMD_PLAY);
streamReq.send(streamParms+"&command="+CMD_PLAY);
streamPlay();
}
@ -600,8 +600,9 @@ var eventReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIM
function eventQuery( eventId ) {
var eventParms = "view=request&request=status&entity=event&id="+eventId;
if ( auth_hash )
eventParms += '&auth='+auth_hash;
if ( auth_hash ) {
eventParms += '&auth='+auth_hash;
}
eventReq.send( eventParms );
}
@ -900,14 +901,15 @@ function getActResponse( respObj, respText ) {
var actReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getActResponse} );
function actQuery( action, parms ) {
function actQuery(action, parms) {
var actParms = "view=request&request=event&id="+eventData.Id+"&action="+action;
if ( auth_hash )
actParms += '&auth='+auth_hash;
if ( parms != null ) {
actParms += "&"+Object.toQueryString( parms );
if ( auth_hash ) {
actParms += '&auth='+auth_hash;
}
actReq.send( actParms );
if ( parms != null ) {
actParms += "&"+Object.toQueryString(parms);
}
actReq.send(actParms);
}
function deleteEvent() {

View File

@ -36,7 +36,7 @@ var eventData = {
Frames: '<?php echo $Event->Frames() ?>',
MonitorName: '<?php echo $Monitor->Name() ?>'
};
var monitorUrl = '<?php echo $Monitor->UrlToIndex(); ?>';
var monitorUrl = '<?php echo $Event->Storage()->Server()->UrlToIndex(); ?>';
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';

View File

@ -30,13 +30,17 @@ function validateForm( form ) {
function updateButtons(element) {
var form = element.form;
console.log(element);
if ( element.type == 'checkbox' && element.checked ) {
form.elements['executeButton'].disabled = false;
} else {
var canExecute = false;
if ( form.elements['filter[AutoArchive]'] && form.elements['filter[AutoArchive]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoCopy]'] && form.elements['filter[AutoCopy]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoMove]'] && form.elements['filter[AutoMove]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoVideo]'] && form.elements['filter[AutoVideo]'].checked ) {
canExecute = true;
} else if ( form.elements['filter[AutoUpload]'] && form.elements['filter[AutoUpload]'].checked ) {

View File

@ -155,9 +155,8 @@ function getImageSource(monId, time) {
frame_id = Frame.FrameId + parseInt( (NextFrame.FrameId-Frame.FrameId) * ( time-Frame.TimeStampSecs )/duration );
//console.log("Have NextFrame: duration: " + duration + " frame_id = " + frame_id + " from " + NextFrame.FrameId + ' - ' + Frame.FrameId + " time: " + (time-Frame.TimeStampSecs) );
} else {
frame_id = Frame.FrameId;
}
frame_id = Frame.FrameId;
}
} else {
frame_id = Frame.FrameId;
console.log("No NextFrame");
@ -1010,7 +1009,8 @@ function initPage() {
$j('#maxTime').datetimepicker({
timeFormat: "HH:mm:ss",
dateFormat: "yy-mm-dd",
minDate: $j('#minTime').val(),
//minDate: $j('#minTime').val(),
minDate: -7,
maxDate: +0,
constrainInput: false,
onClose: function(newDate, oldData) {

View File

@ -19,7 +19,7 @@ xhtmlHeaders(__FILE__, translate('Login') );
<h1><i class="material-icons md-36">account_circle</i> <?php echo validHtmlStr(ZM_WEB_TITLE) . ' ' . translate('Login') ?></h1>
<label for="inputUsername" class="sr-only"><?php echo translate('Username') ?></label>
<input type="text" id="inputUsername" name="username" class="form-control" placeholder="Username" required autofocus autocomplete="username"/>
<input type="text" id="inputUsername" name="username" class="form-control" autocapitalize="none" placeholder="Username" required autofocus autocomplete="username"/>
<label for="inputPassword" class="sr-only"><?php echo translate('Password') ?></label>
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required autocomplete="current-password"/>

View File

@ -950,10 +950,7 @@ if ( $monitor->Type() == 'Local' ) {
0 => 'Disabled',
);
if (stripos(php_uname('m'), 'arm') === false )
$videowriteropts[1] = 'X264 Encode';
else
$videowriteropts[1] = array('text'=>'X264 Encode - Not compatible on Arm','disabled'=>1);
$videowriteropts[1] = 'X264 Encode';
if ($monitor->Type() == 'Ffmpeg' )
$videowriteropts[2] = 'H264 Camera Passthrough';

View File

@ -100,7 +100,7 @@ if ( empty($_REQUEST['path']) ) {
}
}
$Monitor = $Event->Monitor();
if ( $Monitor->SaveJPEGs() & 1 ) {
if ( $Event->SaveJPEGs() & 1 ) {
# If we store Frames as jpgs, then we don't store an alarmed snapshot
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg';
} else {
@ -114,14 +114,14 @@ if ( empty($_REQUEST['path']) ) {
ZM\Warning('No frame found for event ' . $_REQUEST['eid']);
$Frame = new ZM\Frame();
$Frame->Delta(1);
if ( $Monitor->SaveJPEGs() & 1 ) {
if ( $Event->SaveJPEGs() & 1 ) {
$Frame->FrameId(0);
} else {
$Frame->FrameId('snapshot');
}
}
$Monitor = $Event->Monitor();
if ( $Monitor->SaveJPEGs() & 1 ) {
if ( $Event->SaveJPEGs() & 1 ) {
# If we store Frames as jpgs, then we don't store a snapshot
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg';
} else {