From bd1615e9f0dfbbc96f196e26adfd1b4af6a1cf2a Mon Sep 17 00:00:00 2001 From: Mr-Dave Date: Mon, 10 Oct 2022 19:09:09 -0600 Subject: [PATCH] Rewrite dbse module --- src/conf.cpp | 2 +- src/dbse.cpp | 2442 ++++++++++++++++++++++++------------------- src/dbse.hpp | 106 +- src/event.cpp | 97 +- src/logger.cpp | 2 +- src/motion_loop.cpp | 7 - src/motionplus.cpp | 16 +- src/motionplus.hpp | 7 +- src/movie.cpp | 217 ++-- src/movie.hpp | 4 +- src/webu_file.cpp | 14 +- src/webu_json.cpp | 13 +- 12 files changed, 1627 insertions(+), 1300 deletions(-) diff --git a/src/conf.cpp b/src/conf.cpp index 6dcbe10e..f1225be9 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -2619,7 +2619,7 @@ static void conf_edit_database_dbname(struct ctx_cam *cam, std::string &parm, en static void conf_edit_database_host(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) { if (pact == PARM_ACT_DFLT) { - cam->conf->database_host = "localhost"; + cam->conf->database_host = ""; } else if (pact == PARM_ACT_SET) { cam->conf->database_host = parm; } else if (pact == PARM_ACT_GET) { diff --git a/src/dbse.cpp b/src/dbse.cpp index e657ad59..7ae0c913 100644 --- a/src/dbse.cpp +++ b/src/dbse.cpp @@ -17,622 +17,1471 @@ * Copyright 2020-2022 MotionMrDave@gmail.com */ - #include "motionplus.hpp" #include "conf.hpp" #include "util.hpp" #include "logger.hpp" +#include "movie.hpp" #include "dbse.hpp" -static int dbse_global_edits(struct ctx_cam **cam_list) -{ +/* Forward Declares */ +void dbse_close(struct ctx_motapp *motapp); +static int dbse_edits(struct ctx_motapp *motapp) +{ int retcd = 0; - if (cam_list[0]->conf->database_dbname == "") { + if (motapp->dbse->database_dbname == "") { MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Invalid database name")); + , _("Invalid database name")); retcd = -1; } - if ((((cam_list[0]->conf->database_type == "mysql")) || - ((cam_list[0]->conf->database_type == "mariadb")) || - ((cam_list[0]->conf->database_type == "pgsql"))) && - (cam_list[0]->conf->database_port == 0)) { + if (((motapp->dbse->database_type == "mysql") || + (motapp->dbse->database_type == "mariadb") || + (motapp->dbse->database_type == "pgsql")) && + (motapp->dbse->database_port == 0)) { MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Must specify database port for mysql/mariadb/pgsql")); + ,_("Must specify database port for mysql/mariadb/pgsql")); + retcd = -1; + } + + if ((motapp->dbse->database_type == "sqlite3") && + (motapp->dbse->database_dbname == "")) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + ,_("Must specify database name for sqlite3")); retcd = -1; } if (retcd == -1) { MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Database functionality disabled.")); - cam_list[0]->conf->database_type = ""; + ,_("Database functionality disabled.")); + motapp->dbse->database_type = ""; } return retcd; } -void dbse_global_deinit(struct ctx_motapp *motapp) -{ - - int indx; - - #if defined(HAVE_MYSQL) - if (motapp->cam_list[0]->conf->database_type != "") { - if ((motapp->cam_list[0]->conf->database_type == "mysql")) { - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing MYSQL")); - mysql_library_end(); - } - } - #else - (void)motapp; - #endif /* HAVE_MYSQL */ - - #if defined(HAVE_MARIADB) - if (motapp->cam_list[0]->conf->database_type != "") { - if ((motapp->cam_list[0]->conf->database_type == "mariadb")) { - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing MYSQL")); - mysql_library_end(); - } - } - #else - (void)motapp; - #endif /* HAVE_MYSQL */ - - indx = 0; - while (motapp->cam_list[indx] != NULL) { - myfree(&motapp->cam_list[indx]->dbse); - indx++; - } - -} - -static void dbse_global_init_sqlite3(struct ctx_motapp *motapp) +/* Free the cols lists*/ +static void dbse_cols_free(struct ctx_motapp *motapp) { int indx; - motapp->cam_list[0]->dbse->database_sqlite3 = NULL; - - #ifdef HAVE_SQLITE3 - int retcd; - const char *errmsg; - - if ((motapp->cam_list[0]->conf->database_type == "sqlite3") && - (motapp->cam_list[0]->conf->database_dbname != "")) { - - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO,_("SQLite3 Database filename %s") - ,motapp->cam_list[0]->conf->database_dbname.c_str()); - pthread_mutex_lock(&motapp->mutex_sqlite); - retcd = sqlite3_open(motapp->cam_list[0]->conf->database_dbname.c_str() - , &motapp->cam_list[0]->dbse->database_sqlite3); - pthread_mutex_unlock(&motapp->mutex_sqlite); - if (retcd != SQLITE_OK) { - pthread_mutex_lock(&motapp->mutex_sqlite); - errmsg =sqlite3_errmsg(motapp->cam_list[0]->dbse->database_sqlite3); - pthread_mutex_unlock(&motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("Can't open database %s : %s") - , motapp->cam_list[0]->conf->database_dbname.c_str(),errmsg); - pthread_mutex_lock(&motapp->mutex_sqlite); - sqlite3_close(motapp->cam_list[0]->dbse->database_sqlite3); - pthread_mutex_unlock(&motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO,_("Could not initialize database %s") - ,motapp->cam_list[0]->conf->database_dbname.c_str()); - motapp->cam_list[0]->conf->database_type = ""; - motapp->cam_list[0]->dbse->database_sqlite3 = NULL; - } else { - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, _("database_busy_timeout %d msec") - , motapp->cam_list[0]->conf->database_busy_timeout); - pthread_mutex_lock(&motapp->mutex_sqlite); - retcd = sqlite3_busy_timeout( - motapp->cam_list[0]->dbse->database_sqlite3 - , motapp->cam_list[0]->conf->database_busy_timeout); - pthread_mutex_unlock(&motapp->mutex_sqlite); - if (retcd != SQLITE_OK) { - pthread_mutex_lock(&motapp->mutex_sqlite); - errmsg = sqlite3_errmsg( - motapp->cam_list[0]->dbse->database_sqlite3); - pthread_mutex_unlock(&motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("database_busy_timeout failed %s"), errmsg); - } - } - } - #endif /* HAVE_SQLITE3 */ - - /* Cascade to all cameras */ - indx = 1; - while (motapp->cam_list[indx] != NULL) { - if ((motapp->cam_list[indx]->conf->database_type == "sqlite3") && - (motapp->cam_list[indx]->conf->database_dbname == - motapp->cam_list[0]->conf->database_dbname)) { - motapp->cam_list[indx]->dbse->database_sqlite3 = - motapp->cam_list[0]->dbse->database_sqlite3; - } else { - motapp->cam_list[indx]->dbse->database_sqlite3 = NULL; - } - indx++; + if (motapp->dbse == NULL) { + return; } + if (motapp->dbse->cols_list != NULL) { + for (indx=0; indxdbse->cols_cnt; indx++) { + myfree(&motapp->dbse->cols_list[indx].col_nm); + myfree(&motapp->dbse->cols_list[indx].col_typ); + } + myfree(&motapp->dbse->cols_list); + } + motapp->dbse->cols_cnt = 0; + } -void dbse_global_init(struct ctx_motapp *motapp) +/* Create array of all the columns in current version */ +static void dbse_cols_list(struct ctx_motapp *motapp) { int indx; - indx = 0; - while (motapp->cam_list[indx] != NULL) { - if (motapp->cam_list[indx]->conf->database_type != "") { - motapp->cam_list[indx]->dbse = new ctx_dbse; - } - indx++; + dbse_cols_free(motapp); + + motapp->dbse->cols_cnt = 11; + + motapp->dbse->cols_list =(ctx_dbse_col *) + mymalloc(sizeof(ctx_dbse_col) * motapp->dbse->cols_cnt); + + /* The size of 30 is arbitrary */ + for (indx=0; indxdbse->cols_cnt; indx++) { + motapp->dbse->cols_list[indx].col_nm = (char*)mymalloc(30); + motapp->dbse->cols_list[indx].col_typ = (char*)mymalloc(30); + motapp->dbse->cols_list[indx].found = false; } - if (motapp->cam_list[0]->conf->database_type != "") { - if (dbse_global_edits(motapp->cam_list) == -1) { - return; + indx=0; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "camid"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "int"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "movie_nm"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "text"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "movie_dir"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "text"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "full_nm"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "text"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "movie_sz"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "int"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "movie_dtl"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "int"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "movie_tmc"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "text"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "diff_avg"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "int"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "sdev_min"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "int"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "sdev_max"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "int"); + + indx++; + snprintf(motapp->dbse->cols_list[indx].col_nm, 30, "%s", "sdev_avg"); + snprintf(motapp->dbse->cols_list[indx].col_typ, 30, "%s", "int"); + +} + +/* Free the movies lists*/ +static void dbse_movies_free(struct ctx_motapp *motapp) +{ + int indx; + + if (motapp->dbse->movie_list != NULL) { + for (indx=0; indxdbse->movie_cnt; indx++) { + myfree(&motapp->dbse->movie_list[indx].movie_nm); + myfree(&motapp->dbse->movie_list[indx].movie_dir); + myfree(&motapp->dbse->movie_list[indx].full_nm); + myfree(&motapp->dbse->movie_list[indx].movie_tmc); } - - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("Initializing database")); - /* Initialize all the database items */ - #if defined(HAVE_MYSQL) - if ((motapp->cam_list[0]->conf->database_type == "mysql")) { - if (mysql_library_init(0, NULL, NULL)) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Could not initialize database %s") - ,motapp->cam_list[0]->conf->database_type.c_str()); - motapp->cam_list[0]->conf->database_type = ""; - return; - } - } - #endif /* HAVE_MYSQL */ - - #if defined(HAVE_MARIADB) - if ((motapp->cam_list[0]->conf->database_type == "mariadb")) { - if (mysql_library_init(0, NULL, NULL)) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Could not initialize database %s") - ,motapp->cam_list[0]->conf->database_type.c_str()); - motapp->cam_list[0]->conf->database_type = ""; - return; - } - } - #endif /* HAVE_MARIADB */ - - dbse_global_init_sqlite3(motapp); - + myfree(&motapp->dbse->movie_list); } + motapp->dbse->movie_cnt = 0; + } -static void dbse_init_mysql(struct ctx_cam *cam) +static void dbse_rec_default(ctx_dbse_rec *rec) { + rec->found = false; + rec->recordid = -1; + rec->camid = -1; - #if defined(HAVE_MYSQL) - // close database to be sure that we are not leaking - mysql_close(cam->dbse->database_mysql); - cam->dbse->database_event_id = 0; + rec->movie_nm = (char*)mymalloc(5); + snprintf(rec->movie_nm, 5,"%s", "null"); - cam->dbse->database_mysql = (MYSQL *) mymalloc(sizeof(MYSQL)); - mysql_init(cam->dbse->database_mysql); + rec->movie_dir = (char*)mymalloc(5); + snprintf(rec->movie_dir, 5,"%s", "null"); - if (!mysql_real_connect(cam->dbse->database_mysql - , cam->conf->database_host.c_str(), cam->conf->database_user.c_str() - , cam->conf->database_password.c_str(), cam->conf->database_dbname.c_str() - , cam->conf->database_port, NULL, 0)) { + rec->full_nm = (char*)mymalloc(5); + snprintf(rec->full_nm, 5,"%s", "null"); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Cannot connect to MySQL database %s on host %s with user %s") - ,cam->conf->database_dbname.c_str(), cam->conf->database_host.c_str() - ,cam->conf->database_user.c_str()); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("MySQL error was %s"), mysql_error(cam->dbse->database_mysql)); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Disabling database functionality")); - dbse_global_deinit(cam->motapp); - cam->conf->database_type = ""; - return; + rec->movie_sz = 0; + rec->movie_dtl = 0; + + rec->movie_tmc = (char*)mymalloc(5); + snprintf(rec->movie_tmc, 5,"%s", "null"); + + rec->diff_avg = 0; + rec->sdev_min = 0; + rec->sdev_max = 0; + rec->sdev_avg = 0; + +} + +#ifdef HAVE_SQLITE3 + +static void dbse_sqlite3_exec(struct ctx_motapp *motapp, const char *sqlquery) +{ + int retcd; + char *errmsg = NULL; + + if(motapp->dbse->database_sqlite3 == NULL) { + return; + }; + + MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing query"); + retcd = sqlite3_exec( + motapp->dbse->database_sqlite3 + , sqlquery, NULL, 0, &errmsg); + if (retcd != SQLITE_OK ) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("SQLite error was %s"), errmsg); + sqlite3_free(errmsg); + } + MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Finished query"); +} + +/* Process query list of columns in motionplus table*/ +static int dbse_sqlite3_cb ( + void *ptr, int arg_nb, char **arg_val, char **col_nm) +{ + ctx_motapp *motapp = (ctx_motapp *)ptr; + int indx, indx2; + int rnbr, flen; + struct stat statbuf; + ctx_dbse_rec *rec; + + if (motapp->dbse->dbse_action == DBSE_ACT_CHKTBL) { + for (indx=0; indx < arg_nb; indx++) { + if (mystrceq(arg_val[indx],"motionplus")) { + motapp->dbse->table_ok = true; + } } - #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012) - bool my_true = true; - mysql_options(cam->dbse->database_mysql, MYSQL_OPT_RECONNECT, &my_true); - #endif - #else - (void)cam; /* Avoid compiler warnings */ - #endif /* HAVE_MYSQL */ - - return; - -} - -static void dbse_init_mariadb(struct ctx_cam *cam) -{ - - #if defined(HAVE_MARIADB) - // close database to be sure that we are not leaking - mysql_close(cam->dbse->database_mariadb); - cam->dbse->database_event_id = 0; - - cam->dbse->database_mariadb = (MYSQL *) mymalloc(sizeof(MYSQL)); - mysql_init(cam->dbse->database_mariadb); - - if (!mysql_real_connect(cam->dbse->database_mariadb - , cam->conf->database_host.c_str(), cam->conf->database_user.c_str() - , cam->conf->database_password.c_str(), cam->conf->database_dbname.c_str() - , cam->conf->database_port, NULL, 0)) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Cannot connect to MySQL database %s on host %s with user %s") - ,cam->conf->database_dbname.c_str(), cam->conf->database_host.c_str() - ,cam->conf->database_user.c_str()); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("MySQL error was %s"), mysql_error(cam->dbse->database_mariadb)); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Disabling database functionality")); - dbse_global_deinit(cam->motapp); - cam->conf->database_type = ""; - return; + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETCNT) { + for (indx=0; indx < arg_nb; indx++) { + if (mystrceq(col_nm[indx],"movie_cnt")) { + motapp->dbse->movie_cnt =atoi(arg_val[indx]); + } } - #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012) - bool my_true = true; - mysql_options(cam->dbse->database_mariadb, MYSQL_OPT_RECONNECT, &my_true); - #endif - #else - (void)cam; /* Avoid compiler warnings */ - #endif /* HAVE_MARIADB */ - - return; - -} - -static void dbse_init_sqlite3(struct ctx_cam *cam) -{ - #ifdef HAVE_SQLITE3 - int retcd; - const char *errmsg; - - /*User specified a different database for the camera*/ - if ((cam->conf->database_type == "sqlite3") && - (cam->conf->database_dbname != "") && - (cam->dbse->database_sqlite3 == NULL)) { - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, _("SQLite3 Database filename %s") - ,cam->conf->database_dbname.c_str()); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_open(cam->conf->database_dbname.c_str() - , &cam->dbse->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK) { - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - errmsg =sqlite3_errmsg(cam->dbse->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("Can't open database %s : %s") - , cam->conf->database_dbname.c_str(), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_close(cam->dbse->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO,_("Could not initialize database %s") - ,cam->conf->database_dbname.c_str()); - cam->conf->database_type = ""; - cam->dbse->database_sqlite3 = NULL; - } else { - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, _("database_busy_timeout %d msec") - , cam->conf->database_busy_timeout); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_busy_timeout(cam->dbse->database_sqlite3 - , cam->conf->database_busy_timeout); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK) { - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - errmsg = sqlite3_errmsg(cam->dbse->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("database_busy_timeout failed %s"), errmsg); + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETCOLS) { + for (indx=0; indx < arg_nb; indx++) { + if (mystrceq(col_nm[indx],"col_nm")) { + for (indx2=0; indx2 < motapp->dbse->cols_cnt; indx2++) { + if (mystrceq(arg_val[indx] + , motapp->dbse->cols_list[indx2].col_nm)) { + motapp->dbse->cols_list[indx2].found = true; + } } } } - #else - (void)cam; - #endif /* HAVE_SQLITE3 */ + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETTBL) { + rnbr = motapp->dbse->rec_indx; + if (rnbr < motapp->dbse->movie_cnt) { + rec = &motapp->dbse->movie_list[rnbr]; + dbse_rec_default(rec); - return; + for (indx=0; indx < arg_nb; indx++) { + if (arg_val[indx] != NULL) { + if (arg_val[indx] != NULL) { + if (mystrceq(col_nm[indx],"recordid")) { + rec->recordid = atoi(arg_val[indx]); -} + } else if (mystrceq(col_nm[indx],"camid")) { + rec->camid = atoi(arg_val[indx]); -static void dbse_init_pgsql(struct ctx_cam *cam) -{ - #ifdef HAVE_PGSQL - char connstring[255]; - /* Create the connection string. - * Quote the values so we can have null values (blank) - */ - snprintf(connstring, 255, - "dbname='%s' host='%s' user='%s' password='%s' port='%d'", - cam->conf->database_dbname.c_str(), /* dbname */ - (cam->conf->database_host=="" ? cam->conf->database_host.c_str() : ""), /* host (may be blank) */ - (cam->conf->database_user=="" ? cam->conf->database_user.c_str() : ""), /* user (may be blank) */ - (cam->conf->database_password=="" ? cam->conf->database_password.c_str() : ""), /* password (may be blank) */ - cam->conf->database_port - ); + } else if (mystrceq(col_nm[indx],"movie_nm")) { + free(rec->movie_nm); + flen = strlen(arg_val[indx]); + rec->movie_nm = (char*)mymalloc(flen + 1); + snprintf(rec->movie_nm, flen+1,"%s",arg_val[indx]); - cam->dbse->database_pg = PQconnectdb(connstring); - if (PQstatus(cam->dbse->database_pg) == CONNECTION_BAD) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Connection to PostgreSQL database '%s' failed: %s") - ,cam->conf->database_dbname.c_str(), PQerrorMessage(cam->dbse->database_pg)); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Disabling database functionality")); - cam->conf->database_type = ""; - return; + } else if (mystrceq(col_nm[indx],"movie_dir")) { + free(rec->movie_dir); + flen = strlen(arg_val[indx]); + rec->movie_dir = (char*)mymalloc(flen + 1); + snprintf(rec->movie_dir, flen+1,"%s",arg_val[indx]); + + } else if (mystrceq(col_nm[indx],"full_nm")) { + free(rec->full_nm); + flen = strlen(arg_val[indx]); + rec->full_nm = (char*)mymalloc(flen + 1); + snprintf(rec->full_nm, flen+1,"%s",arg_val[indx]); + if (stat(rec->full_nm, &statbuf) == 0) { + rec->found = true; + } + + } else if (mystrceq(col_nm[indx],"movie_sz")) { + rec->movie_sz =atoi(arg_val[indx]); + + } else if (mystrceq(col_nm[indx],"movie_dtl")) { + rec->movie_dtl =atoi(arg_val[indx]); + + } else if (mystrceq(col_nm[indx],"movie_tmc")) { + free(rec->movie_tmc); + flen = strlen(arg_val[indx]); + rec->movie_tmc = + (char*)mymalloc(flen + 1); + snprintf(rec->movie_tmc + ,flen+1,"%s",arg_val[indx]); + + } else if (mystrceq(col_nm[indx],"diff_avg")) { + rec->diff_avg =atoi(arg_val[indx]); + } else if (mystrceq(col_nm[indx],"sdev_min")) { + rec->sdev_min =atoi(arg_val[indx]); + } else if (mystrceq(col_nm[indx],"sdev_max")) { + rec->sdev_max =atoi(arg_val[indx]); + } else if (mystrceq(col_nm[indx],"sdev_avg")) { + rec->sdev_avg =atoi(arg_val[indx]); + } + } + } + } } - #else - (void)cam; /* Avoid compiler warnings */ - #endif /* HAVE_PGSQL */ + motapp->dbse->rec_indx++; + } - return; + return 0; } -void dbse_init(struct ctx_cam *cam) +static void dbse_sqlite3_cols(struct ctx_motapp *motapp) { + int retcd, indx; + char *errmsg = 0; + std::string sqlquery; - if (cam->conf->database_type != "") { + dbse_cols_list(motapp); + + sqlquery = + " select name as col_nm " + " from pragma_table_info('motionplus');"; + motapp->dbse->dbse_action = DBSE_ACT_GETCOLS; + retcd = sqlite3_exec(motapp->dbse->database_sqlite3 + , sqlquery.c_str(), dbse_sqlite3_cb, motapp, &errmsg); + if (retcd != SQLITE_OK ) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Error retrieving table columns: %s"), errmsg); + sqlite3_free(errmsg); + return; + } + + for (indx=0; indxdbse->cols_cnt; indx++) { + if (motapp->dbse->cols_list[indx].found == false) { + sqlquery = "Alter table motionplus add column "; + sqlquery += std::string(motapp->dbse->cols_list[indx].col_nm) + " "; + sqlquery += std::string(motapp->dbse->cols_list[indx].col_typ) + " ;"; + dbse_sqlite3_exec(motapp, sqlquery.c_str()); + } + } + + dbse_cols_free(motapp); + +} + +static void dbse_sqlite3_init(struct ctx_motapp *motapp) +{ + int retcd; + const char *err_open = NULL; + char *err_qry = NULL; + std::string sqlquery; + + motapp->dbse->database_sqlite3 = NULL; + + if (motapp->dbse->database_type != "sqlite3") { + return; + } + + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO + , _("SQLite3 Database filename %s") + , motapp->dbse->database_dbname.c_str()); + retcd = sqlite3_open( + motapp->dbse->database_dbname.c_str() + , &motapp->dbse->database_sqlite3); + if (retcd != SQLITE_OK) { + err_open =sqlite3_errmsg(motapp->dbse->database_sqlite3); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Can't open database %s : %s") + , motapp->dbse->database_dbname.c_str() + , err_open); + sqlite3_close(motapp->dbse->database_sqlite3); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Could not initialize database %s") + , motapp->dbse->database_dbname.c_str()); + motapp->dbse->database_type = ""; + motapp->dbse->database_sqlite3 = NULL; + } else { MOTION_LOG(NTC, TYPE_DB, NO_ERRNO - ,_("Database backend %s"), cam->conf->database_type.c_str()); - if (cam->conf->database_type == "mysql") { - dbse_init_mysql(cam); - } else if (cam->conf->database_type == "mariadb") { - dbse_init_mariadb(cam); - } else if (cam->conf->database_type == "postgresql") { - dbse_init_pgsql(cam); - } else if (cam->conf->database_type == "sqlite3") { - dbse_init_sqlite3(cam); - } else { - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO - ,_("Invalid Database backend %s") - , cam->conf->database_type.c_str()); - } - } - - return; -} - -void dbse_deinit(struct ctx_cam *cam) -{ - if (cam->conf->database_type != "") { - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing database")); - - #if defined(HAVE_MYSQL) - if (cam->conf->database_type == "mysql") { - mysql_close(cam->dbse->database_mysql); - cam->dbse->database_event_id = 0; - } - #endif /* HAVE_MYSQL */ - - #if defined(HAVE_MARIADB) - if (cam->conf->database_type == "mariadb") { - mysql_close(cam->dbse->database_mariadb); - cam->dbse->database_event_id = 0; - } - #endif /* HAVE_MYSQL */ - - #ifdef HAVE_PGSQL - if (cam->conf->database_type == "postgresql") { - PQfinish(cam->dbse->database_pg); - } - #endif /* HAVE_PGSQL */ - - #ifdef HAVE_SQLITE3 - /* Close the SQLite database */ - if ((cam->conf->database_type == "sqlite3") && - (cam->dbse->database_sqlite3 != NULL)) { - sqlite3_close(cam->dbse->database_sqlite3); - cam->dbse->database_sqlite3 = NULL; - } - #endif /* HAVE_SQLITE3 */ - } - -} - -static void dbse_mysql_exec(char *sqlquery,struct ctx_cam *cam, int save_id) -{ - - #if defined(HAVE_MYSQL) - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing mysql query"); - if (mysql_query(cam->dbse->database_mysql, sqlquery) != 0) { - int error_code = mysql_errno(cam->dbse->database_mysql); - - MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO - ,_("Mysql query failed %s error code %d") - ,mysql_error(cam->dbse->database_mysql), error_code); - /* Try to reconnect ONCE if fails continue and discard this sql query */ - if (error_code >= 2000) { - // Close connection before start a new connection - mysql_close(cam->dbse->database_mysql); - - cam->dbse->database_mysql = (MYSQL *) mymalloc(sizeof(MYSQL)); - mysql_init(cam->dbse->database_mysql); - - if (!mysql_real_connect(cam->dbse->database_mysql, cam->conf->database_host.c_str(), - cam->conf->database_user.c_str(), cam->conf->database_password.c_str(), - cam->conf->database_dbname.c_str(), cam->conf->database_port, NULL, 0)) { - MOTION_LOG(ALR, TYPE_DB, NO_ERRNO - ,_("Cannot reconnect to MySQL" - " database %s on host %s with user %s MySQL error was %s"), - cam->conf->database_dbname.c_str(), - cam->conf->database_host.c_str(), cam->conf->database_user.c_str(), - mysql_error(cam->dbse->database_mysql)); - } else { - MOTION_LOG(INF, TYPE_DB, NO_ERRNO - ,_("Re-Connection to Mysql database '%s' Succeed") - ,cam->conf->database_dbname.c_str()); - if (mysql_query(cam->dbse->database_mysql, sqlquery) != 0) { - int error_my = mysql_errno(cam->dbse->database_mysql); - MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO - ,_("after re-connection Mysql query failed %s error code %d") - ,mysql_error(cam->dbse->database_mysql), error_my); - } - } - } - } - if (save_id) { - cam->dbse->database_event_id = (uint64_t) mysql_insert_id(cam->dbse->database_mysql); - } - #else - (void)sqlquery; - (void)cam; - (void)save_id; - #endif /* HAVE_MYSQL HAVE_MARIADB*/ - -} - -static void dbse_mariadb_exec(char *sqlquery,struct ctx_cam *cam, int save_id) -{ - - #if defined(HAVE_MARIADB) - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing mysql query"); - if (mysql_query(cam->dbse->database_mariadb, sqlquery) != 0) { - int error_code = mysql_errno(cam->dbse->database_mariadb); - - MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO - ,_("Mysql query failed %s error code %d") - ,mysql_error(cam->dbse->database_mariadb), error_code); - /* Try to reconnect ONCE if fails continue and discard this sql query */ - if (error_code >= 2000) { - // Close connection before start a new connection - mysql_close(cam->dbse->database_mariadb); - - cam->dbse->database_mariadb = (MYSQL *) mymalloc(sizeof(MYSQL)); - mysql_init(cam->dbse->database_mariadb); - - if (!mysql_real_connect(cam->dbse->database_mariadb, cam->conf->database_host.c_str(), - cam->conf->database_user.c_str(), cam->conf->database_password.c_str(), - cam->conf->database_dbname.c_str(),cam->conf->database_port, NULL, 0)) { - MOTION_LOG(ALR, TYPE_DB, NO_ERRNO - ,_("Cannot reconnect to MySQL" - " database %s on host %s with user %s MySQL error was %s"), - cam->conf->database_dbname.c_str(), - cam->conf->database_host.c_str(), cam->conf->database_user.c_str(), - mysql_error(cam->dbse->database_mariadb)); - } else { - MOTION_LOG(INF, TYPE_DB, NO_ERRNO - ,_("Re-Connection to Mysql database '%s' Succeed") - ,cam->conf->database_dbname.c_str()); - if (mysql_query(cam->dbse->database_mariadb, sqlquery) != 0) { - int error_my = mysql_errno(cam->dbse->database_mariadb); - MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO - ,_("after re-connection Mysql query failed %s error code %d") - ,mysql_error(cam->dbse->database_mariadb), error_my); - } - } - } - } - if (save_id) { - cam->dbse->database_event_id = (uint64_t) mysql_insert_id(cam->dbse->database_mariadb); - } - #else - (void)sqlquery; - (void)cam; - (void)save_id; - #endif /* HAVE_MARIADB*/ - -} - -static void dbse_pgsql_exec(char *sqlquery,struct ctx_cam *cam, int save_id) -{ - #ifdef HAVE_PGSQL - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing postgresql query"); - PGresult *res; - - res = PQexec(cam->dbse->database_pg, sqlquery); - - if (PQstatus(cam->dbse->database_pg) == CONNECTION_BAD) { - + , _("database_busy_timeout %d msec") + , motapp->dbse->database_busy_timeout); + retcd = sqlite3_busy_timeout( + motapp->dbse->database_sqlite3 + , motapp->dbse->database_busy_timeout); + if (retcd != SQLITE_OK) { + err_open = sqlite3_errmsg( + motapp->dbse->database_sqlite3); MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Connection to PostgreSQL database '%s' failed: %s") - ,cam->conf->database_dbname.c_str(), PQerrorMessage(cam->dbse->database_pg)); + , _("database_busy_timeout failed %s"), err_open); + } + } - // This function will close the connection to the server and attempt to reestablish a new connection to the same server, - // using all the same parameters previously used. This may be useful for error recovery if a working connection is lost - PQreset(cam->dbse->database_pg); + sqlquery = + "select name from sqlite_master" + " where type='table' " + " and name='motionplus';"; + motapp->dbse->table_ok = false; + motapp->dbse->dbse_action = DBSE_ACT_CHKTBL; + retcd = sqlite3_exec( + motapp->dbse->database_sqlite3 + , sqlquery.c_str(), dbse_sqlite3_cb, motapp, &err_qry); + if (retcd != SQLITE_OK ) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Error checking table: %s"), err_qry); + sqlite3_free(err_qry); + return; + } - if (PQstatus(cam->dbse->database_pg) == CONNECTION_BAD) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Re-Connection to PostgreSQL database '%s' failed: %s") - ,cam->conf->database_dbname.c_str(), PQerrorMessage(cam->dbse->database_pg)); + if (motapp->dbse->table_ok == false) { + /* Autoincrement is discouraged but I want compatibility across + * all the various DBS used in motionplus + */ + sqlquery = + "create table motionplus (" + " recordid integer primary key autoincrement " + ");"; + retcd = sqlite3_exec(motapp->dbse->database_sqlite3 + , sqlquery.c_str(), 0, 0, &err_qry); + if (retcd != SQLITE_OK ) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Error creating table: %s"), err_qry); + sqlite3_free(err_qry); + return; + } + } + + dbse_sqlite3_cols(motapp); + +} + +static void dbse_sqlite3_movlst(struct ctx_motapp *motapp) +{ + int retcd, indx; + char *errmsg = NULL; + std::string sqlquery, delimit; + + sqlquery = + "select count(*) as movie_cnt " + " from motionplus ;"; + motapp->dbse->dbse_action = DBSE_ACT_GETCNT; + + retcd = sqlite3_exec( + motapp->dbse->database_sqlite3 + , sqlquery.c_str(), dbse_sqlite3_cb, motapp, &errmsg); + if (retcd != SQLITE_OK ) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Error counting table: %s"), errmsg); + sqlite3_free(errmsg); + return; + } + + if (motapp->dbse->movie_cnt > 0) { + motapp->dbse->movie_list =(ctx_dbse_rec *) + mymalloc(sizeof(ctx_dbse_rec)*motapp->dbse->movie_cnt); + motapp->dbse->rec_indx = 0; + + sqlquery =" select * from motionplus ;"; + motapp->dbse->dbse_action = DBSE_ACT_GETTBL; + + retcd = sqlite3_exec( + motapp->dbse->database_sqlite3 + , sqlquery.c_str(), dbse_sqlite3_cb, motapp, &errmsg); + if (retcd != SQLITE_OK ) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Error retrieving table: %s"), errmsg); + sqlite3_free(errmsg); + return; + } + + sqlquery = + " delete from motionplus " + " where recordid in ("; + delimit = " "; + for (indx=0; indxdbse->movie_cnt; indx++) { + if (motapp->dbse->movie_list[indx].found == false) { + sqlquery += delimit + std::to_string( + motapp->dbse->movie_list[indx].recordid); + delimit = ","; + } + /* 5000 is arbitrary */ + if (sqlquery.length() > 5000) { + indx = motapp->dbse->movie_cnt; + } + } + sqlquery += ");"; + if (delimit == ",") { + dbse_sqlite3_exec(motapp, sqlquery.c_str()); + } + + sqlquery ="vacuum"; + dbse_sqlite3_exec(motapp, sqlquery.c_str()); + } + return; + +} + +static void dbse_sqlite3_close(struct ctx_motapp *motapp) +{ + if ((motapp->dbse->database_type == "sqlite3") && + (motapp->dbse->database_sqlite3 != NULL)) { + sqlite3_close(motapp->dbse->database_sqlite3); + motapp->dbse->database_sqlite3 = NULL; + } +} + +#endif /*HAVE_SQLITE3*/ + +#ifdef HAVE_MARIADB + +static void dbse_mariadb_exec (struct ctx_motapp *motapp, const char *sqlquery) +{ + int retcd; + + if (motapp->dbse->database_mariadb == NULL) { + return; + } + + MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing MariaDB query"); + retcd = mysql_query(motapp->dbse->database_mariadb, sqlquery); + if (retcd != 0) { + retcd = mysql_errno(motapp->dbse->database_mariadb); + MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO + , _("MariaDB query '%s' failed. %s error code %d") + , sqlquery, mysql_error(motapp->dbse->database_mariadb) + , retcd); + /* Try to reconnect ONCE if fails continue and discard this sql query */ + if (retcd >= 2000) { + mysql_close(motapp->dbse->database_mariadb); + motapp->dbse->database_mariadb = (MYSQL *) mymalloc(sizeof(MYSQL)); + mysql_init(motapp->dbse->database_mariadb); + + if (mysql_real_connect( + motapp->dbse->database_mariadb + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str() + , motapp->dbse->database_password.c_str() + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_port, NULL, 0) == NULL) { + MOTION_LOG(ALR, TYPE_DB, NO_ERRNO + , _("Cannot reconnect to MariaDB database %s" + " on host %s with user %s MariaDB error was %s") + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str() + , mysql_error(motapp->dbse->database_mariadb)); } else { MOTION_LOG(INF, TYPE_DB, NO_ERRNO - ,_("Re-Connection to PostgreSQL database '%s' Succeed") - ,cam->conf->database_dbname.c_str()); + , _("Re-Connection to MariaDB database '%s' Succeed") + , motapp->dbse->database_dbname.c_str()); + retcd = mysql_query(motapp->dbse->database_mariadb, sqlquery); + if (retcd != 0) { + retcd = mysql_errno(motapp->dbse->database_mariadb); + MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO + , _("after re-connection MariaDB query failed %s" + " error code %d") + , mysql_error(motapp->dbse->database_mariadb), retcd); + } } - - } else if (!(PQresultStatus(res) == PGRES_COMMAND_OK || PQresultStatus(res) == PGRES_TUPLES_OK)) { - MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO, "PGSQL query failed: [%s] %s %s", - sqlquery, PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res)); } - if (save_id) { - //ToDO: Find the equivalent option for pgsql - cam->dbse->database_event_id = 0; - } - - PQclear(res); - #else - (void)sqlquery; - (void)cam; - (void)save_id; - #endif /* HAVE_PGSQL */ + } } -static void dbse_sqlite3_exec(char *sqlquery,struct ctx_cam *cam, int save_id) +static void dbse_mariadb_recs (struct ctx_motapp *motapp, const char *sqlquery) { - #ifdef HAVE_SQLITE3 - int retcd; - char *errmsg = NULL; + int retcd, indx, indx2; + int qry_fields, rnbr, flen; + struct stat statbuf; + MYSQL_RES *qry_result; + MYSQL_ROW qry_row; + MYSQL_FIELD *qry_col; + ctx_dbse_rec *rec; + ctx_dbse_col *cols; - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing query"); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbse->database_sqlite3, sqlquery, NULL, 0, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("SQLite error was %s"), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); + retcd = mysql_query(motapp->dbse->database_mariadb, sqlquery); + if (retcd != 0){ + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Query error: %s"),sqlquery); + dbse_close(motapp); + motapp->dbse->database_type = ""; + return; + } + + qry_result = mysql_store_result(motapp->dbse->database_mariadb); + if (qry_result == NULL) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Query store error: %s"),sqlquery); + dbse_close(motapp); + motapp->dbse->database_type = ""; + return; + } + + qry_fields = mysql_num_fields(qry_result); + cols =(ctx_dbse_col *) + mymalloc(sizeof(ctx_dbse_col) * qry_fields); + for(indx = 0; indx < qry_fields; indx++) { + qry_col = mysql_fetch_field(qry_result); + cols[indx].col_nm = (char*)mymalloc(qry_col->name_length + 1); + snprintf(cols[indx].col_nm, qry_col->name_length + 1 + , "%s", qry_col->name); + } + + qry_row = mysql_fetch_row(qry_result); + + if (motapp->dbse->dbse_action == DBSE_ACT_CHKTBL) { + motapp->dbse->table_ok = false; + while (qry_row != NULL) { + for(indx = 0; indx < qry_fields; indx++) { + if (qry_row[indx] != NULL) { + if (mystrceq(qry_row[indx], "motionplus")) { + motapp->dbse->table_ok = true; + } + } + } + qry_row = mysql_fetch_row(qry_result); } - if (save_id) { - cam->dbse->database_event_id = 0; + + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETCNT) { + motapp->dbse->movie_cnt = 0; + while (qry_row != NULL) { + for(indx = 0; indx < qry_fields; indx++) { + if (mystrceq(cols[indx].col_nm, "movie_cnt")) { + motapp->dbse->movie_cnt =atoi(qry_row[indx]); + } + } + qry_row = mysql_fetch_row(qry_result); } - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Finished query"); - #else - (void)sqlquery; - (void)cam; - (void)save_id; - #endif /* HAVE_SQLITE3 */ + + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETCOLS) { + for(indx = 0; indx < qry_fields; indx++) { + for (indx2=0; indx2 < motapp->dbse->cols_cnt; indx2++) { + if (mystrceq(cols[indx].col_nm + , motapp->dbse->cols_list[indx2].col_nm)) { + motapp->dbse->cols_list[indx2].found = true; + } + } + } + + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETTBL) { + motapp->dbse->rec_indx = 0; + while (qry_row != NULL) { + rnbr = motapp->dbse->rec_indx; + rec = &motapp->dbse->movie_list[rnbr]; + dbse_rec_default(rec); + + for(indx = 0; indx < qry_fields; indx++) { + if (qry_row[indx] != NULL) { + if (mystrceq(cols[indx].col_nm,"recordid")) { + rec->recordid = atoi(qry_row[indx]); + } else if (mystrceq(cols[indx].col_nm,"camid")) { + rec->camid = atoi(qry_row[indx]); + } else if (mystrceq(cols[indx].col_nm,"movie_nm")) { + free(rec->movie_nm); + flen = strlen(qry_row[indx]); + rec->movie_nm = (char*)mymalloc(flen + 1); + snprintf(rec->movie_nm, flen+1,"%s",qry_row[indx]); + } else if (mystrceq(cols[indx].col_nm,"movie_dir")) { + free(rec->movie_dir); + flen = strlen(qry_row[indx]); + rec->movie_dir = (char*)mymalloc(flen + 1); + snprintf(rec->movie_dir, flen+1,"%s",qry_row[indx]); + } else if (mystrceq(cols[indx].col_nm,"full_nm")) { + free(rec->full_nm); + flen = strlen(qry_row[indx]); + rec->full_nm = (char*)mymalloc(flen + 1); + snprintf(rec->full_nm, flen+1,"%s",qry_row[indx]); + if (stat(rec->full_nm, &statbuf) == 0) { + rec->found = true; + } + } else if (mystrceq(cols[indx].col_nm,"movie_sz")) { + rec->movie_sz =atoi(qry_row[indx]); + + } else if (mystrceq(cols[indx].col_nm,"movie_dtl")) { + rec->movie_dtl =atoi(qry_row[indx]); + + } else if (mystrceq(cols[indx].col_nm,"movie_tmc")) { + free(rec->movie_tmc); + flen = strlen(qry_row[indx]); + rec->movie_tmc =(char*)mymalloc(flen + 1); + snprintf(rec->movie_tmc, flen+1,"%s",qry_row[indx]); + + } else if (mystrceq(cols[indx].col_nm,"diff_avg")) { + rec->diff_avg =atoi(qry_row[indx]); + } else if (mystrceq(cols[indx].col_nm,"sdev_min")) { + rec->sdev_min =atoi(qry_row[indx]); + } else if (mystrceq(cols[indx].col_nm,"sdev_max")) { + rec->sdev_max =atoi(qry_row[indx]); + } else if (mystrceq(cols[indx].col_nm,"sdev_avg")) { + rec->sdev_avg =atoi(qry_row[indx]); + } + } + } + motapp->dbse->rec_indx++; + qry_row = mysql_fetch_row(qry_result); + } + } + mysql_free_result(qry_result); + + for(indx = 0; indx < qry_fields; indx++) { + free(cols[indx].col_nm); + } + free(cols); + + return; } +static void dbse_mariadb_cols(struct ctx_motapp *motapp) +{ + int indx; + std::string sqlquery; + + dbse_cols_list(motapp); + + sqlquery = " select * from motionplus;"; + motapp->dbse->dbse_action = DBSE_ACT_GETCOLS; + dbse_mariadb_recs(motapp, sqlquery.c_str()); + + for (indx=0; indxdbse->cols_cnt; indx++) { + if (motapp->dbse->cols_list[indx].found == false) { + sqlquery = "Alter table motionplus add column "; + sqlquery += std::string(motapp->dbse->cols_list[indx].col_nm) + " "; + sqlquery += std::string(motapp->dbse->cols_list[indx].col_typ) + " ;"; + dbse_mariadb_exec(motapp,sqlquery.c_str()); + } + } + + dbse_cols_free(motapp); + +} + +static void dbse_mariadb_setup(struct ctx_motapp *motapp) +{ + std::string sqlquery; + + sqlquery = + "Select table_name " + " from information_schema.tables " + " where table_name = 'motionplus';"; + motapp->dbse->dbse_action = DBSE_ACT_CHKTBL; + dbse_mariadb_recs(motapp,sqlquery.c_str()); + + if (motapp->dbse->table_ok == false) { + MOTION_LOG(INF, TYPE_DB, NO_ERRNO + , _("Creating motionplus table")); + sqlquery = + "create table motionplus (" + " recordid serial " + ");"; + dbse_mariadb_exec(motapp,sqlquery.c_str()); + } + + dbse_mariadb_cols(motapp); + +} + +static void dbse_mariadb_init(struct ctx_motapp *motapp) +{ + bool my_true = true; + + motapp->dbse->database_mariadb = NULL; + + if (motapp->dbse->database_type != "mariadb") { + return; + } + + if (mysql_library_init(0, NULL, NULL)) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Could not initialize database %s") + , motapp->dbse->database_type.c_str()); + motapp->dbse->database_type = ""; + return; + } + + motapp->dbse->database_mariadb = (MYSQL *) mymalloc(sizeof(MYSQL)); + mysql_init(motapp->dbse->database_mariadb); + + if (mysql_real_connect( + motapp->dbse->database_mariadb + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str() + , motapp->dbse->database_password.c_str() + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_port, NULL, 0) == NULL) { + + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Cannot connect to MariaDB database %s on host %s with user %s") + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str()); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("MariaDB error was %s") + , mysql_error(motapp->dbse->database_mariadb)); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Disabling database functionality")); + dbse_close(motapp); + motapp->dbse->database_type = ""; + return; + } + mysql_options(motapp->dbse->database_mariadb + , MYSQL_OPT_RECONNECT, &my_true); + + dbse_mariadb_setup(motapp); + + MOTION_LOG(INF, TYPE_DB, NO_ERRNO + , _("%s database opened") + , motapp->dbse->database_dbname.c_str() ); +} + +static void dbse_mariadb_close(struct ctx_motapp *motapp) +{ + if (motapp->dbse->database_type == "mariadb") { + mysql_library_end(); + if (motapp->dbse->database_mariadb != NULL) { + mysql_close(motapp->dbse->database_mariadb); + free(motapp->dbse->database_mariadb); + motapp->dbse->database_mariadb = NULL; + } + } +} + +static void dbse_mariadb_movlst(struct ctx_motapp *motapp) +{ + int indx; + std::string sqlquery, delimit; + + sqlquery = + "select count(*) as movie_cnt " + " from motionplus ;"; + motapp->dbse->dbse_action = DBSE_ACT_GETCNT; + dbse_mariadb_recs(motapp, sqlquery.c_str()); + + if (motapp->dbse->movie_cnt > 0) { + motapp->dbse->movie_list =(ctx_dbse_rec *) + mymalloc(sizeof(ctx_dbse_rec)*motapp->dbse->movie_cnt); + + sqlquery =" select * from motionplus ;"; + motapp->dbse->dbse_action = DBSE_ACT_GETTBL; + dbse_mariadb_recs(motapp, sqlquery.c_str()); + + sqlquery = + " delete from motionplus " + " where recordid in ("; + delimit = " "; + for (indx=0; indxdbse->movie_cnt; indx++) { + if (motapp->dbse->movie_list[indx].found == false) { + sqlquery += delimit + std::to_string( + motapp->dbse->movie_list[indx].recordid); + delimit = ","; + } + /* 5000 is arbitrary */ + if (sqlquery.length() > 5000) { + indx = motapp->dbse->movie_cnt; + } + } + sqlquery += ");"; + if (delimit == ",") { + dbse_mariadb_exec(motapp, sqlquery.c_str()); + } + } +} + +#endif /*HAVE_MARIADB*/ + +#ifdef HAVE_MYSQL + +static void dbse_mysql_init(struct ctx_motapp *motapp) +{ + motapp->dbse->database_mysql = NULL; + + if (motapp->dbse->database_type != "mysql") { + return; + } + + if (mysql_library_init(0, NULL, NULL) != 0) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Could not initialize database %s") + , motapp->dbse->database_type.c_str()); + motapp->dbse->database_type = ""; + return; + } + + motapp->dbse->database_mysql = (MYSQL *) mymalloc(sizeof(MYSQL)); + mysql_init(motapp->dbse->database_mysql); + + if (mysql_real_connect( + motapp->dbse->database_mysql + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str() + , motapp->dbse->database_password.c_str() + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_port, NULL, 0) == NULL) { + + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Cannot connect to MySQL database %s on host %s with user %s") + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str()); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("MySQL error was %s") + , mysql_error(motapp->dbse->database_mysql)); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Disabling database functionality")); + dbse_close(motapp); + motapp->dbse->database_type = ""; + return; + } + #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012) + bool my_true = true; + mysql_options(motapp->dbse->database_mysql + , MYSQL_OPT_RECONNECT, &my_true); + #endif +} + +static void dbse_mysql_exec(struct ctx_motapp *motapp, const char *sqlquery) +{ + int retcd; + MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing mysql query"); + retcd = mysql_query(motapp->dbse->database_mysql, sqlquery); + if (retcd != 0) { + retcd = mysql_errno(motapp->dbse->database_mysql); + MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO + , _("Mysql query failed %s error code %d") + , mysql_error(motapp->dbse->database_mysql), retcd); + if (retcd >= 2000) { + mysql_close(motapp->dbse->database_mysql); + motapp->dbse->database_mysql = (MYSQL *) mymalloc(sizeof(MYSQL)); + mysql_init(motapp->dbse->database_mysql); + if (mysql_real_connect( + motapp->dbse->database_mysql + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str() + , motapp->dbse->database_password.c_str() + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_port, NULL, 0) == NULL) { + MOTION_LOG(ALR, TYPE_DB, NO_ERRNO + ,_("Cannot reconnect to MySQL" + " database %s on host %s with user %s MySQL error was %s") + , motapp->dbse->database_dbname.c_str() + , motapp->dbse->database_host.c_str() + , motapp->dbse->database_user.c_str() + , mysql_error(motapp->dbse->database_mysql)); + dbse_deinit(motapp); + } else { + MOTION_LOG(INF, TYPE_DB, NO_ERRNO + , _("Re-Connection to Mysql database '%s' Succeed") + , motapp->dbse->database_dbname.c_str()); + retcd = mysql_query(motapp->dbse->database_mysql, sqlquery); + if (retcd != 0) { + retcd = mysql_errno(motapp->dbse->database_mysql); + MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO + , _("after re-connection Mysql query failed " + " %s error code %d") + , mysql_error(motapp->dbse->database_mysql), retcd); + } + } + } + } +} + +static void dbse_mysql_close(struct ctx_motapp *motapp) +{ + if (motapp->dbse->database_type == "mysql") { + MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing MYSQL")); + mysql_library_end(); + if (motapp->dbse->database_mysql != NULL) { + mysql_close(motapp->dbse->database_mysql); + motapp->dbse->database_mysql = NULL; + } + } +} + +int dbse_mysql_movlst(struct ctx_cam *cam) +{ + (void)cam; + return 0; +} + +#endif /*HAVE_MYSQL*/ + +#ifdef HAVE_PGSQL + +static void dbse_pgsql_exec(struct ctx_motapp *motapp, const char *sqlquery) +{ + PGresult *res; + + if (motapp->dbse->database_pgsql == NULL) { + return; + } + + MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing postgresql query"); + res = PQexec(motapp->dbse->database_pgsql, sqlquery); + if (PQstatus(motapp->dbse->database_pgsql) == CONNECTION_BAD) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Connection to PostgreSQL database '%s' failed: %s") + , motapp->dbse->database_dbname.c_str() + , PQerrorMessage(motapp->dbse->database_pgsql)); + PQreset(motapp->dbse->database_pgsql); + if (PQstatus(motapp->dbse->database_pgsql) == CONNECTION_BAD) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Re-Connection to PostgreSQL database '%s' failed: %s") + , motapp->dbse->database_dbname.c_str() + , PQerrorMessage(motapp->dbse->database_pgsql)); + PQclear(res); + dbse_close(motapp); + motapp->dbse->database_type = ""; + return; + } else { + MOTION_LOG(INF, TYPE_DB, NO_ERRNO + , _("Re-Connection to PostgreSQL database '%s' Succeed") + , motapp->dbse->database_dbname.c_str()); + } + } else if (!(PQresultStatus(res) == PGRES_COMMAND_OK || PQresultStatus(res) == PGRES_TUPLES_OK)) { + MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO + , "PGSQL query failed: [%s] %s %s" + , sqlquery + , PQresStatus(PQresultStatus(res)) + , PQresultErrorMessage(res)); + } + PQclear(res); +} + +static void dbse_pgsql_close(struct ctx_motapp *motapp) +{ + if ((motapp->dbse->database_type == "postgresql") && + (motapp->dbse->database_pgsql != NULL)) { + PQfinish(motapp->dbse->database_pgsql); + motapp->dbse->database_pgsql = NULL; + } + +} + +static void dbse_pgsql_recs (struct ctx_motapp *motapp, const char *sqlquery) +{ + PGresult *res; + int indx, indx2, rows, cols, rnbr, flen; + struct stat statbuf; + ctx_dbse_rec *rec; + + if (motapp->dbse->database_pgsql == NULL) { + return; + } + + res = PQexec(motapp->dbse->database_pgsql, sqlquery); + + if (motapp->dbse->dbse_action == DBSE_ACT_CHKTBL) { + motapp->dbse->table_ok = false; + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + PQclear(res); + return; + } + + cols = PQnfields(res); + rows = PQntuples(res); + for(indx = 0; indx < rows; indx++) { + for (indx2 = 0; indx2 < cols; indx2++){ + if (mystrceq("table_nm", PQfname(res, indx2)) && + mystrceq("motionplus", PQgetvalue(res, indx, indx2))) { + motapp->dbse->table_ok = true; + } + } + } + PQclear(res); + + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETCNT) { + motapp->dbse->movie_cnt = 0; + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + PQclear(res); + return; + } + + cols = PQnfields(res); + rows = PQntuples(res); + for(indx = 0; indx < rows; indx++) { + for (indx2 = 0; indx2 < cols; indx2++){ + if (mystrceq("movie_cnt", PQfname(res, indx2))) { + motapp->dbse->movie_cnt =atoi(PQgetvalue(res, indx, indx2)); + } + } + } + PQclear(res); + + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETCOLS) { + cols = PQnfields(res); + for(indx = 0; indx < cols; indx++) { + for (indx2=0; indx2 < motapp->dbse->cols_cnt; indx2++) { + if (mystrceq(PQfname(res, indx) + , motapp->dbse->cols_list[indx2].col_nm)) { + motapp->dbse->cols_list[indx2].found = true; + } + } + } + PQclear(res); + + } else if (motapp->dbse->dbse_action == DBSE_ACT_GETTBL) { + motapp->dbse->rec_indx = 0; + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + PQclear(res); + return; + } + + cols = PQnfields(res); + rows = PQntuples(res); + for(indx = 0; indx < rows; indx++) { + rnbr = motapp->dbse->rec_indx; + rec = &motapp->dbse->movie_list[rnbr]; + dbse_rec_default(rec); + + for (indx2 = 0; indx2 < cols; indx2++) { + if (PQgetvalue(res, indx, indx2) != NULL) { + if (mystrceq(PQfname(res, indx2), "recordid")) { + rec->recordid = atoi(PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"camid")) { + rec->camid = atoi(PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"movie_nm")) { + free(rec->movie_nm); + flen = strlen(PQgetvalue(res, indx, indx2)); + rec->movie_nm = (char*)mymalloc(flen + 1); + snprintf(rec->movie_nm, flen+1, "%s" + ,PQgetvalue(res, indx, indx2)); + } else if (mystrceq(PQfname(res, indx2),"movie_dir")) { + free(rec->movie_dir); + flen = strlen(PQgetvalue(res, indx, indx2)); + rec->movie_dir =(char*)mymalloc(flen + 1); + snprintf(rec->movie_dir, flen+1, "%s" + ,PQgetvalue(res, indx, indx2)); + } else if (mystrceq(PQfname(res, indx2),"full_nm")) { + free(rec->full_nm); + flen = strlen(PQgetvalue(res, indx, indx2)); + rec->full_nm =(char*)mymalloc(flen + 1); + snprintf(rec->full_nm, flen+1, "%s" + ,PQgetvalue(res, indx, indx2)); + if (stat(rec->full_nm, &statbuf) == 0) { + rec->found = true; + } + } else if (mystrceq(PQfname(res, indx2),"movie_sz")) { + rec->movie_sz =atoi(PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"movie_dtl")) { + rec->movie_dtl =atoi(PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"movie_tmc")) { + free(rec->movie_tmc); + flen = strlen(PQgetvalue(res, indx, indx2)); + rec->movie_tmc =(char*)mymalloc(flen + 1); + snprintf(rec->movie_tmc, flen+1, "%s" + ,PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"diff_avg")) { + rec->diff_avg =atoi(PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"sdev_min")) { + rec->sdev_min =atoi(PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"sdev_max")) { + rec->sdev_max =atoi(PQgetvalue(res, indx, indx2)); + + } else if (mystrceq(PQfname(res, indx2),"sdev_avg")) { + rec->sdev_avg =atoi(PQgetvalue(res, indx, indx2)); + } + } + } + motapp->dbse->rec_indx++; + } + PQclear(res); + } + + return; +} + +static void dbse_pgsql_cols(struct ctx_motapp *motapp) +{ + int indx; + std::string sqlquery; + + dbse_cols_list(motapp); + + sqlquery = " select * from motionplus;"; + motapp->dbse->dbse_action = DBSE_ACT_GETCOLS; + dbse_pgsql_recs(motapp, sqlquery.c_str()); + + for (indx=0; indxdbse->cols_cnt; indx++) { + if (motapp->dbse->cols_list[indx].found == false) { + sqlquery = "Alter table motionplus add column "; + sqlquery += std::string(motapp->dbse->cols_list[indx].col_nm) + " "; + sqlquery += std::string(motapp->dbse->cols_list[indx].col_typ) + " ;"; + dbse_pgsql_exec(motapp,sqlquery.c_str()); + } + } + + dbse_cols_free(motapp); + +} + +static void dbse_pgsql_setup(struct ctx_motapp *motapp) +{ + std::string sqlquery; + + sqlquery = + " select tablename as table_nm " + " from pg_catalog.pg_tables " + " where schemaname != 'pg_catalog' " + " and schemaname != 'information_schema' " + " and tablename = 'motionplus';"; + motapp->dbse->dbse_action = DBSE_ACT_CHKTBL; + dbse_pgsql_recs(motapp,sqlquery.c_str()); + + if (motapp->dbse->table_ok == false) { + MOTION_LOG(INF, TYPE_DB, NO_ERRNO + , _("Creating motionplus table")); + sqlquery = + "create table motionplus (" + " recordid serial " + ");"; + dbse_pgsql_exec(motapp,sqlquery.c_str()); + } + + dbse_pgsql_cols(motapp); + +} + +static void dbse_pgsql_init(struct ctx_motapp *motapp) +{ + std::string constr; + + motapp->dbse->database_pgsql = NULL; + + if (motapp->dbse->database_type != "postgresql") { + return; + } + + constr = "dbname='" + motapp->dbse->database_dbname + "' "; + constr += " host='" + motapp->dbse->database_host + "' "; + constr += " user='" + motapp->dbse->database_user + "' "; + constr += " password='" + motapp->dbse->database_password + "' "; + constr += " port="+std::to_string(motapp->dbse->database_port) + " "; + motapp->dbse->database_pgsql = PQconnectdb(constr.c_str()); + if (PQstatus(motapp->dbse->database_pgsql) == CONNECTION_BAD) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + , _("Connection to PostgreSQL database '%s' failed: %s") + , motapp->dbse->database_dbname.c_str() + , PQerrorMessage(motapp->dbse->database_pgsql)); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO + ,_("Disabling database functionality")); + dbse_close(motapp); + motapp->dbse->database_type = ""; + return; + } + + dbse_pgsql_setup(motapp); + + MOTION_LOG(INF, TYPE_DB, NO_ERRNO + , _("%s database opened") + , motapp->dbse->database_dbname.c_str() ); +} + +static void dbse_pgsql_movlst(struct ctx_motapp *motapp) +{ + int indx; + std::string sqlquery, delimit; + + sqlquery = + "select count(*) as movie_cnt " + " from motionplus ;"; + motapp->dbse->dbse_action = DBSE_ACT_GETCNT; + dbse_pgsql_recs(motapp, sqlquery.c_str()); + + if (motapp->dbse->movie_cnt > 0) { + motapp->dbse->movie_list =(ctx_dbse_rec *) + mymalloc(sizeof(ctx_dbse_rec)*motapp->dbse->movie_cnt); + + sqlquery =" select * from motionplus ;"; + motapp->dbse->dbse_action = DBSE_ACT_GETTBL; + dbse_pgsql_recs(motapp, sqlquery.c_str()); + + sqlquery = + " delete from motionplus " + " where recordid in ("; + delimit = " "; + for (indx=0; indxdbse->movie_cnt; indx++) { + if (motapp->dbse->movie_list[indx].found == false) { + sqlquery += delimit + std::to_string( + motapp->dbse->movie_list[indx].recordid); + delimit = ","; + } + /* 5000 is arbitrary */ + if (sqlquery.length() > 5000) { + indx = motapp->dbse->movie_cnt; + } + } + sqlquery += ");"; + if (delimit == ",") { + dbse_pgsql_exec(motapp, sqlquery.c_str()); + } + } + return; +} + +#endif /*HAVE_PGSQL*/ + +void dbse_init(struct ctx_motapp *motapp) +{ + motapp->dbse = new ctx_dbse; + motapp->dbse->database_busy_timeout = motapp->cam_list[0]->conf->database_busy_timeout; + motapp->dbse->database_dbname = motapp->cam_list[0]->conf->database_dbname; + motapp->dbse->database_host = motapp->cam_list[0]->conf->database_host; + motapp->dbse->database_password = motapp->cam_list[0]->conf->database_password; + motapp->dbse->database_port = motapp->cam_list[0]->conf->database_port; + motapp->dbse->database_type = motapp->cam_list[0]->conf->database_type; + motapp->dbse->database_user = motapp->cam_list[0]->conf->database_user; + motapp->dbse->movie_cnt = 0; + motapp->dbse->movie_list = NULL; + motapp->dbse->cols_cnt = 0; + motapp->dbse->cols_list = NULL; + + pthread_mutex_init(&motapp->dbse->mutex_dbse, NULL); + + if (motapp->dbse->database_type != "") { + if (dbse_edits(motapp) == -1) { + return; + } + MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("Initializing database")); + pthread_mutex_lock(&motapp->dbse->mutex_dbse); + #ifdef HAVE_MYSQL + if (motapp->dbse->database_type == "mysql") { + dbse_mysql_init(motapp); + } + #endif + #ifdef HAVE_MARIADB + if (motapp->dbse->database_type == "mariadb") { + dbse_mariadb_init(motapp); + } + #endif + #ifdef HAVE_PGSQL + if (motapp->dbse->database_type == "postgresql") { + dbse_pgsql_init(motapp); + } + #endif + #ifdef HAVE_SQLITE3 + if (motapp->dbse->database_type == "sqlite3") { + dbse_sqlite3_init(motapp); + } + #endif + pthread_mutex_unlock(&motapp->dbse->mutex_dbse); + + } +} + +/* Populate the list of the movies from the database*/ +void dbse_movies_getlist(struct ctx_motapp *motapp) +{ + + if (motapp->dbse->database_type == "") { + return; + } + + dbse_movies_free(motapp); + + pthread_mutex_lock(&motapp->dbse->mutex_dbse); + #ifdef HAVE_MYSQL + if (cam->motapp->dbse->database_type == "mysql") { + + } + #endif + #ifdef HAVE_MARIADB + if (motapp->dbse->database_type == "mariadb") { + dbse_mariadb_movlst(motapp); + } + #endif + #ifdef HAVE_PGSQL + if (motapp->dbse->database_type == "postgresql") { + dbse_pgsql_movlst(motapp); + } + #endif + #ifdef HAVE_SQLITE3 + if (motapp->dbse->database_type == "sqlite3") { + dbse_sqlite3_movlst(motapp); + } + #endif + pthread_mutex_unlock(&motapp->dbse->mutex_dbse); + +} + +void dbse_close(struct ctx_motapp *motapp) +{ + #ifdef HAVE_MYSQL + dbse_mysql_close(motapp); + #endif + #ifdef HAVE_MARIADB + dbse_mariadb_close(motapp); + #endif + #ifdef HAVE_PGSQL + dbse_pgsql_close(motapp); + #endif + #ifdef HAVE_SQLITE3 + dbse_sqlite3_close(motapp); + #endif +} + +void dbse_deinit(struct ctx_motapp *motapp) +{ + dbse_movies_free(motapp); + + dbse_cols_free(motapp); + + dbse_close(motapp); + + pthread_mutex_destroy(&motapp->dbse->mutex_dbse); + + if (motapp->dbse != NULL) { + delete motapp->dbse; + } + +} + +/* Execute sql against database with mutex lock */ +void dbse_exec_sql(struct ctx_motapp *motapp, const char *sqlquery) +{ + + if (motapp->dbse->database_type == "") { + return; + } + + pthread_mutex_lock(&motapp->dbse->mutex_dbse); + #ifdef HAVE_MYSQL + if (motapp->dbse->database_type == "mysql") { + dbse_mysql_exec(motapp, sqlquery); + } + #endif + #ifdef HAVE_MARIADB + if (motapp->dbse->database_type == "mariadb") { + dbse_mariadb_exec(motapp, sqlquery); + } + #endif + #ifdef HAVE_PGSQL + if (motapp->dbse->database_type == "postgresql") { + dbse_pgsql_exec(motapp, sqlquery); + } + #endif + #ifdef HAVE_SQLITE3 + if (motapp->dbse->database_type == "sqlite3") { + dbse_sqlite3_exec(motapp, sqlquery); + } + #endif + pthread_mutex_unlock(&motapp->dbse->mutex_dbse); + +} + +/* Create and execute user provided sql with mutex lock*/ void dbse_exec(struct ctx_cam *cam, char *filename , int sqltype, struct timespec *ts1, const char *cmd) { char sqlquery[PATH_MAX]; - if (cam->conf->database_type == "") { + if (cam->motapp->dbse->database_type == "") { return; } - if (mystreq(cmd,"pic_save")) { + if (mystrceq(cmd,"pic_save")) { mystrftime(cam, sqlquery, sizeof(sqlquery) , cam->conf->sql_pic_save.c_str() , ts1, filename, sqltype); - } else if (mystreq(cmd,"movie_start")) { + } else if (mystrceq(cmd,"movie_start")) { mystrftime(cam, sqlquery, sizeof(sqlquery) , cam->conf->sql_movie_start.c_str() , ts1, filename, sqltype); - } else if (mystreq(cmd,"movie_end")) { + } else if (mystrceq(cmd,"movie_end")) { mystrftime(cam, sqlquery, sizeof(sqlquery) , cam->conf->sql_movie_end.c_str() , ts1, filename, sqltype); - } else if (mystreq(cmd,"event_start")) { + } else if (mystrceq(cmd,"event_start")) { mystrftime(cam, sqlquery, sizeof(sqlquery) , cam->conf->sql_event_start.c_str() , ts1, filename, sqltype); - } else if (mystreq(cmd,"event_end")) { + } else if (mystrceq(cmd,"event_end")) { mystrftime(cam, sqlquery, sizeof(sqlquery) , cam->conf->sql_event_end.c_str() , ts1, filename, sqltype); @@ -641,529 +1490,29 @@ void dbse_exec(struct ctx_cam *cam, char *filename if (strlen(sqlquery) <= 0) { return; } - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "%s query: %s",cmd, sqlquery); + MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "%s query: %s", cmd, sqlquery); - - if (cam->conf->database_type == "mysql") { - dbse_mysql_exec(sqlquery, cam, 0); - } else if (cam->conf->database_type == "mariadb") { - dbse_mariadb_exec(sqlquery, cam, 0); - } else if (cam->conf->database_type == "postgresql") { - dbse_pgsql_exec(sqlquery, cam, 0); - } else if (cam->conf->database_type == "sqlite3") { - dbse_sqlite3_exec(sqlquery, cam, 0); - } + dbse_exec_sql(cam->motapp, sqlquery); } -/* Execute query against the motionplus database */ -void dbse_motpls_exec(const char *sqlquery, struct ctx_cam *cam) -{ - int retcd; - char *errmsg = NULL; - - if (cam->dbsemp == NULL) { - return; - } - if (cam->dbsemp->database_sqlite3 == NULL) { - return; - } - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3, sqlquery, NULL, 0, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("SQLite error was %s"), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - } -} - -/* sqlite query result call back */ -static int dbse_motpls_cb( - void *ptr, int arg_nb, char **arg_val, char **col_nm) -{ - ctx_cam *cam = (ctx_cam *)ptr; - int indx; - - (void)col_nm; - - if (cam->dbsemp->dbse_action == DBSE_ACT_CHKTBL) { - for (indx=0; indx < arg_nb; indx++) { - if (mystrceq(arg_val[indx],"motionplus")) { - cam->dbsemp->table_ok = true; - } - } - } else if (cam->dbsemp->dbse_action == DBSE_ACT_GETCNT) { - for (indx=0; indx < arg_nb; indx++) { - if (mystrceq(col_nm[indx],"movie_cnt")) { - cam->dbsemp->movie_cnt =atoi(arg_val[indx]); - } - } - } - - return 0; -} - -/* Process query records for movie list */ -static int dbse_motpls_cb_movies( - void *ptr, int arg_nb, char **arg_val, char **col_nm) -{ - ctx_cam *cam = (ctx_cam *)ptr; - struct stat statbuf; - int indx, rnbr, flen; - - if (cam->dbsemp->dbse_action == DBSE_ACT_GETTBL) { - rnbr = cam->dbsemp->rec_indx; - if (rnbr < cam->dbsemp->movie_cnt) { - cam->dbsemp->movie_list[rnbr].found = false; - - cam->dbsemp->movie_list[rnbr].rowid = -1; - cam->dbsemp->movie_list[rnbr].camid = -1; - cam->dbsemp->movie_list[rnbr].movie_nm = NULL; - cam->dbsemp->movie_list[rnbr].full_nm = NULL; - cam->dbsemp->movie_list[rnbr].movie_sz = 0; - cam->dbsemp->movie_list[rnbr].movie_dtl = 0; - cam->dbsemp->movie_list[rnbr].movie_tmc = NULL; - cam->dbsemp->movie_list[rnbr].movie_tmc = NULL; - cam->dbsemp->movie_list[rnbr].diff_avg = 0; - cam->dbsemp->movie_list[rnbr].sdev_min = 0; - cam->dbsemp->movie_list[rnbr].sdev_max = 0; - cam->dbsemp->movie_list[rnbr].sdev_avg = 0; - - for (indx=0; indx < arg_nb; indx++) { - if (arg_val[indx] != NULL) { - if (mystreq(col_nm[indx],"rowid")) { - cam->dbsemp->movie_list[rnbr].rowid = atoi(arg_val[indx]); - - } else if (mystreq(col_nm[indx],"camid")) { - cam->dbsemp->movie_list[rnbr].camid = atoi(arg_val[indx]); - - } else if (mystreq(col_nm[indx],"movie_nm")) { - flen = strlen(arg_val[indx]); - cam->dbsemp->movie_list[rnbr].movie_nm = - (char*)mymalloc(flen + 1); - snprintf(cam->dbsemp->movie_list[rnbr].movie_nm - ,flen+1,"%s",arg_val[indx]); - flen += cam->conf->target_dir.length() + 2; - cam->dbsemp->movie_list[rnbr].full_nm = - (char*)mymalloc(flen + 1); - snprintf(cam->dbsemp->movie_list[rnbr].full_nm - , flen, "%s/%s", cam->conf->target_dir.c_str() - , arg_val[indx]); - if (stat(cam->dbsemp->movie_list[rnbr].full_nm, - &statbuf) == 0) { - cam->dbsemp->movie_list[rnbr].found = true; - } - - } else if (mystreq(col_nm[indx],"movie_sz")) { - cam->dbsemp->movie_list[rnbr].movie_sz =atoi(arg_val[indx]); - - } else if (mystreq(col_nm[indx],"movie_dtl")) { - cam->dbsemp->movie_list[rnbr].movie_dtl =atoi(arg_val[indx]); - - } else if (mystreq(col_nm[indx],"movie_tmc")) { - flen = strlen(arg_val[indx]); - cam->dbsemp->movie_list[rnbr].movie_tmc = - (char*)mymalloc(flen + 1); - snprintf(cam->dbsemp->movie_list[rnbr].movie_tmc - ,flen+1,"%s",arg_val[indx]); - - } else if (mystreq(col_nm[indx],"diff_avg")) { - cam->dbsemp->movie_list[rnbr].diff_avg =atoi(arg_val[indx]); - } else if (mystreq(col_nm[indx],"sdev_min")) { - cam->dbsemp->movie_list[rnbr].sdev_min =atoi(arg_val[indx]); - } else if (mystreq(col_nm[indx],"sdev_max")) { - cam->dbsemp->movie_list[rnbr].sdev_max =atoi(arg_val[indx]); - } else if (mystreq(col_nm[indx],"sdev_avg")) { - cam->dbsemp->movie_list[rnbr].sdev_avg =atoi(arg_val[indx]); - - } - } - } - } - cam->dbsemp->rec_indx++; - } - - return 0; -} - -/* Process query list of columns in motionplus table*/ -static int dbse_motpls_cb_cols( - void *ptr, int arg_nb, char **arg_val, char **col_nm) -{ - ctx_cam *cam = (ctx_cam *)ptr; - int indx, indx2; - - if (cam->dbsemp->dbse_action == DBSE_ACT_GETCOLS) { - for (indx=0; indx < arg_nb; indx++) { - if (mystreq(col_nm[indx],"col_nm")) { - for (indx2=0; indx2 < cam->dbsemp->cols_cnt; indx2++) { - if (mystreq(arg_val[indx] - , cam->dbsemp->cols_list[indx2].col_nm)) { - cam->dbsemp->cols_list[indx2].found = true; - } - } - } - } - } - - return 0; -} - -/* Free the movies lists*/ -static void dbse_motpls_free_movies(struct ctx_cam *cam) -{ - int indx; - - if (cam->dbsemp == NULL) { - return; - } - - if (cam->dbsemp->movie_list != NULL) { - for (indx=0; indxdbsemp->movie_cnt; indx++) { - myfree(&cam->dbsemp->movie_list[indx].movie_nm); - myfree(&cam->dbsemp->movie_list[indx].full_nm); - myfree(&cam->dbsemp->movie_list[indx].movie_tmc); - } - myfree(&cam->dbsemp->movie_list); - } - cam->dbsemp->movie_cnt = 0; - -} - -/* Free the cols lists*/ -static void dbse_motpls_free_cols(struct ctx_cam *cam) -{ - int indx; - - if (cam->dbsemp == NULL) { - return; - } - - if (cam->dbsemp->cols_list != NULL) { - for (indx=0; indxdbsemp->cols_cnt; indx++) { - myfree(&cam->dbsemp->cols_list[indx].col_nm); - myfree(&cam->dbsemp->cols_list[indx].col_typ); - } - myfree(&cam->dbsemp->cols_list); - } - cam->dbsemp->cols_cnt = 0; - -} - -/* Create array of all the columns in current version */ -static void dbse_motpls_col_list(struct ctx_cam *cam) -{ - int indx; - - dbse_motpls_free_cols(cam); - - cam->dbsemp->cols_cnt = 9; - - cam->dbsemp->cols_list =(ctx_dbsemp_col *) - mymalloc(sizeof(ctx_dbsemp_col) * cam->dbsemp->cols_cnt); - - /* The size of 30 is arbitrary */ - for (indx=0; indxdbsemp->cols_cnt; indx++) { - cam->dbsemp->cols_list[indx].col_nm = (char*)mymalloc(30); - cam->dbsemp->cols_list[indx].col_typ = (char*)mymalloc(30); - cam->dbsemp->cols_list[indx].found = false; - } - - snprintf(cam->dbsemp->cols_list[0].col_nm, 30, "%s", "camid"); - snprintf(cam->dbsemp->cols_list[0].col_typ, 30, "%s", "int"); - - snprintf(cam->dbsemp->cols_list[1].col_nm, 30, "%s", "movie_nm"); - snprintf(cam->dbsemp->cols_list[1].col_typ, 30, "%s", "text"); - - snprintf(cam->dbsemp->cols_list[2].col_nm, 30, "%s", "movie_sz"); - snprintf(cam->dbsemp->cols_list[2].col_typ, 30, "%s", "int"); - - snprintf(cam->dbsemp->cols_list[3].col_nm, 30, "%s", "movie_dtl"); - snprintf(cam->dbsemp->cols_list[3].col_typ, 30, "%s", "int"); - - snprintf(cam->dbsemp->cols_list[4].col_nm, 30, "%s", "movie_tmc"); - snprintf(cam->dbsemp->cols_list[4].col_typ, 30, "%s", "text"); - - snprintf(cam->dbsemp->cols_list[5].col_nm, 30, "%s", "diff_avg"); - snprintf(cam->dbsemp->cols_list[5].col_typ, 30, "%s", "int"); - - snprintf(cam->dbsemp->cols_list[6].col_nm, 30, "%s", "sdev_min"); - snprintf(cam->dbsemp->cols_list[6].col_typ, 30, "%s", "int"); - - snprintf(cam->dbsemp->cols_list[7].col_nm, 30, "%s", "sdev_max"); - snprintf(cam->dbsemp->cols_list[7].col_typ, 30, "%s", "int"); - - snprintf(cam->dbsemp->cols_list[8].col_nm, 30, "%s", "sdev_avg"); - snprintf(cam->dbsemp->cols_list[8].col_typ, 30, "%s", "int"); - -} - -/* Validate table has our cols. If not add the cols */ -static int dbse_motpls_validate_cols(struct ctx_cam *cam) -{ - int retcd, indx; - char *errmsg = 0; - std::string sqlquery; - - dbse_motpls_col_list(cam); - - sqlquery = - " select name as col_nm " - " from pragma_table_info('motionplus');"; - cam->dbsemp->dbse_action = DBSE_ACT_GETCOLS; - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3 - , sqlquery.c_str(), dbse_motpls_cb_cols, cam, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("Error retrieving table columns: %s"), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - return -1; - } - - for (indx=0; indxdbsemp->cols_cnt; indx++) { - if (cam->dbsemp->cols_list[indx].found == false) { - sqlquery = "Alter table motionplus add column "; - sqlquery += std::string(cam->dbsemp->cols_list[indx].col_nm) + " "; - sqlquery += std::string(cam->dbsemp->cols_list[indx].col_typ) + " ;"; - dbse_motpls_exec(sqlquery.c_str(), cam); - } - } - - dbse_motpls_free_cols(cam); - - return 0; -} - -/* Validate database has our required table, if not create it */ -static int dbse_motpls_validate(struct ctx_cam *cam) -{ - int retcd; - char *errmsg = NULL; - std::string sqlquery; - - sqlquery = - "select name from sqlite_master" - " where type='table' " - " and name='motionplus';"; - cam->dbsemp->table_ok = false; - cam->dbsemp->dbse_action = DBSE_ACT_CHKTBL; - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3 - , sqlquery.c_str(), dbse_motpls_cb, cam, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("Error checking table: %s"), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - return -1; - } - - if (cam->dbsemp->table_ok == false) { - sqlquery = - "create table motionplus (" - " camid int" - ");"; - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3 - , sqlquery.c_str(), 0, 0, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("Error creating table: %s"), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - return -1; - } - } - - retcd = dbse_motpls_validate_cols(cam); - - return retcd; - -} - -/* Open and validate the motionplus database*/ -void dbse_motpls_init(struct ctx_cam *cam) -{ - std::string dbname; - const char *errmsg; - int retcd; - - cam->dbsemp = new ctx_dbsemp; - cam->dbsemp->movie_cnt = 0; - cam->dbsemp->movie_list = NULL; - cam->dbsemp->cols_cnt = 0; - cam->dbsemp->cols_list = NULL; - - dbname = cam->conf->target_dir + "/dbcam" + - std::to_string(cam->camera_id)+".db"; - - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s", dbname.c_str()); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_open(dbname.c_str(), &cam->dbsemp->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK) { - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - errmsg = sqlite3_errmsg(cam->dbsemp->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Can't open database %s : %s") - ,dbname.c_str(), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_close(cam->dbsemp->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - cam->dbsemp->database_sqlite3 = NULL; - return; - } - - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd =sqlite3_busy_timeout(cam->dbsemp->database_sqlite3, 1000); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK) { - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - errmsg = sqlite3_errmsg(cam->dbsemp->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("database_busy_timeout failed %s"),errmsg); - } - - retcd = dbse_motpls_validate(cam); - if (retcd != 0) { - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_close(cam->dbsemp->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - cam->dbsemp->database_sqlite3 = NULL; - return; - }; - - return; - -} - -/* Close the motionplus database */ -void dbse_motpls_deinit(struct ctx_cam *cam) -{ - if (cam->dbsemp != NULL) { - if (cam->dbsemp->database_sqlite3 != NULL) { - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_close(cam->dbsemp->database_sqlite3); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - } - cam->dbsemp->database_sqlite3 = NULL; - dbse_motpls_free_movies(cam); - dbse_motpls_free_cols(cam); - delete cam->dbsemp; - cam->dbsemp = NULL; - } -} - -/* Populate the list of the movies from the database*/ -int dbse_motpls_getlist(struct ctx_cam *cam) -{ - int retcd, indx; - char *errmsg = 0; - std::string sqlquery; - - if (cam->dbsemp == NULL) { - return -1; - } - - dbse_motpls_free_movies(cam); - - if (cam->dbsemp->database_sqlite3 == NULL) { - return -1; - } - - sqlquery = - "select count(*) as movie_cnt " - " from motionplus " - " where camid = " + std::to_string(cam->camera_id) + ";"; - cam->dbsemp->dbse_action = DBSE_ACT_GETCNT; - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3 - , sqlquery.c_str(), dbse_motpls_cb, cam, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("Error counting table: %s"), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - return -1; - } - - if (cam->dbsemp->movie_cnt > 0) { - cam->dbsemp->movie_list =(ctx_dbsemp_rec *) - mymalloc(sizeof(ctx_dbsemp_rec)*cam->dbsemp->movie_cnt); - cam->dbsemp->rec_indx = 0; - sqlquery = - " select rowid, * from motionplus " - " where camid = " + std::to_string(cam->camera_id) + ";"; - cam->dbsemp->dbse_action = DBSE_ACT_GETTBL; - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3 - , sqlquery.c_str(), dbse_motpls_cb_movies, cam, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("Error retrieving table: %s"), errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - return -1; - } - /* Clean the database of files that were removed*/ - for (indx=0; indxdbsemp->movie_cnt; indx++) { - if (cam->dbsemp->movie_list[indx].found == false) { - sqlquery = - " delete from motionplus " - " where camid = " + std::to_string(cam->camera_id) + - " and rowid = " + std::to_string( - cam->dbsemp->movie_list[indx].rowid)+";"; - dbse_motpls_exec(sqlquery.c_str(),cam); - } - /*since we run vacuum after this, the rowids will no longer be valid*/ - cam->dbsemp->movie_list[indx].rowid = -1; - } - sqlquery ="vacuum"; - dbse_motpls_exec(sqlquery.c_str(),cam); - } - - return 0; -} - -/* Add a record for new movies */ -void dbse_motpls_addrec(struct ctx_cam *cam,char *fname, struct timespec *ts1) +/* Add a record to motionplus table for new movies */ +void dbse_movies_addrec(ctx_cam *cam, ctx_movie *movie, timespec *ts1) { std::string sqlquery; struct stat statbuf; - char *errmsg = 0; - int retcd, dirlen; int64_t bsz; char dtl[12]; char tmc[12]; uint64_t diff_avg, sdev_avg; - struct tm timestamp_tm; - if (cam->dbsemp == NULL) { - return; - } - if (cam->dbsemp->database_sqlite3 == NULL) { + if (cam->motapp->dbse->database_type == "") { return; } /* Movie file times */ - if (stat(fname, &statbuf) == 0) { + if (stat(movie->full_nm, &statbuf) == 0) { bsz = statbuf.st_size; } else { bsz = 0; @@ -1172,12 +1521,6 @@ void dbse_motpls_addrec(struct ctx_cam *cam,char *fname, struct timespec *ts1) strftime(dtl, 11, "%G%m%d", ×tamp_tm); strftime(tmc, 11, "%I:%M%p", ×tamp_tm); - /* Add 1 for last slash */ - dirlen = cam->conf->target_dir.length() + 1; - if (dirlen >= (int)strlen(fname)) { - return; - } - if (cam->info_diff_cnt != 0) { diff_avg = (cam->info_diff_tot / cam->info_diff_cnt); } else { @@ -1190,10 +1533,12 @@ void dbse_motpls_addrec(struct ctx_cam *cam,char *fname, struct timespec *ts1) } sqlquery = "insert into motionplus "; - sqlquery += " (camid, movie_nm, movie_sz, movie_dtl, movie_tmc "; - sqlquery += " , diff_avg, sdev_min, sdev_max, sdev_avg)"; + sqlquery += " (camid, movie_nm, movie_dir, full_nm, movie_sz, movie_dtl"; + sqlquery += " , movie_tmc, diff_avg, sdev_min, sdev_max, sdev_avg)"; sqlquery += " values ("+std::to_string(cam->camera_id); - sqlquery += " ,'" + std::string(fname + dirlen) + "'"; + sqlquery += " ,'" + std::string(movie->movie_nm) + "'"; + sqlquery += " ,'" + std::string(movie->movie_dir) + "'"; + sqlquery += " ,'" + std::string(movie->full_nm) + "'"; sqlquery += " ," + std::to_string(bsz); sqlquery += " ," + std::string(dtl); sqlquery += " ,'" + std::string(tmc)+ "'"; @@ -1202,29 +1547,8 @@ void dbse_motpls_addrec(struct ctx_cam *cam,char *fname, struct timespec *ts1) sqlquery += " ," + std::to_string(cam->info_sdev_max); sqlquery += " ," + std::to_string(sdev_avg); sqlquery += ")"; - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3 - , sqlquery.c_str(), NULL, 0, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("SQLite error %d was %s"),retcd, errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - dbse_motpls_deinit(cam); - dbse_motpls_init(cam); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - retcd = sqlite3_exec(cam->dbsemp->database_sqlite3 - , sqlquery.c_str(), NULL, 0, &errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - if (retcd != SQLITE_OK ) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - , _("Serious error %d was %s"),retcd, errmsg); - pthread_mutex_lock(&cam->motapp->mutex_sqlite); - sqlite3_free(errmsg); - pthread_mutex_unlock(&cam->motapp->mutex_sqlite); - dbse_motpls_deinit(cam); - } - } + + dbse_exec_sql(cam->motapp, sqlquery.c_str()); + } + diff --git a/src/dbse.hpp b/src/dbse.hpp index cdfd891c..ec15a8bd 100644 --- a/src/dbse.hpp +++ b/src/dbse.hpp @@ -45,11 +45,33 @@ DBSE_ACT_GETCNT = 1, DBSE_ACT_GETTBL = 2, DBSE_ACT_GETCOLS = 3 - }; + /* Record structure of motionplus table */ + struct ctx_dbse_rec { + bool found; /*Bool for whether the file exists*/ + int64_t recordid; /*recordid*/ + int camid; /*camera id */ + char *movie_nm; /*Name of the movie file*/ + char *movie_dir; /*Directory of the movie file */ + char *full_nm; /*Full name of the movie file with dir*/ + int64_t movie_sz; /*Size of the movie file in bytes*/ + int movie_dtl; /*Date in yyyymmdd format for the movie file*/ + char *movie_tmc; /*Movie time*/ + int diff_avg; /*Average diffs for motion frames */ + int sdev_min; /*std dev min */ + int sdev_max; /*std dev max */ + int sdev_avg; /*std dev average */ + }; - /* Database structure for user specified database*/ + /* Columns in the motionplus table */ + struct ctx_dbse_col { + bool found; /*Bool for whether the col in existing db*/ + char *col_nm; /*Name of the column*/ + char *col_typ; /*Data type of the column*/ + }; + + /* Database context structure*/ struct ctx_dbse { #ifdef HAVE_SQLITE3 sqlite3 *database_sqlite3; @@ -61,61 +83,37 @@ MYSQL *database_mariadb; #endif #ifdef HAVE_PGSQL - PGconn *database_pg; + PGconn *database_pgsql; #endif - uint64_t database_event_id; + std::string database_type; + std::string database_dbname; + std::string database_host; + std::string database_user; + std::string database_password; + + int database_port; + int database_busy_timeout; + + pthread_mutex_t mutex_dbse; /* mutex for database*/ + enum DBSE_ACT dbse_action; /* action to perform with query*/ + bool table_ok; /* bool of whether table exists*/ + int rec_indx; /* index of recordset */ + int movie_cnt; /* count of movie_list */ + struct ctx_dbse_rec *movie_list; /* list of movies from the database*/ + int cols_cnt; /* count of columns */ + struct ctx_dbse_col *cols_list; /* columns of table from the database*/ + + }; - /* Record structure of motionplus database */ - struct ctx_dbsemp_rec { - bool found; /*Bool for whether the file exists in dir*/ - - int64_t rowid; /*rowid from database*/ - int camid; /*camera id */ - char *movie_nm; /*Name of the movie file*/ - char *full_nm; /*Full name of the movie file with dir*/ - int64_t movie_sz; /*Size of the movie file in bytes*/ - int movie_dtl; /*Date in yyyymmdd format for the movie file*/ - char *movie_tmc; /*Movie time*/ - int diff_avg; /*Average diffs for motion frames */ - int sdev_min; /*std dev min */ - int sdev_max; /*std dev max */ - int sdev_avg; /*std dev average */ - }; - - /* Columns in the motionplus database */ - struct ctx_dbsemp_col { - bool found; /*Bool for whether the col in existing db*/ - char *col_nm; /*Name of the column*/ - char *col_typ; /*Data type of the column*/ - }; - - /* Database structure for motionplus dedicated database*/ - struct ctx_dbsemp { - #ifdef HAVE_SQLITE3 - sqlite3 *database_sqlite3; - #endif - enum DBSE_ACT dbse_action; /* action to perform with query*/ - bool table_ok; /* bool of whether table exists*/ - int rec_indx; /* index of recordset */ - int movie_cnt; /* count of movie_list */ - struct ctx_dbsemp_rec *movie_list; /* list of movies from the database*/ - int cols_cnt; /* count of columns */ - struct ctx_dbsemp_col *cols_list; /* columns of table from the database*/ - }; - - - void dbse_global_deinit(struct ctx_motapp *motapp); - void dbse_global_init(struct ctx_motapp *motapp); - void dbse_init(struct ctx_cam *cam); - void dbse_deinit(struct ctx_cam *cam); - void dbse_motpls_init(struct ctx_cam *cam); - void dbse_motpls_deinit(struct ctx_cam *cam); - void dbse_motpls_exec(const char *sqlquery, struct ctx_cam *cam); - int dbse_motpls_getlist(struct ctx_cam *cam); - void dbse_motpls_addrec(struct ctx_cam *cam,char *fname, struct timespec *ts1); - void dbse_exec(struct ctx_cam *cam, char *filename - , int sqltype, struct timespec *ts1, const char *cmd); + void dbse_init(ctx_motapp *motapp); + void dbse_init_motpls(ctx_motapp *motapp); + void dbse_deinit(ctx_motapp *motapp); + void dbse_deinit_motpls(ctx_motapp *motapp); + void dbse_exec(ctx_cam *cam, char *filename + , int sqltype, timespec *ts1, const char *cmd); + void dbse_movies_getlist(ctx_motapp *motapp); + void dbse_movies_addrec(ctx_cam *cam, ctx_movie *movie, timespec *ts1); #endif /* _INCLUDE_DBSE_HPP_ */ \ No newline at end of file diff --git a/src/event.cpp b/src/event.cpp index a2fbc03d..1e62b0af 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -606,15 +606,15 @@ static void event_movie_start(struct ctx_cam *cam, motion_event evnt myfree(&cam->movie_norm); return; } - event(cam, EVENT_FILECREATE, NULL, cam->movie_norm->filename, (void *)FTYPE_MOVIE, ts1); - dbse_exec(cam, cam->movie_norm->filename, FTYPE_MOVIE, ts1, "movie_start"); + event(cam, EVENT_FILECREATE, NULL, cam->movie_norm->full_nm, (void *)FTYPE_MOVIE, ts1); + dbse_exec(cam, cam->movie_norm->full_nm, FTYPE_MOVIE, ts1, "movie_start"); } if (cam->conf->movie_output_motion) { retcd = movie_init_motion(cam, ts1); if (retcd < 0) { MOTION_LOG(ERR, TYPE_EVENTS, NO_ERRNO - ,_("Error creating motion file [%s]"), cam->movie_motion->filename); + ,_("Error creating motion file [%s]"), cam->movie_motion->full_nm); myfree(&cam->movie_motion); return; } @@ -652,49 +652,59 @@ static void event_movie_end(struct ctx_cam *cam, motion_event evnt (void)ftype; if (cam->movie_norm) { + if ((cam->conf->movie_retain == "secondary") && (cam->algsec_inuse)) { + if (cam->algsec->isdetected == false) { + retcd = remove(cam->movie_norm->full_nm); + if (retcd != 0) { + MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO + , _("Unable to remove file %s") + , cam->movie_norm->full_nm); + } + } else { + event(cam, EVENT_FILECLOSE, NULL, cam->movie_norm->full_nm + , (void *)FTYPE_MOVIE, ts1); + dbse_exec(cam, cam->movie_norm->full_nm, FTYPE_MOVIE + , ts1, "movie_end"); + dbse_movies_addrec(cam, cam->movie_norm, ts1); + } + } else { + event(cam, EVENT_FILECLOSE, NULL, cam->movie_norm->full_nm + , (void *)FTYPE_MOVIE, ts1); + dbse_exec(cam, cam->movie_norm->full_nm + , FTYPE_MOVIE, ts1, "movie_end"); + dbse_movies_addrec(cam, cam->movie_norm, ts1); + } movie_close(cam->movie_norm); myfree(&cam->movie_norm); - if ((cam->conf->movie_retain == "secondary") && (cam->algsec_inuse)) { - if (cam->algsec->isdetected == false) { - retcd = remove(cam->newfilename); - if (retcd != 0) { - MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO - , _("Unable to remove file %s"), cam->newfilename); - } - } else { - event(cam, EVENT_FILECLOSE, NULL, cam->newfilename, (void *)FTYPE_MOVIE, ts1); - dbse_exec(cam, cam->newfilename, FTYPE_MOVIE, ts1, "movie_end"); - dbse_motpls_addrec(cam, cam->newfilename, ts1); - } - } else { - event(cam, EVENT_FILECLOSE, NULL, cam->newfilename, (void *)FTYPE_MOVIE, ts1); - dbse_exec(cam, cam->newfilename, FTYPE_MOVIE, ts1, "movie_end"); - dbse_motpls_addrec(cam, cam->newfilename, ts1); - } } if (cam->movie_motion) { + if ((cam->conf->movie_retain == "secondary") && (cam->algsec_inuse)) { + if (cam->algsec->isdetected == false) { + retcd = remove(cam->movie_motion->full_nm); + if (retcd != 0) { + MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO + , _("Unable to remove file %s") + , cam->movie_motion->full_nm); + } + } else { + event(cam, EVENT_FILECLOSE, NULL, cam->movie_motion->full_nm + , (void *)FTYPE_MOVIE_MOTION, ts1); + dbse_exec(cam, cam->movie_motion->full_nm + , FTYPE_MOVIE_MOTION, ts1, "movie_end"); + dbse_movies_addrec(cam, cam->movie_motion, ts1); + } + } else { + event(cam, EVENT_FILECLOSE, NULL, cam->movie_motion->full_nm + , (void *)FTYPE_MOVIE_MOTION, ts1); + dbse_exec(cam, cam->movie_motion->full_nm + , FTYPE_MOVIE_MOTION, ts1, "movie_end"); + dbse_movies_addrec(cam, cam->movie_motion, ts1); + } movie_close(cam->movie_motion); myfree(&cam->movie_motion); - if ((cam->conf->movie_retain == "secondary") && (cam->algsec_inuse)) { - if (cam->algsec->isdetected == false) { - retcd = remove(cam->motionfilename); - if (retcd != 0) { - MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO - , _("Unable to remove file %s"), cam->motionfilename); - } - } else { - event(cam, EVENT_FILECLOSE, NULL, cam->motionfilename, (void *)FTYPE_MOVIE_MOTION, ts1); - dbse_exec(cam, cam->motionfilename, FTYPE_MOVIE_MOTION, ts1, "movie_end"); - dbse_motpls_addrec(cam, cam->motionfilename, ts1); - } - } else { - event(cam, EVENT_FILECLOSE, NULL, cam->motionfilename, (void *)FTYPE_MOVIE_MOTION, ts1); - dbse_exec(cam, cam->motionfilename, FTYPE_MOVIE_MOTION, ts1, "movie_end"); - dbse_motpls_addrec(cam, cam->motionfilename, ts1); - } } } @@ -713,13 +723,13 @@ static void event_tlapse_start(struct ctx_cam *cam, motion_event evnt retcd = movie_init_timelapse(cam, ts1); if (retcd < 0) { MOTION_LOG(ERR, TYPE_EVENTS, NO_ERRNO - ,_("Error creating timelapse file [%s]"), cam->movie_timelapse->filename); + ,_("Error creating timelapse file [%s]"), cam->movie_timelapse->full_nm); myfree(&cam->movie_timelapse); return; } - event(cam, EVENT_FILECREATE, NULL, cam->movie_timelapse->filename + event(cam, EVENT_FILECREATE, NULL, cam->movie_timelapse->full_nm , (void *)FTYPE_MOVIE_TIMELAPSE, ts1); - dbse_exec(cam, cam->movie_timelapse->filename, FTYPE_MOVIE_TIMELAPSE + dbse_exec(cam, cam->movie_timelapse->full_nm, FTYPE_MOVIE_TIMELAPSE , ts1, "movie_start"); } @@ -739,10 +749,13 @@ static void event_tlapse_end(struct ctx_cam *cam, motion_event evnt (void)ftype; if (cam->movie_timelapse) { + event(cam, EVENT_FILECLOSE, NULL, cam->movie_timelapse->full_nm + , (void *)FTYPE_MOVIE_TIMELAPSE, ts1); + dbse_exec(cam, cam->movie_timelapse->full_nm + , FTYPE_MOVIE_TIMELAPSE, ts1, "movie_end"); movie_close(cam->movie_timelapse); myfree(&cam->movie_timelapse); - event(cam, EVENT_FILECLOSE, NULL, cam->timelapsefilename, (void *)FTYPE_MOVIE_TIMELAPSE, ts1); - dbse_exec(cam, cam->timelapsefilename, FTYPE_MOVIE_TIMELAPSE, ts1, "movie_end"); + } } diff --git a/src/logger.cpp b/src/logger.cpp index d61449ef..0c085c81 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -28,7 +28,7 @@ static FILE *logfile = NULL; static int log_level = LEVEL_DEFAULT; static int log_type = TYPE_DEFAULT; -static const char *log_type_str[] = {NULL, "COR", "STR", "ENC", "NET", "DBL", "EVT", "TRK", "VID", "ALL"}; +static const char *log_type_str[] = {NULL, "COR", "STR", "ENC", "NET", "DBS", "EVT", "TRK", "VID", "ALL"}; static const char *log_level_str[] = {NULL, "EMG", "ALR", "CRT", "ERR", "WRN", "NTC", "INF", "DBG", "ALL"}; static struct ctx_motapp *log_motapp; /*Used to access the parms mutex for updates*/ diff --git a/src/motion_loop.cpp b/src/motion_loop.cpp index f2d6b8e7..10cf38cd 100644 --- a/src/motion_loop.cpp +++ b/src/motion_loop.cpp @@ -710,10 +710,6 @@ static int mlp_init(struct ctx_cam *cam) vlp_init(cam); - dbse_init(cam); - - dbse_motpls_init(cam); - pic_init_mask(cam); pic_init_privacy(cam); @@ -789,9 +785,6 @@ void mlp_cleanup(struct ctx_cam *cam) cam->mpipe = -1; } - dbse_deinit(cam); - - dbse_motpls_deinit(cam); } /* check the area detect */ diff --git a/src/motionplus.cpp b/src/motionplus.cpp index 1fc8ebef..9c4294d6 100644 --- a/src/motionplus.cpp +++ b/src/motionplus.cpp @@ -275,7 +275,7 @@ static void motion_shutdown(struct ctx_motapp *motapp) webu_deinit(motapp); - dbse_global_deinit(motapp); + dbse_deinit(motapp); conf_deinit(motapp); @@ -416,7 +416,7 @@ static void motion_startup(struct ctx_motapp *motapp, int daemonize, int argc, c motion_camera_ids(motapp->cam_list); - dbse_global_init(motapp); + dbse_init(motapp); draw_init_chars(); @@ -487,7 +487,9 @@ static void motion_watchdog(struct ctx_motapp *motapp, int camindx) pthread_mutex_unlock(&motapp->mutex_parms); pthread_mutex_unlock(&motapp->mutex_camlst); pthread_mutex_unlock(&motapp->mutex_post); - pthread_mutex_unlock(&motapp->mutex_sqlite); + if (motapp->dbse != NULL) { + pthread_mutex_unlock(&motapp->dbse->mutex_dbse); + } pthread_mutex_unlock(&motapp->global_lock); pthread_mutex_unlock(&motapp->cam_list[indx]->stream.mutex); pthread_mutex_unlock(&motapp->cam_list[indx]->parms_lock); @@ -589,7 +591,6 @@ static void motion_init(struct ctx_motapp *motapp) pthread_mutex_init(&motapp->mutex_parms, NULL); pthread_mutex_init(&motapp->mutex_camlst, NULL); pthread_mutex_init(&motapp->mutex_post, NULL); - pthread_mutex_init(&motapp->mutex_sqlite, NULL); motapp->threads_running = 0; motapp->finish_all = false; @@ -648,9 +649,7 @@ static void motion_cam_add(struct ctx_motapp *motapp) motapp->cam_list[indx_cam]->camera_id = indx; motapp->cam_list[indx_cam]->conf->camera_id = indx; - motapp->cam_list[indx_cam]->dbse = (struct ctx_dbse *)mymalloc(sizeof(struct ctx_dbse)); motapp->cam_list[indx_cam]->conf->webcontrol_port = 0; - dbse_motpls_init(motapp->cam_list[indx_cam]); motapp->cam_add = false; @@ -677,10 +676,6 @@ static void motion_cam_delete(struct ctx_motapp *motapp) return; } - myfree(&motapp->cam_list[motapp->cam_delete]->dbse); - - dbse_motpls_deinit(motapp->cam_list[motapp->cam_delete]); - /* Delete the config context */ delete motapp->cam_list[motapp->cam_delete]->conf; delete motapp->cam_list[motapp->cam_delete]; @@ -797,7 +792,6 @@ int main (int argc, char **argv) pthread_mutex_destroy(&motapp->mutex_parms); pthread_mutex_destroy(&motapp->mutex_camlst); pthread_mutex_destroy(&motapp->mutex_post); - pthread_mutex_destroy(&motapp->mutex_sqlite); delete motapp; diff --git a/src/motionplus.hpp b/src/motionplus.hpp index 019cef2e..e25fc4ed 100644 --- a/src/motionplus.hpp +++ b/src/motionplus.hpp @@ -303,8 +303,6 @@ struct ctx_cam { struct ctx_image_data *current_image; /* Pointer to a structure where the image, diffs etc is stored */ struct ctx_algsec *algsec; struct ctx_rotate *rotate_data; /* rotation data is thread-specific */ - struct ctx_dbse *dbse; /*Multi use/type user specified database */ - struct ctx_dbsemp *dbsemp; /*Dedicated sqlite3 Motionplus database */ struct ctx_movie *movie_norm; struct ctx_movie *movie_motion; struct ctx_movie *movie_timelapse; @@ -368,12 +366,9 @@ struct ctx_cam { char hostname[PATH_MAX]; int movie_fps; - char newfilename[PATH_MAX]; char extpipefilename[PATH_MAX]; char extpipecmdline[PATH_MAX]; bool movie_passthrough; - char timelapsefilename[PATH_MAX]; - char motionfilename[PATH_MAX]; int area_minx[9], area_miny[9], area_maxx[9], area_maxy[9]; int areadetect_eventnbr; @@ -430,12 +425,12 @@ struct ctx_motapp { std::list webcontrol_clients; /* C++ list of client ips */ struct ctx_params *webcontrol_headers; /* parameters for header */ struct ctx_params *webcontrol_actions; /* parameters for actions */ + struct ctx_dbse *dbse; /* user specified database */ bool parms_changed; /*bool indicating if the parms have changed */ pthread_mutex_t mutex_parms; /* mutex used to lock when changing parms */ pthread_mutex_t mutex_camlst; /* Lock the list of cams while adding/removing */ pthread_mutex_t mutex_post; /* mutex to allow for processing of post actions*/ - pthread_mutex_t mutex_sqlite; /* mutex for database*/ }; diff --git a/src/movie.cpp b/src/movie.cpp index fcefbfca..13a66c1d 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -93,7 +93,7 @@ static int movie_timelapse_append(struct ctx_movie *movie, AVPacket *pkt) { FILE *file; - file = myfopen(movie->filename, "abe"); + file = myfopen(movie->full_nm, "abe"); if (!file) { return -1; } @@ -128,97 +128,83 @@ static void movie_free_context(struct ctx_movie *movie) static int movie_get_oformat(struct ctx_movie *movie) { - size_t container_name_len = strcspn(movie->container_name, ":"); - char *container_name =(char*) malloc(container_name_len + 1); - char basename[PATH_MAX]; - int retcd; + size_t container_name_len; + char *container_name; + int len_full, len_nm; - /* TODO: Rework the extenstion asssignment along with the code in event.c - * If extension is ever something other than three bytes, - * preceded by . then lots of things will fail - */ - if (container_name == NULL) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO - ,_("Failed to allocate memory for container name")); - movie_free_context(movie); - return -1; - } + container_name_len = strcspn(movie->container_name, ":"); + container_name =(char*) mymalloc(container_name_len + 1); memcpy(container_name, movie->container_name, container_name_len); container_name[container_name_len] = 0; - retcd = snprintf(basename,PATH_MAX,"%s",movie->filename); - if ((retcd < 0) || (retcd >= PATH_MAX)) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO - ,_("Error setting base file name")); - movie_free_context(movie); - myfree(&container_name); - return -1; - } + /* the full_nm, movie_dir, movie_nm all have an extra 10 bytes allocated + * at the end and initialized to null, so that we can just memcpy in the + * extensions + */ + len_full = strlen(movie->full_nm); + len_nm = strlen(movie->movie_nm); if (movie->tlapse == TIMELAPSE_APPEND) { - movie->oc->oformat = av_guess_format("mpeg2video", NULL, NULL); movie->oc->video_codec_id = MY_CODEC_ID_MPEG2VIDEO; - retcd = snprintf(movie->filename,PATH_MAX,"%s.mpg",basename); - if ((!movie->oc->oformat) || - (retcd < 0) || (retcd >= PATH_MAX)) { + memcpy(movie->full_nm + len_full, ".mpg", 4); + memcpy(movie->movie_nm + len_nm, ".mpg", 4); + if (movie->oc->oformat == NULL) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO ,_("Error setting timelapse append for container %s"), container_name); movie_free_context(movie); myfree(&container_name); return -1; } + myfree(&container_name); return 0; } if (mystreq(container_name, "flv")) { movie->oc->oformat = av_guess_format("flv", NULL, NULL); - retcd = snprintf(movie->filename,PATH_MAX,"%s.flv",basename); + memcpy(movie->full_nm + len_full, ".flv", 4); + memcpy(movie->movie_nm + len_nm, ".flv", 4); movie->oc->video_codec_id = MY_CODEC_ID_FLV1; } if (mystreq(container_name, "ogg")) { movie->oc->oformat = av_guess_format("ogg", NULL, NULL); - retcd = snprintf(movie->filename,PATH_MAX,"%s.ogg",basename); + memcpy(movie->full_nm + len_full, ".ogg", 4); + memcpy(movie->movie_nm + len_nm, ".ogg", 4); movie->oc->video_codec_id = MY_CODEC_ID_THEORA; } if (mystreq(container_name, "vp8")) { movie->oc->oformat = av_guess_format("webm", NULL, NULL); - retcd = snprintf(movie->filename,PATH_MAX,"%s.webm",basename); + memcpy(movie->full_nm + len_full, ".webm", 5); + memcpy(movie->movie_nm + len_nm, ".webm", 5); movie->oc->video_codec_id = MY_CODEC_ID_VP8; } if (mystreq(container_name, "mp4")) { movie->oc->oformat = av_guess_format("mp4", NULL, NULL); - retcd = snprintf(movie->filename,PATH_MAX,"%s.mp4",basename); + memcpy(movie->full_nm + len_full, ".mp4", 4); + memcpy(movie->movie_nm + len_nm, ".mp4", 4); movie->oc->video_codec_id = MY_CODEC_ID_H264; } if (mystreq(container_name, "mkv")) { movie->oc->oformat = av_guess_format("matroska", NULL, NULL); - retcd = snprintf(movie->filename,PATH_MAX,"%s.mkv",basename); + memcpy(movie->full_nm + len_full, ".mkv", 4); + memcpy(movie->movie_nm + len_nm, ".mkv", 4); movie->oc->video_codec_id = MY_CODEC_ID_H264; } if (mystreq(container_name, "hevc")) { - movie->oc->video_codec_id = MY_CODEC_ID_HEVC; + movie->oc->video_codec_id = MY_CODEC_ID_HEVC; movie->oc->oformat = av_guess_format("mp4", NULL, NULL); - retcd = snprintf(movie->filename,PATH_MAX,"%s.mp4",basename); + memcpy(movie->full_nm + len_full, ".mp4", 4); + memcpy(movie->movie_nm + len_nm, ".mp4", 4); movie->oc->video_codec_id = MY_CODEC_ID_HEVC; } - //Check for valid results - if ((retcd < 0) || (retcd >= PATH_MAX)) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO - ,_("Error setting file name")); - movie_free_context(movie); - myfree(&container_name); - return -1; - } - - if (!movie->oc->oformat) { + if (movie->oc->oformat == NULL) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO ,_("container option value %s is not supported"), container_name); movie_free_context(movie); @@ -806,7 +792,7 @@ static int movie_set_outputfile(struct ctx_movie *movie) char errstr[128]; #if (MYFFVER < 58000) - retcd = snprintf(movie->oc->filename, sizeof(movie->oc->filename), "%s", movie->filename); + retcd = snprintf(movie->oc->full_nm, sizeof(movie->oc->full_nm), "%s", movie->full_nm); if ((retcd < 0) || (retcd >= PATH_MAX)) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO ,_("Error setting file name")); @@ -815,33 +801,33 @@ static int movie_set_outputfile(struct ctx_movie *movie) #endif /* Open the output file, if needed. */ - if ((movie_timelapse_exists(movie->filename) == 0) || (movie->tlapse != TIMELAPSE_APPEND)) { + if ((movie_timelapse_exists(movie->full_nm) == 0) || (movie->tlapse != TIMELAPSE_APPEND)) { clock_gettime(CLOCK_MONOTONIC, &movie->cb_st_ts); - retcd = avio_open(&movie->oc->pb, movie->filename, MY_FLAG_WRITE|AVIO_FLAG_NONBLOCK); + retcd = avio_open(&movie->oc->pb, movie->full_nm, MY_FLAG_WRITE|AVIO_FLAG_NONBLOCK); if (retcd < 0) { av_strerror(retcd, errstr, sizeof(errstr)); MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO ,_("avio_open: %s File %s") - , errstr, movie->filename); + , errstr, movie->full_nm); if (errno == ENOENT) { - if (mycreate_path(movie->filename) == -1) { + if (mycreate_path(movie->full_nm) == -1) { movie_free_context(movie); return -1; } clock_gettime(CLOCK_MONOTONIC, &movie->cb_st_ts); - retcd = avio_open(&movie->oc->pb, movie->filename, MY_FLAG_WRITE| AVIO_FLAG_NONBLOCK); + retcd = avio_open(&movie->oc->pb, movie->full_nm, MY_FLAG_WRITE| AVIO_FLAG_NONBLOCK); if (retcd < 0) { av_strerror(retcd, errstr, sizeof(errstr)); MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO ,_("error %s opening file %s") - , errstr, movie->filename); + , errstr, movie->full_nm); movie_free_context(movie); return -1; } } else { MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO ,_("Error opening file %s") - , movie->filename); + , movie->full_nm); movie_free_context(movie); return -1; } @@ -1547,6 +1533,15 @@ void movie_free(struct ctx_movie *movie) if (movie != NULL) { movie_free_context(movie); movie_free_nal(movie); + if (movie->movie_nm != NULL) { + free(movie->movie_nm); + } + if (movie->movie_dir != NULL) { + free(movie->movie_dir); + } + if (movie->full_nm != NULL) { + free(movie->full_nm); + } } } @@ -1691,23 +1686,38 @@ static const char* movie_init_container(struct ctx_cam *cam) int movie_init_norm(struct ctx_cam *cam, struct timespec *ts1) { - char stamp[PATH_MAX]; + char tmp[PATH_MAX]; const char *container; - int retcd; + int retcd, len; - mystrftime(cam, stamp, sizeof(stamp), cam->conf->movie_filename.c_str(), ts1, NULL, 0); + cam->movie_norm =(struct ctx_movie*) mymalloc(sizeof(struct ctx_movie)); + + mystrftime(cam, tmp, sizeof(tmp) + , cam->conf->movie_filename.c_str(), ts1, NULL, 0); container = movie_init_container(cam); - cam->movie_norm =(struct ctx_movie*) mymalloc(sizeof(struct ctx_movie)); + /* The increment of 10 is to allow for the extension and other chars*/ + len = strlen(tmp) + cam->conf->target_dir.length() + 10; + cam->movie_norm->full_nm = (char*)mymalloc(len); if (mystreq(container, "test")) { - retcd = snprintf(cam->movie_norm->filename, PATH_MAX, "%s/%s_%s" - , cam->conf->target_dir.c_str(), container, stamp); + retcd = snprintf(cam->movie_norm->full_nm, len, "%s/%s_%s" + , cam->conf->target_dir.c_str(), container, tmp); } else { - retcd = snprintf(cam->movie_norm->filename, PATH_MAX, "%s/%s" - , cam->conf->target_dir.c_str(), stamp); + retcd = snprintf(cam->movie_norm->full_nm, len, "%s/%s" + , cam->conf->target_dir.c_str(), tmp); } - if ((retcd < 0) || (retcd >= PATH_MAX)) { + + len = cam->conf->target_dir.length() + 10; + cam->movie_norm->movie_dir = (char*)mymalloc(len); + retcd = snprintf(cam->movie_norm->movie_dir,len,"%s" + ,cam->conf->target_dir.c_str()); + + len = strlen(tmp) + 10; + cam->movie_norm->movie_nm = (char*)mymalloc(len); + retcd = snprintf(cam->movie_norm->movie_nm, len, "%s", tmp); + + if (retcd < 0) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO ,_("Error setting file name")); return -1; @@ -1744,38 +1754,43 @@ int movie_init_norm(struct ctx_cam *cam, struct timespec *ts1) retcd = movie_open(cam->movie_norm); - if (retcd == 0) { - /* We set this after the movie open so we get the extension */ - retcd = snprintf(cam->newfilename, PATH_MAX, "%s",cam->movie_norm->filename); - if ((retcd < 0) || (retcd >= PATH_MAX)) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO - ,_("Error setting file name")); - return -1; - } - } - return retcd; } int movie_init_motion(struct ctx_cam *cam, struct timespec *ts1) { - char stamp[PATH_MAX]; + char tmp[PATH_MAX]; const char *container; - int retcd; - - mystrftime(cam, stamp, sizeof(stamp), cam->conf->movie_filename.c_str(), ts1, NULL, 0); - container = movie_init_container(cam); + int retcd, len; cam->movie_motion =(struct ctx_movie*)mymalloc(sizeof(struct ctx_movie)); + + mystrftime(cam, tmp, sizeof(tmp) + , cam->conf->movie_filename.c_str(), ts1, NULL, 0); + container = movie_init_container(cam); + + /* The increment of 10 is to allow for the extension and other chars*/ + len = strlen(tmp) + cam->conf->target_dir.length() + 10; + cam->movie_norm->full_nm = (char*)mymalloc(len); if (mystreq(container, "test")) { - retcd = snprintf(cam->movie_motion->filename, PATH_MAX, "%s/%s_%sm" - , cam->conf->target_dir.c_str(), container, stamp); + retcd = snprintf(cam->movie_motion->full_nm, len, "%s/%s_%sm" + , cam->conf->target_dir.c_str(), container, tmp); } else { - retcd = snprintf(cam->movie_motion->filename, PATH_MAX, "%s/%sm" - , cam->conf->target_dir.c_str(), stamp); + retcd = snprintf(cam->movie_motion->full_nm, len, "%s/%sm" + , cam->conf->target_dir.c_str(), tmp); } - if ((retcd < 0) || (retcd >= PATH_MAX)) { + + len = cam->conf->target_dir.length() + 10; + cam->movie_norm->movie_dir = (char*)mymalloc(len); + retcd = snprintf(cam->movie_norm->movie_dir,len,"%s" + ,cam->conf->target_dir.c_str()); + + len = strlen(tmp) + 10; + cam->movie_norm->movie_nm = (char*)mymalloc(len); + retcd = snprintf(cam->movie_norm->movie_nm, len, "%s", tmp); + + if (retcd < 0) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO ,_("Error setting file name")); return -1; @@ -1806,15 +1821,6 @@ int movie_init_motion(struct ctx_cam *cam, struct timespec *ts1) retcd = movie_open(cam->movie_motion); - if (retcd == 0) { - retcd = snprintf(cam->motionfilename, PATH_MAX, "%s",cam->movie_motion->filename); - if ((retcd < 0) || (retcd >= PATH_MAX)) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO - ,_("Error setting file name")); - return -1; - } - } - return retcd; } @@ -1824,14 +1830,28 @@ int movie_init_timelapse(struct ctx_cam *cam, struct timespec *ts1) char tmp[PATH_MAX]; const char *container_mpg = "mpg"; const char *container_mkv = "mkv"; - int retcd; + int retcd, len; cam->movie_timelapse =(struct ctx_movie*)mymalloc(sizeof(struct ctx_movie)); - mystrftime(cam, tmp, sizeof(tmp), cam->conf->timelapse_filename.c_str(), ts1, NULL, 0); + mystrftime(cam, tmp, sizeof(tmp) + , cam->conf->timelapse_filename.c_str(), ts1, NULL, 0); - retcd = snprintf(cam->movie_timelapse->filename, PATH_MAX, "%s/%s" + /* The increment of 10 is to allow for the extension and other chars*/ + len = strlen(tmp) + cam->conf->target_dir.length() + 10; + cam->movie_norm->full_nm = (char*)mymalloc(len); + retcd = snprintf(cam->movie_timelapse->full_nm, len, "%s/%s" , cam->conf->target_dir.c_str(), tmp); - if (retcd > PATH_MAX) { + + len = cam->conf->target_dir.length() + 10; + cam->movie_norm->movie_dir = (char*)mymalloc(len); + retcd = snprintf(cam->movie_norm->movie_dir,len,"%s" + ,cam->conf->target_dir.c_str()); + + len = strlen(tmp) + 10; + cam->movie_norm->movie_nm = (char*)mymalloc(len); + retcd = snprintf(cam->movie_norm->movie_nm, len, "%s", tmp); + + if (retcd < 0) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO , _("Error setting timelapse file name %s"), tmp); } @@ -1875,15 +1895,6 @@ int movie_init_timelapse(struct ctx_cam *cam, struct timespec *ts1) retcd = movie_open(cam->movie_timelapse); } - if (retcd == 0) { - retcd = snprintf(cam->timelapsefilename, PATH_MAX, "%s",cam->movie_timelapse->filename); - if ((retcd < 0) || (retcd >= PATH_MAX)) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO - ,_("Error setting file name")); - return -1; - } - } - return retcd; } diff --git a/src/movie.hpp b/src/movie.hpp index b02fbf49..ec54f37a 100644 --- a/src/movie.hpp +++ b/src/movie.hpp @@ -60,7 +60,9 @@ struct ctx_movie { enum TIMELAPSE_TYPE tlapse; int fps; int bps; - char filename[PATH_MAX]; + char *movie_nm; + char *movie_dir; + char *full_nm; int quality; const char *container_name; int64_t last_pts; diff --git a/src/webu_file.cpp b/src/webu_file.cpp index 01f39ae8..3f29e7e4 100644 --- a/src/webu_file.cpp +++ b/src/webu_file.cpp @@ -54,14 +54,12 @@ mhdrslt webu_file_main(struct ctx_webui *webui) struct ctx_params *wact; /*If we have not fully started yet, simply return*/ - if (webui->cam->dbsemp == NULL) { + if (webui->cam->motapp->dbse == NULL) { return MHD_NO; } - if (webui->cam->dbsemp->movie_cnt == 0) { - if (dbse_motpls_getlist(webui->cam) != 0) { - return MHD_NO; - } + if (webui->cam->motapp->dbse->movie_cnt == 0) { + dbse_movies_getlist(webui->cam->motapp); } wact = webui->motapp->webcontrol_actions; @@ -77,10 +75,10 @@ mhdrslt webu_file_main(struct ctx_webui *webui) } full_nm = ""; - for (indx=0; indx < webui->cam->dbsemp->movie_cnt; indx++) { - if (mystreq(webui->cam->dbsemp->movie_list[indx].movie_nm + for (indx=0; indx < webui->cam->motapp->dbse->movie_cnt; indx++) { + if (mystreq(webui->cam->motapp->dbse->movie_list[indx].movie_nm , webui->uri_cmd2.c_str())) { - full_nm = webui->cam->dbsemp->movie_list[indx].full_nm; + full_nm = webui->cam->motapp->dbse->movie_list[indx].full_nm; } } diff --git a/src/webu_json.cpp b/src/webu_json.cpp index 5d8c440d..81ce9678 100644 --- a/src/webu_json.cpp +++ b/src/webu_json.cpp @@ -283,14 +283,13 @@ void webu_json_config(struct ctx_webui *webui) static void webu_json_movies_list(struct ctx_webui *webui) { int indx_mov, indx_cam, indx; - int movie_cnt, retcd, skip; + int movie_cnt, skip; std::string response; char fmt[PATH_MAX]; ctx_cam *cam; - ctx_dbsemp_rec db; + ctx_dbse_rec db; struct ctx_params *wact; - /* Get the count */ indx_cam = 0; while (webui->motapp->cam_list[indx_cam] != NULL) { @@ -316,16 +315,16 @@ static void webu_json_movies_list(struct ctx_webui *webui) indx_cam = 1; while (webui->motapp->cam_list[indx_cam] != NULL) { cam =webui->motapp->cam_list[indx_cam]; - retcd = dbse_motpls_getlist(cam); + dbse_movies_getlist(cam->motapp); webui->resp_page += ",\""+ std::to_string(indx_cam) + "\":"; - if ((retcd !=0) || (skip ==1)) { + if (skip == 1) { webui->resp_page += "{\"count\" : 0} "; } else { - movie_cnt = cam->dbsemp->movie_cnt; + movie_cnt = cam->motapp->dbse->movie_cnt; webui->resp_page += "{\"count\" : " + std::to_string(movie_cnt); for (indx_mov=0; indx_mov < movie_cnt; indx_mov++) { - db = cam->dbsemp->movie_list[indx_mov]; + db = cam->motapp->dbse->movie_list[indx_mov]; if ((db.movie_sz/1000) < 1000) { snprintf(fmt,PATH_MAX,"%'.1fKB" ,((double)db.movie_sz/1000));