diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in
index 6c271292d..b46d5c0bd 100644
--- a/db/zm_create.sql.in
+++ b/db/zm_create.sql.in
@@ -636,7 +636,7 @@ insert into Users VALUES (NULL,'admin',password('admin'),'',1,'View','Edit','Edi
--
-- 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,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,0,0,0,0,0,'',1,0,1,0);
--
-- Add in some sample control protocol definitions
@@ -764,6 +764,21 @@ CREATE TABLE Maps (
`ParentId` int(1) unsigned,
PRIMARY KEY (`Id`)
);
+
+CREATE TABLE MontageLayouts (
+ `Id` int(10) unsigned NOT NULL auto_increment,
+ `Name` TEXT NOT NULL,
+ `Positions` LONGTEXT,
+ /*`Positions` JSON,*/
+ PRIMARY KEY (`Id`)
+);
+
+INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('Freeform', '{ "default":{"float":"left","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
+INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('2 Wide', '{ "default":{"float":"left", "width":"49%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
+INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{"float":"left", "width":"33%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
+INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
+INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
+
--
-- Apply the initial configuration
--
diff --git a/db/zm_update-1.31.11.sql b/db/zm_update-1.31.11.sql
new file mode 100644
index 000000000..de17d85d9
--- /dev/null
+++ b/db/zm_update-1.31.11.sql
@@ -0,0 +1,69 @@
+--
+-- Add UpdateDiskSpace action to Filters
+--
+
+SET @s = (SELECT IF(
+ (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
+ AND table_name = 'Filters'
+ AND column_name = 'UpdateDiskSpace'
+ ) > 0,
+"SELECT 'Column UpdateDiskSpace already exists in Filters'",
+"ALTER TABLE Filters ADD `UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoDelete`"
+));
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+--
+-- Update Logs table to have some Indexes
+--
+SET @s = (SELECT IF(
+ (SELECT COUNT(*)
+ FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE table_name = 'Logs'
+ AND table_schema = DATABASE()
+ AND index_name = 'Logs_TimeKey_idx'
+ ) > 0,
+"SELECT 'Logs_TimeKey_idx already exists on Logs table'",
+"CREATE INDEX `Logs_TimeKey_idx` ON `Logs` (`TimeKey`)"
+));
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+SET @s = (SELECT IF(
+ (SELECT COUNT(*)
+ FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE table_name = 'Logs'
+ AND table_schema = DATABASE()
+ AND index_name = 'Logs_Level_idx'
+ ) > 0,
+"SELECT 'Logs_Level_idx already exists on Logs table'",
+"CREATE INDEX `Logs_Level_idx` ON `Logs` (`Level`)"
+));
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+SET @s = (SELECT IF(
+ (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
+ AND table_name = 'Monitors'
+ AND column_name = 'OutputCodec'
+ ) > 0,
+"SELECT 'Column OutputCodec already exists in Monitors'",
+"ALTER TABLE `Monitors` ADD `OutputCodec` enum('h264','mjpeg') AFTER `VideoWriter`"
+));
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+SET @s = (SELECT IF(
+ (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
+ AND table_name = 'Monitors'
+ AND column_name = 'OutputContainer'
+ ) > 0,
+"SELECT 'Column OutputContainer already exists in Monitors'",
+"ALTER TABLE `Monitors` ADD `OutputContainer` enum('mp4','mkv') AFTER `OutputCodec`"
+));
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
diff --git a/db/zm_update-1.31.12.sql b/db/zm_update-1.31.12.sql
new file mode 100644
index 000000000..72dee28ce
--- /dev/null
+++ b/db/zm_update-1.31.12.sql
@@ -0,0 +1,67 @@
+--
+-- This adds Manufacturers and Models
+--
+
+SET @s = (SELECT IF(
+ (SELECT COUNT(*)
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE table_name = 'MontageLayouts'
+ AND table_schema = DATABASE()
+ ) > 0,
+ "SELECT 'MontageLayouts table exists'",
+ "
+ CREATE TABLE MontageLayouts (
+ `Id` int(10) unsigned NOT NULL auto_increment,
+ `Name` TEXT NOT NULL,
+ `Positions` LONGTEXT,
+ PRIMARY KEY (`Id`)
+);
+"
+ ));
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+DELETE FROM MontageLayouts WHERE Name IN ('Freeform','2 Wide','3 Wide','4 Wide','5 Wide');
+
+SET @s = ( SELECT IF(
+ (SELECT COUNT(*) FROM MontageLayouts WHERE Name='Freeform') > 0,
+ "SELECT 'Freeform already in layouts'",
+'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'Freeform\', \'{"default":{"float":"left","position":"relative","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
+) );
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+SET @s = ( SELECT IF(
+ (SELECT COUNT(*) FROM MontageLayouts WHERE Name='2 Wide') > 0,
+"SELECT '2 Wide already in layouts'",
+'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'2 Wide\', \'{"default":{"float":"left","position":"relative","width":"49%","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
+) );
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+SET @s = ( SELECT IF(
+ (SELECT COUNT(*) FROM MontageLayouts WHERE Name='3 Wide') > 0,
+ "SELECT '3 Wide already in layouts'",
+'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'3 Wide\', \'{"default":{"float":"left","position":"relative","width":"33%","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
+) );
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+SET @s = ( SELECT IF(
+ (SELECT COUNT(*) FROM MontageLayouts WHERE Name='4 Wide') > 0,
+ "SELECT '4 Wide already in layouts'",
+'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'4 Wide\', \'{"default":{"float":"left","position":"relative","width":"24.5%","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
+) );
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+SET @s = ( SELECT IF(
+ (SELECT COUNT(*) FROM MontageLayouts WHERE Name='5 Wide') > 0,
+ "SELECT '5 Wide already in layouts'",
+ 'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'5 Wide\', \'{"default":{"float":"left","position":"relative","width":"19%"}}\' );'
+) );
+
+PREPARE stmt FROM @s;
+EXECUTE stmt;
diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules
index 6bc3dffb5..53a9a237a 100755
--- a/distros/ubuntu1604/rules
+++ b/distros/ubuntu1604/rules
@@ -27,7 +27,7 @@ override_dh_auto_configure:
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
- -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
+ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
override_dh_clean:
dh_clean $(MANPAGES1)
diff --git a/distros/ubuntu1604/zoneminder.dirs b/distros/ubuntu1604/zoneminder.dirs
index 56dd56e6b..08840aef4 100644
--- a/distros/ubuntu1604/zoneminder.dirs
+++ b/distros/ubuntu1604/zoneminder.dirs
@@ -4,5 +4,6 @@ var/cache/zoneminder/events
var/cache/zoneminder/images
var/cache/zoneminder/temp
usr/share/zoneminder/db
+usr/share/zoneminder/www/cache
etc/zm/
etc/zm/conf.d
diff --git a/distros/ubuntu1604/zoneminder.tmpfile b/distros/ubuntu1604/zoneminder.tmpfile
index ef68288ba..f23ca55b3 100644
--- a/distros/ubuntu1604/zoneminder.tmpfile
+++ b/distros/ubuntu1604/zoneminder.tmpfile
@@ -1,3 +1,4 @@
d /var/run/zm 0755 www-data www-data
d /tmp/zm 0755 www-data www-data
d /var/tmp/zm 0755 www-data www-data
+d /usr/share/zoneminder/www/cache 0755 www-data www-data
diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm
index 8d752600d..19a5f8662 100644
--- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm
+++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm
@@ -205,6 +205,30 @@ sub zmDbGetMonitorAndControl {
return( $monitor );
}
+sub start_transaction {
+ #my ( $caller, undef, $line ) = caller;
+#$openprint::log->debug("Called start_transaction from $caller : $line");
+ my $d = shift;
+ $d = $dbh if ! $d;
+ my $ac = $d->{AutoCommit};
+ $d->{AutoCommit} = 0;
+ return $ac;
+} # end sub start_transaction
+
+sub end_transaction {
+ #my ( $caller, undef, $line ) = caller;
+#$openprint::log->debug("Called end_transaction from $caller : $line");
+ my ( $d, $ac ) = @_;
+if ( ! defined $ac ) {
+ Error("Undefined ac");
+}
+ $d = $dbh if ! $d;
+ if ( $ac ) {
+ #$log->debug("Committing");
+ $d->commit();
+ } # end if
+ $d->{AutoCommit} = $ac;
+} # end sub end_transaction
1;
__END__
# Below is stub documentation for your module. You'd better edit it!
diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm
index fbb249773..2fc590977 100644
--- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm
+++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm
@@ -48,9 +48,38 @@ use ZoneMinder::Logger qw(:all);
use ZoneMinder::Database qw(:all);
require Date::Parse;
-use vars qw/ $table $primary_key /;
+use vars qw/ $table $primary_key %fields $serial @identified_by/;
$table = 'Events';
-$primary_key = 'Id';
+@identified_by = ('Id');
+$serial = $primary_key = 'Id';
+%fields = map { $_, $_ } qw(
+ Id
+ MonitorId
+ StorageId
+ Name
+ Cause
+ StartTime
+ EndTime
+ Width
+ Height
+ Length
+ Frames
+ AlarmFrames
+ DefaultVideo
+ TotScore
+ AvgScore
+ MaxScore
+ Archived
+ Videoed
+ Uploaded
+ Emailed
+ Messaged
+ Executed
+ Notes
+ StateId
+ Orientation
+ DiskSpace
+);
use POSIX;
@@ -359,14 +388,16 @@ sub age {
return $_[0]{age};
}
-sub DiskUsage {
+sub DiskSpace {
if ( @_ > 1 ) {
- $_[0]{DiskUsage} = $_[1];
+ Debug("Cleared DiskSpace, was $_[0]{DiskSpace}");
+ $_[0]{DiskSpace} = $_[1];
}
- if ( ! defined $_[0]{DiskUsage} ) {
+ if ( ! defined $_[0]{DiskSpace} ) {
my $size = 0;
File::Find::find( { wanted=>sub { $size += -f $_ ? -s _ : 0 }, untaint=>1 }, $_[0]->Path() );
- $_[0]{DiskUsage} = $size;
+ $_[0]{DiskSpace} = $size;
+ Debug("DiskSpace for event $_[0]{Id} at $_[0]{Path} Updated to $size bytes");
}
}
diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm
index 82deff6ff..02209a55c 100644
--- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm
+++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm
@@ -224,7 +224,7 @@ sub Sql {
|| $term->{attr} eq 'Notes'
) {
$value = "'$temp_value'";
- } elsif ( $term->{attr} eq 'DateTime' ) {
+ } elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) {
$value = DateTimeToSQL( $temp_value );
if ( !$value ) {
Error( "Error parsing date/time '$temp_value', "
@@ -232,7 +232,7 @@ sub Sql {
return;
}
$value = "'$value'";
- } elsif ( $term->{attr} eq 'Date' ) {
+ } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
$value = DateTimeToSQL( $temp_value );
if ( !$value ) {
Error( "Error parsing date/time '$temp_value', "
@@ -240,7 +240,7 @@ sub Sql {
return;
}
$value = "to_days( '$value' )";
- } elsif ( $term->{attr} eq 'Time' ) {
+ } elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) {
$value = DateTimeToSQL( $temp_value );
if ( !$value ) {
Error( "Error parsing date/time '$temp_value', "
@@ -259,6 +259,10 @@ sub Sql {
$self->{Sql} .= " regexp $value";
} elsif ( $term->{op} eq '!~' ) {
$self->{Sql} .= " not regexp $value";
+ } elsif ( $term->{op} eq 'IS' ) {
+ $self->{Sql} .= " IS $value";
+ } elsif ( $term->{op} eq 'IS NOT' ) {
+ $self->{Sql} .= " IS NOT $value";
} elsif ( $term->{op} eq '=[]' ) {
$self->{Sql} .= " in (".join( ",", @value_list ).")";
} elsif ( $term->{op} eq '!~' ) {
@@ -277,15 +281,15 @@ sub Sql {
if ( $self->{AutoMessage} ) {
# Include all events, including events that are still ongoing
# and have no EndTime yet
- $sql .= " and ( ".$self->{Sql}." )";
+ $sql .= ' AND ( '.$self->{Sql}.' )';
} else {
# Only include closed events (events with valid EndTime)
- $sql .= " where not isnull(E.EndTime) and ( ".$self->{Sql}." )";
+ $sql .= ' WHERE (E.EndTime IS NOT NULL) AND ( '.$self->{Sql}.' )';
}
}
my @auto_terms;
if ( $self->{AutoArchive} ) {
- push @auto_terms, "E.Archived = 0";
+ push @auto_terms, 'E.Archived = 0';
}
# Don't do this, it prevents re-generation and concatenation.
# If the file already exists, then the video won't be re-recreated
diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm
index d0d6b234b..a81a4d87b 100644
--- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm
+++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm
@@ -678,7 +678,10 @@ sub Dump {
fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) );
}
-sub debug { fetch()->logPrint( DEBUG, @_ ); }
+sub debug {
+ my $log = shift;
+ $log->logPrint( DEBUG, @_ );
+}
sub Debug( @ ) {
fetch()->logPrint( DEBUG, @_ );
@@ -688,7 +691,8 @@ sub Info( @ ) {
fetch()->logPrint( INFO, @_ );
}
sub info {
- fetch()->logPrint( INFO, @_ );
+ my $log = shift;
+ $log->logPrint( INFO, @_ );
}
@@ -696,14 +700,16 @@ sub Warning( @ ) {
fetch()->logPrint( WARNING, @_ );
}
sub warn {
- fetch()->logPrint( WARNING, @_ );
+ my $log = shift;
+ $log->logPrint( WARNING, @_ );
}
sub Error( @ ) {
fetch()->logPrint( ERROR, @_ );
}
sub error {
- fetch()->logPrint( ERROR, @_ );
+ my $log = shift;
+ $log->logPrint( ERROR, @_ );
}
sub Fatal( @ ) {
diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm
index a2d9fa021..d96221405 100644
--- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm
+++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm
@@ -153,7 +153,7 @@ sub save {
my $serial = eval '$'.$type.'::serial';
my @identified_by = eval '@'.$type.'::identified_by';
- my $ac = sql::start_transaction( $local_dbh );
+ my $ac = ZoneMinder::Database::start_transaction( $local_dbh );
if ( ! $serial ) {
my $insert = $force_insert;
my %serial = eval '%'.$type.'::serial';
@@ -170,7 +170,7 @@ $log->debug("No serial") if $debug;
$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();
- sql::end_transaction( $local_dbh, $ac );
+ ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $local_dbh->errstr;
} elsif ( $debug ) {
$log->debug("SQL succesful DELETE FROM $table WHERE $where");
@@ -185,8 +185,11 @@ $log->debug("No serial") if $debug;
next;
}
if ( ! $$self{$id} ) {
- ($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} );
- $log->debug("SQL statement execution SELECT nextval('$serial{$id}') returned $$self{$id}") if $debug or DEBUG_ALL;
+ 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{')} );
+ $log->debug("SQL statement execution SELECT $s returned $$self{$id}") if $debug or DEBUG_ALL;
$insert = 1;
} # end if
} # end foreach
@@ -200,7 +203,7 @@ $log->debug("No serial") if $debug;
$command =~ s/\?/\%s/g;
$log->error('SQL statement execution failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $local_dbh->errstr);
$local_dbh->rollback();
- sql::end_transaction( $local_dbh, $ac );
+ ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
@@ -215,7 +218,7 @@ $log->debug("No serial") if $debug;
$command =~ s/\?/\%s/g;
$log->error('SQL failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys, @$fields{@identified_by}}) ).'):' . $local_dbh->errstr);
$local_dbh->rollback();
- sql::end_transaction( $local_dbh, $ac );
+ ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
@@ -224,22 +227,28 @@ $log->debug("No serial") if $debug;
} # end if
} # end if
} else { # not identified_by
- @identified_by = ('id') if ! @identified_by;
- my $need_serial = ! ( @identified_by == map { $$self{$_} ? $_ : () } @identified_by );
+ @identified_by = ('Id') if ! @identified_by;
+
+ # If the size of the arrays are not equal which means one or more are missing
+ my @identified_by_without_values = map { $$self{$_} ? () : $_ } @identified_by;
+ my $need_serial = @identified_by_without_values > 0;
if ( $force_insert or $need_serial ) {
if ( $need_serial ) {
if ( $serial ) {
- @$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} );
+ 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 SELECT nextval('$serial') returned ".join(',',@$self{@identified_by}));
+ $log->error("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
} elsif ( $debug or DEBUG_ALL ) {
- $log->debug("SQL statement execution SELECT nextval('$serial') returned ".join(',',@$self{@identified_by}));
+ $log->debug("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
} # end if
} # end if
} # end if
+
my @keys = keys %sql;
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys} ) ) ) {
@@ -247,7 +256,7 @@ $log->debug("No serial") if $debug;
my $error = $local_dbh->errstr;
$log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $error);
$local_dbh->rollback();
- sql::end_transaction( $local_dbh, $ac );
+ ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
@@ -257,14 +266,16 @@ $log->debug("No serial") if $debug;
} else {
delete $sql{created_on};
my @keys = keys %sql;
- @keys = sets::exclude( [ @$fields{@identified_by} ], \@keys );
+ 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 );
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys}, @sql{@$fields{@identified_by}} ) ) ) {
my $error = $local_dbh->errstr;
$command =~ s/\?/\%s/g;
$log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}, @sql{@$fields{@identified_by}} ) ).'):' . $error) if $log;
$local_dbh->rollback();
- sql::end_transaction( $local_dbh, $ac );
+ ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
@@ -273,7 +284,7 @@ $log->debug("No serial") if $debug;
} # end if
} # end if
} # end if
- sql::end_transaction( $local_dbh, $ac );
+ ZoneMinder::Database::end_transaction( $local_dbh, $ac );
$self->load();
#if ( $$fields{id} ) {
#if ( ! $ZoneMinder::Object::cache{$type}{$$self{id}} ) {
@@ -294,7 +305,7 @@ sub set {
my $type = ref $self;
my %fields = eval ('%'.$type.'::fields');
if ( ! %fields ) {
- $log->warn('ZoneMinder::Object::set called on an object with no fields');
+ $log->warn("ZoneMinder::Object::set called on an object ($type) with no fields".$@);
} # end if
my %defaults = eval('%'.$type.'::defaults');
if ( ref $params ne 'HASH' ) {
@@ -356,7 +367,7 @@ sub transform {
if ( defined $$fields{$_[1]} ) {
my @transforms = eval('@{$'.$type.'::transforms{$_[1]}}');
- $openprint::log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug;
+ $log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug;
if ( @transforms ) {
foreach my $transform ( @transforms ) {
if ( $transform =~ /^s\// or $transform =~ /^tr\// ) {
@@ -366,15 +377,15 @@ sub transform {
$value = undef;
} # end if
} else {
- $openprint::log->debug("evalling $value ".$transform . " Now value is $value" );
+ $log->debug("evalling $value ".$transform . " Now value is $value" );
eval '$value '.$transform;
- $openprint::log->error("Eval error $@") if $@;
+ $log->error("Eval error $@") if $@;
}
- $openprint::log->debug("After $transform: $value") if $debug;
+ $log->debug("After $transform: $value") if $debug;
} # end foreach
} # end if
} else {
- $openprint::log->error("Object::transform ($_[1]) not in fields for $type");
+ $log->error("Object::transform ($_[1]) not in fields for $type");
} # end if
return $value;
diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in
index 9ccfc2a6e..cbb68faff 100644
--- a/scripts/zmaudit.pl.in
+++ b/scripts/zmaudit.pl.in
@@ -246,7 +246,7 @@ MAIN: while( $loop ) {
$$Event{Path} = join('/', $Storage->Path(), $day_dir,$event_path);
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
- $Event->DiskUsage( undef );
+ $Event->DiskSpace( undef );
} # event path exists
} # end foreach event_link
chdir( $Storage->Path() );
diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in
index fca5b3d7a..efe988882 100644
--- a/scripts/zmfilter.pl.in
+++ b/scripts/zmfilter.pl.in
@@ -251,17 +251,23 @@ sub checkFilter {
my $filter = shift;
my @Events = $filter->Execute();
- Info( join( "Checking filter '$filter->{Name}'",
- ($filter->{AutoDelete}?', delete':''),
- ($filter->{AutoArchive}?', archive':''),
- ($filter->{AutoVideo}?', video':''),
- ($filter->{AutoUpload}?', upload':''),
- ($filter->{AutoEmail}?', email':''),
- ($filter->{AutoMessage}?', message':''),
- ($filter->{AutoExecute}?', execute':''),
- ' returned ' , scalar @Events , ' events',
- "\n",
- ) );
+ Info(
+ join(' ',
+ 'Checking filter', $filter->{Name},
+ join( ', ',
+
+ ($filter->{AutoDelete}?'delete':()),
+ ($filter->{AutoArchive}?'archive':()),
+ ($filter->{AutoVideo}?'video':()),
+ ($filter->{AutoUpload}?'upload':()),
+ ($filter->{AutoEmail}?'email':()),
+ ($filter->{AutoMessage}?'message':()),
+ ($filter->{AutoExecute}?'execute':()),
+ ($filter->{UpdateDiskSpace}?'update disk space':()),
+ ),
+ 'returned' , scalar @Events , 'events',
+ "\n",
+ ) );
foreach my $event ( @Events ) {
Debug( "Checking event $event->{Id}\n" );
@@ -309,6 +315,12 @@ sub checkFilter {
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
}
} # end if AutoDelete
+ if ( $filter->{UpdateDiskSpace} ) {
+ my $Event = new ZoneMinder::Event( $$event{Id}, $event );
+ $Event->DiskSpace(undef);
+ $Event->save();
+
+ } # end if UpdateDiskSpace
} # end foreach event
}
diff --git a/src/zm_curl_camera.cpp b/src/zm_curl_camera.cpp
index 3db890bf9..dbd824dad 100644
--- a/src/zm_curl_camera.cpp
+++ b/src/zm_curl_camera.cpp
@@ -128,10 +128,10 @@ int cURLCamera::Capture( Image &image ) {
/* Grab the mutex to ensure exclusive access to the shared data */
lock();
- while (!frameComplete) {
+ while ( !frameComplete ) {
/* If the work thread did a reset, reset our local variables */
- if(bReset) {
+ if ( bReset ) {
SubHeadersParsingComplete = false;
frame_content_length = 0;
frame_content_type.clear();
@@ -139,25 +139,25 @@ int cURLCamera::Capture( Image &image ) {
bReset = false;
}
- if(mode == MODE_UNSET) {
+ if ( mode == MODE_UNSET ) {
/* Don't have a mode yet. Sleep while waiting for data */
nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
- if(nRet != 0) {
+ if ( nRet != 0 ) {
Error("Failed waiting for available data condition variable: %s",strerror(nRet));
return -20;
}
}
- if(mode == MODE_STREAM) {
+ if ( mode == MODE_STREAM ) {
/* Subheader parsing */
- while(!SubHeadersParsingComplete && !need_more_data) {
+ while( !SubHeadersParsingComplete && !need_more_data ) {
size_t crlf_start, crlf_end, crlf_size;
std::string subheader;
/* Check if the buffer contains something */
- if(databuffer.empty()) {
+ if ( databuffer.empty() ) {
/* Empty buffer, wait for data */
need_more_data = true;
break;
@@ -165,14 +165,14 @@ int cURLCamera::Capture( Image &image ) {
/* Find crlf start */
crlf_start = memcspn(databuffer,"\r\n",databuffer.size());
- if(crlf_start == databuffer.size()) {
+ if ( crlf_start == databuffer.size() ) {
/* Not found, wait for more data */
need_more_data = true;
break;
}
/* See if we have enough data for determining crlf length */
- if(databuffer.size() < crlf_start+5) {
+ if ( databuffer.size() < crlf_start+5 ) {
/* Need more data */
need_more_data = true;
break;
@@ -183,13 +183,13 @@ int cURLCamera::Capture( Image &image ) {
crlf_size = (crlf_start + crlf_end) - crlf_start;
/* Is this the end of a previous stream? (This is just before the boundary) */
- if(crlf_start == 0) {
+ if ( crlf_start == 0 ) {
databuffer.consume(crlf_size);
continue;
}
/* Check for invalid CRLF size */
- if(crlf_size > 4) {
+ if ( crlf_size > 4 ) {
Error("Invalid CRLF length");
}
@@ -209,7 +209,7 @@ int cURLCamera::Capture( Image &image ) {
/* Find where the data in this header starts */
size_t subheader_data_start = subheader.rfind(' ');
- if(subheader_data_start == std::string::npos) {
+ if ( subheader_data_start == std::string::npos ) {
subheader_data_start = subheader.find(':');
}
diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h
index 07e161214..152935d65 100644
--- a/src/zm_eventstream.h
+++ b/src/zm_eventstream.h
@@ -27,6 +27,7 @@
#include "zm_stream.h"
#include "zm_video.h"
#include "zm_ffmpeg_input.h"
+#include "zm_monitor.h"
#ifdef __cplusplus
extern "C" {
@@ -108,11 +109,17 @@ class EventStream : public StreamBase {
}
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
loadInitialEventData( init_event_id, init_frame_id );
- loadMonitor( event_data->monitor_id );
+ if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
+ Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id );
+ return;
+ }
}
void setStreamStart( int monitor_id, time_t event_time ) {
loadInitialEventData( monitor_id, event_time );
- loadMonitor( monitor_id );
+ if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
+ Fatal( "Unable to load monitor id %d for streaming", monitor_id );
+ return;
+ }
}
void setStreamMode( StreamMode p_mode ) {
mode = p_mode;
diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp
index dfcdd1b05..19707f2e5 100644
--- a/src/zm_ffmpeg_camera.cpp
+++ b/src/zm_ffmpeg_camera.cpp
@@ -317,7 +317,7 @@ int FfmpegCamera::Capture( Image &image ) {
} // end if packet.stream_index == mVideoStreamId
zm_av_packet_unref( &packet );
} // end while ! frameComplete
- return (0);
+ return 1;
} // FfmpegCamera::Capture
int FfmpegCamera::PostCapture() {
@@ -495,7 +495,16 @@ int FfmpegCamera::OpenFfmpeg() {
}
}
}
-
+ } else {
+#ifdef AV_CODEC_ID_H265
+ if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) {
+ Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." );
+ } else {
+#endif
+ Error( "Input stream is not h264. The stored event file may not be viewable in browser." );
+#ifdef AV_CODEC_ID_H265
+ }
+#endif
} // end if h264
#endif
@@ -752,6 +761,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
while ( ! frameComplete ) {
av_init_packet( &packet );
+ Debug(4,"before read frame");
ret = av_read_frame( mFormatContext, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
@@ -961,11 +971,11 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
- Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
+ Warning( "Unable to receive frame %d: %s, continuing", frameCount, errbuf );
zm_av_packet_unref( &packet );
continue;
}
-
+
#if HAVE_AVUTIL_HWCONTEXT_H
}
#endif
@@ -981,8 +991,6 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
}
#endif
- Debug( 4, "Decoded video packet at frame %d", frameCount );
-
if ( frameComplete ) {
Debug( 4, "Got frame %d", frameCount );
@@ -1013,6 +1021,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
Debug( 3, "Not framecomplete after av_read_frame" );
} // end if frameComplete
} else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams
+ frameComplete = 1;
if ( videoStore ) {
if ( record_audio ) {
if ( have_video_keyframe ) {
@@ -1034,6 +1043,8 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
} else {
Debug(4, "Have audio packet, but not recording atm" );
}
+ zm_av_packet_unref( &packet );
+ return 0;
} else {
#if LIBAVUTIL_VERSION_CHECK(56, 23, 0, 23, 0)
Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codecpar->codec_type) );
@@ -1045,7 +1056,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
// the packet contents are ref counted... when queuing, we allocate another packet and reference it with that one, so we should always need to unref here, which should not affect the queued version.
zm_av_packet_unref( &packet );
} // end while ! frameComplete
- return (frameCount);
+ return frameCount;
} // end FfmpegCamera::CaptureAndRecord
diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp
index a4135d352..70d833c31 100644
--- a/src/zm_libvlc_camera.cpp
+++ b/src/zm_libvlc_camera.cpp
@@ -23,8 +23,7 @@
#if HAVE_LIBVLC
// Do all the buffer checking work here to avoid unnecessary locking
-void* LibvlcLockBuffer(void* opaque, void** planes)
-{
+void* LibvlcLockBuffer(void* opaque, void** planes) {
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
data->mutex.lock();
@@ -36,15 +35,12 @@ void* LibvlcLockBuffer(void* opaque, void** planes)
return NULL;
}
-void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes)
-{
+void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
bool newFrame = false;
- for(uint32_t i = 0; i < data->bufferSize; i++)
- {
- if(data->buffer[i] != data->prevBuffer[i])
- {
+ for( uint32_t i = 0; i < data->bufferSize; i++ ) {
+ if ( data->buffer[i] != data->prevBuffer[i] ) {
newFrame = true;
break;
}
@@ -54,8 +50,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes)
time_t now;
time(&now);
// Return frames slightly faster than 1fps (if time() supports greater than one second resolution)
- if(newFrame || difftime(now, data->prevTime) >= 0.8)
- {
+ if ( newFrame || difftime(now, data->prevTime) >= 0.8 ) {
data->prevTime = now;
data->newImage.updateValueSignal(true);
}
@@ -90,58 +85,46 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri
Panic("Unexpected colours: %d",colours);
}
- if ( capture )
- {
+ if ( capture ) {
Initialise();
}
}
-LibvlcCamera::~LibvlcCamera()
-{
- if ( capture )
- {
+LibvlcCamera::~LibvlcCamera() {
+ if ( capture ) {
Terminate();
}
- if(mLibvlcMediaPlayer != NULL)
- {
+ if ( mLibvlcMediaPlayer != NULL ) {
libvlc_media_player_release(mLibvlcMediaPlayer);
mLibvlcMediaPlayer = NULL;
}
- if(mLibvlcMedia != NULL)
- {
+ if ( mLibvlcMedia != NULL ) {
libvlc_media_release(mLibvlcMedia);
mLibvlcMedia = NULL;
}
- if(mLibvlcInstance != NULL)
- {
+ if ( mLibvlcInstance != NULL ) {
libvlc_release(mLibvlcInstance);
mLibvlcInstance = NULL;
}
- if (mOptArgV != NULL)
- {
+ if ( mOptArgV != NULL ) {
delete[] mOptArgV;
}
}
-void LibvlcCamera::Initialise()
-{
+void LibvlcCamera::Initialise() {
}
-void LibvlcCamera::Terminate()
-{
+void LibvlcCamera::Terminate() {
libvlc_media_player_stop(mLibvlcMediaPlayer);
- if(mLibvlcData.buffer != NULL)
- {
+ if(mLibvlcData.buffer != NULL) {
zm_freealigned(mLibvlcData.buffer);
}
- if(mLibvlcData.prevBuffer != NULL)
- {
+ if(mLibvlcData.prevBuffer != NULL) {
zm_freealigned(mLibvlcData.prevBuffer);
}
}
-int LibvlcCamera::PrimeCapture()
-{
+int LibvlcCamera::PrimeCapture() {
Info("Priming capture from %s", mPath.c_str());
StringVector opVect = split(Options(), ",");
@@ -154,8 +137,7 @@ int LibvlcCamera::PrimeCapture()
else if ( Method() == "rtpRtspHttp" )
opVect.push_back("--rtsp-http");
- if (opVect.size() > 0)
- {
+ if ( opVect.size() > 0 ) {
mOptArgV = new char*[opVect.size()];
Debug(2, "Number of Options: %d",opVect.size());
for (size_t i=0; i< opVect.size(); i++) {
@@ -166,7 +148,7 @@ int LibvlcCamera::PrimeCapture()
}
mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV);
- if(mLibvlcInstance == NULL)
+ if ( mLibvlcInstance == NULL )
Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg());
mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str());
@@ -189,17 +171,15 @@ int LibvlcCamera::PrimeCapture()
libvlc_media_player_play(mLibvlcMediaPlayer);
- return(0);
+ return 0;
}
-int LibvlcCamera::PreCapture()
-{
+int LibvlcCamera::PreCapture() {
return(0);
}
// Should not return -1 as cancels capture. Always wait for image if available.
-int LibvlcCamera::Capture( Image &image )
-{
+int LibvlcCamera::Capture( Image &image ) {
while(!mLibvlcData.newImage.getValueImmediate())
mLibvlcData.newImage.getUpdatedValue(1);
@@ -208,25 +188,15 @@ int LibvlcCamera::Capture( Image &image )
mLibvlcData.newImage.setValueImmediate(false);
mLibvlcData.mutex.unlock();
- return (0);
+ return 1;
}
// Should not return -1 as cancels capture. Always wait for image if available.
-int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory)
-{
- while(!mLibvlcData.newImage.getValueImmediate())
- mLibvlcData.newImage.getUpdatedValue(1);
-
- mLibvlcData.mutex.lock();
- image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp);
- mLibvlcData.newImage.setValueImmediate(false);
- mLibvlcData.mutex.unlock();
-
+int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) {
return (0);
}
-int LibvlcCamera::PostCapture()
-{
+int LibvlcCamera::PostCapture() {
return(0);
}
diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp
index 52fb2c8f8..e6bc1a405 100644
--- a/src/zm_local_camera.cpp
+++ b/src/zm_local_camera.cpp
@@ -1995,17 +1995,14 @@ int LocalCamera::Contrast( int p_contrast )
return( -1 );
}
-int LocalCamera::PrimeCapture()
-{
+int LocalCamera::PrimeCapture() {
Initialise();
Debug( 2, "Priming capture" );
#if ZM_HAS_V4L2
- if ( v4l_version == 2 )
- {
+ if ( v4l_version == 2 ) {
Debug( 3, "Queueing buffers" );
- for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ )
- {
+ for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ ) {
struct v4l2_buffer vid_buf;
memset( &vid_buf, 0, sizeof(vid_buf) );
@@ -2028,13 +2025,10 @@ int LocalCamera::PrimeCapture()
}
#endif // ZM_HAS_V4L2
#if ZM_HAS_V4L1
- if ( v4l_version == 1 )
- {
- for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ )
- {
+ if ( v4l_version == 1 ) {
+ for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ ) {
Debug( 3, "Queueing frame %d", frame );
- if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 )
- {
+ if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 ) {
Error( "Capture failure for frame %d: %s", frame, strerror(errno) );
return( -1 );
}
@@ -2045,14 +2039,12 @@ int LocalCamera::PrimeCapture()
return( 0 );
}
-int LocalCamera::PreCapture()
-{
- Debug( 2, "Pre-capturing" );
+int LocalCamera::PreCapture() {
+ Debug( 5, "Pre-capturing" );
return( 0 );
}
-int LocalCamera::Capture( Image &image )
-{
+int LocalCamera::Capture( Image &image ) {
Debug( 3, "Capturing" );
static uint8_t* buffer = NULL;
static uint8_t* directbuffer = NULL;
@@ -2069,11 +2061,9 @@ int LocalCamera::Capture( Image &image )
// Do the capture, unless we are the second or subsequent camera on a channel, in which case just reuse the buffer
- if ( channel_prime )
- {
+ if ( channel_prime ) {
#if ZM_HAS_V4L2
- if ( v4l_version == 2 )
- {
+ if ( v4l_version == 2 ) {
static struct v4l2_buffer vid_buf;
memset( &vid_buf, 0, sizeof(vid_buf) );
@@ -2083,10 +2073,8 @@ int LocalCamera::Capture( Image &image )
vid_buf.memory = v4l2_data.reqbufs.memory;
Debug( 3, "Capturing %d frames", captures_per_frame );
- while ( captures_per_frame )
- {
- if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 )
- {
+ while ( captures_per_frame ) {
+ if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) {
if ( errno == EIO )
Warning( "Capture failure, possible signal loss?: %s", strerror(errno) )
else
@@ -2096,15 +2084,13 @@ int LocalCamera::Capture( Image &image )
v4l2_data.bufptr = &vid_buf;
capture_frame = v4l2_data.bufptr->index;
- if ( --captures_per_frame )
- {
- if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 )
- {
+ if ( --captures_per_frame ) {
+ if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) {
Error( "Unable to requeue buffer %d: %s", vid_buf.index, strerror(errno) );
return( -1 );
}
}
- }
+ } // while captures_per_frame
Debug( 3, "Captured frame %d/%d from channel %d", capture_frame, v4l2_data.bufptr->sequence, channel );
@@ -2115,23 +2101,19 @@ int LocalCamera::Capture( Image &image )
Fatal("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",v4l2_data.fmt.fmt.pix.width,v4l2_data.fmt.fmt.pix.height,width,height);
}
- }
+ } // end if v4l2
#endif // ZM_HAS_V4L2
#if ZM_HAS_V4L1
- if ( v4l_version == 1 )
- {
+ if ( v4l_version == 1 ) {
Debug( 3, "Capturing %d frames", captures_per_frame );
- while ( captures_per_frame )
- {
+ while ( captures_per_frame ) {
Debug( 3, "Syncing frame %d", v4l1_data.active_frame );
- if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 )
- {
+ if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) {
Error( "Sync failure for frame %d buffer %d: %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) );
return( -1 );
}
captures_per_frame--;
- if ( captures_per_frame )
- {
+ if ( captures_per_frame ) {
Debug( 3, "Capturing frame %d", v4l1_data.active_frame );
if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 )
{
@@ -2148,18 +2130,18 @@ int LocalCamera::Capture( Image &image )
#endif // ZM_HAS_V4L1
} /* prime capture */
- if(conversion_type != 0) {
+ if ( conversion_type != 0 ) {
Debug( 3, "Performing format conversion" );
/* Request a writeable buffer of the target image */
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
- if(directbuffer == NULL) {
+ if ( directbuffer == NULL ) {
Error("Failed requesting writeable buffer for the captured image.");
- return (-1);
+ return -1;
}
#if HAVE_LIBSWSCALE
- if(conversion_type == 1) {
+ if ( conversion_type == 1 ) {
Debug( 9, "Calling sws_scale to perform the conversion" );
/* Use swscale to convert the image directly into the shared memory */
@@ -2174,14 +2156,11 @@ int LocalCamera::Capture( Image &image )
sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize );
}
#endif
- if(conversion_type == 2) {
-
+ if ( conversion_type == 2 ) {
Debug( 9, "Calling the conversion function" );
/* Call the image conversion function and convert directly into the shared memory */
(*conversion_fptr)(buffer, directbuffer, pixels);
- }
- else if(conversion_type == 3) {
-
+ } else if ( conversion_type == 3 ) {
Debug( 9, "Decoding the JPEG image" );
/* JPEG decoding */
image.DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder);
@@ -2192,10 +2171,9 @@ int LocalCamera::Capture( Image &image )
/* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */
image.Assign( width, height, colours, subpixelorder, buffer, imagesize);
-
}
- return( 0 );
+ return 1;
}
int LocalCamera::PostCapture()
diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp
index 1b3ed85ac..83d14ef7b 100644
--- a/src/zm_monitor.cpp
+++ b/src/zm_monitor.cpp
@@ -1178,7 +1178,7 @@ bool Monitor::Analyse() {
gettimeofday( &now, NULL );
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
- fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
+ fps = double(fps_report_interval)/(now.tv_sec - last_fps_time);
Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps );
static char sql[ZM_SQL_SML_BUFSIZ];
snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", fps, id );
@@ -2889,33 +2889,27 @@ int Monitor::Capture() {
} else {
//Check if FFMPEG camera
- if ( (videowriter == H264PASSTHROUGH ) && camera->SupportsNativeVideo() ) {
+ if ( (videowriter == H264PASSTHROUGH) && camera->SupportsNativeVideo() ) {
//Warning("ZMC: Recording: %d", video_store_data->recording);
- captureResult = camera->CaptureAndRecord(*capture_image, video_store_data->recording, video_store_data->event_file);
- }else{
+ // Should return -1 on error, like loss of signal. Should return 0 if ok but no video frame. > 0 for received a frame.
+ captureResult = camera->CaptureAndRecord(
+ *capture_image,
+ video_store_data->recording,
+ video_store_data->event_file
+ );
+ } else {
/* Capture directly into image buffer, avoiding the need to memcpy() */
captureResult = camera->Capture(*capture_image);
}
}
-
- // CaptureAndRecord returns # of frames captured I think
- if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) {
- //video_store_data->frameNumber = captureResult;
- captureResult = 0;
- }
-
- if ( captureResult != 0 ) {
+Debug(4, "Return from Capture (%d)", captureResult);
+ if ( captureResult < 0 ) {
// Unable to capture image for temporary reason
// Fake a signal loss image
Rgb signalcolor;
signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */
capture_image->Fill(signalcolor);
- captureResult = 0;
- } else {
- captureResult = 1;
- }
-
- if ( captureResult == 1 ) {
+ } else if ( captureResult > 0 ) {
/* Deinterlacing */
if ( deinterlacing_value == 1 ) {
@@ -2969,49 +2963,58 @@ int Monitor::Capture() {
if ( privacy_bitmask )
capture_image->MaskPrivacy( privacy_bitmask );
+ // Might be able to remove this call, when we start passing around ZMPackets, which will already have a timestamp
gettimeofday( image_buffer[index].timestamp, NULL );
if ( config.timestamp_on_capture ) {
TimestampImage( capture_image, image_buffer[index].timestamp );
}
+ // Maybe we don't need to do this on all camera types
shared_data->signal = CheckSignal(capture_image);
shared_data->last_write_index = index;
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
image_count++;
+ } // end if captureResult
- if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
- time_t now = image_buffer[index].timestamp->tv_sec;
- fps = double(fps_report_interval)/(now-last_fps_time);
- //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time );
+ if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
+
+ struct timeval now;
+ if ( !captureResult ) {
+ gettimeofday( &now, NULL );
+ } else {
+ now.tv_sec = image_buffer[index].timestamp->tv_sec;
+ }
+ // If we are too fast, we get div by zero. This seems to happen in the case of audio packets.
+ if ( now.tv_sec != last_fps_time ) {
+ fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
+ Info( "%d -> %d -> %d", fps_report_interval, now.tv_sec, last_fps_time );
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps );
- last_fps_time = now;
+ last_fps_time = now.tv_sec;
static char sql[ZM_SQL_SML_BUFSIZ];
- snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id );
+ snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
}
}
+ }
- // Icon: I'm not sure these should be here. They have nothing to do with capturing
- if ( shared_data->action & GET_SETTINGS ) {
- shared_data->brightness = camera->Brightness();
- shared_data->hue = camera->Hue();
- shared_data->colour = camera->Colour();
- shared_data->contrast = camera->Contrast();
- shared_data->action &= ~GET_SETTINGS;
- }
- if ( shared_data->action & SET_SETTINGS ) {
- camera->Brightness( shared_data->brightness );
- camera->Hue( shared_data->hue );
- camera->Colour( shared_data->colour );
- camera->Contrast( shared_data->contrast );
- shared_data->action &= ~SET_SETTINGS;
- }
- return( 0 );
- } // end if captureResults == 1 which is success I think
- shared_data->signal = false;
- return( -1 );
+ // Icon: I'm not sure these should be here. They have nothing to do with capturing
+ if ( shared_data->action & GET_SETTINGS ) {
+ shared_data->brightness = camera->Brightness();
+ shared_data->hue = camera->Hue();
+ shared_data->colour = camera->Colour();
+ shared_data->contrast = camera->Contrast();
+ shared_data->action &= ~GET_SETTINGS;
+ }
+ if ( shared_data->action & SET_SETTINGS ) {
+ camera->Brightness( shared_data->brightness );
+ camera->Hue( shared_data->hue );
+ camera->Colour( shared_data->colour );
+ camera->Contrast( shared_data->contrast );
+ shared_data->action &= ~SET_SETTINGS;
+ }
+ return captureResult;
}
void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const {
diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp
index f904f23cf..010877b90 100644
--- a/src/zm_monitorstream.cpp
+++ b/src/zm_monitorstream.cpp
@@ -270,7 +270,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
Debug( 1, "Got SCALE command, to %d", scale );
break;
}
- case CMD_QUIT :
+ case CMD_QUIT :
{
Info ("User initiated exit - CMD_QUIT");
break;
@@ -316,7 +316,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
//status_data.enabled = monitor->shared_data->active;
status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF;
status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON;
- Debug( 2, "L:%d, D:%d, P:%d, R:%d, d:%.3f, Z:%d, E:%d F:%d",
+ Debug( 2, "Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d",
status_data.buffer_level,
status_data.delayed,
status_data.paused,
@@ -338,11 +338,15 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
//exit( -1 );
}
}
+Debug(2, "NUmber of bytes sent: (%d)", nbytes );
// quit after sending a status, if this was a quit request
- if ((MsgCommand)msg->msg_data[0]==CMD_QUIT)
- exit(0);
+ if ( (MsgCommand)msg->msg_data[0]==CMD_QUIT ) {
+ Debug(2,"Quitting");
+ exit(0);
+ }
+ Debug(2,"Updating framrate");
updateFrameRate( monitor->GetFPS() );
} // end void MonitorStream::processCommand( const CmdMsg *msg )
@@ -553,20 +557,28 @@ void MonitorStream::runStream() {
Debug( 2, "Assigned temporary buffer" );
}
}
- }
+ } // end if connkey & playback_buffer
float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs)
while ( !zm_terminate ) {
bool got_command = false;
if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) {
+ if ( feof( stdout ) ) {
+ Debug(2,"feof stdout");
+ } else if ( ferror( stdout ) ) {
+ Debug(2,"ferror stdout");
+ } else if ( !monitor->ShmValid() ) {
+ Debug(2,"monitor not valid.... maybe we should wait until it comes back.");
+ }
break;
}
gettimeofday( &now, NULL );
if ( connkey ) {
-Debug(2, "checking command Queue");
+//Debug(2, "checking command Queue for connkey: %d", connkey );
while(checkCommandQueue()) {
+Debug(2, "Have checking command Queue for connkey: %d", connkey );
got_command = true;
}
}
@@ -655,8 +667,10 @@ Debug(2, "checking command Queue");
// Send the next frame
Monitor::Snapshot *snap = &monitor->image_buffer[index];
- if ( !sendFrame( snap->image, snap->timestamp ) )
+ if ( !sendFrame( snap->image, snap->timestamp ) ) {
+ Debug(2, "sendFrame failed, quiting.");
zm_terminate = true;
+ }
memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) );
//frame_sent = true;
@@ -693,9 +707,12 @@ Debug(2, "checking command Queue");
} // end if buffered playback
frame_count++;
}
+ unsigned long sleep_time = (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2)));
+ Debug(2, "Sleeping for (%d)", sleep_time);
usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) );
if ( ttl ) {
if ( (now.tv_sec - stream_start_time) > ttl ) {
+ Debug(2, "now(%d) - start(%d) > ttl(%d) break", now.tv_sec, stream_start_time, ttl);
break;
}
}
diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp
index 95c8ae507..2907e90a3 100644
--- a/src/zm_remote_camera_http.cpp
+++ b/src/zm_remote_camera_http.cpp
@@ -1063,23 +1063,18 @@ int RemoteCameraHttp::GetResponse()
return( 0 );
}
-int RemoteCameraHttp::PreCapture()
-{
- if ( sd < 0 )
- {
+int RemoteCameraHttp::PreCapture() {
+ if ( sd < 0 ) {
Connect();
- if ( sd < 0 )
- {
+ if ( sd < 0 ) {
Error( "Unable to connect to camera" );
return( -1 );
}
mode = SINGLE_IMAGE;
buffer.clear();
}
- if ( mode == SINGLE_IMAGE )
- {
- if ( SendRequest() < 0 )
- {
+ if ( mode == SINGLE_IMAGE ) {
+ if ( SendRequest() < 0 ) {
Error( "Unable to send request" );
Disconnect();
return( -1 );
@@ -1088,50 +1083,43 @@ int RemoteCameraHttp::PreCapture()
return( 0 );
}
-int RemoteCameraHttp::Capture( Image &image )
-{
+int RemoteCameraHttp::Capture( Image &image ) {
int content_length = GetResponse();
- if ( content_length == 0 )
- {
+ if ( content_length == 0 ) {
Warning( "Unable to capture image, retrying" );
- return( 1 );
+ return 0;
}
- if ( content_length < 0 )
- {
+ if ( content_length < 0 ) {
Error( "Unable to get response, disconnecting" );
Disconnect();
- return( -1 );
+ return -1;
}
- switch( format )
- {
+ switch( format ) {
case JPEG :
{
- if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) )
- {
+ if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) {
Error( "Unable to decode jpeg" );
Disconnect();
- return( -1 );
+ return -1;
}
break;
}
case X_RGB :
{
- if ( content_length != (long)image.Size() )
- {
+ if ( content_length != (long)image.Size() ) {
Error( "Image length mismatch, expected %d bytes, content length was %d", image.Size(), content_length );
Disconnect();
- return( -1 );
+ return -1;
}
image.Assign( width, height, colours, subpixelorder, buffer, imagesize );
break;
}
case X_RGBZ :
{
- if ( !image.Unzip( buffer.extract( content_length ), content_length ) )
- {
+ if ( !image.Unzip( buffer.extract( content_length ), content_length ) ) {
Error( "Unable to unzip RGB image" );
Disconnect();
- return( -1 );
+ return -1;
}
image.Assign( width, height, colours, subpixelorder, buffer, imagesize );
break;
@@ -1140,13 +1128,12 @@ int RemoteCameraHttp::Capture( Image &image )
{
Error( "Unexpected image format encountered" );
Disconnect();
- return( -1 );
+ return -1;
}
}
- return( 0 );
+ return 1;
}
-int RemoteCameraHttp::PostCapture()
-{
- return( 0 );
+int RemoteCameraHttp::PostCapture() {
+ return 0;
}
diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp
index 9b0b6b41d..b8e5dc573 100644
--- a/src/zm_remote_camera_rtsp.cpp
+++ b/src/zm_remote_camera_rtsp.cpp
@@ -266,15 +266,15 @@ int RemoteCameraRtsp::Capture( Image &image ) {
/* Request a writeable buffer of the target image */
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
- if(directbuffer == NULL) {
+ if ( directbuffer == NULL ) {
Error("Failed requesting writeable buffer for the captured image.");
- return (-1);
+ return -1;
}
while ( true ) {
buffer.clear();
if ( !rtspThread->isRunning() )
- return (-1);
+ return -1;
if ( rtspThread->getFrame( buffer ) ) {
Debug( 3, "Read frame %d bytes", buffer.size() );
@@ -282,21 +282,21 @@ int RemoteCameraRtsp::Capture( Image &image ) {
Hexdump( 4, buffer.head(), 16 );
if ( !buffer.size() )
- return( -1 );
+ return -1;
- if(mCodecContext->codec_id == AV_CODEC_ID_H264) {
+ if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) {
// SPS and PPS frames should be saved and appended to IDR frames
int nalType = (buffer.head()[3] & 0x1f);
// SPS The SPS NAL unit contains parameters that apply to a series of consecutive coded video pictures
- if(nalType == 7) {
+ if ( nalType == 7 ) {
lastSps = buffer;
continue;
- } else if(nalType == 8) {
+ } else if ( nalType == 8 ) {
// PPS The PPS NAL unit contains parameters that apply to the decoding of one or more individual pictures inside a coded video sequence
lastPps = buffer;
continue;
- } else if(nalType == 5) {
+ } else if ( nalType == 5 ) {
// IDR
buffer += lastSps;
buffer += lastPps;
@@ -357,13 +357,13 @@ int RemoteCameraRtsp::Capture( Image &image ) {
zm_av_packet_unref( &packet );
} /* getFrame() */
- if(frameComplete)
- return (0);
+ if ( frameComplete )
+ return 1;
} // end while true
// can never get here.
- return (0);
+ return 0;
}
//Function to handle capture and store
diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp
index 8002c4f18..282db0f40 100644
--- a/src/zm_stream.cpp
+++ b/src/zm_stream.cpp
@@ -311,7 +311,7 @@ void StreamBase::openComms() {
strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) );
rem_addr.sun_family = AF_UNIX;
} // end if connKey > 0
- Debug(3, "comms open" );
+ Debug(2, "comms open" );
}
void StreamBase::closeComms() {
diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp
index bc6c49e6f..e9e3f2377 100644
--- a/src/zm_videostore.cpp
+++ b/src/zm_videostore.cpp
@@ -960,19 +960,19 @@ void VideoStore::write_video_packet( AVPacket &opkt ) {
int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
Debug(4, "writeAudioFrame");
- if (!audio_out_stream) {
+ if ( !audio_out_stream ) {
Debug(1, "Called writeAudioFramePacket when no audio_out_stream");
return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at
// the moment
}
- if (audio_out_codec) {
+ if ( audio_out_codec ) {
Debug(3, "Have audio codec");
#ifdef HAVE_LIBAVRESAMPLE
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_send_packet(audio_in_ctx, ipkt);
- if (ret < 0) {
+ if ( ret < 0 ) {
Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str());
return 0;
}
diff --git a/version b/version
index b051fa802..623203d2d 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.31.10
+1.31.12
diff --git a/web/ajax/add_monitors.php b/web/ajax/add_monitors.php
new file mode 100644
index 000000000..b95f0e8f4
--- /dev/null
+++ b/web/ajax/add_monitors.php
@@ -0,0 +1,209 @@
+set(array(
+ 'StorageId' => 1,
+ 'ServerId' => 'auto',
+ 'Function' => 'Record',
+ 'Type' => 'Ffmpeg',
+ 'Enabled' => '1',
+ 'Colour' => '4', // 32bit
+ 'PreEventCount' => 0,
+) );
+
+function probe( &$url_bits ) {
+ global $defaultMonitor;
+ $available_streams = array();
+ if ( ! isset($url_bits['port']) ) {
+ // No port given, do a port scan
+ foreach ( range( 2000, 2007 ) as $port ) {
+ $socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
+ socket_set_option( $socket,
+ SOL_SOCKET, // socket level
+ SO_SNDTIMEO, // timeout option
+ array(
+ "sec"=>0, // Timeout in seconds
+ "usec"=>500 // I assume timeout in microseconds
+ )
+ );
+ $new_stream = null;
+Info("Testing connection to " . $url_bits['host'].':'.$port);
+ if ( socket_connect( $socket, $url_bits['host'], $port ) ) {
+ $new_stream = $url_bits; // make a copy
+ $new_stream['port'] = $port;
+ } else {
+ socket_close($socket);
+ Info("No connection to ".$url_bits['host'] . " on port $port");
+ continue;
+ }
+ if ( $new_stream ) {
+ if ( ! isset($new_stream['scheme'] ) )
+ $new_stream['scheme'] = 'http';
+ $url = unparse_url($new_stream, array('path'=>'/', 'query'=>'action=snapshot'));
+ list($width, $height, $type, $attr) = getimagesize( $url );
+ Info("Got $width x $height from $url");
+ $new_stream['Width'] = $width;
+ $new_stream['Height'] = $height;
+
+ //try {
+ //if ( $response = do_request( 'GET', $url ) ) {
+ //$new_stream['path'] = '/';
+ //$new_stream['query'] = '?action=stream';
+//$image = imagecreatefromstring($response);
+ ////$size = getimagesize( $image );
+ //
+ //} else {
+ //Info("No response from $url");
+ //}
+ //} catch ( EXception $e ) {
+ //Info("No response from $url");
+ //}
+ $available_streams[] = $new_stream;
+ } // end if new_Stream
+ } // end foreach port to scan
+ } else {
+ // A port was specified, so don't need to port scan.
+ $available_streams[] = $url_bits;
+ }
+ foreach ( $available_streams as &$stream ) {
+ # check for existence in db.
+ $stream['url'] = unparse_url( $stream, array( 'path'=>'/','query'=>'action=stream' ) );
+ $monitors = Monitor::find_all( array( 'Path'=>$stream['url'] ) );
+ if ( count($monitors ) ) {
+ $stream['Monitor'] = $monitors[0];
+ if ( isset( $stream['Width'] ) and ( $stream['Monitor']->Width() != $stream['Width'] ) ) {
+ $stream['Warning'] .= 'Monitor width ('.$stream['Monitor']->Width().') and stream width ('.$stream['Width'].") do not match!\n";
+ }
+ if ( isset( $stream['Height'] ) and ( $stream['Monitor']->Height() != $stream['Height'] ) ) {
+ $stream['Warning'] .= 'Monitor height ('.$stream['Monitor']->Height().') and stream width ('.$stream['Height'].") do not match!\n";
+ }
+ } else {
+ $stream['Monitor'] = $defaultMonitor;
+ if ( isset($stream['Width']) ) {
+ $stream['Monitor']->Width( $stream['Width'] );
+ $stream['Monitor']->Height( $stream['Height'] );
+ }
+ } // Monitor found or not
+ } // end foreach Stream
+
+ #$macCommandString = 'arp ' . $url_bits['host'] . " | awk 'BEGIN{ i=1; } { i++; if(i==3) print $3 }'";
+ #$mac = exec($macCommandString);
+ #Info("Mac $mac");
+ return $available_streams;
+} // end function probe
+
+if ( canEdit( 'Monitors' ) ) {
+ switch ( $_REQUEST['action'] ) {
+ case 'probe' :
+ {
+ $available_streams = array();
+ $url_bits = null;
+ if ( preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $_REQUEST['url'] ) ) {
+ $url_bits = array( 'host'=>$_REQUEST['url'] );
+ } else {
+ $url_bits = parse_url( $_REQUEST['url'] );
+ }
+
+if ( 0 ) {
+ // Shortcut test
+ $monitors = Monitor::find_all( array( 'Path'=>$_REQUEST['url'] ) );
+ if ( count( $monitors ) ) {
+ Info("Monitor found for " . $_REQUEST['url']);
+ $url_bits['url'] = $_REQUEST['url'];
+ $url_bits['Monitor'] = $monitors[0];
+ $available_stream[] = $url_bits;
+ ajaxResponse( array ( 'Streams'=>$available_streams) );
+ return;
+ } # end url already has a monitor
+}
+
+ if ( ! $url_bits ) {
+ ajaxError("The given URL was too malformed to parse.");
+ return;
+ }
+
+ $available_streams = probe( $url_bits );
+
+ ajaxResponse( array('Streams'=>$available_streams) );
+ return;
+ } // end case url_probe
+ case 'import':
+ {
+
+ $file = $_FILES['import_file'];
+
+ if ($file["error"] > 0) {
+ ajaxError($file["error"]);
+ return;
+ } else {
+ $filename = $file["name"];
+
+ $available_streams = array();
+ $row = 1;
+ if (($handle = fopen($file['tmp_name'], 'r')) !== FALSE) {
+ while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
+ $name = $data[0];
+ $url = $data[1];
+ $group = $data[2];
+ Info("Have the following line data $name $url $group");
+
+ $url_bits = null;
+ if ( preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $url) ) {
+ $url_bits = array( 'host'=>$url, 'scheme'=>'http' );
+ } else {
+ $url_bits = parse_url( $url );
+ }
+ if ( ! $url_bits ) {
+ Info("Bad url, skipping line $name $url $group");
+ continue;
+ }
+
+ $available_streams += probe( $url_bits );
+
+ //$url_bits['url'] = unparse_url( $url_bits );
+ //$url_bits['Monitor'] = $defaultMonitor;
+ //$url_bits['Monitor']->Name( $name );
+ //$url_bits['Monitor']->merge( $_POST['newMonitor'] );
+ //$available_streams[] = $url_bits;
+
+ } // end while rows
+ fclose($handle);
+ ajaxResponse( array('Streams'=>$available_streams) );
+ } else {
+ ajaxError("Uploaded file does not exist");
+ return;
+ }
+
+ }
+ } // end case import
+ default:
+ {
+ Warning("unknown action " . $_REQUEST['action'] );
+ } // end ddcase default
+ }
+} else {
+ Warning("Cannot edit monitors" );
+}
+
+ajaxError( 'Unrecognised action or insufficient permissions' );
+
+?>
diff --git a/web/ajax/status.php b/web/ajax/status.php
index 82929c20b..6827b7e79 100644
--- a/web/ajax/status.php
+++ b/web/ajax/status.php
@@ -1,170 +1,170 @@
array(
- "permission" => "System",
- "table" => "Monitors",
- "limit" => 1,
- "elements" => array(
- "MonitorCount" => array( "sql" => "count(*)" ),
- "ActiveMonitorCount" => array( "sql" => "count(if(Function != 'None',1,NULL))" ),
- "State" => array( "func" => "daemonCheck()?".translate('Running').":".translate('Stopped') ),
- "Load" => array( "func" => "getLoad()" ),
- "Disk" => array( "func" => "getDiskPercent()" ),
+ 'system' => array(
+ 'permission' => 'System',
+ 'table' => 'Monitors',
+ 'limit' => 1,
+ 'elements' => array(
+ 'MonitorCount' => array( 'sql' => "count(*)" ),
+ 'ActiveMonitorCount' => array( 'sql' => "count(if(Function != 'None',1,NULL))" ),
+ 'State' => array( 'func' => "daemonCheck()?".translate('Running').":".translate('Stopped') ),
+ 'Load' => array( 'func' => "getLoad()" ),
+ 'Disk' => array( 'func' => "getDiskPercent()" ),
),
),
- "monitor" => array(
- "permission" => "Monitors",
- "table" => "Monitors",
- "limit" => 1,
- "selector" => "Monitors.Id",
- "elements" => array(
- "Id" => array( "sql" => "Monitors.Id" ),
- "Name" => array( "sql" => "Monitors.Name" ),
- "Type" => true,
- "Function" => true,
- "Enabled" => true,
- "LinkedMonitors" => true,
- "Triggers" => true,
- "Device" => true,
- "Channel" => true,
- "Format" => true,
- "Host" => true,
- "Port" => true,
- "Path" => true,
- "Width" => array( "sql" => "Monitors.Width" ),
- "Height" => array( "sql" => "Monitors.Height" ),
- "Palette" => true,
- "Orientation" => true,
- "Brightness" => true,
- "Contrast" => true,
- "Hue" => true,
- "Colour" => true,
- "EventPrefix" => true,
- "LabelFormat" => true,
- "LabelX" => true,
- "LabelY" => true,
- "LabelSize" => true,
- "ImageBufferCount" => true,
- "WarmupCount" => true,
- "PreEventCount" => true,
- "PostEventCount" => true,
- "AlarmFrameCount" => true,
- "SectionLength" => true,
- "FrameSkip" => true,
- "MotionFrameSkip" => true,
- "MaxFPS" => true,
- "AlarmMaxFPS" => true,
- "FPSReportInterval" => true,
- "RefBlendPerc" => true,
- "Controllable" => true,
- "ControlId" => true,
- "ControlDevice" => true,
- "ControlAddress" => true,
- "AutoStopTimeout" => true,
- "TrackMotion" => true,
- "TrackDelay" => true,
- "ReturnLocation" => true,
- "ReturnDelay" => true,
- "DefaultView" => true,
- "DefaultRate" => true,
- "DefaultScale" => true,
- "WebColour" => true,
- "Sequence" => true,
- "MinEventId" => array( "sql" => "(SELECT min(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
- "MaxEventId" => array( "sql" => "(SELECT max(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
- "TotalEvents" => array( "sql" => "(SELECT count(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
- "Status" => array( "zmu" => "-m ".escapeshellarg($_REQUEST['id'][0])." -s" ),
- "FrameRate" => array( "zmu" => "-m ".escapeshellarg($_REQUEST['id'][0])." -f" ),
+ 'monitor' => array(
+ 'permission' => 'Monitors',
+ 'table' => 'Monitors',
+ 'limit' => 1,
+ 'selector' => "Monitors.Id",
+ 'elements' => array(
+ 'Id' => array( 'sql' => "Monitors.Id" ),
+ 'Name' => array( 'sql' => "Monitors.Name" ),
+ 'Type' => true,
+ 'Function' => true,
+ 'Enabled' => true,
+ 'LinkedMonitors' => true,
+ 'Triggers' => true,
+ 'Device' => true,
+ 'Channel' => true,
+ 'Format' => true,
+ 'Host' => true,
+ 'Port' => true,
+ 'Path' => true,
+ 'Width' => array( 'sql' => "Monitors.Width" ),
+ 'Height' => array( 'sql' => "Monitors.Height" ),
+ 'Palette' => true,
+ 'Orientation' => true,
+ 'Brightness' => true,
+ 'Contrast' => true,
+ 'Hue' => true,
+ 'Colour' => true,
+ 'EventPrefix' => true,
+ 'LabelFormat' => true,
+ 'LabelX' => true,
+ 'LabelY' => true,
+ 'LabelSize' => true,
+ 'ImageBufferCount' => true,
+ 'WarmupCount' => true,
+ 'PreEventCount' => true,
+ 'PostEventCount' => true,
+ 'AlarmFrameCount' => true,
+ 'SectionLength' => true,
+ 'FrameSkip' => true,
+ 'MotionFrameSkip' => true,
+ 'MaxFPS' => true,
+ 'AlarmMaxFPS' => true,
+ 'FPSReportInterval' => true,
+ 'RefBlendPerc' => true,
+ 'Controllable' => true,
+ 'ControlId' => true,
+ 'ControlDevice' => true,
+ 'ControlAddress' => true,
+ 'AutoStopTimeout' => true,
+ 'TrackMotion' => true,
+ 'TrackDelay' => true,
+ 'ReturnLocation' => true,
+ 'ReturnDelay' => true,
+ 'DefaultView' => true,
+ 'DefaultRate' => true,
+ 'DefaultScale' => true,
+ 'WebColour' => true,
+ 'Sequence' => true,
+ 'MinEventId' => array( 'sql' => "(SELECT min(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
+ 'MaxEventId' => array( 'sql' => "(SELECT max(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
+ 'TotalEvents' => array( 'sql' => "(SELECT count(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
+ 'Status' => array( 'zmu' => "-m ".escapeshellarg($_REQUEST['id'][0])." -s" ),
+ 'FrameRate' => array( 'zmu' => "-m ".escapeshellarg($_REQUEST['id'][0])." -f" ),
),
),
- "events" => array(
- "permission" => "Events",
- "table" => "Events",
- "selector" => "Events.MonitorId",
- "elements" => array(
- "Id" => true,
- "Name" => true,
- "Cause" => true,
- "Notes" => true,
- "StartTime" => true,
- "StartTimeShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
- "EndTime" => true,
- "Width" => true,
- "Height" => true,
- "Length" => true,
- "Frames" => true,
- "AlarmFrames" => true,
- "TotScore" => true,
- "AvgScore" => true,
- "MaxScore" => true,
+ 'events' => array(
+ 'permission' => 'Events',
+ 'table' => 'Events',
+ 'selector' => "Events.MonitorId",
+ 'elements' => array(
+ 'Id' => true,
+ 'Name' => true,
+ 'Cause' => true,
+ 'Notes' => true,
+ 'StartTime' => true,
+ 'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
+ 'EndTime' => true,
+ 'Width' => true,
+ 'Height' => true,
+ 'Length' => true,
+ 'Frames' => true,
+ 'AlarmFrames' => true,
+ 'TotScore' => true,
+ 'AvgScore' => true,
+ 'MaxScore' => true,
),
),
- "event" => array(
- "permission" => "Events",
- "table" => "Events",
- "limit" => 1,
- "selector" => "Events.Id",
- "elements" => array(
- "Id" => array( "sql" => "Events.Id" ),
- "MonitorId" => true,
- "MonitorName" => array("sql" => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"),
- "Name" => true,
- "Cause" => true,
- "StartTime" => true,
- "StartTimeShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
- "EndTime" => true,
- "Width" => true,
- "Height" => true,
- "Length" => true,
- "Frames" => true,
- "DefaultVideo" => true,
- "AlarmFrames" => true,
- "TotScore" => true,
- "AvgScore" => true,
- "MaxScore" => true,
- "Archived" => true,
- "Videoed" => true,
- "Uploaded" => true,
- "Emailed" => true,
- "Messaged" => true,
- "Executed" => true,
- "Notes" => true,
- "MinFrameId" => array( "sql" => "(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)" ),
- "MaxFrameId" => array( "sql" => "(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)" ),
- "MinFrameDelta" => array( "sql" => "(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
- "MaxFrameDelta" => array( "sql" => "(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
- //"Path" => array( "postFunc" => "getEventPath" ),
+ 'event' => array(
+ 'permission' => 'Events',
+ 'table' => 'Events',
+ 'limit' => 1,
+ 'selector' => "Events.Id",
+ 'elements' => array(
+ 'Id' => array( 'sql' => "Events.Id" ),
+ 'MonitorId' => true,
+ 'MonitorName' => array('sql' => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"),
+ 'Name' => true,
+ 'Cause' => true,
+ 'StartTime' => true,
+ 'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
+ 'EndTime' => true,
+ 'Width' => true,
+ 'Height' => true,
+ 'Length' => true,
+ 'Frames' => true,
+ 'DefaultVideo' => true,
+ 'AlarmFrames' => true,
+ 'TotScore' => true,
+ 'AvgScore' => true,
+ 'MaxScore' => true,
+ 'Archived' => true,
+ 'Videoed' => true,
+ 'Uploaded' => true,
+ 'Emailed' => true,
+ 'Messaged' => true,
+ 'Executed' => true,
+ 'Notes' => true,
+ 'MinFrameId' => array( 'sql' => "(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)" ),
+ 'MaxFrameId' => array( 'sql' => "(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)" ),
+ 'MinFrameDelta' => array( 'sql' => "(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
+ 'MaxFrameDelta' => array( 'sql' => "(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
+ //'Path' => array( 'postFunc' => 'getEventPath' ),
),
),
- "frame" => array(
- "permission" => "Events",
- "table" => "Frames",
- "limit" => 1,
- "selector" => array( array( "table" => "Events", "join" => "Events.Id = Frames.EventId", "selector"=>"Events.Id" ), "Frames.FrameId" ),
- "elements" => array(
- //"Id" => array( "sql" => "Frames.FrameId" ),
- "FrameId" => true,
- "EventId" => true,
- "Type" => true,
- "TimeStamp" => true,
- "TimeStampShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
- "Delta" => true,
- "Score" => true,
- //"Image" => array( "postFunc" => "getFrameImage" ),
+ 'frame' => array(
+ 'permission' => 'Events',
+ 'table' => 'Frames',
+ 'limit' => 1,
+ 'selector' => array( array( 'table' => 'Events', 'join' => "Events.Id = Frames.EventId", 'selector'=>"Events.Id" ), "Frames.FrameId" ),
+ 'elements' => array(
+ //'Id' => array( 'sql' => "Frames.FrameId" ),
+ 'FrameId' => true,
+ 'EventId' => true,
+ 'Type' => true,
+ 'TimeStamp' => true,
+ 'TimeStampShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
+ 'Delta' => true,
+ 'Score' => true,
+ //'Image' => array( 'postFunc' => 'getFrameImage' ),
),
),
- "frameimage" => array(
- "permission" => "Events",
- "func" => "getFrameImage()"
+ 'frameimage' => array(
+ 'permission' => 'Events',
+ 'func' => "getFrameImage()"
),
- "nearframe" => array(
- "permission" => "Events",
- "func" => "getNearFrame()"
+ 'nearframe' => array(
+ 'permission' => 'Events',
+ 'func' => "getNearFrame()"
),
- "nearevents" => array(
- "permission" => "Events",
- "func" => "getNearEvents()"
+ 'nearevents' => array(
+ 'permission' => 'Events',
+ 'func' => "getNearEvents()"
)
);
@@ -290,7 +290,7 @@ function collectData() {
$data = collectData();
if ( !isset($_REQUEST['layout']) ) {
- $_REQUEST['layout'] = "json";
+ $_REQUEST['layout'] = 'json';
}
switch( $_REQUEST['layout'] ) {
@@ -331,7 +331,7 @@ function getFrameImage() {
$frame = array();
$frame['EventId'] = $eventId;
$frame['FrameId'] = $frameId;
- $frame['Type'] = "Virtual";
+ $frame['Type'] = 'Virtual';
}
$event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $frame['EventId'] ) );
$frame['Image'] = getImageSrc( $event, $frame, SCALE_BASE );
@@ -349,7 +349,7 @@ function getNearFrame() {
return( array() );
}
}
- $_REQUEST['entity'] = "frame";
+ $_REQUEST['entity'] = 'frame';
$_REQUEST['id'][1] = $nearFrameId;
return( collectData() );
}
@@ -358,7 +358,7 @@ function getNearEvents() {
global $user, $sortColumn, $sortOrder;
$eventId = $_REQUEST['id'];
- $event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $eventId ) );
+ $event = dbFetchOne( 'SELECT * FROM Events WHERE Id=?', NULL, array( $eventId ) );
parseFilter( $_REQUEST['filter'] );
parseSort();
@@ -368,7 +368,7 @@ function getNearEvents() {
else
$midSql = '';
- $sql = "select E.Id as Id, E.StartTime as StartTime from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn ".($sortOrder=='asc'?'desc':'asc');
+ $sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn ".($sortOrder=='asc'?'desc':'asc') . ' LIMIT 2';
$result = dbQuery( $sql );
while ( $id = dbFetchNext( $result, 'Id' ) ) {
if ( $id == $eventId ) {
@@ -377,7 +377,7 @@ function getNearEvents() {
}
}
- $sql = "select E.Id as Id, E.StartTime as StartTime from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn $sortOrder";
+ $sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn $sortOrder LIMIT 2";
$result = dbQuery( $sql );
while ( $id = dbFetchNext( $result, 'Id' ) ) {
if ( $id == $eventId ) {
diff --git a/web/ajax/stream.php b/web/ajax/stream.php
index 7f050bda8..03e63407d 100644
--- a/web/ajax/stream.php
+++ b/web/ajax/stream.php
@@ -1,5 +1,7 @@
0 ) {
- if ( count($rSockets) != 1 )
- ajaxError( "Bogus return from select, ".count($rSockets)." sockets available" );
+ if ( count($rSockets) != 1 ) {
+ Error( "Bogus return from select, ".count($rSockets).' sockets available' );
+ ajaxError( "Bogus return from select, ".count($rSockets).' sockets available' );
+ }
}
switch( $nbytes = @socket_recvfrom( $socket, $msg, MSG_DATA_SIZE, 0, $remSockFile ) ) {
@@ -79,7 +99,7 @@ switch( $nbytes = @socket_recvfrom( $socket, $msg, MSG_DATA_SIZE, 0, $remSockFil
}
case 0 :
{
- ajaxError( "No data to read from socket" );
+ ajaxError( 'No data to read from socket' );
break;
}
default :
@@ -90,7 +110,7 @@ switch( $nbytes = @socket_recvfrom( $socket, $msg, MSG_DATA_SIZE, 0, $remSockFil
}
}
-$data = unpack( "ltype", $msg );
+$data = unpack( 'ltype', $msg );
switch ( $data['type'] ) {
case MSG_DATA_WATCH :
{
@@ -99,7 +119,7 @@ switch ( $data['type'] ) {
$data['rate'] /= RATE_BASE;
$data['delay'] = round( $data['delay'], 2 );
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
- if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == "hashed" ) {
+ if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' ) {
session_start();
$time = time();
// Regenerate auth hash after half the lifetime of the hash
@@ -117,7 +137,7 @@ switch ( $data['type'] ) {
//$data['progress'] = sprintf( "%.2f", $data['progress'] );
$data['rate'] /= RATE_BASE;
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
- if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == "hashed" ) {
+ if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' ) {
session_start();
$time = time();
// Regenerate auth hash after half the lifetime of the hash
diff --git a/web/api/app/Console/cake.bat b/web/api/app/Console/cake.bat
index 919ecac49..c33bf22f8 100644
--- a/web/api/app/Console/cake.bat
+++ b/web/api/app/Console/cake.bat
@@ -1,31 +1,31 @@
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-::
-:: Bake is a shell script for running CakePHP bake script
-::
-:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
-:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
-::
-:: Licensed under The MIT License
-:: Redistributions of files must retain the above copyright notice.
-::
-:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
-:: @link http://cakephp.org CakePHP(tm) Project
-:: @package app.Console
-:: @since CakePHP(tm) v 2.0
-:: @license http://www.opensource.org/licenses/mit-license.php MIT License
-::
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
-
-@echo.
-@echo off
-
-SET app=%0
-SET lib=%~dp0
-
-php -q "%lib%cake.php" -working "%CD% " %*
-
-echo.
-
-exit /B %ERRORLEVEL%
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Bake is a shell script for running CakePHP bake script
+::
+:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+::
+:: Licensed under The MIT License
+:: Redistributions of files must retain the above copyright notice.
+::
+:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+:: @link http://cakephp.org CakePHP(tm) Project
+:: @package app.Console
+:: @since CakePHP(tm) v 2.0
+:: @license http://www.opensource.org/licenses/mit-license.php MIT License
+::
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
+
+@echo.
+@echo off
+
+SET app=%0
+SET lib=%~dp0
+
+php -q "%lib%cake.php" -working "%CD% " %*
+
+echo.
+
+exit /B %ERRORLEVEL%
diff --git a/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat b/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat
index 0aa43c024..e37d4a524 100644
--- a/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat
+++ b/web/api/lib/Cake/Console/Templates/skel/Console/cake.bat
@@ -1,30 +1,30 @@
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-::
-:: Bake is a shell script for running CakePHP bake script
-::
-:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
-:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
-::
-:: Licensed under The MIT License
-:: Redistributions of files must retain the above copyright notice.
-::
-:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
-:: @link http://cakephp.org CakePHP(tm) Project
-:: @package app.Console
-:: @since CakePHP(tm) v 2.0
-::
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
-
-@echo.
-@echo off
-
-SET app=%0
-SET lib=%~dp0
-
-php -q "%lib%cake.php" -working "%CD% " %*
-
-echo.
-
-exit /B %ERRORLEVEL%
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Bake is a shell script for running CakePHP bake script
+::
+:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+::
+:: Licensed under The MIT License
+:: Redistributions of files must retain the above copyright notice.
+::
+:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+:: @link http://cakephp.org CakePHP(tm) Project
+:: @package app.Console
+:: @since CakePHP(tm) v 2.0
+::
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
+
+@echo.
+@echo off
+
+SET app=%0
+SET lib=%~dp0
+
+php -q "%lib%cake.php" -working "%CD% " %*
+
+echo.
+
+exit /B %ERRORLEVEL%
diff --git a/web/api/lib/Cake/Console/cake.bat b/web/api/lib/Cake/Console/cake.bat
index 905cc39fb..34429cb24 100644
--- a/web/api/lib/Cake/Console/cake.bat
+++ b/web/api/lib/Cake/Console/cake.bat
@@ -1,28 +1,28 @@
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-::
-:: Bake is a shell script for running CakePHP bake script
-::
-:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
-:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
-::
-:: Licensed under The MIT License
-:: Redistributions of files must retain the above copyright notice.
-::
-:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
-:: @link http://cakephp.org CakePHP(tm) Project
-:: @package Cake.Console
-:: @since CakePHP(tm) v 1.2.0.5012
-:: @license http://www.opensource.org/licenses/mit-license.php MIT License
-::
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-@echo off
-
-SET app=%0
-SET lib=%~dp0
-
-php -q "%lib%cake.php" -working "%CD% " %*
-
-echo.
-
-exit /B %ERRORLEVEL%
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Bake is a shell script for running CakePHP bake script
+::
+:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+::
+:: Licensed under The MIT License
+:: Redistributions of files must retain the above copyright notice.
+::
+:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+:: @link http://cakephp.org CakePHP(tm) Project
+:: @package Cake.Console
+:: @since CakePHP(tm) v 1.2.0.5012
+:: @license http://www.opensource.org/licenses/mit-license.php MIT License
+::
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+@echo off
+
+SET app=%0
+SET lib=%~dp0
+
+php -q "%lib%cake.php" -working "%CD% " %*
+
+echo.
+
+exit /B %ERRORLEVEL%
diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php
index 8e74c6256..e7b114dde 100644
--- a/web/includes/Monitor.php
+++ b/web/includes/Monitor.php
@@ -4,13 +4,16 @@ require_once( 'Server.php' );
class Monitor {
-private $fields = array(
-'Id',
-'Name',
-'StorageId',
-'ServerId',
-'Function',
-'Enabled',
+private $defaults = array(
+'Id' => null,
+'Name' => '',
+'StorageId' => 0,
+'ServerId' => 0,
+'Function' => 'None',
+'Enabled' => 1,
+'Width' => null,
+'Height' => null,
+'Orientation' => null,
);
private $control_fields = array(
'Name' => '',
@@ -158,19 +161,20 @@ private $control_fields = array(
public function Server() {
return new Server( $this->{'ServerId'} );
}
- public function __call( $fn, array $args){
- if ( count( $args ) ) {
+ public function __call($fn, array $args){
+ if ( count($args) ) {
$this->{$fn} = $args[0];
}
- if ( array_key_exists( $fn, $this ) ) {
+ if ( array_key_exists($fn, $this) ) {
return $this->{$fn};
#array_unshift($args, $this);
#call_user_func_array( $this->{$fn}, $args);
} else {
- if ( array_key_exists( $fn, $this->control_fields ) ) {
+ if ( array_key_exists($fn, $this->control_fields) ) {
return $this->control_fields{$fn};
+ } else if ( array_key_exists( $fn, $this->defaults ) ) {
+ return $this->defaults{$fn};
} else {
-
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
@@ -214,14 +218,19 @@ private $control_fields = array(
return( $streamSrc );
} // end function getStreamSrc
- public function Width() {
+ public function Width( $new = null ) {
+ if ( $new )
+ $this->{'Width'} = $new;
+
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
return $this->{'Height'};
}
return $this->{'Width'};
}
- public function Height() {
+ public function Height( $new=null ) {
+ if ( $new )
+ $this->{'Height'} = $new;
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
return $this->{'Width'};
}
@@ -287,11 +296,12 @@ private $control_fields = array(
}
}
- $sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $this->fields ) ) . ' WHERE Id=?';
+ $sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, array_keys( $this->defaults ) ) ) . ' WHERE Id=?';
$values = array_map( function($field){return $this->{$field};}, $this->fields );
$values[] = $this->{'Id'};
dbQuery( $sql, $values );
} // end function save
+
function zmcControl( $mode=false ) {
if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$this->{'ServerId'} ) ) {
if ( $this->{'Type'} == 'Local' ) {
@@ -306,7 +316,8 @@ private $control_fields = array(
if ( $mode == 'restart' ) {
daemonControl( 'stop', 'zmc', $zmcArgs );
}
- daemonControl( 'start', 'zmc', $zmcArgs );
+ if ( $this->{'Function'} != 'None' )
+ daemonControl( 'start', 'zmc', $zmcArgs );
}
} else {
$Server = $this->Server();
diff --git a/web/includes/MontageLayout.php b/web/includes/MontageLayout.php
new file mode 100644
index 000000000..0196d0c9c
--- /dev/null
+++ b/web/includes/MontageLayout.php
@@ -0,0 +1,132 @@
+ null,
+ 'Name' => '',
+ 'Positions' => 0,
+ );
+
+ public function __construct( $IdOrRow = NULL ) {
+ if ( $IdOrRow ) {
+ $row = NULL;
+ if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
+ $row = dbFetchOne( 'SELECT * FROM MontageLayouts WHERE Id=?', NULL, array( $IdOrRow ) );
+ if ( ! $row ) {
+ Error("Unable to load MontageLayout record for Id=" . $IdOrRow );
+ }
+ } elseif ( is_array( $IdOrRow ) ) {
+ $row = $IdOrRow;
+ } else {
+ Error("Unknown argument passed to MontageLayout Constructor ($IdOrRow)");
+ return;
+ }
+
+ if ( $row ) {
+ foreach ($row as $k => $v) {
+ $this->{$k} = $v;
+ }
+ } else {
+ Error('No row for MontageLayout ' . $IdOrRow );
+ }
+ } # end if isset($IdOrRow)
+ } // end function __construct
+
+ public function __call($fn, array $args){
+ if ( count($args) ) {
+ $this->{$fn} = $args[0];
+ }
+ if ( array_key_exists($fn, $this) ) {
+ return $this->{$fn};
+ } else {
+ if ( array_key_exists( $fn, $this->defaults ) ) {
+ return $this->defaults{$fn};
+ } else {
+ $backTrace = debug_backtrace();
+ $file = $backTrace[1]['file'];
+ $line = $backTrace[1]['line'];
+ Warning( "Unknown function call MontageLayout->$fn from $file:$line" );
+ }
+ }
+ }
+
+ public function set( $data ) {
+ foreach ($data as $k => $v) {
+ if ( is_array( $v ) ) {
+ # perhaps should turn into a comma-separated string
+ $this->{$k} = implode(',',$v);
+ } else if ( is_string( $v ) ) {
+ $this->{$k} = trim( $v );
+ } else if ( is_integer( $v ) ) {
+ $this->{$k} = $v;
+ } else if ( is_bool( $v ) ) {
+ $this->{$k} = $v;
+ } else {
+ Error( "Unknown type $k => $v of var " . gettype( $v ) );
+ $this->{$k} = $v;
+ }
+ }
+ }
+ public static function find( $parameters = null, $options = null ) {
+ $filters = array();
+ $sql = 'SELECT * FROM MontageLayouts ';
+ $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 and isset($options['order']) ) {
+ $sql .= ' ORDER BY ' . $options['order'];
+ }
+ $result = dbQuery($sql, $values);
+ if ( $result ) {
+ $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'MontageLayout');
+ foreach ( $results as $row => $obj ) {
+ $filters[] = $obj;
+ }
+ }
+ return $filters;
+ }
+ public function save( $new_values = null ) {
+ if ( $new_values ) {
+ foreach ( $new_values as $k=>$v ) {
+ $this->{$k} = $v;
+ }
+ }
+
+ $fields = array_values( array_filter( array_keys($this->defaults), function($field){return $field != 'Id';} ) );
+ $values = null;
+ if ( isset($this->{'Id'}) ) {
+ $sql = 'UPDATE MontageLayouts SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?';
+ $values = array_map( function($field){return $this->{$field};}, $fields );
+ $values[] = $this->{'Id'};
+ dbQuery( $sql, $values );
+ } else {
+ $sql = 'INSERT INTO MontageLayouts ('.implode( ',', $fields ).') VALUES ('.implode(',',array_map( function(){return '?';}, $fields ) ).')';
+ $values = array_map( function($field){return $this->{$field};}, $fields );
+ dbQuery( $sql, $values );
+ global $dbConn;
+ $this->{Id} = $dbConn->lastInsertId();
+ }
+ } // end function save
+
+} // end class MontageLayout
+?>
diff --git a/web/includes/actions.php b/web/includes/actions.php
index cbadae3f6..24184d7db 100644
--- a/web/includes/actions.php
+++ b/web/includes/actions.php
@@ -18,11 +18,32 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
-
// PP - POST request handler for PHP which does not need extensions
// credit: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/
+function do_request($method, $url, $data=array(), $optional_headers = null) {
+ global $php_errormsg;
+
+ $params = array('http' => array(
+ 'method' => $method,
+ 'content' => $data
+ ));
+ if ($optional_headers !== null) {
+ $params['http']['header'] = $optional_headers;
+ }
+ $ctx = stream_context_create($params);
+ $fp = @fopen($url, 'rb', false, $ctx);
+ if (!$fp) {
+ throw new Exception("Problem with $url, $php_errormsg");
+ }
+ $response = @stream_get_contents($fp);
+ if ($response === false) {
+ throw new Exception("Problem reading data from $url, $php_errormsg");
+ }
+ return $response;
+}
+
function do_post_request($url, $data, $optional_headers = null) {
$params = array('http' => array(
'method' => 'POST',
@@ -56,856 +77,876 @@ function getAffectedIds( $name ) {
}
-if ( !empty($action) ) {
- if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 'remote' || isset($_REQUEST['password']) ) ) {
- // if true, a popup will display after login
- // PP - lets validate reCaptcha if it exists
- if ( defined('ZM_OPT_USE_GOOG_RECAPTCHA')
- && defined('ZM_OPT_GOOG_RECAPTCHA_SECRETKEY')
- && defined('ZM_OPT_GOOG_RECAPTCHA_SITEKEY')
- && ZM_OPT_USE_GOOG_RECAPTCHA && ZM_OPT_GOOG_RECAPTCHA_SECRETKEY
- && ZM_OPT_GOOG_RECAPTCHA_SITEKEY)
- {
- $url = 'https://www.google.com/recaptcha/api/siteverify';
- $fields = array (
- 'secret'=> ZM_OPT_GOOG_RECAPTCHA_SECRETKEY,
- 'response' => $_REQUEST['g-recaptcha-response'],
- 'remoteip'=> $_SERVER['REMOTE_ADDR']
- );
- $res= do_post_request($url, http_build_query($fields));
- $responseData = json_decode($res,true);
- // PP - credit: https://github.com/google/recaptcha/blob/master/src/ReCaptcha/Response.php
- // if recaptcha resulted in error, we might have to deny login
- if (isset($responseData['success']) && $responseData['success'] == false) {
- // PP - before we deny auth, let's make sure the error was not 'invalid secret'
- // because that means the user did not configure the secret key correctly
- // in this case, we prefer to let him login in and display a message to correct
- // the key. Unfortunately, there is no way to check for invalid site key in code
- // as it produces the same error as when you don't answer a recaptcha
- if (isset($responseData['error-codes']) && is_array($responseData['error-codes'])) {
- if (!in_array('invalid-input-secret',$responseData['error-codes'])) {
- Error ('reCaptcha authentication failed');
- userLogout();
- $view='login';
- $refreshParent = true;
- } else {
- //Let them login but show an error
- echo '';
- Error ("Invalid recaptcha secret detected");
- }
- }
- } // end if success==false
-
- } // end if using reCaptcha
-
- $username = validStr( $_REQUEST['username'] );
- $password = isset($_REQUEST['password'])?validStr($_REQUEST['password']):'';
- userLogin( $username, $password );
- $refreshParent = true;
- $view = 'console';
- $redirect = true;
- } else if ( $action == 'logout' ) {
- userLogout();
- $refreshParent = true;
- $view = 'none';
- } else if ( $action == 'bandwidth' && isset($_REQUEST['newBandwidth']) ) {
- $_COOKIE['zmBandwidth'] = validStr($_REQUEST['newBandwidth']);
- setcookie( 'zmBandwidth', validStr($_REQUEST['newBandwidth']), time()+3600*24*30*12*10 );
- $refreshParent = true;
- }
-
- // Event scope actions, view permissions only required
- if ( canView( 'Events' ) ) {
-
- if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) {
- if ( $action == 'addterm' ) {
-Warning("Addterm");
- $_REQUEST['filter'] = addFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
- } elseif ( $action == 'delterm' ) {
- $_REQUEST['filter'] = delFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
- } else if ( canEdit( 'Events' ) ) {
- if ( $action == 'delete' ) {
- if ( ! empty($_REQUEST['Id']) ) {
- dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['Id'] ) );
- }
- } else if ( ( $action == 'save' ) or ( $action == 'execute' ) or ( $action == 'submit' ) ) {
-
- $sql = '';
- $_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' or $action == 'submit' ) {
- $sql .= ' Name = \'_TempFilter'.time().'\'';
- } else {
- $sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
- }
- $sql .= ', Query = '.dbEscape(jsonEncode($_REQUEST['filter']['Query']));
- $sql .= ', AutoArchive = '.(!empty($_REQUEST['filter']['AutoArchive']) ? 1 : 0);
- $sql .= ', AutoVideo = '. ( !empty($_REQUEST['filter']['AutoVideo']) ? 1 : 0);
- $sql .= ', AutoUpload = '. ( !empty($_REQUEST['filter']['AutoUpload']) ? 1 : 0);
- $sql .= ', AutoEmail = '. ( !empty($_REQUEST['filter']['AutoEmail']) ? 1 : 0);
- $sql .= ', AutoMessage = '. ( !empty($_REQUEST['filter']['AutoMessage']) ? 1 : 0);
- $sql .= ', AutoExecute = '. ( !empty($_REQUEST['filter']['AutoExecute']) ? 1 : 0);
- $sql .= ', AutoExecuteCmd = '.dbEscape($_REQUEST['filter']['AutoExecuteCmd']);
- $sql .= ', AutoDelete = '. ( !empty($_REQUEST['filter']['AutoDelete']) ? 1 : 0);
- $sql .= ', UpdateDiskSpace = '. ( !empty($_REQUEST['filter']['UpdateDiskSpace']) ? 1 : 0);
- $sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
- $sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
-
- if ( $_REQUEST['Id'] ) {
- dbQuery( 'UPDATE Filters SET ' . $sql. ' WHERE Id=?', array($_REQUEST['Id']) );
- } else {
- dbQuery( 'INSERT INTO Filters SET' . $sql );
- $_REQUEST['Id'] = dbInsertId();
- }
-
- } // end if save or execute
- } // end if canEdit(Events)
- return;
- } // end if object == filter
- else {
-
- // Event scope actions, edit permissions required
- if ( canEdit( 'Events' ) ) {
- if ( $action == 'rename' && isset($_REQUEST['eventName']) && !empty($_REQUEST['eid']) ) {
- dbQuery( 'UPDATE Events SET Name=? WHERE Id=?', array( $_REQUEST['eventName'], $_REQUEST['eid'] ) );
- } else if ( $action == 'eventdetail' ) {
- if ( !empty($_REQUEST['eid']) ) {
- dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['eid'] ) );
- } else {
- foreach( getAffectedIds( 'markEid' ) as $markEid ) {
- dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $markEid ) );
- }
- }
- $refreshParent = true;
- $closePopup = true;
- } elseif ( $action == 'archive' || $action == 'unarchive' ) {
- $archiveVal = ($action == 'archive')?1:0;
- if ( !empty($_REQUEST['eid']) ) {
- dbQuery( 'UPDATE Events SET Archived=? WHERE Id=?', array( $archiveVal, $_REQUEST['eid']) );
- } else {
- foreach( getAffectedIds( 'markEid' ) as $markEid ) {
- dbQuery( 'UPDATE Events SET Archived=? WHERE Id=?', array( $archiveVal, $markEid ) );
- }
- $refreshParent = true;
- }
- } elseif ( $action == 'delete' ) {
- foreach( getAffectedIds( 'markEid' ) as $markEid ) {
- deleteEvent( $markEid );
- }
- $refreshParent = true;
- }
- } // end if canEdit(Events)
- } // end if filter or something else
- } // end canView(Events)
-
- // Monitor control actions, require a monitor id and control view permissions for that monitor
- if ( !empty($_REQUEST['mid']) && canView( 'Control', $_REQUEST['mid'] ) ) {
- require_once( 'control_functions.php' );
- require_once( 'Monitor.php' );
- $mid = validInt($_REQUEST['mid']);
- if ( $action == 'control' ) {
- $monitor = new Monitor( $mid );
-
- $ctrlCommand = buildControlCommand( $monitor );
- sendControlCommand( $monitor->Id(), $ctrlCommand );
- } elseif ( $action == 'settings' ) {
- $args = " -m " . escapeshellarg($mid);
- $args .= " -B" . escapeshellarg($_REQUEST['newBrightness']);
- $args .= " -C" . escapeshellarg($_REQUEST['newContrast']);
- $args .= " -H" . escapeshellarg($_REQUEST['newHue']);
- $args .= " -O" . escapeshellarg($_REQUEST['newColour']);
-
- $zmuCommand = getZmuCommand( $args );
-
- $zmuOutput = exec( $zmuCommand );
- list( $brightness, $contrast, $hue, $colour ) = explode( ' ', $zmuOutput );
- dbQuery( 'UPDATE Monitors SET Brightness = ?, Contrast = ?, Hue = ?, Colour = ? WHERE Id = ?', array($brightness, $contrast, $hue, $colour, $mid));
- }
- }
-
- // Control capability actions, require control edit permissions
- if ( canEdit( 'Control' ) ) {
- if ( $action == 'controlcap' ) {
- if ( !empty($_REQUEST['cid']) ) {
- $control = dbFetchOne( 'SELECT * FROM Controls WHERE Id = ?', NULL, array($_REQUEST['cid']) );
- } else {
- $control = array();
- }
-
- // Define a field type for anything that's not simple text equivalent
- $types = array(
- // Empty
- );
-
- $columns = getTableColumns( 'Controls' );
- foreach ( $columns as $name=>$type ) {
- if ( preg_match( '/^(Can|Has)/', $name ) ) {
- $types[$name] = 'toggle';
- }
- }
- $changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns );
-
- if ( count( $changes ) ) {
- if ( !empty($_REQUEST['cid']) ) {
- dbQuery( "update Controls set ".implode( ", ", $changes )." where Id = ?", array($_REQUEST['cid']) );
- } else {
- dbQuery( "insert into Controls set ".implode( ", ", $changes ) );
- //$_REQUEST['cid'] = dbInsertId();
- }
- $refreshParent = true;
- }
- $view = 'none';
- } elseif ( $action == 'delete' ) {
- if ( isset($_REQUEST['markCids']) ) {
- foreach( $_REQUEST['markCids'] as $markCid ) {
- dbQuery( "delete from Controls where Id = ?", array($markCid) );
- dbQuery( "update Monitors set Controllable = 0, ControlId = 0 where ControlId = ?", array($markCid) );
- $refreshParent = true;
- }
- }
- }
- }
-
- if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) {
- if ( $action == 'save' ) {
- foreach ( $_REQUEST['mids'] as $mid ) {
- $mid = ValidInt( $mid );
- if ( ! canEdit('Monitors', $mid ) ) {
- Warning("Cannot edit monitor $mid");
- continue;
- }
- $Monitor = new Monitor( $mid );
- $Monitor->zmaControl('stop');
- $Monitor->zmcControl('stop');
- $Monitor->save( $_REQUEST['newMonitor'] );
- if ($Monitor->Function() != 'None' ) {
- $Monitor->zmcControl('start');
- if ( $Monitor->Enabled() ) {
- $Monitor->zmaControl('start');
- }
- }
-
- } // end foreach mid
- $refreshParent = true;
- } // end if action == save
- } // end if object is Monitor
-
- // Monitor edit actions, require a monitor id and edit permissions for that monitor
- if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
- $mid = validInt($_REQUEST['mid']);
- if ( $action == 'function' ) {
- $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id=?', NULL, array($mid) );
-
- $newFunction = validStr($_REQUEST['newFunction']);
- # Because we use a checkbox, it won't get passed in the request. So not being in _REQUEST means 0
- $newEnabled = ( !isset( $_REQUEST['newEnabled'] ) or $_REQUEST['newEnabled'] != '1' ) ? '0' : '1';
- $oldFunction = $monitor['Function'];
- $oldEnabled = $monitor['Enabled'];
- if ( $newFunction != $oldFunction || $newEnabled != $oldEnabled ) {
- dbQuery( 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?', array( $newFunction, $newEnabled, $mid ) );
-
- $monitor['Function'] = $newFunction;
- $monitor['Enabled'] = $newEnabled;
- if ( daemonCheck() ) {
- $restart = ($oldFunction == 'None') || ($newFunction == 'None') || ($newEnabled != $oldEnabled);
- zmaControl( $monitor, 'stop' );
- zmcControl( $monitor, $restart?'restart':'' );
- zmaControl( $monitor, 'start' );
- }
- $refreshParent = true;
- }
- } elseif ( $action == 'zone' && isset( $_REQUEST['zid'] ) ) {
- $zid = validInt($_REQUEST['zid']);
- $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id=?', NULL, array($mid) );
-
- if ( !empty($zid) ) {
- $zone = dbFetchOne( 'SELECT * FROM Zones WHERE MonitorId=? AND Id=?', NULL, array( $mid, $zid ) );
- } else {
- $zone = array();
- }
-
- if ( $_REQUEST['newZone']['Units'] == 'Percent' ) {
- $_REQUEST['newZone']['MinAlarmPixels'] = intval(($_REQUEST['newZone']['MinAlarmPixels']*$_REQUEST['newZone']['Area'])/100);
- $_REQUEST['newZone']['MaxAlarmPixels'] = intval(($_REQUEST['newZone']['MaxAlarmPixels']*$_REQUEST['newZone']['Area'])/100);
- if ( isset($_REQUEST['newZone']['MinFilterPixels']) )
- $_REQUEST['newZone']['MinFilterPixels'] = intval(($_REQUEST['newZone']['MinFilterPixels']*$_REQUEST['newZone']['Area'])/100);
- if ( isset($_REQUEST['newZone']['MaxFilterPixels']) )
- $_REQUEST['newZone']['MaxFilterPixels'] = intval(($_REQUEST['newZone']['MaxFilterPixels']*$_REQUEST['newZone']['Area'])/100);
- if ( isset($_REQUEST['newZone']['MinBlobPixels']) )
- $_REQUEST['newZone']['MinBlobPixels'] = intval(($_REQUEST['newZone']['MinBlobPixels']*$_REQUEST['newZone']['Area'])/100);
- if ( isset($_REQUEST['newZone']['MaxBlobPixels']) )
- $_REQUEST['newZone']['MaxBlobPixels'] = intval(($_REQUEST['newZone']['MaxBlobPixels']*$_REQUEST['newZone']['Area'])/100);
- }
-
- unset( $_REQUEST['newZone']['Points'] );
- $types = array();
- $changes = getFormChanges( $zone, $_REQUEST['newZone'], $types );
-
- if ( count( $changes ) ) {
- if ( $zid > 0 ) {
- dbQuery( "UPDATE Zones SET ".implode( ", ", $changes )." WHERE MonitorId=? AND Id=?", array( $mid, $zid) );
- } else {
- dbQuery( "INSERT INTO Zones SET MonitorId=?, ".implode( ", ", $changes ), array( $mid ) );
- }
- //if ( $cookies ) session_write_close();
- if ( daemonCheck() ) {
- if ( $_REQUEST['newZone']['Type'] == 'Privacy' ) {
- zmaControl( $monitor, 'stop' );
- zmcControl( $monitor, 'restart' );
- zmaControl( $monitor, 'start' );
- } else {
- zmaControl( $mid, 'restart' );
- }
- }
- if ( $_REQUEST['newZone']['Type'] == 'Privacy' && $monitor['Controllable'] ) {
- require_once( 'control_functions.php' );
- sendControlCommand( $mid, 'quit' );
- }
- $refreshParent = true;
- }
- $view = 'none';
- } elseif ( $action == 'plugin' && isset($_REQUEST['pl'])) {
- $sql='SELECT * FROM PluginsConfig WHERE MonitorId=? AND ZoneId=? AND pluginName=?';
- $pconfs=dbFetchAll( $sql, NULL, array( $mid, $_REQUEST['zid'], $_REQUEST['pl'] ) );
- $changes=0;
- foreach( $pconfs as $pconf ) {
- $value=$_REQUEST['pluginOpt'][$pconf['Name']];
- if(array_key_exists($pconf['Name'], $_REQUEST['pluginOpt']) && ($pconf['Value']!=$value)) {
- dbQuery("UPDATE PluginsConfig SET Value=? WHERE id=?", array( $value, $pconf['Id'] ) );
- $changes++;
- }
- }
- if($changes>0) {
- if ( daemonCheck() ) {
- zmaControl( $mid, 'restart' );
- }
- $refreshParent = true;
- }
- $view = 'none';
- } elseif ( $action == 'sequence' && isset($_REQUEST['smid']) ) {
- $smid = validInt($_REQUEST['smid']);
- $monitor = dbFetchOne( 'select * from Monitors where Id = ?', NULL, array($mid) );
- $smonitor = dbFetchOne( 'select * from Monitors where Id = ?', NULL, array($smid) );
-
- dbQuery( 'update Monitors set Sequence=? where Id=?', array( $smonitor['Sequence'], $monitor['Id'] ) );
- dbQuery( 'update Monitors set Sequence=? WHERE Id=?', array( $monitor['Sequence'], $smonitor['Id'] ) );
-
- $refreshParent = true;
- fixSequences();
- } elseif ( $action == 'delete' ) {
- if ( isset($_REQUEST['markZids']) ) {
- $deletedZid = 0;
- foreach( $_REQUEST['markZids'] as $markZid ) {
- $zone = dbFetchOne( 'select * from Zones where Id=?', NULL, array($markZid) );
- dbQuery( 'delete from Zones WHERE MonitorId=? AND Id=?', array( $mid, $markZid) );
- $deletedZid = 1;
- }
- if ( $deletedZid ) {
- //if ( $cookies )
- //session_write_close();
- if ( daemonCheck() ) {
- if ( $zone['Type'] == 'Privacy' ) {
- zmaControl( $mid, 'stop' );
- zmcControl( $mid, 'restart' );
- zmaControl( $mid, 'start' );
- } else {
- zmaControl( $mid, 'restart' );
- }
- } // end if daemonCheck()
- $refreshParent = true;
- } // end if deletedzid
- } // end if isset($_REQUEST['markZids'])
- } // end if action
- } // end if $mid and canEdit($mid)
-
- // Monitor edit actions, monitor id derived, require edit permissions for that monitor
- if ( canEdit( 'Monitors' ) ) {
- if ( $action == 'monitor' ) {
- $mid = 0;
- if ( !empty($_REQUEST['mid']) ) {
- $mid = validInt($_REQUEST['mid']);
- $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id = ?', NULL, array($mid) );
-
- if ( ZM_OPT_X10 ) {
- $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId=?', NULL, array($mid) );
- if ( !$x10Monitor )
- $x10Monitor = array();
- }
- } else {
- $monitor = array();
- if ( ZM_OPT_X10 ) {
- $x10Monitor = array();
- }
- }
-
- // Define a field type for anything that's not simple text equivalent
- $types = array(
- 'Triggers' => 'set',
- 'Controllable' => 'toggle',
- 'TrackMotion' => 'toggle',
- 'Enabled' => 'toggle',
- 'DoNativeMotDet' => 'toggle',
- 'Exif' => 'toggle',
- 'RTSPDescribe' => 'toggle',
- 'RecordAudio' => 'toggle',
- );
-
- $columns = getTableColumns( 'Monitors' );
- $changes = getFormChanges( $monitor, $_REQUEST['newMonitor'], $types, $columns );
-
- if ( count( $changes ) ) {
- if ( $mid ) {
-
- # If we change anything that changes the shared mem size, zma can complain. So let's stop first.
- zmaControl( $monitor, 'stop' );
- zmcControl( $monitor, 'stop' );
- dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) );
- if ( isset($changes['Name']) ) {
- $saferOldName = basename( $monitor['Name'] );
- $saferNewName = basename( $_REQUEST['newMonitor']['Name'] );
- rename( ZM_DIR_EVENTS.'/'.$saferOldName, ZM_DIR_EVENTS.'/'.$saferNewName);
- }
- if ( isset($changes['Width']) || isset($changes['Height']) ) {
- $newW = $_REQUEST['newMonitor']['Width'];
- $newH = $_REQUEST['newMonitor']['Height'];
- $newA = $newW * $newH;
- $oldW = $monitor['Width'];
- $oldH = $monitor['Height'];
- $oldA = $oldW * $oldH;
-
- $zones = dbFetchAll( 'SELECT * FROM Zones WHERE MonitorId=?', NULL, array($mid) );
- foreach ( $zones as $zone ) {
- $newZone = $zone;
- $points = coordsToPoints( $zone['Coords'] );
- for ( $i = 0; $i < count($points); $i++ ) {
- $points[$i]['x'] = intval(($points[$i]['x']*($newW-1))/($oldW-1));
- $points[$i]['y'] = intval(($points[$i]['y']*($newH-1))/($oldH-1));
- }
- $newZone['Coords'] = pointsToCoords( $points );
- $newZone['Area'] = intval(round(($zone['Area']*$newA)/$oldA));
- $newZone['MinAlarmPixels'] = intval(round(($newZone['MinAlarmPixels']*$newA)/$oldA));
- $newZone['MaxAlarmPixels'] = intval(round(($newZone['MaxAlarmPixels']*$newA)/$oldA));
- $newZone['MinFilterPixels'] = intval(round(($newZone['MinFilterPixels']*$newA)/$oldA));
- $newZone['MaxFilterPixels'] = intval(round(($newZone['MaxFilterPixels']*$newA)/$oldA));
- $newZone['MinBlobPixels'] = intval(round(($newZone['MinBlobPixels']*$newA)/$oldA));
- $newZone['MaxBlobPixels'] = intval(round(($newZone['MaxBlobPixels']*$newA)/$oldA));
-
- $changes = getFormChanges( $zone, $newZone, $types );
-
- if ( count( $changes ) ) {
- dbQuery( "update Zones set ".implode( ", ", $changes )." WHERE MonitorId=? AND Id=?", array( $mid, $zone['Id'] ) );
- }
- }
- }
- } elseif ( ! $user['MonitorIds'] ) { // Can only create new monitors if we are not restricted to specific monitors
-# FIXME This is actually a race condition. Should lock the table.
- $maxSeq = dbFetchOne( 'SELECT max(Sequence) AS MaxSequence FROM Monitors', 'MaxSequence' );
- $changes[] = 'Sequence = '.($maxSeq+1);
-
- dbQuery( 'INSERT INTO Monitors SET '.implode( ', ', $changes ) );
- $mid = dbInsertId();
- $zoneArea = $_REQUEST['newMonitor']['Width'] * $_REQUEST['newMonitor']['Height'];
- dbQuery( "insert into Zones set MonitorId = ?, Name = 'All', Type = 'Active', Units = 'Percent', NumCoords = 4, Coords = ?, Area=?, AlarmRGB = 0xff0000, CheckMethod = 'Blobs', MinPixelThreshold = 25, MinAlarmPixels=?, MaxAlarmPixels=?, FilterX = 3, FilterY = 3, MinFilterPixels=?, MaxFilterPixels=?, MinBlobPixels=?, MinBlobs = 1", array( $mid, sprintf( "%d,%d %d,%d %d,%d %d,%d", 0, 0, $_REQUEST['newMonitor']['Width']-1, 0, $_REQUEST['newMonitor']['Width']-1, $_REQUEST['newMonitor']['Height']-1, 0, $_REQUEST['newMonitor']['Height']-1 ), $zoneArea, intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*2)/100) ) );
- //$view = 'none';
- mkdir( ZM_DIR_EVENTS.'/'.$mid, 0755 );
- $saferName = basename($_REQUEST['newMonitor']['Name']);
- symlink( $mid, ZM_DIR_EVENTS.'/'.$saferName );
- if ( isset($_COOKIE['zmGroup']) ) {
- dbQuery( "UPDATE Groups SET MonitorIds = concat(MonitorIds,',".$mid."') WHERE Id=?", array($_COOKIE['zmGroup']) );
- }
- } else {
- Error("Users with Monitors restrictions cannot create new monitors.");
- }
- $restart = true;
- } # end if count(changes)
-
- if ( ZM_OPT_X10 ) {
- $x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] );
-
- if ( count( $x10Changes ) ) {
- if ( $x10Monitor && isset($_REQUEST['newX10Monitor']) ) {
- dbQuery( "update TriggersX10 set ".implode( ", ", $x10Changes )." where MonitorId=?", array($mid) );
- } elseif ( !$user['MonitorIds'] ) {
- if ( !$x10Monitor ) {
- dbQuery( "insert into TriggersX10 set MonitorId = ?, ".implode( ", ", $x10Changes ), array( $mid ) );
- } else {
- dbQuery( "delete from TriggersX10 where MonitorId = ?", array($mid) );
- }
- }
- $restart = true;
- }
- }
-
- if ( $restart ) {
- $new_monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id = ?', NULL, array($mid) );
- //fixDevices();
- //if ( $cookies )
- //session_write_close();
-
- zmcControl( $new_monitor, 'start' );
- zmaControl( $new_monitor, 'start' );
-
- if ( $new_monitor['Controllable'] ) {
- require_once( 'control_functions.php' );
- sendControlCommand( $mid, 'quit' );
- }
- // really should thump zmwatch and maybe zmtrigger too.
- //daemonControl( 'restart', 'zmwatch.pl' );
- $refreshParent = true;
- } // end if restart
- $view = 'none';
- } elseif ( $action == 'delete' ) {
- if ( isset($_REQUEST['markMids']) && !$user['MonitorIds'] ) {
- foreach( $_REQUEST['markMids'] as $markMid ) {
- if ( canEdit( 'Monitors', $markMid ) ) {
- if ( $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id = ?', NULL, array($markMid) ) ) {
- if ( daemonCheck() ) {
- zmaControl( $monitor, 'stop' );
- zmcControl( $monitor, 'stop' );
- }
-
- // If fast deletes are on, then zmaudit will clean everything else up later
- // If fast deletes are off and there are lots of events then this step may
- // well time out before completing, in which case zmaudit will still tidy up
- if ( !ZM_OPT_FAST_DELETE ) {
- $markEids = dbFetchAll( 'SELECT Id FROM Events WHERE MonitorId=?', 'Id', array($markMid) );
- foreach( $markEids as $markEid )
- deleteEvent( $markEid );
-
- deletePath( ZM_DIR_EVENTS.'/'.basename($monitor['Name']) );
- deletePath( ZM_DIR_EVENTS.'/'.$monitor['Id'] ); // I'm trusting the Id.
- } // end if ZM_OPT_FAST_DELETE
-
- // This is the important stuff
- dbQuery( 'DELETE FROM Monitors WHERE Id = ?', array($markMid) );
- dbQuery( 'DELETE FROM Zones WHERE MonitorId = ?', array($markMid) );
- if ( ZM_OPT_X10 )
- dbQuery( 'DELETE FROM TriggersX10 WHERE MonitorId=?', array($markMid) );
-
- fixSequences();
-
- } // end if found the monitor in the db
- } // end if canedit this monitor
- } // end foreach monitor in MarkMid
- } // markMids is set and we aren't limited to specific monitors
- } // end if action == Delete
- }
-
- // Device view actions
- if ( canEdit( 'Devices' ) ) {
- if ( $action == 'device' ) {
- if ( !empty($_REQUEST['command']) ) {
- setDeviceStatusX10( $_REQUEST['key'], $_REQUEST['command'] );
- } elseif ( isset( $_REQUEST['newDevice'] ) ) {
- if ( isset($_REQUEST['did']) ) {
- dbQuery( "update Devices set Name=?, KeyString=? where Id=?", array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'], $_REQUEST['did']) );
- } else {
- dbQuery( "insert into Devices set Name=?, KeyString=?", array( $_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'] ) );
- }
- $refreshParent = true;
- $view = 'none';
- }
- } elseif ( $action == 'delete' ) {
- if ( isset($_REQUEST['markDids']) ) {
- foreach( $_REQUEST['markDids'] as $markDid ) {
- dbQuery( "delete from Devices where Id=?", array($markDid) );
- $refreshParent = true;
- }
- }
- } // end if action
- } // end if canedit devices
-
- // Group view actions
- if ( canView( 'Groups' ) && $action == 'setgroup' ) {
- if ( !empty($_REQUEST['gid']) ) {
- setcookie( 'zmGroup', validInt($_REQUEST['gid']), time()+3600*24*30*12*10 );
- } else {
- setcookie( 'zmGroup', '', time()-3600*24*2 );
- }
- $refreshParent = true;
- }
-
- // Group edit actions
-# Should probably verify that each monitor id is a valid monitor, that we have access to. However at the moment, you have to have System permissions to do this
- if ( canEdit( 'Groups' ) ) {
- if ( $action == 'group' ) {
- $monitors = empty( $_POST['newGroup']['MonitorIds'] ) ? '' : implode(',', $_POST['newGroup']['MonitorIds']);
- if ( !empty($_POST['gid']) ) {
- dbQuery( 'UPDATE Groups SET Name=?, ParentId=?, MonitorIds=? WHERE Id=?',
- array($_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors, $_POST['gid']) );
- } else {
- dbQuery( 'INSERT INTO Groups SET Name=?, ParentId=?, MonitorIds=?',
- array( $_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors ) );
- }
- $view = 'none';
- $refreshParent = true;
- } else if ( $action == 'delete' ) {
- if ( !empty($_REQUEST['gid']) ) {
- if ( is_array( $_REQUEST['gid'] ) ) {
- foreach( $_REQUEST['gid'] as $gid ) {
- $Group = new Group( $gid );
- $Group->delete();
- }
- } else {
- $Group = new Group( $_REQUEST['gid'] );
- $Group->delete();
- }
- }
- $refreshParent = true;
- } # end if action
- } // end if can edit groups
-
- // System edit actions
- if ( canEdit( 'System' ) ) {
- if ( isset( $_REQUEST['object'] ) ) {
- if ( $_REQUEST['object'] == 'server' ) {
-
- if ( $action == 'Save' ) {
- if ( !empty($_REQUEST['id']) )
- $dbServer = dbFetchOne( 'SELECT * FROM Servers WHERE Id=?', NULL, array($_REQUEST['id']) );
- else
- $dbServer = array();
-
- $types = array();
- $changes = getFormChanges( $dbServer, $_REQUEST['newServer'], $types );
-
- if ( count( $changes ) ) {
- if ( !empty($_REQUEST['id']) ) {
- dbQuery( "UPDATE Servers SET ".implode( ", ", $changes )." WHERE Id = ?", array($_REQUEST['id']) );
- } else {
- dbQuery( "INSERT INTO Servers set ".implode( ", ", $changes ) );
- }
- $refreshParent = true;
- }
- $view = 'none';
- } else if ( $action == 'delete' ) {
- if ( !empty($_REQUEST['markIds']) ) {
- foreach( $_REQUEST['markIds'] as $Id )
- dbQuery( "DELETE FROM Servers WHERE Id=?", array($Id) );
- }
- $refreshParent = true;
- } else {
- Error( "Unknown action $action in saving Server" );
- }
- } else if ( $_REQUEST['object'] == 'storage' ) {
- if ( $action == 'Save' ) {
- if ( !empty($_REQUEST['id']) )
- $dbStorage = dbFetchOne( 'SELECT * FROM Storage WHERE Id=?', NULL, array($_REQUEST['id']) );
- else
- $dbStorage = array();
-
- $types = array();
- $changes = getFormChanges( $dbStorage, $_REQUEST['newStorage'], $types );
-
- if ( count( $changes ) ) {
- if ( !empty($_REQUEST['id']) ) {
- dbQuery( "UPDATE Storage SET ".implode( ", ", $changes )." WHERE Id = ?", array($_REQUEST['id']) );
- } else {
- dbQuery( "INSERT INTO Storage set ".implode( ", ", $changes ) );
- }
- $refreshParent = true;
- }
- $view = 'none';
- } else if ( $action == 'delete' ) {
- if ( !empty($_REQUEST['markIds']) ) {
- foreach( $_REQUEST['markIds'] as $Id )
- dbQuery( 'DELETE FROM Storage WHERE Id=?', array($Id) );
- }
- $refreshParent = true;
- } else {
- Error( "Unknown action $action in saving Storage" );
- }
- } # end if isset($_REQUEST['object'] )
-
- } else if ( $action == 'version' && isset($_REQUEST['option']) ) {
- $option = $_REQUEST['option'];
- switch( $option ) {
- case 'go' :
- {
- // Ignore this, the caller will open the page itself
- break;
- }
- case 'ignore' :
- {
- dbQuery( "update Config set Value = '".ZM_DYN_LAST_VERSION."' where Name = 'ZM_DYN_CURR_VERSION'" );
- break;
- }
- case 'hour' :
- case 'day' :
- case 'week' :
- {
- $nextReminder = time();
- if ( $option == 'hour' ) {
- $nextReminder += 60*60;
- } elseif ( $option == 'day' ) {
- $nextReminder += 24*60*60;
- } elseif ( $option == 'week' ) {
- $nextReminder += 7*24*60*60;
- }
- dbQuery( "update Config set Value = '".$nextReminder."' where Name = 'ZM_DYN_NEXT_REMINDER'" );
- break;
- }
- case 'never' :
- {
- dbQuery( "update Config set Value = '0' where Name = 'ZM_CHECK_FOR_UPDATES'" );
- break;
- }
- }
- }
- if ( $action == 'donate' && isset($_REQUEST['option']) ) {
- $option = $_REQUEST['option'];
- switch( $option ) {
- case 'go' :
- {
- // Ignore this, the caller will open the page itself
- break;
- }
- case 'hour' :
- case 'day' :
- case 'week' :
- case 'month' :
- {
- $nextReminder = time();
- if ( $option == 'hour' ) {
- $nextReminder += 60*60;
- } elseif ( $option == 'day' ) {
- $nextReminder += 24*60*60;
- } elseif ( $option == 'week' ) {
- $nextReminder += 7*24*60*60;
- } elseif ( $option == 'month' ) {
- $nextReminder += 30*24*60*60;
- }
- dbQuery( "update Config set Value = '".$nextReminder."' where Name = 'ZM_DYN_DONATE_REMINDER_TIME'" );
- break;
- }
- case 'never' :
- case 'already' :
- {
- dbQuery( "update Config set Value = '0' where Name = 'ZM_DYN_SHOW_DONATE_REMINDER'" );
- break;
- }
- } // end switch option
- }
- if ( $action == 'options' && isset($_REQUEST['tab']) ) {
- $configCat = $configCats[$_REQUEST['tab']];
- $changed = false;
- foreach ( $configCat as $name=>$value ) {
- unset( $newValue );
- if ( $value['Type'] == 'boolean' && empty($_REQUEST['newConfig'][$name]) )
- $newValue = 0;
- elseif ( isset($_REQUEST['newConfig'][$name]) )
- $newValue = preg_replace( "/\r\n/", "\n", stripslashes( $_REQUEST['newConfig'][$name] ) );
-
- if ( isset($newValue) && ($newValue != $value['Value']) ) {
- dbQuery( 'UPDATE Config SET Value=? WHERE Name=?', array( $newValue, $name ) );
- $changed = true;
- }
- }
- if ( $changed ) {
- switch( $_REQUEST['tab'] ) {
- case 'system' :
- case 'config' :
- $restartWarning = true;
- break;
- case 'web' :
- case 'tools' :
- break;
- case 'logging' :
- case 'network' :
- case 'mail' :
- case 'upload' :
- $restartWarning = true;
- break;
- case 'highband' :
- case 'medband' :
- case 'lowband' :
- break;
- }
- }
- loadConfig( false );
- } elseif ( $action == 'user' ) {
- if ( !empty($_REQUEST['uid']) )
- $dbUser = dbFetchOne( "SELECT * FROM Users WHERE Id=?", NULL, array($_REQUEST['uid']) );
- else
- $dbUser = array();
-
- $types = array();
- $changes = getFormChanges( $dbUser, $_REQUEST['newUser'], $types );
-
- if ( $_REQUEST['newUser']['Password'] )
- $changes['Password'] = "Password = password(".dbEscape($_REQUEST['newUser']['Password']).")";
- else
- unset( $changes['Password'] );
-
- if ( count( $changes ) ) {
- if ( !empty($_REQUEST['uid']) ) {
- dbQuery( "update Users set ".implode( ", ", $changes )." where Id = ?", array($_REQUEST['uid']) );
- # If we are updating the logged in user, then update our session user data.
- if ( $user and ( $dbUser['Username'] == $user['Username'] ) )
- userLogin( $dbUser['Username'], $dbUser['Password'] );
- } else {
- dbQuery( "insert into Users set ".implode( ", ", $changes ) );
- }
- $refreshParent = true;
- }
- $view = 'none';
- } elseif ( $action == 'state' ) {
- if ( !empty($_REQUEST['runState']) ) {
- //if ( $cookies ) session_write_close();
- packageControl( $_REQUEST['runState'] );
- $refreshParent = true;
- }
- } elseif ( $action == 'save' ) {
- if ( !empty($_REQUEST['runState']) || !empty($_REQUEST['newState']) ) {
- $sql = 'SELECT Id,Function,Enabled FROM Monitors ORDER BY Id';
- $definitions = array();
- foreach( dbFetchAll( $sql ) as $monitor )
- {
- $definitions[] = $monitor['Id'].":".$monitor['Function'].":".$monitor['Enabled'];
- }
- $definition = join( ',', $definitions );
- if ( $_REQUEST['newState'] )
- $_REQUEST['runState'] = $_REQUEST['newState'];
- dbQuery( "replace into States set Name=?, Definition=?", array( $_REQUEST['runState'],$definition) );
- }
- } elseif ( $action == 'delete' ) {
- if ( isset($_REQUEST['runState']) )
- dbQuery( "delete from States where Name=?", array($_REQUEST['runState']) );
-
- if ( isset($_REQUEST['markUids']) ) {
- foreach( $_REQUEST['markUids'] as $markUid )
- dbQuery( "delete from Users where Id = ?", array($markUid) );
- if ( $markUid == $user['Id'] )
+if ( empty($action) ) {
+ return;
+}
+if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 'remote' || isset($_REQUEST['password']) ) ) {
+ // if true, a popup will display after login
+ // PP - lets validate reCaptcha if it exists
+ if ( defined('ZM_OPT_USE_GOOG_RECAPTCHA')
+ && defined('ZM_OPT_GOOG_RECAPTCHA_SECRETKEY')
+ && defined('ZM_OPT_GOOG_RECAPTCHA_SITEKEY')
+ && ZM_OPT_USE_GOOG_RECAPTCHA && ZM_OPT_GOOG_RECAPTCHA_SECRETKEY
+ && ZM_OPT_GOOG_RECAPTCHA_SITEKEY )
+ {
+ $url = 'https://www.google.com/recaptcha/api/siteverify';
+ $fields = array (
+ 'secret' => ZM_OPT_GOOG_RECAPTCHA_SECRETKEY,
+ 'response' => $_REQUEST['g-recaptcha-response'],
+ 'remoteip' => $_SERVER['REMOTE_ADDR']
+ );
+ $res = do_post_request($url, http_build_query($fields));
+ $responseData = json_decode($res,true);
+ // PP - credit: https://github.com/google/recaptcha/blob/master/src/ReCaptcha/Response.php
+ // if recaptcha resulted in error, we might have to deny login
+ if (isset($responseData['success']) && $responseData['success'] == false) {
+ // PP - before we deny auth, let's make sure the error was not 'invalid secret'
+ // because that means the user did not configure the secret key correctly
+ // in this case, we prefer to let him login in and display a message to correct
+ // the key. Unfortunately, there is no way to check for invalid site key in code
+ // as it produces the same error as when you don't answer a recaptcha
+ if (isset($responseData['error-codes']) && is_array($responseData['error-codes'])) {
+ if (!in_array('invalid-input-secret',$responseData['error-codes'])) {
+ Error ('reCaptcha authentication failed');
userLogout();
+ $view='login';
+ $refreshParent = true;
+ } else {
+ //Let them login but show an error
+ echo '';
+ Error ("Invalid recaptcha secret detected");
+ }
}
- }
- } else {
- if ( ZM_USER_SELF_EDIT && $action == 'user' ) {
- $uid = $user['Id'];
+ } // end if success==false
- $dbUser = dbFetchOne( 'SELECT Id, Password, Language FROM Users WHERE Id = ?', NULL, array($uid) );
+ } // end if using reCaptcha
- $types = array();
- $changes = getFormChanges( $dbUser, $_REQUEST['newUser'], $types );
+ $username = validStr( $_REQUEST['username'] );
+ $password = isset($_REQUEST['password'])?validStr($_REQUEST['password']):'';
+ userLogin( $username, $password );
+ $refreshParent = true;
+ $view = 'console';
+ $redirect = true;
+} else if ( $action == 'logout' ) {
+ userLogout();
+ $refreshParent = true;
+ $view = 'none';
+} else if ( $action == 'bandwidth' && isset($_REQUEST['newBandwidth']) ) {
+ $_COOKIE['zmBandwidth'] = validStr($_REQUEST['newBandwidth']);
+ setcookie( 'zmBandwidth', validStr($_REQUEST['newBandwidth']), time()+3600*24*30*12*10 );
+ $refreshParent = true;
+}
- if ( !empty($_REQUEST['newUser']['Password']) )
- $changes['Password'] = "Password = password(".dbEscape($_REQUEST['newUser']['Password']).")";
- else
- unset( $changes['Password'] );
- if ( count( $changes ) ) {
- dbQuery( "update Users set ".implode( ", ", $changes )." where Id=?", array($uid) );
+// Event scope actions, view permissions only required
+if ( canView( 'Events' ) ) {
+
+ if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) {
+ if ( $action == 'addterm' ) {
+Warning("Addterm");
+ $_REQUEST['filter'] = addFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
+ } elseif ( $action == 'delterm' ) {
+ $_REQUEST['filter'] = delFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
+ } else if ( canEdit( 'Events' ) ) {
+ if ( $action == 'delete' ) {
+ if ( ! empty($_REQUEST['Id']) ) {
+ dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['Id'] ) );
+ }
+ } else if ( ( $action == 'save' ) or ( $action == 'execute' ) or ( $action == 'submit' ) ) {
+
+ $sql = '';
+ $_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' or $action == 'submit' ) {
+ $sql .= ' Name = \'_TempFilter'.time().'\'';
+ } else {
+ $sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
+ }
+ $sql .= ', Query = '.dbEscape(jsonEncode($_REQUEST['filter']['Query']));
+ $sql .= ', AutoArchive = '.(!empty($_REQUEST['filter']['AutoArchive']) ? 1 : 0);
+ $sql .= ', AutoVideo = '. ( !empty($_REQUEST['filter']['AutoVideo']) ? 1 : 0);
+ $sql .= ', AutoUpload = '. ( !empty($_REQUEST['filter']['AutoUpload']) ? 1 : 0);
+ $sql .= ', AutoEmail = '. ( !empty($_REQUEST['filter']['AutoEmail']) ? 1 : 0);
+ $sql .= ', AutoMessage = '. ( !empty($_REQUEST['filter']['AutoMessage']) ? 1 : 0);
+ $sql .= ', AutoExecute = '. ( !empty($_REQUEST['filter']['AutoExecute']) ? 1 : 0);
+ $sql .= ', AutoExecuteCmd = '.dbEscape($_REQUEST['filter']['AutoExecuteCmd']);
+ $sql .= ', AutoDelete = '. ( !empty($_REQUEST['filter']['AutoDelete']) ? 1 : 0);
+ $sql .= ', UpdateDiskSpace = '. ( !empty($_REQUEST['filter']['UpdateDiskSpace']) ? 1 : 0);
+ $sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
+ $sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
+
+ if ( $_REQUEST['Id'] ) {
+ dbQuery( 'UPDATE Filters SET ' . $sql. ' WHERE Id=?', array($_REQUEST['Id']) );
+ } else {
+ dbQuery( 'INSERT INTO Filters SET' . $sql );
+ $_REQUEST['Id'] = dbInsertId();
+ }
+
+ } // end if save or execute
+ } // end if canEdit(Events)
+ return;
+ } // end if object == filter
+ else {
+
+ // Event scope actions, edit permissions required
+ if ( canEdit( 'Events' ) ) {
+ if ( $action == 'rename' && isset($_REQUEST['eventName']) && !empty($_REQUEST['eid']) ) {
+ dbQuery( 'UPDATE Events SET Name=? WHERE Id=?', array( $_REQUEST['eventName'], $_REQUEST['eid'] ) );
+ } else if ( $action == 'eventdetail' ) {
+ if ( !empty($_REQUEST['eid']) ) {
+ dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['eid'] ) );
+ } else {
+ foreach( getAffectedIds( 'markEid' ) as $markEid ) {
+ dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $markEid ) );
+ }
+ }
+ $refreshParent = true;
+ $closePopup = true;
+ } elseif ( $action == 'archive' || $action == 'unarchive' ) {
+ $archiveVal = ($action == 'archive')?1:0;
+ if ( !empty($_REQUEST['eid']) ) {
+ dbQuery( 'UPDATE Events SET Archived=? WHERE Id=?', array( $archiveVal, $_REQUEST['eid']) );
+ } else {
+ foreach( getAffectedIds( 'markEid' ) as $markEid ) {
+ dbQuery( 'UPDATE Events SET Archived=? WHERE Id=?', array( $archiveVal, $markEid ) );
+ }
+ $refreshParent = true;
+ }
+ } elseif ( $action == 'delete' ) {
+ foreach( getAffectedIds( 'markEid' ) as $markEid ) {
+ deleteEvent( $markEid );
+ }
$refreshParent = true;
}
- $view = 'none';
- }
- }
+ } // end if canEdit(Events)
+ } // end if filter or something else
+} // end canView(Events)
- if ( $action == 'reset' ) {
- $_SESSION['zmEventResetTime'] = strftime( STRF_FMT_DATETIME_DB );
- setcookie( 'zmEventResetTime', $_SESSION['zmEventResetTime'], time()+3600*24*30*12*10 );
- //if ( $cookies ) session_write_close();
+// Monitor control actions, require a monitor id and control view permissions for that monitor
+if ( !empty($_REQUEST['mid']) && canView( 'Control', $_REQUEST['mid'] ) ) {
+ require_once( 'control_functions.php' );
+ require_once( 'Monitor.php' );
+ $mid = validInt($_REQUEST['mid']);
+ if ( $action == 'control' ) {
+ $monitor = new Monitor( $mid );
+
+ $ctrlCommand = buildControlCommand( $monitor );
+ sendControlCommand( $monitor->Id(), $ctrlCommand );
+ } elseif ( $action == 'settings' ) {
+ $args = " -m " . escapeshellarg($mid);
+ $args .= " -B" . escapeshellarg($_REQUEST['newBrightness']);
+ $args .= " -C" . escapeshellarg($_REQUEST['newContrast']);
+ $args .= " -H" . escapeshellarg($_REQUEST['newHue']);
+ $args .= " -O" . escapeshellarg($_REQUEST['newColour']);
+
+ $zmuCommand = getZmuCommand( $args );
+
+ $zmuOutput = exec( $zmuCommand );
+ list( $brightness, $contrast, $hue, $colour ) = explode( ' ', $zmuOutput );
+ dbQuery( 'UPDATE Monitors SET Brightness = ?, Contrast = ?, Hue = ?, Colour = ? WHERE Id = ?', array($brightness, $contrast, $hue, $colour, $mid));
}
}
+// Control capability actions, require control edit permissions
+if ( canEdit( 'Control' ) ) {
+ if ( $action == 'controlcap' ) {
+ if ( !empty($_REQUEST['cid']) ) {
+ $control = dbFetchOne( 'SELECT * FROM Controls WHERE Id = ?', NULL, array($_REQUEST['cid']) );
+ } else {
+ $control = array();
+ }
+
+ // Define a field type for anything that's not simple text equivalent
+ $types = array(
+ // Empty
+ );
+
+ $columns = getTableColumns( 'Controls' );
+ foreach ( $columns as $name=>$type ) {
+ if ( preg_match( '/^(Can|Has)/', $name ) ) {
+ $types[$name] = 'toggle';
+ }
+ }
+ $changes = getFormChanges( $control, $_REQUEST['newControl'], $types, $columns );
+
+ if ( count( $changes ) ) {
+ if ( !empty($_REQUEST['cid']) ) {
+ dbQuery( "update Controls set ".implode( ", ", $changes )." where Id = ?", array($_REQUEST['cid']) );
+ } else {
+ dbQuery( "insert into Controls set ".implode( ", ", $changes ) );
+ //$_REQUEST['cid'] = dbInsertId();
+ }
+ $refreshParent = true;
+ }
+ $view = 'none';
+ } elseif ( $action == 'delete' ) {
+ if ( isset($_REQUEST['markCids']) ) {
+ foreach( $_REQUEST['markCids'] as $markCid ) {
+ dbQuery( "delete from Controls where Id = ?", array($markCid) );
+ dbQuery( "update Monitors set Controllable = 0, ControlId = 0 where ControlId = ?", array($markCid) );
+ $refreshParent = true;
+ }
+ }
+ }
+}
+
+if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) {
+ if ( $action == 'save' ) {
+ foreach ( $_REQUEST['mids'] as $mid ) {
+ $mid = ValidInt( $mid );
+ if ( ! canEdit('Monitors', $mid ) ) {
+ Warning("Cannot edit monitor $mid");
+ continue;
+ }
+ $Monitor = new Monitor( $mid );
+ $Monitor->zmaControl('stop');
+ $Monitor->zmcControl('stop');
+ $Monitor->save( $_REQUEST['newMonitor'] );
+ if ($Monitor->Function() != 'None' ) {
+ $Monitor->zmcControl('start');
+ if ( $Monitor->Enabled() ) {
+ $Monitor->zmaControl('start');
+ }
+ }
+
+ } // end foreach mid
+ $refreshParent = true;
+ } // end if action == save
+} // end if object is Monitor
+
+// Monitor edit actions, require a monitor id and edit permissions for that monitor
+if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
+ $mid = validInt($_REQUEST['mid']);
+ if ( $action == 'function' ) {
+ $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id=?', NULL, array($mid) );
+
+ $newFunction = validStr($_REQUEST['newFunction']);
+ # Because we use a checkbox, it won't get passed in the request. So not being in _REQUEST means 0
+ $newEnabled = ( !isset( $_REQUEST['newEnabled'] ) or $_REQUEST['newEnabled'] != '1' ) ? '0' : '1';
+ $oldFunction = $monitor['Function'];
+ $oldEnabled = $monitor['Enabled'];
+ if ( $newFunction != $oldFunction || $newEnabled != $oldEnabled ) {
+ dbQuery( 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?', array( $newFunction, $newEnabled, $mid ) );
+
+ $monitor['Function'] = $newFunction;
+ $monitor['Enabled'] = $newEnabled;
+ if ( daemonCheck() ) {
+ $restart = ($oldFunction == 'None') || ($newFunction == 'None') || ($newEnabled != $oldEnabled);
+ zmaControl( $monitor, 'stop' );
+ zmcControl( $monitor, $restart?'restart':'' );
+ zmaControl( $monitor, 'start' );
+ }
+ $refreshParent = true;
+ }
+ } elseif ( $action == 'zone' && isset( $_REQUEST['zid'] ) ) {
+ $zid = validInt($_REQUEST['zid']);
+ $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id=?', NULL, array($mid) );
+
+ if ( !empty($zid) ) {
+ $zone = dbFetchOne( 'SELECT * FROM Zones WHERE MonitorId=? AND Id=?', NULL, array( $mid, $zid ) );
+ } else {
+ $zone = array();
+ }
+
+ if ( $_REQUEST['newZone']['Units'] == 'Percent' ) {
+ $_REQUEST['newZone']['MinAlarmPixels'] = intval(($_REQUEST['newZone']['MinAlarmPixels']*$_REQUEST['newZone']['Area'])/100);
+ $_REQUEST['newZone']['MaxAlarmPixels'] = intval(($_REQUEST['newZone']['MaxAlarmPixels']*$_REQUEST['newZone']['Area'])/100);
+ if ( isset($_REQUEST['newZone']['MinFilterPixels']) )
+ $_REQUEST['newZone']['MinFilterPixels'] = intval(($_REQUEST['newZone']['MinFilterPixels']*$_REQUEST['newZone']['Area'])/100);
+ if ( isset($_REQUEST['newZone']['MaxFilterPixels']) )
+ $_REQUEST['newZone']['MaxFilterPixels'] = intval(($_REQUEST['newZone']['MaxFilterPixels']*$_REQUEST['newZone']['Area'])/100);
+ if ( isset($_REQUEST['newZone']['MinBlobPixels']) )
+ $_REQUEST['newZone']['MinBlobPixels'] = intval(($_REQUEST['newZone']['MinBlobPixels']*$_REQUEST['newZone']['Area'])/100);
+ if ( isset($_REQUEST['newZone']['MaxBlobPixels']) )
+ $_REQUEST['newZone']['MaxBlobPixels'] = intval(($_REQUEST['newZone']['MaxBlobPixels']*$_REQUEST['newZone']['Area'])/100);
+ }
+
+ unset( $_REQUEST['newZone']['Points'] );
+ $types = array();
+ $changes = getFormChanges( $zone, $_REQUEST['newZone'], $types );
+
+ if ( count( $changes ) ) {
+ if ( $zid > 0 ) {
+ dbQuery( "UPDATE Zones SET ".implode( ", ", $changes )." WHERE MonitorId=? AND Id=?", array( $mid, $zid) );
+ } else {
+ dbQuery( "INSERT INTO Zones SET MonitorId=?, ".implode( ", ", $changes ), array( $mid ) );
+ }
+ //if ( $cookies ) session_write_close();
+ if ( daemonCheck() ) {
+ if ( $_REQUEST['newZone']['Type'] == 'Privacy' ) {
+ zmaControl( $monitor, 'stop' );
+ zmcControl( $monitor, 'restart' );
+ zmaControl( $monitor, 'start' );
+ } else {
+ zmaControl( $mid, 'restart' );
+ }
+ }
+ if ( $_REQUEST['newZone']['Type'] == 'Privacy' && $monitor['Controllable'] ) {
+ require_once( 'control_functions.php' );
+ sendControlCommand( $mid, 'quit' );
+ }
+ $refreshParent = true;
+ }
+ $view = 'none';
+ } elseif ( $action == 'plugin' && isset($_REQUEST['pl'])) {
+ $sql='SELECT * FROM PluginsConfig WHERE MonitorId=? AND ZoneId=? AND pluginName=?';
+ $pconfs=dbFetchAll( $sql, NULL, array( $mid, $_REQUEST['zid'], $_REQUEST['pl'] ) );
+ $changes=0;
+ foreach( $pconfs as $pconf ) {
+ $value=$_REQUEST['pluginOpt'][$pconf['Name']];
+ if(array_key_exists($pconf['Name'], $_REQUEST['pluginOpt']) && ($pconf['Value']!=$value)) {
+ dbQuery("UPDATE PluginsConfig SET Value=? WHERE id=?", array( $value, $pconf['Id'] ) );
+ $changes++;
+ }
+ }
+ if($changes>0) {
+ if ( daemonCheck() ) {
+ zmaControl( $mid, 'restart' );
+ }
+ $refreshParent = true;
+ }
+ $view = 'none';
+ } elseif ( $action == 'sequence' && isset($_REQUEST['smid']) ) {
+ $smid = validInt($_REQUEST['smid']);
+ $monitor = dbFetchOne( 'select * from Monitors where Id = ?', NULL, array($mid) );
+ $smonitor = dbFetchOne( 'select * from Monitors where Id = ?', NULL, array($smid) );
+
+ dbQuery( 'update Monitors set Sequence=? where Id=?', array( $smonitor['Sequence'], $monitor['Id'] ) );
+ dbQuery( 'update Monitors set Sequence=? WHERE Id=?', array( $monitor['Sequence'], $smonitor['Id'] ) );
+
+ $refreshParent = true;
+ fixSequences();
+ } elseif ( $action == 'delete' ) {
+ if ( isset($_REQUEST['markZids']) ) {
+ $deletedZid = 0;
+ foreach( $_REQUEST['markZids'] as $markZid ) {
+ $zone = dbFetchOne( 'select * from Zones where Id=?', NULL, array($markZid) );
+ dbQuery( 'delete from Zones WHERE MonitorId=? AND Id=?', array( $mid, $markZid) );
+ $deletedZid = 1;
+ }
+ if ( $deletedZid ) {
+ //if ( $cookies )
+ //session_write_close();
+ if ( daemonCheck() ) {
+ if ( $zone['Type'] == 'Privacy' ) {
+ zmaControl( $mid, 'stop' );
+ zmcControl( $mid, 'restart' );
+ zmaControl( $mid, 'start' );
+ } else {
+ zmaControl( $mid, 'restart' );
+ }
+ } // end if daemonCheck()
+ $refreshParent = true;
+ } // end if deletedzid
+ } // end if isset($_REQUEST['markZids'])
+ } // end if action
+} // end if $mid and canEdit($mid)
+
+// Monitor edit actions, monitor id derived, require edit permissions for that monitor
+if ( canEdit( 'Monitors' ) ) {
+ if ( $action == 'monitor' ) {
+ $mid = 0;
+ if ( !empty($_REQUEST['mid']) ) {
+ $mid = validInt($_REQUEST['mid']);
+ $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id = ?', NULL, array($mid) );
+
+ if ( ZM_OPT_X10 ) {
+ $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId=?', NULL, array($mid) );
+ if ( !$x10Monitor )
+ $x10Monitor = array();
+ }
+ } else {
+ $monitor = array();
+ if ( ZM_OPT_X10 ) {
+ $x10Monitor = array();
+ }
+ }
+
+ // Define a field type for anything that's not simple text equivalent
+ $types = array(
+ 'Triggers' => 'set',
+ 'Controllable' => 'toggle',
+ 'TrackMotion' => 'toggle',
+ 'Enabled' => 'toggle',
+ 'DoNativeMotDet' => 'toggle',
+ 'Exif' => 'toggle',
+ 'RTSPDescribe' => 'toggle',
+ 'RecordAudio' => 'toggle',
+ );
+
+ $columns = getTableColumns( 'Monitors' );
+ $changes = getFormChanges( $monitor, $_REQUEST['newMonitor'], $types, $columns );
+
+ if ( count( $changes ) ) {
+ if ( $mid ) {
+
+ # If we change anything that changes the shared mem size, zma can complain. So let's stop first.
+ zmaControl( $monitor, 'stop' );
+ zmcControl( $monitor, 'stop' );
+ dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) );
+ if ( isset($changes['Name']) ) {
+ $saferOldName = basename( $monitor['Name'] );
+ $saferNewName = basename( $_REQUEST['newMonitor']['Name'] );
+ rename( ZM_DIR_EVENTS.'/'.$saferOldName, ZM_DIR_EVENTS.'/'.$saferNewName);
+ }
+ if ( isset($changes['Width']) || isset($changes['Height']) ) {
+ $newW = $_REQUEST['newMonitor']['Width'];
+ $newH = $_REQUEST['newMonitor']['Height'];
+ $newA = $newW * $newH;
+ $oldW = $monitor['Width'];
+ $oldH = $monitor['Height'];
+ $oldA = $oldW * $oldH;
+
+ $zones = dbFetchAll( 'SELECT * FROM Zones WHERE MonitorId=?', NULL, array($mid) );
+ foreach ( $zones as $zone ) {
+ $newZone = $zone;
+ $points = coordsToPoints( $zone['Coords'] );
+ for ( $i = 0; $i < count($points); $i++ ) {
+ $points[$i]['x'] = intval(($points[$i]['x']*($newW-1))/($oldW-1));
+ $points[$i]['y'] = intval(($points[$i]['y']*($newH-1))/($oldH-1));
+ }
+ $newZone['Coords'] = pointsToCoords( $points );
+ $newZone['Area'] = intval(round(($zone['Area']*$newA)/$oldA));
+ $newZone['MinAlarmPixels'] = intval(round(($newZone['MinAlarmPixels']*$newA)/$oldA));
+ $newZone['MaxAlarmPixels'] = intval(round(($newZone['MaxAlarmPixels']*$newA)/$oldA));
+ $newZone['MinFilterPixels'] = intval(round(($newZone['MinFilterPixels']*$newA)/$oldA));
+ $newZone['MaxFilterPixels'] = intval(round(($newZone['MaxFilterPixels']*$newA)/$oldA));
+ $newZone['MinBlobPixels'] = intval(round(($newZone['MinBlobPixels']*$newA)/$oldA));
+ $newZone['MaxBlobPixels'] = intval(round(($newZone['MaxBlobPixels']*$newA)/$oldA));
+
+ $changes = getFormChanges( $zone, $newZone, $types );
+
+ if ( count( $changes ) ) {
+ dbQuery( "update Zones set ".implode( ", ", $changes )." WHERE MonitorId=? AND Id=?", array( $mid, $zone['Id'] ) );
+ }
+ }
+ }
+ } elseif ( ! $user['MonitorIds'] ) { // Can only create new monitors if we are not restricted to specific monitors
+# FIXME This is actually a race condition. Should lock the table.
+ $maxSeq = dbFetchOne( 'SELECT max(Sequence) AS MaxSequence FROM Monitors', 'MaxSequence' );
+ $changes[] = 'Sequence = '.($maxSeq+1);
+
+ dbQuery( 'INSERT INTO Monitors SET '.implode( ', ', $changes ) );
+ $mid = dbInsertId();
+ $zoneArea = $_REQUEST['newMonitor']['Width'] * $_REQUEST['newMonitor']['Height'];
+ dbQuery( "insert into Zones set MonitorId = ?, Name = 'All', Type = 'Active', Units = 'Percent', NumCoords = 4, Coords = ?, Area=?, AlarmRGB = 0xff0000, CheckMethod = 'Blobs', MinPixelThreshold = 25, MinAlarmPixels=?, MaxAlarmPixels=?, FilterX = 3, FilterY = 3, MinFilterPixels=?, MaxFilterPixels=?, MinBlobPixels=?, MinBlobs = 1", array( $mid, sprintf( "%d,%d %d,%d %d,%d %d,%d", 0, 0, $_REQUEST['newMonitor']['Width']-1, 0, $_REQUEST['newMonitor']['Width']-1, $_REQUEST['newMonitor']['Height']-1, 0, $_REQUEST['newMonitor']['Height']-1 ), $zoneArea, intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*3)/100), intval(($zoneArea*75)/100), intval(($zoneArea*2)/100) ) );
+ //$view = 'none';
+ mkdir( ZM_DIR_EVENTS.'/'.$mid, 0755 );
+ $saferName = basename($_REQUEST['newMonitor']['Name']);
+ symlink( $mid, ZM_DIR_EVENTS.'/'.$saferName );
+ if ( isset($_COOKIE['zmGroup']) ) {
+ dbQuery( "UPDATE Groups SET MonitorIds = concat(MonitorIds,',".$mid."') WHERE Id=?", array($_COOKIE['zmGroup']) );
+ }
+ } else {
+ Error("Users with Monitors restrictions cannot create new monitors.");
+ }
+ $restart = true;
+ } # end if count(changes)
+
+ if ( ZM_OPT_X10 ) {
+ $x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] );
+
+ if ( count( $x10Changes ) ) {
+ if ( $x10Monitor && isset($_REQUEST['newX10Monitor']) ) {
+ dbQuery( "update TriggersX10 set ".implode( ", ", $x10Changes )." where MonitorId=?", array($mid) );
+ } elseif ( !$user['MonitorIds'] ) {
+ if ( !$x10Monitor ) {
+ dbQuery( "insert into TriggersX10 set MonitorId = ?, ".implode( ", ", $x10Changes ), array( $mid ) );
+ } else {
+ dbQuery( "delete from TriggersX10 where MonitorId = ?", array($mid) );
+ }
+ }
+ $restart = true;
+ }
+ }
+
+ if ( $restart ) {
+ $new_monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id = ?', NULL, array($mid) );
+ //fixDevices();
+ //if ( $cookies )
+ //session_write_close();
+
+ zmcControl( $new_monitor, 'start' );
+ zmaControl( $new_monitor, 'start' );
+
+ if ( $new_monitor['Controllable'] ) {
+ require_once( 'control_functions.php' );
+ sendControlCommand( $mid, 'quit' );
+ }
+ // really should thump zmwatch and maybe zmtrigger too.
+ //daemonControl( 'restart', 'zmwatch.pl' );
+ $refreshParent = true;
+ } // end if restart
+ $view = 'none';
+ } elseif ( $action == 'delete' ) {
+ if ( isset($_REQUEST['markMids']) && !$user['MonitorIds'] ) {
+ foreach( $_REQUEST['markMids'] as $markMid ) {
+ if ( canEdit( 'Monitors', $markMid ) ) {
+ if ( $monitor = dbFetchOne( 'SELECT * FROM Monitors WHERE Id = ?', NULL, array($markMid) ) ) {
+ if ( daemonCheck() ) {
+ zmaControl( $monitor, 'stop' );
+ zmcControl( $monitor, 'stop' );
+ }
+
+ // If fast deletes are on, then zmaudit will clean everything else up later
+ // If fast deletes are off and there are lots of events then this step may
+ // well time out before completing, in which case zmaudit will still tidy up
+ if ( !ZM_OPT_FAST_DELETE ) {
+ $markEids = dbFetchAll( 'SELECT Id FROM Events WHERE MonitorId=?', 'Id', array($markMid) );
+ foreach( $markEids as $markEid )
+ deleteEvent( $markEid );
+
+ deletePath( ZM_DIR_EVENTS.'/'.basename($monitor['Name']) );
+ deletePath( ZM_DIR_EVENTS.'/'.$monitor['Id'] ); // I'm trusting the Id.
+ } // end if ZM_OPT_FAST_DELETE
+
+ // This is the important stuff
+ dbQuery( 'DELETE FROM Monitors WHERE Id = ?', array($markMid) );
+ dbQuery( 'DELETE FROM Zones WHERE MonitorId = ?', array($markMid) );
+ if ( ZM_OPT_X10 )
+ dbQuery( 'DELETE FROM TriggersX10 WHERE MonitorId=?', array($markMid) );
+
+ fixSequences();
+
+ } // end if found the monitor in the db
+ } // end if canedit this monitor
+ } // end foreach monitor in MarkMid
+ } // markMids is set and we aren't limited to specific monitors
+ } // end if action == Delete
+}
+
+// Device view actions
+if ( canEdit( 'Devices' ) ) {
+ if ( $action == 'device' ) {
+ if ( !empty($_REQUEST['command']) ) {
+ setDeviceStatusX10( $_REQUEST['key'], $_REQUEST['command'] );
+ } elseif ( isset( $_REQUEST['newDevice'] ) ) {
+ if ( isset($_REQUEST['did']) ) {
+ dbQuery( "update Devices set Name=?, KeyString=? where Id=?", array($_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'], $_REQUEST['did']) );
+ } else {
+ dbQuery( "insert into Devices set Name=?, KeyString=?", array( $_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'] ) );
+ }
+ $refreshParent = true;
+ $view = 'none';
+ }
+ } elseif ( $action == 'delete' ) {
+ if ( isset($_REQUEST['markDids']) ) {
+ foreach( $_REQUEST['markDids'] as $markDid ) {
+ dbQuery( "delete from Devices where Id=?", array($markDid) );
+ $refreshParent = true;
+ }
+ }
+ } // end if action
+} // end if canedit devices
+
+// Group view actions
+if ( canView( 'Groups' ) && $action == 'setgroup' ) {
+ if ( !empty($_REQUEST['gid']) ) {
+ setcookie( 'zmGroup', validInt($_REQUEST['gid']), time()+3600*24*30*12*10 );
+ } else {
+ setcookie( 'zmGroup', '', time()-3600*24*2 );
+ }
+ $refreshParent = true;
+}
+
+// Group edit actions
+# Should probably verify that each monitor id is a valid monitor, that we have access to. However at the moment, you have to have System permissions to do this
+if ( canEdit( 'Groups' ) ) {
+ if ( $action == 'group' ) {
+ $monitors = empty( $_POST['newGroup']['MonitorIds'] ) ? '' : implode(',', $_POST['newGroup']['MonitorIds']);
+ if ( !empty($_POST['gid']) ) {
+ dbQuery( 'UPDATE Groups SET Name=?, ParentId=?, MonitorIds=? WHERE Id=?',
+ array($_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors, $_POST['gid']) );
+ } else {
+ dbQuery( 'INSERT INTO Groups SET Name=?, ParentId=?, MonitorIds=?',
+ array( $_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors ) );
+ }
+ $view = 'none';
+ $refreshParent = true;
+ } else if ( $action == 'delete' ) {
+ if ( !empty($_REQUEST['gid']) ) {
+ if ( is_array( $_REQUEST['gid'] ) ) {
+ foreach( $_REQUEST['gid'] as $gid ) {
+ $Group = new Group( $gid );
+ $Group->delete();
+ }
+ } else {
+ $Group = new Group( $_REQUEST['gid'] );
+ $Group->delete();
+ }
+ }
+ $refreshParent = true;
+ } # end if action
+} // end if can edit groups
+
+// System edit actions
+if ( canEdit( 'System' ) ) {
+ if ( isset( $_REQUEST['object'] ) ) {
+ if ( $_REQUEST['object'] == 'MontageLayout' ) {
+ require_once('MontageLayout.php');
+ if ( $action == 'Save' ) {
+ $Layout = null;
+ if ( $_REQUEST['Name'] != '' ) {
+ $Layout = new MontageLayout();
+ $Layout->Name( $_REQUEST['Name'] );
+ } else {
+ $Layout = new MontageLayout( $_REQUEST['zmMontageLayout'] );
+ }
+ $Layout->Positions( $_REQUEST['Positions'] );
+ $Layout->save();
+ session_start();
+ $_SESSION['zmMontageLayout'] = $Layout->Id();
+ setcookie('zmMontageLayout', $Layout->Id(), 1 );
+ session_write_close();
+ $redirect = true;
+ } // end if save
+
+ } else if ( $_REQUEST['object'] == 'server' ) {
+
+ if ( $action == 'Save' ) {
+ if ( !empty($_REQUEST['id']) )
+ $dbServer = dbFetchOne( 'SELECT * FROM Servers WHERE Id=?', NULL, array($_REQUEST['id']) );
+ else
+ $dbServer = array();
+
+ $types = array();
+ $changes = getFormChanges( $dbServer, $_REQUEST['newServer'], $types );
+
+ if ( count( $changes ) ) {
+ if ( !empty($_REQUEST['id']) ) {
+ dbQuery( "UPDATE Servers SET ".implode( ", ", $changes )." WHERE Id = ?", array($_REQUEST['id']) );
+ } else {
+ dbQuery( "INSERT INTO Servers set ".implode( ", ", $changes ) );
+ }
+ $refreshParent = true;
+ }
+ $view = 'none';
+ } else if ( $action == 'delete' ) {
+ if ( !empty($_REQUEST['markIds']) ) {
+ foreach( $_REQUEST['markIds'] as $Id )
+ dbQuery( "DELETE FROM Servers WHERE Id=?", array($Id) );
+ }
+ $refreshParent = true;
+ } else {
+ Error( "Unknown action $action in saving Server" );
+ }
+ } else if ( $_REQUEST['object'] == 'storage' ) {
+ if ( $action == 'Save' ) {
+ if ( !empty($_REQUEST['id']) )
+ $dbStorage = dbFetchOne( 'SELECT * FROM Storage WHERE Id=?', NULL, array($_REQUEST['id']) );
+ else
+ $dbStorage = array();
+
+ $types = array();
+ $changes = getFormChanges( $dbStorage, $_REQUEST['newStorage'], $types );
+
+ if ( count( $changes ) ) {
+ if ( !empty($_REQUEST['id']) ) {
+ dbQuery( "UPDATE Storage SET ".implode( ", ", $changes )." WHERE Id = ?", array($_REQUEST['id']) );
+ } else {
+ dbQuery( "INSERT INTO Storage set ".implode( ", ", $changes ) );
+ }
+ $refreshParent = true;
+ }
+ $view = 'none';
+ } else if ( $action == 'delete' ) {
+ if ( !empty($_REQUEST['markIds']) ) {
+ foreach( $_REQUEST['markIds'] as $Id )
+ dbQuery( 'DELETE FROM Storage WHERE Id=?', array($Id) );
+ }
+ $refreshParent = true;
+ } else {
+ Error( "Unknown action $action in saving Storage" );
+ }
+ } # end if isset($_REQUEST['object'] )
+
+ } else if ( $action == 'version' && isset($_REQUEST['option']) ) {
+ $option = $_REQUEST['option'];
+ switch( $option ) {
+ case 'go' :
+ {
+ // Ignore this, the caller will open the page itself
+ break;
+ }
+ case 'ignore' :
+ {
+ dbQuery( "update Config set Value = '".ZM_DYN_LAST_VERSION."' where Name = 'ZM_DYN_CURR_VERSION'" );
+ break;
+ }
+ case 'hour' :
+ case 'day' :
+ case 'week' :
+ {
+ $nextReminder = time();
+ if ( $option == 'hour' ) {
+ $nextReminder += 60*60;
+ } elseif ( $option == 'day' ) {
+ $nextReminder += 24*60*60;
+ } elseif ( $option == 'week' ) {
+ $nextReminder += 7*24*60*60;
+ }
+ dbQuery( "update Config set Value = '".$nextReminder."' where Name = 'ZM_DYN_NEXT_REMINDER'" );
+ break;
+ }
+ case 'never' :
+ {
+ dbQuery( "update Config set Value = '0' where Name = 'ZM_CHECK_FOR_UPDATES'" );
+ break;
+ }
+ }
+ }
+ if ( $action == 'donate' && isset($_REQUEST['option']) ) {
+ $option = $_REQUEST['option'];
+ switch( $option ) {
+ case 'go' :
+ {
+ // Ignore this, the caller will open the page itself
+ break;
+ }
+ case 'hour' :
+ case 'day' :
+ case 'week' :
+ case 'month' :
+ {
+ $nextReminder = time();
+ if ( $option == 'hour' ) {
+ $nextReminder += 60*60;
+ } elseif ( $option == 'day' ) {
+ $nextReminder += 24*60*60;
+ } elseif ( $option == 'week' ) {
+ $nextReminder += 7*24*60*60;
+ } elseif ( $option == 'month' ) {
+ $nextReminder += 30*24*60*60;
+ }
+ dbQuery( "update Config set Value = '".$nextReminder."' where Name = 'ZM_DYN_DONATE_REMINDER_TIME'" );
+ break;
+ }
+ case 'never' :
+ case 'already' :
+ {
+ dbQuery( "update Config set Value = '0' where Name = 'ZM_DYN_SHOW_DONATE_REMINDER'" );
+ break;
+ }
+ } // end switch option
+ }
+ if ( $action == 'options' && isset($_REQUEST['tab']) ) {
+ $configCat = $configCats[$_REQUEST['tab']];
+ $changed = false;
+ foreach ( $configCat as $name=>$value ) {
+ unset( $newValue );
+ if ( $value['Type'] == 'boolean' && empty($_REQUEST['newConfig'][$name]) )
+ $newValue = 0;
+ elseif ( isset($_REQUEST['newConfig'][$name]) )
+ $newValue = preg_replace( "/\r\n/", "\n", stripslashes( $_REQUEST['newConfig'][$name] ) );
+
+ if ( isset($newValue) && ($newValue != $value['Value']) ) {
+ dbQuery( 'UPDATE Config SET Value=? WHERE Name=?', array( $newValue, $name ) );
+ $changed = true;
+ }
+ }
+ if ( $changed ) {
+ switch( $_REQUEST['tab'] ) {
+ case 'system' :
+ case 'config' :
+ $restartWarning = true;
+ break;
+ case 'web' :
+ case 'tools' :
+ break;
+ case 'logging' :
+ case 'network' :
+ case 'mail' :
+ case 'upload' :
+ $restartWarning = true;
+ break;
+ case 'highband' :
+ case 'medband' :
+ case 'lowband' :
+ break;
+ }
+ }
+ loadConfig( false );
+ } elseif ( $action == 'user' ) {
+ if ( !empty($_REQUEST['uid']) )
+ $dbUser = dbFetchOne( "SELECT * FROM Users WHERE Id=?", NULL, array($_REQUEST['uid']) );
+ else
+ $dbUser = array();
+
+ $types = array();
+ $changes = getFormChanges( $dbUser, $_REQUEST['newUser'], $types );
+
+ if ( $_REQUEST['newUser']['Password'] )
+ $changes['Password'] = "Password = password(".dbEscape($_REQUEST['newUser']['Password']).")";
+ else
+ unset( $changes['Password'] );
+
+ if ( count( $changes ) ) {
+ if ( !empty($_REQUEST['uid']) ) {
+ dbQuery( "update Users set ".implode( ", ", $changes )." where Id = ?", array($_REQUEST['uid']) );
+ # If we are updating the logged in user, then update our session user data.
+ if ( $user and ( $dbUser['Username'] == $user['Username'] ) )
+ userLogin( $dbUser['Username'], $dbUser['Password'] );
+ } else {
+ dbQuery( "insert into Users set ".implode( ", ", $changes ) );
+ }
+ $refreshParent = true;
+ }
+ $view = 'none';
+ } elseif ( $action == 'state' ) {
+ if ( !empty($_REQUEST['runState']) ) {
+ //if ( $cookies ) session_write_close();
+ packageControl( $_REQUEST['runState'] );
+ $refreshParent = true;
+ }
+ } elseif ( $action == 'save' ) {
+ if ( !empty($_REQUEST['runState']) || !empty($_REQUEST['newState']) ) {
+ $sql = 'SELECT Id,Function,Enabled FROM Monitors ORDER BY Id';
+ $definitions = array();
+ foreach( dbFetchAll( $sql ) as $monitor )
+ {
+ $definitions[] = $monitor['Id'].":".$monitor['Function'].":".$monitor['Enabled'];
+ }
+ $definition = join( ',', $definitions );
+ if ( $_REQUEST['newState'] )
+ $_REQUEST['runState'] = $_REQUEST['newState'];
+ dbQuery( "replace into States set Name=?, Definition=?", array( $_REQUEST['runState'],$definition) );
+ }
+ } elseif ( $action == 'delete' ) {
+ if ( isset($_REQUEST['runState']) )
+ dbQuery( "delete from States where Name=?", array($_REQUEST['runState']) );
+
+ if ( isset($_REQUEST['markUids']) ) {
+ foreach( $_REQUEST['markUids'] as $markUid )
+ dbQuery( "delete from Users where Id = ?", array($markUid) );
+ if ( $markUid == $user['Id'] )
+ userLogout();
+ }
+ }
+} else {
+ if ( ZM_USER_SELF_EDIT && $action == 'user' ) {
+ $uid = $user['Id'];
+
+ $dbUser = dbFetchOne( 'SELECT Id, Password, Language FROM Users WHERE Id = ?', NULL, array($uid) );
+
+ $types = array();
+ $changes = getFormChanges( $dbUser, $_REQUEST['newUser'], $types );
+
+ if ( !empty($_REQUEST['newUser']['Password']) )
+ $changes['Password'] = "Password = password(".dbEscape($_REQUEST['newUser']['Password']).")";
+ else
+ unset( $changes['Password'] );
+ if ( count( $changes ) ) {
+ dbQuery( "update Users set ".implode( ", ", $changes )." where Id=?", array($uid) );
+ $refreshParent = true;
+ }
+ $view = 'none';
+ }
+}
+
+if ( $action == 'reset' ) {
+ $_SESSION['zmEventResetTime'] = strftime( STRF_FMT_DATETIME_DB );
+ setcookie( 'zmEventResetTime', $_SESSION['zmEventResetTime'], time()+3600*24*30*12*10 );
+ //if ( $cookies ) session_write_close();
+}
+
?>
diff --git a/web/includes/database.php b/web/includes/database.php
index 483df64a5..227de8132 100644
--- a/web/includes/database.php
+++ b/web/includes/database.php
@@ -122,17 +122,26 @@ function dbQuery( $sql, $params=NULL ) {
$result = NULL;
try {
if ( isset($params) ) {
- $result = $dbConn->prepare( $sql );
- $result->execute( $params );
+ if ( ! $result = $dbConn->prepare( $sql ) ) {
+ Error("SQL: Error preparing $sql: " . $pdo->errorInfo);
+ return NULL;
+ }
+
+ if ( ! $result->execute( $params ) ) {
+ Error("SQL: Error executing $sql: " . implode(',', $result->errorInfo() ) );
+ return NULL;
+ }
} else {
$result = $dbConn->query( $sql );
}
+if ( 0 ) {
if ( $params )
- Warning("SQL: $sql" . implode(',',$params));
+ Warning("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() );
else
- Warning("SQL: $sql" );
+ Warning("SQL: $sql: rows:" . $result->rowCount() );
+}
} catch(PDOException $e) {
- Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . implode(',',$params) );
+ Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . ($params?implode(',',$params):'') );
}
return( $result );
}
diff --git a/web/includes/functions.php b/web/includes/functions.php
index ab0e1c898..2d0b9c681 100644
--- a/web/includes/functions.php
+++ b/web/includes/functions.php
@@ -339,11 +339,11 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
}
function outputImageStream( $id, $src, $width, $height, $title='' ) {
- echo getImageStream( $id, $src, $width, $height, $title );
+ echo getImageStreamHTML( $id, $src, $width, $height, $title );
}
-function getImageStream( $id, $src, $width, $height, $title='' ) {
+function getImageStreamHTML( $id, $src, $width, $height, $title='' ) {
if ( canStreamIframe() ) {
return '';
} else {
@@ -1058,6 +1058,7 @@ function parseSort( $saveToSession=false, $querySep='&' ) {
break;
case 'DateTime' :
$sortColumn = 'E.StartTime';
+ $_REQUEST['sort_field'] = 'StartTime';
break;
case 'DiskSpace' :
$sortColumn = 'E.DiskSpace';
@@ -1238,12 +1239,18 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
$value = dbEscape($value);
break;
case 'DateTime':
+ case 'StartDateTime':
+ case 'EndDateTime':
$value = "'".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."'";
break;
case 'Date':
+ case 'StartDate':
+ case 'EndDate':
$value = "to_days( '".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."' )";
break;
case 'Time':
+ case 'StartTime':
+ case 'EndTime':
$value = "extract( hour_second from '".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."' )";
break;
default :
@@ -1274,13 +1281,21 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
case '![]' :
$filter['sql'] .= ' not in ('.join( ',', $valueList ).')';
break;
+ case 'IS' :
+ $filter['sql'] .= " IS $value";
+ break;
+ case 'IS NOT' :
+ $filter['sql'] .= " IS NOT $value";
+ break;
+ default:
+ Warning("Invalid operator in filter: " . $terms[$i]['op'] );
}
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']);
$filter['fields'] .= "\n";
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][val]").'='.urlencode($terms[$i]['val']);
$filter['fields'] .= "\n";
- }
+ } // end foreach term
if ( isset($terms[$i]['cbr']) ) {
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][cbr]").'='.urlencode($terms[$i]['cbr']);
$filter['sql'] .= ' '.str_repeat( ')', $terms[$i]['cbr'] ).' ';
@@ -1295,13 +1310,14 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
}
}
+// Please note that the filter is passed in by copy, so you need to use the return value from this function.
+//
function addFilterTerm( $filter, $position, $term=false ) {
if ( $position < 0 )
$position = 0;
if ( ! isset( $filter['Query']['terms'] ) )
$filter['Query']['terms'] = array();
-
elseif( $position > count($filter['Query']['terms']) )
$position = count($filter['Query']['terms']);
if ( $term && $position == 0 )
@@ -2056,6 +2072,19 @@ function detaintPath( $path ) {
return( $path );
}
+function cache_bust( $file ) {
+ # Use the last modified timestamp to create a link that gets a different filename
+ # To defeat caching. Should probably use md5 hash
+ $parts = pathinfo($file);
+ $cacheFile = 'cache/'.$parts['filename'].'-'.filemtime($file).'.'.$parts['extension'];
+ if ( file_exists( ZM_PATH_WEB.'/'.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_PATH_WEB.'/'.$cacheFile ) ) {
+ return $cacheFile;
+ } else {
+ Warning("Failed linking $file to $cacheFile");
+ }
+ return $file;
+}
+
function getSkinFile( $file ) {
global $skinBase;
$skinFile = false;
@@ -2064,7 +2093,7 @@ function getSkinFile( $file ) {
if ( file_exists( $tempSkinFile ) )
$skinFile = $tempSkinFile;
}
- return( $skinFile );
+ return $skinFile;
}
function getSkinIncludes( $file, $includeBase=false, $asOverride=false ) {
@@ -2121,18 +2150,17 @@ function validHtmlStr( $input ) {
function getStreamHTML( $monitor, $options = array() ) {
if ( isset($options['scale']) and $options['scale'] and ( $options['scale'] != 100 ) ) {
+ //Warning("Scale to " . $options['scale'] );
$options['width'] = reScale( $monitor->Width(), $options['scale'] );
$options['height'] = reScale( $monitor->Height(), $options['scale'] );
} else {
- if ( ! isset( $options['width'] ) ) {
- $options['width'] = NULL;
- } else if ( $options['width'] == 100 ) {
+ # scale is empty or 100
+ # There may be a fixed width applied though, in which case we need to leave the height empty
+ if ( ! ( isset($options['width']) and $options['width'] ) ) {
$options['width'] = $monitor->Width();
- }
- if ( ! isset( $options['height'] ) ) {
- $options['height'] = NULL;
- } else if ( $options['height'] == 100 ) {
- $options['height'] = $monitor->Height();
+ if ( ! ( isset($options['height']) and $options['height'] ) ) {
+ $options['height'] = $monitor->Height();
+ }
}
}
if ( ! isset($options['mode'] ) ) {
@@ -2141,17 +2169,24 @@ function getStreamHTML( $monitor, $options = array() ) {
$options['maxfps'] = ZM_WEB_VIDEO_MAXFPS;
if ( $monitor->StreamReplayBuffer() )
$options['buffer'] = $monitor->StreamReplayBuffer();
+ //Warning("width: " . $options['width'] . ' height: ' . $options['height']. ' scale: ' . $options['scale'] );
//FIXME, the width and height of the image need to be scaled.
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
- $streamSrc = $monitor->getStreamSrc( array( 'mode'=>'mpeg', 'scale'=>$options['scale'], 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format' => ZM_MPEG_LIVE_FORMAT ) );
- return getVideoStream( 'liveStream'.$monitor->Id(), $streamSrc, $options, ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
+ $streamSrc = $monitor->getStreamSrc( array(
+ 'mode'=>'mpeg',
+ 'scale'=>$options['scale'],
+ 'bitrate'=>ZM_WEB_VIDEO_BITRATE,
+ 'maxfps'=>ZM_WEB_VIDEO_MAXFPS,
+ 'format' => ZM_MPEG_LIVE_FORMAT
+ ) );
+ return getVideoStreamHTML( 'liveStream'.$monitor->Id(), $streamSrc, $options['width'], $options['height'], ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
} else if ( $options['mode'] == 'stream' and canStream() ) {
$options['mode'] = 'jpeg';
$streamSrc = $monitor->getStreamSrc( $options );
if ( canStreamNative() )
- return getImageStream( 'liveStream'.$monitor->Id(), $streamSrc, $options['width'], $options['height'], $monitor->Name());
+ return getImageStreamHTML( 'liveStream'.$monitor->Id(), $streamSrc, $options['width'], $options['height'], $monitor->Name());
elseif ( canStreamApplet() )
// Helper, empty widths and heights really don't work.
return getHelperStream( 'liveStream'.$monitor->Id(), $streamSrc,
diff --git a/web/includes/logger.php b/web/includes/logger.php
index b10749f10..f9bc214f6 100644
--- a/web/includes/logger.php
+++ b/web/includes/logger.php
@@ -2,586 +2,505 @@
require_once( 'config.php' );
-class Logger
-{
- private static $instance;
+class Logger {
+ private static $instance;
- const DEBUG = 1;
- const INFO = 0;
- const WARNING = -1;
- const ERROR = -2;
- const FATAL = -3;
- const PANIC = -4;
- const NOLOG = -5; // Special artificial level to prevent logging
+ const DEBUG = 1;
+ const INFO = 0;
+ const WARNING = -1;
+ const ERROR = -2;
+ const FATAL = -3;
+ const PANIC = -4;
+ const NOLOG = -5; // Special artificial level to prevent logging
- private $initialised = false;
+ private $initialised = false;
- private $id = "web";
- private $idRoot = "web";
- private $idArgs = "";
- private $useErrorLog = true;
+ private $id = "web";
+ private $idRoot = "web";
+ private $idArgs = "";
+ private $useErrorLog = true;
- private $level = self::INFO;
- private $termLevel = self::NOLOG;
- private $databaseLevel = self::NOLOG;
- private $fileLevel = self::NOLOG;
- private $weblogLevel = self::NOLOG;
- private $syslogLevel = self::NOLOG;
- private $effectiveLevel = self::NOLOG;
+ private $level = self::INFO;
+ private $termLevel = self::NOLOG;
+ private $databaseLevel = self::NOLOG;
+ private $fileLevel = self::NOLOG;
+ private $weblogLevel = self::NOLOG;
+ private $syslogLevel = self::NOLOG;
+ private $effectiveLevel = self::NOLOG;
- private $hasTerm = false;
+ private $hasTerm = false;
- private $logPath = ZM_PATH_LOGS;
- private $logFile = "";
- private $logFd = NULL;
+ private $logPath = ZM_PATH_LOGS;
+ private $logFile = "";
+ private $logFd = NULL;
- public static $codes = array(
- self::DEBUG => "DBG",
- self::INFO => "INF",
- self::WARNING => "WAR",
- self::ERROR => "ERR",
- self::FATAL => "FAT",
- self::PANIC => "PNC",
- self::NOLOG => "OFF",
- );
- private static $syslogPriorities = array(
- self::DEBUG => LOG_DEBUG,
- self::INFO => LOG_INFO,
- self::WARNING => LOG_WARNING,
- self::ERROR => LOG_ERR,
- self::FATAL => LOG_ERR,
- self::PANIC => LOG_ERR,
- );
- private static $phpErrorLevels = array(
- self::DEBUG => E_USER_NOTICE,
- self::INFO => E_USER_NOTICE,
- self::WARNING => E_USER_WARNING,
- self::ERROR => E_USER_WARNING,
- self::FATAL => E_USER_ERROR,
- self::PANIC => E_USER_ERROR,
- );
+ public static $codes = array(
+ self::DEBUG => "DBG",
+ self::INFO => "INF",
+ self::WARNING => "WAR",
+ self::ERROR => "ERR",
+ self::FATAL => "FAT",
+ self::PANIC => "PNC",
+ self::NOLOG => "OFF",
+ );
+ private static $syslogPriorities = array(
+ self::DEBUG => LOG_DEBUG,
+ self::INFO => LOG_INFO,
+ self::WARNING => LOG_WARNING,
+ self::ERROR => LOG_ERR,
+ self::FATAL => LOG_ERR,
+ self::PANIC => LOG_ERR,
+ );
+ private static $phpErrorLevels = array(
+ self::DEBUG => E_USER_NOTICE,
+ self::INFO => E_USER_NOTICE,
+ self::WARNING => E_USER_WARNING,
+ self::ERROR => E_USER_WARNING,
+ self::FATAL => E_USER_ERROR,
+ self::PANIC => E_USER_ERROR,
+ );
- private function __construct()
- {
- $this->hasTerm = (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']));
- $this->logFile = $this->logPath."/".$this->id.".log";
+ private function __construct() {
+ $this->hasTerm = (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']));
+ $this->logFile = $this->logPath."/".$this->id.".log";
+ }
+
+ public function __destruct() {
+ $this->terminate();
+ }
+
+ public function initialise( $options=array() ) {
+ if ( !empty($options['id']) )
+ $this->id = $options['id'];
+
+ //if ( isset($options['useErrorLog']) )
+ //$this->useErrorLog = $options['useErrorLog'];
+ if ( isset($options['logPath']) ) {
+ $this->logPath = $options['logPath'];
+ $tempLogFile = $this->logPath."/".$this->id.".log";
}
+ if ( isset($options['logFile']) )
+ $tempLogFile = $options['logFile'];
+ else
+ $tempLogFile = $this->logPath."/".$this->id.".log";
+ if ( !is_null($logFile = $this->getTargettedEnv('LOG_FILE')) )
+ $tempLogFile = $logFile;
- public function __destruct()
- {
- $this->terminate();
- }
+ $tempLevel = self::INFO;
+ $tempTermLevel = $this->termLevel;
+ $tempDatabaseLevel = $this->databaseLevel;
+ $tempFileLevel = $this->fileLevel;
+ $tempSyslogLevel = $this->syslogLevel;
+ $tempWeblogLevel = $this->weblogLevel;
- public function initialise( $options=array() )
- {
- if ( !empty($options['id']) )
- $this->id = $options['id'];
+ if ( isset($options['termLevel']) )
+ $tempTermLevel = $options['termLevel'];
+ if ( isset($options['databaseLevel']) )
+ $tempDatabaseLevel = $options['databaseLevel'];
+ else
+ $tempDatabaseLevel = ZM_LOG_LEVEL_DATABASE;
+ if ( isset($options['fileLevel']) )
+ $tempFileLevel = $options['fileLevel'];
+ else
+ $tempFileLevel = ZM_LOG_LEVEL_FILE;
+ if ( isset($options['weblogLevel']) )
+ $tempWeblogLevel = $options['weblogLevel'];
+ else
+ $tempWeblogLevel = ZM_LOG_LEVEL_WEBLOG;
+ if ( isset($options['syslogLevel']) )
+ $tempSyslogLevel = $options['syslogLevel'];
+ else
+ $tempSyslogLevel = ZM_LOG_LEVEL_SYSLOG;
- //if ( isset($options['useErrorLog']) )
- //$this->useErrorLog = $options['useErrorLog'];
- if ( isset($options['logPath']) )
- {
- $this->logPath = $options['logPath'];
- $tempLogFile = $this->logPath."/".$this->id.".log";
+ if ( $value = getenv('LOG_PRINT') )
+ $tempTermLevel = $value ? self::DEBUG : self::NOLOG;
+
+ if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL')) )
+ $tempLevel = $level;
+
+ if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_TERM')) )
+ $tempTermLevel = $level;
+ if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_DATABASE')) )
+ $tempDatabaseLevel = $level;
+ if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_FILE')) )
+ $tempFileLevel = $level;
+ if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_SYSLOG')) )
+ $tempSyslogLevel = $level;
+ if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_WEBLOG')) )
+ $tempWeblogLevel = $level;
+
+ if ( ZM_LOG_DEBUG ) {
+ foreach ( explode( '|', ZM_LOG_DEBUG_TARGET ) as $target ) {
+ if ( $target == $this->id || $target == '_'.$this->id || $target == $this->idRoot || $target == '_'.$this->idRoot || $target == '' ) {
+ if ( ZM_LOG_DEBUG_LEVEL > self::NOLOG ) {
+ $tempLevel = $this->limit( ZM_LOG_DEBUG_LEVEL );
+ if ( ZM_LOG_DEBUG_FILE != '' ) {
+ $tempLogFile = ZM_LOG_DEBUG_FILE;
+ $tempFileLevel = $tempLevel;
+ }
+ }
}
- if ( isset($options['logFile']) )
- $tempLogFile = $options['logFile'];
+ } // end foreach target
+ } // end if DEBUG
+
+ $this->logFile( $tempLogFile );
+ $this->termLevel( $tempTermLevel );
+ $this->databaseLevel( $tempDatabaseLevel );
+ $this->fileLevel( $tempFileLevel );
+ $this->syslogLevel( $tempSyslogLevel );
+ $this->weblogLevel( $tempWeblogLevel );
+
+ $this->level( $tempLevel );
+
+ $this->initialised = true;
+
+ Logger::Debug( "LogOpts: level=".self::$codes[$this->level]."/".self::$codes[$this->effectiveLevel].", screen=".self::$codes[$this->termLevel].", database=".self::$codes[$this->databaseLevel].", logfile=".self::$codes[$this->fileLevel]."->".$this->logFile.", weblog=".self::$codes[$this->weblogLevel].", syslog=".self::$codes[$this->syslogLevel] );
+ }
+
+ private function terminate() {
+ if ( $this->initialised ) {
+ if ( $this->fileLevel > self::NOLOG )
+ $this->closeFile();
+ if ( $this->syslogLevel > self::NOLOG )
+ $this->closeSyslog();
+ }
+ $this->initialised = false;
+ }
+
+ private function limit( $level ) {
+ if ( $level > self::DEBUG )
+ return( self::DEBUG );
+ if ( $level < self::NOLOG )
+ return( self::NOLOG );
+ return( $level );
+ }
+
+ private function getTargettedEnv( $name ) {
+ $envName = $name."_".$this->id;
+ $value = getenv( $envName );
+ if ( $value === false && $this->id != $this->idRoot )
+ $value = getenv( $name."_".$this->idRoot );
+ if ( $value === false )
+ $value = getenv( $name );
+ return( $value !== false ? $value : NULL );
+ }
+
+ public static function fetch( $initialise=true ) {
+ if ( !isset(self::$instance) ) {
+ $class = __CLASS__;
+ self::$instance = new $class;
+ if ( $initialise )
+ self::$instance->initialise( array( 'id'=>'web_php', 'syslogLevel'=>self::INFO, 'weblogLevel'=>self::INFO ) );
+ }
+ return self::$instance;
+ }
+
+ public static function Debug( $string ) {
+ Logger::fetch()->logPrint( Logger::DEBUG, $string );
+ }
+
+ public function id( $id=NULL ) {
+ if ( isset($id) && $this->id != $id ) {
+ // Remove whitespace
+ $id = preg_replace( '/\S/', '', $id );
+ // Replace non-alphanum with underscore
+ $id = preg_replace( '/[^a-zA-Z_]/', '_', $id );
+
+ if ( $this->id != $id ) {
+ $this->id = $this->idRoot = $id;
+ if ( preg_match( '/^([^_]+)_(.+)$/', $id, $matches ) ) {
+ $this->idRoot = $matches[1];
+ $this->idArgs = $matches[2];
+ }
+ }
+ }
+ return( $this->id );
+ }
+
+ public function level( $level ) {
+ if ( isset($level) ) {
+ $lastLevel = $this->level;
+ $this->level = $this->limit($level);
+ $this->effectiveLevel = self::NOLOG;
+ if ( $this->termLevel > $this->effectiveLevel )
+ $this->effectiveLevel = $this->termLevel;
+ if ( $this->databaseLevel > $this->effectiveLevel )
+ $this->effectiveLevel = $this->databaseLevel;
+ if ( $this->fileLevel > $this->effectiveLevel )
+ $this->effectiveLevel = $this->fileLevel;
+ if ( $this->weblogLevel > $this->effectiveLevel )
+ $this->effectiveLevel = $this->weblogLevel;
+ if ( $this->syslogLevel > $this->effectiveLevel )
+ $this->effectiveLevel = $this->syslogLevel;
+ if ( $this->effectiveLevel > $this->level )
+ $this->effectiveLevel = $this->level;
+ if ( !$this->hasTerm ) {
+ if ( $lastLevel < self::DEBUG && $this->level >= self::DEBUG ) {
+ $this->savedErrorReporting = error_reporting( E_ALL );
+ $this->savedDisplayErrors = ini_set( 'display_errors', true );
+ } elseif ( $lastLevel >= self::DEBUG && $this->level < self::DEBUG ) {
+ error_reporting( $this->savedErrorReporting );
+ ini_set( 'display_errors', $this->savedDisplayErrors );
+ }
+ }
+ }
+ return( $this->level );
+ }
+
+ public function debugOn() {
+ return( $this->effectiveLevel >= self::DEBUG );
+ }
+
+ public function termLevel( $termLevel ) {
+ if ( isset($termLevel) ) {
+ $termLevel = $this->limit($termLevel);
+ if ( $this->termLevel != $termLevel )
+ $this->termLevel = $termLevel;
+ }
+ return( $this->termLevel );
+ }
+
+ public function databaseLevel( $databaseLevel=NULL ) {
+ if ( !is_null($databaseLevel) ) {
+ $databaseLevel = $this->limit($databaseLevel);
+ if ( $this->databaseLevel != $databaseLevel ) {
+ $this->databaseLevel = $databaseLevel;
+ if ( $this->databaseLevel > self::NOLOG ) {
+ if ( (include_once 'database.php') === FALSE ) {
+ $this->databaseLevel = self::NOLOG;
+ Warning( "Unable to write log entries to DB, database.php not found" );
+ }
+ }
+ }
+ }
+ return( $this->databaseLevel );
+ }
+
+ public function fileLevel( $fileLevel ) {
+ if ( isset($fileLevel) ) {
+ $fileLevel = $this->limit($fileLevel);
+ if ( $this->fileLevel != $fileLevel ) {
+ if ( $this->fileLevel > self::NOLOG )
+ $this->closeFile();
+ $this->fileLevel = $fileLevel;
+ if ( $this->fileLevel > self::NOLOG )
+ $this->openFile();
+ }
+ }
+ return( $this->fileLevel );
+ }
+
+ public function weblogLevel( $weblogLevel ) {
+ if ( isset($weblogLevel) ) {
+ $weblogLevel = $this->limit($weblogLevel);
+ if ( $this->weblogLevel != $weblogLevel ) {
+ if ( $weblogLevel > self::NOLOG && $this->weblogLevel <= self::NOLOG ) {
+ $this->savedLogErrors = ini_set( 'log_errors', true );
+ } elseif ( $weblogLevel <= self::NOLOG && $this->weblogLevel > self::NOLOG ) {
+ ini_set( 'log_errors', $this->savedLogErrors );
+ }
+ $this->weblogLevel = $weblogLevel;
+ }
+ }
+ return( $this->weblogLevel );
+ }
+
+ public function syslogLevel( $syslogLevel ) {
+ if ( isset($syslogLevel) ) {
+ $syslogLevel = $this->limit($syslogLevel);
+ if ( $this->syslogLevel != $syslogLevel ) {
+ if ( $this->syslogLevel > self::NOLOG )
+ $this->closeSyslog();
+ $this->syslogLevel = $syslogLevel;
+ if ( $this->syslogLevel > self::NOLOG )
+ $this->openSyslog();
+ }
+ }
+ return( $this->syslogLevel );
+ }
+
+ private function openSyslog() {
+ openlog( $this->id, LOG_PID|LOG_NDELAY, LOG_LOCAL1 );
+ }
+
+ private function closeSyslog() {
+ closelog();
+ }
+
+ private function logFile( $logFile ) {
+ if ( preg_match( '/^(.+)\+$/', $logFile, $matches ) )
+ $this->logFile = $matches[1].'.'.getmypid();
+ else
+ $this->logFile = $logFile;
+ }
+
+ private function openFile() {
+ if ( !$this->useErrorLog ) {
+ if ( $this->logFd = fopen( $this->logFile, 'a+' ) ) {
+ if ( strnatcmp( phpversion(), '5.2.0' ) >= 0 ) {
+ $error = error_get_last();
+ trigger_error( "Can't open log file '$logFile': ".$error['message'].' @ '.$error['file'].'/'.$error['line'], E_USER_ERROR );
+ }
+ $this->fileLevel = self::NOLOG;
+ }
+ }
+ }
+
+ private function closeFile() {
+ if ( $this->logFd )
+ fclose( $this->logFd );
+ }
+
+ public function logPrint( $level, $string, $file=NULL, $line=NULL ) {
+ if ( $level <= $this->effectiveLevel ) {
+ $string = preg_replace( '/[\r\n]+$/', '', $string );
+ $code = self::$codes[$level];
+
+ $time = gettimeofday();
+ $message = sprintf( '%s.%06d %s[%d].%s [%s]', strftime( '%x %H:%M:%S', $time['sec'] ), $time['usec'], $this->id, getmypid(), $code, $string );
+
+ if ( is_null($file) ) {
+ if ( $this->useErrorLog || $this->databaseLevel > self::NOLOG ) {
+ $backTrace = debug_backtrace();
+ $file = $backTrace[1]['file'];
+ $line = $backTrace[1]['line'];
+ if ( $this->hasTerm )
+ $rootPath = getcwd();
+ else
+ $rootPath = $_SERVER['DOCUMENT_ROOT'];
+ $file = preg_replace( '/^'.addcslashes($rootPath,'/').'\/?/', '', $file );
+ }
+ }
+
+ if ( $this->useErrorLog )
+ $message .= " at ".$file." line ".$line;
+ else
+ $message = $message;
+
+ if ( $level <= $this->termLevel )
+ if ( $this->hasTerm )
+ print( $message."\n" );
else
- $tempLogFile = $this->logPath."/".$this->id.".log";
- if ( !is_null($logFile = $this->getTargettedEnv('LOG_FILE')) )
- $tempLogFile = $logFile;
+ print( preg_replace( "/\n/", '
', htmlspecialchars($message) ).'
' );
- $tempLevel = self::INFO;
- $tempTermLevel = $this->termLevel;
- $tempDatabaseLevel = $this->databaseLevel;
- $tempFileLevel = $this->fileLevel;
- $tempSyslogLevel = $this->syslogLevel;
- $tempWeblogLevel = $this->weblogLevel;
+ if ( $level <= $this->fileLevel )
+ if ( $this->useErrorLog ) {
+ if ( !error_log( $message."\n", 3, $this->logFile ) ) {
+ if ( strnatcmp( phpversion(), '5.2.0' ) >= 0 ) {
+ $error = error_get_last();
+ trigger_error( "Can't write to log file '".$this->logFile."': ".$error['message'].' @ '.$error['file'].'/'.$error['line'], E_USER_ERROR );
+ }
+ }
+ } elseif ( $this->logFd ) {
+ fprintf( $this->logFd, $message."\n" );
+ }
- if ( isset($options['termLevel']) )
- $tempTermLevel = $options['termLevel'];
- if ( isset($options['databaseLevel']) )
- $tempDatabaseLevel = $options['databaseLevel'];
+ $message = $code.' ['.$string.']';
+ if ( $level <= $this->syslogLevel )
+ syslog( self::$syslogPriorities[$level], $message );
+ if ( $level <= $this->databaseLevel ) {
+ try {
+ global $dbConn;
+ $sql = "INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, ? )";
+ $stmt = $dbConn->prepare( $sql );
+ $result = $stmt->execute( array( sprintf( "%d.%06d", $time['sec'], $time['usec'] ), $this->id, getmypid(), $level, $code, $string, $file, $line ) );
+ } catch(PDOException $ex) {
+ $this->databaseLevel = self::NOLOG;
+ Fatal( "Can't write log entry '$sql': ". $ex->getMessage() );
+ }
+ }
+ // This has to be last as trigger_error can be fatal
+ if ( $level <= $this->weblogLevel ) {
+ if ( $this->useErrorLog )
+ error_log( $message, 0 );
else
- $tempDatabaseLevel = ZM_LOG_LEVEL_DATABASE;
- if ( isset($options['fileLevel']) )
- $tempFileLevel = $options['fileLevel'];
- else
- $tempFileLevel = ZM_LOG_LEVEL_FILE;
- if ( isset($options['weblogLevel']) )
- $tempWeblogLevel = $options['weblogLevel'];
- else
- $tempWeblogLevel = ZM_LOG_LEVEL_WEBLOG;
- if ( isset($options['syslogLevel']) )
- $tempSyslogLevel = $options['syslogLevel'];
- else
- $tempSyslogLevel = ZM_LOG_LEVEL_SYSLOG;
-
- if ( $value = getenv('LOG_PRINT') )
- $tempTermLevel = $value ? self::DEBUG : self::NOLOG;
-
- if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL')) )
- $tempLevel = $level;
-
- if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_TERM')) )
- $tempTermLevel = $level;
- if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_DATABASE')) )
- $tempDatabaseLevel = $level;
- if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_FILE')) )
- $tempFileLevel = $level;
- if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_SYSLOG')) )
- $tempSyslogLevel = $level;
- if ( !is_null($level = $this->getTargettedEnv('LOG_LEVEL_WEBLOG')) )
- $tempWeblogLevel = $level;
-
- if ( ZM_LOG_DEBUG )
- {
- foreach ( explode( '|', ZM_LOG_DEBUG_TARGET ) as $target )
- {
- if ( $target == $this->id || $target == "_".$this->id || $target == $this->idRoot || $target == "_".$this->idRoot || $target == "" )
- {
- if ( ZM_LOG_DEBUG_LEVEL > self::NOLOG )
- {
- $tempLevel = $this->limit( ZM_LOG_DEBUG_LEVEL );
- if ( ZM_LOG_DEBUG_FILE != "" )
- {
- $tempLogFile = ZM_LOG_DEBUG_FILE;
- $tempFileLevel = $tempLevel;
- }
- }
- }
- }
- }
-
- $this->logFile( $tempLogFile );
-
- $this->termLevel( $tempTermLevel );
- $this->databaseLevel( $tempDatabaseLevel );
- $this->fileLevel( $tempFileLevel );
- $this->syslogLevel( $tempSyslogLevel );
- $this->weblogLevel( $tempWeblogLevel );
-
- $this->level( $tempLevel );
-
- $this->initialised = true;
-
- Logger::Debug( "LogOpts: level=".self::$codes[$this->level]."/".self::$codes[$this->effectiveLevel].", screen=".self::$codes[$this->termLevel].", database=".self::$codes[$this->databaseLevel].", logfile=".self::$codes[$this->fileLevel]."->".$this->logFile.", weblog=".self::$codes[$this->weblogLevel].", syslog=".self::$codes[$this->syslogLevel] );
- }
-
- private function terminate()
- {
- if ( $this->initialised )
- {
- if ( $this->fileLevel > self::NOLOG )
- $this->closeFile();
- if ( $this->syslogLevel > self::NOLOG )
- $this->closeSyslog();
- }
- $this->initialised = false;
- }
-
- private function limit( $level )
- {
- if ( $level > self::DEBUG )
- return( self::DEBUG );
- if ( $level < self::NOLOG )
- return( self::NOLOG );
- return( $level );
- }
-
- private function getTargettedEnv( $name )
- {
- $envName = $name."_".$this->id;
- $value = getenv( $envName );
- if ( $value === false && $this->id != $this->idRoot )
- $value = getenv( $name."_".$this->idRoot );
- if ( $value === false )
- $value = getenv( $name );
- return( $value !== false ? $value : NULL );
- }
-
- public static function fetch( $initialise=true )
- {
- if ( !isset(self::$instance) )
- {
- $class = __CLASS__;
- self::$instance = new $class;
- if ( $initialise )
- self::$instance->initialise( array( 'id'=>'web_php', 'syslogLevel'=>self::INFO, 'weblogLevel'=>self::INFO ) );
- }
- return self::$instance;
- }
-
- public static function Debug( $string )
- {
- Logger::fetch()->logPrint( Logger::DEBUG, $string );
- }
-
- public function id( $id=NULL )
- {
- if ( isset($id) && $this->id != $id )
- {
- // Remove whitespace
- $id = preg_replace( '/\S/', '', $id );
- // Replace non-alphanum with underscore
- $id = preg_replace( '/[^a-zA-Z_]/', '_', $id );
-
- if ( $this->id != $id )
- {
- $this->id = $this->idRoot = $id;
- if ( preg_match( '/^([^_]+)_(.+)$/', $id, $matches ) )
- {
- $this->idRoot = $matches[1];
- $this->idArgs = $matches[2];
- }
- }
- }
- return( $this->id );
- }
-
- public function level( $level )
- {
- if ( isset($level) )
- {
- $lastLevel = $this->level;
- $this->level = $this->limit($level);
- $this->effectiveLevel = self::NOLOG;
- if ( $this->termLevel > $this->effectiveLevel )
- $this->effectiveLevel = $this->termLevel;
- if ( $this->databaseLevel > $this->effectiveLevel )
- $this->effectiveLevel = $this->databaseLevel;
- if ( $this->fileLevel > $this->effectiveLevel )
- $this->effectiveLevel = $this->fileLevel;
- if ( $this->weblogLevel > $this->effectiveLevel )
- $this->effectiveLevel = $this->weblogLevel;
- if ( $this->syslogLevel > $this->effectiveLevel )
- $this->effectiveLevel = $this->syslogLevel;
- if ( $this->effectiveLevel > $this->level )
- $this->effectiveLevel = $this->level;
- if ( !$this->hasTerm )
- {
- if ( $lastLevel < self::DEBUG && $this->level >= self::DEBUG )
- {
- $this->savedErrorReporting = error_reporting( E_ALL );
- $this->savedDisplayErrors = ini_set( 'display_errors', true );
- }
- elseif ( $lastLevel >= self::DEBUG && $this->level < self::DEBUG )
- {
- error_reporting( $this->savedErrorReporting );
- ini_set( 'display_errors', $this->savedDisplayErrors );
- }
- }
- }
- return( $this->level );
- }
-
- public function debugOn()
- {
- return( $this->effectiveLevel >= self::DEBUG );
- }
-
- public function termLevel( $termLevel )
- {
- if ( isset($termLevel) )
- {
- $termLevel = $this->limit($termLevel);
- if ( $this->termLevel != $termLevel )
- $this->termLevel = $termLevel;
- }
- return( $this->termLevel );
- }
-
- public function databaseLevel( $databaseLevel=NULL )
- {
- if ( !is_null($databaseLevel) )
- {
- $databaseLevel = $this->limit($databaseLevel);
- if ( $this->databaseLevel != $databaseLevel )
- {
- $this->databaseLevel = $databaseLevel;
- if ( $this->databaseLevel > self::NOLOG )
- {
- if ( (include_once 'database.php') === FALSE )
- {
- $this->databaseLevel = self::NOLOG;
- Warning( "Unable to write log entries to DB, database.php not found" );
- }
- }
- }
- }
- return( $this->databaseLevel );
- }
-
- public function fileLevel( $fileLevel )
- {
- if ( isset($fileLevel) )
- {
- $fileLevel = $this->limit($fileLevel);
- if ( $this->fileLevel != $fileLevel )
- {
- if ( $this->fileLevel > self::NOLOG )
- $this->closeFile();
- $this->fileLevel = $fileLevel;
- if ( $this->fileLevel > self::NOLOG )
- $this->openFile();
- }
- }
- return( $this->fileLevel );
- }
-
- public function weblogLevel( $weblogLevel )
- {
- if ( isset($weblogLevel) )
- {
- $weblogLevel = $this->limit($weblogLevel);
- if ( $this->weblogLevel != $weblogLevel )
- {
- if ( $weblogLevel > self::NOLOG && $this->weblogLevel <= self::NOLOG )
- {
- $this->savedLogErrors = ini_set( 'log_errors', true );
- }
- elseif ( $weblogLevel <= self::NOLOG && $this->weblogLevel > self::NOLOG )
- {
- ini_set( 'log_errors', $this->savedLogErrors );
- }
- $this->weblogLevel = $weblogLevel;
- }
- }
- return( $this->weblogLevel );
- }
-
- public function syslogLevel( $syslogLevel )
- {
- if ( isset($syslogLevel) )
- {
- $syslogLevel = $this->limit($syslogLevel);
- if ( $this->syslogLevel != $syslogLevel )
- {
- if ( $this->syslogLevel > self::NOLOG )
- $this->closeSyslog();
- $this->syslogLevel = $syslogLevel;
- if ( $this->syslogLevel > self::NOLOG )
- $this->openSyslog();
- }
- }
- return( $this->syslogLevel );
- }
-
- private function openSyslog()
- {
- openlog( $this->id, LOG_PID|LOG_NDELAY, LOG_LOCAL1 );
- }
-
- private function closeSyslog()
- {
- closelog();
- }
-
- private function logFile( $logFile )
- {
- if ( preg_match( '/^(.+)\+$/', $logFile, $matches ) )
- $this->logFile = $matches[1].'.'.getmypid();
- else
- $this->logFile = $logFile;
- }
-
- private function openFile()
- {
- if ( !$this->useErrorLog )
- {
- if ( $this->logFd = fopen( $this->logFile, "a+" ) )
- {
- if ( strnatcmp( phpversion(), '5.2.0' ) >= 0 )
- {
- $error = error_get_last();
- trigger_error( "Can't open log file '$logFile': ".$error['message']." @ ".$error['file']."/".$error['line'], E_USER_ERROR );
- }
- $this->fileLevel = self::NOLOG;
- }
- }
- }
-
- private function closeFile()
- {
- if ( $this->logFd )
- fclose( $this->logFd );
- }
-
- public function logPrint( $level, $string, $file=NULL, $line=NULL )
- {
- if ( $level <= $this->effectiveLevel )
- {
- $string = preg_replace( '/[\r\n]+$/', '', $string );
- $code = self::$codes[$level];
-
- $time = gettimeofday();
- $message = sprintf( "%s.%06d %s[%d].%s [%s]", strftime( "%x %H:%M:%S", $time['sec'] ), $time['usec'], $this->id, getmypid(), $code, $string );
-
- if ( is_null( $file) )
- {
- if ( $this->useErrorLog || $this->databaseLevel > self::NOLOG )
- {
- $backTrace = debug_backtrace();
- $file = $backTrace[1]['file'];
- $line = $backTrace[1]['line'];
- if ( $this->hasTerm )
- $rootPath = getcwd();
- else
- $rootPath = $_SERVER['DOCUMENT_ROOT'];
- $file = preg_replace( '/^'.addcslashes($rootPath,'/').'\/?/', '', $file );
- }
- }
-
- if ( $this->useErrorLog )
- $message .= " at ".$file." line ".$line;
- else
- $message = $message;
-
- if ( $level <= $this->termLevel )
- if ( $this->hasTerm )
- print( $message."\n" );
- else
- print( preg_replace( "/\n/", '
', htmlspecialchars($message) )."
" );
-
- if ( $level <= $this->fileLevel )
- if ( $this->useErrorLog )
- {
- if ( !error_log( $message."\n", 3, $this->logFile ) )
- {
- if ( strnatcmp( phpversion(), '5.2.0' ) >= 0 )
- {
- $error = error_get_last();
- trigger_error( "Can't write to log file '".$this->logFile."': ".$error['message']." @ ".$error['file']."/".$error['line'], E_USER_ERROR );
- }
- }
- }
- elseif ( $this->logFd )
- fprintf( $this->logFd, $message."\n" );
-
- $message = $code." [".$string."]";
- if ( $level <= $this->syslogLevel )
- syslog( self::$syslogPriorities[$level], $message );
- if ( $level <= $this->databaseLevel )
- {
- try {
- global $dbConn;
- $sql = "INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, ? )";
- $stmt = $dbConn->prepare( $sql );
- $result = $stmt->execute( array( sprintf( "%d.%06d", $time['sec'], $time['usec'] ), $this->id, getmypid(), $level, $code, $string, $file, $line ) );
- } catch(PDOException $ex) {
- $this->databaseLevel = self::NOLOG;
- Fatal( "Can't write log entry '$sql': ". $ex->getMessage() );
- }
- }
- // This has to be last as trigger_error can be fatal
- if ( $level <= $this->weblogLevel )
- {
- if ( $this->useErrorLog )
- error_log( $message, 0 );
- else
- trigger_error( $message, self::$phpErrorLevels[$level] );
- }
- }
+ trigger_error( $message, self::$phpErrorLevels[$level] );
+ }
}
+ }
};
-function logInit( $options=array() )
-{
- $logger = Logger::fetch();
- $logger->initialise( $options );
- set_error_handler( 'ErrorHandler' );
+function logInit( $options=array() ) {
+ $logger = Logger::fetch();
+ $logger->initialise( $options );
+ set_error_handler( 'ErrorHandler' );
}
-function logToDatabase( $level=NULL )
-{
- return( Logger::fetch()->databaseLevel( $level ) );
+function logToDatabase( $level=NULL ) {
+ return( Logger::fetch()->databaseLevel( $level ) );
}
-function Mark( $level=Logger::DEBUG, $tag="Mark" )
-{
- Logger::fetch()->logPrint( $level, $tag );
+function Mark( $level=Logger::DEBUG, $tag='Mark' ) {
+ Logger::fetch()->logPrint( $level, $tag );
}
-function Dump( &$var, $label="VAR" )
-{
+function Dump( &$var, $label='VAR' ) {
+ ob_start();
+ print( $label.' => ' );
+ print_r( $var );
+ Logger::fetch()->logPrint( Logger::DEBUG, ob_get_clean() );
+}
+
+function Info( $string ) {
+ Logger::fetch()->logPrint( Logger::INFO, $string );
+}
+
+function Warning( $string ) {
+ Logger::fetch()->logPrint( Logger::WARNING, $string );
+}
+
+function Error( $string ) {
+ Logger::fetch()->logPrint( Logger::ERROR, $string );
+}
+
+function Fatal( $string ) {
+ Logger::fetch()->logPrint( Logger::FATAL, $string );
+ die( htmlentities($string) );
+}
+
+function Panic( $string ) {
+ if ( true ) {
+ // Use builtin function
ob_start();
- print( $label." => " );
- print_r( $var );
- Logger::fetch()->logPrint( Logger::DEBUG, ob_get_clean() );
-}
-
-function Info( $string )
-{
- Logger::fetch()->logPrint( Logger::INFO, $string );
-}
-
-function Warning( $string )
-{
- Logger::fetch()->logPrint( Logger::WARNING, $string );
-}
-
-function Error( $string )
-{
- Logger::fetch()->logPrint( Logger::ERROR, $string );
-}
-
-function Fatal( $string )
-{
- Logger::fetch()->logPrint( Logger::FATAL, $string );
- die( htmlentities($string) );
-}
-
-function Panic( $string )
-{
- if ( true )
- {
- // Use builtin function
- ob_start();
- debug_print_backtrace();
- $backtrace = "\n".ob_get_clean();
+ debug_print_backtrace();
+ $backtrace = "\n".ob_get_clean();
+ } else {
+ // Roll your own
+ $backtrace = '';
+ $frames = debug_backtrace();
+ for ( $i = 0; $i < count($frames); $i++ ) {
+ $frame = $frames[$i];
+ $backtrace .= sprintf( "\n#%d %s() at %s/%d", $i, $frame['function'], $frame['file'], $frame['line'] );
}
- else
- {
- // Roll your own
- $backtrace = '';
- $frames = debug_backtrace();
- for ( $i = 0; $i < count($frames); $i++ )
- {
- $frame = $frames[$i];
- $backtrace .= sprintf( "\n#%d %s() at %s/%d", $i, $frame['function'], $frame['file'], $frame['line'] );
- }
- }
- Logger::fetch()->logPrint( Logger::PANIC, $string.$backtrace );
- die( $string );
+ }
+ Logger::fetch()->logPrint( Logger::PANIC, $string.$backtrace );
+ die( $string );
}
-function ErrorHandler( $error, $string, $file, $line )
-{
- if ( ! (error_reporting() & $error) )
- {
- // This error code is not included in error_reporting
- return( false );
- }
+function ErrorHandler( $error, $string, $file, $line ) {
+ if ( ! (error_reporting() & $error) ) {
+ // This error code is not included in error_reporting
+ return( false );
+ }
- switch ( $error )
- {
- case E_USER_ERROR:
- Logger::fetch()->logPrint( Logger::FATAL, $string, $file, $line );
- break;
+ switch ( $error ) {
+ case E_USER_ERROR:
+ Logger::fetch()->logPrint( Logger::FATAL, $string, $file, $line );
+ break;
- case E_USER_WARNING:
- Logger::fetch()->logPrint( Logger::ERROR, $string, $file, $line );
- break;
+ case E_USER_WARNING:
+ Logger::fetch()->logPrint( Logger::ERROR, $string, $file, $line );
+ break;
- case E_USER_NOTICE:
- Logger::fetch()->logPrint( Logger::WARNING, $string, $file, $line );
- break;
+ case E_USER_NOTICE:
+ Logger::fetch()->logPrint( Logger::WARNING, $string, $file, $line );
+ break;
- default:
- Panic( "Unknown error type: [$error] $string" );
- break;
- }
- return( true );
+ default:
+ Panic( "Unknown error type: [$error] $string" );
+ break;
+ }
+ return( true );
}
?>
diff --git a/web/index.php b/web/index.php
index d6f53af1b..1829f289b 100644
--- a/web/index.php
+++ b/web/index.php
@@ -34,7 +34,7 @@ if ( version_compare( phpversion(), '4.1.0', '<') ) {
}
// Useful debugging lines for mobile devices
-if ( false ) {
+if ( true ) {
ob_start();
phpinfo( INFO_VARIABLES );
$fp = fopen( '/tmp/env.html', 'w' );
@@ -113,7 +113,7 @@ if ( !file_exists( ZM_SKIN_PATH ) )
$skinBase[] = $skin;
$currentCookieParams = session_get_cookie_params();
-Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
+//Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
session_set_cookie_params(
$currentCookieParams['lifetime'],
$currentCookieParams['path'],
@@ -175,9 +175,7 @@ foreach ( getSkinIncludes( 'skin.php' ) as $includeFile )
if ( ZM_OPT_USE_AUTH && ZM_AUTH_HASH_LOGINS ) {
if ( empty($user) && ! empty($_REQUEST['auth']) ) {
-Logger::Debug("Getting user from auth hash");
if ( $authUser = getAuthUser( $_REQUEST['auth'] ) ) {
-Logger::Debug("Success Getting user from auth hash");
userLogin( $authUser['Username'], $authUser['Password'], true );
}
} else if ( ! empty($user) ) {
diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php
index 59b5b8ba3..4d00798be 100644
--- a/web/lang/en_gb.php
+++ b/web/lang/en_gb.php
@@ -302,6 +302,7 @@ $SLANG = array(
'DuplicateMonitorName' => 'Duplicate Monitor Name',
'Duration' => 'Duration',
'Edit' => 'Edit',
+ 'EditLayout' => 'Edit Layout',
'Email' => 'Email',
'EnableAlarms' => 'Enable Alarms',
'Enabled' => 'Enabled',
@@ -556,6 +557,8 @@ $SLANG = array(
'OpNe' => 'not equal to',
'OpNotIn' => 'not in set',
'OpNotMatches' => 'does not match',
+ 'OpIs' => 'is',
+ 'OpIsNot' => 'is not',
'OptionalEncoderParam' => 'Optional Encoder Parameters',
'OptionHelp' => 'Option Help',
'OptionRestartWarning' => 'These changes may not come into effect fully\nwhile the system is running. When you have\nfinished making your changes please ensure that\nyou restart ZoneMinder.',
diff --git a/web/skins/classic/css/flat/views/montage.css b/web/skins/classic/css/flat/views/montage.css
index 7c571f7c1..479ade89e 100644
--- a/web/skins/classic/css/flat/views/montage.css
+++ b/web/skins/classic/css/flat/views/montage.css
@@ -6,6 +6,15 @@
width: 99%;
}
+#monitors:after {
+ content: ".";
+ display: block;
+ height: 0;
+ font-size: 0;
+ clear: both;
+ visibility: hidden;
+}
+
#monitors .monitor {
min-width: 180px;
margin: 0;
diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php
index 26cb1a26e..450cf63b3 100644
--- a/web/skins/classic/includes/functions.php
+++ b/web/skins/classic/includes/functions.php
@@ -48,8 +48,10 @@ function xhtmlHeaders( $file, $title ) {