diff --git a/apps/aqhome-storage/0BUILD b/apps/aqhome-storage/0BUILD
index 436a34c..66a4e77 100644
--- a/apps/aqhome-storage/0BUILD
+++ b/apps/aqhome-storage/0BUILD
@@ -38,6 +38,7 @@
aqhomestorage_p.h
aqhomestorage.h
init.h
+ http.h
@@ -45,6 +46,7 @@
aqhomestorage.c
init.c
+ http.c
main.c
diff --git a/apps/aqhome-storage/aqhomestorage.h b/apps/aqhome-storage/aqhomestorage.h
index b4584ff..a9ba6ba 100644
--- a/apps/aqhome-storage/aqhomestorage.h
+++ b/apps/aqhome-storage/aqhomestorage.h
@@ -11,6 +11,7 @@
#include "aqhome/data/storage.h"
+#include "aqhome/service/session.h"
#include
diff --git a/apps/aqhome-storage/aqhomestorage_p.h b/apps/aqhome-storage/aqhomestorage_p.h
index 704ec0f..737525f 100644
--- a/apps/aqhome-storage/aqhomestorage_p.h
+++ b/apps/aqhome-storage/aqhomestorage_p.h
@@ -22,6 +22,9 @@
#define AQHOME_STORAGE_DEFAULT_MQTT_KEEPALIVE 600
#define AQHOME_STORAGE_DEFAULT_MQTT_PORT 1883
+#define AQHOME_STORAGE_SITEHEADER "site-header.html"
+#define AQHOME_STORAGE_SITEFOOTER "site-footer.html"
+
struct AQHOME_STORAGE {
@@ -36,7 +39,6 @@ struct AQHOME_STORAGE {
AQH_STORAGE *storage;
char *pidFile;
-
};
#endif
diff --git a/apps/aqhome-storage/html/site_footer.html b/apps/aqhome-storage/html/site_footer.html
new file mode 100644
index 0000000..635e1f2
--- /dev/null
+++ b/apps/aqhome-storage/html/site_footer.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+AqHome Storage Service
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/aqhome-storage/html/site_header.html b/apps/aqhome-storage/html/site_header.html
new file mode 100644
index 0000000..f4b292b
--- /dev/null
+++ b/apps/aqhome-storage/html/site_header.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+AqHome Storage Service
+
+
+
diff --git a/apps/aqhome-storage/http.c b/apps/aqhome-storage/http.c
new file mode 100644
index 0000000..429b178
--- /dev/null
+++ b/apps/aqhome-storage/http.c
@@ -0,0 +1,192 @@
+/****************************************************************************
+ * 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
+#endif
+
+
+#include "./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
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_SYS_TYPES_H
+# include
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+# include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * defines
+ * ------------------------------------------------------------------------------------------------
+ */
+
+//#define I18N(msg) msg
+#define I18S(msg) msg
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+
+static GWEN_MSG *_handleUrl(AQHOME_STORAGE *aqh, const GWEN_MSG *msgReceived, const GWEN_URL *url);
+static GWEN_MSG *_handleUrl_login(AQHOME_STORAGE *aqh, const GWEN_MSG *msgReceived, const GWEN_URL *url);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * implementations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+
+int AqHomeStorage_AddFile(GWEN_UNUSED AQHOME_STORAGE *aqh, GWEN_UNUSED AQH_SESSION *session, const char *fname, GWEN_BUFFER *buf)
+{
+ if (fname && *fname) {
+ int rv;
+
+ rv=GWEN_SyncIo_Helper_ReadFile(fname, buf);
+ if (rv<0) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"%s\": %d", fname, rv);
+ return rv;
+ }
+ }
+
+ return 0;
+}
+
+
+
+int AqHomeStorage_AddSiteHeader(AQHOME_STORAGE *aqh, AQH_SESSION *session, GWEN_BUFFER *buf)
+{
+ return AqHomeStorage_AddFile(aqh, session, AQHOME_STORAGE_SITEHEADER, buf);
+}
+
+
+
+int AqHomeStorage_AddSiteFooter(AQHOME_STORAGE *aqh, AQH_SESSION *session, GWEN_BUFFER *buf)
+{
+ return AqHomeStorage_AddFile(aqh, session, AQHOME_STORAGE_SITEFOOTER, buf);
+}
+
+
+
+GWEN_MSG *AqHomeStorage_HandleMessage(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msgReceived)
+{
+ GWEN_DB_NODE *dbParsedMsgInfo;
+ GWEN_DB_NODE *dbCommand;
+ GWEN_DB_NODE *dbHeader;
+ const char *sCmd;
+ const char *sUrl;
+ GWEN_URL *gUrl;
+ const char *sPath;
+ GWEN_MSG *msgToSend;
+
+ dbParsedMsgInfo=GWEN_Msg_GetDbParsedInfo(msgReceived);
+ if (dbParsedMsgInfo==NULL) {
+ DBG_ERROR(AQH_LOGDOMAIN, "No parsed msg info in received message, SNH");
+ return NULL;
+ }
+ dbCommand=GWEN_DB_GetGroup(dbParsedMsgInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "command");
+ dbHeader=GWEN_DB_GetGroup(dbParsedMsgInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "header");
+ if (dbCommand==NULL || dbHeader==NULL) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Either command group or headser group missing in parsed msg info, SNH");
+ return NULL;
+ }
+
+ sCmd=GWEN_DB_GetCharValue(dbCommand, "command", 0, NULL);
+ if (!(sCmd && *sCmd)) {
+ DBG_ERROR(NULL, "No command in message");
+ return NULL;
+ }
+
+ sUrl=GWEN_DB_GetCharValue(dbCommand, "url", 0, NULL);
+ if (!(sUrl && *sUrl)) {
+ DBG_ERROR(NULL, "No url in message");
+ return NULL;
+ }
+
+ gUrl=GWEN_Url_fromCommandString(sUrl);
+ if (gUrl==NULL) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Invalid url [%s]", sUrl);
+ return NULL;
+ }
+ sPath=GWEN_Url_GetPath(gUrl);
+ if (!(sPath && *sPath)) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Invalid URL (no path): [%s]", sUrl);
+ GWEN_Url_free(gUrl);
+ return NULL;
+ }
+ /* now we have all info from the incoming http message */
+
+ msgToSend=_handleUrl(aqh, msgReceived, gUrl);
+ if (msgToSend==NULL) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Error handling url [%s]", sUrl);
+ }
+ GWEN_Url_free(gUrl);
+ return msgToSend;
+}
+
+
+
+GWEN_MSG *_handleUrl(AQHOME_STORAGE *aqh, const GWEN_MSG *msgReceived, const GWEN_URL *url)
+{
+ const char *sPath;
+
+ sPath=GWEN_Url_GetPath(url);
+ if (strcasecmp(sPath, "/login")==0)
+ return _handleUrl_login(aqh, msgReceived, url);
+ else {
+ DBG_ERROR(NULL, "Invalid URL [%s]", sPath);
+ return NULL;
+ }
+}
+
+
+
+GWEN_MSG *_handleUrl_login(AQHOME_STORAGE *aqh, const GWEN_MSG *msgReceived, const GWEN_URL *url)
+{
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/aqhome-storage/http.h b/apps/aqhome-storage/http.h
new file mode 100644
index 0000000..757ff24
--- /dev/null
+++ b/apps/aqhome-storage/http.h
@@ -0,0 +1,30 @@
+/****************************************************************************
+ * 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"
+
+
+
+int AqHomeStorage_AddFile(AQHOME_STORAGE *aqh, AQH_SESSION *session, const char *fname, GWEN_BUFFER *buf);
+int AqHomeStorage_AddSiteHeader(AQHOME_STORAGE *aqh, AQH_SESSION *session, GWEN_BUFFER *buf);
+int AqHomeStorage_AddSiteFooter(AQHOME_STORAGE *aqh, AQH_SESSION *session, GWEN_BUFFER *buf);
+
+void AqHomeStorage_AddStatusLine(AQHOME_STORAGE *aqh, int code, const char *msg, const char *proto, GWEN_BUFFER *buf);
+void AqHomeStorage_AddHeader(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbHeader, GWEN_BUFFER *buf);
+
+int AqHomeStorage_ParsePostBody(AQHOME_STORAGE *aqh, const GWEN_MSG *msgReceived, GWEN_DB_NODE *dbBody);
+
+
+
+#endif
+
+
diff --git a/aqhome/0BUILD b/aqhome/0BUILD
index 62adbdf..3803226 100644
--- a/aqhome/0BUILD
+++ b/aqhome/0BUILD
@@ -66,6 +66,7 @@
http
hexfile
data
+ service
@@ -77,6 +78,7 @@
aqhhttp
aqhhexfile
aqhdata
+ aqhservice
diff --git a/aqhome/http/0BUILD b/aqhome/http/0BUILD
index f8acc58..313db50 100644
--- a/aqhome/http/0BUILD
+++ b/aqhome/http/0BUILD
@@ -47,12 +47,18 @@
endpoint_http.h
urlhandler.h
+ content.h
+ content_files.h
+ httpservice.h
endpoint_http_p.h
urlhandler_p.h
+ content_p.h
+ content_files_p.h
+ httpservice_p.h
@@ -61,6 +67,9 @@
endpoint_http.c
urlhandler.c
+ content.c
+ content_files.c
+ httpservice.c
diff --git a/aqhome/http/content.c b/aqhome/http/content.c
new file mode 100644
index 0000000..ca5d7a4
--- /dev/null
+++ b/aqhome/http/content.c
@@ -0,0 +1,84 @@
+/****************************************************************************
+ * 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
+#endif
+
+
+#include "aqhome/http/content_p.h"
+
+#include
+
+
+
+
+GWEN_INHERIT_FUNCTIONS(AQH_HTTP_CONTENT)
+GWEN_TREE2_FUNCTIONS(AQH_HTTP_CONTENT, AQH_HttpContent)
+
+
+
+
+
+AQH_HTTP_CONTENT *AQH_HttpContent_new(void)
+{
+ AQH_HTTP_CONTENT *cp;
+
+ GWEN_NEW_OBJECT(AQH_HTTP_CONTENT, cp);
+ GWEN_INHERIT_INIT(AQH_HTTP_CONTENT, cp);
+ GWEN_TREE2_INIT(AQH_HTTP_CONTENT, cp, AQH_HttpContent);
+
+ return cp;
+}
+
+
+
+void AQH_HttpContent_free(AQH_HTTP_CONTENT *cp)
+{
+ if (cp) {
+ GWEN_TREE2_FINI(AQH_HTTP_CONTENT, cp, AQH_HttpContent);
+ GWEN_INHERIT_FINI(AQH_HTTP_CONTENT, cp);
+ GWEN_FREE_OBJECT(cp);
+ }
+}
+
+
+
+int AQH_HttpContent_AddOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
+{
+ return (cp && cp->addOpeningContentFn)?(cp->addOpeningContentFn(cp, mode, buffer)):0;
+}
+
+
+
+int AQH_HttpContent_AddClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
+{
+ return (cp && cp->addClosingContentFn)?(cp->addClosingContentFn(cp, mode, buffer)):0;
+}
+
+
+
+void AQH_HttpContent_SetAddOpeningContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN f)
+{
+ if (cp)
+ cp->addOpeningContentFn=f;
+}
+
+
+
+void AQH_HttpContent_SetAddClosingContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN f)
+{
+ if (cp)
+ cp->addClosingContentFn=f;
+}
+
+
+
+
+
+
diff --git a/aqhome/http/content.h b/aqhome/http/content.h
new file mode 100644
index 0000000..6edb228
--- /dev/null
+++ b/aqhome/http/content.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * 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_CONTENT_H
+#define AQHOME_CONTENT_H
+
+
+#include
+
+#include
+#include
+#include
+
+
+#define AQH_HTTP_CONTENT_MODE_DESKTOP 0
+#define AQH_HTTP_CONTENT_MODE_MOBILE 1
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+typedef struct AQH_HTTP_CONTENT AQH_HTTP_CONTENT;
+GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_HTTP_CONTENT, AQHOME_API)
+GWEN_TREE2_FUNCTION_LIB_DEFS(AQH_HTTP_CONTENT, AQH_HttpContent, AQHOME_API)
+
+
+typedef int (*AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN)(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
+typedef int (*AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN)(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
+
+
+AQHOME_API AQH_HTTP_CONTENT *AQH_HttpContent_new(void);
+AQHOME_API void AQH_HttpContent_free(AQH_HTTP_CONTENT *cp);
+
+AQHOME_API int AQH_HttpContent_AddOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
+AQHOME_API int AQH_HttpContent_AddClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
+
+
+AQHOME_API void AQH_HttpContent_SetAddOpeningContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN f);
+AQHOME_API void AQH_HttpContent_SetAddClosingContentFn(AQH_HTTP_CONTENT *cp, AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN f);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif
diff --git a/aqhome/http/content_files.c b/aqhome/http/content_files.c
new file mode 100644
index 0000000..dd711ef
--- /dev/null
+++ b/aqhome/http/content_files.c
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * 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
+#endif
+
+#include "aqhome/http/content_files_p.h"
+
+#include
+#include
+
+
+
+GWEN_INHERIT(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES)
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+static void _freeData(void *bp, void *p);
+static int _addOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
+static int _addClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * implementations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+AQH_HTTP_CONTENT *AQH_HttpContentFiles_new(const char *headerFilename, const char *footerFilename)
+{
+ AQH_HTTP_CONTENT *cp;
+ AQH_HTTP_CONTENT_FILES *xcp;
+
+ cp=AQH_HttpContent_new();
+ GWEN_NEW_OBJECT(AQH_HTTP_CONTENT_FILES, xcp);
+ GWEN_INHERIT_SETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp, xcp, _freeData);
+
+ xcp->headerFilename=(headerFilename && *headerFilename)?strdup(headerFilename):NULL;
+ xcp->footerFilename=(footerFilename && *footerFilename)?strdup(footerFilename):NULL;
+
+ AQH_HttpContent_SetAddOpeningContentFn(cp, _addOpeningContent);
+ AQH_HttpContent_SetAddClosingContentFn(cp, _addClosingContent);
+
+ return cp;
+}
+
+
+
+void _freeData(void *bp, void *p)
+{
+ AQH_HTTP_CONTENT_FILES *xcp;
+
+ xcp=(AQH_HTTP_CONTENT_FILES*) p;
+
+ free(xcp->footerData);
+ free(xcp->headerData);
+
+ free(xcp->footerFilename);
+ free(xcp->headerFilename);
+ GWEN_FREE_OBJECT(xcp);
+}
+
+
+
+int _addOpeningContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
+{
+ if (cp) {
+ AQH_HTTP_CONTENT_FILES *xcp;
+
+ xcp=GWEN_INHERIT_GETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp);
+ if (xcp) {
+ if (xcp->headerData==NULL) {
+ if (xcp->headerFilename) {
+ int rv;
+ GWEN_BUFFER *fileBuffer;
+
+ fileBuffer=GWEN_Buffer_new(0, 256, 0, 1);
+ rv=GWEN_SyncIo_Helper_ReadFile(xcp->headerFilename, fileBuffer);
+ if (rv<0) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Error reading header file \"%s\": %d", xcp->headerFilename, rv);
+ GWEN_Buffer_free(fileBuffer);
+ return rv;
+ }
+ xcp->headerData=strdup(GWEN_Buffer_GetStart(fileBuffer));
+ GWEN_Buffer_free(fileBuffer);
+ }
+ }
+ if (xcp->headerData)
+ GWEN_Buffer_AppendString(buffer, xcp->headerData);
+ }
+ }
+
+ return 0;
+}
+
+
+
+int _addClosingContent(AQH_HTTP_CONTENT *cp, int mode, GWEN_BUFFER *buffer)
+{
+ if (cp) {
+ AQH_HTTP_CONTENT_FILES *xcp;
+
+ xcp=GWEN_INHERIT_GETDATA(AQH_HTTP_CONTENT, AQH_HTTP_CONTENT_FILES, cp);
+ if (xcp) {
+ if (xcp->footerData==NULL) {
+ if (xcp->footerFilename) {
+ int rv;
+ GWEN_BUFFER *fileBuffer;
+
+ fileBuffer=GWEN_Buffer_new(0, 256, 0, 1);
+ rv=GWEN_SyncIo_Helper_ReadFile(xcp->footerFilename, fileBuffer);
+ if (rv<0) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Error reading footer file \"%s\": %d", xcp->footerFilename, rv);
+ GWEN_Buffer_free(fileBuffer);
+ return rv;
+ }
+ xcp->footerData=strdup(GWEN_Buffer_GetStart(fileBuffer));
+ GWEN_Buffer_free(fileBuffer);
+ }
+ if (xcp->footerData)
+ GWEN_Buffer_AppendString(buffer, xcp->footerData);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/aqhome/http/content_files.h b/aqhome/http/content_files.h
new file mode 100644
index 0000000..402febc
--- /dev/null
+++ b/aqhome/http/content_files.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+ * 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_CONTENT_FILES_H
+#define AQHOME_CONTENT_FILES_H
+
+
+#include
+#include
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+AQHOME_API AQH_HTTP_CONTENT *AQH_HttpContentFiles_new(const char *headerFilename, const char *footerFilename);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif
diff --git a/aqhome/http/content_files_p.h b/aqhome/http/content_files_p.h
new file mode 100644
index 0000000..ccd5cb6
--- /dev/null
+++ b/aqhome/http/content_files_p.h
@@ -0,0 +1,28 @@
+/****************************************************************************
+ * 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_CONTENT_FILES_P_H
+#define AQHOME_CONTENT_FILES_P_H
+
+
+#include "aqhome/http/content_files.h"
+
+
+
+typedef struct AQH_HTTP_CONTENT_FILES AQH_HTTP_CONTENT_FILES;
+struct AQH_HTTP_CONTENT_FILES {
+ char *headerFilename;
+ char *footerFilename;
+
+ char *headerData;
+ char *footerData;
+};
+
+
+
+#endif
diff --git a/aqhome/http/content_p.h b/aqhome/http/content_p.h
new file mode 100644
index 0000000..2023098
--- /dev/null
+++ b/aqhome/http/content_p.h
@@ -0,0 +1,27 @@
+/****************************************************************************
+ * 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_CONTENT_P_H
+#define AQHOME_CONTENT_P_H
+
+
+#include "aqhome/http/content.h"
+
+
+struct AQH_HTTP_CONTENT {
+ GWEN_INHERIT_ELEMENT(AQH_HTTP_CONTENT);
+ GWEN_TREE2_ELEMENT(AQH_HTTP_CONTENT);
+
+ AQH_HTTP_CONTENT_ADD_OPENING_CONTENT_FN addOpeningContentFn;
+ AQH_HTTP_CONTENT_ADD_CLOSING_CONTENT_FN addClosingContentFn;
+};
+
+
+
+
+#endif
diff --git a/aqhome/http/endpoint_http.c b/aqhome/http/endpoint_http.c
index 48e89e2..5d86302 100644
--- a/aqhome/http/endpoint_http.c
+++ b/aqhome/http/endpoint_http.c
@@ -395,7 +395,8 @@ int _distributeBufferInHeaderMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPt
}
else {
xep->currentBodyPos=GWEN_Buffer_GetPos(xep->currentReadBuffer);
- xep->currentBodySize=contentLength;
+ xep->currentBodySize=contentLength;
+ xep->remainingBodySize=contentLength;
xep->readMode=AQH_EndpointHttpd_ReadMode_Body;
}
}
@@ -411,16 +412,16 @@ int _distributeBufferInBodyMode(GWEN_MSG_ENDPOINT *ep, const uint8_t *bufferPtr,
AQH_ENDPOINT_HTTP *xep;
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
- if (xep->currentBodySize>0) {
+ if (xep->remainingBodySize>0) {
int len;
len=bufferLen;
- if (len>xep->currentBodySize)
- len=xep->currentBodySize;
+ if (len>xep->remainingBodySize)
+ len=xep->remainingBodySize;
if (len) {
GWEN_Buffer_AppendBytes(xep->currentReadBuffer, (const char*) bufferPtr, len);
- xep->currentBodySize-=len;
- if (xep->currentBodySize==0) {
+ xep->remainingBodySize-=len;
+ if (xep->remainingBodySize==0) {
DBG_INFO(AQH_LOGDOMAIN, "Body completely received");
_finishMessageAndStartNext(ep);
}
@@ -475,6 +476,10 @@ void _finishMessageAndStartNext(GWEN_MSG_ENDPOINT *ep)
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(xep->currentReadBuffer), GWEN_Buffer_GetUsedBytes(xep->currentReadBuffer));
+ if (xep->currentBodySize) {
+ GWEN_Msg_SetParsedPayloadOffset(msg, xep->currentBodyPos);
+ GWEN_Msg_SetParsedPayloadSize(msg, xep->currentBodySize);
+ }
dbParsedData=GWEN_DB_Group_new("parsedData");
if (xep->dbCurrentReadCommand)
GWEN_DB_AddGroup(dbParsedData, xep->dbCurrentReadCommand);
@@ -488,6 +493,7 @@ void _finishMessageAndStartNext(GWEN_MSG_ENDPOINT *ep)
xep->currentHeaderPos=0;
xep->currentBodyPos=0;
xep->currentBodySize=0;
+ xep->remainingBodySize=0;
xep->lastLineStartPos=0;
xep->dbCurrentReadCommand=NULL;
xep->dbCurrentReadHeader=NULL;
@@ -511,6 +517,7 @@ void _abortMessage(GWEN_MSG_ENDPOINT *ep)
xep->currentHeaderPos=0;
xep->currentBodyPos=0;
xep->currentBodySize=0;
+ xep->remainingBodySize=0;
xep->lastLineStartPos=0;
if (xep->dbCurrentReadCommand)
GWEN_DB_Group_free(xep->dbCurrentReadCommand);
diff --git a/aqhome/http/endpoint_http_p.h b/aqhome/http/endpoint_http_p.h
index 1091704..048c76f 100644
--- a/aqhome/http/endpoint_http_p.h
+++ b/aqhome/http/endpoint_http_p.h
@@ -43,6 +43,7 @@ struct AQH_ENDPOINT_HTTP {
int currentHeaderPos;
int currentBodyPos;
int currentBodySize;
+ int remainingBodySize;
int lastLineStartPos;
};
diff --git a/aqhome/http/httpservice.c b/aqhome/http/httpservice.c
new file mode 100644
index 0000000..15a9e6a
--- /dev/null
+++ b/aqhome/http/httpservice.c
@@ -0,0 +1,328 @@
+/****************************************************************************
+ * 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
+#endif
+
+
+#include "aqhome/http/httpservice_p.h"
+
+#include
+#include
+#include
+#include
+
+
+
+GWEN_INHERIT(AQH_SERVICE, AQH_HTTP_SERVICE)
+
+
+static void GWENHYWFAR_CB _freeData(void *bp, void *p);
+
+static int _checkHeaderGetBodySize(const GWEN_MSG *msgReceived);
+
+
+
+
+
+void AQH_HttpService_Extend(AQH_SERVICE *sv)
+{
+ AQH_HTTP_SERVICE *xsv;
+
+ GWEN_NEW_OBJECT(AQH_HTTP_SERVICE, xsv);
+ GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv, xsv, _freeData);
+}
+
+
+
+void _freeData(void *bp, void *p)
+{
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=(AQH_HTTP_SERVICE*) p;
+ free(xsv->sourceFolder);
+ free(xsv->siteHeader);
+ free(xsv->siteFooter);
+ GWEN_FREE_OBJECT(xsv);
+}
+
+
+
+const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
+ if (xsv)
+ return xsv->sourceFolder;
+ }
+ return NULL;
+}
+
+
+
+void AQH_HttpService_SetSourceFolder(AQH_SERVICE *sv, const char *s)
+{
+ if (sv) {
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
+ if (xsv) {
+ free(xsv->sourceFolder);
+ xsv->sourceFolder=s?strdup(s):NULL;
+ }
+ }
+}
+
+
+
+const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
+ if (xsv)
+ return xsv->siteHeader;
+ }
+ return NULL;
+}
+
+
+
+void AQH_HttpService_SetSiteHeader(AQH_SERVICE *sv, const char *s)
+{
+ if (sv) {
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
+ if (xsv) {
+ free(xsv->siteHeader);
+ xsv->siteHeader=s?strdup(s):NULL;
+ }
+ }
+}
+
+
+
+const char *AQH_HttpService_GetSiteFooter(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
+ if (xsv)
+ return xsv->siteFooter;
+ }
+ return NULL;
+}
+
+
+
+void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s)
+{
+ if (sv) {
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
+ if (xsv) {
+ free(xsv->siteFooter);
+ xsv->siteFooter=s?strdup(s):NULL;
+ }
+ }
+}
+
+
+
+int AQH_HttpService_AddFile(AQH_SERVICE *sv, const char *fname, GWEN_BUFFER *buf)
+{
+ if (fname && *fname) {
+ AQH_HTTP_SERVICE *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_HTTP_SERVICE, sv);
+ if (xsv) {
+ int rv;
+ GWEN_BUFFER *fnbuf;
+
+ fnbuf=GWEN_Buffer_new(0, 256, 0, 1);
+ if (xsv->sourceFolder) {
+ GWEN_Buffer_AppendString(fnbuf, xsv->sourceFolder);
+ GWEN_Buffer_AppendString(fnbuf, GWEN_DIR_SEPARATOR_S);
+ }
+ GWEN_Buffer_AppendString(fnbuf, fname);
+
+ rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fnbuf), buf);
+ if (rv<0) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"%s\": %d", GWEN_Buffer_GetStart(fnbuf), rv);
+ GWEN_Buffer_free(fnbuf);
+ return rv;
+ }
+ GWEN_Buffer_free(fnbuf);
+ }
+ else {
+ DBG_ERROR(AQH_LOGDOMAIN, "No http service object");
+ }
+ }
+ return 0;
+}
+
+
+
+void AQH_HttpService_AddStatusLine(AQH_SERVICE *sv, int code, const char *msg, const char *proto, GWEN_BUFFER *buf)
+{
+ GWEN_Buffer_AppendArgs(buf, "%s %03d %s \r\n", proto?proto:"HTTP/1.1", code, msg?msg:"");
+}
+
+
+
+void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeader, GWEN_BUFFER *buf)
+{
+ GWEN_DB_NODE *dbVar;
+
+ dbVar=GWEN_DB_GetFirstVar(dbHeader);
+ while (dbVar) {
+ GWEN_DB_NODE *dbVal;
+
+ /* only handle first value */
+ dbVal=GWEN_DB_GetFirstValue(dbVar);
+ if (dbVal) {
+ const char *sVar;
+
+ sVar=GWEN_DB_VariableName(dbVar);
+ if (sVar && *sVar) {
+ GWEN_DB_NODE_TYPE vtype;
+
+ vtype=GWEN_DB_GetValueType(dbVal);
+ if (vtype==GWEN_DB_NodeType_ValueChar) {
+ const char *sValue;
+
+ sValue=GWEN_DB_GetCharValueFromNode(dbVal);
+ if (sValue)
+ GWEN_Buffer_AppendArgs(buf, "%s:%s\r\n", sVar, sValue);
+ } /* if char */
+ else if (vtype==GWEN_DB_NodeType_ValueInt) {
+ int i;
+
+ i=GWEN_DB_GetIntValueFromNode(dbVal);
+ if (i!=-1 || strcasecmp(sVar, "Content-Length")==0)
+ GWEN_Buffer_AppendArgs(buf, "%s:%d\r\n", sVar, i);
+ } /* if int */
+ else {
+ DBG_INFO(AQH_LOGDOMAIN, "Variable type %d of var [%s] not supported, ignoring", vtype, sVar);
+ }
+ } /* if sVar */
+ }
+ dbVar=GWEN_DB_GetNextVar(dbVar);
+ }
+
+ /* finalize header */
+ GWEN_Buffer_AppendString(buf, "\r\n");
+}
+
+
+
+int AQH_HttpService_ParsePostBody(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, GWEN_DB_NODE *dbBody)
+{
+ int contentLength;
+ const char *s;
+
+ contentLength=_checkHeaderGetBodySize(msgReceived);
+ if (contentLength<1) {
+ DBG_ERROR(NULL, "Empty message body");
+ return 0;
+ }
+ s=(const char*)(GWEN_Msg_GetConstBuffer(msgReceived)+GWEN_Msg_GetParsedPayloadOffset(msgReceived));
+ while(contentLength>0) {
+ const char *sNameStart;
+ int nameLen;
+
+ while((contentLength>0) && (*s<33)) {
+ contentLength--;
+ s++;
+ }
+ sNameStart=s;
+ while((contentLength>0) && (*s!='=') && (*s!='&')) {
+ contentLength--;
+ s++;
+ }
+ nameLen=s-sNameStart;
+ if ((contentLength>0) && (*s=='=')) {
+ const char *sValueStart;
+ int valueLen;
+
+ s++;
+ while((contentLength>0) && (*s<33)) {
+ s++;
+ contentLength--;
+ }
+ sValueStart=s;
+ while((contentLength>0) && (*s!='&')) {
+ contentLength--;
+ s++;
+ }
+ valueLen=s-sValueStart;
+ if (nameLen && valueLen) {
+ char sNameBuf[32];
+ char sValueBuf[64];
+
+ if (GWEN_Text_UnescapeN(sNameStart, nameLen, sNameBuf, sizeof(sNameBuf))!=NULL &&
+ GWEN_Text_UnescapeN(sValueStart, valueLen, sValueBuf, sizeof(sValueBuf))!=NULL)
+ GWEN_DB_SetCharValue(dbBody, 0, sNameBuf, sValueBuf);
+ else {
+ DBG_ERROR(NULL, "Either name or value invalid in body, aborting");
+ return GWEN_ERROR_BAD_DATA;
+ }
+ }
+ if ((contentLength>0) && (*s=='&'))
+ s++;
+ }
+ } /* while */
+ return 0;
+}
+
+
+
+int _checkHeaderGetBodySize(const GWEN_MSG *msgReceived)
+{
+ GWEN_DB_NODE *dbParsedInfo;
+ GWEN_DB_NODE *dbHeader;
+ const char *contentType;
+ int contentLength;
+
+ dbParsedInfo=GWEN_Msg_GetDbParsedInfo(msgReceived);
+ if (dbParsedInfo==NULL) {
+ DBG_ERROR(AQH_LOGDOMAIN, "No parsed info in received message");
+ return GWEN_ERROR_BAD_DATA;
+ }
+ dbHeader=GWEN_DB_GetGroup(dbParsedInfo, GWEN_PATH_FLAGS_PATHMUSTEXIST, "header");
+ if (dbHeader==NULL) {
+ DBG_ERROR(AQH_LOGDOMAIN, "No http header group in received message");
+ return GWEN_ERROR_BAD_DATA;
+ }
+
+ contentType=GWEN_DB_GetCharValue(dbHeader, "content-type", 0, NULL);
+ if (!(contentType && *contentType && strcasecmp(contentType, "application/x-www-form-urlencoded")==0)) {
+ DBG_ERROR(NULL, "Invalid or missing content type [%s]", contentType?contentType:"");
+ return GWEN_ERROR_BAD_DATA;
+ }
+
+ contentLength=GWEN_Msg_GetParsedPayloadSize(msgReceived);
+ if (contentLength<1) {
+ DBG_ERROR(NULL, "Empty message body");
+ return 0;
+ }
+
+ return contentLength;
+}
+
+
+
+
+
diff --git a/aqhome/http/httpservice.h b/aqhome/http/httpservice.h
new file mode 100644
index 0000000..54730ba
--- /dev/null
+++ b/aqhome/http/httpservice.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+ * 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 AQH_HTTP_SERVICE_H
+#define AQH_HTTP_SERVICE_H
+
+
+
+#include "aqhome/service/service.h"
+
+#include
+#include
+#include
+
+
+
+void AQH_HttpService_Extend(AQH_SERVICE *sv);
+
+
+const char *AQH_HttpService_GetSourceFolder(const AQH_SERVICE *sv);
+void AQH_HttpService_SetSourceFolder(AQH_SERVICE *sv, const char *s);
+
+const char *AQH_HttpService_GetSiteHeader(const AQH_SERVICE *sv);
+void AQH_HttpService_SetSiteHeader(AQH_SERVICE *sv, const char *s);
+
+
+const char *AQH_HttpService_GetSiteFooter(const AQH_SERVICE *sv);
+void AQH_HttpService_SetSiteFooter(AQH_SERVICE *sv, const char *s);
+
+
+int AQH_HttpService_AddFile(AQH_SERVICE *sv, const char *fname, GWEN_BUFFER *buf);
+void AQH_HttpService_AddStatusLine(AQH_SERVICE *sv, int code, const char *msg, const char *proto, GWEN_BUFFER *buf);
+void AQH_HttpService_AddHeader(AQH_SERVICE *sv, GWEN_DB_NODE *dbHeader, GWEN_BUFFER *buf);
+
+int AQH_HttpService_ParsePostBody(AQH_SERVICE *sv, const GWEN_MSG *msgReceived, GWEN_DB_NODE *dbBody);
+
+
+
+
+#endif
+
+
+
diff --git a/aqhome/http/httpservice_p.h b/aqhome/http/httpservice_p.h
new file mode 100644
index 0000000..5b73a21
--- /dev/null
+++ b/aqhome/http/httpservice_p.h
@@ -0,0 +1,31 @@
+/****************************************************************************
+ * 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 AQH_HTTP_SERVICE_P_H
+#define AQH_HTTP_SERVICE_P_H
+
+
+#include "aqhome/http/httpservice.h"
+
+
+
+typedef struct AQH_HTTP_SERVICE AQH_HTTP_SERVICE;
+struct AQH_HTTP_SERVICE {
+ char *sourceFolder;
+
+ char *siteHeader;
+ char *siteFooter;
+
+};
+
+
+
+#endif
+
+
+
diff --git a/aqhome/http/urlhandler.c b/aqhome/http/urlhandler.c
index 0e226d1..52a0871 100644
--- a/aqhome/http/urlhandler.c
+++ b/aqhome/http/urlhandler.c
@@ -51,6 +51,21 @@ void AQH_UrlHandler_free(AQH_URLHANDLER *uh)
+AQH_HTTP_CONTENT *AQH_UrlHandler_GetContentProvider(const AQH_URLHANDLER *uh)
+{
+ return uh?uh->httpContentProvider:NULL;
+}
+
+
+
+void AQH_UrlHandler_SetContentProvider(AQH_URLHANDLER *uh, AQH_HTTP_CONTENT *cp)
+{
+ if (uh)
+ uh->httpContentProvider=cp;
+}
+
+
+
void AQH_UrlHandler_AddUrlPattern(AQH_URLHANDLER *uh, const char *s)
{
if (uh && s && *s)
diff --git a/aqhome/http/urlhandler.h b/aqhome/http/urlhandler.h
index 4386ca4..06658c6 100644
--- a/aqhome/http/urlhandler.h
+++ b/aqhome/http/urlhandler.h
@@ -11,6 +11,8 @@
#include
+#include "aqhome/http/content.h"
+
#include
#include
#include
@@ -30,6 +32,9 @@ typedef GWEN_MSG*(*AQH_URLHANDLER_HANDLE_FN)(AQH_URLHANDLER *uh, GWEN_MSG_ENDPOI
AQHOME_API AQH_URLHANDLER *AQH_UrlHandler_new(void);
AQHOME_API void AQH_UrlHandler_free(AQH_URLHANDLER *uh);
+AQHOME_API AQH_HTTP_CONTENT *AQH_UrlHandler_GetContentProvider(const AQH_URLHANDLER *uh);
+AQHOME_API void AQH_UrlHandler_SetContentProvider(AQH_URLHANDLER *uh, AQH_HTTP_CONTENT *cp);
+
AQHOME_API void AQH_UrlHandler_AddUrlPattern(AQH_URLHANDLER *uh, const char *s);
AQHOME_API int AQH_UrlHandler_UrlMatches(const AQH_URLHANDLER *uh, const char *s);
diff --git a/aqhome/http/urlhandler_p.h b/aqhome/http/urlhandler_p.h
index 6177e7d..8cd05a6 100644
--- a/aqhome/http/urlhandler_p.h
+++ b/aqhome/http/urlhandler_p.h
@@ -19,6 +19,8 @@ struct AQH_URLHANDLER {
GWEN_STRINGLIST *urlPatternList;
AQH_URLHANDLER_HANDLE_FN handleFn;
+
+ AQH_HTTP_CONTENT *httpContentProvider;
};
diff --git a/aqhome/service/0BUILD b/aqhome/service/0BUILD
new file mode 100644
index 0000000..1214ebe
--- /dev/null
+++ b/aqhome/service/0BUILD
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+ $(gwenhywfar_cflags)
+ -I$(topsrcdir)
+ -I$(topbuilddir)
+
+
+
+ --include=$(builddir)
+ --include=$(srcdir)
+
+
+
+
+
+ $(visibility_cflags)
+
+
+
+ --api=AQHOME_API
+
+
+
+ module.t2d
+ moduleperms.t2d
+ role.t2d
+ user.t2d
+ session.t2d
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(local/built_headers_pub)
+
+
+
+
+ service.h
+
+
+
+
+ service_p.h
+
+
+
+
+ $(local/typefiles)
+
+ service.c
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aqhome/service/module.t2d b/aqhome/service/module.t2d
new file mode 100644
index 0000000..ff50d36
--- /dev/null
+++ b/aqhome/service/module.t2d
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+ AQH_MODULE
+ AQH_Module
+ module
+
+
+ with_inherit
+ with_xml
+ with_db
+ with_list1
+ with_list2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ public
+ with_getbymember
+
+
+
+ 0
+ 0
+ public
+ with_getbymember
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ NULL
+ NULL
+ public
+ own
+
+
+
+
+
+
+
+
diff --git a/aqhome/service/moduleperms.t2d b/aqhome/service/moduleperms.t2d
new file mode 100644
index 0000000..015d862
--- /dev/null
+++ b/aqhome/service/moduleperms.t2d
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+ AQH_MODULE_PERMS
+ AQH_ModulePerms
+ moduleperms
+
+
+ with_inherit
+ with_xml
+ with_db
+ with_list1
+ with_list2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ public
+ with_getbymember
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+
+
+
+
+
diff --git a/aqhome/service/role.t2d b/aqhome/service/role.t2d
new file mode 100644
index 0000000..311916b
--- /dev/null
+++ b/aqhome/service/role.t2d
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+ AQH_ROLE
+ AQH_Role
+ role
+
+
+ with_xml
+ with_db
+ with_list1
+ with_list2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ public
+ with_getbymember
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+
+
+
+
+
diff --git a/aqhome/service/service.c b/aqhome/service/service.c
new file mode 100644
index 0000000..0381ce0
--- /dev/null
+++ b/aqhome/service/service.c
@@ -0,0 +1,186 @@
+/****************************************************************************
+ * 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
+#endif
+
+
+#include "aqhome/service/service_p.h"
+
+#include
+
+
+
+GWEN_INHERIT_FUNCTIONS(AQH_SERVICE);
+GWEN_LIST_FUNCTIONS(AQH_SERVICE, AQH_Service);
+
+
+
+
+AQH_SERVICE *AQH_Service_new(void)
+{
+ AQH_SERVICE *sv;
+
+ GWEN_NEW_OBJECT(AQH_SERVICE, sv);
+ GWEN_INHERIT_INIT(AQH_SERVICE, sv);
+ GWEN_LIST_INIT(AQH_SERVICE, sv);
+
+ sv->userList=AQH_User_List_new();
+ sv->moduleList=AQH_Module_List_new();
+ sv->sessionList=AQH_Session_List_new();
+
+ return sv;
+}
+
+
+
+void AQH_Service_free(AQH_SERVICE *sv)
+{
+ if (sv) {
+ GWEN_LIST_FINI(AQH_SERVICE, sv);
+ AQH_User_List_free(sv->userList);
+ AQH_Module_List_free(sv->moduleList);
+ AQH_Session_List_free(sv->sessionList);
+ GWEN_INHERIT_FINI(AQH_SERVICE, sv);
+ GWEN_FREE_OBJECT(sv);
+ }
+}
+
+
+
+AQH_USER_LIST *AQH_Service_GetUserList(const AQH_SERVICE *sv)
+{
+ return sv?sv->userList:NULL;
+}
+
+
+
+AQH_USER *AQH_Service_GetUserById(const AQH_SERVICE *sv, uint32_t id)
+{
+ return sv?AQH_User_List_GetById(sv->userList, id):NULL;
+}
+
+
+
+AQH_USER *AQH_Service_GetUserByAlias(const AQH_SERVICE *sv, const char *s)
+{
+ return sv?AQH_User_List_GetByAlias(sv->userList, s):NULL;
+}
+
+
+
+void AQH_Service_AddUser(AQH_SERVICE *sv, AQH_USER *u)
+{
+ if (sv && u)
+ AQH_User_List_Add(u, sv->userList);
+}
+
+
+
+void AQH_Service_DelUser(AQH_SERVICE *sv, uint32_t userId)
+{
+ if (sv && userId) {
+ AQH_USER *u;
+
+ u=AQH_User_List_GetById(sv->userList, userId);
+ if (u) {
+ AQH_User_List_Del(u);
+ AQH_User_free(u);
+ }
+ }
+}
+
+
+
+AQH_MODULE_LIST *AQH_Service_GetModuleList(const AQH_SERVICE *sv)
+{
+ return sv?sv->moduleList:NULL;
+}
+
+
+
+AQH_MODULE *AQH_Service_GetModuleById(const AQH_SERVICE *sv, uint32_t id)
+{
+ return sv?AQH_Module_List_GetById(sv->moduleList, id):NULL;
+}
+
+
+
+AQH_MODULE *AQH_Service_GetModuleByName(const AQH_SERVICE *sv, const char *s)
+{
+ return sv?AQH_Module_List_GetByName(sv->moduleList, s):NULL;
+}
+
+
+
+void AQH_Service_AddModule(AQH_SERVICE *sv, AQH_MODULE *m)
+{
+ if (sv && m)
+ AQH_Module_List_Add(m, sv->moduleList);
+}
+
+
+
+void AQH_Service_DelModule(AQH_SERVICE *sv, uint32_t moduleId)
+{
+ if (sv && moduleId) {
+ AQH_MODULE *m;
+
+ m=AQH_Module_List_GetById(sv->moduleList, moduleId);
+ if (m) {
+ AQH_Module_List_Del(m);
+ AQH_Module_free(m);
+ }
+ }
+}
+
+
+
+AQH_SESSION_LIST *AQH_Service_GetSessionList(const AQH_SERVICE *sv)
+{
+ return sv?sv->sessionList:NULL;
+}
+
+
+
+AQH_SESSION *AQH_Service_GetSessionById(const AQH_SERVICE *sv, uint32_t sessionId)
+{
+ return sv?AQH_Session_List_GetById(sv->sessionList, sessionId):NULL;
+}
+
+
+
+void AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session)
+{
+ if (sv && session)
+ AQH_Session_List_Add(session, sv->sessionList);
+}
+
+
+
+void AQH_Service_DelSession(AQH_SERVICE *sv, uint32_t id)
+{
+ if (sv && id) {
+ AQH_SESSION *session;
+
+ session=AQH_Session_List_GetById(sv->sessionList, id);
+ if (session) {
+ AQH_Session_List_Del(session);
+ AQH_Session_free(session);
+ }
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/aqhome/service/service.h b/aqhome/service/service.h
new file mode 100644
index 0000000..1358825
--- /dev/null
+++ b/aqhome/service/service.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+ * 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_SERVICE_H
+#define AQHOME_SERVICE_H
+
+
+#include
+
+#include
+#include
+
+
+typedef struct AQH_SERVICE AQH_SERVICE;
+GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_SERVICE, AQHOME_API);
+GWEN_LIST_FUNCTION_LIB_DEFS(AQH_SERVICE, AQH_Service, AQHOME_API);
+
+
+#include "aqhome/service/user.h"
+#include "aqhome/service/module.h"
+#include "aqhome/service/session.h"
+
+
+
+AQHOME_API AQH_SERVICE *AQH_Service_new(void);
+AQHOME_API void AQH_Service_free(AQH_SERVICE *sv);
+
+AQHOME_API AQH_USER_LIST *AQH_Service_GetUserList(const AQH_SERVICE *sv);
+AQHOME_API AQH_USER *AQH_Service_GetUserById(const AQH_SERVICE *sv, uint32_t id);
+AQHOME_API AQH_USER *AQH_Service_GetUserByAlias(const AQH_SERVICE *sv, const char *s);
+AQHOME_API void AQH_Service_AddUser(AQH_SERVICE *sv, AQH_USER *u);
+AQHOME_API void AQH_Service_DelUser(AQH_SERVICE *sv, uint32_t userId);
+
+
+AQHOME_API AQH_MODULE_LIST *AQH_Service_GetModuleList(const AQH_SERVICE *sv);
+AQHOME_API AQH_MODULE *AQH_Service_GetModuleById(const AQH_SERVICE *sv, uint32_t id);
+AQHOME_API AQH_MODULE *AQH_Service_GetModuleByName(const AQH_SERVICE *sv, const char *s);
+AQHOME_API void AQH_Service_AddModule(AQH_SERVICE *sv, AQH_MODULE *m);
+AQHOME_API void AQH_Service_DelModule(AQH_SERVICE *sv, uint32_t moduleId);
+
+AQHOME_API AQH_SESSION_LIST *AQH_Service_GetSessionList(const AQH_SERVICE *sv);
+AQHOME_API AQH_SESSION *AQH_Service_GetSessionById(const AQH_SERVICE *sv, uint32_t sessionId);
+AQHOME_API void AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session);
+AQHOME_API void AQH_Service_DelSession(AQH_SERVICE *sv, uint32_t id);
+
+
+
+#endif
diff --git a/aqhome/service/service_p.h b/aqhome/service/service_p.h
new file mode 100644
index 0000000..1e9a1ab
--- /dev/null
+++ b/aqhome/service/service_p.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+ * 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_SERVICE_P_H
+#define AQHOME_SERVICE_P_H
+
+
+#include "aqhome/service/service.h"
+
+
+struct AQH_SERVICE {
+ GWEN_INHERIT_ELEMENT(AQH_SERVICE);
+ GWEN_LIST_ELEMENT(AQH_SERVICE);
+
+ AQH_USER_LIST *userList;
+ AQH_MODULE_LIST *moduleList;
+ AQH_SESSION_LIST *sessionList;
+
+};
+
+
+
+
+#endif
diff --git a/aqhome/service/session.t2d b/aqhome/service/session.t2d
new file mode 100644
index 0000000..d0ccca1
--- /dev/null
+++ b/aqhome/service/session.t2d
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+ AQH_SESSION
+ AQH_Session
+ session
+
+
+ with_xml
+ with_db
+ with_list1
+ with_list2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ public
+ with_getbymember
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+ with_flags
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ NULL
+ NULL
+ public
+ own
+
+
+
+
+
+ NULL
+ NULL
+ public
+ assign
+ assign
+ volatile
+
+
+
+
+
+
+
+
diff --git a/aqhome/service/user.t2d b/aqhome/service/user.t2d
new file mode 100644
index 0000000..c7b9f5d
--- /dev/null
+++ b/aqhome/service/user.t2d
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+ AQH_USER
+ AQH_User
+ user
+
+
+ with_xml
+ with_db
+ with_list1
+ with_list2
+
+
+
+
+
+
+ aqhome/service/moduleperms.h
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ public
+ with_getbymember
+
+
+
+ 0
+ 0
+ public
+ with_flags
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+ with_getbymember
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ 0
+ 0
+ public
+
+
+
+
+ NULL
+ NULL
+ public
+ own
+
+
+
+ NULL
+ NULL
+ public
+ own
+
+
+
+ NULL
+ NULL
+ public
+ none
+ none
+ own
+
+
+
+
+
+
+
+
diff --git a/avr/att841_node.asm b/avr/att841_node.asm
new file mode 100644
index 0000000..97f3799
--- /dev/null
+++ b/avr/att841_node.asm
@@ -0,0 +1,472 @@
+; ***************************************************************************
+; copyright : (C) 2023 by Martin Preuss
+; email : martin@libchipcard.de
+;
+; ***************************************************************************
+; * This file is part of the project "AqHome". *
+; * Please see toplevel file COPYING of that project for license details. *
+; ***************************************************************************
+
+
+
+
+; ***************************************************************************
+; Source file for temperature sensor node on AtTiny 841
+;
+; This is for the full system (i.e. not the boot loader).
+;
+; All definitions and changes should go into this file.
+;
+;
+;
+; AtTiny 841
+; -------
+; VCC 1 14 GND
+; KEY1 PB0 2 13 PA0 MISO (SPI) REED_OUT
+; COM_ATTN PB1 3 12 PA1 MOSI (SPI) REED_IN1
+; /RESET PB3 4 11 PA2 /SS (SPI) REED_IN2
+; RXD0 (UART0) PB2 5 10 PA3 SCK (SPI)
+; TXD0 (UART0) PA7 6 9 PA4 SCL (I2C)
+; SDA (I2C) PA6 7 8 PA5 LED
+; -------
+;
+
+
+
+;
+;
+; AtTiny84
+; --------
+; VCC 1 14 GND
+; PB0 2 13 PA0 REED_OUT
+; PB1 3 12 PA1 COM-DATA
+; /RESET PB3 4 11 PA2 REED_IN1
+; [KEY1] PB2 5 10 PA3 LED
+; COM_ATTN PA7 6 9 PA4 TWI-SCL
+; TWI-SDA PA6 7 8 PA5 REED_IN2
+; --------
+;
+; ***************************************************************************
+
+
+
+.nolist
+.include "include/tn84def.inc" ; Define device ATtiny84
+.list
+
+.include "defs.asm"
+
+
+
+; ***************************************************************************
+; defines
+
+; ---------------------------------------------------------------------------
+; generic
+
+.equ clock=1000000 ; Define the clock frequency
+
+.include "common/utils_wait.asm"
+
+
+; ---------------------------------------------------------------------------
+; firmware settings including list of modules used
+
+#define FW_TYPE AQHOME_FW_TYPE_ATT84_TEMP1
+#define FW_VERSION 0x0001
+
+
+#define MODULES_TIMER
+#define MODULES_COM
+#define MODULES_COM_WITH_ADDR_PROTO
+#define MODULES_LED
+#define MODULES_TWI_MASTER
+;#define MODULES_LCD
+#define MODULES_SI7021
+#define MODULES_STATS
+;#define MODULES_CNY70
+
+
+.set MODULES_MASK = 0
+#ifdef MODULES_TIMER
+.set MODULES_MASK = MODULES_MASK | (1<