mirror of
https://github.com/Motion-Project/motion.git
synced 2025-12-23 23:18:21 -05:00
Implement a new configuration option which allows users to specify the type of parameters which can be accessed via the webcontrol page. The new option permits levels 0(none) to 3(restricted) with a default of none. This option is to enhance the security associated with the application for users that may expose the webcontrol port publicly. Close #515
2733 lines
122 KiB
C
2733 lines
122 KiB
C
/*
|
|
* webhttpd.c
|
|
*
|
|
* HTTP Control interface for motion.
|
|
*
|
|
* Specs : http://www.lavrsen.dk/twiki/bin/view/Motion/MotionHttpAPI
|
|
*
|
|
* Copyright 2004-2005 by Angel Carpintero (motiondevelop@gmail.com)
|
|
* This software is distributed under the GNU Public License Version 2
|
|
* See also the file 'COPYING'.
|
|
*
|
|
*/
|
|
#include "webhttpd.h" /* already includes motion.h */
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <stddef.h>
|
|
#include <ctype.h>
|
|
|
|
/* Timeout in seconds, used for read and write */
|
|
const int NONBLOCK_TIMEOUT = 1;
|
|
|
|
pthread_mutex_t httpd_mutex;
|
|
|
|
// This is a dummy variable use to kill warnings when not checking sscanf and similar functions
|
|
int warningkill;
|
|
|
|
static const char *ini_template =
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<head><title>Motion "VERSION"</title></head>\n"
|
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">\n"
|
|
"<body>\n";
|
|
|
|
static const char *set_template =
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<head>\n"
|
|
"<title>Motion "VERSION"</title>\n"
|
|
"<script language='javascript'>"
|
|
"function show() {top.location.href="
|
|
"'set?'+document.n.onames.options[document.n.onames.selectedIndex].value"
|
|
"+'='+document.s.valor.value;"
|
|
"}</script>\n"
|
|
"</head>\n"
|
|
"<body>\n";
|
|
|
|
static const char *end_template =
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
static const char *ok_response =
|
|
"HTTP/1.1 200 OK\r\n"
|
|
"Server: Motion-httpd/"VERSION"\r\n"
|
|
"Connection: close\r\n"
|
|
"Max-Age: 0\r\n"
|
|
"Expires: 0\r\n"
|
|
"Cache-Control: no-cache\r\n"
|
|
"Cache-Control: private\r\n"
|
|
"Pragma: no-cache\r\n"
|
|
"Content-type: text/html\r\n\r\n";
|
|
|
|
static const char *ok_response_raw =
|
|
"HTTP/1.1 200 OK\r\n"
|
|
"Server: Motion-httpd/"VERSION"\r\n"
|
|
"Connection: close\r\n"
|
|
"Max-Age: 0\r\n"
|
|
"Expires: 0\r\n"
|
|
"Cache-Control: no-cache\r\n"
|
|
"Cache-Control: private\r\n"
|
|
"Pragma: no-cache\r\n"
|
|
"Content-type: text/plain\r\n\r\n";
|
|
|
|
static const char *bad_request_response =
|
|
"HTTP/1.0 400 Bad Request\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Bad Request</h1>\n"
|
|
"<p>The server did not understand your request.</p>\n"
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
static const char *bad_request_response_raw =
|
|
"HTTP/1.0 400 Bad Request\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"Bad Request";
|
|
|
|
static const char *not_found_response_template =
|
|
"HTTP/1.0 404 Not Found\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Not Found</h1>\n"
|
|
"<p>The requested URL was not found on the server.</p>\n"
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
static const char *not_found_response_template_raw =
|
|
"HTTP/1.0 404 Not Found\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"Not Found";
|
|
|
|
static const char *not_found_response_valid =
|
|
"HTTP/1.0 404 Not Valid\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Not Valid</h1>\n"
|
|
"<p>The requested URL is not valid.</p>\n"
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
static const char *not_found_response_valid_raw =
|
|
"HTTP/1.0 404 Not Valid\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"The requested URL is not valid.";
|
|
|
|
static const char *not_valid_syntax =
|
|
"HTTP/1.0 404 Not Valid Syntax\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Not Valid Syntax</h1>\n"
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
static const char *not_valid_syntax_raw =
|
|
"HTTP/1.0 404 Not Valid Syntax\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"Not Valid Syntax\n";
|
|
|
|
static const char *not_track =
|
|
"HTTP/1.0 200 OK\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Tracking Not Enabled</h1>\n";
|
|
|
|
static const char *not_track_raw =
|
|
"HTTP/1.0 200 OK\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"Tracking Not Enabled";
|
|
|
|
static const char *track_error =
|
|
"HTTP/1.0 200 OK\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Track Error</h1>\n";
|
|
|
|
static const char *track_error_raw =
|
|
"HTTP/1.0 200 OK\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"Track Error";
|
|
|
|
static const char *error_value =
|
|
"HTTP/1.0 200 OK\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Value Error</h1>\n";
|
|
|
|
static const char *error_value_raw =
|
|
"HTTP/1.0 200 OK\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"Value Error";
|
|
|
|
static const char *not_found_response_valid_command =
|
|
"HTTP/1.0 404 Not Valid Command\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Not Valid Command</h1>\n"
|
|
"<p>The requested URL is not valid Command.</p>\n"
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
static const char *not_found_response_valid_command_raw =
|
|
"HTTP/1.0 404 Not Valid Command\r\n"
|
|
"Content-type: text/plain\n\n"
|
|
"Not Valid Command\n";
|
|
|
|
static const char *bad_method_response_template =
|
|
"HTTP/1.0 501 Method Not Implemented\r\n"
|
|
"Content-type: text/html\r\n\r\n"
|
|
"<!DOCTYPE html>\n"
|
|
"<html>\n"
|
|
"<body>\n"
|
|
"<h1>Method Not Implemented</h1>\n"
|
|
"<p>The method is not implemented by this server.</p>\n"
|
|
"</body>\n"
|
|
"</html>\n";
|
|
|
|
static const char *bad_method_response_template_raw =
|
|
"HTTP/1.0 501 Method Not Implemented\r\n"
|
|
"Content-type: text/plain\r\n\r\n"
|
|
"Method Not Implemented\n";
|
|
|
|
static const char *request_auth_response_template=
|
|
"HTTP/1.0 401 Authorization Required\r\n"
|
|
"WWW-Authenticate: Basic realm=\"Motion Security Access\"\r\n";
|
|
|
|
/**
|
|
* write_nonblock
|
|
*/
|
|
static ssize_t write_nonblock(int fd, const void *buf, size_t size)
|
|
{
|
|
ssize_t nwrite = -1;
|
|
struct timeval tm;
|
|
fd_set fds;
|
|
|
|
tm.tv_sec = NONBLOCK_TIMEOUT;
|
|
tm.tv_usec = 0;
|
|
FD_ZERO(&fds);
|
|
FD_SET(fd, &fds);
|
|
|
|
if (select(fd + 1, NULL, &fds, NULL, &tm) > 0) {
|
|
if (FD_ISSET(fd, &fds)) {
|
|
if ((nwrite = write(fd , buf, size)) < 0) {
|
|
if (errno != EWOULDBLOCK)
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nwrite;
|
|
}
|
|
|
|
/**
|
|
* read_nonblock
|
|
*/
|
|
static ssize_t read_nonblock(int fd ,void *buf, ssize_t size)
|
|
{
|
|
ssize_t nread = -1;
|
|
struct timeval tm;
|
|
fd_set fds;
|
|
|
|
tm.tv_sec = NONBLOCK_TIMEOUT; /* Timeout in seconds */
|
|
tm.tv_usec = 0;
|
|
FD_ZERO(&fds);
|
|
FD_SET(fd, &fds);
|
|
|
|
if (select(fd + 1, &fds, NULL, NULL, &tm) > 0) {
|
|
if (FD_ISSET(fd, &fds)) {
|
|
if ((nread = read(fd , buf, size)) < 0) {
|
|
if (errno != EWOULDBLOCK)
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nread;
|
|
}
|
|
|
|
/**
|
|
* send_template_ini_client
|
|
*/
|
|
static void send_template_ini_client(int client_socket, const char *template)
|
|
{
|
|
ssize_t nwrite = 0;
|
|
nwrite = write_nonblock(client_socket, ok_response, strlen(ok_response));
|
|
nwrite += write_nonblock(client_socket, template, strlen(template));
|
|
if (nwrite != (ssize_t)(strlen(ok_response) + strlen(template)))
|
|
MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO, "failure write");
|
|
}
|
|
|
|
/**
|
|
* send_template_ini_client_raw
|
|
*/
|
|
static void send_template_ini_client_raw(int client_socket)
|
|
{
|
|
ssize_t nwrite = 0;
|
|
nwrite = write_nonblock(client_socket, ok_response_raw, strlen(ok_response_raw));
|
|
if (nwrite != (ssize_t)strlen(ok_response_raw))
|
|
MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO, "failure write");
|
|
}
|
|
|
|
/**
|
|
* send_template
|
|
*/
|
|
static void send_template(int client_socket, char *res)
|
|
{
|
|
ssize_t nwrite = 0;
|
|
nwrite = write_nonblock(client_socket, res, strlen(res));
|
|
if (nwrite != (ssize_t)strlen(res))
|
|
MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO, "failure write");
|
|
}
|
|
|
|
/**
|
|
* send_template_raw
|
|
*/
|
|
static void send_template_raw(int client_socket, char *res)
|
|
{
|
|
ssize_t nwrite = 0;
|
|
nwrite = write_nonblock(client_socket, res, strlen(res));
|
|
if (nwrite < 0)
|
|
MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "write_nonblock returned value less than zero.");
|
|
}
|
|
|
|
/**
|
|
* send_template_end_client
|
|
*/
|
|
static void send_template_end_client(int client_socket)
|
|
{
|
|
ssize_t nwrite = 0;
|
|
nwrite = write_nonblock(client_socket, end_template, strlen(end_template));
|
|
if (nwrite < 0)
|
|
MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "write_nonblock returned value less than zero.");
|
|
|
|
}
|
|
|
|
/**
|
|
* response_client
|
|
*/
|
|
static void response_client(int client_socket, const char *template, char *back)
|
|
{
|
|
ssize_t nwrite = 0;
|
|
nwrite = write_nonblock(client_socket, template, strlen(template));
|
|
if (back != NULL) {
|
|
send_template(client_socket, back);
|
|
send_template_end_client(client_socket);
|
|
}
|
|
if (nwrite < 0)
|
|
MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "write_nonblock returned value less than zero.");
|
|
|
|
}
|
|
|
|
/**
|
|
* get_host
|
|
* Gets the host (IP) of a client from the socket file descriptor
|
|
* Returns nothing
|
|
*/
|
|
static void get_host(char *buf, int fd)
|
|
{
|
|
struct sockaddr_in6 client;
|
|
socklen_t client_len = sizeof(client);
|
|
int res = getpeername(fd, (struct sockaddr *)&client, &client_len);
|
|
if (res != 0)
|
|
return;
|
|
|
|
char host[NI_MAXHOST];
|
|
res = getnameinfo((struct sockaddr *)&client, client_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
|
|
if (res != 0)
|
|
return;
|
|
|
|
strncpy(buf, host, NI_MAXHOST - 1);
|
|
}
|
|
|
|
/**
|
|
* replace
|
|
*/
|
|
static char *replace(const char *str, const char *old, const char *new)
|
|
{
|
|
char *ret, *r;
|
|
const char *p, *q;
|
|
size_t oldlen = strlen(old);
|
|
size_t count, retlen, newlen = strlen(new);
|
|
|
|
if (oldlen != newlen) {
|
|
for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen)
|
|
count++;
|
|
/* this is undefined if p - str > PTRDIFF_MAX */
|
|
retlen = p - str + strlen(p) + count * (newlen - oldlen);
|
|
} else
|
|
retlen = strlen(str);
|
|
|
|
ret = mymalloc(retlen + 1);
|
|
|
|
for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
|
|
/* this is undefined if q - p > PTRDIFF_MAX */
|
|
ptrdiff_t l = q - p;
|
|
memcpy(r, p, l);
|
|
r += l;
|
|
memcpy(r, new, newlen);
|
|
r += newlen;
|
|
}
|
|
strcpy(r, p);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* url_decode
|
|
* This function decode the values from GET request following the http RFC.
|
|
*
|
|
* Returns nothing.
|
|
*/
|
|
static void url_decode(char *urlencoded, size_t length)
|
|
{
|
|
char *data = urlencoded;
|
|
char *urldecoded = urlencoded;
|
|
|
|
while (length > 0) {
|
|
if (*data == '%') {
|
|
char c[3];
|
|
int i;
|
|
data++;
|
|
length--;
|
|
c[0] = *data++;
|
|
length--;
|
|
c[1] = *data;
|
|
c[2] = 0;
|
|
|
|
warningkill = sscanf(c, "%x", &i);
|
|
|
|
if (i < 128) {
|
|
*urldecoded++ = (char)i;
|
|
} else {
|
|
*urldecoded++ = '%';
|
|
*urldecoded++ = c[0];
|
|
*urldecoded++ = c[1];
|
|
}
|
|
|
|
} else if (*data == '<' || *data == '+' || *data == '>') {
|
|
*urldecoded++ = ' ';
|
|
} else {
|
|
*urldecoded++ = *data;
|
|
}
|
|
|
|
data++;
|
|
length--;
|
|
}
|
|
*urldecoded = '\0';
|
|
}
|
|
|
|
|
|
/**
|
|
* config
|
|
* Manages/parses the config action for motion ( set , get , write , list ).
|
|
*
|
|
* Returns 1 to exit from function.
|
|
*/
|
|
static unsigned int config(char *pointer, char *res, unsigned int length_uri,
|
|
unsigned int thread, int client_socket, void *userdata)
|
|
{
|
|
char question='\0';
|
|
char command[256] = {'\0'};
|
|
unsigned int i;
|
|
struct context **cnt = userdata;
|
|
|
|
warningkill = sscanf(pointer, "%255[a-z]%c", command , &question);
|
|
if (!strcmp(command, "list")) {
|
|
pointer = pointer + 4;
|
|
length_uri = length_uri - 4;
|
|
if (length_uri == 0) {
|
|
const char *value = NULL;
|
|
char *retval = NULL;
|
|
/*call list*/
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/config><– back</a><br><br>\n<b>Camera %d%s%s</b>\n<ul>",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
|
|
send_template(client_socket, res);
|
|
|
|
for (i=0; config_params[i].param_name != NULL; i++) {
|
|
|
|
if (((thread != 0) && (config_params[i].main_thread)) ||
|
|
(config_params[i].webui_level > cnt[0]->conf.webcontrol_parms) ||
|
|
(config_params[i].webui_level == WEBUI_LEVEL_NEVER) )
|
|
continue;
|
|
|
|
value = config_params[i].print(cnt, NULL, i, thread);
|
|
|
|
if (value == NULL) {
|
|
retval = NULL;
|
|
|
|
/* Only get the thread value for main thread */
|
|
if (thread == 0)
|
|
config_params[i].print(cnt, &retval, i, thread);
|
|
|
|
/* thread value*/
|
|
|
|
if (retval) {
|
|
|
|
if (!strcmp(retval,"")) {
|
|
free(retval);
|
|
retval = mystrdup("No threads");
|
|
} else {
|
|
char *temp = retval;
|
|
size_t retval_miss = 0;
|
|
size_t retval_len = strlen(retval);
|
|
unsigned int ind = 0;
|
|
char thread_strings[1024] = {'\0'};
|
|
|
|
while (retval_miss != retval_len) {
|
|
while (*temp != '\n') {
|
|
thread_strings[ind++] = *temp;
|
|
retval_miss++;
|
|
temp++;
|
|
}
|
|
temp++;
|
|
thread_strings[ind++] = '<';
|
|
thread_strings[ind++] = 'b';
|
|
thread_strings[ind++] = 'r';
|
|
thread_strings[ind++] = '>';
|
|
retval_miss++;
|
|
}
|
|
free(retval);
|
|
retval = NULL;
|
|
retval = mystrdup(thread_strings);
|
|
}
|
|
|
|
sprintf(res, "<li><a href=/%u/config/set?%s>%s</a> = %s</li>\n", thread,
|
|
config_params[i].param_name, config_params[i].param_name, retval);
|
|
free(retval);
|
|
} else if (thread != 0) {
|
|
/* get the value from main thread for the rest of threads */
|
|
value = config_params[i].print(cnt, NULL, i, 0);
|
|
|
|
sprintf(res, "<li><a href=/%u/config/set?%s>%s</a> = %s</li>\n", thread,
|
|
config_params[i].param_name, config_params[i].param_name,
|
|
value ? value : "(not defined)");
|
|
} else {
|
|
sprintf(res, "<li><a href=/%u/config/set?%s>%s</a> = %s</li>\n", thread,
|
|
config_params[i].param_name, config_params[i].param_name,
|
|
"(not defined)");
|
|
}
|
|
|
|
} else {
|
|
sprintf(res, "<li><a href=/%u/config/set?%s>%s</a> = %s</li>\n", thread,
|
|
config_params[i].param_name, config_params[i].param_name, value);
|
|
}
|
|
send_template(client_socket, res);
|
|
}
|
|
|
|
sprintf(res, "</ul><a href=/%u/config><– back</a>", thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
for (i=0; config_params[i].param_name != NULL; i++) {
|
|
value = config_params[i].print(cnt, NULL, i, thread);
|
|
if (value == NULL)
|
|
value = config_params[i].print(cnt, NULL, i, 0);
|
|
sprintf(res, "%s = %s\n", config_params[i].param_name, value);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
}
|
|
} else {
|
|
/*error*/
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "set")) {
|
|
/* set?param_name=value */
|
|
pointer = pointer + 3;
|
|
length_uri = length_uri - 3;
|
|
if ((length_uri != 0) && (question == '?')) {
|
|
pointer++;
|
|
length_uri--;
|
|
warningkill = sscanf(pointer,"%255[-0-9a-z_]%c", command, &question);
|
|
/*check command , question == '=' length_uri too*/
|
|
if ((question == '=') && (command[0] != '\0')) {
|
|
length_uri = length_uri - strlen(command) - 1;
|
|
pointer = pointer + strlen(command) + 1;
|
|
/* check if command exists and type of command and not end of URI */
|
|
i=0;
|
|
while (config_params[i].param_name != NULL) {
|
|
|
|
if (((thread != 0) && (config_params[i].main_thread)) ||
|
|
(config_params[i].webui_level > cnt[0]->conf.webcontrol_parms) ||
|
|
(config_params[i].webui_level == WEBUI_LEVEL_NEVER) ) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (!strcasecmp(command, config_params[i].param_name))
|
|
break;
|
|
i++;
|
|
}
|
|
|
|
if (config_params[i].param_name) {
|
|
if (length_uri > 0) {
|
|
char Value[1024] = {'\0'};
|
|
warningkill = sscanf(pointer,"%1023s", Value);
|
|
length_uri = length_uri - strlen(Value);
|
|
if ((length_uri == 0) && (strlen(Value) > 0)) {
|
|
/* FIXME need to assure that is a valid value */
|
|
url_decode(Value, strlen(Value));
|
|
conf_cmdparse(cnt + thread, config_params[i].param_name, Value);
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res,
|
|
"<a href=/%u/config/list><– back</a>"
|
|
"<br><br>\n<b>Camera %d%s%s</b>\n"
|
|
"<ul><li><a href=/%u/config/set?%s>%s</a> = %s"
|
|
"</li></ul><b>Done</b>",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
thread, config_params[i].param_name,
|
|
config_params[i].param_name, Value);
|
|
|
|
send_template_ini_client(client_socket, ini_template);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "%s = %s\nDone\n", config_params[i].param_name, Value);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/*error*/
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
}
|
|
} else {
|
|
char *type = NULL;
|
|
type = mystrdup(config_type(&config_params[i]));
|
|
|
|
if (!strcmp(type, "string")) {
|
|
char *value = NULL;
|
|
conf_cmdparse(cnt+thread, config_params[i].param_name, value);
|
|
free(type);
|
|
type = mystrdup("(null)");
|
|
} else if (!strcmp(type, "int")) {
|
|
free(type);
|
|
type = mystrdup("0");
|
|
conf_cmdparse(cnt+thread, config_params[i].param_name, type);
|
|
} else if (!strcmp(type, "bool")) {
|
|
free(type);
|
|
type = mystrdup("off");
|
|
conf_cmdparse(cnt+thread, config_params[i].param_name, type);
|
|
} else {
|
|
free(type);
|
|
type = mystrdup("unknown");
|
|
}
|
|
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res,
|
|
"<a href=/%u/config/list><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b>\n<ul><li><a href=/%u/config/set?%s>%s</a>"
|
|
"= %s</li></ul><br><b>Done</b>", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
thread,
|
|
config_params[i].param_name, config_params[i].param_name, type);
|
|
|
|
send_template_ini_client(client_socket, ini_template);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "%s = %s\nDone\n", config_params[i].param_name, type);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
free(type);
|
|
|
|
}
|
|
} else {
|
|
/*error*/
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
/* Show param_name dialogue only for html output */
|
|
if ((cnt[0]->conf.webcontrol_html_output) && (command[0] != '\0') &&
|
|
(((length_uri = length_uri - strlen(command)) == 0))) {
|
|
i=0;
|
|
while (config_params[i].param_name != NULL) {
|
|
if (((thread != 0) && (config_params[i].main_thread)) ||
|
|
(config_params[i].webui_level > cnt[0]->conf.webcontrol_parms) ||
|
|
(config_params[i].webui_level == WEBUI_LEVEL_NEVER) ) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (!strcasecmp(command, config_params[i].param_name))
|
|
break;
|
|
i++;
|
|
}
|
|
/* param_name exists */
|
|
if (config_params[i].param_name) {
|
|
const char *value = NULL;
|
|
char *text_help = NULL;
|
|
char *sharp = NULL;
|
|
|
|
value = config_params[i].print(cnt, NULL, i, thread);
|
|
|
|
sharp = strstr(config_params[i].param_help, "#\n\n#");
|
|
if (sharp == NULL)
|
|
sharp = strstr(config_params[i].param_help, "#");
|
|
sharp++;
|
|
|
|
text_help = replace(sharp, "\n#", "<br>");
|
|
|
|
send_template_ini_client(client_socket, ini_template);
|
|
if (!strcmp ("bool", config_type(&config_params[i]))) {
|
|
char option[80] = {'\0'};
|
|
|
|
if ((value == NULL) && (thread != 0))
|
|
value = config_params[i].print(cnt, NULL, i, 0);
|
|
|
|
if (!strcmp ("on", value))
|
|
sprintf(option, "<option value='on' selected>on</option>\n"
|
|
"<option value='off'>off</option>\n");
|
|
else
|
|
sprintf(option, "<option value='on'>on</option>\n"
|
|
"<option value='off' selected>off</option>\n");
|
|
|
|
sprintf(res, "<a href=/%u/config/list><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b>\n"
|
|
"<form action=set?>\n"
|
|
"<b>%s</b> <select name='%s'>\n"
|
|
"%s"
|
|
"</select><input type='submit' value='set'>\n"
|
|
" "
|
|
"<a href='%s#%s' target=_blank>[help]</a>"
|
|
"</form>\n<hr><i>%s</i>", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
config_params[i].param_name, config_params[i].param_name,
|
|
option, TWIKI_URL, config_params[i].param_name, text_help);
|
|
} else {
|
|
|
|
if (value == NULL) {
|
|
if (thread != 0)
|
|
/* get the value from main thread for the rest of threads */
|
|
value = config_params[i].print(cnt, NULL, i, 0);
|
|
if (value == NULL) value = "";
|
|
}
|
|
sprintf(res, "<a href=/%u/config/list><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b>\n<form action=set?>\n"
|
|
"<b>%s</b> <input type=text name='%s' value='%s' size=80>\n"
|
|
"<input type='submit' value='set'>\n"
|
|
" "
|
|
"<a href='%s#%s' target=_blank>[help]</a>"
|
|
"</form>\n<hr><i>%s</i>", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
config_params[i].param_name, config_params[i].param_name,
|
|
value, TWIKI_URL, config_params[i].param_name, text_help);
|
|
}
|
|
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
free(text_help);
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
}
|
|
} else if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, set_template);
|
|
sprintf(res, "<a href=/%u/config><– back</a><br><br>\n<b>Camera %d%s%s</b>\n"
|
|
"<form name='n'>\n<select name='onames'>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
|
|
send_template(client_socket, res);
|
|
for (i=0; config_params[i].param_name != NULL; i++) {
|
|
if (((thread != 0) && (config_params[i].main_thread)) ||
|
|
(config_params[i].webui_level > cnt[0]->conf.webcontrol_parms) ||
|
|
(config_params[i].webui_level == WEBUI_LEVEL_NEVER) )
|
|
continue;
|
|
sprintf(res, "<option value='%s'>%s</option>\n",
|
|
config_params[i].param_name, config_params[i].param_name);
|
|
send_template(client_socket, res);
|
|
}
|
|
sprintf(res, "</select>\n</form>\n"
|
|
"<form action=set name='s'"
|
|
"ONSUBMIT='if (!this.submitted) return false; else return true;'>\n"
|
|
"<input type=text name='valor' value=''>\n"
|
|
"<input type='button' value='set' onclick='javascript:show()'>\n"
|
|
"</form>\n");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "set needs param_name=value\n");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/*error*/
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "get")) {
|
|
/* get?query=param_name */
|
|
pointer = pointer + 3;
|
|
length_uri = length_uri - 3;
|
|
|
|
if ((length_uri > 7) && (question == '?')) {
|
|
/* 8 -> query=param_name FIXME minimum length param_name */
|
|
pointer++;
|
|
length_uri--;
|
|
warningkill = sscanf(pointer,"%255[-0-9a-z]%c", command, &question);
|
|
|
|
if ((question == '=') && (!strcmp(command, "query"))) {
|
|
pointer = pointer + 6;
|
|
length_uri = length_uri - 6;
|
|
warningkill = sscanf(pointer, "%255[-0-9a-z_]", command);
|
|
/*check if command exist, length_uri too*/
|
|
length_uri = length_uri - strlen(command);
|
|
|
|
if (length_uri == 0) {
|
|
const char *value = NULL;
|
|
i = 0;
|
|
while (config_params[i].param_name != NULL) {
|
|
if (((thread != 0) && (config_params[i].main_thread)) ||
|
|
(config_params[i].webui_level > cnt[0]->conf.webcontrol_parms) ||
|
|
(config_params[i].webui_level == WEBUI_LEVEL_NEVER) ) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (!strcasecmp(command, config_params[i].param_name))
|
|
break;
|
|
i++;
|
|
}
|
|
/*
|
|
* FIXME bool values or commented values maybe that should be
|
|
* solved with config_type
|
|
*/
|
|
if (config_params[i].param_name) {
|
|
const char *type = NULL;
|
|
type = config_type(&config_params[i]);
|
|
if (!strcmp(type, "unknown")) {
|
|
/* error doesn't exists this param_name */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
return 1;
|
|
} else {
|
|
char *text_help = NULL;
|
|
char *sharp = NULL;
|
|
|
|
value = config_params[i].print(cnt, NULL, i, thread);
|
|
|
|
sharp = strstr(config_params[i].param_help, "#\n\n#");
|
|
if (sharp == NULL)
|
|
sharp = strstr(config_params[i].param_help, "#");
|
|
sharp++;
|
|
|
|
text_help = replace(sharp, "\n#", "<br>");
|
|
|
|
if (value == NULL)
|
|
value = config_params[i].print(cnt, NULL, i, 0);
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/config/get><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b><br>\n<ul><li>%s = %s "
|
|
" <a href='%s#%s' target=_blank>"
|
|
"[help]</a></li></ul><hr><i>%s</i>",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
config_params[i].param_name, value,
|
|
TWIKI_URL, config_params[i].param_name, text_help);
|
|
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
|
|
free(text_help);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "%s = %s\nDone\n", config_params[i].param_name, value);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
}
|
|
} else if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/config><– back</a><br><br>\n<b>Camera %d%s%s</b><br>\n"
|
|
"<form action=get>\n"
|
|
"<select name='query'>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template(client_socket, res);
|
|
for (i=0; config_params[i].param_name != NULL; i++) {
|
|
if (((thread != 0) && (config_params[i].main_thread)) ||
|
|
(config_params[i].webui_level > cnt[0]->conf.webcontrol_parms) ||
|
|
(config_params[i].webui_level == WEBUI_LEVEL_NEVER) )
|
|
continue;
|
|
sprintf(res, "<option value='%s'>%s</option>\n",
|
|
config_params[i].param_name, config_params[i].param_name);
|
|
send_template(client_socket, res);
|
|
}
|
|
sprintf(res, "</select>\n"
|
|
"<input type='submit' value='get'>\n"
|
|
"</form>\n");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "get needs param_name\n");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "write")) {
|
|
pointer = pointer + 5;
|
|
length_uri = length_uri - 5;
|
|
if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/config><– back</a><br><br>"
|
|
"Are you sure? <a href=/%u/config/writeyes>Yes</a>\n", thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
conf_print(cnt);
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d write\nDone\n", cnt[thread]->conf.camera_id);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
|
|
} else if (!strcmp(command, "writeyes")) {
|
|
pointer = pointer + 8;
|
|
length_uri = length_uri - 8;
|
|
if (length_uri == 0) {
|
|
conf_print(cnt);
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/config><– back</a><br><br>\n<b>Camera %d%s%s</b> write done !\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d write\nDone\n", cnt[thread]->conf.camera_id);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
}
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* action
|
|
* manages/parses the actions for motion ( makemovie , snapshot , restart , quit ).
|
|
*
|
|
* Returns
|
|
* 0 for restart & quit
|
|
* 1 for makemovie & snaphost
|
|
*/
|
|
static unsigned int action(char *pointer, char *res, unsigned int length_uri,
|
|
unsigned int thread, int client_socket, void *userdata)
|
|
{
|
|
/* parse action commands */
|
|
char command[256] = {'\0'};
|
|
struct context **cnt = userdata;
|
|
unsigned int i = 0;
|
|
|
|
warningkill = sscanf(pointer, "%255[a-z]" , command);
|
|
if (!strcmp(command, "makemovie")) {
|
|
pointer = pointer + 9;
|
|
length_uri = length_uri - 9;
|
|
if (length_uri == 0) {
|
|
/* call makemovie */
|
|
|
|
if (thread == 0) {
|
|
while (cnt[++i])
|
|
cnt[i]->makemovie = 1;
|
|
} else {
|
|
cnt[thread]->makemovie = 1;
|
|
}
|
|
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/action><– back</a><br><br>\n"
|
|
"makemovie for thread %u done<br>\n", thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "makemovie for thread %u\nDone\n", thread);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "snapshot")) {
|
|
pointer = pointer + 8;
|
|
length_uri = length_uri - 8;
|
|
if (length_uri == 0) {
|
|
/* call snapshot */
|
|
|
|
if (thread == 0) {
|
|
while (cnt[++i])
|
|
cnt[i]->snapshot = 1;
|
|
} else {
|
|
cnt[thread]->snapshot = 1;
|
|
}
|
|
|
|
cnt[thread]->snapshot = 1;
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/action><– back</a><br><br>\n"
|
|
"snapshot for thread %u done<br>\n", thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "snapshot for thread %u\nDone\n", thread);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "restart")) {
|
|
pointer = pointer + 7;
|
|
length_uri = length_uri - 7;
|
|
if (length_uri == 0) {
|
|
/* call restart */
|
|
|
|
if (thread == 0) {
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "httpd is going to restart");
|
|
kill(getpid(),SIGHUP);
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "restart in progress ... bye<br>\n<a href='/'>Home</a>");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "restart in progress ...\nDone\n");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
return 0; // to restart
|
|
} else {
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "httpd is going to restart thread %d",
|
|
thread);
|
|
if (cnt[thread]->running) {
|
|
cnt[thread]->makemovie = 1;
|
|
cnt[thread]->finish = 1;
|
|
}
|
|
cnt[thread]->restart = 1;
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/action><– back</a><br><br>\n"
|
|
"restart for thread %u done<br>\n", thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "restart for thread %u\nDone\n", thread);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "quit")) {
|
|
pointer = pointer + 4;
|
|
length_uri = length_uri - 4;
|
|
if (length_uri == 0) {
|
|
/* call quit */
|
|
|
|
if (thread == 0) {
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "httpd quits");
|
|
kill(getpid(),SIGQUIT);
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "quit in progress ... bye");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res,"quit in progress ... bye\nDone\n");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
return 0; // to quit
|
|
} else {
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "httpd quits thread %d",
|
|
thread);
|
|
cnt[thread]->restart = 0;
|
|
cnt[thread]->makemovie = 1;
|
|
cnt[thread]->finish = 1;
|
|
cnt[thread]->watchdog = WATCHDOG_OFF;
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/action><– back</a><br><br>\n"
|
|
"quit for thread %u done<br>\n", thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "quit for thread %u\nDone\n", thread);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* detection
|
|
* manages/parses the detection actions for motion ( status , start , pause ).
|
|
*
|
|
* Returns
|
|
* 1 to exit from function.
|
|
*/
|
|
|
|
static unsigned int detection(char *pointer, char *res, unsigned int length_uri,
|
|
unsigned int thread, int client_socket, void *userdata)
|
|
{
|
|
char command[256] = {'\0'};
|
|
struct context **cnt = userdata;
|
|
unsigned int i = 0;
|
|
|
|
warningkill = sscanf(pointer, "%255[a-z]" , command);
|
|
if (!strcmp(command, "status")) {
|
|
pointer = pointer + 6;
|
|
length_uri = length_uri - 6;
|
|
if (length_uri == 0) {
|
|
/* call status */
|
|
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/detection><– back</a><br><br><b>Camera %d%s%s</b>"
|
|
" Detection status %s\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
(!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
sprintf(res, "Camera %d Detection status %s\n", cnt[thread]->conf.camera_id,
|
|
(!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE");
|
|
send_template_ini_client_raw(client_socket);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "start")) {
|
|
pointer = pointer + 5;
|
|
length_uri = length_uri - 5;
|
|
if (length_uri == 0) {
|
|
/* call start */
|
|
|
|
if (thread == 0) {
|
|
do {
|
|
cnt[i]->pause = 0;
|
|
} while (cnt[++i]);
|
|
} else {
|
|
cnt[thread]->pause = 0;
|
|
}
|
|
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/detection><– back</a><br><br>\n<b>Camera %d%s%s</b>"
|
|
" Detection resumed\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d%s%s Detection resumed\nDone\n", cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "pause")) {
|
|
pointer = pointer + 5;
|
|
length_uri = length_uri - 5;
|
|
if (length_uri == 0) {
|
|
/* call pause */
|
|
|
|
if (thread == 0) {
|
|
do {
|
|
cnt[i]->pause = 1;
|
|
} while (cnt[++i]);
|
|
} else {
|
|
cnt[thread]->pause = 1;
|
|
}
|
|
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/detection><– back</a><br><br>\n<b>Camera %d%s%s</b>"
|
|
" Detection paused\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d%s%s Detection paused\nDone\n", cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "connection")) {
|
|
pointer = pointer + 10;
|
|
length_uri = length_uri - 10;
|
|
|
|
if (length_uri == 0) {
|
|
/* call connection */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/detection><– back</a><br><br>\n", thread);
|
|
send_template(client_socket, res);
|
|
if (thread == 0) {
|
|
do{
|
|
sprintf(res, "<b>Camera %d%s%s</b> %s<br>\n", cnt[i]->conf.camera_id,
|
|
cnt[i]->conf.camera_name ? " -- " : "",
|
|
cnt[i]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
(!cnt[i]->running)? "NOT RUNNING" :
|
|
(cnt[i]->lost_connection)?CONNECTION_KO:CONNECTION_OK);
|
|
send_template(client_socket, res);
|
|
} while (cnt[++i]);
|
|
} else {
|
|
sprintf(res, "<b>Camera %d%s%s</b> %s\n", cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
(!cnt[thread]->running)? "NOT RUNNING" :
|
|
(cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
|
|
send_template(client_socket, res);
|
|
}
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
if (thread == 0) {
|
|
do {
|
|
sprintf(res, "Camera %d %s\n", cnt[i]->conf.camera_id,
|
|
(!cnt[i]->running)? "NOT RUNNING" :
|
|
(cnt[i]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
|
|
send_template_raw(client_socket, res);
|
|
} while (cnt[++i]);
|
|
} else {
|
|
sprintf(res, "Camera %d %s\n", cnt[thread]->conf.camera_id,
|
|
(!cnt[thread]->running)? "NOT RUNNING" :
|
|
(cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
|
|
}
|
|
} else {
|
|
/* error */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* track
|
|
* manages/parses the track action for motion ( set , pan , tilt , auto ).
|
|
*
|
|
* Returns
|
|
* 1 to exit from function.
|
|
*/
|
|
static unsigned int track(char *pointer, char *res, unsigned int length_uri,
|
|
unsigned int thread, int client_socket, void *userdata)
|
|
{
|
|
char question='\0';
|
|
char command[256] = {'\0'};
|
|
struct context **cnt = userdata;
|
|
|
|
warningkill = sscanf(pointer, "%255[a-z]%c", command, &question);
|
|
if (!strcmp(command, "set")) {
|
|
pointer = pointer+3;
|
|
length_uri = length_uri-3;
|
|
/*
|
|
* FIXME need to check each value
|
|
* Relative movement set?pan=0&tilt=0 | set?pan=0 | set?tilt=0
|
|
* Absolute movement set?x=0&y=0 | set?x=0 | set?y=0
|
|
*/
|
|
|
|
if ((question == '?') && (length_uri > 2)) {
|
|
char panvalue[12] = {'\0'}, tiltvalue[12] = {'\0'};
|
|
char x_value[12] = {'\0'}, y_value[12] = {'\0'};
|
|
struct context *setcnt;
|
|
int pan = 0, tilt = 0, X = 0 , Y = 0;
|
|
|
|
pointer++;
|
|
length_uri--;
|
|
/*
|
|
* set?pan=value&tilt=value
|
|
* set?x=value&y=value
|
|
* pan= or x= | tilt= or y=
|
|
*/
|
|
|
|
warningkill = sscanf(pointer, "%255[a-z]%c" , command, &question);
|
|
|
|
if ((question != '=') || (command[0] == '\0')) {
|
|
/* no valid syntax */
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 1");
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
}
|
|
|
|
pointer++;
|
|
length_uri--;
|
|
|
|
/* Check first parameter */
|
|
|
|
if (!strcmp(command, "pan")) {
|
|
pointer = pointer + 3;
|
|
length_uri = length_uri - 3;
|
|
pan = 1;
|
|
if ((warningkill = sscanf(pointer, "%10[-0-9]", panvalue))) {
|
|
pointer = pointer + strlen(panvalue);
|
|
length_uri = length_uri - strlen(panvalue);
|
|
}
|
|
}
|
|
else if (!strcmp(command, "tilt")) {
|
|
pointer = pointer + 4;
|
|
length_uri = length_uri - 4;
|
|
tilt = 1;
|
|
if ((warningkill = sscanf(pointer, "%10[-0-9]", tiltvalue))) {
|
|
pointer = pointer + strlen(tiltvalue);
|
|
length_uri = length_uri - strlen(tiltvalue);
|
|
}
|
|
}
|
|
else if (!strcmp(command, "x")) {
|
|
pointer++;
|
|
length_uri--;
|
|
X = 1;
|
|
if ((warningkill = sscanf(pointer, "%10[-0-9]", x_value))) {
|
|
pointer = pointer + strlen(x_value);
|
|
length_uri = length_uri - strlen(x_value);
|
|
}
|
|
}
|
|
else if (!strcmp(command, "y")) {
|
|
pointer++;
|
|
length_uri--;
|
|
Y = 1;
|
|
if ((warningkill = sscanf(pointer, "%10[-0-9]" , y_value))) {
|
|
pointer = pointer + strlen(y_value);
|
|
length_uri = length_uri - strlen(y_value);
|
|
}
|
|
} else {
|
|
/* no valid syntax */
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 2");
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
}
|
|
|
|
/* first value check for error */
|
|
|
|
if (!warningkill) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 3");
|
|
/* error value */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, error_value, NULL);
|
|
else
|
|
response_client(client_socket, error_value_raw, NULL);
|
|
return 1;
|
|
}
|
|
|
|
/* Only one parameter (pan= ,tilt= ,x= ,y= ) */
|
|
if (length_uri == 0) {
|
|
if (pan) {
|
|
struct coord cent;
|
|
struct context *pancnt;
|
|
|
|
/* move pan */
|
|
|
|
pancnt = cnt[thread];
|
|
cent.width = pancnt->imgs.width;
|
|
cent.height = pancnt->imgs.height;
|
|
cent.y = 0;
|
|
cent.x = atoi(panvalue);
|
|
// Add the number of frame to skip for motion detection
|
|
cnt[thread]->moved = track_move(pancnt, pancnt->video_dev, ¢, &pancnt->imgs, 1);
|
|
if (cnt[thread]->moved) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"track set relative pan=%s<br>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
panvalue);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "track set relative pan=%s\nDone\n", panvalue);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error in track action */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
response_client(client_socket, track_error, res);
|
|
} else {
|
|
response_client(client_socket, track_error_raw, NULL);
|
|
}
|
|
}
|
|
} else if (tilt) {
|
|
struct coord cent;
|
|
struct context *tiltcnt;
|
|
|
|
/* move tilt */
|
|
|
|
tiltcnt = cnt[thread];
|
|
cent.width = tiltcnt->imgs.width;
|
|
cent.height = tiltcnt->imgs.height;
|
|
cent.x = 0;
|
|
cent.y = atoi(tiltvalue);
|
|
// Add the number of frame to skip for motion detection
|
|
cnt[thread]->moved = track_move(tiltcnt, tiltcnt->video_dev, ¢, &tiltcnt->imgs, 1);
|
|
if (cnt[thread]->moved) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"track set relative tilt=%s\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
tiltvalue);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "track set relative tilt=%s\nDone\n", tiltvalue);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error in track action */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
response_client(client_socket, track_error, res);
|
|
} else {
|
|
response_client(client_socket, track_error_raw, NULL);
|
|
}
|
|
}
|
|
} else if (X) {
|
|
/* X */
|
|
setcnt = cnt[thread];
|
|
// 1000 is out of range for pwc
|
|
cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, atoi(x_value), 1000);
|
|
if (cnt[thread]->moved) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"track set absolute x=%s\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
x_value);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "track set absolute x=%s\nDone\n", x_value);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error in track action */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
response_client(client_socket, track_error, res);
|
|
} else {
|
|
response_client(client_socket, track_error_raw, NULL);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
/* Y */
|
|
setcnt = cnt[thread];
|
|
// 1000 is out of range for pwc
|
|
cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, 1000, atoi(y_value));
|
|
if (cnt[thread]->moved) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"track set absolute y=%s<br>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
y_value);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "track set absolute y=%s\nDone\n", y_value);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error in track action */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
response_client(client_socket, track_error, res);
|
|
} else {
|
|
response_client(client_socket, track_error_raw, NULL);
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Check Second parameter */
|
|
|
|
warningkill = sscanf(pointer, "%c%255[a-z]" , &question, command);
|
|
if ((question != '&') || (command[0] == '\0')) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 4");
|
|
if (strstr(pointer, "&")) {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, error_value, NULL);
|
|
else
|
|
response_client(client_socket, error_value_raw, NULL);
|
|
|
|
/* no valid syntax */
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
pointer++;
|
|
length_uri--;
|
|
|
|
if (!strcmp(command, "pan")) {
|
|
pointer = pointer + 3;
|
|
length_uri = length_uri - 3;
|
|
if (pan || !tilt || X || Y) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 5");
|
|
/* no valid syntax */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
}
|
|
pan=2;
|
|
warningkill = sscanf(pointer, "%c%10[-0-9]" , &question, panvalue);
|
|
|
|
} else if (!strcmp(command, "tilt")) {
|
|
pointer = pointer + 4;
|
|
length_uri = length_uri - 4;
|
|
if (tilt || !pan || X || Y) {
|
|
/* no valid syntax */
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 6");
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
}
|
|
tilt = 2;
|
|
warningkill = sscanf(pointer, "%c%10[-0-9]" , &question, tiltvalue);
|
|
|
|
} else if (!strcmp(command, "x")) {
|
|
pointer++;
|
|
length_uri--;
|
|
if (X || !Y || pan || tilt) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 7");
|
|
|
|
/* no valid syntax */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
}
|
|
X = 2;
|
|
warningkill = sscanf(pointer, "%c%10[-0-9]" , &question, x_value);
|
|
|
|
} else if (!strcmp(command, "y")) {
|
|
pointer++;
|
|
length_uri--;
|
|
if (Y || !X || pan || tilt) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 8");
|
|
/* no valid syntax */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
}
|
|
Y = 2;
|
|
warningkill = sscanf(pointer, "%c%10[-0-9]" , &question, y_value);
|
|
|
|
} else {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 9");
|
|
/* no valid syntax */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
}
|
|
|
|
/* Second value check */
|
|
|
|
if ((warningkill < 2) && (question != '=')) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 10");
|
|
/* no valid syntax */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_valid_syntax, NULL);
|
|
else
|
|
response_client(client_socket, not_valid_syntax_raw, NULL);
|
|
return 1;
|
|
} else if ((question == '=') && (warningkill == 1)) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 11");
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, error_value, NULL);
|
|
else
|
|
response_client(client_socket, error_value_raw, NULL);
|
|
return 1;
|
|
}
|
|
|
|
|
|
if (pan == 2) {
|
|
pointer = pointer + strlen(panvalue) + 1;
|
|
length_uri = length_uri - strlen(panvalue) - 1;
|
|
} else if (tilt == 2) {
|
|
pointer = pointer + strlen(tiltvalue) + 1;
|
|
length_uri = length_uri - strlen(tiltvalue) - 1;
|
|
} else if (X == 2) {
|
|
pointer = pointer + strlen(x_value) + 1;
|
|
length_uri = length_uri - strlen(x_value) - 1;
|
|
} else {
|
|
pointer = pointer + strlen(y_value) + 1;
|
|
length_uri = length_uri - strlen(y_value) - 1;
|
|
}
|
|
|
|
|
|
if (length_uri != 0) {
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "httpd debug race 12");
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, error_value, NULL);
|
|
else
|
|
response_client(client_socket, error_value_raw, NULL);
|
|
return 1;
|
|
}
|
|
|
|
/* track set absolute ( x , y )*/
|
|
|
|
if (X && Y) {
|
|
setcnt = cnt[thread];
|
|
cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, atoi(x_value), atoi(y_value));
|
|
if (cnt[thread]->moved) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"track absolute set x=%s y=%s<br>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
x_value, y_value);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "track absolute set x=%s y=%s\nDone\n", x_value, y_value);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error in track action */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
response_client(client_socket, track_error, res);
|
|
} else {
|
|
response_client(client_socket, track_error_raw, NULL);
|
|
}
|
|
}
|
|
/* track set relative ( pan , tilt )*/
|
|
} else {
|
|
struct coord cent;
|
|
struct context *relativecnt;
|
|
|
|
/* move pan */
|
|
|
|
relativecnt = cnt[thread];
|
|
cent.width = relativecnt->imgs.width;
|
|
cent.height = relativecnt->imgs.height;
|
|
cent.y = 0;
|
|
cent.x = atoi(panvalue);
|
|
// Add the number of frame to skip for motion detection
|
|
cnt[thread]->moved = track_move(relativecnt, relativecnt->video_dev,
|
|
¢, &relativecnt->imgs, 1);
|
|
|
|
if (cnt[thread]->moved) {
|
|
/* move tilt */
|
|
relativecnt = cnt[thread];
|
|
cent.width = relativecnt->imgs.width;
|
|
cent.height = relativecnt->imgs.height;
|
|
cent.x = 0;
|
|
cent.y = atoi(tiltvalue);
|
|
// SLEEP(1,0);
|
|
cnt[thread]->moved = track_move(relativecnt, relativecnt->video_dev,
|
|
¢, &relativecnt->imgs, 1);
|
|
if (cnt[thread]->moved) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"track relative pan=%s tilt=%s\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
panvalue, tiltvalue);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "track relative pan=%s tilt=%s\nDone\n", panvalue, tiltvalue);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
return 1;
|
|
|
|
} else {
|
|
/* error in track tilt */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
response_client(client_socket, track_error, res);
|
|
} else {
|
|
response_client(client_socket, track_error_raw, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* error in track pan */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br><b>Camera %d%s%s</b>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
response_client(client_socket, track_error, res);
|
|
} else {
|
|
response_client(client_socket, track_error_raw, NULL);
|
|
}
|
|
}
|
|
} else if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>\n<b>Camera %d%s%s</b><br>\n"
|
|
"<form action='set'>\n"
|
|
"Pan<input type=text name='pan' value=''>\n"
|
|
"Tilt<input type=text name='tilt' value=''>\n"
|
|
"<input type=submit value='set relative'>\n"
|
|
"</form>\n"
|
|
"<form action='set'>\n"
|
|
"X<input type=text name='x' value=''>\n"
|
|
"Y<input type=text name='y' value=''>\n"
|
|
"<input type=submit value='set absolute'>\n"
|
|
"</form>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "set needs a pan/tilt or x/y values\n");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error not valid command */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "center")) {
|
|
pointer = pointer+6;
|
|
length_uri = length_uri-6;
|
|
if (length_uri==0) {
|
|
struct context *setcnt;
|
|
setcnt = cnt[thread];
|
|
// 1000 is out of range for pwc
|
|
cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, 0, 0);
|
|
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>\n<b>Camera %d%s%s</b>"
|
|
"<br>track set center", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
sprintf(res, "Camera %d\n track set center\nDone\n", cnt[thread]->conf.camera_id);
|
|
send_template_ini_client_raw(client_socket);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error not valid command */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "status")) {
|
|
pointer = pointer+6;
|
|
length_uri = length_uri-6;
|
|
if (length_uri==0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>\n<b>Camera %d%s%s</b>"
|
|
"<br>track auto %s", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
(cnt[thread]->track.active)? "enabled":"disabled");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
sprintf(res, "Camera %d\n track auto %s\nDone\n", cnt[thread]->conf.camera_id,
|
|
(cnt[thread]->track.active)? "enabled":"disabled");
|
|
send_template_ini_client_raw(client_socket);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
/* error not valid command */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command, "auto")) {
|
|
pointer = pointer + 4;
|
|
length_uri = length_uri - 4;
|
|
if ((question == '?') && (length_uri > 0)) {
|
|
char query[256] = {'\0'};
|
|
pointer++;
|
|
length_uri--;
|
|
/* value= */
|
|
|
|
warningkill = sscanf(pointer, "%255[a-z]%c", query, &question);
|
|
if ((question == '=') && (!strcmp(query, "value"))) {
|
|
pointer = pointer + 6;
|
|
length_uri = length_uri - 6;
|
|
warningkill = sscanf(pointer, "%255[-0-9a-z]" , command);
|
|
if (strlen(command) > 0) {
|
|
struct context *autocnt;
|
|
|
|
/* auto value=0|1|status */
|
|
|
|
if (!strcmp(command, "status")) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b><br>"
|
|
"track auto %s", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
(cnt[thread]->track.active)? "enabled":"disabled");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
sprintf(res, "Camera %d\n track auto %s\nDone\n", cnt[thread]->conf.camera_id,
|
|
(cnt[thread]->track.active)? "enabled":"disabled");
|
|
send_template_ini_client_raw(client_socket);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
int active;
|
|
active = atoi(command);
|
|
/* CHECK */
|
|
if (active > -1 && active < 2) {
|
|
autocnt = cnt[thread];
|
|
autocnt->track.active = active;
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>"
|
|
"<b>Camera %d%s%s</b>"
|
|
"<br>track auto %s<br>", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
active ? "enabled":"disabled");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "track auto %s\nDone\n", active ? "enabled":"disabled");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (length_uri == 0) {
|
|
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%u/track><– back</a><br><br>\n<b>Camera %d%s%s</b>\n"
|
|
"<form action='auto'><select name='value'>\n"
|
|
"<option value='0' %s>Disable</option><option value='1' %s>Enable</option>\n"
|
|
"<option value='status'>status</option>\n"
|
|
"</select><input type=submit value='set'>\n"
|
|
"</form>\n", thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
(cnt[thread]->track.active) ? "selected":"",
|
|
(cnt[thread]->track.active) ? "selected":"");
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "auto accepts only 0,1 or status as valid value\n");
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* handle_get
|
|
* parses the action requested for motion ( config , action , detection , track )
|
|
* and call to action function if needed.
|
|
*
|
|
* Returns
|
|
* 0 on action restart or quit
|
|
* 1 on success
|
|
*/
|
|
static unsigned int handle_get(int client_socket, const char *url, void *userdata, const char *httphostname)
|
|
{
|
|
struct context **cnt = userdata;
|
|
|
|
if (*url == '/') {
|
|
int i = 0;
|
|
int cams;
|
|
char *res=NULL;
|
|
res = mymalloc(2048);
|
|
|
|
/* get the number of threads */
|
|
while (cnt[++i]);
|
|
/* If not single threaded, assume main thread and seperate camera threads */
|
|
cams = i;
|
|
if (i > 1)
|
|
cams--;
|
|
|
|
/* ROOT_URI -> GET / */
|
|
if (!strcmp(url, "/")) {
|
|
int y;
|
|
int counter;
|
|
char hostname[1024];
|
|
|
|
//Send the webcontrol section if applicable
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<b>Motion "VERSION" Running [%d] Camera%s</b><br>\n"
|
|
"<a href='/0/'>All</a>\n", cams, (cams > 1 ? "s" : ""));
|
|
send_template(client_socket, res);
|
|
|
|
counter = 0;
|
|
for (y = 1; y < i; y++) {
|
|
counter++;
|
|
if (counter == 6){
|
|
sprintf(res, "<br>");
|
|
send_template(client_socket, res);
|
|
counter = 0;
|
|
}
|
|
sprintf(res, "<a href='/%d/'>Camera %d%s%s</a>\n", y, cnt[y]->conf.camera_id,
|
|
cnt[y]->conf.camera_name ? " -- " : "",
|
|
cnt[y]->conf.camera_name ? cnt[y]->conf.camera_name : "");
|
|
send_template(client_socket, res);
|
|
}
|
|
sprintf(res, "<br>");
|
|
send_template(client_socket, res);
|
|
|
|
if (!httphostname)
|
|
{
|
|
hostname[1023] = '\0';
|
|
gethostname(hostname, 1023);
|
|
httphostname = hostname;
|
|
}
|
|
|
|
/*
|
|
* Send the preview section
|
|
* Set y to 1 if multi-threaded and to 0 if single-threaded.
|
|
* This prevents showing a duplicate preview if 'stream_port'
|
|
* is configured in motion.conf when multi-threaded.
|
|
*/
|
|
for (y = (i > 1 ? 1 : 0); y < i; y++) {
|
|
if (cnt[y]->conf.stream_port) {
|
|
if (cnt[y]->conf.stream_preview_newline) {
|
|
sprintf(res, "<br>");
|
|
send_template(client_socket, res);
|
|
}
|
|
sprintf(res, "<a href=http://%s:%d> "
|
|
"<img src=http://%s:%d/ border=0 width=%d%%></a>\n"
|
|
,httphostname,cnt[y]->conf.stream_port
|
|
,httphostname,(cnt[y]->conf.substream_port)?cnt[y]->conf.substream_port:cnt[y]->conf.stream_port
|
|
,cnt[y]->conf.stream_preview_scale);
|
|
send_template(client_socket, res);
|
|
}
|
|
}
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Motion "VERSION" Running [%d] Camera%s\n0\n", cams, (cams > 1 ? "s" : ""));
|
|
send_template_raw(client_socket, res);
|
|
for (y = 1; y < i; y++) {
|
|
sprintf(res, "%d\n", y);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
}
|
|
} else {
|
|
char command[256] = {'\0'};
|
|
char slash;
|
|
int thread = -1;
|
|
size_t length_uri = 0;
|
|
char *pointer = (char *)url;
|
|
|
|
length_uri = strlen(url);
|
|
/* Check for Thread number first -> GET /2 */
|
|
pointer++;
|
|
length_uri--;
|
|
warningkill = sscanf(pointer, "%d%c", &thread, &slash);
|
|
|
|
if ((thread != -1) && (thread < i)) {
|
|
/* thread_number found */
|
|
if (thread > 9) {
|
|
pointer = pointer + 2;
|
|
length_uri = length_uri - 2;
|
|
} else {
|
|
pointer++;
|
|
length_uri--;
|
|
}
|
|
|
|
if (slash == '/') { /* slash found /2/ */
|
|
pointer++;
|
|
length_uri--;
|
|
}
|
|
|
|
if (length_uri != 0) {
|
|
warningkill = sscanf(pointer, "%255[a-z]%c" , command , &slash);
|
|
|
|
/* config */
|
|
if (!strcmp(command, "config")) {
|
|
pointer = pointer + 6;
|
|
length_uri = length_uri - 6;
|
|
if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%d/><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"<a href=/%d/config/list>list</a><br>\n"
|
|
"<a href=/%d/config/write>write</a><br>\n"
|
|
"<a href=/%d/config/set>set</a><br>\n"
|
|
"<a href=/%d/config/get>get</a><br>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
thread, thread, thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d\nlist\nwrite\nset\nget\n", cnt[thread]->conf.camera_id);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else if ((slash == '/') && (length_uri >= 4)) {
|
|
/* call config() */
|
|
pointer++;
|
|
length_uri--;
|
|
config(pointer, res, length_uri, thread, client_socket, cnt);
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
|
|
} else if (!strcmp(command, "action")) { /* action */
|
|
pointer = pointer + 6;
|
|
length_uri = length_uri - 6;
|
|
/* call action() */
|
|
if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%d/><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"<a href=/%d/action/makemovie>makemovie</a><br>\n"
|
|
"<a href=/%d/action/snapshot>snapshot</a><br>\n"
|
|
"<a href=/%d/action/restart>restart</a><br>\n"
|
|
"<a href=/%d/action/quit>quit</a><br>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
thread, thread, thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d\nmakemovie\nsnapshot\nrestart\nquit\n", cnt[thread]->conf.camera_id);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else if ((slash == '/') && (length_uri > 4)) {
|
|
unsigned int ret = 1;
|
|
pointer++;
|
|
length_uri--;
|
|
ret = action(pointer, res, length_uri, thread, client_socket, cnt);
|
|
free(res);
|
|
return ret;
|
|
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command,NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw,NULL);
|
|
}
|
|
} else if (!strcmp(command, "detection")) { /* detection */
|
|
pointer = pointer + 9;
|
|
length_uri = length_uri - 9;
|
|
if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%d/><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"<a href=/%d/detection/status>status</a><br>\n"
|
|
"<a href=/%d/detection/start>start</a><br>\n"
|
|
"<a href=/%d/detection/pause>pause</a><br>\n"
|
|
"<a href=/%d/detection/connection>connection</a><br>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
thread, thread, thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d\nstatus\nstart\npause\nconnection\n", cnt[thread]->conf.camera_id);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
} else if ((slash == '/') && (length_uri > 5)) {
|
|
pointer++;
|
|
length_uri--;
|
|
/* call detection() */
|
|
detection(pointer, res, length_uri, thread, client_socket, cnt);
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_valid_command, NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
} else if (!strcmp(command,"track")) { /* track */
|
|
pointer = pointer + 5;
|
|
length_uri = length_uri - 5;
|
|
if (length_uri == 0) {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/%d/><– back</a><br><br>\n"
|
|
"<b>Camera %d%s%s</b><br>\n"
|
|
"<a href=/%d/track/set>track set pan/tilt</a><br>\n"
|
|
"<a href=/%d/track/center>track center</a><br>\n"
|
|
"<a href=/%d/track/auto>track auto</a><br>\n"
|
|
"<a href=/%d/track/status>track status</a><br>\n",
|
|
thread, cnt[thread]->conf.camera_id,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
thread, thread, thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d\nset pan/tilt\ncenter\nauto\nstatus\n", cnt[thread]->conf.camera_id);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
|
|
} else if ((slash == '/') && (length_uri >= 4)) {
|
|
pointer++;
|
|
length_uri--;
|
|
/* call track() */
|
|
if (cnt[thread]->track.type) {
|
|
track(pointer, res, length_uri, thread, client_socket, cnt);
|
|
} else {
|
|
/* error track not enable */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%d/><– back</a>\n", thread);
|
|
response_client(client_socket, not_track, res);
|
|
} else {
|
|
response_client(client_socket, not_track_raw, NULL);
|
|
}
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%d/><– back</a>\n", thread);
|
|
response_client(client_socket, not_found_response_valid_command, res);
|
|
} else {
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/%d/><– back</a>\n", thread);
|
|
response_client(client_socket, not_found_response_valid_command, res);
|
|
} else {
|
|
response_client(client_socket, not_found_response_valid_command_raw, NULL);
|
|
}
|
|
}
|
|
} else {
|
|
/* /thread_number/ requested */
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
send_template_ini_client(client_socket, ini_template);
|
|
sprintf(res, "<a href=/><– back</a><br><br>\n<b>Camera %d -- Thread %d%s%s</b><br>\n"
|
|
"<a href='/%d/config'>config</a><br>\n"
|
|
"<a href='/%d/action'>action</a><br>\n"
|
|
"<a href='/%d/detection'>detection</a><br>\n"
|
|
"<a href='/%d/track'>track</a><br>\n",
|
|
cnt[thread]->conf.camera_id, thread,
|
|
cnt[thread]->conf.camera_name ? " -- " : "",
|
|
cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "",
|
|
thread, thread, thread, thread);
|
|
send_template(client_socket, res);
|
|
send_template_end_client(client_socket);
|
|
} else {
|
|
send_template_ini_client_raw(client_socket);
|
|
sprintf(res, "Camera %d\nconfig\naction\ndetection\ntrack\n", cnt[thread]->conf.camera_id);
|
|
send_template_raw(client_socket, res);
|
|
}
|
|
}
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output) {
|
|
sprintf(res, "<a href=/><– back</a>\n");
|
|
response_client(client_socket, not_found_response_valid, res);
|
|
} else {
|
|
response_client(client_socket, not_found_response_valid_raw, NULL);
|
|
}
|
|
}
|
|
}
|
|
free(res);
|
|
} else {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
response_client(client_socket, not_found_response_template,NULL);
|
|
else
|
|
response_client(client_socket, not_found_response_template_raw,NULL);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* read_client
|
|
* As usually web clients uses nonblocking connect/read
|
|
* read_client should handle nonblocking sockets.
|
|
*
|
|
* Returns
|
|
* 0 to quit or restart
|
|
* 1 on success
|
|
*/
|
|
static unsigned int read_client(int client_socket, void *userdata, char *auth)
|
|
{
|
|
unsigned int alive = 1;
|
|
unsigned int ret = 1;
|
|
char buffer[1024] = {'\0'};
|
|
ssize_t length = 1023;
|
|
struct context **cnt = userdata;
|
|
|
|
/* lock the mutex */
|
|
pthread_mutex_lock(&httpd_mutex);
|
|
|
|
while (alive) {
|
|
ssize_t nread = 0, readb = -1;
|
|
|
|
nread = read_nonblock(client_socket, buffer, length);
|
|
|
|
if (nread <= 0) {
|
|
MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "motion-httpd First Read Error");
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
} else {
|
|
char method[10]={'\0'};
|
|
char url[512]={'\0'};
|
|
char protocol[10]={'\0'};
|
|
char *authentication=NULL;
|
|
char *hostname=NULL;
|
|
|
|
buffer[nread] = '\0';
|
|
|
|
warningkill = sscanf(buffer, "%9s %511s %9s", method, url, protocol);
|
|
|
|
if (warningkill != 3) {
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
warningkill = write_nonblock(client_socket, bad_request_response,
|
|
sizeof (bad_request_response));
|
|
else
|
|
warningkill = write_nonblock(client_socket, bad_request_response_raw,
|
|
sizeof (bad_request_response_raw));
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
}
|
|
|
|
while ((strstr(buffer, "\r\n\r\n") == NULL) && (readb != 0) && (nread < length)) {
|
|
readb = read_nonblock(client_socket, buffer+nread, sizeof (buffer) - nread);
|
|
|
|
if (readb == -1) {
|
|
nread = -1;
|
|
break;
|
|
}
|
|
|
|
nread += readb;
|
|
|
|
if (nread > length) {
|
|
MOTION_LOG(WRN, TYPE_STREAM, SHOW_ERRNO, "motion-httpd End buffer"
|
|
" reached waiting for buffer ending");
|
|
break;
|
|
}
|
|
buffer[nread] = '\0';
|
|
}
|
|
|
|
/*
|
|
* Make sure the last read didn't fail. If it did, there's a
|
|
* problem with the connection, so give up.
|
|
*/
|
|
if (nread == -1) {
|
|
MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO, "motion-httpd READ give up!");
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
}
|
|
alive = 0;
|
|
|
|
/* Check Protocol */
|
|
if (strcmp(protocol, "HTTP/1.0") && strcmp (protocol, "HTTP/1.1")) {
|
|
/* We don't understand this protocol. Report a bad response. */
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
warningkill = write_nonblock(client_socket, bad_request_response,
|
|
sizeof (bad_request_response));
|
|
else
|
|
warningkill = write_nonblock(client_socket, bad_request_response_raw,
|
|
sizeof (bad_request_response_raw));
|
|
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp (method, "GET")) {
|
|
/*
|
|
* This server only implements the GET method. If client
|
|
* uses other method, report the failure.
|
|
*/
|
|
char response[1024];
|
|
if (cnt[0]->conf.webcontrol_html_output)
|
|
snprintf(response, sizeof (response), bad_method_response_template, method);
|
|
else
|
|
snprintf(response, sizeof (response), bad_method_response_template_raw, method);
|
|
warningkill = write_nonblock(client_socket, response, strlen(response));
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
}
|
|
|
|
if ((hostname = strstr(buffer,"Host:"))) {
|
|
/* use the hostname the browser used to connect to us when
|
|
* constructing links to the stream ports. If available
|
|
* (which it is in all modern browsers) it is more likely to
|
|
* work that the result of gethostname(), which is reliant on
|
|
* the machine we're running on having it's hostname setup
|
|
* correctly and corresponding DNS in place. */
|
|
hostname += strlen("Host:");
|
|
char *end_host = strstr(hostname,"\r\n");
|
|
if (end_host) {
|
|
while (hostname < end_host && isspace(hostname[0]))
|
|
hostname++;
|
|
while (hostname < end_host && isspace(end_host[-1]))
|
|
end_host--;
|
|
/* we have a string that is the hostname followed by
|
|
* optionally a colon and a port number - strip off any
|
|
* port number & colon */
|
|
char *colon = NULL;
|
|
if (hostname[0] == '[') {
|
|
// hostname is a IPv6 address like "[::1]"
|
|
char *end_bracket = memchr(hostname, ']', end_host-hostname);
|
|
// look for the colon after the "]"
|
|
colon = memchr(end_bracket, ':', end_host-end_bracket);
|
|
} else {
|
|
colon = memchr(hostname, ':', end_host-hostname);
|
|
}
|
|
if (colon)
|
|
end_host = colon;
|
|
hostname = strndup(hostname, end_host-hostname);
|
|
} else {
|
|
hostname = NULL;
|
|
}
|
|
}
|
|
|
|
if (auth != NULL) {
|
|
if ((authentication = strstr(buffer,"Basic"))) {
|
|
char *end_auth = NULL;
|
|
authentication = authentication + 6;
|
|
|
|
if ((end_auth = strstr(authentication,"\r\n"))) {
|
|
authentication[end_auth - authentication] = '\0';
|
|
} else {
|
|
char response[1024];
|
|
snprintf(response, sizeof (response), request_auth_response_template, method);
|
|
warningkill = write_nonblock(client_socket, response, strlen(response));
|
|
free(hostname);
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(auth, authentication)) {
|
|
char response[1024] = {'\0'};
|
|
snprintf(response, sizeof (response), request_auth_response_template, method);
|
|
warningkill = write_nonblock(client_socket, response, strlen(response));
|
|
char host[NI_MAXHOST] = "unknown";
|
|
get_host(host, client_socket);
|
|
MOTION_LOG(ALR, TYPE_STREAM, NO_ERRNO, "motion-httpd - failed auth attempt from %s", host);
|
|
free(hostname);
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
} else {
|
|
ret = handle_get(client_socket, url, cnt, hostname);
|
|
/* A valid auth request. Process it. */
|
|
}
|
|
} else {
|
|
// Request Authorization
|
|
char response[1024] = {'\0'};
|
|
snprintf(response, sizeof (response), request_auth_response_template, method);
|
|
warningkill = write_nonblock(client_socket, response, strlen(response));
|
|
free(hostname);
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
return 1;
|
|
}
|
|
} else {
|
|
ret = handle_get(client_socket, url, cnt, hostname);
|
|
/* A valid request. Process it. */
|
|
}
|
|
free(hostname);
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&httpd_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* acceptnonblocking
|
|
* waits timeout seconds for listen socket.
|
|
*
|
|
* Returns
|
|
* -1 if the timeout expires or on accept error.
|
|
* curfd (client socket) on accept success.
|
|
*/
|
|
static int acceptnonblocking(int serverfd, int timeout)
|
|
{
|
|
int curfd;
|
|
struct sockaddr_in6 client;
|
|
socklen_t client_len = sizeof(client);
|
|
|
|
struct timeval tm;
|
|
fd_set fds;
|
|
|
|
tm.tv_sec = timeout; /* Timeout in seconds */
|
|
tm.tv_usec = 0;
|
|
FD_ZERO(&fds);
|
|
FD_SET(serverfd, &fds);
|
|
|
|
if (select(serverfd + 1, &fds, NULL, NULL, &tm) > 0) {
|
|
if (FD_ISSET(serverfd, &fds)) {
|
|
if ((curfd = accept(serverfd, (struct sockaddr *)&client, &client_len)) > 0)
|
|
return curfd;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/**
|
|
* httpd_run
|
|
* Creates the listening socket and waits client requests.
|
|
*/
|
|
void httpd_run(struct context **cnt)
|
|
{
|
|
unsigned int client_sent_quit_message = 1, closehttpd = 0;
|
|
struct sigaction act;
|
|
char *authentication = NULL;
|
|
|
|
/* Initialize the mutex */
|
|
pthread_mutex_init(&httpd_mutex, NULL);
|
|
|
|
/* set signal handlers TO IGNORE */
|
|
memset(&act, 0, sizeof(act));
|
|
sigemptyset(&act.sa_mask);
|
|
act.sa_handler = SIG_IGN;
|
|
sigaction(SIGPIPE, &act, NULL);
|
|
sigaction(SIGCHLD, &act, NULL);
|
|
|
|
int sd = http_bindsock(cnt[0]->conf.webcontrol_port,
|
|
cnt[0]->conf.webcontrol_localhost, cnt[0]->conf.ipv6_enabled);
|
|
if (sd < 0) {
|
|
pthread_mutex_destroy(&httpd_mutex);
|
|
return;
|
|
}
|
|
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "Started motion-httpd server on port %d (auth %s)",
|
|
cnt[0]->conf.webcontrol_port, cnt[0]->conf.webcontrol_authentication ? "Enabled":"Disabled");
|
|
|
|
if (cnt[0]->conf.webcontrol_authentication != NULL) {
|
|
char *userpass = NULL;
|
|
size_t auth_size = strlen(cnt[0]->conf.webcontrol_authentication);
|
|
|
|
authentication = mymalloc(BASE64_LENGTH(auth_size) + 1);
|
|
userpass = mymalloc(auth_size + 4);
|
|
/* motion_base64_encode can read 3 bytes after the end of the string, initialize it */
|
|
memset(userpass, 0, auth_size + 4);
|
|
strcpy(userpass, cnt[0]->conf.webcontrol_authentication);
|
|
motion_base64_encode(userpass, authentication, auth_size);
|
|
free(userpass);
|
|
}
|
|
|
|
while ((client_sent_quit_message) && (!closehttpd)) {
|
|
|
|
int client_socket_fd = acceptnonblocking(sd, NONBLOCK_TIMEOUT);
|
|
|
|
if (client_socket_fd < 0) {
|
|
if ((!cnt[0]) || (cnt[0]->webcontrol_finish)) {
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "motion-httpd - Finishing");
|
|
closehttpd = 1;
|
|
}
|
|
} else {
|
|
/* Get the Client request */
|
|
client_sent_quit_message = read_client(client_socket_fd, cnt, authentication);
|
|
char host[NI_MAXHOST] = "unknown";
|
|
get_host(host, client_socket_fd);
|
|
MOTION_LOG(INF, TYPE_STREAM, NO_ERRNO, "motion-httpd - Read from client (%s)", host);
|
|
|
|
/* Close Connection */
|
|
if (client_socket_fd)
|
|
close(client_socket_fd);
|
|
}
|
|
|
|
}
|
|
|
|
free(authentication);
|
|
close(sd);
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "motion-httpd Closing");
|
|
pthread_mutex_destroy(&httpd_mutex);
|
|
}
|
|
|
|
/**
|
|
* motion_web_control
|
|
* Calls main function httpd_run
|
|
*/
|
|
void *motion_web_control(void *arg)
|
|
{
|
|
struct context **cnt = arg;
|
|
|
|
util_threadname_set("wc", 0,NULL);
|
|
|
|
httpd_run(cnt);
|
|
|
|
|
|
|
|
/*
|
|
* Update how many threads we have running. This is done within a
|
|
* mutex lock to prevent multiple simultaneous updates to
|
|
* 'threads_running'.
|
|
*/
|
|
pthread_mutex_lock(&global_lock);
|
|
threads_running--;
|
|
cnt[0]->webcontrol_running = 0;
|
|
pthread_mutex_unlock(&global_lock);
|
|
|
|
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "motion-httpd thread exit");
|
|
pthread_exit(NULL);
|
|
}
|