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 + + + +
aqhome/api.h
+
gwenhywfar/error.h
+
aqhome/service/role.h
+
+ + + + +
+ + + + + + 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 + + + +
aqhome/api.h
+
gwenhywfar/error.h
+
aqhome/service/role.h
+
+ + + + +
+ + + + + + 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 + + + +
aqhome/api.h
+
gwenhywfar/error.h
+
+ + + + +
+ + + + + + 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 + + + +
aqhome/api.h
+
gwenhywfar/error.h
+
gwenhywfar/timestamp.h
+
aqhome/service/user.h
+
+ + + + +
+ + + + + + 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/api.h
+
gwenhywfar/error.h
+
gwenhywfar/timestamp.h
+
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<