removed old code.

aqhome-storage has long been incorporated into aqhome-data.
This commit is contained in:
Martin Preuss
2026-03-01 21:47:44 +01:00
parent 1be66e6c7a
commit d8558015b2
46 changed files with 0 additions and 5572 deletions

View File

@@ -1 +0,0 @@
test/

View File

@@ -1,107 +0,0 @@
<?xml?>
<gwbuild>
<target type="Program" name="aqhome-storage" install="$(bindir)" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
-I$(builddir)
-I$(srcdir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags" >
</setVar>
<setVar name="local/typefiles" >
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="true" >
aqhomestorage_p.h
aqhomestorage.h
init.h
init_http.h
init_mqtt.h
fini.h
loop.h
loop_http.h
loop_mqtt.h
cleanup.h
u_base.h
u_login.h
u_objects.h
u_objects_p.h
u_rooms.h
u_devices.h
u_mqtttopics.h
u_values.h
u_static.h
u_static_p.h
aqhomehttp.h
aqhomehttp_p.h
</headers>
<sources>
$(local/typefiles)
aqhomestorage.c
init.c
init_http.c
init_mqtt.c
fini.c
loop.c
loop_http.c
loop_mqtt.c
cleanup.c
u_base.c
u_login.c
u_objects.c
u_rooms.c
u_devices.c
u_mqtttopics.c
u_values.c
u_static.c
main.c
aqhomehttp.c
</sources>
<useTargets>
aqhome
</useTargets>
<libraries>
$(gwenhywfar_libs)
</libraries>
<subdirs>
</subdirs>
<extradist>
</extradist>
</target>
</gwbuild>

View File

@@ -1,68 +0,0 @@
TODO
- isolate storage service:
- remove http service from here
- add ipc service
- admin:
- add room/device/MQTT topic/value
- edit room/device/MQTT topic/value
- del room/device/MQTT topic/value
- get received topics
- list rooms/devices/MQTT topics/values
- getValues(valueId, timeFrom, timeUntil)
- addValue(valueId/valueName, timeStamp, value)
- aqhome-tool
- add ipc admin code to connect to ipc service
- create http service as stand-alone app or create PHP code which uses aqhome-tool
- connect to storage service for information/admin
- move http service into own folder
- isolate functions:
- getRoomList
- getDeviceList
- getTopicList
- addRoom/Device/Topic/Value
- delRoom/Device/Topic/Value
- editRoom/Device/Topic/Value
- aqhome-storage->aqhome-data
- aqhome-data
- only list of values
- manages datafiles only
- IPC (later secure ipc):
- get value list
- add value
- del value
- edit value
- add datapoint(valueId, timestamp, data)
- add datapoint(valueName, timestamp, data)
- getData(valueId, timeFrom, timeUntil)
- getLastData(valueId)
- aqhome-tool:
- add ipc code
- aqhome-mqttdata:
- use devices, topics and values from aqhome-storage
- derive valueid and data from mqtt messages
- send data to aqhome-data via ipc (later secure ipc)
- mqtt values:
- aliases (e.g. for doors: open=1.0, closed=0.0, tilted=0.5)
- later services only:
- aqhomed (tty, ipcd)
- aqhome-data (ipcd)
- aqhome-mqtt (mqttc, ipcd)
- aqhome-httpd (maybe; httpd, ipcc)

View File

@@ -1,191 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./aqhomehttp_p.h"
#include "aqhome/http/httpservice.h"
#include "aqhome/http/httpservice_http.h"
#include <gwenhywfar/db.h>
#include <gwenhywfar/buffer.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
GWEN_INHERIT(AQH_SERVICE, AQHOME_HTTP)
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeHttpService_Extend(AQH_SERVICE *sv)
{
AQHOME_HTTP *xsv;
GWEN_NEW_OBJECT(AQHOME_HTTP, xsv);
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQHOME_HTTP, sv, xsv, _freeData);
xsv->contentTree=AQH_HttpContent_new("root");
xsv->storageMutex=GWEN_Mutex_new();
}
void _freeData(void *bp, void *p)
{
AQHOME_HTTP *xsv;
xsv=(AQHOME_HTTP*) p;
xsv->storage=NULL;
AQH_HttpContent_free(xsv->contentTree);
xsv->contentTree=NULL;
GWEN_Mutex_free(xsv->storageMutex);
GWEN_FREE_OBJECT(xsv);
}
AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv)
{
if (sv) {
AQHOME_HTTP *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
if (xsv)
return xsv->storage;
}
return NULL;
}
void AqHomeHttpService_SetStorage(AQH_SERVICE *sv, AQH_STORAGE *sto)
{
if (sv) {
AQHOME_HTTP *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
if (xsv)
xsv->storage=sto;
}
}
AQH_HTTP_CONTENT *AqHomeHttpService_GetContentTree(const AQH_SERVICE *sv)
{
if (sv) {
AQHOME_HTTP *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
if (xsv)
return xsv->contentTree;
}
return NULL;
}
void AqHomeHttpService_SetContentTree(AQH_SERVICE *sv, AQH_HTTP_CONTENT *c)
{
if (sv) {
AQHOME_HTTP *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
if (xsv) {
AQH_HttpContent_free(xsv->contentTree);
xsv->contentTree=c;
}
}
}
void AqHomeHttpService_MarkStorageChanged(AQH_SERVICE *sv)
{
if (sv) {
AQHOME_HTTP *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
if (xsv) {
AQH_Storage_AddRuntimeFlags(xsv->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
}
}
}
int AqHomeHttpService_LockStorage(AQH_SERVICE *sv)
{
if (sv) {
AQHOME_HTTP *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
if (xsv) {
int rv;
rv=GWEN_Mutex_Lock(xsv->storageMutex);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on storage mutex");
return rv;
}
return 0;
}
}
return GWEN_ERROR_GENERIC;
}
int AqHomeHttpService_UnlockStorage(AQH_SERVICE *sv)
{
if (sv) {
AQHOME_HTTP *xsv;
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
if (xsv) {
int rv;
rv=GWEN_Mutex_Unlock(xsv->storageMutex);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on storage mutex");
return rv;
}
return 0;
}
}
return GWEN_ERROR_GENERIC;
}

View File

@@ -1,59 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_HTTP_H
#define AQHOME_HTTP_H
#include "aqhome/service/service.h"
#include "aqhome/data/storage.h"
#include "aqhome/http/content.h"
#include <gwenhywfar/endpoint.h>
#define AQHOME_HTTP_PERMS_LIST_ROOMS 0x00000001
#define AQHOME_HTTP_PERMS_LIST_DEVICES 0x00000002
#define AQHOME_HTTP_PERMS_LIST_VALUES 0x00000004
#define AQHOME_HTTP_PERMS_LIST_TOPICS 0x00000008
#define AQHOME_HTTP_PERMS_ADD_ROOM 0x00000100
#define AQHOME_HTTP_PERMS_ADD_DEVICE 0x00000200
#define AQHOME_HTTP_PERMS_ADD_VALUE 0x00000400
#define AQHOME_HTTP_PERMS_ADD_TOPIC 0x00000800
#define AQHOME_HTTP_PERMS_DEL_ROOM 0x00010000
#define AQHOME_HTTP_PERMS_DEL_DEVICE 0x00020000
#define AQHOME_HTTP_PERMS_DEL_VALUE 0x00040000
#define AQHOME_HTTP_PERMS_DEL_TOPIC 0x00080000
#define AQHOME_HTTP_PERMS_EDIT_ROOM 0x01000000
#define AQHOME_HTTP_PERMS_EDIT_DEVICE 0x02000000
#define AQHOME_HTTP_PERMS_EDIT_VALUE 0x04000000
#define AQHOME_HTTP_PERMS_EDIT_TOPIC 0x08000000
void AqHomeHttpService_Extend(AQH_SERVICE *sv);
AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv);
void AqHomeHttpService_SetStorage(AQH_SERVICE *sv, AQH_STORAGE *sto);
AQH_HTTP_CONTENT *AqHomeHttpService_GetContentTree(const AQH_SERVICE *sv);
void AqHomeHttpService_SetContentTree(AQH_SERVICE *sv, AQH_HTTP_CONTENT *c);
int AqHomeHttpService_LockStorage(AQH_SERVICE *sv);
int AqHomeHttpService_UnlockStorage(AQH_SERVICE *sv);
void AqHomeHttpService_MarkStorageChanged(AQH_SERVICE *sv);
#endif

View File

@@ -1,31 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_HTTP_P_H
#define AQHOME_HTTP_P_H
#include "./aqhomehttp.h"
#include <gwenhywfar/mutex.h>
typedef struct AQHOME_HTTP AQHOME_HTTP;
struct AQHOME_HTTP {
AQH_STORAGE *storage; /* do not release */
GWEN_MUTEX *storageMutex;
AQH_HTTP_CONTENT *contentTree;
};
#endif

View File

@@ -1,126 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./aqhomestorage_p.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
AQHOME_STORAGE *AqHomeStorage_new()
{
AQHOME_STORAGE *aqh;
GWEN_NEW_OBJECT(AQHOME_STORAGE, aqh);
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
return aqh;
}
void AqHomeStorage_free(AQHOME_STORAGE *aqh)
{
if (aqh) {
AQH_Service_free(aqh->httpService);
aqh->httpService=NULL;
AQH_Storage_free(aqh->storage);
aqh->storage=NULL;
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
aqh->rootEndpoint=NULL;
aqh->ipcdEndpoint=NULL;
aqh->mqttEndpoint=NULL;
aqh->httpdEndpoint=NULL;
GWEN_DB_Group_free(aqh->dbArgs);
aqh->dbArgs=NULL;
free(aqh->pidFile);
GWEN_FREE_OBJECT(aqh);
}
}
GWEN_MSG_ENDPOINT *AqHomeStorage_GetRootEndpoint(const AQHOME_STORAGE *aqh)
{
return aqh?(aqh->rootEndpoint):NULL;
}
GWEN_MSG_ENDPOINT *AqHomeStorage_GetIpcdEndpoint(const AQHOME_STORAGE *aqh)
{
return aqh?(aqh->ipcdEndpoint):NULL;
}
GWEN_MSG_ENDPOINT *AqHomeStorage_GetMqttEndpoint(const AQHOME_STORAGE *aqh)
{
return aqh?(aqh->mqttEndpoint):NULL;
}
GWEN_MSG_ENDPOINT *AqHomeStorage_GetHttpdEndpoint(const AQHOME_STORAGE *aqh)
{
return aqh?(aqh->httpdEndpoint):NULL;
}
GWEN_DB_NODE *AqHomeStorage_GetDbArgs(const AQHOME_STORAGE *aqh)
{
return aqh?(aqh->dbArgs):NULL;
}
AQH_STORAGE *AqHomeStorage_GetStorage(const AQHOME_STORAGE *aqh)
{
return aqh?(aqh->storage):NULL;
}
const char *AqHomeStorage_GetPidFile(const AQHOME_STORAGE *aqh)
{
return aqh?aqh->pidFile:NULL;
}
void AqHomeStorage_SetPidFile(AQHOME_STORAGE *aqh, const char *s)
{
if (aqh) {
free(aqh->pidFile);
aqh->pidFile=s?strdup(s):NULL;
}
}
int AqHomeStorage_GetTimeout(const AQHOME_STORAGE *aqh)
{
return aqh?aqh->timeout:0;
}

View File

@@ -1,42 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_H
#define AQHOME_STORAGE_H
#include "aqhome/data/storage.h"
#include "aqhome/service/session.h"
#include "aqhome/http/httpservice.h"
#include <gwenhywfar/endpoint.h>
typedef struct AQHOME_STORAGE AQHOME_STORAGE;
AQHOME_STORAGE *AqHomeStorage_new();
void AqHomeStorage_free(AQHOME_STORAGE *aqh);
GWEN_MSG_ENDPOINT *AqHomeStorage_GetRootEndpoint(const AQHOME_STORAGE *aqh);
GWEN_MSG_ENDPOINT *AqHomeStorage_GetIpcdEndpoint(const AQHOME_STORAGE *aqh);
GWEN_MSG_ENDPOINT *AqHomeStorage_GetMqttEndpoint(const AQHOME_STORAGE *aqh);
GWEN_MSG_ENDPOINT *AqHomeStorage_GetHttpdEndpoint(const AQHOME_STORAGE *aqh);
GWEN_DB_NODE *AqHomeStorage_GetDbArgs(const AQHOME_STORAGE *aqh);
AQH_STORAGE *AqHomeStorage_GetStorage(const AQHOME_STORAGE *aqh);
const char *AqHomeStorage_GetPidFile(const AQHOME_STORAGE *aqh);
void AqHomeStorage_SetPidFile(AQHOME_STORAGE *aqh, const char *s);
int AqHomeStorage_GetTimeout(const AQHOME_STORAGE *aqh);
#endif

View File

@@ -1,59 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_P_H
#define AQHOME_STORAGE_P_H
#include "./aqhomestorage.h"
/* default values */
#define AQHOME_STORAGE_DEFAULT_PIDFILE "/var/run/aqhome-storage.pid"
#define AQHOME_STORAGE_DEFAULT_IPC_PORT 45455
#define AQHOME_STORAGE_DEFAULT_HTTP_PORT 45456
#define AQHOME_STORAGE_DEFAULT_MQTT_CLIENTID "AQHOMESTORAGE"
#define AQHOME_STORAGE_DEFAULT_MQTT_KEEPALIVE 600
#define AQHOME_STORAGE_DEFAULT_MQTT_PORT 1883
#define AQHOME_STORAGE_DEFAULT_CONFIGDIR "/var/lib/aqhomestorage/config"
#define AQHOME_STORAGE_DEFAULT_HTTP_SOURCEDIR "/var/lib/aqhomestorage/html"
#define AQHOME_STORAGE_DEFAULT_DATADIR "/var/lib/aqhomestorage/data"
#define AQHOME_STORAGE_DEFAULT_STATEFILE "/var/lib/aqhomestorage/config/statefile"
#define AQHOME_STORAGE_DEFAULT_MAXSESSIONAGE (30*60)
#define AQHOME_STORAGE_SITEHEADER "site-header.html"
#define AQHOME_STORAGE_SITEFOOTER "site-footer.html"
#define AQHOME_STORAGE_STATIC_RELFOLDER "static"
struct AQHOME_STORAGE {
GWEN_MSG_ENDPOINT *rootEndpoint;
GWEN_MSG_ENDPOINT *ipcdEndpoint; /* don't release, will be released by freeing rootEndpoint! */
GWEN_MSG_ENDPOINT *mqttEndpoint; /* don't release, will be released by freeing rootEndpoint! */
GWEN_MSG_ENDPOINT *httpdEndpoint; /* don't release, will be released by freeing rootEndpoint! */
GWEN_DB_NODE *dbArgs;
AQH_SERVICE *httpService;
AQH_STORAGE *storage;
char *pidFile;
int maxSessionAgeInSeconds;
int timeout; /* timeout for run e.g. inside valgrind */
};
#endif

View File

@@ -1,61 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./cleanup.h"
#include "./aqhomehttp.h"
#include "./aqhomestorage_p.h"
#include "aqhome/http/httpservice_conf.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeStorage_Cleanup(AQHOME_STORAGE *aqh)
{
int rv;
rv=AQH_HttpService_CleanupSessions(aqh->httpService, aqh->maxSessionAgeInSeconds);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
}
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_CLEANUP_H
#define AQHOME_STORAGE_CLEANUP_H
#include "./aqhomestorage.h"
void AqHomeStorage_Cleanup(AQHOME_STORAGE *aqh);
#endif

View File

@@ -1,83 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./fini.h"
#include "./aqhomestorage_p.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <unistd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeStorage_Fini(AQHOME_STORAGE *aqh)
{
if (aqh) {
if (aqh->rootEndpoint) {
_disconnectTree(aqh->rootEndpoint);
GWEN_MsgEndpoint_Disconnect(aqh->rootEndpoint);
}
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
aqh->rootEndpoint=NULL;
aqh->ipcdEndpoint=NULL;
aqh->httpdEndpoint=NULL;
aqh->mqttEndpoint=NULL;
if (aqh->pidFile)
remove(aqh->pidFile);
}
}
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
{
GWEN_MSG_ENDPOINT *epChild;
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
while(epChild) {
_disconnectTree(epChild);
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
} /* while */
GWEN_MsgEndpoint_Disconnect(ep);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_FINI_H
#define AQHOME_STORAGE_FINI_H
#include "./aqhomestorage.h"
void AqHomeStorage_Fini(AQHOME_STORAGE *aqh);
#endif

View File

@@ -1,5 +0,0 @@
</body>
</html>

View File

@@ -1,16 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<!-- copyright (c) 2023 by martin -->
<meta name="generator" content="FTE 1.1" />
<meta name="revised" content="martin,2023-07-23" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="author" content="martin" />
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<title>AqHome Storage Service</title>
</head>
<body>

View File

@@ -1,506 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./init.h"
#include "./init_http.h"
#include "./init_mqtt.h"
#include "./aqhomestorage_p.h"
#include "./aqhomehttp.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include "aqhome/http/endpoint_http.h"
#include "aqhome/http/httpservice_conf.h"
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_msgio.h>
#include <gwenhywfar/directory.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
//#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _setupFolders(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
static int _setupStorage(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
static void _setupIpc(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
static int _createPidFile(const char *pidFilename);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomeStorage_Init(AQHOME_STORAGE *aqh, int argc, char **argv)
{
GWEN_DB_NODE *dbArgs;
int rv;
const char *s;
dbArgs=GWEN_DB_Group_new("args");
rv=_readArgs(argc, argv, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error reading args (%d)", rv);
return rv;
}
aqh->dbArgs=dbArgs;
aqh->maxSessionAgeInSeconds=GWEN_DB_GetIntValue(dbArgs, "maxSessionAge", 0, AQHOME_STORAGE_DEFAULT_MAXSESSIONAGE);
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_STORAGE_DEFAULT_PIDFILE);
if (s && *s) {
AqHomeStorage_SetPidFile(aqh, s);
rv=_createPidFile(s);
if (rv<0) {
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
return rv;
}
}
rv=_setupFolders(aqh, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_setupStorage(aqh, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
_setupIpc(aqh, dbArgs);
rv=AqHomeStorage_SetupMqtt(aqh, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=AqHomeStorage_SetupHttp(aqh, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return 0;
}
int _setupFolders(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
const char *s;
GWEN_BUFFER *nameBuf;
int pos;
int rv;
s=GWEN_DB_GetCharValue(dbArgs, "cfgdir", 0, AQHOME_STORAGE_DEFAULT_CONFIGDIR);
if (!(s && *s)) {
DBG_ERROR(NULL, "Missing configuration folder");
return GWEN_ERROR_GENERIC;
}
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(nameBuf, s);
pos=GWEN_Buffer_GetPos(nameBuf);
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
if (rv<0) {
DBG_ERROR(NULL, "Error accessing configuration folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
GWEN_Buffer_free(nameBuf);
return GWEN_ERROR_GENERIC;
}
GWEN_Buffer_Crop(nameBuf, 0, pos);
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S "modules");
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
if (rv<0) {
DBG_ERROR(NULL, "Error accessing modules folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
GWEN_Buffer_free(nameBuf);
return GWEN_ERROR_GENERIC;
}
GWEN_Buffer_Crop(nameBuf, 0, pos);
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S "users");
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
if (rv<0) {
DBG_ERROR(NULL, "Error accessing configuration folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
GWEN_Buffer_free(nameBuf);
return GWEN_ERROR_GENERIC;
}
GWEN_Buffer_free(nameBuf);
return 0;
}
int _setupStorage(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
const char *dataFolder;
const char *stateFile;
dataFolder=GWEN_DB_GetCharValue(dbArgs, "dataFolder", 0, AQHOME_STORAGE_DEFAULT_DATADIR);
stateFile=GWEN_DB_GetCharValue(dbArgs, "stateFile", 0, NULL);
if (stateFile && *stateFile) {
AQH_STORAGE *sto;
int rv;
sto=AQH_Storage_new();
AQH_Storage_SetStateFile(sto, stateFile);
AQH_Storage_SetDataFileFolder(sto, (dataFolder && *dataFolder)?dataFolder:NULL);
rv=AQH_Storage_Init(sto);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
AQH_Storage_free(sto);
return rv;
}
aqh->storage=sto;
}
else {
DBG_ERROR(NULL, "No state file given");
return GWEN_ERROR_GENERIC;
}
return 0;
}
void _setupIpc(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
const char *tcpAddress;
int tcpPort;
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, AQHOME_STORAGE_DEFAULT_IPC_PORT);
if (tcpAddress && *tcpAddress && tcpPort) {
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh);
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
aqh->ipcdEndpoint=ep;
}
}
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep,
GWEN_SOCKET *sk,
const GWEN_INETADDRESS *addr,
GWEN_UNUSED void *data)
{
/* AQHOME_STORAGE *aqh;
*
* aqh=(AQHOME_STORAGE*) data;
*/
DBG_INFO(NULL, "Incoming IPC connection");
return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, 0);
}
int _createPidFile(const char *pidFilename)
{
FILE *f;
int pidfd;
if (remove(pidFilename)==0) {
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
}
#ifdef HAVE_SYS_STAT_H
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (pidfd < 0) {
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
f = fdopen(pidfd, "w");
#else /* HAVE_STAT_H */
f=fopen(pidFilename,"w+");
#endif /* HAVE_STAT_H */
/* write pid */
#ifdef HAVE_GETPID
fprintf(f,"%d\n",getpid());
#else
fprintf(f,"-1\n");
#endif
if (fclose(f)) {
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
return 0;
}
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
{
int rv;
const GWEN_ARGS args[]= {
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"cfgdir", /* name */
0, /* minnum */
1, /* maxnum */
"D", /* short option */
"cfgdir", /* long option */
I18S("Specify the configuration folder"),
I18S("Specify the configuration folder")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"tcpAddress", /* name */
0, /* minnum */
1, /* maxnum */
"t", /* short option */
"tcpaddress", /* long option */
I18S("Specify the TCP address to listen on (disabled if missing)"),
I18S("Specify the TCP address to listen on (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"tcpPort", /* name */
0, /* minnum */
1, /* maxnum */
"P", /* short option */
"tcpport", /* long option */
I18S("Specify the TCP port to listen on"),
I18S("Specify the TCP port to listen on")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"mqttAddress", /* name */
0, /* minnum */
1, /* maxnum */
"ma", /* short option */
"mqttaddress", /* long option */
I18S("Specify the address of the MQTT server to connect to (disabled if missing)"),
I18S("Specify the address of the MQTT server to connect to (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"mqttPort", /* name */
0, /* minnum */
1, /* maxnum */
"mp", /* short option */
"mqttport", /* long option */
I18S("Specify the port of the MQTT server (default: 1883)"),
I18S("Specify the port of the MQTT server (default: 1883)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"mqttClientId", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"mqttclientid", /* long option */
I18S("Specify client id for the MQTT server (default: \"AQHOMESTORAGE\")"),
I18S("Specify client id for the MQTT server (default: \"AQHOMESTORAGE\")")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"mqttKeepAlive", /* name */
0, /* minnum */
1, /* maxnum */
"mk", /* short option */
"mqttkeepalive", /* long option */
I18S("Specify keepalive time in seconds (defaults: 600)"),
I18S("Specify keepalive time in seconds (defaults: 600)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"httpAddress", /* name */
0, /* minnum */
1, /* maxnum */
"ha", /* short option */
"httpaddress", /* long option */
I18S("Specify the address to bind the http service to (disabled if missing)"),
I18S("Specify the address to bind the http service to (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"httpPort", /* name */
0, /* minnum */
1, /* maxnum */
"hp", /* short option */
"httpport", /* long option */
I18S("Specify the port to listen on for HTTP connections"),
I18S("Specify the port to listen on for HTTP connections")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"maxSessionAge", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"maxsessionage", /* long option */
I18S("Specify maximum session age in seconds (default: 30mins)"),
I18S("Specify maximum session age in seconds (default: 30mins)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"sourcefolder", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"sourcefolder", /* long option */
I18S("Folder where static HTML source files are stored"),
I18S("Folder where static HTML source files are stored")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"datafolder", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"datafolder", /* long option */
I18S("Folder where data files are stored"),
I18S("Folder where data files are stored")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"statefile", /* name */
0, /* minnum */
1, /* maxnum */
"S", /* short option */
"statefile", /* long option */
I18S("File where rooms, devices and values etc. are stored"),
I18S("File where rooms, devices and values etc. are stored")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"pidfile", /* name */
0, /* minnum */
1, /* maxnum */
"p", /* short option */
"pidfile", /* long option */
I18S("Specify the PID file"),
I18S("Specify the PID file")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"timeout", /* name */
0, /* minnum */
1, /* maxnum */
"T", /* short option */
"timeout", /* long option */
I18S("Specify timeout in second (default: no timeout)"),
I18S("Specify timeout in second (default: no timeout)")
},
{
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
GWEN_ArgsType_Int, /* type */
"help", /* name */
0, /* minnum */
0, /* maxnum */
"h", /* short option */
"help",
I18S("Show this help screen."),
I18S("Show this help screen.")
}
};
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
if (rv==GWEN_ARGS_RESULT_ERROR) {
fprintf(stderr, "ERROR: Could not parse arguments main\n");
return GWEN_ERROR_INVALID;
}
else if (rv==GWEN_ARGS_RESULT_HELP) {
GWEN_BUFFER *ubuf;
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
GWEN_Buffer_AppendArgs(ubuf,
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
AQHOME_VERSION_STRING,
argv[0]);
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
fprintf(stderr, "ERROR: Could not create help string\n");
return 1;
}
GWEN_Buffer_AppendString(ubuf, "\n");
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
GWEN_Buffer_free(ubuf);
return GWEN_ERROR_CLOSE;
}
return 0;
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_INIT_H
#define AQHOME_STORAGE_INIT_H
#include "./aqhomestorage.h"
int AqHomeStorage_Init(AQHOME_STORAGE *aqh, int argc, char **argv);
#endif

View File

@@ -1,336 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./init_http.h"
#include "./aqhomestorage_p.h"
#include "./aqhomehttp.h"
#include "./u_login.h"
#include "./u_rooms.h"
#include "./u_devices.h"
#include "./u_mqtttopics.h"
#include "./u_values.h"
#include "./u_static.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include "aqhome/http/endpoint_http.h"
#include "aqhome/http/httpservice_conf.h"
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice.h"
#include "aqhome/http/content_files.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_msgio.h>
#include <gwenhywfar/directory.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
//#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort);
static int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
static int _createContentRoot(AQHOME_STORAGE *aqh);
static GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
static int _createUrlHandler_login(AQHOME_STORAGE *aqh);
static int _createUrlHandler_rooms(AQHOME_STORAGE *aqh);
static int _createUrlHandler_devices(AQHOME_STORAGE *aqh);
static int _createUrlHandler_topics(AQHOME_STORAGE *aqh);
static int _createUrlHandler_values(AQHOME_STORAGE *aqh);
static int _createUrlHandler_static(AQHOME_STORAGE *aqh);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
const char *tcpAddress;
int tcpPort;
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "httpAddress", 0, NULL);
tcpPort=GWEN_DB_GetIntValue(dbArgs, "httpPort", 0, AQHOME_STORAGE_DEFAULT_HTTP_PORT);
if (tcpAddress && *tcpAddress && tcpPort) {
int rv;
_setupEndpoint(aqh, tcpAddress, tcpPort);
rv=_setupHttpService(aqh, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_createContentRoot(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_createUrlHandler_login(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_createUrlHandler_rooms(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_createUrlHandler_devices(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_createUrlHandler_topics(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_createUrlHandler_values(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_createUrlHandler_static(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
}
return 0;
}
void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort)
{
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptHttpFn, aqh);
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
aqh->httpdEndpoint=ep;
}
int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
const char *configFolder;
const char *sourceFolder;
int rv;
configFolder=GWEN_DB_GetCharValue(dbArgs, "cfgdir", 0, AQHOME_STORAGE_DEFAULT_CONFIGDIR);
sourceFolder=GWEN_DB_GetCharValue(dbArgs, "sourceFolder", 0, AQHOME_STORAGE_DEFAULT_HTTP_SOURCEDIR);
aqh->httpService=AQH_HttpService_new(configFolder, sourceFolder);
AqHomeHttpService_Extend(aqh->httpService);
AqHomeHttpService_SetStorage(aqh->httpService, aqh->storage);
rv=AQH_HttpService_LoadConfig(aqh->httpService);
if (rv<0) {
DBG_ERROR(NULL, "Error loading config for HTTP service (%d)", rv);
return GWEN_ERROR_GENERIC;
}
AQH_HttpService_LoadAllSessions(aqh->httpService);
return 0;
}
GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep,
GWEN_SOCKET *sk,
const GWEN_INETADDRESS *addr,
GWEN_UNUSED void *data)
{
GWEN_MSG_ENDPOINT *epIncoming;
/* AQHOME_STORAGE *aqh;
*
* aqh=(AQHOME_STORAGE*) data;
*/
DBG_INFO(NULL, "Incoming HTTP connection");
epIncoming=GWEN_MsgEndpoint_new("http", 0);
GWEN_MsgEndpoint_SetSocket(epIncoming, sk);
GWEN_MsgIoEndpoint_Extend(epIncoming);
AQH_HttpEndpoint_Extend(epIncoming, AQH_ENDPOINT_HTTP_FLAGS_PASSIVE);
return epIncoming;
}
int _createContentRoot(AQHOME_STORAGE *aqh)
{
const char *sourceFolder;
GWEN_BUFFER *nbuf1;
GWEN_BUFFER *nbuf2;
AQH_HTTP_CONTENT *c;
sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService);
nbuf1=GWEN_Buffer_new(0, 256, 0, 1);
nbuf2=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(nbuf1, sourceFolder);
GWEN_Buffer_AppendString(nbuf1, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEHEADER);
GWEN_Buffer_AppendString(nbuf2, sourceFolder);
GWEN_Buffer_AppendString(nbuf2, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEFOOTER);
c=AQH_HttpContentFiles_new("root", GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
if (c==NULL) {
DBG_INFO(NULL,
"Unable to create content for root (header=[%s], footer=[%s])",
GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
GWEN_Buffer_free(nbuf2);
GWEN_Buffer_free(nbuf1);
return GWEN_ERROR_GENERIC;
}
AqHomeHttpService_SetContentTree(aqh->httpService, c);
GWEN_Buffer_free(nbuf2);
GWEN_Buffer_free(nbuf1);
return 0;
}
int _createUrlHandler_login(AQHOME_STORAGE *aqh)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_LoginHttpUrlHandler_new(aqh->httpService);
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
AQH_HttpUrlHandler_AddUrlPattern(uh, "/login");
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
return 0;
}
int _createUrlHandler_rooms(AQHOME_STORAGE *aqh)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_RoomsHttpUrlHandler_new(aqh->httpService);
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
AQH_HttpUrlHandler_AddUrlPattern(uh, "/rooms/*");
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
return 0;
}
int _createUrlHandler_devices(AQHOME_STORAGE *aqh)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_DevicesHttpUrlHandler_new(aqh->httpService);
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
AQH_HttpUrlHandler_AddUrlPattern(uh, "/devices/*");
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
return 0;
}
int _createUrlHandler_topics(AQHOME_STORAGE *aqh)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_MqttTopicsHttpUrlHandler_new(aqh->httpService);
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
AQH_HttpUrlHandler_AddUrlPattern(uh, "/mqtttopics/*");
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
return 0;
}
int _createUrlHandler_values(AQHOME_STORAGE *aqh)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_ValuesHttpUrlHandler_new(aqh->httpService);
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
AQH_HttpUrlHandler_AddUrlPattern(uh, "/values/*");
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
return 0;
}
int _createUrlHandler_static(AQHOME_STORAGE *aqh)
{
AQH_HTTP_URLHANDLER *uh;
GWEN_BUFFER *nameBuf;
const char *sourceFolder;
sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService);
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(nameBuf, sourceFolder);
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_STATIC_RELFOLDER GWEN_DIR_SEPARATOR_S "pics");
uh=AQH_StaticHttpUrlHandler_new(aqh->httpService, GWEN_Buffer_GetStart(nameBuf));
GWEN_Buffer_free(nameBuf);
AQH_HttpUrlHandler_AddUrlPattern(uh, "/pics/*");
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
return 0;
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_INIT_HTTP_H
#define AQHOME_STORAGE_INIT_HTTP_H
#include "./aqhomestorage.h"
int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
#endif

View File

@@ -1,212 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./init_mqtt.h"
#include "./aqhomestorage_p.h"
#include "./aqhomehttp.h"
#include "./u_login.h"
#include "./u_rooms.h"
#include "./u_devices.h"
#include "./u_mqtttopics.h"
#include "./u_values.h"
#include "./u_static.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include <aqhome/mqtt/msg_mqtt_subscribe.h>
#include <aqhome/mqtt/msg_mqtt_suback.h>
#include "aqhome/http/endpoint_http.h"
#include "aqhome/http/httpservice_conf.h"
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice.h"
#include "aqhome/http/content_files.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_msgio.h>
#include <gwenhywfar/directory.h>
#include <gwenhywfar/text.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
//#define I18N(msg) msg
#define I18S(msg) msg
#define AQHOME_STORAGE_DEFAULT_CMDTIMEOUT 10000
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _mqttConnect(GWEN_MSG_ENDPOINT *epTcp);
static int _subscribe(AQHOME_STORAGE *aqh, const char *topicFilter);
static GWEN_MSG *_awaitPacket(GWEN_MSG_ENDPOINT *epTcp, uint8_t expectedPacketType, int timeoutInSeconds);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomeStorage_SetupMqtt(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
const char *mqttAddress;
int mqttPort;
const char *mqttClientId;
int mqttKeepAlive;
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "mqttAddress", 0, NULL);
mqttPort=GWEN_DB_GetIntValue(dbArgs, "mqttPort", 0, AQHOME_STORAGE_DEFAULT_MQTT_PORT);
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "mqttClientId", 0, AQHOME_STORAGE_DEFAULT_MQTT_CLIENTID);
mqttKeepAlive=GWEN_DB_GetIntValue(dbArgs, "mqttKeepAlive", 0, AQHOME_STORAGE_DEFAULT_MQTT_KEEPALIVE);
if (mqttAddress && *mqttAddress && mqttPort) {
GWEN_MSG_ENDPOINT *ep;
int rv;
ep=AQH_MqttClientEndpoint_new(mqttClientId, mqttAddress, mqttPort, NULL, 0);
AQH_MqttClientEndpoint_SetKeepAliveTime(ep, mqttKeepAlive);
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
aqh->mqttEndpoint=ep;
rv=_mqttConnect(ep);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting to MQTT server %s:%d (%d)", mqttAddress, mqttPort, rv);
return rv;
}
rv=_subscribe(aqh, "#");
if (rv<0) {
DBG_ERROR(NULL, "Error subscribingconnecting to MQTT server %s:%d (%d)", mqttAddress, mqttPort, rv);
return rv;
}
}
return 0;
}
int _mqttConnect(GWEN_MSG_ENDPOINT *epTcp)
{
if (GWEN_MsgEndpoint_GetState(epTcp)==GWEN_MSG_ENDPOINT_STATE_UNCONNECTED) {
int rv;
rv=AQH_MqttClientEndpoint_StartConnect(epTcp);
if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
DBG_ERROR(NULL, "Error starting to connect (%d)", rv);
return rv;
}
}
while(GWEN_MsgEndpoint_GetState(epTcp)!=GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
DBG_DEBUG(NULL, "Next loop");
GWEN_MsgEndpoint_IoLoop(epTcp, 2000); /* 2000 ms */
}
return 0;
}
int _subscribe(AQHOME_STORAGE *aqh, const char *topicFilter)
{
uint16_t pckId;
GWEN_MSG *msgOut;
GWEN_MSG *msgIn;
DBG_INFO(NULL, "Sending SUBSCRIBE %s", topicFilter);
pckId=AQH_MqttClientEndpoint_GetNextPacketId(aqh->mqttEndpoint);
msgOut=GWEN_SubscribeMqttMsg_new(AQH_MQTTMSG_MSGTYPE_SUBSCRIBE, pckId, topicFilter, 0);
if (msgOut==NULL) {
DBG_ERROR(NULL, "Error creating message");
return GWEN_ERROR_INTERNAL;
}
GWEN_MsgEndpoint_AddSendMessage(aqh->mqttEndpoint, msgOut);
DBG_INFO(NULL, "Waiting for response");
msgIn=_awaitPacket(aqh->mqttEndpoint, AQH_MQTTMSG_MSGTYPE_SUBACK, AQHOME_STORAGE_DEFAULT_CMDTIMEOUT);
if (msgIn) {
GWEN_BUFFER *buf;
buf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_SubAckMqttMsg_DumpToBuffer(msgIn, buf, "received");
DBG_INFO(NULL, "%s", GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
GWEN_Msg_free(msgIn);
}
return 0;
}
GWEN_MSG *_awaitPacket(GWEN_MSG_ENDPOINT *epTcp, uint8_t expectedPacketType, int timeoutInSeconds)
{
time_t startTime;
startTime=time(NULL);
for (;;) {
GWEN_MSG *msg;
time_t now;
GWEN_MsgEndpoint_IoLoop(epTcp, 2000); /* 2000 ms */
msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp);
if (msg) {
if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(expectedPacketType & 0xf0)) {
return msg;
}
else {
DBG_ERROR(NULL, "Received this message:");
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
}
GWEN_Msg_free(msg);
}
now=time(NULL);
if (now-startTime>timeoutInSeconds) {
DBG_INFO(NULL, "Timeout");
break;
}
}
return NULL;
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_INIT_MQTT_H
#define AQHOME_STORAGE_INIT_MQTT_H
#include "./aqhomestorage.h"
int AqHomeStorage_SetupMqtt(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
#endif

View File

@@ -1,150 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop.h"
#include "./loop_http.h"
#include "./loop_mqtt.h"
#include "./aqhomehttp.h"
#include "./aqhomestorage_p.h"
#include "aqhome/http/httpservice_conf.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _writeModifiedSessions(AQHOME_STORAGE *aqh);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeStorage_Loop(AQHOME_STORAGE *aqh, int timeoutInMsecs)
{
if (aqh) {
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
AqHomeStorage_ReadAndHandleHttpMessages(aqh);
AqHomeStorage_ReadAndHandleMqttMessages(aqh);
// AqHomeStorage_ReadAndHandleIpcMessages(aqh);
}
}
int AqHomeStorage_WriteStorageIfChanged(AQHOME_STORAGE *aqh)
{
if (AQH_Storage_GetRuntimeFlags(aqh->storage) & AQH_STORAGE_RTFLAGS_MODIFIED) {
int rv;
DBG_INFO(NULL, "Storage modified, writing statefile");
rv=AqHomeHttpService_LockStorage(aqh->httpService);
if (rv<0) {
DBG_INFO(NULL, "Error locking storage (%d)", rv);
return rv;
}
rv=AQH_Storage_WriteState(aqh->storage);
if (rv<0) {
DBG_INFO(NULL, "Error writing state file (%d)", rv);
AqHomeHttpService_UnlockStorage(aqh->httpService);
return rv;
}
rv=AqHomeHttpService_UnlockStorage(aqh->httpService);
if (rv<0) {
DBG_INFO(NULL, "Error unlocking storage (%d)", rv);
return rv;
}
}
return 0;
}
int AqHomeStorage_WriteServiceIfChanged(AQHOME_STORAGE *aqh)
{
int rv;
rv=_writeModifiedSessions(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return 0;
}
int _writeModifiedSessions(AQHOME_STORAGE *aqh)
{
AQH_SESSION_LIST *sessionList;
int rv;
rv=AQH_HttpService_LockSessions(aqh->httpService);
if (rv<0) {
DBG_INFO(NULL, "Error locking sessions (%d)", rv);
return rv;
}
sessionList=AQH_Service_GetSessionList(aqh->httpService);
if (sessionList) {
AQH_SESSION *session;
session=AQH_Session_List_First(sessionList);
while(session) {
if (AQH_Session_GetRuntimeFlags(session) & AQH_SESSION_RTFLAGS_MODIFIED) {
DBG_INFO(NULL, "Session \"%s\" modified, writing", AQH_Session_GetUid(session));
rv=AQH_HttpService_SaveSession(aqh->httpService, session);
if (rv<0) {
DBG_INFO(NULL, "Error writing session \"%s\" (%d)", AQH_Session_GetUid(session), rv);
}
else {
DBG_DEBUG(NULL, "Session \"%s\" written", AQH_Session_GetUid(session));
AQH_Session_SubRuntimeFlags(session, AQH_SESSION_RTFLAGS_MODIFIED);
}
}
session=AQH_Session_List_Next(session);
}
}
rv=AQH_HttpService_UnlockSessions(aqh->httpService);
if (rv<0) {
DBG_INFO(NULL, "Error unlocking sessions (%d)", rv);
return rv;
}
return 0;
}

View File

@@ -1,27 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_LOOP_H
#define AQHOME_STORAGE_LOOP_H
#include "./aqhomestorage.h"
void AqHomeStorage_Loop(AQHOME_STORAGE *aqh, int timeoutInMsecs);
int AqHomeStorage_WriteStorageIfChanged(AQHOME_STORAGE *aqh);
int AqHomeStorage_WriteServiceIfChanged(AQHOME_STORAGE *aqh);
#endif

View File

@@ -1,117 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_http.h"
#include "./aqhomestorage_p.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include "aqhome/http/endpoint_http.h"
#include "aqhome/http/httpservice_http.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_msgio.h>
#include <gwenhywfar/syncio.h>
#include <gwenhywfar/url.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
//#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handleHttpEndpoint(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep);
static void _handleHttpMsg(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msgReceived);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeStorage_ReadAndHandleHttpMessages(AQHOME_STORAGE *aqh)
{
if (aqh->httpdEndpoint) {
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->httpdEndpoint);
while(ep) {
_handleHttpEndpoint(aqh, ep);
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
}
}
void _handleHttpEndpoint(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep)
{
GWEN_MSG *msg;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
_handleHttpMsg(aqh, ep, msg);
GWEN_Msg_free(msg);
}
}
void _handleHttpMsg(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msgReceived)
{
GWEN_MSG *msgResponse;
msgResponse=AQH_HttpService_HandleHttpRequest(aqh->httpService, ep, msgReceived);
if (msgResponse) {
DBG_INFO(NULL, "Sending response message");
GWEN_MsgEndpoint_AddSendMessage(ep, msgResponse);
}
else {
DBG_INFO(NULL, "No response for message");
}
}

View File

@@ -1,21 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_HTTP_H
#define AQHOME_STORAGE_HTTP_H
#include "./aqhomestorage.h"
void AqHomeStorage_ReadAndHandleHttpMessages(AQHOME_STORAGE *aqh);
#endif

View File

@@ -1,110 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_mqtt.h"
#include "./aqhomestorage_p.h"
#include "aqhome/mqtt/msg_mqtt_publish.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
//#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handlePublishMsg(AQHOME_STORAGE *aqh, GWEN_MSG *msg);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeStorage_ReadAndHandleMqttMessages(AQHOME_STORAGE *aqh)
{
GWEN_MSG *msg;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->mqttEndpoint)) ) {
if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PUBLISH & 0xf0)) {
_handlePublishMsg(aqh, msg);
}
else if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PINGRESP & 0xf0)) {
DBG_INFO(AQH_LOGDOMAIN, "PING response received");
}
else {
DBG_INFO(NULL, "Received unexpected MQTT message %02x", AQH_MqttMsg_GetMsgTypeAndFlags(msg));
}
GWEN_Msg_free(msg);
}
}
int AqHomeStorage_MqttPing(AQHOME_STORAGE *aqh)
{
GWEN_MSG *msgOut;
DBG_INFO(AQH_LOGDOMAIN, "Sending PING");
msgOut=GWEN_MqttMsg_new(AQH_MQTTMSG_MSGTYPE_PINGREQ, 0, NULL);
if (msgOut==NULL) {
DBG_ERROR(NULL, "Error creating message");
return GWEN_ERROR_INTERNAL;
}
GWEN_MsgEndpoint_AddSendMessage(aqh->mqttEndpoint, msgOut);
return 0;
}
void _handlePublishMsg(AQHOME_STORAGE *aqh, GWEN_MSG *msg)
{
char *topic;
char *value;
topic=AQH_PublishMqttMsg_ExtractTopic(msg);
value=AQH_PublishMqttMsg_ExtractValue(msg);
if (topic && value)
AQH_Storage_HandleMqttPublish(aqh->storage, topic, value);
else {
DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg");
}
free(value);
free(topic);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_MQTT_H
#define AQHOME_STORAGE_MQTT_H
#include "./aqhomestorage.h"
void AqHomeStorage_ReadAndHandleMqttMessages(AQHOME_STORAGE *aqh);
int AqHomeStorage_MqttPing(AQHOME_STORAGE *aqh);
#endif

View File

@@ -1,269 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <aqhome/api.h>
#include <aqhome/aqhome.h>
#include "./aqhomestorage.h"
#include "./init.h"
#include "./fini.h"
#include "./loop.h"
#include "./loop_mqtt.h"
#include "./cleanup.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/cgui.h>
#include <gwenhywfar/debug.h>
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
//#define CLEANUP_INTERVAL_IN_SECS (5*60)
//#define WRITE_INTERVAL_IN_SECS (5*60)
#define CLEANUP_INTERVAL_IN_SECS (60)
#define WRITE_INTERVAL_IN_SECS (60)
#define PING_INTERVAL 120
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
#ifdef HAVE_SIGNAL_H
static int _setSignalHandlers(void);
static int _setupSigAction(struct sigaction *sa, int sig);
static void _signalHandler(int s);
#endif
static void _runService(AQHOME_STORAGE *aqh);
static void _writeCurrentState(AQHOME_STORAGE *aqh);
/* ------------------------------------------------------------------------------------------------
* static vars
* ------------------------------------------------------------------------------------------------
*/
#ifdef HAVE_SIGNAL_H
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
#endif
static int stopService=0;
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int main(int argc, char **argv)
{
int rv;
AQHOME_STORAGE *aqh;
GWEN_GUI *gui;
rv=GWEN_Init();
if (rv) {
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
return 2;
}
GWEN_Logger_Open(0, "aqhome-storage", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
//GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info);
rv=_setSignalHandlers();
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=AQH_Init();
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return 2;
}
gui=GWEN_Gui_CGui_new();
GWEN_Gui_SetGui(gui);
aqh=AqHomeStorage_new();
rv=AqHomeStorage_Init(aqh, argc, argv);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return 2;
}
_runService(aqh);
AqHomeStorage_Fini(aqh);
AqHomeStorage_free(aqh);
GWEN_Gui_SetGui(NULL);
GWEN_Gui_free(gui);
return 0;
}
void _runService(AQHOME_STORAGE *aqh)
{
time_t timeStart;
time_t timeLastCleanup;
time_t timeLastWrite;
time_t timeLastPing;
int timeout;
timeout=AqHomeStorage_GetTimeout(aqh);
timeStart=time(NULL);
timeLastCleanup=time(NULL);
timeLastWrite=time(NULL);
timeLastPing=time(NULL);
while(!stopService) {
time_t now;
DBG_DEBUG(NULL, "Next loop");
AqHomeStorage_Loop(aqh, 2000);
now=time(NULL);
if (((int)difftime(now, timeLastCleanup))>CLEANUP_INTERVAL_IN_SECS) {
DBG_INFO(NULL, "Cleanup time");
AqHomeStorage_Cleanup(aqh);
timeLastCleanup=now;
}
if (((int)difftime(now, timeLastWrite))>WRITE_INTERVAL_IN_SECS) {
DBG_INFO(NULL, "Write time");
_writeCurrentState(aqh);
timeLastWrite=now;
}
if (timeout && ((int)difftime(now, timeLastPing))>timeout) {
DBG_INFO(NULL, "Sending ping");
AqHomeStorage_MqttPing(aqh);
timeLastPing=now;
}
if (timeout && ((int)difftime(now, timeStart))>timeout) {
DBG_INFO(NULL, "Timeout");
_writeCurrentState(aqh);
break;
}
} /* while */
}
void _writeCurrentState(AQHOME_STORAGE *aqh)
{
int rv;
rv=AqHomeStorage_WriteStorageIfChanged(aqh);
if (rv<0) {
DBG_ERROR(NULL, "ATTENTION: Could not write storage statefile (%d)", rv);
}
rv=AqHomeStorage_WriteServiceIfChanged(aqh);
if (rv<0) {
DBG_ERROR(NULL, "ATTENTION: Could not write current config (%d)", rv);
}
}
int _setSignalHandlers(void)
{
#ifdef HAVE_SIGNAL_H
int rv;
rv=_setupSigAction(&saINT, SIGINT);
if (rv)
return rv;
rv=_setupSigAction(&saTERM, SIGTERM);
if (rv)
return rv;
rv=_setupSigAction(&saHUP, SIGHUP);
if (rv)
return rv;
# ifdef SIGTSTP
rv=_setupSigAction(&saTSTP, SIGTSTP);
if (rv)
return rv;
# endif
# ifdef SIGCONT
rv=_setupSigAction(&saCONT, SIGCONT);
if (rv)
return rv;
# endif
#endif
return 0;
}
int _setupSigAction(struct sigaction *sa, int sig)
{
sa->sa_handler=_signalHandler;
sigemptyset(&sa->sa_mask);
sa->sa_flags=0;
if (sigaction(sig, sa, 0)) {
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
return GWEN_ERROR_IO;
}
return 0;
}
void _signalHandler(int s)
{
switch(s) {
case SIGINT:
case SIGTERM:
case SIGHUP:
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
stopService=1;
break;
default:
DBG_WARN(0, "Unknown signal %d",s);
break;
}
}

View File

@@ -1,71 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_base.h"
#include "./aqhomehttp.h"
#include "aqhome/http/httpservice_http.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
GWEN_MSG *AQH_BaseHttpUrlHandler_CreateResponseForErrorCode(AQH_HTTP_URLHANDLER *uh,
AQH_HTTP_REQUEST *rq,
int rv,
AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb,
GWEN_DB_NODE *db)
{
if (rv<0) {
switch(rv) {
case GWEN_ERROR_INVALID:
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Missing fields"), 1, db, cb);
case GWEN_ERROR_FOUND:
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Object already exists"), 1, db, cb);
case GWEN_ERROR_NOT_FOUND:
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Object not found"), 1, db, cb);
case GWEN_ERROR_IO:
case GWEN_ERROR_INTERNAL:
default:
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh),
500, "Internal error",
AQH_HttpRequest_GetProtocol(rq), NULL);
}
}
return NULL;
}

View File

@@ -1,27 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_BASE_H
#define AQHOME_STORAGE_U_BASE_H
#include "aqhome/http/urlhandler.h"
GWEN_MSG *AQH_BaseHttpUrlHandler_CreateResponseForErrorCode(AQH_HTTP_URLHANDLER *uh,
AQH_HTTP_REQUEST *rq,
int rv,
AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb,
GWEN_DB_NODE *db);
#endif

View File

@@ -1,351 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_devices.h"
#include "./u_objects.h"
#include "./aqhomehttp.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _setFromObject(AQH_DEVICE *device, const AQH_DEVICE *srcDevice);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_HTTP_URLHANDLER *AQH_DevicesHttpUrlHandler_new(AQH_SERVICE *sv)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_ObjectsHttpUrlHandler_new(sv,
AQHOME_HTTP_PERMS_LIST_DEVICES,
AQHOME_HTTP_PERMS_ADD_DEVICE,
AQHOME_HTTP_PERMS_DEL_DEVICE,
AQHOME_HTTP_PERMS_EDIT_DEVICE,
"/devices/list");
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
return uh;
}
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
AQH_DEVICE *newDevice;
const char *deviceName;
int rv;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
newDevice=AQH_Device_fromDb(db);
deviceName=AQH_Device_GetName(newDevice);
if (!(deviceName && *deviceName)) {
DBG_INFO(NULL, "Missing device name");
AQH_Device_free(newDevice);
return GWEN_ERROR_INVALID;
}
rv=AqHomeHttpService_LockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error locking storage");
AQH_Device_free(newDevice);
return GWEN_ERROR_IO;
}
if (id>0) {
AQH_DEVICE *device;
DBG_INFO(NULL, "Edit existing device");
device=AQH_Storage_GetDeviceById(sto, id);
if (device==NULL) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "Device %d not found", id);
AQH_Device_free(newDevice);
return GWEN_ERROR_NOT_FOUND;
}
AQH_Device_SetId(device, id);
_setFromObject(device, newDevice);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
else {
AQH_DEVICE *device;
DBG_INFO(NULL, "Adding new device");
device=AQH_Storage_GetDeviceByName(sto, deviceName);
if (device) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "Device %s exists", deviceName);
AQH_Device_free(newDevice);
return GWEN_ERROR_FOUND;
}
device=AQH_Device_new();
AQH_Device_SetId(device, 0);
_setFromObject(device, newDevice);
AQH_Storage_AddDevice(sto, device);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
AQH_Device_free(newDevice);
rv=AqHomeHttpService_UnlockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking storage");
return GWEN_ERROR_IO;
}
return 0;
}
void _setFromObject(AQH_DEVICE *device, const AQH_DEVICE *srcDevice)
{
AQH_Device_SetRoomId(device, AQH_Device_GetRoomId(srcDevice));
AQH_Device_SetName(device, AQH_Device_GetName(srcDevice));
AQH_Device_SetDeviceType(device, AQH_Device_GetDeviceType(srcDevice));
AQH_Device_SetLocation(device, AQH_Device_GetLocation(srcDevice));
AQH_Device_SetDescription(device, AQH_Device_GetDescription(srcDevice));
}
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_DEVICE *device;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
device=AQH_Storage_GetDeviceById(sto, id);
if (device) {
GWEN_DB_NODE *db;
db=GWEN_DB_Group_new("device");
AQH_Device_toDb(device, db);
return db;
}
return NULL;
}
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/devices/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Add Device"));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/devices/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Edit Device"),
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_ROOM_LIST *roomList;
unsigned long int selectedRoomId=0;
char numbuf[16];
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
roomList=AQH_Storage_GetRoomList(sto);
selectedRoomId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "roomId", 0, 0):0);
snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedRoomId);
numbuf[sizeof(numbuf)-1]=0;
GWEN_Buffer_AppendArgs(pageBuf,
" <table>"
" <tr>"
" <td><label for=\"name\">%s: </label></td>"
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
" </tr>",
I18N("Name"),
dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"");
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td><label for=\"roomId\">%s: </label></td>"
"<td><select id=\"roomId\" name=\"roomId\">",
I18N("Room"));
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>", I18N("-- select room --"));
if (roomList) {
const AQH_ROOM *r;
r=AQH_Room_List_First(roomList);
while(r) {
const char *roomName;
roomName=AQH_Room_GetName(r);
if (roomName && *roomName) {
snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_Room_GetId(r));
numbuf[sizeof(numbuf)-1]=0;
if (selectedRoomId && AQH_Room_GetId(r)==selectedRoomId)
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>", numbuf, roomName);
else
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>", numbuf, roomName);
}
r=AQH_Room_List_Next(r);
}
}
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>");
GWEN_Buffer_AppendArgs(pageBuf,
" <tr>"
" <td><label for=\"deviceType\">%s: </label></td>"
" <td><input type=\"text\" name=\"deviceType\" value=\"%s\"></td>"
" </tr>",
I18N("Type"),
dbValues?GWEN_DB_GetCharValue(dbValues, "deviceType", 0, ""):"");
GWEN_Buffer_AppendArgs(pageBuf,
" <tr>"
" <td><label for=\"location\">%s: </label></td>"
" <td><input type=\"text\" name=\"location\" value=\"%s\"></td>"
" </tr>",
I18N("Location"),
dbValues?GWEN_DB_GetCharValue(dbValues, "location", 0, ""):"");
GWEN_Buffer_AppendArgs(pageBuf,
" <tr>"
" <td><label for=\"description\">%s: </label></td>"
" <td><input type=\"text\" name=\"description\" value=\"%s\"></td>"
" </tr>"
" </table>",
I18N("Description"),
dbValues?GWEN_DB_GetCharValue(dbValues, "description", 0, ""):"");
}
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_DEVICE_LIST *rl;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2>"
"<table class=\"dataTable\">"
"<thead>"
" <tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
"</thead>",
I18N("Devices"),
I18N("Name"),
I18N("Room"),
I18N("Type"),
I18N("Location"),
I18N("Description"));
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
rl=AQH_Storage_GetDeviceList(sto);
if (rl) {
const AQH_DEVICE *device;
device=AQH_Device_List_First(rl);
while(device) {
long unsigned int id;
int roomId;
const char *name;
const char *roomName=NULL;
const char *devType;
const char *descr;
const char *location;
const AQH_ROOM *r=NULL;
id=(long unsigned int) AQH_Device_GetId(device);
roomId=(long unsigned int) AQH_Device_GetRoomId(device);
if (roomId>0)
r=AQH_Storage_GetRoomById(sto, roomId);
if (r)
roomName=AQH_Room_GetName(r);
name=AQH_Device_GetName(device);
devType=AQH_Device_GetDeviceType(device);
descr=AQH_Device_GetDescription(device);
location=AQH_Device_GetLocation(device);
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
"<td><a href=\"/devices/edit/%lu\">"
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
"</tr>",
name?name:"",
roomName?roomName:"",
devType?devType:"",
location?location:"",
descr?descr:"", id);
device=AQH_Device_List_Next(device);
}
}
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/devices/add\">%s</a><br>", I18N("Add Device"));
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_DEVICES_H
#define AQHOME_STORAGE_U_DEVICES_H
#include "aqhome/http/urlhandler.h"
AQH_HTTP_URLHANDLER *AQH_DevicesHttpUrlHandler_new(AQH_SERVICE *sv);
#endif

View File

@@ -1,394 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_login.h"
#include "aqhome/http/httpservice.h"
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice_conf.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/mdigest.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/timestamp.h>
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static int _loginUser(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static int _verifyPass(AQH_USER *u, const char *userName, const char *password);
static AQH_SESSION *_generateSessionForUser(AQH_SERVICE *sv, AQH_USER *u);
static GWEN_BUFFER *_generateSessionUid(void);
static void _headerSetCookie(GWEN_DB_NODE *db, uint32_t flags, const char *cookieName, const char *cookieValue);
static GWEN_MSG *_createLoginResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *sessionId, const char *newPage);
AQH_HTTP_URLHANDLER *AQH_LoginHttpUrlHandler_new(AQH_SERVICE *sv)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_HttpUrlHandler_new(sv);
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
return uh;
}
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
const char *protocol;
const char *cmd;
GWEN_MSG *msgOut=NULL;
protocol=AQH_HttpRequest_GetProtocol(rq);
cmd=AQH_HttpRequest_GetCommand(rq);
if (cmd && *cmd) {
int rv;
if (strcasecmp(cmd, "GET")==0) {
rv=_handleGet(uh, rq);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return rv;
}
}
else if (strcasecmp(cmd, "POST")==0) {
rv=_handlePost(uh, rq);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return rv;
}
}
else {
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
}
return 0;
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
return GWEN_ERROR_INVALID;
}
}
int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
GWEN_BUFFER *pageBuf;
int rv;
GWEN_MSG *msgOut=NULL;
const char *protocol;
protocol=AQH_HttpRequest_GetProtocol(rq);
pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
GWEN_Buffer_free(pageBuf);
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
rv=AQH_HttpService_AddFile(AQH_HttpUrlHandler_GetHttpService(uh), NULL, "login.html", pageBuf);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"login.html\"");
GWEN_Buffer_free(pageBuf);
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers");
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
GWEN_Buffer_free(pageBuf);
return rv;
}
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
GWEN_Buffer_free(pageBuf);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
GWEN_DB_NODE *db;
int rv;
DBG_ERROR(NULL, "Login POST:");
db=AQH_HttpRequest_GetDbPostBody(rq);
GWEN_DB_Dump(db, 2);
rv=_loginUser(uh, rq);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return 0;
}
int _loginUser(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
AQH_SERVICE *sv;
GWEN_MSG *msgOut=NULL;
const char *protocol;
GWEN_DB_NODE *db;
const char *userName;
const char *password;
AQH_USER *u;
AQH_SESSION *session;
int i;
int rv;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
db=AQH_HttpRequest_GetDbPostBody(rq);
protocol=AQH_HttpRequest_GetProtocol(rq);
userName=GWEN_DB_GetCharValue(db, "username", 0, NULL);
password=GWEN_DB_GetCharValue(db, "password", 0, NULL);
if (!(userName && *userName && password && *password)) {
msgOut=AQH_HttpService_CreateResponseMsg(sv, 401, "Unauthorized", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
u=AQH_HttpService_GetUser(sv, userName);
if (u==NULL) {
DBG_INFO(NULL, "User \"%s\" not found", userName);
/* TODO: sleep */
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
i=AQH_User_GetState(u);
if (i==AQH_UserState_Suspended) {
DBG_INFO(NULL, "User \"%s\" suspended", userName);
/* TODO: sleep */
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
rv=_verifyPass(u, userName, password);
if (rv<0) {
if (rv==GWEN_ERROR_VERIFY)
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, "error");
else
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
/* TODO: sleep */
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
session=_generateSessionForUser(sv, u);
if (session==NULL) {
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
/* TODO: sleep */
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
DBG_ERROR(NULL, "Session generated");
AQH_User_SetTimestampLastLogin(u, AQH_Session_GetTimestampCreation(session));
rv=AQH_HttpService_WriteUser(sv, u);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
msgOut=_createLoginResponseMsg(sv, protocol, AQH_Session_GetUid(session), "/rooms/list");
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
int _verifyPass(AQH_USER *u, const char *userName, const char *password)
{
GWEN_MDIGEST *md;
int rv;
const char *storedPasswordHash;
char buffer[70];
storedPasswordHash=AQH_User_GetHashedPassword(u);
if (!(storedPasswordHash && *storedPasswordHash)) {
DBG_ERROR(NULL, "No password hash stored with user \"%s\"", userName);
return GWEN_ERROR_INTERNAL;
}
md=GWEN_MDigest_Sha256_new();
rv=GWEN_MDigest_Begin(md);
if (rv<0) {
DBG_ERROR(NULL, "Error digesting given password [begin] (%d)", rv);
GWEN_MDigest_free(md);
return rv;
}
rv=GWEN_MDigest_Update(md, (const uint8_t*) password, strlen(password));
if (rv<0) {
DBG_ERROR(NULL, "Error digesting given password [update] (%d)", rv);
GWEN_MDigest_free(md);
return rv;
}
rv=GWEN_MDigest_End(md);
if (rv<0) {
DBG_ERROR(NULL, "Error digesting given password [end] (%d)", rv);
GWEN_MDigest_free(md);
return rv;
}
DBG_ERROR(NULL, "Digest needs %d bytes", (GWEN_MDigest_GetDigestSize(md)*2)+1);
if (NULL==GWEN_Text_ToHex((const char*) GWEN_MDigest_GetDigestPtr(md), GWEN_MDigest_GetDigestSize(md), buffer, sizeof(buffer)-1)) {
DBG_ERROR(NULL, "Buffer too small (need %d)", (GWEN_MDigest_GetDigestSize(md)*2)+1);
GWEN_MDigest_free(md);
return GWEN_ERROR_INTERNAL;
}
GWEN_MDigest_free(md);
if (strcasecmp(buffer, storedPasswordHash)!=0) {
DBG_ERROR(NULL, "Bad password for user \"%s\"", userName);
return GWEN_ERROR_VERIFY;
}
DBG_ERROR(NULL, "Valid password for user \"%s\"", userName);
return 0;
}
AQH_SESSION *_generateSessionForUser(AQH_SERVICE *sv, AQH_USER *u)
{
AQH_SESSION *session;
GWEN_BUFFER *buf;
GWEN_TIMESTAMP *ts;
int rv;
buf=_generateSessionUid();
if (buf==NULL) {
DBG_INFO(NULL, "here");
return NULL;
}
DBG_INFO(NULL, "New session id: [%s]", GWEN_Buffer_GetStart(buf));
session=AQH_Session_new();
AQH_Session_SetUid(session, GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
ts=GWEN_Timestamp_NowInLocalTime();
AQH_Session_SetTimestampCreation(session, ts);
AQH_Session_SetTimestampLastAccess(session, ts);
GWEN_Timestamp_free(ts);
AQH_Session_SetUserAlias(session, AQH_User_GetAlias(u));
AQH_Session_SetUser(session, u);
rv=AQH_HttpService_AddSession(sv, session);
if (rv<0) {
DBG_INFO(NULL, "Error adding session \"%s\" (%d)", AQH_Session_GetUid(session), rv);
AQH_Session_free(session);
return NULL;
}
return session;
}
GWEN_BUFFER *_generateSessionUid(void)
{
uint8_t binbuf[8];
GWEN_BUFFER *buf;
int rv;
rv=GWEN_SyncIo_Helper_PartiallyReadFile("/dev/urandom", binbuf, sizeof(binbuf));
if (rv<sizeof(binbuf)) {
DBG_ERROR(NULL, "Error reading from /dev/urandom: %d", rv);
return NULL;
}
buf=GWEN_Buffer_new(0, 20, 0, 1);
rv=GWEN_Text_ToHexBuffer((const char*) binbuf, rv, buf, 0, 0, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error converting random bytes to hex (%d)", rv);
GWEN_Buffer_free(buf);
return NULL;
}
return buf;
}
GWEN_MSG *_createLoginResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *sessionId, const char *newPage)
{
GWEN_BUFFER *buf;
GWEN_MSG *msg;
GWEN_DB_NODE *db;
buf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_HttpService_AddStatusLine(sv, 303, "OK, redirecting to content", protocol, buf);
db=GWEN_DB_Group_new("header");
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive");
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", "text/html; charset=utf-8");
_headerSetCookie(db, GWEN_DB_FLAGS_OVERWRITE_VARS, AQH_HTTP_REQUEST_SESSIONCOOKIE, sessionId);
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Location", newPage);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", 0);
AQH_HttpService_AddHeader(sv, db, buf);
GWEN_DB_Group_free(db);
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
GWEN_Buffer_free(buf);
return msg;
}
void _headerSetCookie(GWEN_DB_NODE *db, uint32_t flags, const char *cookieName, const char *cookieValue)
{
if (cookieName && cookieValue) {
GWEN_BUFFER *dbuf;
dbuf=GWEN_Buffer_new(0, 32, 0, 1);
GWEN_Buffer_AppendArgs(dbuf, "%s=%s", cookieName, cookieValue);
GWEN_DB_SetCharValue(db, flags, "Set-Cookie", GWEN_Buffer_GetStart(dbuf));
GWEN_Buffer_free(dbuf);
}
}

View File

@@ -1,24 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_LOGIN_H
#define AQHOME_STORAGE_U_LOGIN_H
#include "aqhome/http/urlhandler.h"
#include <gwenhywfar/endpoint.h>
AQH_HTTP_URLHANDLER *AQH_LoginHttpUrlHandler_new(AQH_SERVICE *sv);
#endif

View File

@@ -1,379 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_mqtttopics.h"
#include "./u_objects.h"
#include "./aqhomehttp.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _setFromObject(AQH_MQTT_TOPIC *mqttTopic, const AQH_MQTT_TOPIC *srcMqttTopic);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_HTTP_URLHANDLER *AQH_MqttTopicsHttpUrlHandler_new(AQH_SERVICE *sv)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_ObjectsHttpUrlHandler_new(sv,
AQHOME_HTTP_PERMS_LIST_TOPICS,
AQHOME_HTTP_PERMS_ADD_TOPIC,
AQHOME_HTTP_PERMS_DEL_TOPIC,
AQHOME_HTTP_PERMS_EDIT_TOPIC,
"/mqtttopics/list");
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
return uh;
}
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
AQH_MQTT_TOPIC *newMqttTopic;
const char *topic;
int rv;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
newMqttTopic=AQH_MqttTopic_fromDb(db);
topic=AQH_MqttTopic_GetTopic(newMqttTopic);
if (!(topic && *topic)) {
DBG_INFO(NULL, "Missing mqttTopic topic");
AQH_MqttTopic_free(newMqttTopic);
return GWEN_ERROR_INVALID;
}
rv=AqHomeHttpService_LockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error locking storage");
AQH_MqttTopic_free(newMqttTopic);
return GWEN_ERROR_IO;
}
if (id>0) {
AQH_MQTT_TOPIC *mqttTopic;
DBG_INFO(NULL, "Edit existing mqttTopic");
mqttTopic=AQH_Storage_GetMqttTopicById(sto, id);
if (mqttTopic==NULL) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "MqttTopic %d not found", id);
AQH_MqttTopic_free(newMqttTopic);
return GWEN_ERROR_NOT_FOUND;
}
AQH_MqttTopic_SetId(mqttTopic, id);
_setFromObject(mqttTopic, newMqttTopic);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
else {
AQH_MQTT_TOPIC *mqttTopic;
DBG_INFO(NULL, "Adding new mqttTopic");
mqttTopic=AQH_Storage_GetMqttTopicByTopic(sto, topic);
if (mqttTopic) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "MqttTopic %s exists", topic);
AQH_MqttTopic_free(newMqttTopic);
return GWEN_ERROR_FOUND;
}
mqttTopic=AQH_MqttTopic_new();
AQH_MqttTopic_SetId(mqttTopic, 0);
_setFromObject(mqttTopic, newMqttTopic);
AQH_Storage_AddMqttTopic(sto, mqttTopic);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
AQH_MqttTopic_free(newMqttTopic);
rv=AqHomeHttpService_UnlockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking storage");
return GWEN_ERROR_IO;
}
return 0;
}
void _setFromObject(AQH_MQTT_TOPIC *mqttTopic, const AQH_MQTT_TOPIC *srcMqttTopic)
{
AQH_MqttTopic_SetDeviceId(mqttTopic, AQH_MqttTopic_GetDeviceId(srcMqttTopic));
AQH_MqttTopic_SetTopic(mqttTopic, AQH_MqttTopic_GetTopic(srcMqttTopic));
AQH_MqttTopic_SetDataType(mqttTopic, AQH_MqttTopic_GetDataType(srcMqttTopic));
}
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_MQTT_TOPIC *mqttTopic;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
mqttTopic=AQH_Storage_GetMqttTopicById(sto, id);
if (mqttTopic) {
GWEN_DB_NODE *db;
db=GWEN_DB_Group_new("mqttTopic");
AQH_MqttTopic_toDb(mqttTopic, db);
return db;
}
return NULL;
}
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/mqtttopics/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Add MQTT Topic"));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/mqtttopics/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Edit MQTT Topic"),
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const GWEN_STRINGLIST *seenTopicsList;
const AQH_DEVICE_LIST *deviceList;
unsigned long int selectedDeviceId=0;
int dataType;
char numbuf[16];
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
deviceList=AQH_Storage_GetDeviceList(sto);
selectedDeviceId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "deviceId", 0, 0):0);
snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedDeviceId);
numbuf[sizeof(numbuf)-1]=0;
dataType=dbValues?GWEN_DB_GetIntValue(dbValues, "dataType", 0, AQH_MqttTopicType_Num):0;
/* topic */
GWEN_Buffer_AppendArgs(pageBuf,
"<table>"
"<tr>"
" <td><label for=\"topic\">%s: </label></td>"
" <td>"
" <input list=\"seenTopics\" type=\"text\" name=\"topic\" id=\"topic\" value=\"%s\" size=\"64\" required>\n"
" <datalist id=\"seenTopics\">",
I18N("MQTT Topic"),
dbValues?GWEN_DB_GetCharValue(dbValues, "topic", 0, ""):"");
seenTopicsList=AQH_Storage_GetRecvdTopicList(sto);
if (seenTopicsList && GWEN_StringList_Count(seenTopicsList)) {
GWEN_STRINGLISTENTRY *se;
se=GWEN_StringList_FirstEntry(seenTopicsList);
while(se) {
const char *s=GWEN_StringListEntry_Data(se);
if (s && *s) {
DBG_INFO(NULL, "Adding MQTT string %s", s);
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">\n", s);
}
se=GWEN_StringListEntry_Next(se);
}
}
else {
}
GWEN_Buffer_AppendString(pageBuf, "</datalist></td></tr>");
/* device */
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td><label for=\"deviceId\">%s: </label></td>"
"<td><select id=\"deviceId\" name=\"deviceId\">",
I18N("Device"));
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>\n", I18N("-- select device --"));
if (deviceList) {
const AQH_DEVICE *device;
device=AQH_Device_List_First(deviceList);
while(device) {
const char *deviceName;
deviceName=AQH_Device_GetName(device);
if (deviceName && *deviceName) {
snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_Device_GetId(device));
numbuf[sizeof(numbuf)-1]=0;
if (selectedDeviceId && AQH_Device_GetId(device)==selectedDeviceId)
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>\n", numbuf, deviceName);
else
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>\n", numbuf, deviceName);
}
device=AQH_Device_List_Next(device);
}
}
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>\n");
/* data type */
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td><label for=\"dataType\">%s: </label></td>"
"<td><select id=\"dataType\" name=\"dataType\">",
I18N("Data Type"));
if (dataType==AQH_MqttTopicType_Num)
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" selected>%s</option>", AQH_MqttTopicType_Num, I18N("numeric"));
else
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" >%s</option>", AQH_MqttTopicType_Num, I18N("numeric"));
if (dataType==AQH_MqttTopicType_Json)
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" selected>%s</option>", AQH_MqttTopicType_Json, I18N("JSON"));
else
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" >%s</option>", AQH_MqttTopicType_Json, I18N("JSON"));
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>\n");
if (seenTopicsList && GWEN_StringList_Count(seenTopicsList)) {
GWEN_STRINGLISTENTRY *se;
GWEN_Buffer_AppendArgs(pageBuf, "<tr><td valign=\"top\"><label for=\"receivedTopicsList\">%s: </label></td>", I18N("Received Topics"));
GWEN_Buffer_AppendString(pageBuf, "<td><output name=\"receivedTopicsList\" id=\"receivedTopicsList\">");
se=GWEN_StringList_FirstEntry(seenTopicsList);
while(se) {
const char *s=GWEN_StringListEntry_Data(se);
if (s && *s)
GWEN_Buffer_AppendArgs(pageBuf, "%s<br>\n", s);
se=GWEN_StringListEntry_Next(se);
}
GWEN_Buffer_AppendString(pageBuf, "</output></td></tr>");
}
GWEN_Buffer_AppendString(pageBuf, "</tbody></table>\n");
}
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_MQTT_TOPIC_LIST *rl;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2>"
"<table class=\"dataTable\">"
"<thead>"
" <tr><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
"</thead>",
I18N("Mqtt Topics"),
I18N("Topic"),
I18N("Device"),
I18N("Datatype"));
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
rl=AQH_Storage_GetMqttTopicList(sto);
if (rl) {
const AQH_MQTT_TOPIC *mqttTopic;
mqttTopic=AQH_MqttTopic_List_First(rl);
while(mqttTopic) {
long unsigned int id;
int deviceId;
const char *topic;
int dataType;
const char *deviceName=NULL;
const AQH_DEVICE *device=NULL;
id=(long unsigned int) AQH_MqttTopic_GetId(mqttTopic);
deviceId=(long unsigned int) AQH_MqttTopic_GetDeviceId(mqttTopic);
if (deviceId>0)
device=AQH_Storage_GetDeviceById(sto, deviceId);
if (device)
deviceName=AQH_Device_GetName(device);
topic=AQH_MqttTopic_GetTopic(mqttTopic);
dataType=AQH_MqttTopic_GetDataType(mqttTopic);
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td>%s</td><td>%s</td><td>%s</td>"
"<td><a href=\"/mqtttopics/edit/%lu\">"
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
"</tr>",
topic?topic:"",
deviceName?deviceName:"",
AQH_MqttTopicType_toString(dataType),
id);
mqttTopic=AQH_MqttTopic_List_Next(mqttTopic);
}
}
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/mqtttopics/add\">%s</a><br>", I18N("Add MqttTopic"));
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_MQTTTOPICS_H
#define AQHOME_STORAGE_U_MQTTTOPICS_H
#include "aqhome/http/urlhandler.h"
AQH_HTTP_URLHANDLER *AQH_MqttTopicsHttpUrlHandler_new(AQH_SERVICE *sv);
#endif

View File

@@ -1,458 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_objects_p.h"
#include "./u_base.h"
#include "./aqhomehttp.h"
#include "aqhome/http/httpservice_http.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
GWEN_INHERIT(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS);
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf);
static void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf);
static void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf);
static GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id);
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static GWEN_MSG *_addOrEditAndCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb);
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_HTTP_URLHANDLER *AQH_ObjectsHttpUrlHandler_new(AQH_SERVICE *sv,
uint32_t neededPermsList,
uint32_t neededPermsAdd,
uint32_t neededPermsDel,
uint32_t neededPermsEdit,
const char *urlForObjectList)
{
AQH_HTTP_URLHANDLER *uh;
AQH_URLHANDLER_OBJECTS *xuh;
uh=AQH_HttpUrlHandler_new(sv);
GWEN_NEW_OBJECT(AQH_URLHANDLER_OBJECTS, xuh);
GWEN_INHERIT_SETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh, xuh, _freeData);
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
xuh->neededPermsList=neededPermsList;
xuh->neededPermsAdd=neededPermsAdd;
xuh->neededPermsDel=neededPermsDel;
xuh->neededPermsEdit=neededPermsEdit;
xuh->urlForObjectList=urlForObjectList?strdup(urlForObjectList):NULL;
return uh;
}
void _freeData(void *bp, void *p)
{
AQH_URLHANDLER_OBJECTS *xuh;
xuh=(AQH_URLHANDLER_OBJECTS*)p;
free(xuh->urlForObjectList);
GWEN_FREE_OBJECT(xuh);
}
void AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN fn)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh) {
xuh->addOrEditObjectFn=fn;
}
}
void AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(AQH_HTTP_URLHANDLER *uh,
AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN fn)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh) {
xuh->findObjectByIdAndReturnAsDbFn=fn;
}
}
void AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN fn)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh) {
xuh->writeAddPageFn=fn;
}
}
void AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN fn)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh) {
xuh->writeEditPageFn=fn;
}
}
void AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(AQH_HTTP_URLHANDLER *uh,
AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN fn)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh) {
xuh->listObjectsIntoBufferFn=fn;
}
}
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
if (GWEN_INHERIT_ISOFTYPE(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh)) {
const char *protocol;
const char *cmd;
GWEN_MSG *msgOut;
AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome");
protocol=AQH_HttpRequest_GetProtocol(rq);
AQH_HttpRequest_SetupUrlPathMembers(rq);
if (AQH_HttpRequest_GetUrlPathMembers(rq)==NULL) {
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
cmd=AQH_HttpRequest_GetCommand(rq);
if (cmd && *cmd) {
if (strcasecmp(cmd, "GET")==0)
msgOut=_handleGet(uh, rq);
else if (strcasecmp(cmd, "POST")==0)
msgOut=_handlePost(uh, rq);
else {
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
}
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
return GWEN_ERROR_INVALID;
}
}
else {
DBG_ERROR(NULL, "Not an AQH_URLHANDLER_OBJECTS object");
return GWEN_ERROR_INTERNAL;
}
}
GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
GWEN_BUFFER *pageBuf;
int rv;
GWEN_MSG *msgOut=NULL;
const char *protocol;
const GWEN_STRINGLIST *sl;
const char *s;
protocol=AQH_HttpRequest_GetProtocol(rq);
pageBuf=GWEN_Buffer_new(0, 2048, 0, 1);
/* header */
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
GWEN_Buffer_free(pageBuf);
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
}
/* middle part (header - middle - footer) */
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
s=GWEN_StringList_StringAt(sl, 1);
if (!(s && *s))
s="list";
if (strcasecmp(s, "list")==0)
_handleGetList(uh, rq, pageBuf);
else if (strcasecmp(s, "add")==0)
_handleGetAdd(uh, rq, pageBuf);
else if (strcasecmp(s, "edit")==0)
_handleGetEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0), pageBuf);
else {
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
GWEN_Buffer_free(pageBuf);
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
}
/* footer */
rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers");
GWEN_Buffer_free(pageBuf);
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
}
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
GWEN_Buffer_free(pageBuf);
return msgOut;
}
GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
GWEN_DB_NODE *db;
const GWEN_STRINGLIST *sl;
const char *protocol;
const char *s;
DBG_ERROR(NULL, "POST:");
db=AQH_HttpRequest_GetDbPostBody(rq);
GWEN_DB_Dump(db, 2);
protocol=AQH_HttpRequest_GetProtocol(rq);
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
s=GWEN_StringList_StringAt(sl, 1);
if (s && *s) {
if (strcasecmp(s, "add")==0)
return _handlePostAdd(uh, rq);
else if (strcasecmp(s, "edit")==0)
return _handlePostEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0));
else {
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
}
}
else {
DBG_ERROR(NULL, "Invalid url (2nd member missing)");
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
}
}
void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
uint32_t perms;
DBG_ERROR(NULL, "LIST");
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & xuh->neededPermsList) {
_listObjectsIntoBuffer(uh, pageBuf);
}
else {
GWEN_Buffer_AppendArgs(pageBuf, "<p>%s</p>", I18N("No permissions to see list of objects."));
}
}
void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
uint32_t perms;
DBG_ERROR(NULL, "ADD");
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & xuh->neededPermsAdd) {
_writeAddPage(uh, rq, NULL, pageBuf);
}
else {
DBG_INFO(NULL, "No permissions to add.");
GWEN_Buffer_AppendArgs(pageBuf, "<p><font color=\"red\">%s</font></p>", I18N("No permissions to add an object."));
}
}
void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
uint32_t perms;
DBG_ERROR(NULL, "EDIT");
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & xuh->neededPermsEdit) {
if (id>0) {
GWEN_DB_NODE *db;
db=_findObjectByIdAndReturnAsDb(uh, id);
if (db) {
_writeEditPage(uh, rq, db, pageBuf);
GWEN_DB_Group_free(db);
}
else {
DBG_ERROR(NULL, "Object %d not found", id);
GWEN_Buffer_AppendArgs(pageBuf, "<p><font color=\"red\">%s</font></p>", I18N("Object not found."));
}
}
else {
DBG_ERROR(NULL, "Missing object id");
GWEN_Buffer_AppendArgs(pageBuf, "<p><font color=\"red\">%s</font></p>", I18N("Missing or invalid object id."));
}
}
else {
DBG_INFO(NULL, "No permissions to edit.");
GWEN_Buffer_AppendArgs(pageBuf, "<p>%s</p>", I18N("No permissions to edit."));
}
}
GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
uint32_t perms;
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & xuh->neededPermsAdd)
return _addOrEditAndCreateResponse(uh, rq, 0, _writeAddPage);
else {
DBG_INFO(NULL, "No perms to add object");
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 403, "Forbidden",
AQH_HttpRequest_GetProtocol(rq), NULL);
}
}
GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
uint32_t perms;
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & xuh->neededPermsEdit) {
return _addOrEditAndCreateResponse(uh, rq, id, _writeEditPage);
}
else {
DBG_INFO(NULL, "No perms to edit");
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 403, "Forbidden",
AQH_HttpRequest_GetProtocol(rq), NULL);
}
}
GWEN_MSG *_addOrEditAndCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
AQH_SERVICE *sv;
GWEN_DB_NODE *db;
int rv;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
db=AQH_HttpRequest_GetDbPostBody(rq);
rv=_addOrEditObject(uh, db, id);
if (rv<0)
return AQH_BaseHttpUrlHandler_CreateResponseForErrorCode(uh, rq, rv, cb, db);
return AQH_HttpService_CreateRedirectingResponseMsg(sv, AQH_HttpRequest_GetProtocol(rq), xuh->urlForObjectList);
}
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh->addOrEditObjectFn)
return xuh->addOrEditObjectFn(uh, db, id);
return GWEN_ERROR_NOT_IMPLEMENTED;
}
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh->findObjectByIdAndReturnAsDbFn)
return xuh->findObjectByIdAndReturnAsDbFn(uh, id);
return NULL;
}
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh->writeAddPageFn)
return xuh->writeAddPageFn(uh, rq, dbValues, pageBuf);
return GWEN_ERROR_NOT_IMPLEMENTED;
}
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh->writeEditPageFn)
return xuh->writeEditPageFn(uh, rq, dbValues, pageBuf);
return GWEN_ERROR_NOT_IMPLEMENTED;
}
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
{
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
if (xuh->listObjectsIntoBufferFn)
xuh->listObjectsIntoBufferFn(uh, pageBuf);
}

View File

@@ -1,45 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_OBJECTS_H
#define AQHOME_STORAGE_U_OBJECTS_H
#include "aqhome/http/urlhandler.h"
AQH_HTTP_URLHANDLER *AQH_ObjectsHttpUrlHandler_new(AQH_SERVICE *sv,
uint32_t neededPermsList,
uint32_t neededPermsAdd,
uint32_t neededPermsDel,
uint32_t neededPermsEdit,
const char *urlForObjectList);
typedef int (*AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN)(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
typedef GWEN_DB_NODE* (*AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN)(AQH_HTTP_URLHANDLER *uh, int id);
typedef int (*AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN)(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq,
GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
typedef int (*AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN)(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq,
GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
typedef void (*AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN)(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
void AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN fn);
void AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(AQH_HTTP_URLHANDLER *uh,
AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN fn);
void AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN fn);
void AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN fn);
void AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(AQH_HTTP_URLHANDLER *uh,
AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN fn);
#endif

View File

@@ -1,37 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_OBJECTS_P_H
#define AQHOME_STORAGE_U_OBJECTS_P_H
#include "./u_objects.h"
#include <gwenhywfar/stringlist.h>
typedef struct AQH_URLHANDLER_OBJECTS AQH_URLHANDLER_OBJECTS;
struct AQH_URLHANDLER_OBJECTS {
uint32_t neededPermsList;
uint32_t neededPermsAdd;
uint32_t neededPermsDel;
uint32_t neededPermsEdit; /* e.g. AQHOME_HTTP_PERMS_EDIT_ROOM */
char *urlForObjectList;
AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN addOrEditObjectFn;
AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN findObjectByIdAndReturnAsDbFn;
AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN writeAddPageFn;
AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN writeEditPageFn;
AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN listObjectsIntoBufferFn;
};
#endif

View File

@@ -1,272 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_rooms.h"
#include "./u_objects.h"
#include "./aqhomehttp.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _setFromObject(AQH_ROOM *r, const AQH_ROOM *srcRoom);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_ObjectsHttpUrlHandler_new(sv,
AQHOME_HTTP_PERMS_LIST_ROOMS,
AQHOME_HTTP_PERMS_ADD_ROOM,
AQHOME_HTTP_PERMS_DEL_ROOM,
AQHOME_HTTP_PERMS_EDIT_ROOM,
"/rooms/list");
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
return uh;
}
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
AQH_ROOM *newRoom;
const char *roomName;
int rv;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
newRoom=AQH_Room_fromDb(db);
roomName=AQH_Room_GetName(newRoom);
if (!(roomName && *roomName)) {
DBG_INFO(NULL, "Missing room name");
AQH_Room_free(newRoom);
return GWEN_ERROR_INVALID;
}
rv=AqHomeHttpService_LockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error locking storage");
AQH_Room_free(newRoom);
return GWEN_ERROR_IO;
}
if (id>0) {
AQH_ROOM *r;
DBG_INFO(NULL, "Edit existing room");
r=AQH_Storage_GetRoomById(sto, id);
if (r==NULL) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "Room %d not found", id);
AQH_Room_free(newRoom);
return GWEN_ERROR_NOT_FOUND;
}
AQH_Room_SetId(r, id);
_setFromObject(r, newRoom);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
else {
AQH_ROOM *r;
DBG_INFO(NULL, "Adding new room");
r=AQH_Storage_GetRoomByName(sto, roomName);
if (r) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "Room %s exists", roomName);
AQH_Room_free(newRoom);
return GWEN_ERROR_FOUND;
}
r=AQH_Room_new();
AQH_Room_SetId(r, 0);
_setFromObject(r, newRoom);
AQH_Storage_AddRoom(sto, r);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
AQH_Room_free(newRoom);
rv=AqHomeHttpService_UnlockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking storage");
return GWEN_ERROR_IO;
}
return 0;
}
void _setFromObject(AQH_ROOM *r, const AQH_ROOM *srcRoom)
{
AQH_Room_SetName(r, AQH_Room_GetName(srcRoom));
AQH_Room_SetDescription(r, AQH_Room_GetDescription(srcRoom));
}
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_ROOM *r;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
r=AQH_Storage_GetRoomById(sto, id);
if (r) {
GWEN_DB_NODE *db;
db=GWEN_DB_Group_new("room");
AQH_Room_toDb(r, db);
return db;
}
return NULL;
}
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/rooms/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Add Room"));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/rooms/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Edit Room"),
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
" <table>"
" <tr>"
" <td><label for=\"name\">%s: </label></td>"
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
" </tr>"
" <tr>"
" <td><label for=\"description\">%s: </label></td>"
" <td><input type=\"text\" name=\"description\" value=\"%s\" ></td>"
" </tr>"
" </table>",
I18N("Name"),
dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"",
I18N("Description"),
dbValues?GWEN_DB_GetCharValue(dbValues, "description", 0, ""):"");
}
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_ROOM_LIST *rl;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2>"
"<table class=\"dataTable\">"
"<thead>"
" <tr><th>%s</th><th>%s</th><th></th></tr>"
"</thead>",
I18N("Rooms"),
I18N("Name"),
I18N("Description"));
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
rl=AQH_Storage_GetRoomList(sto);
if (rl) {
const AQH_ROOM *r;
r=AQH_Room_List_First(rl);
while(r) {
long unsigned int id;
const char *name;
const char *descr;
id=(long unsigned int) AQH_Room_GetId(r);
name=AQH_Room_GetName(r);
descr=AQH_Room_GetDescription(r);
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td>%s</td><td>%s</td>"
"<td><a href=\"/rooms/edit/%lu\">"
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
"</tr>",
name?name:"", descr?descr:"", id);
r=AQH_Room_List_Next(r);
}
}
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/rooms/add\">%s</a><br>", I18N("Add Room"));
}

View File

@@ -1,24 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_ROOMS_H
#define AQHOME_STORAGE_U_ROOMS_H
#include "aqhome/http/urlhandler.h"
#include <gwenhywfar/endpoint.h>
AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv);
#endif

View File

@@ -1,291 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_static_p.h"
#include "./aqhomehttp.h"
#include "aqhome/http/httpservice.h"
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice_conf.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
GWEN_INHERIT(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC);
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static void _readFileList(AQH_HTTP_URLHANDLER *uh);
static GWEN_BUFFER *_readFileIntoBuffer(AQH_HTTP_URLHANDLER *uh, const char *requestedFilename);
static const char *_getContentTypeFromFilename(const char *filename);
static GWEN_MSG *_createFileResponseMsg(AQH_HTTP_URLHANDLER *uh,
const char *protocol,
const char *contentType,
const uint8_t *ptr, uint32_t len);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_HTTP_URLHANDLER *AQH_StaticHttpUrlHandler_new(AQH_SERVICE *sv, const char *folder)
{
AQH_HTTP_URLHANDLER *uh;
AQH_URLHANDLER_STATIC *xuh;
uh=AQH_HttpUrlHandler_new(sv);
GWEN_NEW_OBJECT(AQH_URLHANDLER_STATIC, xuh);
GWEN_INHERIT_SETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh, xuh, _freeData);
AQH_HttpUrlHandler_SetFolder(uh, folder);
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
_readFileList(uh);
return uh;
}
void _freeData(void *bp, void *p)
{
AQH_URLHANDLER_STATIC *xuh;
xuh=(AQH_URLHANDLER_STATIC*)p;
GWEN_StringList_free(xuh->fileList);
GWEN_FREE_OBJECT(xuh);
}
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
const char *protocol;
const char *cmd;
GWEN_MSG *msgOut;
AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome");
AQH_HttpRequest_SetupUrlPathMembers(rq);
protocol=AQH_HttpRequest_GetProtocol(rq);
cmd=AQH_HttpRequest_GetCommand(rq);
if (cmd && *cmd) {
if (strcasecmp(cmd, "GET")==0)
msgOut=_handleGet(uh, rq);
else {
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
}
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
return 0;
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
return GWEN_ERROR_INVALID;
}
}
GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
AQH_URLHANDLER_STATIC *xuh;
AQH_SERVICE *sv;
const char *protocol;
const GWEN_STRINGLIST *sl;
xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh);
if (xuh==NULL) {
DBG_ERROR(NULL, "Not a AQH_URLHANDLER_STATIC object");
return NULL;
}
sv=AQH_HttpUrlHandler_GetHttpService(uh);
protocol=AQH_HttpRequest_GetProtocol(rq);
/* handle middle part (header - middle - footer) */
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
if (sl) {
const char *s;
s=GWEN_StringList_StringAt(sl, 1);
if (!(s && *s)) {
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
return AQH_HttpService_CreateResponseMsg(sv, 404, "Not found", protocol, NULL);
}
else {
GWEN_BUFFER *fileBuf;
const char *contentType;
GWEN_MSG *msgOut;
contentType=_getContentTypeFromFilename(s);
DBG_INFO(NULL, "Reading file \"%s\" (%s)", s, contentType);
fileBuf=_readFileIntoBuffer(uh, s);
if (fileBuf==NULL) {
DBG_INFO(NULL, "here");
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
}
msgOut=_createFileResponseMsg(uh, protocol, contentType,
(const uint8_t*) GWEN_Buffer_GetStart(fileBuf), GWEN_Buffer_GetUsedBytes(fileBuf));
GWEN_Buffer_free(fileBuf);
return msgOut;
}
}
else {
DBG_ERROR(NULL, "No list of url members");
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
}
}
void _readFileList(AQH_HTTP_URLHANDLER *uh)
{
AQH_URLHANDLER_STATIC *xuh;
const char *folder;
xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh);
GWEN_StringList_free(xuh->fileList);
xuh->fileList=NULL;
folder=AQH_HttpUrlHandler_GetFolder(uh);
if (folder && *folder) {
GWEN_STRINGLIST *fileList;
fileList=AQH_HttpService_GetFolderFileList(folder, NULL, 1);
if (fileList) {
GWEN_StringList_RemoveString(fileList, ".");
GWEN_StringList_RemoveString(fileList, "..");
GWEN_StringList_free(xuh->fileList);
xuh->fileList=fileList;
}
else {
DBG_INFO(NULL, "No file list (empty folder?)");
}
}
}
GWEN_BUFFER *_readFileIntoBuffer(AQH_HTTP_URLHANDLER *uh, const char *requestedFilename)
{
AQH_URLHANDLER_STATIC *xuh;
const char *folder;
xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh);
folder=AQH_HttpUrlHandler_GetFolder(uh);
if (!(xuh->fileList && GWEN_StringList_Count(xuh->fileList)>0)) {
DBG_INFO(NULL, "Reading file list for folder \"%s\"", folder);
_readFileList(uh);
}
if (!(xuh->fileList && GWEN_StringList_Count(xuh->fileList)>0)) {
DBG_INFO(NULL, "No file list (empty or missing/bad folder? Permissions?");
return NULL;
}
if (GWEN_StringList_HasString(xuh->fileList, requestedFilename)) {
GWEN_BUFFER *nameBuf;
GWEN_BUFFER *fileBuf;
int rv;
fileBuf=GWEN_Buffer_new(0, 1024, 0, 1);
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(nameBuf, folder);
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(nameBuf, requestedFilename);
DBG_INFO(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(nameBuf));
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(nameBuf), fileBuf);
if (rv<0) {
DBG_ERROR(NULL, "Error reading file \"%s\" (%d)", GWEN_Buffer_GetStart(nameBuf), rv);
GWEN_Buffer_free(nameBuf);
GWEN_Buffer_free(fileBuf);
return NULL;
}
GWEN_Buffer_free(nameBuf);
return fileBuf;
}
else {
DBG_INFO(NULL, "File \"%s\" not found in folder \"%s\"", requestedFilename, folder);
return NULL;
}
}
GWEN_MSG *_createFileResponseMsg(AQH_HTTP_URLHANDLER *uh,
const char *protocol,
const char *contentType,
const uint8_t *ptr, uint32_t len)
{
GWEN_BUFFER *buf;
GWEN_MSG *msg;
GWEN_DB_NODE *db;
buf=GWEN_Buffer_new(0, len+256, 0, 1);
AQH_HttpService_AddStatusLine(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, buf);
db=GWEN_DB_Group_new("header");
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive");
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", contentType);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", len);
AQH_HttpService_AddHeader(AQH_HttpUrlHandler_GetHttpService(uh), db, buf);
GWEN_DB_Group_free(db);
GWEN_Buffer_AppendBytes(buf, (const char *) ptr, len);
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
GWEN_Buffer_free(buf);
return msg;
}
const char *_getContentTypeFromFilename(const char *filename)
{
if (filename) {
const char *s;
s=strrchr(filename, '.');
if (s) {
if (strcasecmp(s, ".png")==0)
return "image/png";
else if (strcasecmp(s, ".jpg")==0)
return "image/jpg";
}
}
return "application/x-binary";
}

View File

@@ -1,24 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_STATIC_H
#define AQHOME_STORAGE_U_STATIC_H
#include "aqhome/http/urlhandler.h"
#include <gwenhywfar/endpoint.h>
AQH_HTTP_URLHANDLER *AQH_StaticHttpUrlHandler_new(AQH_SERVICE *sv, const char *folder);
#endif

View File

@@ -1,27 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_STATIC_P_H
#define AQHOME_STORAGE_U_STATIC_P_H
#include "./u_static.h"
#include <gwenhywfar/stringlist.h>
typedef struct AQH_URLHANDLER_STATIC AQH_URLHANDLER_STATIC;
struct AQH_URLHANDLER_STATIC {
GWEN_STRINGLIST *fileList;
};
#endif

View File

@@ -1,340 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./u_values.h"
#include "./u_objects.h"
#include "./aqhomehttp.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_ObjectsHttpUrlHandler_new(sv,
AQHOME_HTTP_PERMS_LIST_VALUES,
AQHOME_HTTP_PERMS_ADD_VALUE,
AQHOME_HTTP_PERMS_DEL_VALUE,
AQHOME_HTTP_PERMS_EDIT_VALUE,
"/values/list");
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
return uh;
}
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
AQH_VALUE *newValue;
const char *valueName;
int rv;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
newValue=AQH_Value_fromDb(db);
valueName=AQH_Value_GetNameForSystem(newValue);
if (!(valueName && *valueName)) {
DBG_INFO(NULL, "Missing value name");
AQH_Value_free(newValue);
return GWEN_ERROR_INVALID;
}
rv=AqHomeHttpService_LockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error locking storage");
AQH_Value_free(newValue);
return GWEN_ERROR_IO;
}
if (id>0) {
AQH_VALUE *value;
DBG_INFO(NULL, "Edit existing value");
value=AQH_Storage_GetValueById(sto, id);
if (value==NULL) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "Value %d not found", id);
AQH_Value_free(newValue);
return GWEN_ERROR_NOT_FOUND;
}
AQH_Value_SetId(value, id);
_setFromObject(value, newValue);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
else {
AQH_VALUE *value;
DBG_INFO(NULL, "Adding new value");
value=AQH_Storage_GetValueByName(sto, valueName);
if (value) {
AqHomeHttpService_UnlockStorage(sv);
DBG_ERROR(NULL, "Value %s exists", valueName);
AQH_Value_free(newValue);
return GWEN_ERROR_FOUND;
}
value=AQH_Value_new();
AQH_Value_SetId(value, 0);
_setFromObject(value, newValue);
AQH_Storage_AddValue(sto, value);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
}
AQH_Value_free(newValue);
rv=AqHomeHttpService_UnlockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking storage");
return GWEN_ERROR_IO;
}
return 0;
}
void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue)
{
AQH_Value_SetName(value, AQH_Value_GetName(srcValue));
AQH_Value_SetTopicId(value, AQH_Value_GetTopicId(srcValue));
AQH_Value_SetValueType(value, AQH_Value_GetValueType(srcValue));
AQH_Value_SetValueUnits(value, AQH_Value_GetValueUnits(srcValue));
AQH_Value_SetDataPath(value, AQH_Value_GetDataPath(srcValue));
}
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_VALUE *value;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
value=AQH_Storage_GetValueById(sto, id);
if (value) {
GWEN_DB_NODE *db;
db=GWEN_DB_Group_new("value");
AQH_Value_toDb(value, db);
return db;
}
return NULL;
}
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/values/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Add Value"));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/values/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Edit Value"),
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
return 0;
}
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_MQTT_TOPIC_LIST *topicList;
unsigned long int selectedTopicId=0;
char numbuf[16];
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
topicList=AQH_Storage_GetMqttTopicList(sto);
selectedTopicId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "TopicId", 0, 0):0);
snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedTopicId);
numbuf[sizeof(numbuf)-1]=0;
GWEN_Buffer_AppendArgs(pageBuf,
" <table>"
" <tr>"
" <td><label for=\"name\">%s: </label></td>"
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
" </tr>",
I18N("Name"),
dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"");
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td><label for=\"topicId\">%s: </label></td>"
"<td><select id=\"topicId\" name=\"topicId\">",
I18N("Topic"));
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>", I18N("-- select topic --"));
if (topicList) {
const AQH_MQTT_TOPIC *topic;
topic=AQH_MqttTopic_List_First(topicList);
while(topic) {
const char *topicName;
topicName=AQH_MqttTopic_GetTopic(topic);
if (topicName && *topicName) {
snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_MqttTopic_GetId(topic));
numbuf[sizeof(numbuf)-1]=0;
if (selectedTopicId && AQH_MqttTopic_GetId(topic)==selectedTopicId)
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>", numbuf, topicName);
else
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>", numbuf, topicName);
}
topic=AQH_MqttTopic_List_Next(topic);
}
}
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>");
GWEN_Buffer_AppendArgs(pageBuf,
" <tr>"
" <td><label for=\"valueUnits\">%s: </label></td>"
" <td><input type=\"text\" name=\"valueUnits\" value=\"%s\"></td>"
" </tr>",
I18N("Units"),
dbValues?GWEN_DB_GetCharValue(dbValues, "valueUnits", 0, ""):"");
GWEN_Buffer_AppendArgs(pageBuf,
" <tr>"
" <td><label for=\"dataPath\">%s: </label></td>"
" <td><input type=\"text\" name=\"dataPath\" value=\"%s\"></td>"
" </tr>"
" </table>",
I18N("Data Path (JSON)"),
dbValues?GWEN_DB_GetCharValue(dbValues, "dataPath", 0, ""):"");
}
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
{
AQH_SERVICE *sv;
AQH_STORAGE *sto;
const AQH_VALUE_LIST *rl;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2>"
"<table class=\"dataTable\">"
"<thead>"
" <tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
"</thead>",
I18N("Values"),
I18N("Name"),
I18N("Topic"),
I18N("Units"),
I18N("Data Path"));
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
rl=AQH_Storage_GetValueList(sto);
if (rl) {
const AQH_VALUE *value;
value=AQH_Value_List_First(rl);
while(value) {
long unsigned int id;
int topicId;
const char *name;
const char *topicName=NULL;
const char *valueUnits;
const char *dataPath;
const AQH_MQTT_TOPIC *topic=NULL;
id=(long unsigned int) AQH_Value_GetId(value);
topicId=(long unsigned int) AQH_Value_GetTopicId(value);
if (topicId>0)
topic=AQH_Storage_GetMqttTopicById(sto, topicId);
if (topic)
topicName=AQH_MqttTopic_GetTopic(topic);
name=AQH_Value_GetName(value);
valueUnits=AQH_Value_GetValueUnits(value);
dataPath=AQH_Value_GetDataPath(value);
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
"<td><a href=\"/values/edit/%lu\">"
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
"</tr>",
name?name:"",
topicName?topicName:"",
valueUnits?valueUnits:"",
dataPath?dataPath:"",
id);
value=AQH_Value_List_Next(value);
}
}
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/values/add\">%s</a><br>", I18N("Add Value"));
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_STORAGE_U_VALUES_H
#define AQHOME_STORAGE_U_VALUES_H
#include "aqhome/http/urlhandler.h"
AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv);
#endif