diff --git a/apps/aqhome-storage/0BUILD b/apps/aqhome-storage/0BUILD
index 66a4e77..dd8fe00 100644
--- a/apps/aqhome-storage/0BUILD
+++ b/apps/aqhome-storage/0BUILD
@@ -39,6 +39,8 @@
aqhomestorage.h
init.h
http.h
+ aqhomehttp.h
+ aqhomehttp_p.h
@@ -48,6 +50,7 @@
init.c
http.c
main.c
+ aqhomehttp.c
diff --git a/apps/aqhome-storage/aqhomehttp.c b/apps/aqhome-storage/aqhomehttp.c
new file mode 100644
index 0000000..3253b77
--- /dev/null
+++ b/apps/aqhome-storage/aqhomehttp.c
@@ -0,0 +1,306 @@
+/****************************************************************************
+ * 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 "./aqhomehttp_p.h"
+#include "aqhome/http/httpservice.h"
+#include "aqhome/http/httpservice_http.h"
+
+#include
+#include
+#include
+#include
+
+
+
+GWEN_INHERIT(AQH_SERVICE, AQHOME_HTTP)
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+static void GWENHYWFAR_CB _freeData(void *bp, void *p);
+static int _handleUrl(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq);
+static int _handleUrl_login(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq);
+static GWEN_MSG *_createResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol, const char *page);
+static void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWEN_BUFFER *buf);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * 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);
+
+ AQH_HttpService_SetHandleRequestFn(sv, _handleUrl);
+}
+
+
+
+void _freeData(void *bp, void *p)
+{
+ AQHOME_HTTP *xsv;
+
+ xsv=(AQHOME_HTTP*) p;
+
+ AQH_Storage_free(xsv->storage);
+ xsv->storage=NULL;
+ GWEN_MsgEndpoint_free(xsv->rootEndpoint);
+ xsv->rootEndpoint=NULL;
+ xsv->ipcdEndpoint=NULL;
+ xsv->mqttEndpoint=NULL;
+ xsv->httpdEndpoint=NULL;
+ GWEN_DB_Group_free(xsv->dbArgs);
+ xsv->dbArgs=NULL;
+ free(xsv->pidFile);
+
+ GWEN_FREE_OBJECT(xsv);
+}
+
+
+
+GWEN_DB_NODE *AqHomeHttpService_GetDbArgs(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQHOME_HTTP *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
+ if (xsv)
+ return xsv->dbArgs;
+ }
+ return NULL;
+}
+
+
+
+const char *AqHomeHttpService_GetPidFile(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQHOME_HTTP *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
+ if (xsv)
+ return xsv->pidFile;
+ }
+ return NULL;
+}
+
+
+
+void AqHomeHttpService_SetPidFile(AQH_SERVICE *sv, const char *s)
+{
+ if (sv) {
+ AQHOME_HTTP *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
+ if (xsv) {
+ free(xsv->pidFile);
+ xsv->pidFile=s?strdup(s):NULL;
+ }
+ }
+}
+
+
+
+
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetRootEndpoint(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQHOME_HTTP *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
+ if (xsv)
+ return xsv->rootEndpoint;
+ }
+ return NULL;
+}
+
+
+
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetIpcdEndpoint(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQHOME_HTTP *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
+ if (xsv)
+ return xsv->ipcdEndpoint;
+ }
+ return NULL;
+}
+
+
+
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetMqttEndpoint(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQHOME_HTTP *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
+ if (xsv)
+ return xsv->mqttEndpoint;
+ }
+ return NULL;
+}
+
+
+
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetHttpdEndpoint(const AQH_SERVICE *sv)
+{
+ if (sv) {
+ AQHOME_HTTP *xsv;
+
+ xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
+ if (xsv)
+ return xsv->httpdEndpoint;
+ }
+ return NULL;
+}
+
+
+
+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;
+}
+
+
+
+
+
+
+
+
+int _handleUrl(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
+{
+
+ const GWEN_URL *url;
+ const char *sPath;
+
+ url=AQH_HttpRequest_GetUrl(rq);
+
+ sPath=GWEN_Url_GetPath(url);
+ if (strcasecmp(sPath, "/login")==0)
+ return _handleUrl_login(sv, rq);
+ else {
+ DBG_ERROR(NULL, "Invalid URL [%s]", sPath);
+ return GWEN_ERROR_INVALID;
+ }
+}
+
+
+
+int _handleUrl_login(AQH_SERVICE *sv, AQH_HTTP_REQUEST *rq)
+{
+ const char *protocol;
+ const char *cmd;
+ AQH_SESSION *session;
+ GWEN_MSG *msgOut=NULL;
+
+ protocol=AQH_HttpRequest_GetProtocol(rq);
+ session=AQH_HttpRequest_GetSession(rq);
+ cmd=AQH_HttpRequest_GetCommand(rq);
+ if (cmd && strcasecmp(cmd, "GET")==0) {
+ GWEN_BUFFER *pageBuf;
+ const char *s;
+ int rv;
+
+ pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
+ s=AQH_HttpService_GetSiteHeader(sv);
+ if (s)
+ GWEN_Buffer_AppendString(pageBuf, s);
+
+ rv=AQH_HttpService_AddFile(sv, session, "login.html", pageBuf);
+ if (rv<0) {
+ DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"login.html\"");
+ GWEN_Buffer_free(pageBuf);
+ msgOut=_createResponseMsg(sv, 500, "Internal Error", protocol, NULL);
+ AQH_HttpRequest_SetResponseMsg(rq, msgOut);
+ return 0;
+ }
+
+ s=AQH_HttpService_GetSiteFooter(sv);
+ if (s)
+ GWEN_Buffer_AppendString(pageBuf, s);
+
+ msgOut=_createResponseMsg(sv, 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
+ GWEN_Buffer_free(pageBuf);
+ AQH_HttpRequest_SetResponseMsg(rq, msgOut);
+ return 0;
+ }
+ else {
+ msgOut=_createResponseMsg(sv, 501, "Not (yet) implemented", protocol, NULL);
+ AQH_HttpRequest_SetResponseMsg(rq, msgOut);
+ return 0;
+ }
+}
+
+
+
+
+
+
+GWEN_MSG *_createResponseMsg(AQH_SERVICE *sv, int code, const char *text, const char *protocol, const char *page)
+{
+ GWEN_BUFFER *buf;
+ GWEN_MSG *msg;
+
+ buf=GWEN_Buffer_new(0, 256, 0, 1);
+ AQH_HttpService_AddStatusLine(sv, code, text, protocol, buf);
+ _writeDefaultResponseHeaderToBuffer(sv, (page && *page)?strlen(page):0, buf);
+ if (page && *page)
+ GWEN_Buffer_AppendString(buf, page);
+
+ msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
+ GWEN_Buffer_free(buf);
+ return msg;
+}
+
+
+
+void _writeDefaultResponseHeaderToBuffer(AQH_SERVICE *sv, int contentLength, GWEN_BUFFER *buf)
+{
+ GWEN_DB_NODE *db;
+
+ 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");
+ GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", contentLength);
+
+ AQH_HttpService_AddHeader(sv, db, buf);
+ GWEN_DB_Group_free(db);
+}
+
+
+
+
+
+
+
+
diff --git a/apps/aqhome-storage/aqhomehttp.h b/apps/aqhome-storage/aqhomehttp.h
new file mode 100644
index 0000000..726e020
--- /dev/null
+++ b/apps/aqhome-storage/aqhomehttp.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+ * 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
+
+
+void AqHomeHttpService_Extend(AQH_SERVICE *sv);
+
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetRootEndpoint(const AQH_SERVICE *sv);
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetIpcdEndpoint(const AQH_SERVICE *sv);
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetMqttEndpoint(const AQH_SERVICE *sv);
+GWEN_MSG_ENDPOINT *AqHomeHttpService_GetHttpdEndpoint(const AQH_SERVICE *sv);
+
+AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv);
+
+GWEN_DB_NODE *AqHomeHttpService_GetDbArgs(const AQH_SERVICE *sv);
+const char *AqHomeHttpService_GetPidFile(const AQH_SERVICE *sv);
+void AqHomeHttpService_SetPidFile(AQH_SERVICE *sv, const char *s);
+
+
+
+
+
+
+
+
+#endif
+
+
diff --git a/apps/aqhome-storage/aqhomehttp_p.h b/apps/aqhome-storage/aqhomehttp_p.h
new file mode 100644
index 0000000..e046244
--- /dev/null
+++ b/apps/aqhome-storage/aqhomehttp_p.h
@@ -0,0 +1,35 @@
+/****************************************************************************
+ * 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"
+
+
+typedef struct AQHOME_HTTP AQHOME_HTTP;
+struct AQHOME_HTTP {
+ GWEN_MSG_ENDPOINT *rootEndpoint;
+
+ GWEN_MSG_ENDPOINT *ipcdEndpoint;
+ GWEN_MSG_ENDPOINT *mqttEndpoint;
+ GWEN_MSG_ENDPOINT *httpdEndpoint;
+
+ AQH_STORAGE *storage;
+
+ GWEN_DB_NODE *dbArgs;
+
+ char *pidFile;
+};
+
+
+
+#endif
+
+