/* ** ** conf.cpp ** Copyright 1999 Jeroen Vreeken (pe1rxq@chello.nl) ** ** This software is licensed under the terms of the GNU General ** Public License (GPL). Please see the file COPYING for details. ** ** */ #include #include #include "motion.hpp" #include "util.hpp" #include "logger.hpp" #include "conf_edit.hpp" /* Forward Declares */ void conf_process(struct ctx_motapp *motapp, FILE *fp, int threadnbr); /*Configuration parameters */ struct ctx_parm config_parms[] = { { "daemon", "############################################################\n" "# System control configuration parameters\n" "############################################################\n\n" "# Start in daemon (background) mode and release terminal.", 1 ,PARM_TYP_BOOL,PARM_CAT_00,WEBUI_LEVEL_ADVANCED}, { "setup_mode", "# Start in Setup-Mode, daemon disabled.", 0 ,PARM_TYP_BOOL ,PARM_CAT_00,WEBUI_LEVEL_ADVANCED}, { "conf_filename", "# Configuration file name.", 1 ,PARM_TYP_STRING ,PARM_CAT_00,WEBUI_LEVEL_ADVANCED}, { "pid_file", "# File to store the process ID.", 1 ,PARM_TYP_STRING ,PARM_CAT_00,WEBUI_LEVEL_ADVANCED}, { "log_file", "# File to write logs messages into. If not defined stderr and syslog is used.", 1, PARM_TYP_STRING, PARM_CAT_00 , WEBUI_LEVEL_ADVANCED}, { "log_level", "# Level of log messages [1..9] (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL).", 1, PARM_TYP_INT, PARM_CAT_00, WEBUI_LEVEL_LIMITED}, { "log_type", "# Filter to log messages by type (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL).", 1, PARM_TYP_STRING, PARM_CAT_00, WEBUI_LEVEL_LIMITED}, { "quiet", "# Do not sound beeps when detecting motion", 0, PARM_TYP_BOOL, PARM_CAT_01, WEBUI_LEVEL_LIMITED}, { "native_language", "# Native language support.", 1, PARM_TYP_STRING, PARM_CAT_00, WEBUI_LEVEL_LIMITED}, { "camera_name", "# User defined name for the camera.", 0, PARM_TYP_STRING,PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, { "camera_id", "# Numeric identifier for the camera.", 0, PARM_TYP_INT,PARM_CAT_01,WEBUI_LEVEL_ADVANCED}, /* camera and camera_dir must be last in this list */ { "target_dir", "# Target directory for pictures, snapshots and movies", 0,PARM_TYP_STRING,PARM_CAT_01, WEBUI_LEVEL_LIMITED }, { "videodevice", "# Video device (e.g. /dev/video0) to be used for capturing.", 0,PARM_TYP_STRING,PARM_CAT_01,WEBUI_LEVEL_ADVANCED }, { "vid_control_params", "# Parameters to control video device. See motion_guide.html", 0,PARM_TYP_STRING,PARM_CAT_01,WEBUI_LEVEL_LIMITED}, { "v4l2_palette", "# Preferred color palette to be used for the video device", 0, PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_ADVANCED}, { "input", "# The input number to be used on the video device.", 0, PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, { "norm", "# The video norm to use for video capture and TV tuner cards.", 0,PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, { "frequency", "# The frequency to set the tuner to (kHz) for TV tuner cards", 0,PARM_TYP_INT, PARM_CAT_01,WEBUI_LEVEL_ADVANCED }, { "roundrobin_frames", "# Number of frames to capture in each roundrobin step", 0,PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_LIMITED }, { "roundrobin_skip", "# Number of frames to skip before each roundrobin step", 0,PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_LIMITED }, { "roundrobin_switchfilter", "# Try to filter out noise generated by roundrobin", 0,PARM_TYP_BOOL, PARM_CAT_01, WEBUI_LEVEL_LIMITED}, { "netcam_url", "# The full URL of the network camera stream.", 0, PARM_TYP_STRING, PARM_CAT_01, WEBUI_LEVEL_ADVANCED}, { "netcam_highres", "# Optional high resolution URL for rtsp/rtmp cameras only.", 0, PARM_TYP_STRING, PARM_CAT_01, WEBUI_LEVEL_ADVANCED}, { "netcam_userpass", "# Username and password for network camera. Syntax username:password", 0, PARM_TYP_STRING, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, { "netcam_use_tcp", "# Use TCP transport for RTSP/RTMP connections to camera.", 1, PARM_TYP_STRING, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, { "mmalcam_name", "# Name of mmal camera (e.g. vc.ril.camera for pi camera).", 0, PARM_TYP_STRING, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, { "mmalcam_control_params", "# Camera control parameters (see raspivid/raspistill tool documentation)", 0, PARM_TYP_STRING, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, { "width", "############################################################\n" "# Image Processing configuration parameters\n" "############################################################\n\n" "# Image width in pixels.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_ADVANCED }, { "height", "# Image height in pixels.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_ADVANCED}, { "framerate", "# Maximum number of frames to be captured per second.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "rotate", "# Number of degrees to rotate image.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "flip_axis", "# Flip image over a given axis", 0, PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "locate_motion_mode", "# Draw a locate box around the moving object.", 0, PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "locate_motion_style", "# Set the look and style of the locate box.", 0, PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "text_left", "# Text to be overlayed in the lower left corner of images", 0,PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "text_right", "# Text to be overlayed in the lower right corner of images.", 0,PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "text_changes", "# Overlay number of changed pixels in upper right corner of images.", 0,PARM_TYP_BOOL, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "text_scale", "# Scale factor for text overlayed on images.", 0,PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "text_event", "# The special event conversion specifier %C", 0,PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "emulate_motion", "############################################################\n" "# Motion detection configuration parameters\n" "############################################################\n\n" "# Always save pictures and movies even if there was no motion.", 0,PARM_TYP_BOOL, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "threshold", "# Threshold for number of changed pixels that triggers motion.", 0,PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "threshold_maximum", "# The maximum threshold for number of changed pixels that triggers motion.", 0,PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "threshold_tune", "# Enable tuning of the threshold down if possible.", 0,PARM_TYP_BOOL, PARM_CAT_02, WEBUI_LEVEL_LIMITED}, { "noise_level", "# Noise threshold for the motion detection.", 0,PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "noise_tune", "# Automatically tune the noise threshold", 0,PARM_TYP_BOOL, PARM_CAT_02, WEBUI_LEVEL_LIMITED}, { "despeckle_filter", "# Despeckle the image using (E/e)rode or (D/d)ilate or (l)abel.", 0,PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "area_detect", "# Area number used to trigger the on_area_detected script.", 0,PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "mask_file", "# Full path and file name for motion detection mask PGM file.", 0,PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_ADVANCED }, { "mask_privacy", "# Full path and file name for privacy mask PGM file.", 0,PARM_TYP_STRING, PARM_CAT_02, WEBUI_LEVEL_ADVANCED }, { "smart_mask_speed", "# The value defining how slow or fast the smart motion mask created and used.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "lightswitch_percent", "# Percentage of image that triggers a lightswitch detected.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED}, { "lightswitch_frames", "# When lightswitch is detected, ignore this many frames", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "minimum_motion_frames", "# Number of images that must contain motion to trigger an event.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "event_gap", "# Gap in seconds of no motion detected that triggers the end of an event.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "pre_capture", "# The number of pre-captured (buffered) pictures from before motion.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "post_capture", "# Number of frames to capture after motion is no longer detected.", 0, PARM_TYP_INT, PARM_CAT_02, WEBUI_LEVEL_LIMITED }, { "on_event_start", "############################################################\n" "# Script execution configuration parameters\n" "############################################################\n\n" "# Command to be executed when an event starts.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED }, { "on_event_end", "# Command to be executed when an event ends.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED}, { "on_picture_save", "# Command to be executed when a picture is saved.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED }, { "on_area_detected", "# Command to be executed when motion in a predefined area is detected", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED }, { "on_motion_detected", "# Command to be executed when motion is detected", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED }, { "on_movie_start", "# Command to be executed when a movie file is created.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED}, { "on_movie_end", "# Command to be executed when a movie file is closed.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED }, { "on_camera_lost", "# Command to be executed when a camera can't be opened or if it is lost", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED }, { "on_camera_found", "# Command to be executed when a camera that was lost has been found.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED}, { "picture_output", "############################################################\n" "# Picture output configuration parameters\n" "############################################################\n\n" "# Output pictures when motion is detected", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "picture_output_motion", "# Output pictures with only the pixels moving object (ghost images)", 0, PARM_TYP_BOOL, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "picture_type", "# Format for the output pictures.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED}, { "picture_quality", "# The quality (in percent) to be used in the picture compression", 0, PARM_TYP_INT, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "picture_exif", "# Text to include in a JPEG EXIF comment", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "picture_filename", "# File name(without extension) for pictures relative to target directory", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "snapshot_interval", "############################################################\n" "# Snapshot output configuration parameters\n" "############################################################\n\n" "# Make automated snapshot every N seconds", 0, PARM_TYP_INT, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "snapshot_filename", "# File name(without extension) for snapshots relative to target directory", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED}, { "movie_output", "############################################################\n" "# Movie output configuration parameters\n" "############################################################\n\n" "# Create movies of motion events.", 0, PARM_TYP_BOOL, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_output_motion", "# Create movies of moving pixels of motion events.", 0, PARM_TYP_BOOL, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_max_time", "# Maximum length of movie in seconds.", 0, PARM_TYP_INT, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_bps", "# The fixed bitrate to be used by the movie encoder. Ignore quality setting", 0, PARM_TYP_INT, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_quality", "# The encoding quality of the movie. (0=use bitrate. 1=worst quality, 100=best)", 0, PARM_TYP_INT, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_codec", "# Container/Codec to used for the movie. See motion_guide.html", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_passthrough", "# Pass through from the camera to the movie without decode/encoding.", 0, PARM_TYP_BOOL, PARM_CAT_03, WEBUI_LEVEL_ADVANCED }, { "movie_filename", "# File name(without extension) for movies relative to target directory", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_extpipe_use", "# Use pipe and external encoder for creating movies.", 0, PARM_TYP_BOOL, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "movie_extpipe", "# Full path and options for external encoder of movies from raw images", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_RESTRICTED }, { "timelapse_interval", "############################################################\n" "# Timelapse output configuration parameters\n" "############################################################\n\n" "# Interval in seconds between timelapse captures.", 0, PARM_TYP_INT, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "timelapse_mode", "# Timelapse file rollover mode. See motion_guide.html for options and uses.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED}, { "timelapse_fps", "# Frame rate for timelapse playback", 0, PARM_TYP_INT, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "timelapse_codec", "# Container/Codec for timelapse movie.", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED}, { "timelapse_filename", "# File name(without extension) for timelapse movies relative to target directory", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED}, { "video_pipe", "############################################################\n" "# Loopback pipe configuration parameters\n" "############################################################\n\n" "# v4l2 loopback device to receive normal images", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED }, { "video_pipe_motion", "# v4l2 loopback device to receive motion images", 0, PARM_TYP_STRING, PARM_CAT_03, WEBUI_LEVEL_LIMITED}, { "webcontrol_port", "############################################################\n" "# Webcontrol configuration parameters\n" "############################################################\n\n" "# Port number used for the webcontrol.", 1, PARM_TYP_STRING, PARM_CAT_04, WEBUI_LEVEL_ADVANCED}, { "webcontrol_ipv6", "# Enable IPv6 addresses.", 0, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_ADVANCED}, { "webcontrol_localhost", "# Restrict webcontrol connections to the localhost.", 1, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_ADVANCED }, { "webcontrol_parms", "# Type of configuration options to allow via the webcontrol.", 1, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_NEVER}, { "webcontrol_interface", "# Method that webcontrol should use for interface with user.", 1, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "webcontrol_auth_method", "# The authentication method for the webcontrol", 0, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED}, { "webcontrol_authentication", "# Authentication string for the webcontrol. Syntax username:password", 1, PARM_TYP_STRING, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED}, { "webcontrol_tls", "# Use ssl / tls for the webcontrol", 0, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED }, { "webcontrol_cert", "# Full path and file name of the certificate file for tls", 1, PARM_TYP_STRING, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED}, { "webcontrol_key", "# Full path and file name of the key file for tls", 1, PARM_TYP_STRING, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED}, { "webcontrol_cors_header", "# The cross-origin resource sharing (CORS) header for webcontrol", 0, PARM_TYP_STRING, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED }, { "stream_port", "############################################################\n" "# Live stream configuration parameters\n" "############################################################\n\n" "# The port number for the live stream.", 0, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_ADVANCED }, { "stream_localhost", "# Restrict stream connections to the localhost.", 0, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_ADVANCED }, { "stream_auth_method", "# Authentication method for live stream.", 0, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED}, { "stream_authentication", "# The authentication string for the stream. Syntax username:password", 1, PARM_TYP_STRING, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED }, { "stream_tls", "# Use ssl / tls for stream.", 0, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED }, { "stream_cors_header", "# The cross-origin resource sharing (CORS) header for the stream", 0, PARM_TYP_STRING, PARM_CAT_04, WEBUI_LEVEL_RESTRICTED }, { "stream_preview_scale", "# Percentage to scale the stream image on the webcontrol.", 0, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "stream_preview_newline", "# Have the stream image start on a new line of the webcontrol", 0, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "stream_preview_method", "# Method for showing stream on webcontrol.", 0, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "stream_quality", "# Quality of the jpeg images produced for stream.", 0, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "stream_grey", "# Provide the stream images in black and white", 0, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "stream_motion", "# Output frames at 1 fps when no motion is detected.", 0, PARM_TYP_BOOL, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "stream_maxrate", "# Maximum framerate of images provided for stream", 0, PARM_TYP_INT, PARM_CAT_04, WEBUI_LEVEL_LIMITED }, { "database_type", "############################################################\n" "# Database and SQL Configuration parameters\n" "############################################################\n\n" "# The type of database being used if any.", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED}, { "database_dbname", "# Database name to use. For sqlite3, the full path and name.", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, { "database_host", "# The host on which the database is located", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, { "database_port", "# Port used by the database.", 0, PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, { "database_user", "# User account name for database.", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_RESTRICTED }, { "database_password", "# User password for database.", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_RESTRICTED }, { "database_busy_timeout", "# Database wait for unlock time", 0, PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, { "sql_log_picture", "# Log to the database when creating motion triggered image file", 0,PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "sql_log_snapshot", "# Log to the database when creating a snapshot image file", 0,PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED}, { "sql_log_movie", "# Log to the database when creating motion triggered movie file", 0,PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "sql_log_timelapse", "# Log to the database when creating timelapse movie file", 0,PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED}, { "sql_query_start", "# SQL query at event start. See motion_guide.html", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, { "sql_query_stop", "# SQL query at event stop. See motion_guide.html", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, { "sql_query", "# SQL query string that is sent to the database. See motion_guide.html", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED}, { "track_type", "############################################################\n" "# Tracking configuration parameters\n" "############################################################\n\n" "# Method used by tracking camera. See motion_guide.html", 0, PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "track_auto", "# Enable auto tracking", 0, PARM_TYP_BOOL, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "track_move_wait", "# Delay to wait for after tracking movement as number of picture frames.", 0, PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "track_generic_move", "# Command to execute to move a camera in generic tracking mode", 0, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "track_step_angle_x", "# Angle in degrees the camera moves per step on the X-axis with auto-track", 0, PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "track_step_angle_y", "# Angle in degrees the camera moves per step on the Y-axis with auto-track.", 0, PARM_TYP_INT, PARM_CAT_05, WEBUI_LEVEL_LIMITED }, { "camera", "##############################################################\n" "# Camera config files - One for each camera.\n" "##############################################################", 1, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, /* using a conf.d style camera addition */ { "camera_dir", "##############################################################\n" "# Directory to read '.conf' files for cameras.\n" "##############################################################", 1, PARM_TYP_STRING, PARM_CAT_05, WEBUI_LEVEL_ADVANCED }, { NULL, NULL, 0, (enum PARM_TYP)0, (enum PARM_CAT)0, (enum WEBUI_LEVEL)0 } }; /* * Array of deprecated config options: * When deprecating an option, remove it from above (config_parms array) * and create an entry in this array of name, last version, info, * and (if applicable) a replacement conf value and copy funcion. * Upon reading a deprecated config option, a warning will be logged * with the given information and last version it was used in. * If set, the given value will be copied into the conf value * for backwards compatibility. */ struct ctx_parm_depr config_parms_depr[] = { { "thread", "3.4.1", "The \"thread\" option has been replaced by the \"camera\"", "camera" }, { "ffmpeg_timelapse", "4.0.1", "\"ffmpeg_timelapse\" replaced with \"timelapse_interval\"", "timelapse_interval" }, { "ffmpeg_timelapse_mode", "4.0.1", "\"ffmpeg_timelapse_mode\" replaced with \"timelapse_mode\"", "timelapse_mode" }, { "brightness", "4.1.1", "\"brightness\" replaced with \"vid_control_params\"", "vid_control_params" }, { "contrast", "4.1.1", "\"contrast\" replaced with \"vid_control_params\"", "vid_control_params" }, { "saturation", "4.1.1", "\"saturation\" replaced with \"vid_control_params\"", "vid_control_params" }, { "hue", "4.1.1", "\"hue\" replaced with \"vid_control_params\"", "vid_control_params" }, { "power_line_frequency", "4.1.1", "\"power_line_frequency\" replaced with \"vid_control_params\"", "vid_control_params" }, { "text_double", "4.1.1", "\"text_double\" replaced with \"text_scale\"", "text_scale" }, { "webcontrol_html_output", "4.1.1", "\"webcontrol_html_output\" replaced with \"webcontrol_interface\"", "webcontrol_interface" }, { "lightswitch", "4.1.1", "\"lightswitch\" replaced with \"lightswitch_percent\"", "lightswitch_percent" }, { "ffmpeg_output_movies", "4.1.1", "\"ffmpeg_output_movies\" replaced with \"movie_output\"", "movie_output" }, { "ffmpeg_output_debug_movies", "4.1.1", "\"ffmpeg_output_debug_movies\" replaced with \"movie_output_motion\"", "movie_output_motion" }, { "max_movie_time", "4.1.1", "\"max_movie_time\" replaced with \"movie_max_time\"", "movie_max_time" }, { "ffmpeg_bps", "4.1.1", "\"ffmpeg_bps\" replaced with \"movie_bps\"", "movie_bps" }, { "ffmpeg_variable_bitrate", "4.1.1", "\"ffmpeg_variable_bitrate\" replaced with \"movie_quality\"", "movie_quality" }, { "ffmpeg_video_codec", "4.1.1", "\"ffmpeg_video_codec\" replaced with \"movie_codec\"", "movie_codec" }, { "ffmpeg_passthrough", "4.1.1", "\"ffmpeg_passthrough\" replaced with \"movie_passthrough\"", "movie_passthrough" }, { "use_extpipe", "4.1.1", "\"use_extpipe\" replaced with \"movie_extpipe_use\"", "movie_extpipe_use" }, { "extpipe", "4.1.1", "\"extpipe\" replaced with \"movie_extpipe\"", "movie_extpipe" }, { "output_pictures", "4.1.1", "\"output_pictures\" replaced with \"picture_output\"", "picture_output" }, { "output_debug_pictures", "4.1.1", "\"output_debug_pictures\" replaced with \"picture_output_motion\"", "picture_output_motion" }, { "quality", "4.1.1", "\"quality\" replaced with \"picture_quality\"", "picture_quality" }, { "exif_text", "4.1.1", "\"exif_text\" replaced with \"picture_exif\"", "picture_exif" }, { "motion_video_pipe", "4.1.1", "\"motion_video_pipe\" replaced with \"video_pipe_motion\"", "video_pipe_motion" }, { "ipv6_enabled", "4.1.1", "\"ipv6_enabled\" replaced with \"webcontrol_ipv6\"", "webcontrol_ipv6" }, { "rtsp_uses_tcp", "4.1.1", "\"rtsp_uses_tcp\" replaced with \"netcam_use_tcp\"", "netcam_use_tcp" }, { "switchfilter", "4.1.1", "\"switchfilter\" replaced with \"roundrobin_switchfilter\"", "roundrobin_switchfilter" }, { "logfile", "4.1.1", "\"logfile\" replaced with \"log_file\"", "log_file" }, { "process_id_file", "4.1.1", "\"process_id_file\" replaced with \"pid_file\"", "pid_file" }, { NULL, NULL, NULL, NULL} }; /** Prints usage and options allowed from Command-line. */ static void usage(void) { printf("motion Version %s, Copyright 2000-2019 Jeroen Vreeken/Folkert van Heusden/Kenneth Lavrsen/Motion-Project maintainers\n",PACKAGE_VERSION); printf("\nHome page :\t https://motion-project.github.io/ \n"); printf("\nusage:\tmotion [options]\n"); printf("\n\n"); printf("Possible options:\n\n"); printf("-b\t\t\tRun in background (daemon) mode.\n"); printf("-n\t\t\tRun in non-daemon mode.\n"); printf("-s\t\t\tRun in setup mode.\n"); printf("-c config\t\tFull path and filename of config file.\n"); printf("-d level\t\tLog level (1-9) (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). default: 6 / NTC.\n"); printf("-k type\t\t\tType of log (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL). default: ALL.\n"); printf("-p process_id_file\tFull path and filename of process id file (pid file).\n"); printf("-l log file \t\tFull path and filename of log file.\n"); printf("-m\t\t\tDisable motion detection at startup.\n"); printf("-h\t\t\tShow this screen.\n"); printf("\n"); printf("Motion is configured using a config file only. If none is supplied,\n"); printf("it will read motion.conf from current directory, ~/.motion or %s.\n", sysconfdir); printf("%s\n", sysconfdir); printf("\n"); } /** Process Command-line options specified */ static void conf_cmdline(struct ctx_motapp *motapp) { int c; while ((c = getopt(motapp->argc, motapp->argv, "bc:d:hmns?p:k:l:")) != EOF) switch (c) { case 'c': conf_edit_set(motapp, -1, (char*)"conf_filename", optarg); break; case 'b': conf_edit_set(motapp, -1, (char*)"daemon", (char*)"on"); break; case 'n': conf_edit_set(motapp, -1, (char*)"daemon", (char*)"off"); break; case 's': conf_edit_set(motapp, -1, (char*)"setup_mode", (char*)"on"); break; case 'd': conf_edit_set(motapp, -1, (char*)"log_level", optarg); break; case 'k': conf_edit_set(motapp, -1, (char*)"log_type", optarg); break; case 'p': conf_edit_set(motapp, -1, (char*)"pid_file", optarg); break; case 'l': conf_edit_set(motapp, -1, (char*)"log_file", optarg); break; case 'm': motapp->pause = TRUE; break; case 'h': case '?': default: usage(); exit(1); } optind = 1; } static void conf_parm_camera(struct ctx_motapp *motapp, char *str) { int indx_cams, indx; char parm_val[PATH_MAX]; FILE *fp; fp = fopen(str, "r"); if (!fp) { MOTION_LOG(ALR, TYPE_ALL, SHOW_ERRNO ,_("Camera config file %s not found"), str); return; } /* Find the current number of threads defined. */ indx_cams = 0; while (motapp->cam_list[indx_cams] != NULL){ indx_cams++; }; /* Index starts at zero (+1) plus another for our new camera(+2)*/ motapp->cam_list = (struct ctx_cam **)myrealloc( motapp->cam_list, sizeof(struct ctx_cam *) * (indx_cams + 2), "config_camera"); motapp->cam_list[indx_cams] = (struct ctx_cam *)mymalloc(sizeof(struct ctx_cam)); motapp->cam_list[indx_cams + 1] = NULL; conf_edit_dflt_cam(motapp->cam_list[indx_cams]); indx = 0; while (config_parms[indx].parm_name != NULL) { conf_edit_get(motapp->cam_list[0],(char *)config_parms[indx].parm_name ,parm_val, config_parms[indx].parm_cat); /* Once we adjust all the code to allow for "" being same as NULL we can remove this*/ if ((config_parms[indx].parm_type == PARM_TYP_STRING) && (mystreq(parm_val,""))) { conf_edit_set(motapp,indx_cams, (char *)config_parms[indx].parm_name, NULL); } else { conf_edit_set(motapp,indx_cams, (char *)config_parms[indx].parm_name, parm_val); } indx++; } /* Process the camera's config file and notify user on console. */ MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO ,_("Processing camera config file %s"), str); snprintf(motapp->cam_list[indx_cams]->conf_filename ,sizeof(motapp->cam_list[indx_cams]->conf_filename),"%s", str); conf_process(motapp, fp, indx_cams); myfclose(fp); /*Cascade new pointers to all cameras. */ indx_cams = 0; while (motapp->cam_list[indx_cams] != NULL){ motapp->cam_list[indx_cams]->motapp = motapp; motapp->cam_list[indx_cams]->cam_list = motapp->cam_list; indx_cams++; } return; } /** Process camera_dir */ static void conf_parm_camera_dir(struct ctx_motapp *motapp, char *str) { DIR *dp; struct dirent *ep; size_t name_len; int i; char conf_file[PATH_MAX]; dp = opendir(str); if (dp != NULL) { while( (ep = readdir(dp)) ) { name_len = strlen(ep->d_name); if ((name_len > strlen(".conf")) && (mystreq(".conf",ep->d_name + name_len - strlen(".conf")))) { memset(conf_file, '\0', sizeof(conf_file)); snprintf(conf_file, sizeof(conf_file) - 1, "%s/%s", str, ep->d_name); MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO ,_("Processing config file %s"), conf_file ); conf_parm_camera(motapp, conf_file); /* The last ctx_cam thread would be ours, * set it as created from conf directory. */ i = 0; while (motapp->cam_list[++i]); motapp->cam_list[i-1]->from_conf_dir = TRUE; } } closedir(dp); } else { MOTION_LOG(ALR, TYPE_ALL, SHOW_ERRNO ,_("Camera directory config %s not found"), str); } /* Store the given config value to allow writing it out */ conf_edit_set(motapp,0, (char *)"camera_dir", str); return; } /** Process each line from the config file. */ void conf_process(struct ctx_motapp *motapp, FILE *fp, int threadnbr) { char line[PATH_MAX], *cmd = NULL, *arg1 = NULL; char *beg = NULL, *end = NULL; while (fgets(line, PATH_MAX-1, fp)) { if (!(line[0] == '#' || line[0] == ';' || strlen(line) < 2)) { arg1 = NULL; /* Trim white space and any CR or LF at the end of the line. */ end = line + strlen(line) - 1; /* Point to the last non-null character in the string. */ while (end >= line && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')){ end--; } *(end+1) = '\0'; if (strlen(line) == 0) continue; /* Trim leading whitespace from the line and find command. */ beg = line; while (*beg == ' ' || *beg == '\t'){ beg++; } cmd = beg; /* Command starts here. */ while (*beg != ' ' && *beg != '\t' && *beg != '=' && *beg != '\0'){ beg++; } *beg = '\0'; /* Command string terminates here. */ /* Trim space between command and argument. */ beg++; if (strlen(beg) > 0) { while (*beg == ' ' || *beg == '\t' || *beg == '=' || *beg == '\n' || *beg == '\r'){ beg++; } /* Strip quotes from around arg */ if ((beg[0] == '"' && beg[strlen(beg)-1] == '"') || (beg[0] == '\'' && beg[strlen(beg)-1] == '\'')) { beg[strlen(beg)-1] = '\0'; beg++; } arg1 = beg; /* Argument starts here */ } /* Ignore camera/dir in sub files */ if (threadnbr == -1){ conf_edit_set(motapp, threadnbr, cmd, arg1); } else { if (mystreq(cmd,"camera_dir")) { if (threadnbr == 0) conf_parm_camera_dir(motapp, arg1); } else if (mystreq(cmd,"camera")) { if (threadnbr == 0) conf_parm_camera(motapp, arg1); } else { conf_edit_set(motapp, threadnbr, cmd, arg1); } } } } return; } /** Write the configuration(s) to the log */ void conf_parms_log(struct ctx_cam **cam_list) { int i, threadnbr, diff_val; char parm_val[PATH_MAX], parm_main[PATH_MAX]; MOTION_LOG(INF, TYPE_ALL, NO_ERRNO ,_("Writing configuration parameters from all files")); threadnbr = 0; while (cam_list[threadnbr]!= NULL){ motion_log(INF, TYPE_ALL, NO_ERRNO,0 ,_("Camera %d - Config file: %s"), threadnbr, cam_list[threadnbr]->conf_filename); i = 0; while (config_parms[i].parm_name != NULL) { diff_val = TRUE; conf_edit_get(cam_list[threadnbr], config_parms[i].parm_name , parm_val ,config_parms[i].parm_cat); if (threadnbr > 0){ conf_edit_get(cam_list[0], config_parms[i].parm_name , parm_main ,config_parms[i].parm_cat); if (mystreq(parm_val, parm_main)) diff_val = FALSE; } if (diff_val) { if (mystreq(config_parms[i].parm_name, "netcam_url") || mystreq(config_parms[i].parm_name, "netcam_userpass") || mystreq(config_parms[i].parm_name, "netcam_highres") || mystreq(config_parms[i].parm_name, "stream_cors_header") || mystreq(config_parms[i].parm_name, "stream_authentication") || mystreq(config_parms[i].parm_name, "webcontrol_authentication") || mystreq(config_parms[i].parm_name, "webcontrol_cors_header") || mystreq(config_parms[i].parm_name, "webcontrol_key") || mystreq(config_parms[i].parm_name, "webcontrol_cert") || mystreq(config_parms[i].parm_name, "database_user") || mystreq(config_parms[i].parm_name, "database_password")) { motion_log(INF, TYPE_ALL, NO_ERRNO,0 ,_("%-25s "), config_parms[i].parm_name); } else { if (strncmp(config_parms[i].parm_name, "text", 4) || strncmp(parm_val, " ", 1)){ motion_log(INF, TYPE_ALL, NO_ERRNO,0, "%-25s %s" , config_parms[i].parm_name, parm_val); } else { motion_log(INF, TYPE_ALL, NO_ERRNO,0, "%-25s \"%s\"" , config_parms[i].parm_name, parm_val); } } } i++; } threadnbr++; } } /** Write the configuration(s) to file */ void conf_parms_write(struct ctx_cam **cam_list) { char parm_val[PATH_MAX]; int i, thread; char timestamp[32]; FILE *conffile; for (thread = 0; cam_list[thread]; thread++) { MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO ,_("Writing config file to %s") ,cam_list[thread]->conf_filename); conffile = myfopen(cam_list[thread]->conf_filename, "w"); if (!conffile) continue; time_t now = time(0); strftime(timestamp, 32, "%Y-%m-%dT%H:%M:%S", localtime(&now)); fprintf(conffile, "# %s\n", cam_list[thread]->conf_filename); fprintf(conffile, "#\n# This config file was generated by motion " VERSION "\n"); fprintf(conffile, "# at %s\n", timestamp); fprintf(conffile, "\n\n"); for (i = 0; config_parms[i].parm_name; i++) { conf_edit_get(cam_list[i], config_parms[i].parm_name , parm_val, config_parms[i].parm_cat); /* If config parameter has a value (not NULL) print it to the config file. */ if (strlen(parm_val) > 0) { fprintf(conffile, "%s\n", config_parms[i].parm_help); /* * If the option is a text_* and first char is a space put * quotation marks around to allow leading spaces. */ if (strncmp(config_parms[i].parm_name, "text", 4) || strncmp(parm_val, " ", 1)){ fprintf(conffile, "%s %s\n\n", config_parms[i].parm_name, parm_val); } else { fprintf(conffile, "%s \"%s\"\n\n", config_parms[i].parm_name, parm_val); } } else { if (thread == 0) { char value[PATH_MAX]; /* The 'camera_dir' option should keep the installed default value */ if (mystreq(config_parms[i].parm_name, "camera_dir")){ sprintf(value, "%s", sysconfdir "/conf.d"); } else { sprintf(value, "%s", "value"); } fprintf(conffile, "%s\n", config_parms[i].parm_help); fprintf(conffile, "; %s %s\n\n", config_parms[i].parm_name, value); } } } fprintf(conffile, "\n"); myfclose(conffile); conffile = NULL; } } void conf_init_app(struct ctx_motapp *motapp, int argc, char *argv[]){ FILE *fp = NULL; char filename[PATH_MAX]; char path[PATH_MAX]; int retcd; motapp->argc = argc; motapp->argv = argv; conf_edit_dflt_app(motapp); conf_cmdline(motapp); /* Get the filename if provided */ if (motapp->conf_filename != NULL) { retcd = snprintf(filename, PATH_MAX, "%s", motapp->conf_filename); if ((retcd < 0) || (retcd > PATH_MAX)){ MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error setting filename")); exit(-1); } fp = fopen (filename, "r"); } if (!fp) { if (getcwd(path, sizeof(path)) == NULL) { MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error getcwd")); exit(-1); } retcd = snprintf(filename, PATH_MAX, "%s/motion.conf", path); if ((retcd < 0) || (retcd > PATH_MAX)){ MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error setting filename")); exit(-1); } fp = fopen (filename, "r"); } if (!fp) { retcd = snprintf(filename, PATH_MAX, "%s/.motion/motion.conf", getenv("HOME")); if ((retcd < 0) || (retcd > PATH_MAX)){ MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error setting filename")); exit(-1); } fp = fopen(filename, "r"); } if (!fp) { retcd = snprintf(filename, PATH_MAX, "%s/motion.conf", sysconfdir); if ((retcd < 0) || (retcd > PATH_MAX)){ MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error setting filename")); exit(-1); } fp = fopen(filename, "r"); } if (!fp){ MOTION_LOG(ALR, TYPE_ALL, SHOW_ERRNO ,_("could not open configfile %s"), filename); } /* Now we process the motion.conf config file and close it. */ if (fp) { MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO,_("Processing config file %s"), filename); conf_edit_set(motapp, -1, (char*)"conf_filename", (char*)filename); conf_process(motapp, fp, -1); myfclose(fp); conf_cmdline(motapp); } else { MOTION_LOG(CRT, TYPE_ALL, NO_ERRNO ,_("No config file to process, using default values")); } return; } void conf_init_cams(struct ctx_motapp *motapp){ FILE *fp = NULL; int retcd; motapp->cam_list = (struct ctx_cam**)calloc(sizeof(struct ctx_cam *), 2); motapp->cam_list[0] = (struct ctx_cam *)mymalloc(sizeof(struct ctx_cam)); memset(motapp->cam_list[0], 0, sizeof(struct ctx_cam)); motapp->cam_list[1] = NULL; motapp->cam_list[0]->motapp = motapp; motapp->cam_list[0]->cam_list = motapp->cam_list; conf_edit_dflt_cam(motapp->cam_list[0]); if (motapp->conf_filename != NULL) { retcd = snprintf(motapp->cam_list[0]->conf_filename ,PATH_MAX,"%s",motapp->conf_filename); if ((retcd < 0)|| (retcd > PATH_MAX)){ MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO ,_("Error setting file name %s"), motapp->conf_filename); exit(1); } fp = fopen (motapp->conf_filename, "r"); } if (fp) { MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO ,_("Processing thread 0 - config file %s"), motapp->conf_filename); conf_process(motapp, fp, 0); myfclose(fp); } else { MOTION_LOG(CRT, TYPE_ALL, NO_ERRNO ,_("No config file to process, using default values")); } motapp->cam_list[0]->pause = motapp->pause; return; } void conf_deinit(struct ctx_motapp *motapp) { int indx; indx = 0; while (motapp->cam_list[indx] != NULL){ conf_edit_free(motapp->cam_list[indx]); free(motapp->cam_list[indx]); indx++; } free(motapp->cam_list); motapp->cam_list = NULL; }