/* ** ** 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 #include "motion.hpp" #include "util.hpp" #include "logger.hpp" #define EXTENSION ".conf" /* Forward Declares */ static void conf_process(struct ctx_cam *cam, FILE *fp); /* Set a NULL (0) as a type of ctx_cam, then get the address of the varname. * This result will be the offset from the start of any ctx_cam to the location * of the variable within the entire ctx_cam struct */ #define CONF_OFFSET(varname) ((long)&((struct ctx_cam *)NULL)->conf.varname) #define TRACK_OFFSET(varname) ((long)&((struct ctx_cam *)NULL)->track.varname) /* The sequence of these within here determines how they are presented to user * Descriptions are limited to one line and few to no references to values since * the motion_guide.html is our single source of documentation and historically * these descriptions were not updated with revisions. */ /*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, CONF_OFFSET(daemon), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "setup_mode", "# Start in Setup-Mode, daemon disabled.", 0, CONF_OFFSET(setup_mode), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "pid_file", "# File to store the process ID.", 1, CONF_OFFSET(pid_file), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "log_file", "# File to write logs messages into. If not defined stderr and syslog is used.", 1, CONF_OFFSET(log_file), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "log_level", "# Level of log messages [1..9] (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL).", 1, CONF_OFFSET(log_level), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "log_type", "# Filter to log messages by type (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL).", 1, CONF_OFFSET(log_type), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "quiet", "# Do not sound beeps when detecting motion", 0, CONF_OFFSET(quiet), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "native_language", "# Native language support.", 1, CONF_OFFSET(native_language), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "camera_name", "# User defined name for the camera.", 0, CONF_OFFSET(camera_name), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "camera_id", "# Numeric identifier for the camera.", 0, CONF_OFFSET(camera_id), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, /* camera and camera_dir must be last in this list */ { "target_dir", "# Target directory for pictures, snapshots and movies", 0, CONF_OFFSET(target_dir), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "videodevice", "# Video device (e.g. /dev/video0) to be used for capturing.", 0, CONF_OFFSET(video_device), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "vid_control_params", "# Parameters to control video device. See motion_guide.html", 0, CONF_OFFSET(vid_control_params), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "v4l2_palette", "# Preferred color palette to be used for the video device", 0, CONF_OFFSET(v4l2_palette), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "input", "# The input number to be used on the video device.", 0, CONF_OFFSET(input), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "norm", "# The video norm to use for video capture and TV tuner cards.", 0, CONF_OFFSET(norm), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "frequency", "# The frequency to set the tuner to (kHz) for TV tuner cards", 0, CONF_OFFSET(frequency), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "roundrobin_frames", "# Number of frames to capture in each roundrobin step", 0, CONF_OFFSET(roundrobin_frames), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "roundrobin_skip", "# Number of frames to skip before each roundrobin step", 0, CONF_OFFSET(roundrobin_skip), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "roundrobin_switchfilter", "# Try to filter out noise generated by roundrobin", 0, CONF_OFFSET(roundrobin_switchfilter), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "netcam_url", "# The full URL of the network camera stream.", 0, CONF_OFFSET(netcam_url), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "netcam_highres", "# Optional high resolution URL for rtsp/rtmp cameras only.", 0, CONF_OFFSET(netcam_highres), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "netcam_userpass", "# Username and password for network camera. Syntax username:password", 0, CONF_OFFSET(netcam_userpass), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "netcam_keepalive", "# The method for keep-alive of network socket for mjpeg streams.", 0, CONF_OFFSET(netcam_keepalive), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "netcam_proxy", "# The URL to use for a netcam proxy server.", 0, CONF_OFFSET(netcam_proxy), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "netcam_tolerant_check", "# Use less strict jpeg checks for network cameras.", 0, CONF_OFFSET(netcam_tolerant_check), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "netcam_use_tcp", "# Use TCP transport for RTSP/RTMP connections to camera.", 1, CONF_OFFSET(netcam_use_tcp), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "mmalcam_name", "# Name of mmal camera (e.g. vc.ril.camera for pi camera).", 0, CONF_OFFSET(mmalcam_name), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "mmalcam_control_params", "# Camera control parameters (see raspivid/raspistill tool documentation)", 0, CONF_OFFSET(mmalcam_control_params), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "width", "############################################################\n" "# Image Processing configuration parameters\n" "############################################################\n\n" "# Image width in pixels.", 0, CONF_OFFSET(width), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "height", "# Image height in pixels.", 0, CONF_OFFSET(height), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "framerate", "# Maximum number of frames to be captured per second.", 0, CONF_OFFSET(framerate), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "rotate", "# Number of degrees to rotate image.", 0, CONF_OFFSET(rotate), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "flip_axis", "# Flip image over a given axis", 0, CONF_OFFSET(flip_axis), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "locate_motion_mode", "# Draw a locate box around the moving object.", 0, CONF_OFFSET(locate_motion_mode), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "locate_motion_style", "# Set the look and style of the locate box.", 0, CONF_OFFSET(locate_motion_style), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "text_left", "# Text to be overlayed in the lower left corner of images", 0, CONF_OFFSET(text_left), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "text_right", "# Text to be overlayed in the lower right corner of images.", 0, CONF_OFFSET(text_right), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "text_changes", "# Overlay number of changed pixels in upper right corner of images.", 0, CONF_OFFSET(text_changes), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "text_scale", "# Scale factor for text overlayed on images.", 0, CONF_OFFSET(text_scale), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "text_event", "# The special event conversion specifier %C", 0, CONF_OFFSET(text_event), PARM_TYPE_STRING, 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, CONF_OFFSET(emulate_motion), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "threshold", "# Threshold for number of changed pixels that triggers motion.", 0, CONF_OFFSET(threshold), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "threshold_maximum", "# The maximum threshold for number of changed pixels that triggers motion.", 0, CONF_OFFSET(threshold_maximum), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "threshold_tune", "# Enable tuning of the threshold down if possible.", 0, CONF_OFFSET(threshold_tune), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "noise_level", "# Noise threshold for the motion detection.", 0, CONF_OFFSET(noise_level), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "noise_tune", "# Automatically tune the noise threshold", 0, CONF_OFFSET(noise_tune), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "despeckle_filter", "# Despeckle the image using (E/e)rode or (D/d)ilate or (l)abel.", 0, CONF_OFFSET(despeckle_filter), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "area_detect", "# Area number used to trigger the on_area_detected script.", 0, CONF_OFFSET(area_detect), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "mask_file", "# Full path and file name for motion detection mask PGM file.", 0, CONF_OFFSET(mask_file), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "mask_privacy", "# Full path and file name for privacy mask PGM file.", 0, CONF_OFFSET(mask_privacy), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "smart_mask_speed", "# The value defining how slow or fast the smart motion mask created and used.", 0, CONF_OFFSET(smart_mask_speed), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "lightswitch_percent", "# Percentage of image that triggers a lightswitch detected.", 0, CONF_OFFSET(lightswitch_percent), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "lightswitch_frames", "# When lightswitch is detected, ignore this many frames", 0, CONF_OFFSET(lightswitch_frames), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "minimum_motion_frames", "# Number of images that must contain motion to trigger an event.", 0, CONF_OFFSET(minimum_motion_frames), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "event_gap", "# Gap in seconds of no motion detected that triggers the end of an event.", 0, CONF_OFFSET(event_gap), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "pre_capture", "# The number of pre-captured (buffered) pictures from before motion.", 0, CONF_OFFSET(pre_capture), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "post_capture", "# Number of frames to capture after motion is no longer detected.", 0, CONF_OFFSET(post_capture), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "on_event_start", "############################################################\n" "# Script execution configuration parameters\n" "############################################################\n\n" "# Command to be executed when an event starts.", 0, CONF_OFFSET(on_event_start), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_event_end", "# Command to be executed when an event ends.", 0, CONF_OFFSET(on_event_end), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_picture_save", "# Command to be executed when a picture is saved.", 0, CONF_OFFSET(on_picture_save), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_area_detected", "# Command to be executed when motion in a predefined area is detected", 0, CONF_OFFSET(on_area_detected), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_motion_detected", "# Command to be executed when motion is detected", 0, CONF_OFFSET(on_motion_detected), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_movie_start", "# Command to be executed when a movie file is created.", 0, CONF_OFFSET(on_movie_start), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_movie_end", "# Command to be executed when a movie file is closed.", 0, CONF_OFFSET(on_movie_end), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_camera_lost", "# Command to be executed when a camera can't be opened or if it is lost", 0, CONF_OFFSET(on_camera_lost), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "on_camera_found", "# Command to be executed when a camera that was lost has been found.", 0, CONF_OFFSET(on_camera_found), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "picture_output", "############################################################\n" "# Picture output configuration parameters\n" "############################################################\n\n" "# Output pictures when motion is detected", 0, CONF_OFFSET(picture_output), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "picture_output_motion", "# Output pictures with only the pixels moving object (ghost images)", 0, CONF_OFFSET(picture_output_motion), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "picture_type", "# Format for the output pictures.", 0, CONF_OFFSET(picture_type), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "picture_quality", "# The quality (in percent) to be used in the picture compression", 0, CONF_OFFSET(picture_quality), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "picture_exif", "# Text to include in a JPEG EXIF comment", 0, CONF_OFFSET(picture_exif), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "picture_filename", "# File name(without extension) for pictures relative to target directory", 0, CONF_OFFSET(picture_filename), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "snapshot_interval", "############################################################\n" "# Snapshot output configuration parameters\n" "############################################################\n\n" "# Make automated snapshot every N seconds", 0, CONF_OFFSET(snapshot_interval), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "snapshot_filename", "# File name(without extension) for snapshots relative to target directory", 0, CONF_OFFSET(snapshot_filename), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "movie_output", "############################################################\n" "# Movie output configuration parameters\n" "############################################################\n\n" "# Create movies of motion events.", 0, CONF_OFFSET(movie_output), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "movie_output_motion", "# Create movies of moving pixels of motion events.", 0, CONF_OFFSET(movie_output_motion), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "movie_max_time", "# Maximum length of movie in seconds.", 0, CONF_OFFSET(movie_max_time), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "movie_bps", "# The fixed bitrate to be used by the movie encoder. Ignore quality setting", 0, CONF_OFFSET(movie_bps), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "movie_quality", "# The encoding quality of the movie. (0=use bitrate. 1=worst quality, 100=best)", 0, CONF_OFFSET(movie_quality), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "movie_codec", "# Container/Codec to used for the movie. See motion_guide.html", 0, CONF_OFFSET(movie_codec), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "movie_passthrough", "# Pass through from the camera to the movie without decode/encoding.", 0, CONF_OFFSET(movie_passthrough), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "movie_filename", "# File name(without extension) for movies relative to target directory", 0, CONF_OFFSET(movie_filename), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "movie_extpipe_use", "# Use pipe and external encoder for creating movies.", 0, CONF_OFFSET(movie_extpipe_use), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "movie_extpipe", "# Full path and options for external encoder of movies from raw images", 0, CONF_OFFSET(movie_extpipe), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "timelapse_interval", "############################################################\n" "# Timelapse output configuration parameters\n" "############################################################\n\n" "# Interval in seconds between timelapse captures.", 0, CONF_OFFSET(timelapse_interval), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "timelapse_mode", "# Timelapse file rollover mode. See motion_guide.html for options and uses.", 0, CONF_OFFSET(timelapse_mode), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "timelapse_fps", "# Frame rate for timelapse playback", 0, CONF_OFFSET(timelapse_fps), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "timelapse_codec", "# Container/Codec for timelapse movie.", 0, CONF_OFFSET(timelapse_codec), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "timelapse_filename", "# File name(without extension) for timelapse movies relative to target directory", 0, CONF_OFFSET(timelapse_filename), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "video_pipe", "############################################################\n" "# Loopback pipe configuration parameters\n" "############################################################\n\n" "# v4l2 loopback device to receive normal images", 0, CONF_OFFSET(video_pipe), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "video_pipe_motion", "# v4l2 loopback device to receive motion images", 0, CONF_OFFSET(video_pipe_motion), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "webcontrol_port", "############################################################\n" "# Webcontrol configuration parameters\n" "############################################################\n\n" "# Port number used for the webcontrol.", 1, CONF_OFFSET(webcontrol_port), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "webcontrol_ipv6", "# Enable IPv6 addresses.", 0, CONF_OFFSET(webcontrol_ipv6), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "webcontrol_localhost", "# Restrict webcontrol connections to the localhost.", 1, CONF_OFFSET(webcontrol_localhost), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "webcontrol_parms", "# Type of configuration options to allow via the webcontrol.", 1, CONF_OFFSET(webcontrol_parms), PARM_TYPE_INT, WEBUI_LEVEL_NEVER }, { "webcontrol_interface", "# Method that webcontrol should use for interface with user.", 1, CONF_OFFSET(webcontrol_interface), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "webcontrol_auth_method", "# The authentication method for the webcontrol", 0, CONF_OFFSET(webcontrol_auth_method), PARM_TYPE_INT, WEBUI_LEVEL_RESTRICTED }, { "webcontrol_authentication", "# Authentication string for the webcontrol. Syntax username:password", 1, CONF_OFFSET(webcontrol_authentication), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "webcontrol_tls", "# Use ssl / tls for the webcontrol", 0, CONF_OFFSET(webcontrol_tls), PARM_TYPE_BOOL, WEBUI_LEVEL_RESTRICTED }, { "webcontrol_cert", "# Full path and file name of the certificate file for tls", 1, CONF_OFFSET(webcontrol_cert), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "webcontrol_key", "# Full path and file name of the key file for tls", 1, CONF_OFFSET(webcontrol_key), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "webcontrol_cors_header", "# The cross-origin resource sharing (CORS) header for webcontrol", 0, CONF_OFFSET(webcontrol_cors_header), PARM_TYPE_URI, WEBUI_LEVEL_RESTRICTED }, { "stream_port", "############################################################\n" "# Live stream configuration parameters\n" "############################################################\n\n" "# The port number for the live stream.", 0, CONF_OFFSET(stream_port), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "stream_localhost", "# Restrict stream connections to the localhost.", 0, CONF_OFFSET(stream_localhost), PARM_TYPE_BOOL, WEBUI_LEVEL_ADVANCED }, { "stream_auth_method", "# Authentication method for live stream.", 0, CONF_OFFSET(stream_auth_method), PARM_TYPE_INT, WEBUI_LEVEL_RESTRICTED }, { "stream_authentication", "# The authentication string for the stream. Syntax username:password", 1, CONF_OFFSET(stream_authentication), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "stream_tls", "# Use ssl / tls for stream.", 0, CONF_OFFSET(stream_tls), PARM_TYPE_BOOL, WEBUI_LEVEL_RESTRICTED }, { "stream_cors_header", "# The cross-origin resource sharing (CORS) header for the stream", 0, CONF_OFFSET(stream_cors_header), PARM_TYPE_URI, WEBUI_LEVEL_RESTRICTED }, { "stream_preview_scale", "# Percentage to scale the stream image on the webcontrol.", 0, CONF_OFFSET(stream_preview_scale), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "stream_preview_newline", "# Have the stream image start on a new line of the webcontrol", 0, CONF_OFFSET(stream_preview_newline), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "stream_preview_method", "# Method for showing stream on webcontrol.", 0, CONF_OFFSET(stream_preview_method), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "stream_quality", "# Quality of the jpeg images produced for stream.", 0, CONF_OFFSET(stream_quality), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "stream_grey", "# Provide the stream images in black and white", 0, CONF_OFFSET(stream_grey), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "stream_motion", "# Output frames at 1 fps when no motion is detected.", 0, CONF_OFFSET(stream_motion), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "stream_maxrate", "# Maximum framerate of images provided for stream", 0, CONF_OFFSET(stream_maxrate), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "stream_limit", "# Limit the number of images per connection", 0, CONF_OFFSET(stream_limit), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "database_type", "############################################################\n" "# Database and SQL Configuration parameters\n" "############################################################\n\n" "# The type of database being used if any.", 0, CONF_OFFSET(database_type), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "database_dbname", "# Database name to use. For sqlite3, the full path and name.", 0, CONF_OFFSET(database_dbname), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "database_host", "# The host on which the database is located", 0, CONF_OFFSET(database_host), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "database_port", "# Port used by the database.", 0, CONF_OFFSET(database_port), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "database_user", "# User account name for database.", 0, CONF_OFFSET(database_user), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "database_password", "# User password for database.", 0, CONF_OFFSET(database_password), PARM_TYPE_STRING, WEBUI_LEVEL_RESTRICTED }, { "database_busy_timeout", "# Database wait for unlock time", 0, CONF_OFFSET(database_busy_timeout), PARM_TYPE_INT, WEBUI_LEVEL_ADVANCED }, { "sql_log_picture", "# Log to the database when creating motion triggered image file", 0, CONF_OFFSET(sql_log_picture), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "sql_log_snapshot", "# Log to the database when creating a snapshot image file", 0, CONF_OFFSET(sql_log_snapshot), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "sql_log_movie", "# Log to the database when creating motion triggered movie file", 0, CONF_OFFSET(sql_log_movie), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "sql_log_timelapse", "# Log to the database when creating timelapse movie file", 0, CONF_OFFSET(sql_log_timelapse), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "sql_query_start", "# SQL query at event start. See motion_guide.html", 0, CONF_OFFSET(sql_query_start), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "sql_query_stop", "# SQL query at event stop. See motion_guide.html", 0, CONF_OFFSET(sql_query_stop), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "sql_query", "# SQL query string that is sent to the database. See motion_guide.html", 0, CONF_OFFSET(sql_query), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { "track_type", "############################################################\n" "# Tracking configuration parameters\n" "############################################################\n\n" "# Method used by tracking camera. See motion_guide.html", 0, TRACK_OFFSET(type), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "track_auto", "# Enable auto tracking", 0, TRACK_OFFSET(active), PARM_TYPE_BOOL, WEBUI_LEVEL_LIMITED }, { "track_move_wait", "# Delay to wait for after tracking movement as number of picture frames.", 0, TRACK_OFFSET(move_wait), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "track_generic_move", "# Command to execute to move a camera in generic tracking mode", 0, TRACK_OFFSET(generic_move), PARM_TYPE_STRING, WEBUI_LEVEL_LIMITED }, { "track_maxx", "# Maximum value on x-axis", 0, TRACK_OFFSET(maxx), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "track_minx", "# Minimum value on x-axis", 0, TRACK_OFFSET(minx), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "track_maxy", "# Maximum value on y-axis", 0, TRACK_OFFSET(maxy), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "track_miny", "# Minimum value on y-axis", 0, TRACK_OFFSET(miny), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "track_step_angle_x", "# Angle in degrees the camera moves per step on the X-axis with auto-track", 0, TRACK_OFFSET(step_angle_x), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "track_step_angle_y", "# Angle in degrees the camera moves per step on the Y-axis with auto-track.", 0, TRACK_OFFSET(step_angle_y), PARM_TYPE_INT, WEBUI_LEVEL_LIMITED }, { "camera", "##############################################################\n" "# Camera config files - One for each camera.\n" "##############################################################", 1, 0, PARM_TYPE_CAMERA, WEBUI_LEVEL_ADVANCED }, /* using a conf.d style camera addition */ { "camera_dir", "##############################################################\n" "# Directory to read '.conf' files for cameras.\n" "##############################################################", 1, CONF_OFFSET(camera_dir), PARM_TYPE_STRING, WEBUI_LEVEL_ADVANCED }, { NULL, NULL, 0, 0, (enum PARM_TYPE)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\"", 0, "camera", PARM_TYPE_CAMERA }, { "ffmpeg_timelapse", "4.0.1", "\"ffmpeg_timelapse\" replaced with \"timelapse_interval\"", CONF_OFFSET(timelapse_interval), "timelapse_interval", PARM_TYPE_INT }, { "ffmpeg_timelapse_mode", "4.0.1", "\"ffmpeg_timelapse_mode\" replaced with \"timelapse_mode\"", CONF_OFFSET(timelapse_mode), "timelapse_mode", PARM_TYPE_STRING }, { "brightness", "4.1.1", "\"brightness\" replaced with \"vid_control_params\"", CONF_OFFSET(vid_control_params), "vid_control_params", PARM_TYPE_STRING }, { "contrast", "4.1.1", "\"contrast\" replaced with \"vid_control_params\"", CONF_OFFSET(vid_control_params), "vid_control_params", PARM_TYPE_STRING }, { "saturation", "4.1.1", "\"saturation\" replaced with \"vid_control_params\"", CONF_OFFSET(vid_control_params), "vid_control_params", PARM_TYPE_STRING }, { "hue", "4.1.1", "\"hue\" replaced with \"vid_control_params\"", CONF_OFFSET(vid_control_params), "vid_control_params", PARM_TYPE_STRING }, { "power_line_frequency", "4.1.1", "\"power_line_frequency\" replaced with \"vid_control_params\"", CONF_OFFSET(vid_control_params), "vid_control_params", PARM_TYPE_STRING }, { "text_double", "4.1.1", "\"text_double\" replaced with \"text_scale\"", CONF_OFFSET(text_scale), "text_scale", PARM_TYPE_INT }, { "webcontrol_html_output", "4.1.1", "\"webcontrol_html_output\" replaced with \"webcontrol_interface\"", CONF_OFFSET(webcontrol_interface), "webcontrol_interface", PARM_TYPE_INT }, { "lightswitch", "4.1.1", "\"lightswitch\" replaced with \"lightswitch_percent\"", CONF_OFFSET(lightswitch_percent), "lightswitch_percent", PARM_TYPE_INT }, { "ffmpeg_output_movies", "4.1.1", "\"ffmpeg_output_movies\" replaced with \"movie_output\"", CONF_OFFSET(movie_output), "movie_output", PARM_TYPE_BOOL }, { "ffmpeg_output_debug_movies", "4.1.1", "\"ffmpeg_output_debug_movies\" replaced with \"movie_output_motion\"", CONF_OFFSET(movie_output_motion), "movie_output_motion", PARM_TYPE_BOOL }, { "max_movie_time", "4.1.1", "\"max_movie_time\" replaced with \"movie_max_time\"", CONF_OFFSET(movie_max_time), "movie_max_time", PARM_TYPE_INT }, { "ffmpeg_bps", "4.1.1", "\"ffmpeg_bps\" replaced with \"movie_bps\"", CONF_OFFSET(movie_bps), "movie_bps", PARM_TYPE_INT }, { "ffmpeg_variable_bitrate", "4.1.1", "\"ffmpeg_variable_bitrate\" replaced with \"movie_quality\"", CONF_OFFSET(movie_quality), "movie_quality", PARM_TYPE_INT }, { "ffmpeg_video_codec", "4.1.1", "\"ffmpeg_video_codec\" replaced with \"movie_codec\"", CONF_OFFSET(movie_codec), "movie_codec", PARM_TYPE_STRING }, { "ffmpeg_passthrough", "4.1.1", "\"ffmpeg_passthrough\" replaced with \"movie_passthrough\"", CONF_OFFSET(movie_passthrough), "movie_passthrough", PARM_TYPE_BOOL }, { "use_extpipe", "4.1.1", "\"use_extpipe\" replaced with \"movie_extpipe_use\"", CONF_OFFSET(movie_extpipe_use), "movie_extpipe_use", PARM_TYPE_BOOL }, { "extpipe", "4.1.1", "\"extpipe\" replaced with \"movie_extpipe\"", CONF_OFFSET(movie_extpipe), "movie_extpipe", PARM_TYPE_STRING }, { "output_pictures", "4.1.1", "\"output_pictures\" replaced with \"picture_output\"", CONF_OFFSET(picture_output), "picture_output", PARM_TYPE_STRING }, { "output_debug_pictures", "4.1.1", "\"output_debug_pictures\" replaced with \"picture_output_motion\"", CONF_OFFSET(picture_output_motion), "picture_output_motion", PARM_TYPE_BOOL }, { "quality", "4.1.1", "\"quality\" replaced with \"picture_quality\"", CONF_OFFSET(picture_quality), "picture_quality", PARM_TYPE_INT }, { "exif_text", "4.1.1", "\"exif_text\" replaced with \"picture_exif\"", CONF_OFFSET(picture_exif), "picture_exif", PARM_TYPE_STRING }, { "motion_video_pipe", "4.1.1", "\"motion_video_pipe\" replaced with \"video_pipe_motion\"", CONF_OFFSET(video_pipe_motion), "video_pipe_motion", PARM_TYPE_STRING }, { "ipv6_enabled", "4.1.1", "\"ipv6_enabled\" replaced with \"webcontrol_ipv6\"", CONF_OFFSET(webcontrol_ipv6), "webcontrol_ipv6", PARM_TYPE_BOOL }, { "rtsp_uses_tcp", "4.1.1", "\"rtsp_uses_tcp\" replaced with \"netcam_use_tcp\"", CONF_OFFSET(netcam_use_tcp), "netcam_use_tcp", PARM_TYPE_BOOL }, { "switchfilter", "4.1.1", "\"switchfilter\" replaced with \"roundrobin_switchfilter\"", CONF_OFFSET(roundrobin_switchfilter), "roundrobin_switchfilter", PARM_TYPE_BOOL }, { "logfile", "4.1.1", "\"logfile\" replaced with \"log_file\"", CONF_OFFSET(log_file), "log_file", PARM_TYPE_STRING }, { "process_id_file", "4.1.1", "\"process_id_file\" replaced with \"pid_file\"", CONF_OFFSET(pid_file), "pid_file", PARM_TYPE_STRING }, { NULL, NULL, NULL, 0, NULL,(enum PARM_TYPE)0} }; static void config_parms_intl(void){ /* This function prints out the configuration parms side by side * with the translations. It is currently disabled but put into * the code so that they can be found by xgettext. If enabled, then * it will be printed when called from the conf_load. */ if (FALSE){ MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","daemon",_("daemon")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","setup_mode",_("setup_mode")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","pid_file",_("pid_file")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","log_file",_("log_file")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","log_level",_("log_level")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","log_type",_("log_type")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","quiet",_("quiet")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","native_language",_("native_language")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","camera_name",_("camera_name")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","camera_id",_("camera_id")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","target_dir",_("target_dir")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","videodevice",_("videodevice")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","vid_control_params",_("vid_control_params")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","v4l2_palette",_("v4l2_palette")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","input",_("input")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","norm",_("norm")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","frequency",_("frequency")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","tunerdevice",_("tunerdevice")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","roundrobin_frames",_("roundrobin_frames")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","roundrobin_skip",_("roundrobin_skip")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","roundrobin_switchfilter",_("roundrobin_switchfilter")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","netcam_url",_("netcam_url")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","netcam_highres",_("netcam_highres")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","netcam_userpass",_("netcam_userpass")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","netcam_keepalive",_("netcam_keepalive")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","netcam_proxy",_("netcam_proxy")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","netcam_tolerant_check",_("netcam_tolerant_check")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","netcam_use_tcp",_("netcam_use_tcp")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","mmalcam_name",_("mmalcam_name")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","mmalcam_control_params",_("mmalcam_control_params")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","width",_("width")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","height",_("height")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","framerate",_("framerate")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","rotate",_("rotate")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","flip_axis",_("flip_axis")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","locate_motion_mode",_("locate_motion_mode")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","locate_motion_style",_("locate_motion_style")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","text_left",_("text_left")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","text_right",_("text_right")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","text_changes",_("text_changes")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","text_scale",_("text_scale")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","text_event",_("text_event")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","emulate_motion",_("emulate_motion")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","threshold",_("threshold")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","threshold_maximum",_("threshold_maximum")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","threshold_tune",_("threshold_tune")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","noise_level",_("noise_level")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","noise_tune",_("noise_tune")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","despeckle_filter",_("despeckle_filter")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","area_detect",_("area_detect")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","mask_file",_("mask_file")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","mask_privacy",_("mask_privacy")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","smart_mask_speed",_("smart_mask_speed")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","lightswitch_percent",_("lightswitch_percent")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","lightswitch_frames",_("lightswitch_frames")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","minimum_motion_frames",_("minimum_motion_frames")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","event_gap",_("event_gap")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","pre_capture",_("pre_capture")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","post_capture",_("post_capture")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_event_start",_("on_event_start")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_event_end",_("on_event_end")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_picture_save",_("on_picture_save")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_area_detected",_("on_area_detected")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_motion_detected",_("on_motion_detected")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_movie_start",_("on_movie_start")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_movie_end",_("on_movie_end")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_camera_lost",_("on_camera_lost")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","on_camera_found",_("on_camera_found")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","picture_output",_("picture_output")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","picture_output_motion",_("picture_output_motion")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","picture_type",_("picture_type")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","picture_quality",_("picture_quality")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","picture_exif",_("picture_exif")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","picture_filename",_("picture_filename")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","snapshot_interval",_("snapshot_interval")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","snapshot_filename",_("snapshot_filename")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_output",_("movie_output")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_output_motion",_("movie_output_motion")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_max_time",_("movie_max_time")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_bps",_("movie_bps")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_quality",_("movie_quality")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_codec",_("movie_codec")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_passthrough",_("movie_passthrough")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_filename",_("movie_filename")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_extpipe_use",_("movie_extpipe_use")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","movie_extpipe",_("movie_extpipe")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","timelapse_interval",_("timelapse_interval")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","timelapse_mode",_("timelapse_mode")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","timelapse_fps",_("timelapse_fps")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","timelapse_codec",_("timelapse_codec")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","timelapse_filename",_("timelapse_filename")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","video_pipe",_("video_pipe")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","video_pipe_motion",_("video_pipe_motion")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_port",_("webcontrol_port")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_ipv6",_("webcontrol_ipv6")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_localhost",_("webcontrol_localhost")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_parms",_("webcontrol_parms")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_interface",_("webcontrol_interface")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_auth_method",_("webcontrol_auth_method")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_authentication",_("webcontrol_authentication")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_tls",_("webcontrol_tls")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_cert",_("webcontrol_cert")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_key",_("webcontrol_key")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","webcontrol_cors_header",_("webcontrol_cors_header")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_port",_("stream_port")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_localhost",_("stream_localhost")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_auth_method",_("stream_auth_method")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_authentication",_("stream_authentication")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_tls",_("stream_tls")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_cors_header",_("stream_cors_header")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_preview_scale",_("stream_preview_scale")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_preview_newline",_("stream_preview_newline")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_preview_method",_("stream_preview_method")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_quality",_("stream_quality")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_grey",_("stream_grey")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_motion",_("stream_motion")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_maxrate",_("stream_maxrate")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","stream_limit",_("stream_limit")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","database_type",_("database_type")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","database_dbname",_("database_dbname")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","database_host",_("database_host")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","database_port",_("database_port")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","database_user",_("database_user")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","database_password",_("database_password")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","database_busy_timeout",_("database_busy_timeout")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","sql_log_picture",_("sql_log_picture")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","sql_log_snapshot",_("sql_log_snapshot")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","sql_log_movie",_("sql_log_movie")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","sql_log_timelapse",_("sql_log_timelapse")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","sql_query_start",_("sql_query_start")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","sql_query_stop",_("sql_query_stop")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","sql_query",_("sql_query")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_type",_("track_type")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_auto",_("track_auto")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_maxx",_("track_maxx")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_minx",_("track_minx")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_maxy",_("track_maxy")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_miny",_("track_miny")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_step_angle_x",_("track_step_angle_x")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_step_angle_y",_("track_step_angle_y")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_move_wait",_("track_move_wait")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","track_generic_move",_("track_generic_move")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","camera",_("camera")); MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","camera_dir",_("camera_dir")); } } /** 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"); } static void conf_malloc_strings(struct ctx_cam *cam) { unsigned int i = 0; char **val; while (config_parms[i].parm_name != NULL) { if ((config_parms[i].parm_type == PARM_TYPE_STRING) || (config_parms[i].parm_type == PARM_TYPE_URI)) { /* val is made to point to a pointer to the current string. */ val = (char **)((char *)cam + config_parms[i].parm_offset); /* * If there is a string, malloc() space for it, copy * the string to new space, and point to the new * string. we don't free() because we're copying a * static string. */ *val = mystrdup(*val); } i++; } } /** Process Command-line options specified */ static void conf_cmdline(struct ctx_cam *cam, int thread) { struct ctx_config *conf = &cam->conf; int c; while ((c = getopt(conf->argc, conf->argv, "bc:d:hmns?p:k:l:")) != EOF) switch (c) { case 'c': if (thread == -1){ strcpy(cam->conf_filename, optarg); } break; case 'b': cam->motapp->daemon = TRUE; break; case 'n': cam->motapp->daemon = FALSE; break; case 's': conf->setup_mode = 1; break; case 'd': /* No validation - just take what user gives. */ if (thread == -1){ cam->motapp->log_level = (unsigned int)atoi(optarg); } break; case 'k': if (thread == -1) { strncpy(cam->motapp->log_type_str, optarg, sizeof(cam->motapp->log_type_str) - 1); cam->motapp->log_type_str[sizeof(cam->motapp->log_type_str) - 1] = '\0'; } break; case 'p': if (thread == -1) { strncpy(cam->motapp->pid_file, optarg, sizeof(cam->motapp->pid_file) - 1); cam->motapp->pid_file[sizeof(cam->motapp->pid_file) - 1] = '\0'; } break; case 'l': if (thread == -1) { strncpy(cam->motapp->log_file, optarg, sizeof(cam->motapp->log_file) - 1); cam->motapp->log_file[sizeof(cam->motapp->log_file) - 1] = '\0'; } break; case 'm': cam->pause = TRUE; break; case 'h': case '?': default: usage(); exit(1); } optind = 1; } static void conf_parm_set_bool(struct ctx_cam *cam, const char *str, int offset) { void *tmp; tmp = (char *)cam + (int)offset; if (mystrceq(str, "1") || mystrceq(str, "yes") || mystrceq(str, "on")) { *((int *)tmp) = 1; } else { *((int *)tmp) = 0; } } static void conf_parm_set_int(struct ctx_cam *cam, const char *str, int offset) { void *tmp; tmp = (char *)cam + offset; if ( mystrceq(str, "yes") || mystrceq(str, "on")) { *((int *)tmp) = 1; } else if (mystrceq(str, "no") || mystrceq(str, "off")) { *((int *)tmp) = 0; } else { *((int *)tmp) = atoi(str); } } static void conf_parm_set_string(struct ctx_cam *cam, const char *str, int offset) { char **tmp; tmp = (char **)((char *)cam + offset); *tmp = mystrcpy(*tmp, str); } static void conf_parm_set_uri(struct ctx_cam *cam, const char *str, int offset) { // A complicated regex to validate a url found here: // https://stackoverflow.com/questions/38608116/how-to-check-a-specified-string-is-a-valid-url-or-not-using-c-code const char *regex_str = "^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$"; regex_t regex; if (regcomp(®ex, regex_str, REG_EXTENDED) != 0) { MOTION_LOG(ERR, TYPE_STREAM, NO_ERRNO ,_("Error compiling regex in copy_uri")); return; } // A single asterisk is also valid if (!mystrceq(str, "*") && regexec(®ex, str, 0, NULL, 0) == REG_NOMATCH) { MOTION_LOG(ERR, TYPE_STREAM, NO_ERRNO ,_("Invalid origin for cors_header")); regfree(®ex); return; } regfree(®ex); conf_parm_set_string(cam, str, offset); } static void conf_parm_set_text_double(struct ctx_cam *cam, const char *str, int offset) { void *tmp; tmp = (char *)cam + (int)offset; if (mystrceq(str, "1") || mystrceq(str, "yes") || mystrceq(str, "on")) { *((int *)tmp) = 2; } else { *((int *)tmp) = 1; } } static void conf_parm_set_html_output(struct ctx_cam *cam, const char *str, int offset) { void *tmp; tmp = (char *)cam + (int)offset; if (mystrceq(str, "1") || mystrceq(str, "yes") || mystrceq(str, "on")) { *((int *)tmp) = 0; } else { *((int *)tmp) = 1; } } static void conf_parm_set_vid_ctrl(struct ctx_cam *cam, const char *config_val, int config_indx) { int indx_vid; int parmnew_len, parmval; char *orig_parm, *parmname_new; indx_vid = 0; while (config_parms[indx_vid].parm_name != NULL) { if (mystreq(config_parms[indx_vid].parm_name,"vid_control_params")) break; indx_vid++; } if (mystrne(config_parms[indx_vid].parm_name,"vid_control_params")){ MOTION_LOG(ALR, TYPE_ALL, NO_ERRNO ,_("Unable to locate vid_control_params")); return; } if (config_val == NULL){ MOTION_LOG(ALR, TYPE_ALL, NO_ERRNO ,_("No value provided to put into vid_control_params")); } /* If the depreciated option is the default, then just return */ parmval = atoi(config_val); if (mystreq(config_parms_depr[config_indx].parm_name,"power_line_frequency") && (parmval == -1)) return; if (mystrne(config_parms_depr[config_indx].parm_name,"power_line_frequency") && (parmval == 0)) return; /* Remove underscore from parm name and add quotes*/ if (mystreq(config_parms_depr[config_indx].parm_name,"power_line_frequency")) { parmname_new = (char*)mymalloc(strlen(config_parms_depr[config_indx].parm_name) + 3); sprintf(parmname_new,"%s","\"power line frequency\""); } else { parmname_new = (char*)mymalloc(strlen(config_parms_depr[config_indx].parm_name)+1); sprintf(parmname_new,"%s",config_parms_depr[config_indx].parm_name); } /* Recall that the current parms have already been processed by time this is called */ parmnew_len = strlen(parmname_new) + strlen(config_val) + 2; /*Add for = and /0*/ if (cam->conf.vid_control_params != NULL) { orig_parm = (char*)mymalloc(strlen(cam->conf.vid_control_params)+1); sprintf(orig_parm,"%s",cam->conf.vid_control_params); parmnew_len = strlen(orig_parm) + parmnew_len + 1; /*extra 1 for the comma */ free(cam->conf.vid_control_params); cam->conf.vid_control_params = (char*)mymalloc(parmnew_len); sprintf(cam->conf.vid_control_params,"%s=%s,%s",parmname_new, config_val, orig_parm); free(orig_parm); } else { cam->conf.vid_control_params = (char*)mymalloc(parmnew_len); sprintf(cam->conf.vid_control_params,"%s=%s", parmname_new, config_val); } free(parmname_new); return; } static void conf_camera(struct ctx_cam *cam, const char *str) { int indx_cams; 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 (cam->motapp->cam_list[indx_cams] != NULL){ indx_cams++; }; /* Index starts at zero (+1) plus another for our new camera(+2)*/ cam->motapp->cam_list = (struct ctx_cam **)myrealloc( cam->motapp->cam_list, sizeof(struct ctx_cam *) * (indx_cams + 2), "config_camera"); cam->motapp->cam_list[indx_cams] = (struct ctx_cam *)mymalloc(sizeof(struct ctx_cam)); cam->motapp->cam_list[indx_cams + 1] = NULL; /* Copy numeric values and set string pointers to new locations */ memcpy(cam->motapp->cam_list[indx_cams],cam->motapp->cam_list[0], sizeof(struct ctx_cam)); conf_malloc_strings(cam->motapp->cam_list[indx_cams]); /* 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(cam->motapp->cam_list[indx_cams]->conf_filename ,sizeof(cam->motapp->cam_list[indx_cams]->conf_filename),"%s", str); conf_process(cam->motapp->cam_list[indx_cams], fp); /*Cascade new pointers to all cameras. */ cam->motapp->cam_list[indx_cams]->motapp = cam->motapp; indx_cams = 0; while (cam->motapp->cam_list[indx_cams] != NULL){ cam->motapp->cam_list[indx_cams]->cam_list = cam->motapp->cam_list; indx_cams++; } /* Finally we close the camera config file. */ myfclose(fp); return; } /** Process camera_dir */ static void conf_camera_dir(struct ctx_cam *cam, const char *str, int offset) { 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(EXTENSION) && (strncmp(EXTENSION, (ep->d_name + name_len - strlen(EXTENSION)), strlen(EXTENSION)) == 0 ) ) { 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_camera(cam, conf_file); /* The last ctx_cam thread would be ours, * set it as created from conf directory. */ i = 0; while (cam->motapp->cam_list[++i]); cam->motapp->cam_list[i-1]->from_conf_dir = 1; } } 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_parm_set_string(cam, str, offset); return; } static int conf_parm_set_current(struct ctx_cam *cam, const char *cmd, const char *arg1) { int indx = 0; while (config_parms[indx].parm_name != NULL) { if (mystreq(cmd, config_parms[indx].parm_name)) { if (mystreq(config_parms[indx].parm_name,"camera")) { conf_camera(cam, arg1); } else if (mystreq(config_parms[indx].parm_name,"camera_dir")) { conf_camera_dir(cam, arg1, config_parms[indx].parm_offset); } else if (config_parms[indx].parm_type == PARM_TYPE_BOOL) { conf_parm_set_bool(cam, arg1, config_parms[indx].parm_offset); } else if (config_parms[indx].parm_type == PARM_TYPE_INT) { conf_parm_set_int(cam, arg1, config_parms[indx].parm_offset); } else if (config_parms[indx].parm_type == PARM_TYPE_STRING) { conf_parm_set_string(cam, arg1, config_parms[indx].parm_offset); } else if (config_parms[indx].parm_type == PARM_TYPE_URI) { conf_parm_set_uri(cam, arg1, config_parms[indx].parm_offset); } else { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO , _("Coding error \"%s\""), config_parms[indx].parm_name); } return 0; } indx++; } return -1; } static int conf_parm_set_depreciated(struct ctx_cam *cam, const char *cmd, const char *arg1) { int indx = 0; while (config_parms_depr[indx].parm_name != NULL) { if (mystreq(cmd, config_parms_depr[indx].parm_name)) { MOTION_LOG(ALR, TYPE_ALL, NO_ERRNO, "%s after version %s" , config_parms_depr[indx].info , config_parms_depr[indx].last_version); if (mystreq(config_parms_depr[indx].parm_name,"brightness") || mystreq(config_parms_depr[indx].parm_name,"contrast") || mystreq(config_parms_depr[indx].parm_name,"saturation") || mystreq(config_parms_depr[indx].parm_name,"hue") || mystreq(config_parms_depr[indx].parm_name,"power_line_frequency")) { conf_parm_set_vid_ctrl(cam, arg1, indx); } else if (mystreq(config_parms_depr[indx].parm_name,"webcontrol_html_output")) { conf_parm_set_html_output(cam, arg1, config_parms[indx].parm_offset); } else if (mystreq(config_parms_depr[indx].parm_name,"text_double")) { conf_parm_set_text_double(cam, arg1, config_parms[indx].parm_offset); } else if (mystreq(config_parms_depr[indx].parm_name,"thread")) { conf_camera(cam, arg1); } else if (config_parms_depr[indx].parm_type == PARM_TYPE_BOOL) { conf_parm_set_bool(cam, arg1, config_parms[indx].parm_offset); } else if (config_parms_depr[indx].parm_type == PARM_TYPE_INT) { conf_parm_set_int(cam, arg1, config_parms[indx].parm_offset); } else if (config_parms_depr[indx].parm_type == PARM_TYPE_STRING) { conf_parm_set_string(cam, arg1, config_parms[indx].parm_offset); } else if (config_parms_depr[indx].parm_type == PARM_TYPE_URI) { conf_parm_set_uri(cam, arg1, config_parms[indx].parm_offset); } else { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO , _("Coding error \"%s\""), config_parms_depr[indx].parm_name); } return 0; } indx++; } return -1; } /** Set the parameter to specified value */ void conf_parm_set(struct ctx_cam *cam, const char *cmd, const char *arg1) { if (!cmd) return; if (conf_parm_set_current(cam, cmd, arg1) == 0) return; if (conf_parm_set_depreciated(cam, cmd, arg1) == 0) return; MOTION_LOG(ALR, TYPE_ALL, NO_ERRNO, _("Unknown config option \"%s\""), cmd); return; } /** Process each line from the config file. */ static void conf_process(struct ctx_cam *cam, FILE *fp) { 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)) {/* skipcomment */ 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 line is only whitespace we continue to the next line. */ 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++; } /* * If argument is in "" we will strip them off * It is important that we can use "" so that we can use * leading spaces in text_left and text_right. */ if ((beg[0] == '"' && beg[strlen(beg)-1] == '"') || (beg[0] == '\'' && beg[strlen(beg)-1] == '\'')) { beg[strlen(beg)-1] = '\0'; beg++; } arg1 = beg; /* Argument starts here */ } /* Else arg1 stays null pointer */ conf_parm_set(cam, cmd, arg1); } } return; } static void conf_defaults(struct ctx_cam **cam_list) { /* * Copy the template config structure with all the default config values * into cam_list[0]->conf */ cam_list[0]->conf.setup_mode = FALSE; cam_list[0]->conf.pid_file = NULL; cam_list[0]->conf.log_file = NULL; cam_list[0]->conf.log_level = LEVEL_DEFAULT+10; cam_list[0]->conf.log_type = NULL; cam_list[0]->conf.quiet = TRUE; cam_list[0]->conf.native_language = TRUE; cam_list[0]->conf.camera_name = NULL; cam_list[0]->conf.camera_id = 0; cam_list[0]->conf.camera_dir = NULL; cam_list[0]->conf.target_dir = NULL; /* Capture device configuration parameters */ cam_list[0]->conf.video_device = "/dev/video0"; cam_list[0]->conf.vid_control_params = NULL; cam_list[0]->conf.v4l2_palette = 17; cam_list[0]->conf.input = -1; cam_list[0]->conf.norm = 0; cam_list[0]->conf.frequency = 0; cam_list[0]->conf.roundrobin_frames = 1; cam_list[0]->conf.roundrobin_skip = 1; cam_list[0]->conf.roundrobin_switchfilter = FALSE; cam_list[0]->conf.netcam_url = NULL; cam_list[0]->conf.netcam_highres = NULL; cam_list[0]->conf.netcam_userpass = NULL; cam_list[0]->conf.netcam_keepalive = "off"; cam_list[0]->conf.netcam_proxy = NULL; cam_list[0]->conf.netcam_tolerant_check = FALSE; cam_list[0]->conf.netcam_use_tcp = TRUE; cam_list[0]->conf.mmalcam_name = NULL; cam_list[0]->conf.mmalcam_control_params = NULL; /* Image processing configuration parameters */ cam_list[0]->conf.width = 640; cam_list[0]->conf.height = 480; cam_list[0]->conf.framerate = 15; cam_list[0]->conf.rotate = 0; cam_list[0]->conf.flip_axis = "none"; cam_list[0]->conf.locate_motion_mode = "off"; cam_list[0]->conf.locate_motion_style = "box", cam_list[0]->conf.text_left = NULL; cam_list[0]->conf.text_right = "%Y-%m-%d\\n%T"; cam_list[0]->conf.text_changes = FALSE; cam_list[0]->conf.text_scale = 1; cam_list[0]->conf.text_event = "%Y%m%d%H%M%S"; /* Motion detection configuration parameters */ cam_list[0]->conf.emulate_motion = FALSE; cam_list[0]->conf.threshold = 1500; cam_list[0]->conf.threshold_maximum = 0; cam_list[0]->conf.threshold_tune = FALSE; cam_list[0]->conf.noise_level = 32; cam_list[0]->conf.noise_tune = TRUE; cam_list[0]->conf.despeckle_filter = NULL; cam_list[0]->conf.area_detect = NULL; cam_list[0]->conf.mask_file = NULL; cam_list[0]->conf.mask_privacy = NULL; cam_list[0]->conf.smart_mask_speed = 0; cam_list[0]->conf.lightswitch_percent = 0; cam_list[0]->conf.lightswitch_frames = 5; cam_list[0]->conf.minimum_motion_frames = 1; cam_list[0]->conf.event_gap = 60; cam_list[0]->conf.pre_capture = 0; cam_list[0]->conf.post_capture = 0; /* Script execution configuration parameters */ cam_list[0]->conf.on_event_start = NULL; cam_list[0]->conf.on_event_end = NULL; cam_list[0]->conf.on_picture_save = NULL; cam_list[0]->conf.on_motion_detected = NULL; cam_list[0]->conf.on_area_detected = NULL; cam_list[0]->conf.on_movie_start = NULL; cam_list[0]->conf.on_movie_end = NULL; cam_list[0]->conf.on_camera_lost = NULL; cam_list[0]->conf.on_camera_found = NULL; /* Picture output configuration parameters */ cam_list[0]->conf.picture_output = "off"; cam_list[0]->conf.picture_output_motion = FALSE; cam_list[0]->conf.picture_type = "jpeg"; cam_list[0]->conf.picture_quality = 75; cam_list[0]->conf.picture_exif = NULL; cam_list[0]->conf.picture_filename = "%v-%Y%m%d%H%M%S-%q"; /* Snapshot configuration parameters */ cam_list[0]->conf.snapshot_interval = 0; cam_list[0]->conf.snapshot_filename = "%v-%Y%m%d%H%M%S-snapshot"; /* Movie output configuration parameters */ cam_list[0]->conf.movie_output = TRUE; cam_list[0]->conf.movie_output_motion = FALSE; cam_list[0]->conf.movie_max_time = 120; cam_list[0]->conf.movie_bps = 400000; cam_list[0]->conf.movie_quality = 60; cam_list[0]->conf.movie_codec = "mkv"; cam_list[0]->conf.movie_passthrough = FALSE; cam_list[0]->conf.movie_filename = "%v-%Y%m%d%H%M%S"; cam_list[0]->conf.movie_extpipe_use = FALSE; cam_list[0]->conf.movie_extpipe = NULL; /* Timelapse movie configuration parameters */ cam_list[0]->conf.timelapse_interval = 0; cam_list[0]->conf.timelapse_mode = "daily"; cam_list[0]->conf.timelapse_fps = 30; cam_list[0]->conf.timelapse_codec = "mpg"; cam_list[0]->conf.timelapse_filename = "%Y%m%d-timelapse"; /* Loopback device configuration parameters */ cam_list[0]->conf.video_pipe = NULL; cam_list[0]->conf.video_pipe_motion = NULL; /* Webcontrol configuration parameters */ cam_list[0]->conf.webcontrol_port = 0; cam_list[0]->conf.webcontrol_ipv6 = FALSE; cam_list[0]->conf.webcontrol_localhost = TRUE; cam_list[0]->conf.webcontrol_parms = 0; cam_list[0]->conf.webcontrol_interface = 0; cam_list[0]->conf.webcontrol_auth_method = 0; cam_list[0]->conf.webcontrol_authentication = NULL; cam_list[0]->conf.webcontrol_tls = FALSE; cam_list[0]->conf.webcontrol_cert = NULL; cam_list[0]->conf.webcontrol_key = NULL; cam_list[0]->conf.webcontrol_cors_header = NULL; /* Live stream configuration parameters */ cam_list[0]->conf.stream_port = 0; cam_list[0]->conf.stream_localhost = TRUE; cam_list[0]->conf.stream_auth_method = 0; cam_list[0]->conf.stream_authentication = NULL; cam_list[0]->conf.stream_tls = FALSE; cam_list[0]->conf.stream_cors_header = NULL; cam_list[0]->conf.stream_preview_scale = 25; cam_list[0]->conf.stream_preview_newline = FALSE; cam_list[0]->conf.stream_preview_method = 0; cam_list[0]->conf.stream_quality = 50; cam_list[0]->conf.stream_grey = FALSE; cam_list[0]->conf.stream_motion = FALSE; cam_list[0]->conf.stream_maxrate = 1; cam_list[0]->conf.stream_limit = 0; /* Database and SQL configuration parameters */ cam_list[0]->conf.database_type = NULL; cam_list[0]->conf.database_dbname = NULL; cam_list[0]->conf.database_host = "localhost"; cam_list[0]->conf.database_port = 0; cam_list[0]->conf.database_user = NULL; cam_list[0]->conf.database_password = NULL; cam_list[0]->conf.database_busy_timeout = 0; cam_list[0]->conf.sql_log_picture = 0; cam_list[0]->conf.sql_log_snapshot = 0; cam_list[0]->conf.sql_log_movie = 0; cam_list[0]->conf.sql_log_timelapse = 0; cam_list[0]->conf.sql_query_start = NULL; cam_list[0]->conf.sql_query_stop = NULL; cam_list[0]->conf.sql_query = NULL; } static const char *conf_parm_get_bool(struct ctx_cam **cam_list, int indx_parm, int indx_thrd) { int val = config_parms[indx_parm].parm_offset; if (indx_thrd && *(int*)((char *)cam_list[indx_thrd] + val) == *(int*)((char *)cam_list[0] + val)){ return NULL; } if (*(int*)((char *)cam_list[indx_thrd] + val)){ return "on"; } else { return "off"; } } static const char *conf_parm_get_int(struct ctx_cam **cam_list, int indx_parm, int indx_thrd){ static char retval[20]; int val = config_parms[indx_parm].parm_offset; if (indx_thrd && *(int*)((char *)cam_list[indx_thrd] + val) == *(int*)((char *)cam_list[0] + val)){ return NULL; } sprintf(retval, "%d", *(int*)((char *)cam_list[indx_thrd] + val)); return retval; } static const char *conf_parm_get_string(struct ctx_cam **cam_list, int indx_parm, int indx_thrd) { int val = config_parms[indx_parm].parm_offset; const char **cptr0, **cptr1; cptr0 = (const char **)((char *)cam_list[0] + val); cptr1 = (const char **)((char *)cam_list[indx_thrd] + val); if ((indx_thrd) && (*cptr0 != NULL) && (*cptr1 != NULL) && (mystreq(*cptr0, *cptr1))){ return NULL; } return *cptr1; } static const char *conf_parm_get_camera(struct ctx_cam **cam_list, int indx_parm, int indx_thrd){ char *retval; unsigned int i = 0; (void)indx_parm; if (indx_thrd != 0) return NULL; retval = (char*)mymalloc(1); retval[0] = 0; while (cam_list[++i]) { /* Skip config files loaded from conf directory */ if (cam_list[i]->from_conf_dir) continue; retval = (char*)myrealloc(retval, strlen(retval) + strlen(cam_list[i]->conf_filename) + 10, "print_camera"); sprintf(retval + strlen(retval), "camera %s\n", cam_list[i]->conf_filename); } return NULL; } /** Retrieve the parameter requested */ const char *conf_parm_get(struct ctx_cam **cam_list, int indx_parm, int indx_thrd){ if (config_parms[indx_parm].parm_type == PARM_TYPE_BOOL) { return conf_parm_get_bool(cam_list, indx_parm, indx_thrd); } else if (config_parms[indx_parm].parm_type == PARM_TYPE_INT) { return conf_parm_get_int(cam_list, indx_parm, indx_thrd); } else if ((config_parms[indx_parm].parm_type == PARM_TYPE_STRING) || (config_parms[indx_parm].parm_type == PARM_TYPE_URI)) { return conf_parm_get_string(cam_list, indx_parm, indx_thrd); } else if ((config_parms[indx_parm].parm_type == PARM_TYPE_CAMERA)) { return conf_parm_get_camera(cam_list, indx_parm, indx_thrd); } else { return NULL; } } /** Write the configuration(s) to the log */ void conf_parms_log(struct ctx_cam **cam_list) { int i, t; const char *parm_val; t = 0; while(cam_list[++t]); MOTION_LOG(INF, TYPE_ALL, NO_ERRNO ,_("Writing configuration parameters from all files (%d):"), t); for (t = 0; cam_list[t]; t++) { motion_log(INF, TYPE_ALL, NO_ERRNO,0 ,_("Camera %d - Config file: %s"), t, cam_list[t]->conf_filename); i = 0; while (config_parms[i].parm_name != NULL) { parm_val = conf_parm_get(cam_list, i, t); if (parm_val != NULL) { 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); } } } else { if (t == 0) { motion_log(INF, TYPE_ALL, NO_ERRNO,0, "%-25s " , config_parms[i].parm_name); } } i++; } } } /** Write the configuration(s) to file */ void conf_parms_write(struct ctx_cam **cam_list) { const char *retval; 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++) { retval = conf_parm_get(cam_list, i, thread); /* If config parameter has a value (not NULL) print it to the config file. */ if (retval) { 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(retval, " ", 1)){ fprintf(conffile, "%s %s\n\n", config_parms[i].parm_name, retval); } else { fprintf(conffile, "%s \"%s\"\n\n", config_parms[i].parm_name, retval); } } else { if (thread == 0) { char value[PATH_MAX]; /* The 'camera_dir' option should keep the installed default value */ if (!strncmp(config_parms[i].parm_name, "camera_dir", 10)){ 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(struct ctx_motapp *motapp, int argc, char *argv[]){ FILE *fp = NULL; char filename[PATH_MAX]; int i; /* Create the starting cam_list. The last entry must be NULL */ 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; /* Minimum required initial values. Most defaults set in * motion_init_defaults at start of motion_loop */ motapp->cam_list[0]->motapp = motapp; motapp->cam_list[0]->cam_list = motapp->cam_list; motapp->cam_list[0]->conf.argv = argv; motapp->cam_list[0]->conf.argc = argc; conf_defaults(motapp->cam_list); /* * For each member of cam_list[0] which is a pointer to a string * if the member points to a string in conf_template and is not NULL. * 1. Reserve (malloc) memory for the string. * 2. Copy the conf_template given string to the reserved memory. * 3. Change the cam_list[0] member (char*) pointing to the string in reserved memory. * This ensures that we can free and malloc the string when changed * via http remote control or config file or Command-line options. */ conf_malloc_strings(motapp->cam_list[0]); /* * Open the motion.conf file. We try in this sequence: * 1. Command-line * 2. current working directory * 3. $HOME/.motion/motion.conf * 4. sysconfdir/motion.conf */ /* Get filename , pid file & log file from Command-line. */ conf_cmdline(motapp->cam_list[0], -1); if (motapp->cam_list[0]->conf_filename[0]) { /* User has supplied filename on Command-line. */ strncpy(filename, motapp->cam_list[0]->conf_filename, PATH_MAX-1); filename[PATH_MAX-1] = '\0'; fp = fopen (filename, "r"); } if (!fp) { /* Command-line didn't work, try current dir. */ char path[PATH_MAX]; if (motapp->cam_list[0]->conf_filename[0]){ MOTION_LOG(ALR, TYPE_ALL, SHOW_ERRNO ,_("Configfile %s not found - trying defaults.") ,filename); } if (getcwd(path, sizeof(path)) == NULL) { MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Error getcwd")); exit(-1); } snprintf(filename, PATH_MAX, "%.*s/motion.conf" , (int)(PATH_MAX-1-strlen("/motion.conf")) , path); fp = fopen (filename, "r"); } if (!fp) { /* Specified file does not exist... try default file. */ snprintf(filename, PATH_MAX, "%s/.motion/motion.conf", getenv("HOME")); fp = fopen(filename, "r"); if (!fp) { snprintf(filename, PATH_MAX, "%s/motion.conf", sysconfdir); fp = fopen(filename, "r"); if (!fp){ /* There is no config file.... use defaults. */ 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) { strncpy(motapp->cam_list[0]->conf_filename, filename , sizeof(motapp->cam_list[0]->conf_filename) - 1); motapp->cam_list[0]->conf_filename[sizeof(motapp->cam_list[0]->conf_filename) - 1] = '\0'; MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO ,_("Processing thread 0 - config file %s"), filename); conf_process(motapp->cam_list[0], fp); myfclose(fp); } else { MOTION_LOG(CRT, TYPE_ALL, NO_ERRNO ,_("No config file to process, using default values")); } /* Set the application defaults to values in cam_list[0] */ motapp->daemon = motapp->cam_list[0]->conf.daemon; if (motapp->cam_list[0]->conf.pid_file){ snprintf(motapp->pid_file , sizeof(motapp->pid_file) , "%s", motapp->cam_list[0]->conf.pid_file); } if (motapp->cam_list[0]->conf.log_file){ snprintf(motapp->log_file , sizeof(motapp->log_file) , "%s", motapp->cam_list[0]->conf.log_file); } if (motapp->cam_list[0]->conf.log_type){ snprintf(motapp->log_type_str , sizeof(motapp->log_type_str) , "%s", motapp->cam_list[0]->conf.log_type); } motapp->log_level = motapp->cam_list[0]->conf.log_level; /*Now update everything with command line overrides */ i = -1; while (motapp->cam_list[++i]){ conf_cmdline(motapp->cam_list[i], i); motapp->cam_list[i]->motapp = motapp; motapp->cam_list[i]->cam_list = motapp->cam_list; } config_parms_intl(); return; } void conf_deinit(struct ctx_motapp *motapp) { int j, indx; void **val; indx = 0; while (motapp->cam_list[indx] != NULL){ /* Free memory allocated for config parameters */ for (j = 0; config_parms[j].parm_name != NULL; j++) { if ((config_parms[j].parm_type == PARM_TYPE_STRING) || (config_parms[j].parm_type == PARM_TYPE_URI) ) { val = (void **)((char *)motapp->cam_list[indx] + config_parms[j].parm_offset); if (*val) { free(*val); *val = NULL; } } } free(motapp->cam_list[indx]); indx++; } free(motapp->cam_list); motapp->cam_list = NULL; }