zoneminder/web/includes/actions.php

1035 lines
42 KiB
PHP
Raw Normal View History

2013-03-17 07:45:21 +08:00
<?php
//
// ZoneMinder web action file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2013-03-17 07:45:21 +08:00
//
// PP - POST request handler for PHP which does not need extensions
// credit: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/
2015-09-25 03:44:35 +08:00
function do_post_request($url, $data, $optional_headers = null)
{
$params = array('http' => array(
'method' => 'POST',
'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;
}
2013-03-17 07:45:21 +08:00
function getAffectedIds( $name )
{
$names = $name."s";
$ids = array();
if ( isset($_REQUEST[$names]) || isset($_REQUEST[$name]) )
{
if ( isset($_REQUEST[$names]) )
$ids = validInt($_REQUEST[$names]);
else if ( isset($_REQUEST[$name]) )
$ids[] = validInt($_REQUEST[$name]);
}
return( $ids );
}
if ( ZM_OPT_USE_AUTH && ZM_AUTH_HASH_LOGINS && empty($user) && !empty($_REQUEST['auth']) )
{
if ( $authUser = getAuthUser( $_REQUEST['auth'] ) )
{
userLogin( $authUser['Username'], $authUser['Password'], true );
}
}
if ( !empty($action) )
{
if ( $action == "login" && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == "remote" || isset($_REQUEST['password']) ) )
{
// if true, a popup will display after login
2015-09-25 03:44:35 +08:00
// 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)
2015-08-30 01:29:52 +08:00
{
$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));
2015-09-25 03:44:35 +08:00
$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)
{
2015-09-25 03:44:35 +08:00
// 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");
2015-09-25 03:44:35 +08:00
userLogout();
$view='login';
$refreshParent = true;
}
else
{
//Let them login but show an error
echo '<script type="text/javascript">alert("'.translate('RecaptchaWarning').'"); </script>';
Error ("Invalid recaptcha secret detected");
2015-09-25 03:44:35 +08:00
}
}
}
2015-08-30 01:29:52 +08:00
}
}
2015-08-30 01:29:52 +08:00
2013-03-17 07:45:21 +08:00
// General scope actions
if ( $action == "login" && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == "remote" || isset($_REQUEST['password']) ) )
{
$username = validStr( $_REQUEST['username'] );
$password = isset($_REQUEST['password'])?validStr($_REQUEST['password']):'';
userLogin( $username, $password );
}
elseif ( $action == "logout" )
{
userLogout();
$refreshParent = true;
$view = 'none';
}
elseif ( $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 ( $action == "filter" )
{
if ( !empty($_REQUEST['subaction']) )
{
if ( $_REQUEST['subaction'] == "addterm" )
$_REQUEST['filter'] = addFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
elseif ( $_REQUEST['subaction'] == "delterm" )
$_REQUEST['filter'] = delFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
}
elseif ( canEdit( 'Events' ) )
{
if ( !empty($_REQUEST['execute']) )
$tempFilterName = "_TempFilter".time();
if ( isset($tempFilterName) )
$filterName = $tempFilterName;
elseif ( !empty($_REQUEST['newFilterName']) )
$filterName = $_REQUEST['newFilterName'];
if ( !empty($filterName) )
{
$_REQUEST['filter']['sort_field'] = validStr($_REQUEST['sort_field']);
$_REQUEST['filter']['sort_asc'] = validStr($_REQUEST['sort_asc']);
$_REQUEST['filter']['limit'] = validInt($_REQUEST['limit']);
2013-10-18 03:54:17 +08:00
$sql = "replace into Filters set Name = ".dbEscape($filterName).", Query = ".dbEscape(jsonEncode($_REQUEST['filter']));
if ( !empty($_REQUEST['AutoArchive']) )
$sql .= ", AutoArchive = ".dbEscape($_REQUEST['AutoArchive']);
if ( !empty($_REQUEST['AutoVideo']) )
$sql .= ", AutoVideo = ".dbEscape($_REQUEST['AutoVideo']);
if ( !empty($_REQUEST['AutoUpload']) )
$sql .= ", AutoUpload = ".dbEscape($_REQUEST['AutoUpload']);
if ( !empty($_REQUEST['AutoEmail']) )
$sql .= ", AutoEmail = ".dbEscape($_REQUEST['AutoEmail']);
if ( !empty($_REQUEST['AutoMessage']) )
$sql .= ", AutoMessage = ".dbEscape($_REQUEST['AutoMessage']);
if ( !empty($_REQUEST['AutoExecute']) && !empty($_REQUEST['AutoExecuteCmd']) )
$sql .= ", AutoExecute = ".dbEscape($_REQUEST['AutoExecute']).", AutoExecuteCmd = ".dbEscape($_REQUEST['AutoExecuteCmd']);
if ( !empty($_REQUEST['AutoDelete']) )
$sql .= ", AutoDelete = ".dbEscape($_REQUEST['AutoDelete']);
2013-03-17 07:45:21 +08:00
if ( !empty($_REQUEST['background']) )
2013-10-18 03:54:17 +08:00
$sql .= ", Background = ".dbEscape($_REQUEST['background']);
2013-03-17 07:45:21 +08:00
dbQuery( $sql );
$refreshParent = true;
}
}
}
}
// 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'] ) );
2013-03-17 07:45:21 +08:00
}
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'] ) );
2013-03-17 07:45:21 +08:00
$refreshParent = true;
}
else
{
foreach( getAffectedIds( 'markEid' ) as $markEid )
{
dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $markEid ) );
2013-03-17 07:45:21 +08:00
$refreshParent = 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']) );
2013-03-17 07:45:21 +08:00
}
else
{
foreach( getAffectedIds( 'markEid' ) as $markEid )
{
dbQuery( 'UPDATE Events SET Archived=? WHERE Id=?', array( $archiveVal, $markEid ) );
2013-03-17 07:45:21 +08:00
$refreshParent = true;
}
}
}
elseif ( $action == "delete" )
{
foreach( getAffectedIds( 'markEid' ) as $markEid )
{
deleteEvent( $markEid );
$refreshParent = true;
}
if ( !empty($_REQUEST['fid']) )
{
dbQuery( 'DELETE FROM Filters WHERE Name=?', array( $_REQUEST['fid'] ) );
2013-03-17 07:45:21 +08:00
//$refreshParent = true;
}
}
}
// 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' );
2015-12-09 22:23:36 +08:00
require_once( 'Monitor.php' );
2013-03-17 07:45:21 +08:00
$mid = validInt($_REQUEST['mid']);
if ( $action == "control" )
{
2015-12-09 22:23:36 +08:00
$monitor = new Monitor( $mid );
2013-03-17 07:45:21 +08:00
$ctrlCommand = buildControlCommand( $monitor );
2015-12-09 22:23:36 +08:00
sendControlCommand( $monitor->Id(), $ctrlCommand );
2013-03-17 07:45:21 +08:00
}
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 );
2013-03-17 07:45:21 +08:00
list( $brightness, $contrast, $hue, $colour ) = explode( ' ', $zmuOutput );
dbQuery( "update Monitors set Brightness = ?, Contrast = ?, Hue = ?, Colour = ? where Id = ?", array($brightness, $contrast, $hue, $colour, $mid));
2013-03-17 07:45:21 +08:00
}
}
// 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']) );
2013-03-17 07:45:21 +08:00
}
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']) );
2013-03-17 07:45:21 +08:00
}
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) );
2013-03-17 07:45:21 +08:00
$refreshParent = true;
}
}
}
}
// 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) );
2013-03-17 07:45:21 +08:00
$newFunction = validStr($_REQUEST['newFunction']);
2016-10-12 00:10:47 +08:00
# 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';
2013-03-17 07:45:21 +08:00
$oldFunction = $monitor['Function'];
$oldEnabled = $monitor['Enabled'];
if ( $newFunction != $oldFunction || $newEnabled != $oldEnabled )
{
dbQuery( "update Monitors set Function=?, Enabled=? where Id=?", array( $newFunction, $newEnabled, $mid ) );
2013-03-17 07:45:21 +08:00
$monitor['Function'] = $newFunction;
$monitor['Enabled'] = $newEnabled;
//if ( $cookies ) session_write_close();
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) );
2013-03-17 07:45:21 +08:00
if ( !empty($zid) )
{
2013-12-18 03:58:06 +08:00
$zone = dbFetchOne( "SELECT * FROM Zones WHERE MonitorId=? AND Id=?", NULL, array( $mid, $zid ) );
2013-03-17 07:45:21 +08:00
}
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) );
2013-03-17 07:45:21 +08:00
}
else
{
dbQuery( "INSERT INTO Zones SET MonitorId=?, ".implode( ", ", $changes ), array( $mid ) );
2013-03-17 07:45:21 +08:00
}
//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' );
}
2013-03-17 07:45:21 +08:00
$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'] ) );
2013-03-17 07:45:21 +08:00
$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'] ) );
2013-03-17 07:45:21 +08:00
$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) );
2013-03-17 07:45:21 +08:00
dbQuery( "update Monitors set Sequence=? where Id=?", array( $smonitor['Sequence'], $monitor['Id'] ) );
dbQuery( "update Monitors set Sequence=? WHERE Id=?", array( $monitor['Sequence'], $smonitor['Id'] ) );
2013-03-17 07:45:21 +08:00
$refreshParent = true;
fixSequences();
}
if ( $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) );
2013-03-17 07:45:21 +08:00
$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" );
}
2013-03-17 07:45:21 +08:00
$refreshParent = true;
}
}
}
}
// Monitor edit actions, monitor id derived, require edit permissions for that monitor
if ( canEdit( 'Monitors' ) )
{
if ( $action == "monitor" )
{
if ( !empty($_REQUEST['mid']) )
{
$mid = validInt($_REQUEST['mid']);
$monitor = dbFetchOne( "select * from Monitors where Id = ?", NULL, array($mid) );
2013-03-17 07:45:21 +08:00
if ( ZM_OPT_X10 )
{
$x10Monitor = dbFetchOne( "select * from TriggersX10 where MonitorId=?", NULL, array($mid) );
2013-03-17 07:45:21 +08:00
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',
Feature h264 videostorage (#1882) * Moved writing of configure options from Controller to Model. Fixes #191. * Initial commit for saving events as videos :) * Add zm_video.cpp to autotools * Add zm_video.h to autotools * Search for MP4V2 header file 3 times: mp4v2/mp4v2.h, mp4v2.h, mp4.h * Fix serve memory leak * Few minor code improvements * Added the ability to override preset, tune, profile and few other improvements * Correctly write SPS & PPS from x264 encoder headers * Remove unnessecary SPS & PPS writing code * Imported missing files from master to feature-h264-videostorage * Audio support including fixes for dts/pts, split on keyframe and update to mkv extension to prevent ffmpeg problems writing rtsp audio to mp4 containter (header problem) * Updates to make gcc happy * Add html5 video control to timeline and event to support mkv playback * Add zm_videostore.cpp to CMakeLists.txt * Remove Modern Branch for now * Fix minor bug * Option handled added in master, removing duplicate declaration * Add CaptureandRecord from zm_camera.h * Putting placeholder in for CaptureAndRecord function * Removed duplicate code and brackets * add digest auth file for cmake Conflicts: src/CMakeLists.txt * Add web dir back into Makefile.am Revert "Removed web from SUBDIRS in Makefile.am" This reverts commit d9bbcdf3a94cba4d8955fcd03bd965ed2772f34d. * Add CaptureAndRecord to vlc, still need to make it record * Resolve SegFault on videostore * Swap to mp4 container * mp4 changes * spaces to tabs, hide video stuff if video writer is turned off * Make timeline open event.mp4 instead of mkv * Missed mkv in timeline.js * Fix some issues from the merge conflict * Resolve post merge build issues with braces * Fix whitespace * Update Jpeg and Video options for passthrough options * Whitespace fix zm_camera.h * Fix array mkssing comma * Add support for Jpeg save options for h264 branch snapshot. Might remove altogether if snapshots not needed * Update VideoStoreData memory size comment * Change from config.use_mkv_storage to per monitor option VideoWriter from video branch * Fix bracket issues post merge * Clean up comments and add av_free_packet * Convert from event_directory to event file as per Video branch * Testing videojs for video playback * Fixed a missing bracket post merge and also SQL_values now used for EventID and Monitors * bring recent improvements in ffmpeg capture function into captureandrecord * Remove pict from writeAudioFramePacket as not used * Add translate options for h264 Storage options in Monitor and update en_gb file * Cherry-Pick from iconnor - make it compile on ubuntu 15.04. Which is libav 56.1.0 Conflicts: src/zm_ffmpeg.cpp src/zm_remote_camera_rtsp.cpp Conflicts: distros/ubuntu1204/changelog * Clean up videostore code and remove lots of unused code * proof of concept for dynamic/automatic video rotation using video-js plugin zoomrotate Conflicts: web/skins/classic/views/event.php * removed redundant field in sql query Conflicts: web/skins/classic/views/event.php * local storage of video js plugin * Beautify! Make the code somewhat readable. * added missing videojs.zoomrotate.js file added missing videojs.zoomrotate.js file * Typo added missing " * Added missing brackets * fix to display thumbnails when only storing snapshot.jpg * added control for video playback rate Conflicts: web/skins/classic/views/event.php * dynamically create jpegs from video file for viewing in browser * fix timeline view for SaveJPEGs monitors (without enabled VideoWriter) * only expose monitor info which are being used in client * fix segmentation fault in zma with ubuntu 14.04 and ffmpeg 2.5.8 (gcc 4.8) when libx264 is not installed * better way of detecting showing image or video in timeline and event view instead of Monitor.VideoWriter, Event.DefaultVideo is used, so even if VideoWriter/SaveJPEG option is changed, a valid image or video will always be displayed for historical events in both timeline and event view this also fixes loading videos in timeline view * Fixes problem of crashing zmc when bad packet arrives causing av_interleaved_write_frame() to return non-zero (-22). Prefilters common packet issues. Add metadata title to generated video file * Remove syslog.h * fixed SaveJPEGs are not working which is caused in errors introduced when merging with master * Update README.md * Fix build warnings specific to h264 branch, unused FrameImg, unused ret and int64_t snprintf issues * Fix PRId64 issue in travis, builds locally fine, but I can see a gcc version issue here * Fix PRId64 issue in travis, another try * Try "STDC_FORMAT_MACROS" to see if that helps Travis on gcc 4.6.3 * Revert space removal around PRId64 * video branch ffmpeg 2.9 fixes ffmpeg 2.9 patched removed SSE2 CPU * Add FFMPEGInit back * use webvvt to overlay timestamp (honoring Monitor.LabelFormat) to videos in timeline and event also fixed bug which prevented seeking in timeline video preview * ffmpeg 3.0 API build failure fixes * Update README.md * merge all the commits from the messed up iconnor_video branch * fix whitespace * revert * whitespace fixes * spelling fix * put back some text * add these back * fix spelling mistake * Steal some packet dumping routines from ffmpeg. Convert them to use our logging routines * add a test and error message if the codec is not h264 * these have been removed in master * add a view to check auth and just send the video * add some comments, and dump filename and AVFormatContext on failure to write header * add the toggle for RecordAudio so that the checkbox works to turn off Audio * Must init videoStore in constuctor * more debug and comments, return checking * Fix dropped part of sql query. * fix extra else and some whitespace * Fix missing } from merge that was preventing building. * fix tabs * get rid of use of separator, just use \n * Restore lost fixes for deprecation * Why are these failing * Respect record_audio flag when setting up video file so dont try and initiliase mp4 with unsupported audio * Forgot that I was trying to solve case of stream is true and record_audio is false. * Pass swscale_ctx back in to getCachedContext or it will create new context every frame and leak memory like a mofo. * Add libx264-dev and libmp4v2-dev to build requires to save hassle of ensuring they are installed before build. * Merge my Rotation/Orientation work and fixes for bad h264 streams * need arpa/inet for reverse lookups * pull in the new byte range code for viewing videos * Move our recording flag deeper into closeevent * add braces and only call closeEvent if there is an event * deprecate the z_frame_rate stuff which is deprecated in ffmpeg * remark out some debugging * fix for video on stream 1 * fix audio_stream to audio_st * Ignore bad decodes * fix problems with content-length causing viewing to not work in chrome/android * change logic of sending file contents to handle an off by one and be more readable * Some fixes pointed out by Maxim Romanov. Also simply the loading of events to not join the Monitors table * fix to sql for timeline * added RecordAudio to sql in README * Use sub queries instead of joins to fix errors when using new mysql defaults. * fix sql queries * Dockerfile to build feature-h264-videostorage * Must cast codec * add php-acpu as a dependency * require php5-acpu * fix typo * remove extra / * Add a line for out-of-tree builds to do api/lib/Cake/bootstrap.php * delete merge conflict files * delete merge conflict files
2017-05-16 10:02:48 +08:00
'RecordAudio' => 'toggle',
2013-03-17 07:45:21 +08:00
);
$columns = getTableColumns( 'Monitors' );
$changes = getFormChanges( $monitor, $_REQUEST['newMonitor'], $types, $columns );
if ( count( $changes ) )
{
if ( !empty($_REQUEST['mid']) )
{
$mid = validInt($_REQUEST['mid']);
dbQuery( "update Monitors set ".implode( ", ", $changes )." where Id =?", array($mid) );
2013-03-17 07:45:21 +08:00
if ( isset($changes['Name']) )
{
$saferOldName = basename( $monitor['Name'] );
$saferNewName = basename( $_REQUEST['newMonitor']['Name'] );
rename( ZM_DIR_EVENTS."/".$saferOldName, ZM_DIR_EVENTS."/".$saferNewName);
2013-03-17 07:45:21 +08:00
}
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) );
2013-03-17 07:45:21 +08:00
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'] ) );
2013-03-17 07:45:21 +08:00
}
}
}
}
elseif ( !$user['MonitorIds'] )
{
# FIXME This is actually a race condition. Should lock the table.
2013-03-17 07:45:21 +08:00
$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) ) );
2013-03-17 07:45:21 +08:00
//$view = 'none';
mkdir( ZM_DIR_EVENTS.'/'.$mid, 0755 );
$saferName = basename($_REQUEST['newMonitor']['Name']);
symlink( $mid, ZM_DIR_EVENTS.'/'.$saferName );
2013-03-17 07:45:21 +08:00
if ( isset($_COOKIE['zmGroup']) )
{
dbQuery( "UPDATE Groups SET MonitorIds = concat(MonitorIds,',".$mid."') WHERE Id=?", array($_COOKIE['zmGroup']) );
2013-03-17 07:45:21 +08:00
}
}
$restart = true;
}
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) );
2013-03-17 07:45:21 +08:00
}
elseif ( !$user['MonitorIds'] )
{
if ( !$x10Monitor )
{
dbQuery( "insert into TriggersX10 set MonitorId = ?,".implode( ", ", $x10Changes ), array( $mid ) );
2013-03-17 07:45:21 +08:00
}
else
{
dbQuery( "delete from TriggersX10 where MonitorId = ?", array($mid) );
2013-03-17 07:45:21 +08:00
}
}
$restart = true;
}
}
if ( $restart )
{
$monitor = dbFetchOne( "select * from Monitors where Id = ?", NULL, array($mid) );
//fixDevices();
2013-03-17 07:45:21 +08:00
//if ( $cookies )
//session_write_close();
if ( daemonCheck() )
{
zmaControl( $monitor, "stop" );
zmcControl( $monitor, "restart" );
zmaControl( $monitor, "start" );
}
if ( $monitor['Controllable'] ) {
require_once( 'control_functions.php' );
sendControlCommand( $mid, 'quit' );
}
2013-03-17 07:45:21 +08:00
//daemonControl( 'restart', 'zmwatch.pl' );
$refreshParent = true;
}
$view = 'none';
}
if ( $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) ) )
2013-03-17 07:45:21 +08:00
{
if ( daemonCheck() )
{
zmaControl( $monitor, "stop" );
zmcControl( $monitor, "stop" );
}
// This is the important stuff
dbQuery( "delete from Monitors where Id = ?", array($markMid) );
dbQuery( "delete from Zones where MonitorId = ?", array($markMid) );
2013-03-17 07:45:21 +08:00
if ( ZM_OPT_X10 )
dbQuery( "delete from TriggersX10 where MonitorId=?", array($markMid) );
2013-03-17 07:45:21 +08:00
fixSequences();
// 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 )
{
// Slight hack, we maybe should load *, but we happen to know that the deleteEvent function uses Id and StartTime.
$markEids = dbFetchAll( "SELECT Id,StartTime FROM Events WHERE MonitorId=?", NULL, array($markMid) );
2013-03-17 07:45:21 +08:00
foreach( $markEids as $markEid )
deleteEvent( $markEid, $markMid );
2013-03-17 07:45:21 +08:00
2014-06-06 03:23:15 +08:00
deletePath( ZM_DIR_EVENTS."/".basename($monitor['Name']) );
deletePath( ZM_DIR_EVENTS."/".$monitor['Id'] ); // I'm trusting the Id.
2013-03-17 07:45:21 +08:00
}
}
}
}
}
}
}
// 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']) );
2013-03-17 07:45:21 +08:00
}
else
{
dbQuery( "insert into Devices set Name=?, KeyString=?", array( $_REQUEST['newDevice']['Name'], $_REQUEST['newDevice']['KeyString'] ) );
2013-03-17 07:45:21 +08:00
}
$refreshParent = true;
$view = 'none';
}
}
elseif ( $action == "delete" )
{
if ( isset($_REQUEST['markDids']) )
{
foreach( $_REQUEST['markDids'] as $markDid )
{
dbQuery( "delete from Devices where Id=?", array($markDid) );
2013-03-17 07:45:21 +08:00
$refreshParent = true;
}
}
}
}
// Group view actions
2015-08-16 02:22:13 +08:00
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
2015-08-16 03:03:11 +08:00
if ( canEdit( 'Groups' ) ) {
if ( $action == "group" ) {
# Should probably verfy 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
$monitors = empty( $_POST['newGroup']['MonitorIds'] ) ? NULL : implode(',', $_POST['newGroup']['MonitorIds']);
if ( !empty($_POST['gid']) ) {
dbQuery( "UPDATE Groups SET Name=?, MonitorIds=? WHERE Id=?", array($_POST['newGroup']['Name'], $monitors, $_POST['gid']) );
} else {
dbQuery( "INSERT INTO Groups SET Name=?, MonitorIds=?", array( $_POST['newGroup']['Name'], $monitors ) );
}
$view = 'none';
}
if ( !empty($_REQUEST['gid']) && $action == "delete" ) {
dbQuery( "delete from Groups where Id = ?", array($_REQUEST['gid']) );
if ( isset($_COOKIE['zmGroup']) )
{
if ( $_REQUEST['gid'] == $_COOKIE['zmGroup'] )
{
unset( $_COOKIE['zmGroup'] );
setcookie( "zmGroup", "", time()-3600*24*2 );
$refreshParent = true;
}
}
2015-08-16 02:22:13 +08:00
}
$refreshParent = true;
}
2013-03-17 07:45:21 +08:00
// System edit actions
if ( canEdit( 'System' ) )
{
if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'server' ) ) {
2015-09-16 05:26:31 +08:00
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 ( $action == "version" && isset($_REQUEST['option']) )
2013-03-17 07:45:21 +08:00
{
$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;
}
}
}
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 ) );
2013-03-17 07:45:21 +08:00
$changed = true;
}
}
if ( $changed )
{
switch( $_REQUEST['tab'] )
{
case "system" :
case "config" :
case "paths" :
$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']) );
2013-03-17 07:45:21 +08:00
else
$dbUser = array();
$types = array();
$changes = getFormChanges( $dbUser, $_REQUEST['newUser'], $types );
if ( $_REQUEST['newUser']['Password'] )
2013-10-18 03:54:17 +08:00
$changes['Password'] = "Password = password(".dbEscape($_REQUEST['newUser']['Password']).")";
2013-03-17 07:45:21 +08:00
else
unset( $changes['Password'] );
if ( count( $changes ) )
{
if ( !empty($_REQUEST['uid']) )
{
dbQuery( "update Users set ".implode( ", ", $changes )." where Id = ?", array($_REQUEST['uid']) );
2013-03-17 07:45:21 +08:00
}
else
{
dbQuery( "insert into Users set ".implode( ", ", $changes ) );
2013-03-17 07:45:21 +08:00
}
$refreshParent = true;
if ( $dbUser['Username'] == $user['Username'] )
userLogin( $dbUser['Username'], $dbUser['Password'] );
}
$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) );
2013-03-17 07:45:21 +08:00
}
}
elseif ( $action == "delete" )
{
if ( isset($_REQUEST['runState']) )
dbQuery( "delete from States where Name=?", array($_REQUEST['runState']) );
2013-03-17 07:45:21 +08:00
if ( isset($_REQUEST['markUids']) )
{
foreach( $_REQUEST['markUids'] as $markUid )
dbQuery( "delete from Users where Id = ?", array($markUid) );
2013-03-17 07:45:21 +08:00
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) );
2013-03-17 07:45:21 +08:00
$types = array();
$changes = getFormChanges( $dbUser, $_REQUEST['newUser'], $types );
if ( !empty($_REQUEST['newUser']['Password']) )
2013-10-18 03:54:17 +08:00
$changes['Password'] = "Password = password(".dbEscape($_REQUEST['newUser']['Password']).")";
2013-03-17 07:45:21 +08:00
else
unset( $changes['Password'] );
if ( count( $changes ) )
{
dbQuery( "update Users set ".implode( ", ", $changes )." where Id=?", array($uid) );
2013-03-17 07:45:21 +08:00
$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();
}
}
?>