From 0ff9002adf395637a33b72253ec06be82de1e35a Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Sun, 15 Jul 2018 21:17:35 -0400 Subject: [PATCH 1/7] 2156 api login (#2157) * error can be due to bad user or password * added login/logout and related private functions * handle case when userLogin fails, current code returns PHP error for and API throw is not called * formatting * converted login params to POST, removed user=&pass= for other APIs * formatting * add auth check back but leave out login/out * fixes to make it work across zmN, postman and curl * added back enabled check --- web/api/app/Controller/AppController.php | 142 ++++------ web/api/app/Controller/HostController.php | 300 +++++++++++++++------- web/includes/auth.php | 2 +- 3 files changed, 257 insertions(+), 187 deletions(-) diff --git a/web/api/app/Controller/AppController.php b/web/api/app/Controller/AppController.php index 52708a402..06797ab5b 100644 --- a/web/api/app/Controller/AppController.php +++ b/web/api/app/Controller/AppController.php @@ -27,116 +27,64 @@ App::uses('CrudControllerTrait', 'Crud.Lib'); * Add your application-wide methods in the class below, your controllers * will inherit them. * - * @package app.Controller - * @link http://book.cakephp.org/2.0/en/controllers.html#the-app-controller + * @package app.Controller + * @link http://book.cakephp.org/2.0/en/controllers.html#the-app-controller */ class AppController extends Controller { - use CrudControllerTrait; + use CrudControllerTrait; - public $components = [ - 'Session', // We are going to use SessionHelper to check PHP session vars - 'RequestHandler', - 'Crud.Crud' => [ - 'actions' => [ - 'index' => 'Crud.Index', - 'add' => 'Crud.Add', - 'edit' => 'Crud.Edit', - 'view' => 'Crud.View', - 'keyvalue' => 'Crud.List', - 'category' => 'Crud.Category' - ], - 'listeners' => ['Api', 'ApiTransformation'] - #], + public $components = [ + 'Session', // We are going to use SessionHelper to check PHP session vars + 'RequestHandler', + 'Crud.Crud' => [ + 'actions' => [ + 'index' => 'Crud.Index', + 'add' => 'Crud.Add', + 'edit' => 'Crud.Edit', + 'view' => 'Crud.View', + 'keyvalue' => 'Crud.List', + 'category' => 'Crud.Category' + ], + 'listeners' => ['Api', 'ApiTransformation'] + #], #'DebugKit.Toolbar' => [ # 'bootstrap' => true, 'routes' => true ] - ]; + ]; - // Global beforeFilter function - //Zoneminder sets the username session variable - // to the logged in user. If this variable is set - // then you are logged in - // its pretty simple to extend this to also check - // for role and deny API access in future - // Also checking to do this only if ZM_OPT_USE_AUTH is on - public function beforeFilter() { - $this->loadModel('Config'); - + // Global beforeFilter function + //Zoneminder sets the username session variable + // to the logged in user. If this variable is set + // then you are logged in + // its pretty simple to extend this to also check + // for role and deny API access in future + // Also checking to do this only if ZM_OPT_USE_AUTH is on + public function beforeFilter() { + $this->loadModel('Config'); + $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_API')); $config = $this->Config->find('first', $options); $zmOptApi = $config['Config']['Value']; - if ($zmOptApi !='1') { + if ($zmOptApi !='1') { throw new UnauthorizedException(__('API Disabled')); return; - } - - $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')); - $config = $this->Config->find('first', $options); - $zmOptAuth = $config['Config']['Value']; - - if ( $zmOptAuth == '1' ) { - require_once "../../../includes/auth.php"; - - global $user; - $user = $this->Session->read('user'); - - if ( isset($_REQUEST['user']) and isset($_REQUEST['pass']) ) { - $user = userLogin($_REQUEST['user'],$_REQUEST['pass']); - if ( !$user ) { - throw new UnauthorizedException(__('User not found')); - return; - } - } - - if ( isset($_REQUEST['auth']) ) { - $user = getAuthUser($_REQUEST['auth']); - if ( ! $user ) { - throw new UnauthorizedException(__('User not found')); - return; - } - } # end if REQUEST['auth'] - - if ( 0 and $user ) { - # We have to redo the session variables because cakephp's Session code will overwrite the normal php session - # Actually I'm not sure that is true. Getting indeterminate behaviour - Logger::Debug("user.Username: " . $this->Session->read('user.Username')); - if ( ! $this->Session->Write('user', $user) ) - $this->log("Error writing session var user"); - Logger::Debug("user.Username: " . $this->Session->read('user.Username')); - if ( ! $this->Session->Write('user.Username', $user['Username']) ) - $this->log("Error writing session var user.Username"); - if ( ! $this->Session->Write('password', $user['Password']) ) - $this->log("Error writing session var user.Username"); - if ( ! $this->Session->Write('user.Enabled', $user['Enabled']) ) - $this->log("Error writing session var user.Enabled"); - if ( ! $this->Session->Write('remoteAddr', $_SERVER['REMOTE_ADDR']) ) - $this->log("Error writing session var remoteAddr"); - } - - if ( ! $this->Session->read('user.Username') ) { - throw new UnauthorizedException(__('Not Authenticated')); - return; - } else if ( ! $this->Session->read('user.Enabled') ) { - throw new UnauthorizedException(__('User is not enabled')); - return; - } - - $this->Session->Write('allowedMonitors',$user['MonitorIds']); - $this->Session->Write('streamPermission',$user['Stream']); - $this->Session->Write('eventPermission',$user['Events']); - $this->Session->Write('controlPermission',$user['Control']); - $this->Session->Write('systemPermission',$user['System']); - $this->Session->Write('monitorPermission',$user['Monitors']); - } else { - // if auth is not on, you can do everything - //$userMonitors = $this->User->find('first', $options); - $this->Session->Write('allowedMonitors',''); - $this->Session->Write('streamPermission','View'); - $this->Session->Write('eventPermission','Edit'); - $this->Session->Write('controlPermission','Edit'); - $this->Session->Write('systemPermission','Edit'); - $this->Session->Write('monitorPermission','Edit'); } + // We need to reject methods that are not authenticated + // besides login and logout + if (strcasecmp($this->params->controller, "host") && + strcasecmp($this->params->action, "login") && + strcasecmp($this->params->action,"logout")) { + + if (!$this->Session->read('user.Username')) { + throw new UnauthorizedException(__('Not Authenticated')); + return; + } else if (!$this->Session->read('user.Enabled')) { + throw new UnauthorizedException(__('User is not enabled')); + return; + } + + } + } # end function beforeFilter() } diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index 85a7baed3..4daec2368 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -3,9 +3,9 @@ App::uses('AppController', 'Controller'); class HostController extends AppController { - public $components = array('RequestHandler'); + public $components = array('RequestHandler', 'Session'); - public function daemonCheck($daemon=false, $args=false) { + public function daemonCheck($daemon=false, $args=false) { $string = Configure::read('ZM_PATH_BIN').'/zmdc.pl check'; if ( $daemon ) { $string .= " $daemon"; @@ -15,27 +15,139 @@ class HostController extends AppController { $result = exec($string); $result = preg_match('/running/', $result); - $this->set(array( - 'result' => $result, - '_serialize' => array('result') - )); - } + $this->set(array( + 'result' => $result, + '_serialize' => array('result') + )); + } - function getLoad() { - $load = sys_getloadavg(); + function getLoad() { + $load = sys_getloadavg(); - $this->set(array( - 'load' => $load, - '_serialize' => array('load') - )); - } + $this->set(array( + 'load' => $load, + '_serialize' => array('load') + )); + } - function getCredentials() { - // ignore debug warnings from other functions - $this->view='Json'; + + + function login() { + + $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')); + $config = $this->Config->find('first', $options); + $zmOptAuth = $config['Config']['Value']; + + if ( $zmOptAuth == '1' ) { + require_once "../../../includes/auth.php"; + + global $user; + $user = $this->Session->read('user'); + + + + $mUser = $this->request->data('user'); + $mPassword = $this->request->data('pass'); + $mAuth = $this->request->data('auth'); + + + if ( $mUser and $mPassword) { + $user = userLogin($mUser, $mPassword); + if ( !$user ) { + throw new UnauthorizedException(__('User not found or incorrect password')); + return; + } + } + + elseif ( $mAuth ) { + $user = getAuthUser($mAuth); + if ( ! $user ) { + throw new UnauthorizedException(__('User not found or incorrect password')); + return; + } + } + else { + throw new UnauthorizedException(__('missing credentials')); + } + + if ( 0 and $user ) { + # We have to redo the session variables because cakephp's Session code will overwrite the normal php session + # Actually I'm not sure that is true. Getting indeterminate behaviour + Logger::Debug("user.Username: " . $this->Session->read('user.Username')); + if ( ! $this->Session->Write('user', $user) ) + $this->log("Error writing session var user"); + Logger::Debug("user.Username: " . $this->Session->read('user.Username')); + if ( ! $this->Session->Write('user.Username', $user['Username']) ) + $this->log("Error writing session var user.Username"); + if ( ! $this->Session->Write('password', $user['Password']) ) + $this->log("Error writing session var user.Username"); + if ( ! $this->Session->Write('user.Enabled', $user['Enabled']) ) + $this->log("Error writing session var user.Enabled"); + if ( ! $this->Session->Write('remoteAddr', $_SERVER['REMOTE_ADDR']) ) + $this->log("Error writing session var remoteAddr"); + } + + + + // I don't think this is really needed - the Username part + // Enabled check is ok + if ( !$user['Username'] ) { + throw new UnauthorizedException(__('Not Authenticated')); + return; + } else if ( !$user['Enabled'] ) { + throw new UnauthorizedException(__('User is not enabled')); + return; + } + + + $this->Session->Write('allowedMonitors',$user['MonitorIds']); + $this->Session->Write('streamPermission',$user['Stream']); + $this->Session->Write('eventPermission',$user['Events']); + $this->Session->Write('controlPermission',$user['Control']); + $this->Session->Write('systemPermission',$user['System']); + $this->Session->Write('monitorPermission',$user['Monitors']); + } else { + // if auth is not on, you can do everything + //$userMonitors = $this->User->find('first', $options); + $this->Session->Write('allowedMonitors',''); + $this->Session->Write('streamPermission','View'); + $this->Session->Write('eventPermission','Edit'); + $this->Session->Write('controlPermission','Edit'); + $this->Session->Write('systemPermission','Edit'); + $this->Session->Write('monitorPermission','Edit'); + } + + + $cred = $this->_getCredentials(); + $ver = $this->_getVersion(); + $this->set(array( + 'credentials' => $cred[0], + 'append_password'=>$cred[1], + 'version' => $ver[0], + 'apiversion' => $ver[1], + '_serialize' => array('credentials', + 'append_password', + 'version', + 'apiversion' + ))); + + } + + // clears out session + function logout() { + global $user; + $this->Session->Write('user', null); + + $this->set(array( + 'result' => 'ok', + '_serialize' => array('result') + )); + + } + + private function _getCredentials() { $credentials = ''; $appendPassword = 0; - $this->loadModel('Config'); $isZmAuth = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')))['Config']['Value']; @@ -52,80 +164,90 @@ class HostController extends AppController { $credentials = 'user='.$this->Session->read('user.Username'); } } + return array($credentials, $appendPassword); + + } + + function getCredentials() { + // ignore debug warnings from other functions + $this->view='Json'; + $val = $this->_getCredentials(); $this->set(array( - 'credentials'=> $credentials, - 'append_password'=>$appendPassword, + 'credentials'=> $val[0], + 'append_password'=>$val[1], '_serialize' => array('credentials', 'append_password') ) ); } + + - // If $mid is set, only return disk usage for that monitor + // If $mid is set, only return disk usage for that monitor // Else, return an array of total disk usage, and per-monitor // usage. - function getDiskPercent($mid = null) { - $this->loadModel('Config'); - $this->loadModel('Monitor'); + function getDiskPercent($mid = null) { + $this->loadModel('Config'); + $this->loadModel('Monitor'); - // If $mid is passed, see if it is valid - if ($mid) { - if (!$this->Monitor->exists($mid)) { - throw new NotFoundException(__('Invalid monitor')); - } - } + // If $mid is passed, see if it is valid + if ($mid) { + if (!$this->Monitor->exists($mid)) { + throw new NotFoundException(__('Invalid monitor')); + } + } - $zm_dir_events = $this->Config->find('list', array( - 'conditions' => array('Name' => 'ZM_DIR_EVENTS'), - 'fields' => array('Name', 'Value') - )); - $zm_dir_events = $zm_dir_events['ZM_DIR_EVENTS' ]; + $zm_dir_events = $this->Config->find('list', array( + 'conditions' => array('Name' => 'ZM_DIR_EVENTS'), + 'fields' => array('Name', 'Value') + )); + $zm_dir_events = $zm_dir_events['ZM_DIR_EVENTS' ]; - // Test to see if $zm_dir_events is relative or absolute - if ('/' === "" || strrpos($zm_dir_events, '/', -strlen($zm_dir_events)) !== TRUE) { - // relative - so add the full path - $zm_dir_events = Configure::read('ZM_PATH_WEB') . '/' . $zm_dir_events; - } + // Test to see if $zm_dir_events is relative or absolute + if ('/' === "" || strrpos($zm_dir_events, '/', -strlen($zm_dir_events)) !== TRUE) { + // relative - so add the full path + $zm_dir_events = Configure::read('ZM_PATH_WEB') . '/' . $zm_dir_events; + } - if ($mid) { - // Get disk usage for $mid - $usage = shell_exec ("du -sh0 $zm_dir_events/$mid | awk '{print $1}'"); - } else { - $monitors = $this->Monitor->find('all', array( - 'fields' => array('Id', 'Name', 'WebColour') - )); - $usage = array(); + if ($mid) { + // Get disk usage for $mid + $usage = shell_exec ("du -sh0 $zm_dir_events/$mid | awk '{print $1}'"); + } else { + $monitors = $this->Monitor->find('all', array( + 'fields' => array('Id', 'Name', 'WebColour') + )); + $usage = array(); - // Add each monitor's usage to array - foreach ($monitors as $key => $value) { - $id = $value['Monitor']['Id']; - $name = $value['Monitor']['Name']; - $color = $value['Monitor']['WebColour']; + // Add each monitor's usage to array + foreach ($monitors as $key => $value) { + $id = $value['Monitor']['Id']; + $name = $value['Monitor']['Name']; + $color = $value['Monitor']['WebColour']; - $space = shell_exec ("du -s0 $zm_dir_events/$id | awk '{print $1}'"); - if ($space == null) { - $space = 0; - } - $space = $space/1024/1024; + $space = shell_exec ("du -s0 $zm_dir_events/$id | awk '{print $1}'"); + if ($space == null) { + $space = 0; + } + $space = $space/1024/1024; - $usage[$name] = array( - 'space' => rtrim($space), - 'color' => $color - ); - } + $usage[$name] = array( + 'space' => rtrim($space), + 'color' => $color + ); + } - // Add total usage to array - $space = shell_exec( "df $zm_dir_events |tail -n1 | awk '{print $3 }'"); - $space = $space/1024/1024; - $usage['Total'] = array( - 'space' => rtrim($space), - 'color' => '#F7464A' - ); - } + // Add total usage to array + $space = shell_exec( "df $zm_dir_events |tail -n1 | awk '{print $3 }'"); + $space = $space/1024/1024; + $usage['Total'] = array( + 'space' => rtrim($space), + 'color' => '#F7464A' + ); + } - $this->set(array( - 'usage' => $usage, - '_serialize' => array('usage') - )); - } + $this->set(array( + 'usage' => $usage, + '_serialize' => array('usage') + )); + } function getTimeZone() { //http://php.net/manual/en/function.date-default-timezone-get.php @@ -136,18 +258,18 @@ class HostController extends AppController { )); } - function getVersion() { - //throw new UnauthorizedException(__('API Disabled')); - $version = Configure::read('ZM_VERSION'); - // not going to use the ZM_API_VERSION - // requires recompilation and dependency on ZM upgrade - //$apiversion = Configure::read('ZM_API_VERSION'); - $apiversion = '1.0'; + private function _getVersion() { + $version = Configure::read('ZM_VERSION'); + $apiversion = '1.0'; + return array($version, $apiversion); + } - $this->set(array( - 'version' => $version, - 'apiversion' => $apiversion, - '_serialize' => array('version', 'apiversion') - )); - } + function getVersion() { + $val = $this->_getVersion(); + $this->set(array( + 'version' => $val[0], + 'apiversion' => $val[1], + '_serialize' => array('version', 'apiversion') + )); + } } diff --git a/web/includes/auth.php b/web/includes/auth.php index c9b61c40c..9cf8d37c1 100644 --- a/web/includes/auth.php +++ b/web/includes/auth.php @@ -61,7 +61,7 @@ function userLogin($username, $password='', $passwordHashed=false) { } if ( $close_session ) session_write_close(); - return $user; + return isset($user) ? $user: null; } # end function userLogin function userLogout() { From 455204135da89df083a67851b3d48b1a89b2509d Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 17 Jul 2018 06:57:38 -0500 Subject: [PATCH 2/7] fail if zm_path_ffmpeg not set --- scripts/zmvideo.pl.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/zmvideo.pl.in b/scripts/zmvideo.pl.in index 1f1b33acc..95a395b4d 100644 --- a/scripts/zmvideo.pl.in +++ b/scripts/zmvideo.pl.in @@ -173,6 +173,12 @@ my $cwd = getcwd; my $video_name; my @event_ids; + +# Fail if the path to a valid ffmpeg binary is not set +if ( ! -x $Config{ZM_PATH_FFMPEG} ) { + Fatal("Ffmpeg binary not found or not executable. Verify ZM_PATH_FFMPEG points to ffmpeg, avconv, or a compatible binary."); +} + if ( $event_id ) { @event_ids = ( $event_id ); From 26d6b9901814e66a37c7bf16e4a7328282e829c3 Mon Sep 17 00:00:00 2001 From: Daedilus Date: Tue, 17 Jul 2018 06:09:15 -0600 Subject: [PATCH 3/7] Added new control script for iPhone ip camera software (#2161) https://itunes.apple.com/ca/app/ipcamera-high-end-network-camera/id570912928?mt=8 See https://forums.zoneminder.com/viewtopic.php?f=9&t=27386 for details. --- .../lib/ZoneMinder/Control/IPCAMIOS.pm | 326 ++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 scripts/ZoneMinder/lib/ZoneMinder/Control/IPCAMIOS.pm diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/IPCAMIOS.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/IPCAMIOS.pm new file mode 100644 index 000000000..8465ee472 --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/IPCAMIOS.pm @@ -0,0 +1,326 @@ +# ========================================================================== +# +# ZoneMinder iPhone Control Protocol Module, $Date: 2018-07-15 00:20:00 +0000 $, $Revision: 0003 $ +# Copyright (C) 2001-2008 Philip Coombes +# +# Modified for iPhone ipcamera for IOS BY PETER ZARGLIS n 2018-06-09 13:45:00 +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ========================================================================== +# +# This module contains the implementation of the iPhone ipcamera for IOS +# control protocol. +# +# ========================================================================== +package ZoneMinder::Control::IPCAMIOS; + +use 5.006; +use strict; +use warnings; + +require ZoneMinder::Base; +require ZoneMinder::Control; + +our @ISA = qw(ZoneMinder::Control); + +our $VERSION = $ZoneMinder::Base::VERSION; + +# ========================================================================== +# +# iPhone ipcamera for IOS Protocol +# +# ========================================================================== + +use ZoneMinder::Logger qw(:all); +use ZoneMinder::Config qw(:all); +use Time::HiRes qw( usleep ); + +my $loopfactor=100000; + +sub new +{ + my $class = shift; + my $id = shift; + my $self = ZoneMinder::Control->new( $id ); + my $logindetails = ""; + bless( $self, $class ); + srand( time() ); + return $self; +} + +our $AUTOLOAD; + +sub AUTOLOAD +{ + my $self = shift; + my $class = ref($self) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + if ( exists($self->{$name}) ) + { + return( $self->{$name} ); + } + Fatal( "Can't access $name member of object of class $class" ); +} + +sub open +{ + my $self = shift; + + $self->loadMonitor(); + + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->agent( "ZoneMinder Control Agent" ); + + + $self->{state} = 'open'; +} + +sub close +{ + my $self = shift; + $self->{state} = 'closed'; +} + +sub sendCmd +{ + my $self = shift; + my $cmd = shift; + my $result = undef; + my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" ); + my $res = $self->{ua}->request($req); + if ( $res->is_success ) + { + $result = $res->decoded_content; + } + else + { + Error( "Error check failed: '".$res->status_line()."'" ); + } + return( $result ); +} +sub getDisplayAttr +{ + my $self = shift; + my $param = shift; + my $cmdget = "parameters?"; + my $resp = $self->sendCmd( $cmdget ); + my @fields = split(',',$resp); + my $response=$fields[$param]; + my @buffer=split(':',$response); + my $response2=$buffer[1]; + return ($response2); +} + +sub sleep +{ + +} +# Flip image vertically -> Horz -> off +sub moveConUp +{ + my $self = shift; + my $params = shift; + Debug( "Flip Image" ); + my $dvalue=$self->getDisplayAttr(3); + if ( $dvalue == 2 ) + { + $dvalue=0; + my $cmd = "parameters?flip=$dvalue"; + $self->sendCmd( $cmd ); + } + else + { + $dvalue=$dvalue+1; + my $cmd = "parameters?flip=$dvalue"; + $self->sendCmd( $cmd ); + } +} +# Change camera (front facing or back) +sub moveConDown +{ + my $self = shift; + my $params = shift; + Debug( "Change Camera" ); + my $dvalue=$self->getDisplayAttr(7); + if ( $dvalue == 0 ) + { + my $cmd = "parameters?camera=1"; + $self->sendCmd( $cmd ); + } + else + { + my $cmd = "parameters?camera=0"; + $self->sendCmd( $cmd ); + } +} +# Picture Orientation Clockwise +sub moveConRight +{ + my $self = shift; + my $params = shift; + Debug( "Orientation" ); + my $dvalue=$self->getDisplayAttr(10); + if ( $dvalue == 1 ) + { + $dvalue=4; + my $cmd = "parameters?rotation=$dvalue"; + $self->sendCmd( $cmd ); + } + else + { + $dvalue=$dvalue-1; + my $cmd = "parameters?rotation=$dvalue"; + $self->sendCmd( $cmd ); + } +} +# Picture Orientation Anti-Clockwise +sub moveConLeft +{ + my $self = shift; + my $params = shift; + Debug( "Orientation" ); + my $dvalue=$self->getDisplayAttr(10); + if ( $dvalue == 4 ) + { + $dvalue=1; + my $cmd = "parameters?rotation=$dvalue"; + $self->sendCmd( $cmd ); + } + else + { + $dvalue=$dvalue+1; + my $cmd = "parameters?rotation=$dvalue"; + $self->sendCmd( $cmd ); + } +} + +# presetHome is used to turn off Torch, unlock Focus, unlock Exposure, unlock white-balance, rotation, image flipping +# Just basically reset all the little variables and set it to medium quality +# Rotation = 0 means it will autoselect using built in detection +sub presetHome +{ + my $self = shift; + Debug( "Home Preset" ); + my $cmd = "parameters?torch=0&focus=0&wb=0&exposure=0&rotation=0&flip=0&quality=0.5"; + $self->sendCmd( $cmd ); +} + +sub focusAbsNear +# Focus Un/Lock +{ + my $self = shift; + my $params = shift; + Debug( "Focus Un/Lock" ); + my $dvalue=$self->getDisplayAttr(2); + if ( $dvalue == 0 ) + { + my $cmd = "parameters?focus=1"; + $self->sendCmd( $cmd ); + } + else + { + my $cmd = "parameters?focus=0"; + $self->sendCmd( $cmd ); + } +} + +sub focusAbsFar +# Exposure Un/Lock +{ + my $self = shift; + my $params = shift; + Debug( "Exposure Un/Lock" ); + my $dvalue=$self->getDisplayAttr(11); + if ( $dvalue == 0 ) + { + my $cmd = "parameters?exposure=1"; + $self->sendCmd( $cmd ); + } + else + { + my $cmd = "parameters?exposure=0"; + $self->sendCmd( $cmd ); + } +} +# Increase stream Quality (from 0 to 10) +sub irisAbsOpen +{ + my $self = shift; + my $params = shift; + Debug( "Quality" ); + my $dvalue=$self->getDisplayAttr(8); + if ( $dvalue < 1 ) + { + $dvalue=$dvalue+0.1; + my $cmd = "parameters?quality=$dvalue"; + $self->sendCmd( $cmd ); + } +} + +# Decrease stream Quality (from 10 to 0) +sub irisAbsClose +{ + my $self = shift; + my $params = shift; + Debug( "Quality" ); + my $dvalue=$self->getDisplayAttr(8); + if ( $dvalue > 0 ) + { + $dvalue=$dvalue-0.1; + my $cmd = "parameters?quality=$dvalue"; + $self->sendCmd( $cmd ); + } +} +# White Balance Un/Lock +sub whiteAbsIn +{ + my $self = shift; + my $params = shift; + Debug( "White Balance" ); + my $dvalue=$self->getDisplayAttr(9); + if ( $dvalue == 0 ) + { + my $cmd = "parameters?wb=1"; + $self->sendCmd( $cmd ); + } + else + { + my $cmd = "parameters?wb=0"; + $self->sendCmd( $cmd ); + } +} + +# Torch control on/off +sub whiteAbsOut +{ + my $self = shift; + my $params = shift; + Debug( "Torch" ); + my $dvalue=$self->getDisplayAttr(5); + if ( $dvalue == 0 ) + { + my $cmd = "parameters?torch=1"; + $self->sendCmd( $cmd ); + } + else + { + my $cmd = "parameters?torch=0"; + $self->sendCmd( $cmd ); + } +} + +1; From a41ce9c9fecc9ce112e9343e391415a17ea1ff13 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Jul 2018 08:24:19 -0400 Subject: [PATCH 4/7] default to exporting all event data --- web/skins/classic/views/export.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/skins/classic/views/export.php b/web/skins/classic/views/export.php index 63b8e9193..b390277ab 100644 --- a/web/skins/classic/views/export.php +++ b/web/skins/classic/views/export.php @@ -36,6 +36,12 @@ if ( isset($_SESSION['export']) ) { $_REQUEST['exportMisc'] = $_SESSION['export']['misc']; if ( isset($_SESSION['export']['format']) ) $_REQUEST['exportFormat'] = $_SESSION['export']['format']; +} else { + $_REQUEST['exportDetail'] = + $_REQUEST['exportFrames'] = + $_REQUEST['exportImages'] = + $_REQUEST['exportVideo'] = + $_REQUEST['exportMisc'] = 1; } $focusWindow = true; From 683e8716f21863c3142265fd2dc51bbbdd224e94 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Jul 2018 08:25:15 -0400 Subject: [PATCH 5/7] add type=button to button to prevent them from submitting --- web/skins/classic/views/filter.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index beb5b34a2..d52baed1d 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -410,18 +410,20 @@ if ( ZM_OPT_MESSAGE ) {
- - - + + + - - + + Id() ) { ?> - + Date: Tue, 17 Jul 2018 08:26:19 -0400 Subject: [PATCH 6/7] use a window.location.assign instead of creating a popup to export --- web/skins/classic/views/js/filter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index 167eab63b..c3e94cec9 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -81,7 +81,7 @@ function submitToEvents( element ) { function submitToExport(element) { var form = element.form; - createPopup('?view=export&filter='+$j(form).serialize(), 'zmExport', 'export' ); + window.location.assign('?view=export&filter='+$j(form).serialize()); //createPopup('?view=export&filter_id='+form.elements['Id'].value, 'zmExport', 'export' ); } From 965ffda01eec7e253569283c674bb609e1dce0c5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Jul 2018 15:32:30 -0400 Subject: [PATCH 7/7] Add button types. fix extra px in slideheight --- .../classic/includes/export_functions.php | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 545a7eb96..4234709de 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -268,17 +268,17 @@ function exportEventImages($event, $exportDetail, $exportFrames, $myfilelist) { } else { // end if DefaultVideo ?> - +

- - - - - - + + + + + +
 
@@ -303,7 +303,7 @@ var variableslide=[]; //configure the below 3 variables to set the dimension/background color of the slideshow var slidewidth=eventWidth+'px'; //set to width of LARGEST image in your slideshow -var slideheight=eventHeight+'px'; //set to height of LARGEST iamge in your slideshow, plus any text description +var slideheight=eventHeight+'px'; //set to height of LARGEST image in your slideshow, plus any text description var slidebgcolor='#ffffff'; //configure the below variable to determine the delay between image rotations (in miliseconds) @@ -324,7 +324,7 @@ var currentslide = -1; var mytimer = null; //if (ie||dom) document.write('
'); -if (ie||dom) document.getElementById('imagevideo').innerHTML = '
'; +if (ie||dom) document.getElementById('imagevideo').innerHTML = '
'; function rotateimages(){ if (currentslide==variableslide.length-1) currentslide=0; @@ -378,7 +378,6 @@ function stepforward() { else currentslide++; changeimage(); - } function stepbackward() { @@ -867,11 +866,16 @@ function exportEvents( } foreach ( $eids as $eid ) { $event = new Event($eid); - if ( !mkdir($export_dir.'/'.$event->Id()) ) - Error("Can't mkdir $export_dir/".$event->Id()); - $exportFileList = array_merge($exportFileList, exportFileList($event, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc)); - foreach ( $exportFileList as $file ) { - exec('cp -as '.$event->Path().'/../'.$file." $export_dir/$file"); + $event_dir = $export_dir.'/'.$event->Id(); + if ( !mkdir($event_dir) ) + Error("Can't mkdir $event_dir"); + $event_exportFileList = exportFileList($event, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc); + $exportFileList = array_merge($exportFileList,$event_exportFileList); + foreach ( $event_exportFileList as $file ) { + if ( preg_match('/\.html$/', $file ) ) + continue; + Logger::Debug('cp -as '.$event->Path().'/../'.$file.' '.$export_dir.'/'.$file); + exec('cp -as '.$event->Path().'/../'.$file.' '.$export_dir.'/'.$file); } } @@ -905,11 +909,11 @@ function exportEvents( fwrite($fp, "$listFile\n"); fclose($fp); + chdir(ZM_DIR_EXPORTS); $archive = ''; if ( $exportFormat == 'tar' ) { $archive = ZM_DIR_EXPORTS.'/'.$export_root.($connkey?'_'.$connkey:'').'.tar.gz'; @unlink($archive); - chdir(ZM_DIR_EXPORTS); $command = 'nice -10 tar --create --gzip --dereference --file='.escapeshellarg($archive).' zmExport_'.$connkey.'/'; #$command = 'nice -10 tar --create --gzip --file='.escapeshellarg($archive).' --files-from='.escapeshellarg($listFile); if ( $exportStructure == 'flat' ) { @@ -920,17 +924,17 @@ function exportEvents( $archive = ZM_DIR_EXPORTS.'/'.$export_root.($connkey?'_'.$connkey:'').'.zip'; @unlink($archive); if ( $exportStructure == 'flat' ) { - $command = 'nice -10 zip -q -j '.escapeshellarg($archive).' ' . $export_dir; + $command = 'nice -10 zip -j '.escapeshellarg($archive).' zmExport_'.$connkey.'/'; #$command = 'cat '.escapeshellarg($listFile).' | nice -10 zip -q -j '.escapeshellarg($archive).' -@'; } else { - $command = 'nice -10 zip -q '.escapeshellarg($archive).' ' . $export_dir; + $command = 'nice -10 zip -r '.escapeshellarg($archive).' zmExport_' . $connkey.'/'; #$command = 'cat '.escapeshellarg($listFile).' | nice -10 zip -q '.escapeshellarg($archive).' -@'; } } else { Error("No exportFormat specified."); return false; } // if $exportFormat - + Logger::Debug("Command is $command"); exec($command, $output, $status); if ( $status ) { Error("Command '$command' returned with status $status");