From 6fba9fa65ab26284c93a02fdded2db00d4d37540 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Oct 2017 14:54:28 -0400 Subject: [PATCH 01/80] google code style and quotes --- web/includes/logger.php | 1011 ++++++++++++++++++--------------------- 1 file changed, 465 insertions(+), 546 deletions(-) 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 ); } ?> From fc3934c8bbd54a075121f4898a82d2263cfb0d22 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Oct 2017 13:20:18 -0700 Subject: [PATCH 02/80] kill off curl and libvlc --- distros/ubuntu1604/rules | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules index 6bc3dffb5..5cf153266 100755 --- a/distros/ubuntu1604/rules +++ b/distros/ubuntu1604/rules @@ -27,7 +27,9 @@ 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" \ + -DZM_NO_CURL=1 \ + -DZM_NO_LIBVLC=1 override_dh_clean: dh_clean $(MANPAGES1) From bc150574c7c0f140e78a1a2648faff17c4a083b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Oct 2017 18:56:10 -0700 Subject: [PATCH 03/80] wip import --- web/includes/Monitor.php | 39 ++++++++++++++++----------- web/includes/actions.php | 22 +++++++++++++++ web/index.php | 2 +- web/skins/classic/views/console.php | 3 ++- web/skins/classic/views/js/console.js | 2 +- web/skins/classic/views/monitor.php | 2 +- 6 files changed, 51 insertions(+), 19 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 8e74c6256..5c4643657 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,7 +296,7 @@ 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 ); diff --git a/web/includes/actions.php b/web/includes/actions.php index cbadae3f6..41bfe81ad 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -23,6 +23,28 @@ // 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', diff --git a/web/index.php b/web/index.php index d6f53af1b..7fa8790a5 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' ); diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 679a569d4..7e9094cb8 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -385,7 +385,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { - + + diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 9675a96b5..3ba206f81 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -19,7 +19,7 @@ function setButtonStates( element ) { form.deleteBtn.disabled = (checked==0); } -function addMonitor( element) { +function addMonitor(element) { var form = element.form; var dupParam; var monitorId=-1; diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 340fec26b..ef15bf1e8 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -665,7 +665,7 @@ if ( ZM_HAS_V4L && ($tab != 'misc' || $monitor->Type()!= 'Local') ) { - +
Date: Fri, 27 Oct 2017 08:03:09 -0700 Subject: [PATCH 04/80] make zmfilter update DiskSPace. ALso rename DiskUsage in Event to DiskSpace --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 8 ++++---- scripts/zmaudit.pl.in | 2 +- scripts/zmfilter.pl.in | 7 +++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index fbb249773..8ba3d2098 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -359,14 +359,14 @@ sub age { return $_[0]{age}; } -sub DiskUsage { +sub DiskSpace { if ( @_ > 1 ) { - $_[0]{DiskUsage} = $_[1]; + $_[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; } } 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..d1b4c1766 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -259,6 +259,7 @@ sub checkFilter { ($filter->{AutoEmail}?', email':''), ($filter->{AutoMessage}?', message':''), ($filter->{AutoExecute}?', execute':''), + ($filter->{UpdateDiskSpace}?', update disk space':''), ' returned ' , scalar @Events , ' events', "\n", ) ); @@ -309,6 +310,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 } From 82fbec697f7bd03e8a72f112afc540a332307b93 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 08:37:53 -0700 Subject: [PATCH 05/80] add IS and IS NOT as filter operators so that we can do IS NULL and IS NOT NULL because = NULL and !=NULL are not valid --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 1 + scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 10 +++++++--- scripts/zmfilter.pl.in | 3 ++- web/includes/functions.php | 4 ++++ web/lang/en_gb.php | 2 ++ web/skins/classic/views/filter.php | 2 ++ 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 8ba3d2098..16a117297 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -367,6 +367,7 @@ sub DiskSpace { my $size = 0; File::Find::find( { wanted=>sub { $size += -f $_ ? -s _ : 0 }, untaint=>1 }, $_[0]->Path() ); $_[0]{DiskSpace} = $size; + Debug("DiskSpace for event $_[0]{Id} Updated to $size bytes"); } } diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 82deff6ff..07dd659cc 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -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/zmfilter.pl.in b/scripts/zmfilter.pl.in index d1b4c1766..b52ae90c1 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -251,7 +251,8 @@ sub checkFilter { my $filter = shift; my @Events = $filter->Execute(); - Info( join( "Checking filter '$filter->{Name}'", + Info( join( ' ', + "Checking filter '$filter->{Name}'", ($filter->{AutoDelete}?', delete':''), ($filter->{AutoArchive}?', archive':''), ($filter->{AutoVideo}?', video':''), diff --git a/web/includes/functions.php b/web/includes/functions.php index ab0e1c898..012dc7760 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1274,6 +1274,10 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) { case '![]' : $filter['sql'] .= ' not in ('.join( ',', $valueList ).')'; break; + case 'IS' : + $filter['sql'] .= " IS $value"; + case 'IS NOT' : + $filter['sql'] .= " IS NOT $value"; } $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']); diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 59b5b8ba3..45132b72f 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -556,6 +556,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/views/filter.php b/web/skins/classic/views/filter.php index b62d85d4a..cb7e30087 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -104,6 +104,8 @@ $opTypes = array( '!~' => translate('OpNotMatches'), '=[]' => translate('OpIn'), '![]' => translate('OpNotIn'), + 'IS' => translate('OpIs'), + 'IS NOT' => translate('OpIsNot'), ); $archiveTypes = array( From 663cc6df87ebc742b6209e4caf1ffc6f12299e4f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 09:09:12 -0700 Subject: [PATCH 06/80] improve logging of zmfilter --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 5 ++-- scripts/zmfilter.pl.in | 30 ++++++++++++---------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 16a117297..3e877205d 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -361,13 +361,14 @@ sub age { sub DiskSpace { if ( @_ > 1 ) { + Debug("Cleared DiskSpace, was $_[0]{DiskSpace}"); $_[0]{DiskSpace} = $_[1]; } if ( ! defined $_[0]{DiskSpace} ) { my $size = 0; File::Find::find( { wanted=>sub { $size += -f $_ ? -s _ : 0 }, untaint=>1 }, $_[0]->Path() ); - $_[0]{DiskSpace} = $size; - Debug("DiskSpace for event $_[0]{Id} Updated to $size bytes"); + $_[0]{DiskSpace} = $size; + Debug("DiskSpace for event $_[0]{Id} at $_[0]{Path} Updated to $size bytes"); } } diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index b52ae90c1..efe988882 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -251,19 +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':''), - ($filter->{UpdateDiskSpace}?', update disk space':''), - ' 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" ); From 60fb654a4701c295a37df00572b5d3a0c7f1a60c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 09:57:41 -0700 Subject: [PATCH 07/80] rough in the MontageLayouts table --- db/zm_create.sql.in | 8 +++++ db/zm_update-1.31.11.sql | 69 ++++++++++++++++++++++++++++++++++++++++ db/zm_update-1.31.12.sql | 23 ++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 db/zm_update-1.31.11.sql create mode 100644 db/zm_update-1.31.12.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 01176eb43..2cff3c576 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -762,6 +762,14 @@ 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` JSON, + PRIMARY KEY (`Id`) +); + -- -- 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..a267728f5 --- /dev/null +++ b/db/zm_update-1.31.12.sql @@ -0,0 +1,23 @@ +-- +-- 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` JSON, + PRIMARY KEY (`Id`) +); +" + )); + +PREPARE stmt FROM @s; +EXECUTE stmt; From 71c8562b4620706027dc48762c5b6628b8ce8bb8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 10:01:16 -0700 Subject: [PATCH 08/80] Rough in a MontageLayout class --- web/includes/MontageLayout.php | 118 +++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 web/includes/MontageLayout.php diff --git a/web/includes/MontageLayout.php b/web/includes/MontageLayout.php new file mode 100644 index 000000000..9c74e1856 --- /dev/null +++ b/web/includes/MontageLayout.php @@ -0,0 +1,118 @@ + 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_all( $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); + $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; + } + } + + $sql = 'UPDATE MontageLayouts 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 + +} // end class MontageLayout +?> From 9942b886f22aec4e441824ffafb37422c82edc6b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 12:04:42 -0700 Subject: [PATCH 09/80] conditionally add the standard layouts --- db/zm_update-1.31.12.sql | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/db/zm_update-1.31.12.sql b/db/zm_update-1.31.12.sql index a267728f5..deb97c777 100644 --- a/db/zm_update-1.31.12.sql +++ b/db/zm_update-1.31.12.sql @@ -21,3 +21,44 @@ SET @s = (SELECT IF( PREPARE stmt FROM @s; EXECUTE stmt; + +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"} }' );" +) ); +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", "width":"49%"} }' );"; +) ); +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", "width":"33%"} }' );" +) ); +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", "width":"24.5%"} }' );" +) ); + +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", "width":"19%"} }' );" +) ); + +PREPARE stmt FROM @s; +EXECUTE stmt; From b3d420b13bf2e9034162f72ba79277acaad7f0dd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 12:06:07 -0700 Subject: [PATCH 10/80] add standard layouts to db creation --- db/zm_create.sql.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 2cff3c576..b422d2936 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -770,6 +770,12 @@ CREATE TABLE MontageLayouts ( PRIMARY KEY (`Id`) ); +INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('Freeform', '{ "default":{"float":"left"} }' ); +INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('2 Wide', '{ "default":{"float":"left", "width":"49%"} }' ); +INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{"float":"left", "width":"33%"} }' ); +INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%"} }' ); +INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%"} }' ); + -- -- Apply the initial configuration -- From 71222d7f2f057cbd10faf76754884325a87667f6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 12:06:26 -0700 Subject: [PATCH 11/80] rework how montage layouts are done, pull from db now --- web/includes/MontageLayout.php | 22 +++++---- web/skins/classic/views/js/montage.js | 57 +++++++++++++++++++---- web/skins/classic/views/js/montage.js.php | 19 ++++++-- web/skins/classic/views/montage.php | 22 +++++++-- 4 files changed, 95 insertions(+), 25 deletions(-) diff --git a/web/includes/MontageLayout.php b/web/includes/MontageLayout.php index 9c74e1856..fd105a8cd 100644 --- a/web/includes/MontageLayout.php +++ b/web/includes/MontageLayout.php @@ -1,12 +1,14 @@ null, - 'Name' => '', - 'Positions' => 0, -); + private $defaults = array( + 'Id' => null, + 'Name' => '', + 'Positions' => 0, + ); public function __construct( $IdOrRow = NULL ) { if ( $IdOrRow ) { @@ -68,7 +70,7 @@ private $defaults = array( } } } - public static function find_all( $parameters = null, $options = null ) { + public static function find( $parameters = null, $options = null ) { $filters = array(); $sql = 'SELECT * FROM MontageLayouts '; $values = array(); @@ -95,9 +97,11 @@ private $defaults = array( $sql .= ' ORDER BY ' . $options['order']; } $result = dbQuery($sql, $values); - $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'MontageLayout'); - foreach ( $results as $row => $obj ) { - $filters[] = $obj; + if ( $result ) { + $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'MontageLayout'); + foreach ( $results as $row => $obj ) { + $filters[] = $obj; + } } return $filters; } diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 3fe8c5b87..2a4badccc 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -10,8 +10,6 @@ function Monitor( monitorData ) { this.streamCmdParms = "view=request&request=stream&connkey="+this.connKey; if ( auth_hash ) this.streamCmdParms += '&auth='+auth_hash; - else - console.log("No auth_hash"); this.streamCmdTimer = null; this.start = function( delay ) { @@ -112,13 +110,45 @@ function Monitor( monitorData ) { } function selectLayout( element ) { - layout = $(element).get('value') - var cssFile = skinPath+'/css/'+Cookie.read('zmCSS')+'/views/'+layout; - if ( $('dynamicStyles') ) - $('dynamicStyles').destroy(); - new Asset.css( cssFile, { id: 'dynamicStyles' } ); + layout = $(element).get('value'); + + if ( layout_id = parseInt(layout) ) { + layout = layouts[layout]; +console.log("Have layout # " + layout_id); + + for ( var i = 0; i < monitors.length; i++ ) { + monitor = monitors[i]; + // Need to clear the current positioning, and apply the new + + monitor_frame = $j('#monitorFrame'+monitor.id); + if ( ! monitor_frame ) { + console.log("Error finding frame for " + monitor.id ); + continue; + } + + // Apply default layout options, like float left + if ( layout.default ) { + styles = layout.default; + for ( style in styles ) { +console.log("applying " + style + ': ' + styles[style]); + monitor_frame.css(style, styles[style]); + } + } // end if default styles + + if ( layout[monitor.id] ) { + styles = layout[monitor.id]; + for ( style in styles ) { +console.log("applying " + style + ': ' + styles[style]); + monitor_frame.css(style, styles[style]); + } + } // end if specific monitor style + } // end foreach monitor + } // end if a stored layout + if ( ! layout ) { + return; + } Cookie.write( 'zmMontageLayout', layout, { duration: 10*365 } ); - if ( layout != 'montage_freeform.css' ) { + if ( layout_id != 1 ) { // 'montage_freeform.css' ) { Cookie.write( 'zmMontageScale', '', { duration: 10*365 } ); $('scale').set('value', '' ); $('width').set('value', ''); @@ -152,6 +182,17 @@ function changeSize() { for ( var x = 0; x < monitors.length; x++ ) { var monitor = monitors[x]; + + // Scale the frame + monitor_frame = $j('#monitorFrame'+monitor.id); + if ( ! monitor_frame ) { + console.log("Error finding frame for " + monitor.id ); + continue; + } + if ( width ) + monitor_frame.css('width',width+'px'); + if ( height ) + monitor_frame.css('height',height+'px'); /*Stream could be an applet so can't use moo tools*/ var streamImg = $( 'liveStream'+monitor.id ); if ( streamImg ) { diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index cd065a355..7aba1e4fb 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -31,12 +31,21 @@ var monitorData = new Array(); foreach ( $monitors as $monitor ) { ?> monitorData[monitorData.length] = { - 'id': Id() ?>, - 'connKey': connKey() ?>, - 'width': Width() ?>, - 'height':Height() ?>, + 'id': Id() ?>, + 'connKey': connKey() ?>, + 'width': Width() ?>, + 'height':Height() ?>, 'server_url': 'Server()->Url().(ZM_MIN_STREAMING_PORT?':'.(ZM_MIN_STREAMING_PORT+$monitor->Id()):'').$_SERVER['PHP_SELF'] ?>' }; +layouts = new Array(); +layouts[0] = {}; // reserved, should hold which fields to clear when transitioning + +layouts[Id() ?>] = Positions() ?>; + diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index e4cc59dde..fa5352563 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -23,6 +23,8 @@ if ( !canView('Stream') ) { return; } +require_once('includes/MontageLayout.php'); + $showControl = false; $showZones = false; if ( isset( $_REQUEST['showZones'] ) ) { @@ -59,6 +61,7 @@ if ( ! $scale ) $focusWindow = true; +/* $layouts = array( 'montage_freeform.css' => translate('MtgDefault'), 'montage_2wide.css' => translate('Mtg2widgrd'), @@ -66,6 +69,15 @@ $layouts = array( 'montage_4wide.css' => translate('Mtg4widgrd'), 'montage_3wide50enlarge.css' => translate('Mtg3widgrx'), ); +foreach ( MontageLayout::find() as $Layout ) { + $layouts[$Layout->Id()] = $Layout->Name(); +} +*/ +$layouts = MontageLayout::find(NULL, array('order'=>"lower('Name')")); +$layoutsById = array(); +foreach ( $layouts as $l ) { + $layoutsById[$l->Id()] = $l->Name(); +} $layout = ''; if ( isset($_COOKIE['zmMontageLayout']) ) @@ -141,11 +153,11 @@ if ( $showControl ) { } if ( $showZones ) { ?> - Hide Zones + Hide Zones - Show Zones + Show Zones @@ -157,10 +169,14 @@ if ( $showZones ) { 'changeMonitor(this);') ); ?> +
- + + + +
From eb48759ff8d193b0226e59f38b8187a825623643 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 13:37:51 -0700 Subject: [PATCH 12/80] wip --- src/zm_monitorstream.cpp | 2 +- web/ajax/stream.php | 2 +- web/skins/classic/views/js/montage.js | 44 +++++++++++++- web/skins/classic/views/montage.php | 87 +++++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 9 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index f904f23cf..85b223f6a 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -553,7 +553,7 @@ 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 ) { diff --git a/web/ajax/stream.php b/web/ajax/stream.php index 7f050bda8..2d4c3c612 100644 --- a/web/ajax/stream.php +++ b/web/ajax/stream.php @@ -44,7 +44,7 @@ switch ( $_REQUEST['command'] ) { $remSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'s.sock'; $max_socket_tries = 10; while ( !file_exists($remSockFile) && $max_socket_tries-- ) { //sometimes we are too fast for our own good, if it hasn't been setup yet give it a second. - usleep(200000); + usleep(2000000); } if ( !file_exists($remSockFile) ) { diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 2a4badccc..c2f96258c 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -87,8 +87,12 @@ function Monitor( monitorData ) { } else { console.error( respObj.message ); // Try to reload the image stream. - if ( stream ) + if ( stream ) { + console.log('Reloading stream: ' + stream.src ); stream.src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); + } else { + console.log( 'No stream to reload?' ); + } } var streamCmdTimeout = statusRefreshTimeout; if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) @@ -147,7 +151,7 @@ console.log("applying " + style + ': ' + styles[style]); if ( ! layout ) { return; } - Cookie.write( 'zmMontageLayout', layout, { duration: 10*365 } ); + Cookie.write( 'zmMontageLayout', layout_id, { duration: 10*365 } ); if ( layout_id != 1 ) { // 'montage_freeform.css' ) { Cookie.write( 'zmMontageScale', '', { duration: 10*365 } ); $('scale').set('value', '' ); @@ -264,6 +268,42 @@ function initPage() { monitors[i].start( delay ); } selectLayout($('layout')); + + $j('#monitors .monitorFrame').draggable({ + cursor: 'crosshair', + revert: 'invalid' + }); + + function toGrid(value) { + return Math.round(value / 80) * 80; + } + + $j('#monitors').droppable({ + accept: '#monitors .monitorFrame', + drop: function(event, ui) { + //console.log(event); + $j(this).removeClass('border over'); + $j(ui.draggable).detach(). + appendTo($j(this).find('ul')). + draggable({ + containment: '.fw-content', + cursor: 'help', + grid: [ 80, 80 ] + }). + css({ + position: 'absolute', + left: toGrid(event.clientX - $j('#monitors').offset().left), + top: toGrid(event.clientY - $j('#monitors').offset().top) + }); + }, + over: function(event, elem) { + console.log('over'); + $j(this).addClass('over'); + }, + out: function(event, elem) { + $j(this).removeClass('over'); + } + }); } // Kick everything off diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index fa5352563..fe9d688e0 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -103,6 +103,35 @@ ob_end_clean(); $groupSql = Group::get_group_sql( $group_id ); +$servers = Server::find_all(); +$ServersById = array(); +foreach ( $servers as $S ) { + $ServersById[$S->Id()] = $S; +} +session_start(); +foreach ( array('ServerFilter','StorageFilter') as $var ) { + if ( isset( $_REQUEST[$var] ) ) { + if ( $_REQUEST[$var] != '' ) { + $_SESSION[$var] = $_REQUEST[$var]; + } else { + unset( $_SESSION[$var] ); + } + } else if ( isset( $_COOKIE[$var] ) ) { + if ( $_COOKIE[$var] != '' ) { + $_SESSION[$var] = $_COOKIE[$var]; + } else { + unset($_SESSION[$var]); + } + } +} +session_write_close(); + +$storage_areas = Storage::find_all(); +$StorageById = array(); +foreach ( $storage_areas as $S ) { + $StorageById[$S->Id()] = $S; +} + $monitor_id = 0; if ( isset( $_REQUEST['monitor_id'] ) ) { $monitor_id = $_REQUEST['monitor_id']; @@ -112,15 +141,46 @@ if ( isset( $_REQUEST['monitor_id'] ) ) { $monitors = array(); $monitors_dropdown = array( '' => 'All' ); -$sql = "SELECT * FROM Monitors WHERE Function != 'None'"; -if ( $groupSql ) { $sql .= ' AND ' . $groupSql; }; -if ( $monitor_id ) { $sql .= ' AND Id='.$monitor_id; }; + $conditions = array(); + $values = array(); -$sql .= ' ORDER BY Sequence'; -foreach( dbFetchAll( $sql ) as $row ) { + if ( $groupSql ) + $conditions[] = $groupSql; + if ( isset($_SESSION['ServerFilter']) ) { + $conditions[] = 'ServerId=?'; + $values[] = $_SESSION['ServerFilter']; + } + if ( isset($_SESSION['StorageFilter']) ) { + $conditions[] = 'StorageId=?'; + $values[] = $_SESSION['StorageFilter']; + } + $sql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC'; + $monitor_rows = dbFetchAll( $sql, null, $values ); + + if ( $monitor_id ) { + $found_selected_monitor = false; + + for ( $i = 0; $i < count($monitor_rows); $i++ ) { + if ( !visibleMonitor( $monitor_rows[$i]['Id'] ) ) { + continue; + } + $monitors_dropdown[$monitor_rows[$i]['Id']] = $monitor_rows[$i]['Name']; + if ( $monitor_rows[$i]['Id'] == $monitor_id ) { + $found_selected_monitor = true; + } + } + if ( ! $found_selected_monitor ) { + $monitor_id = ''; + } + } + +$monitors = array(); +foreach( $monitor_rows as $row ) { if ( !visibleMonitor( $row['Id'] ) ) { continue; } + if ( $monitor_id and $row['Id'] != $monitor_id ) + continue; $row['Scale'] = $scale; $row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); @@ -169,6 +229,23 @@ if ( $showZones ) { 'changeMonitor(this);') ); ?> + 0 ) { ?> + +'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') ); +?> + + 0 ) { ?> + +'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') ); +?> + +
From f89680e6481c2f034058c706edd0a9e473f2bc81 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 15:39:08 -0700 Subject: [PATCH 13/80] bump version --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index b051fa802..623203d2d 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.10 +1.31.12 From 0683cb28ecccfc08c6eef255f7f71c26908855c3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 08:03:09 -0700 Subject: [PATCH 14/80] make zmfilter update DiskSPace. ALso rename DiskUsage in Event to DiskSpace From c16e1011200212eca6e7a905921c6a9d4aa021d6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 20:52:08 -0700 Subject: [PATCH 15/80] rough in add monitors import wizard --- web/ajax/add_monitors.php | 209 +++++++++++++++++++++ web/skins/classic/views/add_monitors.php | 112 +++++++++++ web/skins/classic/views/js/add_monitors.js | 89 +++++++++ 3 files changed, 410 insertions(+) create mode 100644 web/ajax/add_monitors.php create mode 100644 web/skins/classic/views/add_monitors.php create mode 100644 web/skins/classic/views/js/add_monitors.js 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/skins/classic/views/add_monitors.php b/web/skins/classic/views/add_monitors.php new file mode 100644 index 000000000..61f26c4d5 --- /dev/null +++ b/web/skins/classic/views/add_monitors.php @@ -0,0 +1,112 @@ + + +
+ +
+ +
+
+
+
Results +
+ +
+
+
+
+
Enter by IP or URL + + +
+
Import CSV Spreadsheet + Spreadsheet should have the following format:
+
+ + + + + + + + + + +
NameURLGroup
Example Name MN1-30 INQ37.01http://10.34.152.20:2001/?action=streamMN1
+ Defaults to apply to each monitor:
+ + +Id()] = $S; + } + + if ( count($ServersById) > 0 ) { ?> + +Id()] = $S; + } + if ( count($StorageById) > 0 ) { +?> + + + +
SettingValue
+ +
+ 'Auto')+$ServersById, '' ); ?> +
+'All')+$StorageById, 1 ); ?> +
+ + + + + + + + + + diff --git a/web/skins/classic/views/js/add_monitors.js b/web/skins/classic/views/js/add_monitors.js new file mode 100644 index 000000000..a94fd2200 --- /dev/null +++ b/web/skins/classic/views/js/add_monitors.js @@ -0,0 +1,89 @@ + +var probeReq = new Request.JSON( { url:thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getProbeResponse } ); + +function probe( url_e ) { + probeReq.send( "request=add_monitors&action=probe&url="+url_e.value ); +} + +var ProbeResults; + +function getProbeResponse( respObj, respText ) { + if ( checkStreamForErrors( "getProbeResponse", respObj ) ) + return; +//alert(respText); + + if ( respObj.Streams ) { + parseStreams( respObj.Streams ); + } else { + alert("No Streams"); + } +} // end function getProbeResponse + +function parseStreams( Streams ) { + ProbeResults = Array(); + + var results_div = $j('#url_results')[0]; + if ( ! results_div ) { + console.log("No results div found."); + return; + } + results_div.innerHTML = ''; + var html = ''; + + for( i in Streams ) { + var stream = Streams[i]; + if ( stream.url ) { + html += '

'+stream.url; + if ( stream.Monitor.Id ) { + html += ' is already entered into the system by Monitor ' + stream.Monitor.Id + ' ' + stream.Monitor.Name + '
'; + html += ''; + } else { + html += ''; + } + html += '

'; + ProbeResults[stream.url] = stream; + } else { + //console.log(stream); + } + } // end for eah Stream + + results_div.innerHTML = html; +} + +function addMonitor(url) { + if ( ! ProbeResults[url] ) { + alert("Monitor for url " + url + " not found in probe results." ); + return; + } + var Stream = ProbeResults[url]; + var Monitor = Stream.Monitor; + + popup_url = '?view=monitor&newMonitor[Path]='+url; + keys = Object.keys( Monitor ); + for ( i in Monitor ) { + if ( ! Monitor[i] ) + continue; + if ( Monitor[i] == 'null' ) + Monitor[i]=''; + popup_url += '&newMonitor['+i+']='+Monitor[i]; + } + createPopup( popup_url, 'zmMonitor0', 'monitor' ); +} + +function import_csv( form ) { + var formData = new FormData( form ); + console.log(formData); + //formData.append('file', $('#file')[0].files[0]); + + $j.ajax({ + url : thisUrl+"?request=add_monitors&action=import", + type : 'POST', + data : formData, + processData: false, // tell jQuery not to process the data + contentType: false, // tell jQuery not to set contentType + success : function(data) { + var json = JSON.parse(data); + parseStreams( json.Streams ); + } + }); +} From 8b4468caeda80c5661fbf31ac96415770786391d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 09:05:07 -0700 Subject: [PATCH 16/80] add apache log style aliases --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 031a2b7b6..d0d6b234b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -678,6 +678,8 @@ sub Dump { fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) ); } +sub debug { fetch()->logPrint( DEBUG, @_ ); } + sub Debug( @ ) { fetch()->logPrint( DEBUG, @_ ); } @@ -685,14 +687,24 @@ sub Debug( @ ) { sub Info( @ ) { fetch()->logPrint( INFO, @_ ); } +sub info { + fetch()->logPrint( INFO, @_ ); +} + sub Warning( @ ) { fetch()->logPrint( WARNING, @_ ); } +sub warn { + fetch()->logPrint( WARNING, @_ ); +} sub Error( @ ) { fetch()->logPrint( ERROR, @_ ); } +sub error { + fetch()->logPrint( ERROR, @_ ); +} sub Fatal( @ ) { fetch()->logPrint( FATAL, @_ ); From 2d8a4794de3bfaddacb3fdacc4ef5f1e11ba7d4f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 09:05:25 -0700 Subject: [PATCH 17/80] add save, set, transform, and some globals pointing to dbh and log --- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 269 +++++++++++++++++++- 1 file changed, 268 insertions(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index 63193bccf..af4d9fd21 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -42,7 +42,12 @@ use ZoneMinder::Config qw(:all); use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); -use vars qw/ $AUTOLOAD /; +use vars qw/ $AUTOLOAD $log $dbh/; + +*log = \$ZoneMinder::Logger::logger; +*dbh = \$ZoneMinder::Database::dbh; + +my $debug = 1; sub new { my ( $parent, $id, $data ) = @_; @@ -110,7 +115,269 @@ sub AUTOLOAD { return $_[0]{$name}; } +sub save { + my ( $self, $data, $force_insert ) = @_; + my $type = ref $self; + if ( ! $type ) { + my ( $caller, undef, $line ) = caller; + $log->error("No type in Object::save. self:$self from $caller:$line"); + } + my $local_dbh = eval '$'.$type.'::dbh'; + $local_dbh = $ZoneMinder::Database::dbh if ! $local_dbh; + $self->set( $data ? $data : {} ); + if ( $debug or DEBUG_ALL ) { + if ( $data ) { + foreach my $k ( keys %$data ) { + $log->debug("Object::save after set $k => $$data{$k} $$self{$k}"); + } + } else { + $log->debug("No data after set"); + } + } +#$debug = 0; + + my $table = eval '$'.$type.'::table'; + my $fields = eval '\%'.$type.'::fields'; + my $debug = eval '$'.$type.'::debug'; + #$debug = DEBUG_ALL if ! $debug; + + my %sql; + foreach my $k ( keys %$fields ) { + $sql{$$fields{$k}} = $$self{$k} if defined $$fields{$k}; + } # end foreach + if ( ! $force_insert ) { + $sql{$$fields{updated_on}} = 'NOW()' if exists $$fields{updated_on}; + } # end if + my $serial = eval '$'.$type.'::serial'; + my @identified_by = eval '@'.$type.'::identified_by'; + + my $ac = sql::start_transaction( $local_dbh ); + if ( ! $serial ) { + my $insert = $force_insert; + my %serial = eval '%'.$type.'::serial'; + if ( ! %serial ) { +$log->debug("No serial") if $debug; + # No serial columns defined, which means that we will do saving by delete/insert instead of insert/update + if ( @identified_by ) { + my $where = join(' AND ', map { $$fields{$_}.'=?' } @identified_by ); + if ( $debug ) { + $log->debug("DELETE FROM $table WHERE $where"); + } # end if + + if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM $table WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) { + $where =~ s/\?/\%s/g; + $log->error("Error deleting: DELETE FROM $table WHERE " . sprintf($where, map { defined $_ ? $_ : 'undef' } ( @$self{@identified_by}) ).'):' . $local_dbh->errstr); + $local_dbh->rollback(); + sql::end_transaction( $local_dbh, $ac ); + return $local_dbh->errstr; + } elsif ( $debug ) { + $log->debug("SQL succesful DELETE FROM $table WHERE $where"); + } # end if + } # end if + $insert = 1; + } else { + foreach my $id ( @identified_by ) { + if ( ! $serial{$id} ) { + my ( $caller, undef, $line ) = caller; + $log->error("$id nor in serial for $type from $caller:$line") 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; + $insert = 1; + } # end if + } # end foreach + } # end if ! %serial + + if ( $insert ) { + 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} ) ) ) { + my $error = $local_dbh->errstr; + $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 ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL statement execution: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' ); + } # end if + } else { + my @keys = keys %sql; + my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $_ . ' = ?' } @$fields{@identified_by} ); + if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys,@$fields{@identified_by}} ) ) ) { + my $error = $local_dbh->errstr; + $command =~ s/\?/\%s/g; + $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 ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys,@$fields{@identified_by}} ) ).'):' ); + } # end if + } # end if + } else { # not identified_by + @identified_by = ('id') if ! @identified_by; + my $need_serial = ! ( @identified_by == map { $$self{$_} ? $_ : () } @identified_by ); + + 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{')} ); + 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})); + } elsif ( $debug or DEBUG_ALL ) { + $log->debug("SQL statement execution SELECT nextval('$serial') 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} ) ) ) { + $command =~ s/\?/\%s/g; + 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 ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' ); + } # end if + } else { + delete $sql{created_on}; + my @keys = keys %sql; + @keys = sets::exclude( [ @$fields{@identified_by} ], \@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 ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? ( ref $_ eq 'ARRAY' ? join(',',@{$_}) : $_ ) : 'undef' } ( @sql{@keys}, @$self{@identified_by} ) ).'):' ); + } # end if + } # end if + } # end if + sql::end_transaction( $local_dbh, $ac ); + $self->load(); + #if ( $$fields{id} ) { + #if ( ! $ZoneMinder::Object::cache{$type}{$$self{id}} ) { + #$ZoneMinder::Object::cache{$type}{$$self{id}} = $self; + #} # end if + #delete $ZoneMinder::Object::cache{$config{db_name}}{$type}{$$self{id}}; + #} # end if +#$log->debug("after delete"); + #eval 'if ( %'.$type.'::find_cache ) { %'.$type.'::find_cache = (); }'; +#$log->debug("after clear cache"); + return ''; +} # end sub save + +sub set { + my ( $self, $params ) = @_; + my @set_fields = (); + + my $type = ref $self; + my %fields = eval ('%'.$type.'::fields'); + if ( ! %fields ) { + $log->warn('ZoneMinder::Object::set called on an object with no fields'); + } # end if + my %defaults = eval('%'.$type.'::defaults'); + if ( ref $params ne 'HASH' ) { + my ( $caller, undef, $line ) = caller; + $openprint::log->error("$type -> set called with non-hash params from $caller $line"); + } + + foreach my $field ( keys %fields ) { +$log->debug("field: $field, param: ".$$params{$field}) if $debug; + if ( exists $$params{$field} ) { +$openprint::log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug; + if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) { +# Only make changes to fields that have changed + if ( defined $fields{$field} ) { + $$self{$field} = $$params{$field} if defined $fields{$field}; + push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating + } # end if +$openprint::log->debug("Running $field with $$params{$field}") if $debug; + if ( my $func = $self->can( $field ) ) { + $func->( $self, $$params{$field} ); + } # end if + } # end if + } # end if + + if ( defined $fields{$field} ) { + if ( $$self{$field} ) { + $$self{$field} = transform( $type, $field, $$self{$field} ); + } # end if $$self{field} + } + } # end foreach field + + foreach my $field ( keys %defaults ) { + + if ( ( ! exists $$self{$field} ) or (!defined $$self{$field}) or ( $$self{$field} eq '' ) ) { + $log->debug("Setting default ($field) ($$self{$field}) ($defaults{$field}) ") if $debug; + if ( defined $defaults{$field} ) { + $log->debug("Default $field is defined: $defaults{$field}") if $debug; + if ( $defaults{$field} eq 'NOW()' ) { + $$self{$field} = 'NOW()'; + } else { + $$self{$field} = eval($defaults{$field}); + $log->error( "Eval error of object default $field default ($defaults{$field}) Reason: " . $@ ) if $@; + } # end if + } else { + $$self{$field} = $defaults{$field}; + } # end if +#$$self{$field} = ( defined $defaults{$field} ) ? eval($defaults{$field}) : $defaults{$field}; + $log->debug("Setting default for ($field) using ($defaults{$field}) to ($$self{$field}) ") if $debug; + } # end if + } # end foreach default + return @set_fields; +} # end sub set + +sub transform { + my $type = ref $_[0]; + $type = $_[0] if ! $type; + my $fields = eval '\%'.$type.'::fields'; + my $value = $_[2]; + + if ( defined $$fields{$_[1]} ) { + my @transforms = eval('@{$'.$type.'::transforms{$_[1]}}'); + $openprint::log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug; + if ( @transforms ) { + foreach my $transform ( @transforms ) { + if ( $transform =~ /^s\// or $transform =~ /^tr\// ) { + eval '$value =~ ' . $transform; + } elsif ( $transform =~ /^<(\d+)/ ) { + if ( $value > $1 ) { + $value = undef; + } # end if + } else { + $openprint::log->debug("evalling $value ".$transform . " Now value is $value" ); + eval '$value '.$transform; + $openprint::log->error("Eval error $@") if $@; + } + $openprint::log->debug("After $transform: $value") if $debug; + } # end foreach + } # end if + } else { + $openprint::log->error("Object::transform ($_[1]) not in fields for $type"); + } # end if + return $value; + +} # end sub transform 1; __END__ From 2d6998ad2577dcd2cd79bd441ef8c9b4d57ca602 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 15:21:10 -0700 Subject: [PATCH 18/80] fix debug_all --- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index af4d9fd21..a2d9fa021 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -48,6 +48,7 @@ use vars qw/ $AUTOLOAD $log $dbh/; *dbh = \$ZoneMinder::Database::dbh; my $debug = 1; +use constant DEBUG_ALL=>0; sub new { my ( $parent, $id, $data ) = @_; From 2003798e6406fc4afd23c6889a4bb290de1692cc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 21:06:11 -0700 Subject: [PATCH 19/80] copy in start and end transaction --- scripts/ZoneMinder/lib/ZoneMinder/Database.pm | 24 +++++++++++++++++++ scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 14 +++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index 8d752600d..bd0877e0e 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 ) { + $log->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/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index a2d9fa021..dfcc02ea9 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"); @@ -200,7 +200,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 +215,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 ) { @@ -247,7 +247,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 ) { @@ -264,7 +264,7 @@ $log->debug("No serial") if $debug; $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 +273,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}} ) { From b3d65729daa73329b3091c40f84920690bfe5aa7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 21:13:01 -0700 Subject: [PATCH 20/80] apache style logging function take a logging object --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index d0d6b234b..8bdbe3f7f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -678,7 +678,7 @@ sub Dump { fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) ); } -sub debug { fetch()->logPrint( DEBUG, @_ ); } +sub debug { $_[0]->logPrint( DEBUG, @_ ); } sub Debug( @ ) { fetch()->logPrint( DEBUG, @_ ); @@ -688,7 +688,7 @@ sub Info( @ ) { fetch()->logPrint( INFO, @_ ); } sub info { - fetch()->logPrint( INFO, @_ ); + $_[0]->logPrint( INFO, @_ ); } @@ -696,14 +696,14 @@ sub Warning( @ ) { fetch()->logPrint( WARNING, @_ ); } sub warn { - fetch()->logPrint( WARNING, @_ ); + $_[0]->logPrint( WARNING, @_ ); } sub Error( @ ) { fetch()->logPrint( ERROR, @_ ); } sub error { - fetch()->logPrint( ERROR, @_ ); + $_[0]->logPrint( ERROR, @_ ); } sub Fatal( @ ) { From ae8bfadcf79adb624fd14d377100fb9b4b756d01 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 21:13:14 -0700 Subject: [PATCH 21/80] use static logging method --- scripts/ZoneMinder/lib/ZoneMinder/Database.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index bd0877e0e..19a5f8662 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -220,7 +220,7 @@ sub end_transaction { #$openprint::log->debug("Called end_transaction from $caller : $line"); my ( $d, $ac ) = @_; if ( ! defined $ac ) { - $log->error("Undefined ac"); + Error("Undefined ac"); } $d = $dbh if ! $d; if ( $ac ) { From f420dde04dbbf6eff4f1d5a739c0c7f006867787 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 09:05:08 -0400 Subject: [PATCH 22/80] fix quotes --- db/zm_update-1.31.12.sql | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/db/zm_update-1.31.12.sql b/db/zm_update-1.31.12.sql index deb97c777..f99ea708c 100644 --- a/db/zm_update-1.31.12.sql +++ b/db/zm_update-1.31.12.sql @@ -25,15 +25,15 @@ EXECUTE stmt; 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"} }' );" +"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('Freeform', '{\"default\":{\"float\":\"left\"}}');" ) ); 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", "width":"49%"} }' );"; +"SELECT '2 Wide already in layouts'", +"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('2 Wide', '{\"default\":{\"float\":\"left\",\"width\":\"49%\"}}');" ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -41,7 +41,7 @@ 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", "width":"33%"} }' );" +"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ \"default\":{\"float\":\"left\", \"width\":\"33%\"} }');" ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -49,15 +49,16 @@ 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", "width":"24.5%"} }' );" +"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ \"default\":{\"float\":\"left\", \"width\":\"24.5%\"} }' );" ) ); 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", "width":"19%"} }' );" + "INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ \"default\":{\"float\":\"left\", \"width\":\"19%\"} }' );" ) ); PREPARE stmt FROM @s; From a6c790b374da753c6a96abe1f33e213bfa6a79be Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 07:37:08 -0700 Subject: [PATCH 23/80] use a shared include for the filters bar --- db/zm_create.sql.in | 2 + web/includes/database.php | 4 +- web/index.php | 2 +- web/skins/classic/views/_monitor_filters.php | 144 +++++++++++++ web/skins/classic/views/console.php | 203 ++++--------------- web/skins/classic/views/js/montage.js | 14 ++ web/skins/classic/views/montage.php | 118 +---------- 7 files changed, 211 insertions(+), 276 deletions(-) create mode 100644 web/skins/classic/views/_monitor_filters.php diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index b422d2936..f509c070f 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -776,6 +776,8 @@ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%"} }' ); INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%"} }' ); +INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('Fixed', '{ "default":{"float":"none", "position":"absolute"} }' ); + -- -- Apply the initial configuration -- diff --git a/web/includes/database.php b/web/includes/database.php index 483df64a5..21c6092dd 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -128,9 +128,9 @@ function dbQuery( $sql, $params=NULL ) { $result = $dbConn->query( $sql ); } 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) ); } diff --git a/web/index.php b/web/index.php index 7fa8790a5..501cbe557 100644 --- a/web/index.php +++ b/web/index.php @@ -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'], diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php new file mode 100644 index 000000000..e1063b484 --- /dev/null +++ b/web/skins/classic/views/_monitor_filters.php @@ -0,0 +1,144 @@ +Id()] = $S; +} +session_start(); +foreach ( array('ServerFilter','StorageFilter','StatusFilter','MonitorId') as $var ) { + if ( isset( $_REQUEST[$var] ) ) { + if ( $_REQUEST[$var] != '' ) { + $_SESSION[$var] = $_REQUEST[$var]; + } else { + unset( $_SESSION[$var] ); + } + } else if ( isset( $_COOKIE[$var] ) ) { + if ( $_COOKIE[$var] != '' ) { + $_SESSION[$var] = $_COOKIE[$var]; + } else { + unset($_SESSION[$var]); + } + } +} +session_write_close(); + +$storage_areas = Storage::find_all(); +$StorageById = array(); +foreach ( $storage_areas as $S ) { + $StorageById[$S->Id()] = $S; +} + +?> +
+ + + + +'All'); + + if ( $monitor_id ) { + $found_selected_monitor = false; + + for ( $i = 0; $i < count($monitors); $i++ ) { + if ( !visibleMonitor( $monitors[$i]['Id'] ) ) { + continue; + } + $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name']; + if ( $monitors[$i]['Id'] == $monitor_id ) { + $found_selected_monitor = true; + } + } + if ( ! $found_selected_monitor ) { + $monitor_id = ''; + } + } + for ( $i = 0; $i < count($monitors); $i++ ) { + if ( !visibleMonitor( $monitors[$i]['Id'] ) ) { + continue; + } + $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name']; + + if ( $monitor_id and ( $monitors[$i]['Id'] != $monitor_id ) ) { + continue; + } + $displayMonitors[] = $monitors[$i]; + } + echo htmlSelect( 'MonitorId', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') ); +?> + + 0 ) { +?> + +'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') ); +?> + + 0 ) { ?> + +'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') ); +?> + + + +'All', + 'Unknown' => translate('Unknown'), + 'NotRunning' => translate('NotRunning'), + 'Running' => translate('Running'), + ); +echo htmlSelect( 'StatusFilter', $status_options, ( isset($_SESSION['StatusFilter']) ? $_SESSION['StatusFilter'] : '' ), array('onchange'=>'changeFilter(this);') ); +?> + +
diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 7e9094cb8..4e4d1af5c 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -18,36 +18,6 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -$servers = Server::find_all(); -$ServersById = array(); -foreach ( $servers as $S ) { - $ServersById[$S->Id()] = $S; -} -session_start(); -foreach ( array('ServerFilter','StorageFilter') as $var ) { - if ( isset( $_REQUEST[$var] ) ) { - if ( $_REQUEST[$var] != '' ) { - $_SESSION[$var] = $_REQUEST[$var]; - } else { - unset( $_SESSION[$var] ); - } - } else if ( isset( $_COOKIE[$var] ) ) { - if ( $_COOKIE[$var] != '' ) { - $_SESSION[$var] = $_COOKIE[$var]; - } else { - unset($_SESSION[$var]); - } - } -} -session_write_close(); - -$storage_areas = Storage::find_all(); -$StorageById = array(); -foreach ( $storage_areas as $S ) { - $StorageById[$S->Id()] = $S; -} - -$show_storage_areas = count($storage_areas) > 1 and canEdit( 'System' ) ? 1 : 0; if ( $running == null ) $running = daemonCheck(); @@ -120,6 +90,45 @@ $eventCounts = array( $navbar = getNavBarHTML(); +ob_start(); +include('_monitor_filters.php'); +$filterbar = ob_get_contents(); +ob_end_clean(); + +$show_storage_areas = count($storage_areas) > 1 and canEdit( 'System' ) ? 1 : 0; +$maxWidth = 0; +$maxHeight = 0; +$zoneCount = 0; +for ( $i = 0; $i < count($displayMonitors); $i++ ) { + $monitor = &$displayMonitors[$i]; + if ( $monitor['Function'] != 'None' ) { + $scaleWidth = reScale( $monitor['Width'], $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); + $scaleHeight = reScale( $monitor['Height'], $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); + if ( $maxWidth < $scaleWidth ) $maxWidth = $scaleWidth; + if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight; + } + $monitor['zmc'] = zmcStatus( $monitor ); + $monitor['zma'] = zmaStatus( $monitor ); + $monitor['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitor['Id']) ); + $zoneCount += $monitor['ZoneCount']; + + $counts = array(); + for ( $j = 0; $j < count($eventCounts); $j += 1 ) { + $filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) ); + parseFilter( $filter ); + $counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) AS EventCount$j, SUM(if(1".$filter['sql'].",DiskSpace,NULL)) As DiskSpace$j"; + $monitor['eventCounts'][$j]['filter'] = $filter; + } + $sql = 'SELECT '.join($counts,', ').' FROM Events as E where MonitorId = ?'; + $counts = dbFetchOne( $sql, NULL, array($monitor['Id']) ); + if ( $counts ) + $displayMonitors[$i] = $monitor = array_merge( $monitor, $counts ); + for ( $j = 0; $j < count($eventCounts); $j += 1 ) { + $eventCounts[$j]['total'] += $monitor['EventCount'.$j]; + } +} +$cycleWidth = $maxWidth; +$cycleHeight = $maxHeight; noCacheHeaders(); @@ -137,139 +146,7 @@ xhtmlHeaders( __FILE__, translate('Console') ); -
- - - - -'All'); - - if ( $monitor_id ) { - $found_selected_monitor = false; - - for ( $i = 0; $i < count($monitors); $i++ ) { - if ( !visibleMonitor( $monitors[$i]['Id'] ) ) { - continue; - } - $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name']; - if ( $monitors[$i]['Id'] == $monitor_id ) { - $found_selected_monitor = true; - } - } - if ( ! $found_selected_monitor ) { - $monitor_id = ''; - } - } - for ( $i = 0; $i < count($monitors); $i++ ) { - if ( !visibleMonitor( $monitors[$i]['Id'] ) ) { - continue; - } - $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name']; - - if ( $monitor_id and ( $monitors[$i]['Id'] != $monitor_id ) ) { - continue; - } - if ( $monitors[$i]['Function'] != 'None' ) { - $scaleWidth = reScale( $monitors[$i]['Width'], $monitors[$i]['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); - $scaleHeight = reScale( $monitors[$i]['Height'], $monitors[$i]['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); - if ( $maxWidth < $scaleWidth ) $maxWidth = $scaleWidth; - if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight; - } - $displayMonitors[] = $monitors[$i]; - } - - - echo htmlSelect( 'monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') ); - - $cycleWidth = $maxWidth; - $cycleHeight = $maxHeight; - $zoneCount = 0; - -for( $i = 0; $i < count($displayMonitors); $i += 1 ) { - $monitor = $displayMonitors[$i]; - $monitor['zmc'] = zmcStatus( $monitor ); - $monitor['zma'] = zmaStatus( $monitor ); - $monitor['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitor['Id']) ); - $counts = array(); - for ( $j = 0; $j < count($eventCounts); $j += 1 ) { - $filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) ); - parseFilter( $filter ); - $counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) AS EventCount$j, SUM(if(1".$filter['sql'].",DiskSpace,NULL)) As DiskSpace$j"; - $monitor['eventCounts'][$j]['filter'] = $filter; - } - $sql = 'SELECT '.join($counts,', ').' FROM Events as E where MonitorId = ?'; - $counts = dbFetchOne( $sql, NULL, array($monitor['Id']) ); - if ( $counts ) - $displayMonitors[$i] = $monitor = array_merge( $monitor, $counts ); - for ( $j = 0; $j < count($eventCounts); $j += 1 ) { - $eventCounts[$j]['total'] += $monitor['EventCount'.$j]; - } - $zoneCount += $monitor['ZoneCount']; -} -?> - - 0 ) { ?> - -'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') ); -?> - - 0 ) { ?> - -'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') ); -?> - - - -'All', - 'Unknown' => translate('Unknown'), - 'NotRunning' => translate('NotRunning'), - 'Running' => translate('Running'), - ); -echo htmlSelect( 'StatusFilter', $status_options, ( isset($_SESSION['StatusFilter']) ? $_SESSION['StatusFilter'] : '' ), array('onchange'=>'changeFilter(this);') ); -?> - -
+
diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index c2f96258c..a497c408b 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -305,6 +305,20 @@ function initPage() { } }); } +function edit_layout(button) { + for ( var x = 0; x < monitors.length; x++ ) { + var monitor = monitors[x]; + + // Scale the frame + monitor_frame = $j('#monitorFrame'+monitor.id); + if ( ! monitor_frame ) { + console.log("Error finding frame for " + monitor.id ); + continue; + } + monitor_frame.css('float','none'); + monitor_frame.css('position','absolute'); + } // end foreach monitor +} // Kick everything off window.addEvent( 'domready', initPage ); diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index fe9d688e0..dc9dd7682 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -96,106 +96,25 @@ if ( $scale ) $options['scale'] = $scale; ob_start(); -# This will end up with the group_id of the deepest selection -$group_id = Group::get_group_dropdowns(); -$group_dropdowns = ob_get_contents(); +include('_monitor_filters.php'); +$filterbar = ob_get_contents(); ob_end_clean(); -$groupSql = Group::get_group_sql( $group_id ); - -$servers = Server::find_all(); -$ServersById = array(); -foreach ( $servers as $S ) { - $ServersById[$S->Id()] = $S; -} -session_start(); -foreach ( array('ServerFilter','StorageFilter') as $var ) { - if ( isset( $_REQUEST[$var] ) ) { - if ( $_REQUEST[$var] != '' ) { - $_SESSION[$var] = $_REQUEST[$var]; - } else { - unset( $_SESSION[$var] ); - } - } else if ( isset( $_COOKIE[$var] ) ) { - if ( $_COOKIE[$var] != '' ) { - $_SESSION[$var] = $_COOKIE[$var]; - } else { - unset($_SESSION[$var]); - } - } -} -session_write_close(); - -$storage_areas = Storage::find_all(); -$StorageById = array(); -foreach ( $storage_areas as $S ) { - $StorageById[$S->Id()] = $S; -} - -$monitor_id = 0; -if ( isset( $_REQUEST['monitor_id'] ) ) { - $monitor_id = $_REQUEST['monitor_id']; -} else if ( isset($_COOKIE['zmMonitorId']) ) { - $monitor_id = $_COOKIE['zmMonitorId']; -} - $monitors = array(); -$monitors_dropdown = array( '' => 'All' ); - $conditions = array(); - $values = array(); - - if ( $groupSql ) - $conditions[] = $groupSql; - if ( isset($_SESSION['ServerFilter']) ) { - $conditions[] = 'ServerId=?'; - $values[] = $_SESSION['ServerFilter']; - } - if ( isset($_SESSION['StorageFilter']) ) { - $conditions[] = 'StorageId=?'; - $values[] = $_SESSION['StorageFilter']; - } - $sql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC'; - $monitor_rows = dbFetchAll( $sql, null, $values ); - - if ( $monitor_id ) { - $found_selected_monitor = false; - - for ( $i = 0; $i < count($monitor_rows); $i++ ) { - if ( !visibleMonitor( $monitor_rows[$i]['Id'] ) ) { - continue; - } - $monitors_dropdown[$monitor_rows[$i]['Id']] = $monitor_rows[$i]['Name']; - if ( $monitor_rows[$i]['Id'] == $monitor_id ) { - $found_selected_monitor = true; - } - } - if ( ! $found_selected_monitor ) { - $monitor_id = ''; - } - } - -$monitors = array(); -foreach( $monitor_rows as $row ) { - if ( !visibleMonitor( $row['Id'] ) ) { - continue; - } - if ( $monitor_id and $row['Id'] != $monitor_id ) - continue; - +foreach( $displayMonitors as &$row ) { $row['Scale'] = $scale; $row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); if ( ZM_OPT_CONTROL && $row['ControlId'] && $row['Controllable'] ) $showControl = true; $row['connKey'] = generateConnKey(); - $Monitor = $monitors[] = new Monitor( $row ); - $monitors_dropdown[$Monitor->Id()] = $Monitor->Name(); if ( ! isset( $widths[$row['Width']] ) ) { $widths[$row['Width']] = $row['Width']; } if ( ! isset( $heights[$row['Height']] ) ) { $heights[$row['Height']] = $row['Height']; } + $monitors[] = new Monitor( $row ); } # end foreach Monitor xhtmlHeaders(__FILE__, translate('Montage') ); @@ -222,31 +141,8 @@ if ( $showZones ) { } ?> -
- - - - - 'changeMonitor(this);') ); ?> - - 0 ) { ?> - -'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') ); -?> - - 0 ) { ?> - -'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') ); -?> - - -
+ +
@@ -254,6 +150,8 @@ echo htmlSelect( 'StorageFilter', array(''=>'All')+$StorageById, (isset($_SESSIO + +
From 01acd154f93f6c7c54ae4acde54ce74bdd08d717 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 16:28:55 -0400 Subject: [PATCH 24/80] fix adding Layouts --- db/zm_update-1.31.12.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/zm_update-1.31.12.sql b/db/zm_update-1.31.12.sql index f99ea708c..2f5be2e15 100644 --- a/db/zm_update-1.31.12.sql +++ b/db/zm_update-1.31.12.sql @@ -25,7 +25,7 @@ EXECUTE stmt; 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\"}}');" +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'Freeform\', \'{"default":{"float":"left"}}\');' ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -33,7 +33,7 @@ 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\",\"width\":\"49%\"}}');" +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'2 Wide\', \'{"default":{"float":"left","width":"49%"}}\');' ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -41,7 +41,7 @@ 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\", \"width\":\"33%\"} }');" +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'3 Wide\', \'{ "default":{"float":"left", "width":"33%"} }\');' ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -49,7 +49,7 @@ 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\", \"width\":\"24.5%\"} }' );" +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'4 Wide\', \'{ "default":{"float":"left", "width":"24.5%"} }\');' ) ); PREPARE stmt FROM @s; From 97757ba6cdfd84f1c9cbb3f8443aa39fc91d5123 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 16:29:13 -0400 Subject: [PATCH 25/80] add Inserting when saving --- web/includes/MontageLayout.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/web/includes/MontageLayout.php b/web/includes/MontageLayout.php index fd105a8cd..ef915a069 100644 --- a/web/includes/MontageLayout.php +++ b/web/includes/MontageLayout.php @@ -111,10 +111,17 @@ class MontageLayout { $this->{$k} = $v; } } - - $sql = 'UPDATE MontageLayouts 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'}; + + $fields = array_keys( $this->defaults ); + $values = null; + if ( $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'}; + } 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 ); } // end function save From 1694eeb43686b19141d8394977d30484fb89bcd9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 16:29:27 -0400 Subject: [PATCH 26/80] debugging and code simplification --- web/includes/actions.php | 1703 +++++++++++++++++++------------------- 1 file changed, 861 insertions(+), 842 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 41bfe81ad..f8c1045e7 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -17,7 +17,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // - +warning("Un error"); // PP - POST request handler for PHP which does not need extensions // credit: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/ @@ -78,856 +78,875 @@ 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) ) { + Warning("No action"); + return; +} +Warning("Have action $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"); + } } - } - } 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'] ) ) { + Warning("Have object: " . $_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'] ); + } + Warning("Positions: " . $_REQUEST['Positions'] ); + $Layout->Positions( $_REQUEST['Positions'] ); + $Layout->save(); + } // 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(); +} + ?> From 207b66c8fa3a65649f7435a81eb0cf541960c830 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 16:29:46 -0400 Subject: [PATCH 27/80] add Edit Layout --- web/lang/en_gb.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 45132b72f..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', From c69e2468b09ba66a4ce5ee5b954fa09482e9b13f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 16:30:15 -0400 Subject: [PATCH 28/80] add edit and save layout --- web/skins/classic/views/js/montage.js | 111 ++++++++++++++------------ web/skins/classic/views/montage.php | 69 ++++++++-------- 2 files changed, 94 insertions(+), 86 deletions(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index a497c408b..b7196d302 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -13,6 +13,7 @@ function Monitor( monitorData ) { this.streamCmdTimer = null; this.start = function( delay ) { + console.log(delay); this.streamCmdTimer = this.streamCmdQuery.delay( delay, this ); }; @@ -32,7 +33,7 @@ function Monitor( monitorData ) { if ( this.streamCmdTimer ) this.streamCmdTimer = clearTimeout( this.streamCmdTimer ); - var stream = $j('#liveStream'+this.id )[0]; + var stream = $j('#liveStream'+this.id)[0]; if ( respObj.result == 'Ok' ) { this.status = respObj.status; this.alarmState = this.status.state; @@ -81,9 +82,10 @@ function Monitor( monitorData ) { // Try to reload the image stream. if ( stream ) stream.src = stream.src.replace( /auth=\w+/i, 'auth='+this.status.auth ); - console.log("Changed auth to " + this.status.auth ); + console.log("Changed auth from " + auth_hash + " to " + this.status.auth ); + auth_hash = this.status.auth; } - } // end if haev a new auth hash + } // end if have a new auth hash } else { console.error( respObj.message ); // Try to reload the image stream. @@ -93,7 +95,7 @@ function Monitor( monitorData ) { } else { console.log( 'No stream to reload?' ); } - } + } // end if Ok or not var streamCmdTimeout = statusRefreshTimeout; if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) streamCmdTimeout = streamCmdTimeout/5; @@ -114,11 +116,10 @@ function Monitor( monitorData ) { } function selectLayout( element ) { - layout = $(element).get('value'); + layout = $j(element).val(); if ( layout_id = parseInt(layout) ) { layout = layouts[layout]; -console.log("Have layout # " + layout_id); for ( var i = 0; i < monitors.length; i++ ) { monitor = monitors[i]; @@ -134,7 +135,6 @@ console.log("Have layout # " + layout_id); if ( layout.default ) { styles = layout.default; for ( style in styles ) { -console.log("applying " + style + ': ' + styles[style]); monitor_frame.css(style, styles[style]); } } // end if default styles @@ -142,7 +142,6 @@ console.log("applying " + style + ': ' + styles[style]); if ( layout[monitor.id] ) { styles = layout[monitor.id]; for ( style in styles ) { -console.log("applying " + style + ': ' + styles[style]); monitor_frame.css(style, styles[style]); } } // end if specific monitor style @@ -152,7 +151,7 @@ console.log("applying " + style + ': ' + styles[style]); return; } Cookie.write( 'zmMontageLayout', layout_id, { duration: 10*365 } ); - if ( layout_id != 1 ) { // 'montage_freeform.css' ) { + if ( layouts[layout_id].Name != 'Freeform' ) { // 'montage_freeform.css' ) { Cookie.write( 'zmMontageScale', '', { duration: 10*365 } ); $('scale').set('value', '' ); $('width').set('value', ''); @@ -260,52 +259,15 @@ function changeScale() { Cookie.write( 'zmMontageHeight', '', { duration: 10*365 } ); } -var monitors = new Array(); -function initPage() { - for ( var i = 0; i < monitorData.length; i++ ) { - monitors[i] = new Monitor( monitorData[i] ); - var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); - monitors[i].start( delay ); - } - selectLayout($('layout')); - - $j('#monitors .monitorFrame').draggable({ - cursor: 'crosshair', - revert: 'invalid' - }); - - function toGrid(value) { - return Math.round(value / 80) * 80; - } - - $j('#monitors').droppable({ - accept: '#monitors .monitorFrame', - drop: function(event, ui) { - //console.log(event); - $j(this).removeClass('border over'); - $j(ui.draggable).detach(). - appendTo($j(this).find('ul')). - draggable({ - containment: '.fw-content', - cursor: 'help', - grid: [ 80, 80 ] - }). - css({ - position: 'absolute', - left: toGrid(event.clientX - $j('#monitors').offset().left), - top: toGrid(event.clientY - $j('#monitors').offset().top) - }); - }, - over: function(event, elem) { - console.log('over'); - $j(this).addClass('over'); - }, - out: function(event, elem) { - $j(this).removeClass('over'); - } - }); +function toGrid(value) { + return Math.round(value / 80) * 80; } + + +// Makes monitorFrames draggable. function edit_layout(button) { + console.log("edit click"); + for ( var x = 0; x < monitors.length; x++ ) { var monitor = monitors[x]; @@ -318,7 +280,50 @@ function edit_layout(button) { monitor_frame.css('float','none'); monitor_frame.css('position','absolute'); } // end foreach monitor + + $j('#monitors .monitorFrame').draggable({ + cursor: 'crosshair', + //revert: 'invalid' + }); + $j('#SaveLayout').show(); + $j('#EditLayout').hide(); +} // end function edit_layout + +function save_layout(button) { + var form=button.form; + var Positions = new Array(); + for ( var x = 0; x < monitors.length; x++ ) { + var monitor = monitors[x]; + monitor_frame = $j('#monitorFrame'+monitor.id); + + Positions[monitor.id] = { + width: monitor_frame.css('width'), + height: monitor_frame.css('width'), + top: monitor_frame.css('top'), + bottom: monitor_frame.css('bottom'), + left: monitor_frame.css('left'), + right: monitor_frame.css('right'), + position: monitor_frame.css('position'), + float: monitor_frame.css('float'), + }; + } // end foreach monitor + form.Positions.value = JSON.stringify( Positions ); + form.submit(); +} +function cancel_layout(button) { + $j('#SaveLayout').hide(); + $j('#EditLayout').show(); } +var monitors = new Array(); +function initPage() { + for ( var i = 0; i < monitorData.length; i++ ) { + monitors[i] = new Monitor(monitorData[i]); + var delay = Math.round( (Math.random()+0.75)*statusRefreshTimeout ); + console.log("delay: " + delay); + //monitors[i].start(delay); + } + selectLayout('#zmMontageLayout'); +} // Kick everything off window.addEvent( 'domready', initPage ); diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index dc9dd7682..ae841de18 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -59,20 +59,6 @@ if ( isset( $_REQUEST['scale'] ) ) { if ( ! $scale ) $scale = 100; -$focusWindow = true; - -/* -$layouts = array( - 'montage_freeform.css' => translate('MtgDefault'), - 'montage_2wide.css' => translate('Mtg2widgrd'), - 'montage_3wide.css' => translate('Mtg3widgrd'), - 'montage_4wide.css' => translate('Mtg4widgrd'), - 'montage_3wide50enlarge.css' => translate('Mtg3widgrx'), -); -foreach ( MontageLayout::find() as $Layout ) { - $layouts[$Layout->Id()] = $Layout->Name(); -} -*/ $layouts = MontageLayout::find(NULL, array('order'=>"lower('Name')")); $layoutsById = array(); foreach ( $layouts as $l ) { @@ -83,15 +69,23 @@ $layout = ''; if ( isset($_COOKIE['zmMontageLayout']) ) $layout = $_COOKIE['zmMontageLayout']; +session_start(); $options = array(); -if ( isset($_COOKIE['zmMontageWidth']) and $_COOKIE['zmMontageWidth'] ) - $options['width'] = $_COOKIE['zmMontageWidth']; -else +if ( isset($_COOKIE['zmMontageWidth']) and $_COOKIE['zmMontageWidth'] ) { + $_SESSION['zmMontageWidth'] = $options['width'] = $_COOKIE['zmMontageWidth']; +} elseif ( isset($_SESSION['zmMontageWidth']) and $_SESSION['zmMontageWidth'] ) { + $options['width'] = $_SESSION['zmMontageWidth']; +} else $options['width'] = ''; + if ( isset($_COOKIE['zmMontageHeight']) and $_COOKIE['zmMontageHeight'] ) - $options['height'] = $_COOKIE['zmMontageHeight']; + $_SESSION['zmMontageHeight'] = $options['height'] = $_COOKIE['zmMontageHeight']; +else if ( isset($_SESSION['zmMontageHeight']) and $_SESSION['zmMontageHeight'] ) + $options['height'] = $_SESSION['zmMontageHeight']; else $options['height'] = ''; +session_write_close(); + if ( $scale ) $options['scale'] = $scale; @@ -102,6 +96,9 @@ ob_end_clean(); $monitors = array(); foreach( $displayMonitors as &$row ) { + if ( $row['Function'] == 'None' ) + continue; + $row['Scale'] = $scale; $row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); @@ -143,15 +140,24 @@ if ( $showZones ) {
- - - - - - - - - +
+ + + + + + + + 'selectLayout(this);', 'id'=>'zmMontageLayout') ); ?> + + + + +
@@ -160,7 +166,7 @@ if ( $showZones ) { foreach ( $monitors as $monitor ) { $connkey = $monitor->connKey(); // Minor hack ?> -
+
- - '; } // end foreach zone ?> Sorry, your browser does not support inline SVG From efe8b2db7e31ae35f94ad721a19f3d67108783f1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 16:32:03 -0400 Subject: [PATCH 29/80] update code because we are now including the entire object in the layouts array --- web/skins/classic/views/js/montage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index b7196d302..9898866cf 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -140,7 +140,7 @@ function selectLayout( element ) { } // end if default styles if ( layout[monitor.id] ) { - styles = layout[monitor.id]; + styles = layout[monitor.id].Positions; for ( style in styles ) { monitor_frame.css(style, styles[style]); } From 52110adfa9aa215902409f22fe29c9dfb0ef3bce Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 16:32:14 -0400 Subject: [PATCH 30/80] update code because we are now including the entire object in the layouts array --- web/skins/classic/views/js/montage.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index 7aba1e4fb..a3c8d479e 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -45,7 +45,7 @@ layouts[0] = {}; // reserved, should hold which fields to clear when transitioni -layouts[Id() ?>] = Positions() ?>; +layouts[Id() ?>] = ; From ce6cc24de5102948bbc637f8dac6302a03c03c37 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 20:20:40 -0400 Subject: [PATCH 31/80] turn off debug --- web/includes/database.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/web/includes/database.php b/web/includes/database.php index 21c6092dd..bbfd588b0 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -122,15 +122,24 @@ 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) . ' rows: '.$result->rowCount() ); else Warning("SQL: $sql: rows:" . $result->rowCount() ); +} } catch(PDOException $e) { Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . implode(',',$params) ); } From b5491102efb8b533a225c9c1836bc1076dd2cbb5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 20:21:16 -0400 Subject: [PATCH 32/80] Fix saving MontageLayouts --- db/zm_update-1.31.12.sql | 6 ++--- web/includes/MontageLayout.php | 4 ++-- web/includes/actions.php | 15 +++++-------- web/index.php | 2 -- web/skins/classic/views/js/montage.js | 27 ++++++++++++++--------- web/skins/classic/views/js/montage.js.php | 2 +- web/skins/classic/views/montage.php | 3 ++- 7 files changed, 29 insertions(+), 30 deletions(-) diff --git a/db/zm_update-1.31.12.sql b/db/zm_update-1.31.12.sql index 2f5be2e15..6a43d697c 100644 --- a/db/zm_update-1.31.12.sql +++ b/db/zm_update-1.31.12.sql @@ -41,7 +41,7 @@ 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", "width":"33%"} }\');' +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'3 Wide\', \'{"default":{"float":"left","width":"33%"}}\');' ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -49,7 +49,7 @@ 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", "width":"24.5%"} }\');' +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'4 Wide\', \'{"default":{"float":"left","width":"24.5%"}}\');' ) ); PREPARE stmt FROM @s; @@ -58,7 +58,7 @@ 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\", \"width\":\"19%\"} }' );" + "INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{\"default\":{\"float\":\"left\",\"width\":\"19%\"}}' );" ) ); PREPARE stmt FROM @s; diff --git a/web/includes/MontageLayout.php b/web/includes/MontageLayout.php index ef915a069..6f1fdf161 100644 --- a/web/includes/MontageLayout.php +++ b/web/includes/MontageLayout.php @@ -112,9 +112,9 @@ class MontageLayout { } } - $fields = array_keys( $this->defaults ); + $fields = array_values( array_filter( array_keys($this->defaults), function($field){return $field != 'Id';} ) ); $values = null; - if ( $this->{'Id'} ) { + 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'}; diff --git a/web/includes/actions.php b/web/includes/actions.php index f8c1045e7..08496809f 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -warning("Un error"); // PP - POST request handler for PHP which does not need extensions // credit: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/ @@ -79,10 +78,8 @@ function getAffectedIds( $name ) { if ( empty($action) ) { - Warning("No action"); return; } -Warning("Have action $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 @@ -90,15 +87,15 @@ if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 're && 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) + && 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'] + 'secret' => ZM_OPT_GOOG_RECAPTCHA_SECRETKEY, + 'response' => $_REQUEST['g-recaptcha-response'], + 'remoteip' => $_SERVER['REMOTE_ADDR'] ); - $res= do_post_request($url, http_build_query($fields)); + $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 @@ -685,7 +682,6 @@ if ( canEdit( 'Groups' ) ) { // System edit actions if ( canEdit( 'System' ) ) { if ( isset( $_REQUEST['object'] ) ) { - Warning("Have object: " . $_REQUEST['object']); if ( $_REQUEST['object'] == 'MontageLayout' ) { require_once('MontageLayout.php'); if ( $action == 'Save' ) { @@ -696,7 +692,6 @@ if ( canEdit( 'System' ) ) { } else { $Layout = new MontageLayout( $_REQUEST['zmMontageLayout'] ); } - Warning("Positions: " . $_REQUEST['Positions'] ); $Layout->Positions( $_REQUEST['Positions'] ); $Layout->save(); } // end if save diff --git a/web/index.php b/web/index.php index 501cbe557..1829f289b 100644 --- a/web/index.php +++ b/web/index.php @@ -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/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 9898866cf..72445f453 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -13,7 +13,6 @@ function Monitor( monitorData ) { this.streamCmdTimer = null; this.start = function( delay ) { - console.log(delay); this.streamCmdTimer = this.streamCmdQuery.delay( delay, this ); }; @@ -120,6 +119,7 @@ function selectLayout( element ) { if ( layout_id = parseInt(layout) ) { layout = layouts[layout]; + console.log(layout); for ( var i = 0; i < monitors.length; i++ ) { monitor = monitors[i]; @@ -132,18 +132,23 @@ function selectLayout( element ) { } // Apply default layout options, like float left - if ( layout.default ) { - styles = layout.default; + if ( layout.Positions['default'] ) { + styles = layout.Positions['default']; for ( style in styles ) { monitor_frame.css(style, styles[style]); } + } else { + console.log("No default styles to apply" + layout.Positions); } // end if default styles - if ( layout[monitor.id] ) { - styles = layout[monitor.id].Positions; + if ( layout.Positions['mId'+monitor.id] ) { + styles = layout.Positions['mId'+monitor.id]; for ( style in styles ) { monitor_frame.css(style, styles[style]); + console.log("Applying " + style + ' : ' + styles[style] ); } + } else { + console.log("No Monitor styles to apply"); } // end if specific monitor style } // end foreach monitor } // end if a stored layout @@ -291,14 +296,14 @@ function edit_layout(button) { function save_layout(button) { var form=button.form; - var Positions = new Array(); - for ( var x = 0; x < monitors.length; x++ ) { - var monitor = monitors[x]; + var Positions = {}; + for ( var i = 0; i < monitors.length; i++ ) { + var monitor = monitors[i]; monitor_frame = $j('#monitorFrame'+monitor.id); - Positions[monitor.id] = { + Positions['mId'+monitor.id] = { width: monitor_frame.css('width'), - height: monitor_frame.css('width'), + height: monitor_frame.css('height'), top: monitor_frame.css('top'), bottom: monitor_frame.css('bottom'), left: monitor_frame.css('left'), @@ -321,7 +326,7 @@ function initPage() { monitors[i] = new Monitor(monitorData[i]); var delay = Math.round( (Math.random()+0.75)*statusRefreshTimeout ); console.log("delay: " + delay); - //monitors[i].start(delay); + monitors[i].start(delay); } selectLayout('#zmMontageLayout'); } diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index a3c8d479e..9dca1cbb8 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -45,7 +45,7 @@ layouts[0] = {}; // reserved, should hold which fields to clear when transitioni -layouts[Id() ?>] = ; +layouts[Id() ?>] = {"Name":"Name()?>","Positions":Positions() ?>}; diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index ae841de18..60f605f16 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -142,6 +142,7 @@ if ( $showZones ) {
+ @@ -154,7 +155,7 @@ if ( $showZones ) { From 3deb8a35bbefa061deabf6d258eec6c6c21e7709 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 30 Oct 2017 21:38:27 -0400 Subject: [PATCH 33/80] fixes --- db/zm_update-1.31.12.sql | 10 +++++----- web/skins/classic/views/js/montage.js | 13 +++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/db/zm_update-1.31.12.sql b/db/zm_update-1.31.12.sql index 6a43d697c..733541c85 100644 --- a/db/zm_update-1.31.12.sql +++ b/db/zm_update-1.31.12.sql @@ -25,7 +25,7 @@ EXECUTE stmt; 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"}}\');' +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'Freeform\', \'{"default":{"float":"left","position":"relative"}}\');' ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -33,7 +33,7 @@ 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","width":"49%"}}\');' +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'2 Wide\', \'{"default":{"float":"left","position":"relative","width":"49%"}}\');' ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -41,7 +41,7 @@ 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","width":"33%"}}\');' +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'3 Wide\', \'{"default":{"float":"left","position":"relative","width":"33%"}}\');' ) ); PREPARE stmt FROM @s; EXECUTE stmt; @@ -49,7 +49,7 @@ 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","width":"24.5%"}}\');' +'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'4 Wide\', \'{"default":{"float":"left","position":"relative","width":"24.5%"}}\');' ) ); PREPARE stmt FROM @s; @@ -58,7 +58,7 @@ 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\",\"width\":\"19%\"}}' );" + 'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'5 Wide\', \'{"default":{"float":"left","position":"relative","width":"19%"}}\' );' ) ); PREPARE stmt FROM @s; diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 72445f453..45c57098c 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -268,6 +268,16 @@ function toGrid(value) { return Math.round(value / 80) * 80; } +function getOffset( el ) { + var _x = 0; + var _y = 0; + while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { + _x += el.offsetLeft - el.scrollLeft; + _y += el.offsetTop - el.scrollTop; + el = el.offsetParent; + } + return { top: _y, left: _x }; +} // Makes monitorFrames draggable. function edit_layout(button) { @@ -282,8 +292,11 @@ function edit_layout(button) { console.log("Error finding frame for " + monitor.id ); continue; } + var position = getOffset( monitor_frame ); monitor_frame.css('float','none'); monitor_frame.css('position','absolute'); + monitor_frame.css('top', position.top+'px' ); + monitor_frame.css('left', position.left+'px' ); } // end foreach monitor $j('#monitors .monitorFrame').draggable({ From c9d52b47ba92ff4f533c4ca3d399f9b2f6c95b77 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 31 Oct 2017 13:29:49 -0700 Subject: [PATCH 34/80] add debug --- src/zm_monitorstream.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 85b223f6a..d7b74b051 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 ) From 9473fbecd891120f1a64e774bcea98297f13f767 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 31 Oct 2017 13:32:42 -0700 Subject: [PATCH 35/80] more debug --- web/ajax/stream.php | 60 ++++++++++++++++++--------- web/skins/classic/views/js/montage.js | 2 +- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/web/ajax/stream.php b/web/ajax/stream.php index 2d4c3c612..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/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index c2f96258c..da97a6d9b 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -108,7 +108,7 @@ function Monitor( monitorData ) { this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); }; - this.streamCmdReq = new Request.JSON( { url: this.server_url, method: 'get', timeout: AJAX_TIMEOUT, onSuccess: this.getStreamCmdResponse.bind( this ), onTimeout: this.streamCmdQuery.bind( this, true ), link: 'cancel' } ); + this.streamCmdReq = new Request.JSON( { url: this.server_url, method: 'get', timeout: 1000+AJAX_TIMEOUT, onSuccess: this.getStreamCmdResponse.bind( this ), onTimeout: this.streamCmdQuery.bind( this, true ), link: 'cancel' } ); requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq ); } From e6918cd1bde0f547415d0e041ef793c54b5dc4b1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Nov 2017 09:41:19 -0400 Subject: [PATCH 36/80] implement crude cache busting code for .js and .css files --- web/includes/functions.php | 14 +++++++++++++- web/skins/classic/includes/functions.php | 10 +++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 012dc7760..c84eab8ed 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2060,6 +2060,18 @@ 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 + $cacheFile = '/cache/'.basename($file).'-'.filemtime($file); + 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; @@ -2068,7 +2080,7 @@ function getSkinFile( $file ) { if ( file_exists( $tempSkinFile ) ) $skinFile = $tempSkinFile; } - return( $skinFile ); + return $skinFile; } function getSkinIncludes( $file, $includeBase=false, $asOverride=false ) { diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 26cb1a26e..c2b5a14de 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -60,11 +60,11 @@ if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) { - + - + - + - + - + From 36e13039c7b18527a919596695582cf7f52be52c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Nov 2017 11:05:21 -0400 Subject: [PATCH 37/80] Switch to LONGTEXT FROM JSON type --- db/zm_create.sql.in | 3 +- db/zm_update-1.31.12.sql | 2 +- web/skins/classic/views/_monitor_filters.php | 6 ++ web/skins/classic/views/js/montage.js | 4 +- web/skins/classic/views/montagereview.php | 106 ++----------------- 5 files changed, 22 insertions(+), 99 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index f509c070f..e2f661bfd 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -766,7 +766,8 @@ CREATE TABLE Maps ( CREATE TABLE MontageLayouts ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` TEXT NOT NULL, - `Positions` JSON, + `Positions` LONGTEXT, + /*`Positions` JSON,*/ PRIMARY KEY (`Id`) ); diff --git a/db/zm_update-1.31.12.sql b/db/zm_update-1.31.12.sql index 733541c85..f20ccff2e 100644 --- a/db/zm_update-1.31.12.sql +++ b/db/zm_update-1.31.12.sql @@ -13,7 +13,7 @@ SET @s = (SELECT IF( CREATE TABLE MontageLayouts ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` TEXT NOT NULL, - `Positions` JSON, + `Positions` LONGTEXT, PRIMARY KEY (`Id`) ); " diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index e1063b484..231e4bdce 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -76,6 +76,12 @@ $groupSql = Group::get_group_sql( $group_id ); $conditions[] = 'StorageId=?'; $values[] = $_SESSION['StorageFilter']; } + if ( ! empty( $user['MonitorIds'] ) ) { + $ids = explode(',', $user['MonitorIds'] ); + $conditions[] = 'Id IN ('.implode(',',array_map( function(){return '?';}, $ids) ).')'; + $values += $ids; + } + $sql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC'; $monitors = dbFetchAll( $sql, null, $values ); $displayMonitors = array(); diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index e5801a2d2..1d8f867be 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -293,10 +293,10 @@ function edit_layout(button) { continue; } var position = getOffset( monitor_frame ); - monitor_frame.css('float','none'); - monitor_frame.css('position','absolute'); monitor_frame.css('top', position.top+'px' ); monitor_frame.css('left', position.left+'px' ); + monitor_frame.css('float','none'); + monitor_frame.css('position','absolute'); } // end foreach monitor $j('#monitors .monitorFrame').draggable({ diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 2aeac465a..69a5c2921 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -55,62 +55,10 @@ if ( !canView( 'Events' ) ) { } ob_start(); -# This will end up with the group_id of the deepest selection -$group_id = Group::get_group_dropdowns(); -$group_dropdowns = ob_get_contents(); +include('_monitor_filters.php'); +$filter_bar = ob_get_contents(); ob_end_clean(); -$groupSql = Group::get_group_sql( $group_id ); - -$servers = Server::find_all(); -$ServersById = array(); -foreach ( $servers as $S ) { - $ServersById[$S->Id()] = $S; -} -$storage_areas = Storage::find_all(); -$StorageById = array(); -foreach ( $storage_areas as $S ) { - $StorageById[$S->Id()] = $S; -} -session_start(); -foreach ( array('minTime','maxTime','ServerFilter','StorageFilter') as $var ) { - if ( isset( $_REQUEST[$var] ) ) { - if ( $_REQUEST[$var] != '' ) { - $_SESSION[$var] = $_REQUEST[$var]; - } else { - unset( $_SESSION[$var] ); - } - } else if ( isset( $_COOKIE[$var] ) ) { - if ( $_COOKIE[$var] != '' ) { - $_SESSION[$var] = $_COOKIE[$var]; - } else { - unset($_SESSION[$var]); - } - } -} -session_write_close(); - -$monitor_id = 0; -if ( isset( $_REQUEST['monitor_id'] ) ) { - $monitor_id = $_REQUEST['monitor_id']; -} else if ( isset($_COOKIE['zmMonitorId']) ) { - $monitor_id = $_COOKIE['zmMonitorId']; -} - - $conditions = array(); - $values = array(); - - if ( $groupSql ) - $conditions[] = $groupSql; - if ( isset($_SESSION['ServerFilter']) ) { - $conditions[] = 'ServerId=?'; - $values[] = $_SESSION['ServerFilter']; - } - if ( isset($_SESSION['StorageFilter']) ) { - $conditions[] = 'StorageId=?'; - $values[] = $_SESSION['StorageFilter']; - } - // Note that this finds incomplete events as well, and any frame records written, but still cannot "see" to the end frame // if the bulk record has not been written - to be able to include more current frames reduce bulk frame sizes (event size can be large) // Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly. @@ -141,18 +89,12 @@ $frameSql = ' // This program only calls itself with the time range involved -- it does all monitors (the user can see, in the called group) all the time if ( ! empty( $user['MonitorIds'] ) ) { - $eventsSql .= ' AND M.Id IN ('.$user['MonitorIds'].')'; - $monitorsSql .= ' AND Id IN ('.$user['MonitorIds'].')'; - $monitor_ids = explode(',',$user['MonitorIds']); - $conditions[] .= 'Id IN ('.array_map( function(){return '?';}, $monitor_ids ) . ')'; - array_push( $values, $monitor_ids ); - $frameSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')'; + $eventsSql .= ' AND M.Id IN ('.$user['MonitorIds'].')'; + $frameSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')'; } if ( $monitor_id ) { - $conditions[] = 'Id=?'; - $values[] = $monitor_id; $eventsSql .= ' AND M.Id='.$monitor_id; - $frameSql .= ' AND E.MonitorId='.$monitor_id; + $frameSql .= ' AND E.MonitorId='.$monitor_id; } // Parse input parameters -- note for future, validate/clean up better in case we don't get called from self. @@ -160,7 +102,6 @@ if ( $monitor_id ) { // The default (nothing at all specified) is for 1 hour so we do not read the whole database - if ( !isset($_REQUEST['minTime']) && !isset($_REQUEST['maxTime']) ) { $time = time(); $maxTime = strftime("%FT%T",$time); @@ -180,7 +121,7 @@ if ( (strtotime($maxTime) - strtotime($minTime))/(365*24*3600) > 30 ) { $maxTime = null; } -$fitMode=1; +$fitMode = 1; if (isset($_REQUEST['fit']) && $_REQUEST['fit']=='0' ) $fitMode = 0; @@ -196,7 +137,7 @@ if ( isset($_REQUEST['speed']) ) else $defaultSpeed = 1; -$speedIndex=5; // default to 1x +$speedIndex = 5; // default to 1x for ( $i = 0; $i < count($speeds); $i++ ) { if ( $speeds[$i] == $defaultSpeed ) { $speedIndex = $i; @@ -225,10 +166,10 @@ if ( isset($minTime) && isset($maxTime) ) { } $frameSql .= ' GROUP BY E.Id, E.MonitorId, F.TimeStamp, F.Delta ORDER BY E.MonitorId, F.TimeStamp ASC'; - $monitors = array(); -$monitorsSql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC'; -foreach( dbFetchAll( $monitorsSql, null, $values ) as $row ) { +foreach( $displayMonitors as &$row ) { + if ( $row['Function'] == 'None' ) + continue; $Monitor = new Monitor( $row ); $monitors[] = $Monitor; } @@ -243,32 +184,7 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
- + From cb01b96dc092130dd5af4137efe0973a30473b66 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Nov 2017 12:01:11 -0700 Subject: [PATCH 51/80] fixes --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 33 +++++++++- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 14 ++-- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 73 ++++++++++++--------- 3 files changed, 84 insertions(+), 36 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 3e877205d..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; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 8bdbe3f7f..f8033800f 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 { $_[0]->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 { - $_[0]->logPrint( INFO, @_ ); + my $log = shift; + $log->logPrint( INFO, @_ ); } @@ -696,14 +700,16 @@ sub Warning( @ ) { fetch()->logPrint( WARNING, @_ ); } sub warn { - $_[0]->logPrint( WARNING, @_ ); + my $log = shift; + $log->logPrint( WARNING, @_ ); } sub Error( @ ) { fetch()->logPrint( ERROR, @_ ); } sub error { - $_[0]->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 dfcc02ea9..e06486bf0 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -48,7 +48,7 @@ use vars qw/ $AUTOLOAD $log $dbh/; *dbh = \$ZoneMinder::Database::dbh; my $debug = 1; -use constant DEBUG_ALL=>0; +use constant DEBUG_ALL=>1; sub new { my ( $parent, $id, $data ) = @_; @@ -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 @@ -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} ) ) ) { @@ -257,7 +266,9 @@ $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; @@ -294,30 +305,32 @@ 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' ) { my ( $caller, undef, $line ) = caller; - $openprint::log->error("$type -> set called with non-hash params from $caller $line"); + $log->error("$type -> set called with non-hash params from $caller $line"); } foreach my $field ( keys %fields ) { -$log->debug("field: $field, param: ".$$params{$field}) if $debug; - if ( exists $$params{$field} ) { -$openprint::log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug; - if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) { + if ( $params ) { + $log->debug("field: $field, param: ".$$params{$field}) if $debug; + if ( exists $$params{$field} ) { + $log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug; + if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) { # Only make changes to fields that have changed - if ( defined $fields{$field} ) { - $$self{$field} = $$params{$field} if defined $fields{$field}; - push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating - } # end if -$openprint::log->debug("Running $field with $$params{$field}") if $debug; - if ( my $func = $self->can( $field ) ) { - $func->( $self, $$params{$field} ); - } # end if - } # end if - } # end if + if ( defined $fields{$field} ) { + $$self{$field} = $$params{$field} if defined $fields{$field}; + push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating + } # end if + $log->debug("Running $field with $$params{$field}") if $debug; + if ( my $func = $self->can( $field ) ) { + $func->( $self, $$params{$field} ); + } # end if + } # end if + } # end if + } # end if $params if ( defined $fields{$field} ) { if ( $$self{$field} ) { @@ -356,7 +369,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 +379,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; From 5aa61cf1f5c0802990e95b67f16d2130893948da Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 2 Nov 2017 07:59:25 -0400 Subject: [PATCH 52/80] unset the ref so that last monitor isn't duplicated --- web/skins/classic/views/console.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index b9fc80633..fb5785c92 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -122,10 +122,11 @@ for ( $i = 0; $i < count($displayMonitors); $i++ ) { $sql = 'SELECT '.join($counts,', ').' FROM Events as E where MonitorId = ?'; $counts = dbFetchOne( $sql, NULL, array($monitor['Id']) ); if ( $counts ) - $displayMonitors[$i] = $monitor = array_merge( $monitor, $counts ); + $monitor = array_merge( $monitor, $counts ); for ( $j = 0; $j < count($eventCounts); $j += 1 ) { $eventCounts[$j]['total'] += $monitor['EventCount'.$j]; } + unset($monitor); } $cycleWidth = $maxWidth; $cycleHeight = $maxHeight; From a8b679e4797b1179b54ef3221a16e480febf2c78 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 2 Nov 2017 11:45:33 -0400 Subject: [PATCH 53/80] set frameCount for audio packets too so that a long period of just audio will return and update lastframesent etc. --- src/zm_ffmpeg_camera.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 3339f2958..4b6e5e4ee 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -964,7 +964,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { zm_av_packet_unref( &packet ); continue; } - + #if HAVE_AVUTIL_HWCONTEXT_H } #endif @@ -980,8 +980,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 ); @@ -1012,6 +1010,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 ) { From 495cd580aafdc7ca9014109e5b2d4662c40d1f26 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 2 Nov 2017 11:45:49 -0400 Subject: [PATCH 54/80] add more debugging --- src/zm_monitorstream.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 6c3f7b144..010877b90 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -563,14 +563,22 @@ void MonitorStream::runStream() { 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 for connkey: %d", connkey ); +//Debug(2, "checking command Queue for connkey: %d", connkey ); while(checkCommandQueue()) { +Debug(2, "Have checking command Queue for connkey: %d", connkey ); got_command = true; } } @@ -659,8 +667,10 @@ Debug(2, "checking command Queue for connkey: %d", connkey ); // 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; @@ -697,9 +707,12 @@ Debug(2, "checking command Queue for connkey: %d", connkey ); } // 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; } } From 31b756bd53e9fe3b481e8c98241287d68fd4c4b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 07:18:30 -0400 Subject: [PATCH 55/80] add missing tests for StartDateTime etc --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 07dd659cc..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', " From 4ef28bb30dcdd36d468553b6fc036ae07fa89160 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:22:43 -0400 Subject: [PATCH 56/80] don't put the leading / in the cache link --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 6a94bb8ef..2f201c6e3 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2064,7 +2064,7 @@ 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']; + $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 { From fdbd344d742a4a1bd57e0101eaad58c925b531ef Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:23:08 -0400 Subject: [PATCH 57/80] whitespace --- src/zm_videostore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 208f64818..c8704eae0 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -823,19 +823,19 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { 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; } From 073c06f6a872e24efc6a999f14d140b3c0dbb06a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:23:50 -0400 Subject: [PATCH 58/80] fix sizing after switching scale. basically re-apply the layout --- web/skins/classic/views/js/montage.js | 41 +++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 97fee5998..5927c9b39 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -8,7 +8,7 @@ function Monitor( monitorData ) { this.alarmState = STATE_IDLE; this.lastAlarmState = STATE_IDLE; this.streamCmdParms = "view=request&request=stream&connkey="+this.connKey; - this.onclick=monitorData.onclick; + this.onclick = monitorData.onclick; if ( auth_hash ) this.streamCmdParms += '&auth='+auth_hash; this.streamCmdTimer = null; @@ -34,6 +34,7 @@ function Monitor( monitorData ) { this.streamCmdTimer = clearTimeout( this.streamCmdTimer ); var stream = $j('#liveStream'+this.id)[0]; + if ( respObj.result == 'Ok' ) { this.status = respObj.status; this.alarmState = this.status.state; @@ -97,15 +98,17 @@ function Monitor( monitorData ) { } } // end if Ok or not var streamCmdTimeout = statusRefreshTimeout; - if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) - streamCmdTimeout = streamCmdTimeout/5; + // The idea here is if we are alarmed, do updates faster. However, there is a timeout in the php side which isn't getting modified, so this may cause a problem. Also the server may only be able to update so fast. + //if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) { + //streamCmdTimeout = streamCmdTimeout/5; + //} this.streamCmdTimer = this.streamCmdQuery.delay( streamCmdTimeout, this ); this.lastAlarmState = this.alarmState; }; this.streamCmdQuery = function( resent ) { - //if ( resent ) - //console.log( this.connKey+": Resending" ); + if ( resent ) + console.log( this.connKey+": Resending" ); //this.streamCmdReq.cancel(); this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); }; @@ -231,13 +234,32 @@ function changeSize() { function changeScale() { var scale = $('scale').get('value'); - + $('width').set('value', ''); + $('height').set('value', ''); + Cookie.write( 'zmMontageScale', scale, { duration: 10*365 } ); + Cookie.write( 'zmMontageWidth', '', { duration: 10*365 } ); + Cookie.write( 'zmMontageHeight', '', { duration: 10*365 } ); + if ( ! scale ) { + selectLayout('#zmMontageLayout'); + return; + } for ( var x = 0; x < monitors.length; x++ ) { var monitor = monitors[x]; var newWidth = ( monitorData[x].width * scale ) / SCALE_BASE; var newHeight = ( monitorData[x].height * scale ) / SCALE_BASE; + + // Scale the frame + monitor_frame = $j('#monitorFrame'+monitor.id); + if ( ! monitor_frame ) { + console.log("Error finding frame for " + monitor.id ); + continue; + } + if ( width ) + monitor_frame.css('width',width+'px'); + if ( height ) + monitor_frame.css('height',height+'px'); /*Stream could be an applet so can't use moo tools*/ - var streamImg = document.getElementById( 'liveStream'+monitor.id ); + var streamImg = $j('#liveStream'+monitor.id )[0]; if ( streamImg ) { if ( streamImg.nodeName == 'IMG' ) { var src = streamImg.src; @@ -258,11 +280,6 @@ function changeScale() { zonesSVG.style.height = newHeight + "px"; } } - $('width').set('value', ''); - $('height').set('value', ''); - Cookie.write( 'zmMontageScale', scale, { duration: 10*365 } ); - Cookie.write( 'zmMontageWidth', '', { duration: 10*365 } ); - Cookie.write( 'zmMontageHeight', '', { duration: 10*365 } ); } function toGrid(value) { From 09938ef7eeaca6eb7da507700620f76084590a1a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:24:13 -0400 Subject: [PATCH 59/80] join the echo's into 1 to also get the line breaks --- web/skins/classic/includes/functions.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index c2b5a14de..450cf63b3 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -48,8 +48,10 @@ function xhtmlHeaders( $file, $title ) { <?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?> \n"; - echo "\n"; + echo " + + +"; } else { echo ' From 67bb8c302faf7e3f3b37afe76a22458d11dd49c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 10:00:29 -0400 Subject: [PATCH 60/80] add missing / --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 2f201c6e3..724e9e521 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2065,7 +2065,7 @@ function cache_bust( $file ) { # 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 ) ) { + 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"); From 54d77519c05a4d8bdcf4b3d0b11965c0824555ba Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 12:03:01 -0400 Subject: [PATCH 61/80] Only show Storage and Server filters if there is more than 1 --- web/skins/classic/views/_monitor_filters.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index 231e4bdce..c8607f845 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -118,7 +118,7 @@ $groupSql = Group::get_group_sql( $group_id ); ?> 0 ) { +if ( count($ServersById) > 1 ) { ?> 'All')+$ServersById, (isset($_SESSION 0 ) { ?> +if ( count($StorageById) > 1 ) { ?> 'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') ); From cab8c4cd5ee30d292167547109b5e30f9a4af187 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 13:49:42 -0400 Subject: [PATCH 62/80] cleanup Monitor::Capture. Cleanup the return values from Capture and CaptureAndRecord. <0 is error, 0 is things ok, but no video frame. > 0 means we have a frame. Plus google code style --- src/zm_curl_camera.cpp | 24 +++---- src/zm_ffmpeg_camera.cpp | 8 ++- src/zm_libvlc_camera.cpp | 80 ++++++++--------------- src/zm_monitor.cpp | 91 +++++++++++++-------------- src/zm_remote_camera_http.cpp | 55 +++++++--------- src/zm_remote_camera_rtsp.cpp | 22 +++---- src/zm_stream.cpp | 2 +- web/skins/classic/views/js/montage.js | 20 +++++- 8 files changed, 138 insertions(+), 164 deletions(-) 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_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 4b6e5e4ee..889f2eb6f 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() { @@ -1010,7 +1010,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; + frameComplete = 1; if ( videoStore ) { if ( record_audio ) { if ( have_video_keyframe ) { @@ -1032,6 +1032,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) ); @@ -1043,7 +1045,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_monitor.cpp b/src/zm_monitor.cpp index e51c2ca7d..28002d393 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2878,6 +2878,12 @@ int Monitor::Capture() { captureResult = camera->CaptureAndRecord(*(next_buffer.image), video_store_data->recording, video_store_data->event_file ); + // CaptureAndRecord returns # of frames captured I think + //if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) { + if ( captureResult > 0 ) { + //video_store_data->frameNumber = captureResult; + captureResult = 0; + } } else { captureResult = camera->Capture(*(next_buffer.image)); } @@ -2889,33 +2895,28 @@ 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 ) { + 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 ) { @@ -2978,40 +2979,38 @@ int Monitor::Capture() { shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; image_count++; + } - 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 ); - //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; - static char sql[ZM_SQL_SML_BUFSIZ]; - 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 ) ); - } + 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 ); + //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; + static char sql[ZM_SQL_SML_BUFSIZ]; + 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_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/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 5927c9b39..364e79b91 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -7,7 +7,7 @@ function Monitor( monitorData ) { this.status = null; this.alarmState = STATE_IDLE; this.lastAlarmState = STATE_IDLE; - this.streamCmdParms = "view=request&request=stream&connkey="+this.connKey; + this.streamCmdParms = 'view=request&request=stream&connkey='+this.connKey; this.onclick = monitorData.onclick; if ( auth_hash ) this.streamCmdParms += '&auth='+auth_hash; @@ -112,8 +112,24 @@ function Monitor( monitorData ) { //this.streamCmdReq.cancel(); this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); }; + this.onError = function( text, error ) { + console.log('onerror: ' + text + ' error:'+error); + }; + this.onFailure = function( xhr ) { + console.log('onFailure: ' ); + console.log(xhr ); + }; - this.streamCmdReq = new Request.JSON( { url: this.server_url, method: 'get', timeout: 1000+AJAX_TIMEOUT, onSuccess: this.getStreamCmdResponse.bind( this ), onTimeout: this.streamCmdQuery.bind( this, true ), link: 'cancel' } ); + this.streamCmdReq = new Request.JSON( { + url: this.server_url, + method: 'get', + timeout: 1000+AJAX_TIMEOUT, + onSuccess: this.getStreamCmdResponse.bind( this ), + onTimeout: this.streamCmdQuery.bind( this, true ), + onError: this.onError.bind(this), + onFailure: this.onFailure.bind(this), + link: 'cancel' + } ); requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq ); } From 0ef5c16bcce76a80fb31b535db0597f375e1ff12 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:07:04 -0400 Subject: [PATCH 63/80] when doing parseSort, reset the sortfield to StartTime instead of DateTime --- web/includes/functions.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/includes/functions.php b/web/includes/functions.php index 724e9e521..4579f21af 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -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'; From 8432ab5938528a52671f01ac21f675bd9bd3f9b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:09:19 -0400 Subject: [PATCH 64/80] change quotes, and limit the # of results to 2 when getting next and previous frames. 2 is because one of them could be the currently selected Event, --- web/ajax/status.php | 316 ++++++++++++++++++++++---------------------- 1 file changed, 158 insertions(+), 158 deletions(-) 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 ) { From f39353a4a323d6a54e64c825c66788de81099b04 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:44:53 -0400 Subject: [PATCH 65/80] add missing breaks --- web/includes/functions.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/includes/functions.php b/web/includes/functions.php index 4579f21af..8dcab3b42 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1277,8 +1277,10 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) { break; case 'IS' : $filter['sql'] .= " IS $value"; + break; case 'IS NOT' : $filter['sql'] .= " IS NOT $value"; + break; } $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']); From 63c788ef0e5af5fcb12ebfcdf0f3df511bb57751 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:45:11 -0400 Subject: [PATCH 66/80] handle when sql error occurs and no params given --- web/includes/database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/database.php b/web/includes/database.php index bbfd588b0..34387e040 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -141,7 +141,7 @@ if ( 0 ) { 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 ); } From 09f3355e183c5a49436721561922bc585a0cc85e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 4 Nov 2017 14:52:36 -0400 Subject: [PATCH 67/80] add /usr/share/zoneminder/www/cache as a temp dir --- distros/ubuntu1604/zoneminder.dirs | 1 + distros/ubuntu1604/zoneminder.tmpfile | 1 + web/skins/classic/views/console.php | 3 +-- web/skins/classic/views/group.php | 6 ++++-- 4 files changed, 7 insertions(+), 4 deletions(-) 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/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index fb5785c92..43214ea1f 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -263,8 +263,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { - - + diff --git a/web/skins/classic/views/group.php b/web/skins/classic/views/group.php index 9f00555dd..0e71040c7 100644 --- a/web/skins/classic/views/group.php +++ b/web/skins/classic/views/group.php @@ -87,9 +87,11 @@ function get_children($Group) { } $kids = get_children($newGroup); -$kids[] = $newGroup->Id(); +if ( $newGroup->Id() ) + $kids[] = $newGroup->Id(); +$sql = 'SELECT Id,Name from Groups'.(count($kids)?' WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids )).')' : '').' ORDER BY Name'; $options = array(''=>'None'); -foreach ( dbFetchAll( 'SELECT Id,Name from Groups WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids )).') ORDER BY Name', null, $kids ) as $option ) { +foreach ( dbFetchAll( $sql, null, $kids ) as $option ) { $options[$option['Id']] = $option['Name']; } echo htmlSelect( 'newGroup[ParentId]', $options, $newGroup->ParentId(), array('onchange'=>'configureButtons(this);' )); From ee96f58ac4762e5974c99698cfbd1296523807dd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 09:59:06 -0500 Subject: [PATCH 68/80] fix fps reporting value when Capture doesn't return a new frame --- src/zm_monitor.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 28002d393..7e0d4b630 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 ); @@ -2878,12 +2878,6 @@ int Monitor::Capture() { captureResult = camera->CaptureAndRecord(*(next_buffer.image), video_store_data->recording, video_store_data->event_file ); - // CaptureAndRecord returns # of frames captured I think - //if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) { - if ( captureResult > 0 ) { - //video_store_data->frameNumber = captureResult; - captureResult = 0; - } } else { captureResult = camera->Capture(*(next_buffer.image)); } @@ -2908,8 +2902,7 @@ int Monitor::Capture() { captureResult = camera->Capture(*capture_image); } } - - +Debug(4, "Return from Capture (%d)", captureResult); if ( captureResult < 0 ) { // Unable to capture image for temporary reason // Fake a signal loss image @@ -2970,26 +2963,34 @@ 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 ); + + struct timeval now; + if ( !captureResult ) { + gettimeofday( &now, NULL ); + } else { + now.tv_sec = image_buffer[index].timestamp->tv_sec; + } + fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); + Info( "%d -> %d -> %d", fps_report_interval, now, 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 ) ); } From 0a3327e2d2efcda3b19f9557e9c4e59717a9b288 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 09:59:27 -0500 Subject: [PATCH 69/80] move test for h264 into the code that opens the stream instead of comparing on every capture --- src/zm_ffmpeg_camera.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 889f2eb6f..ee5437633 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -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 @@ -735,22 +744,12 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event mReopenThread = 0; } - if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) { -#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 - } int frameComplete = false; 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 ); @@ -960,7 +959,7 @@ 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; } From 7374ced0762088986561dd3a818787380e63e17e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 10:00:24 -0500 Subject: [PATCH 70/80] 0 is a prefectly valid PreEventCount --- web/skins/classic/views/js/monitor.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index 97a60dd8c..470bb92b8 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -97,7 +97,7 @@ function validateForm( form ) { errors[errors.length] = ""; if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) ) errors[errors.length] = ""; - if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) > 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) + if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) errors[errors.length] = ""; if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) ) errors[errors.length] = ""; From bef7c0ed947d52a9988069e449a74c0c7a49e308 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 11:54:00 -0500 Subject: [PATCH 71/80] Only start a monitor if it has a Function --- web/includes/Monitor.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 5c4643657..e7b114dde 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -301,6 +301,7 @@ private $control_fields = array( $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' ) { @@ -315,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(); From 4b8a8e7b566c454818cc2a1e28de3468fd7a4fa7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 18:02:09 -0500 Subject: [PATCH 72/80] fix new return value from Capture, 1 signals 1 frame captured --- src/zm_local_camera.cpp | 78 +++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 50 deletions(-) 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() From c3cfd096c7e8635b8cb81962ed26d4b35202df35 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 7 Nov 2017 09:34:47 -0500 Subject: [PATCH 73/80] Don't connect to the monitor when doing an eventStream --- src/zm_eventstream.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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; From a9419064ef1824a59e6bb2227f87a1e1cf9dd16a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 7 Nov 2017 09:35:13 -0500 Subject: [PATCH 74/80] don't calc fps if no time has passed --- src/zm_monitor.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 7e0d4b630..b01b72208 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2984,15 +2984,18 @@ Debug(4, "Return from Capture (%d)", captureResult); } else { now.tv_sec = image_buffer[index].timestamp->tv_sec; } - fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); - Info( "%d -> %d -> %d", fps_report_interval, now, 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.tv_sec; - static char sql[ZM_SQL_SML_BUFSIZ]; - 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 ) ); + // 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.tv_sec; + static char sql[ZM_SQL_SML_BUFSIZ]; + 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 ) ); + } } } From b6548ba137f7de66a54b9776f5e6278911b8df40 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 7 Nov 2017 15:54:13 -0500 Subject: [PATCH 75/80] put curl back, we use it's decoding function for urls --- distros/ubuntu1604/rules | 1 - 1 file changed, 1 deletion(-) diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules index 5cf153266..10489432b 100755 --- a/distros/ubuntu1604/rules +++ b/distros/ubuntu1604/rules @@ -28,7 +28,6 @@ override_dh_auto_configure: -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \ - -DZM_NO_CURL=1 \ -DZM_NO_LIBVLC=1 override_dh_clean: From 625170bffcc31dbadd7b68bf916afc73ac109741 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 8 Nov 2017 11:17:30 -0500 Subject: [PATCH 76/80] fix getVideoStream to getVideoStreamHTML. Change how scaling works --- web/includes/functions.php | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 8dcab3b42..2bb743681 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 '