diff --git a/0BUILD b/0BUILD index c6780a5..2e817b5 100644 --- a/0BUILD +++ b/0BUILD @@ -51,6 +51,8 @@ $(includedir)/aqhome/$(package) $(datadir)/$(package) + /var/www + TRUE TRUE FALSE diff --git a/apps/aqhome-cgi/0BUILD b/apps/aqhome-cgi/0BUILD index 1cc8bdf..3fc42e3 100644 --- a/apps/aqhome-cgi/0BUILD +++ b/apps/aqhome-cgi/0BUILD @@ -3,7 +3,7 @@ - + $(gwenhywfar_cflags) @@ -55,6 +55,7 @@ $(gwenhywfar_libs) -lm + $(aqcgi_libs) @@ -117,6 +118,7 @@ aqhome aqhcgi_service + aqhcgi_modules @@ -127,6 +129,7 @@ service + modules diff --git a/apps/aqhome-cgi/README b/apps/aqhome-cgi/README new file mode 100644 index 0000000..6dbd1b1 --- /dev/null +++ b/apps/aqhome-cgi/README @@ -0,0 +1,14 @@ + + +Modules: +- login +- devices + - list + - show?id="nodes/12345678" + - add + - edit + - delete +- values +- rooms + +- dashboards diff --git a/apps/aqhome-cgi/main.c b/apps/aqhome-cgi/main.c index b9676a7..a868688 100644 --- a/apps/aqhome-cgi/main.c +++ b/apps/aqhome-cgi/main.c @@ -1,11 +1,167 @@ +#include "./service_file.h" +#include "aqhome-cgi/modules/mroot.h" +#include "aqhome/aqhome.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +#define AQHOME_CGI_LOGFILE "/var/www/aqhome-cgi/log/aqhome-cgi.log" + +#define AQHOME_CGI_DEFAULT_STATIC_FILES "0-build/services/static" +#define AQHOME_CGI_DEFAULT_RUNTIME_FILES "0-build/services/runtime" + + + +void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles); +int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles); +AQH_MODULE *_loadModule(AQH_SERVICE *sv, AQCGI_REQUEST *rq, AQH_MODULE *mParent, const char *sModuleName); +static void logStart(void); int main(int argc, char **argv) { + AQCGI_REQUEST *rq; + + logStart(); + GWEN_Logger_Open(GWEN_LOGDOMAIN, "gwenhywfar", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); + GWEN_Logger_Open(AQH_LOGDOMAIN, "aqhome", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); + GWEN_Logger_Open(AQCGI_LOGDOMAIN, "aqcgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); + GWEN_Logger_SetLevel(AQCGI_LOGDOMAIN, GWEN_LoggerLevel_Debug); + GWEN_Logger_Open(NULL, "aqhome-cgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); + + DBG_ERROR(NULL, "Init CGI"); + AQCGI_Init(); + + rq=AQCGI_ReadRequest(); + if (rq) { + const char *sPathStaticFiles; + const char *sPathRuntimeFiles; + + sPathStaticFiles=getenv("AQHOME_STATIC_FILES"); + if (!(sPathStaticFiles && *sPathStaticFiles)) + sPathStaticFiles=AQHOME_CGI_DEFAULT_STATIC_FILES; + + sPathRuntimeFiles=getenv("AQHOME_RUNTIME_FILES"); + if (!(sPathRuntimeFiles && *sPathRuntimeFiles)) + sPathRuntimeFiles=AQHOME_CGI_DEFAULT_RUNTIME_FILES; + + _handleRequest(rq, sPathStaticFiles, sPathRuntimeFiles); + } + else { + fprintf(stdout, "Content-type: text/plain\n\n"); + fprintf(stdout, "Error: No Request!\n"); + return 0; + } + + AQCGI_Fini(); + + fprintf(stdout, "Content-type: text/plain\n\n"); + fprintf(stdout, "Request handled\n"); + return 0; } + +void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles) +{ + AQH_SERVICE *sv; + int rv; + + sv=AQH_ServiceFiles_new(sPathRuntimeFiles); + + rv=_handlePath(sv, rq, sPathStaticFiles); + if (rv<0) { + } + AQH_Service_free(sv); +} + + + +int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles) +{ + AQH_MODULE *mRoot; + AQH_MODULE *mParent; + const GWEN_STRINGLIST *sl; + + mRoot=AQH_ModRoot_new(sv, sPathStaticFiles); + mParent=mRoot; + + sl=AQCGI_Request_GetStringlistPath(rq); + if (sl) { + GWEN_STRINGLISTENTRY *se; + + se=GWEN_StringList_FirstEntry(sl); + while(se) { + GWEN_STRINGLISTENTRY *seNext; + const char *s; + + seNext=GWEN_StringListEntry_Next(se); + s=GWEN_StringListEntry_Data(se); + if (s && *s) { + if (seNext) { + AQH_MODULE *m; + + DBG_ERROR(NULL, "Entry: %s (%s)", s, seNext?"not last":"last"); + m=AQH_ModService_LoadSubModule(mParent, rq, s); + if (m==NULL) { + AQH_Module_free(mRoot); + AQCGI_SendResponseWithStatus(rq, 404, "Not found"); + return GWEN_ERROR_GENERIC; + } + mParent=m; + } + else { + int rv; + + /* last, let module handle remaining part */ + rv=AQH_ModService_HandleRequest(mParent, rq, s); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQH_Module_free(mRoot); + return rv; + } + break; + } + } + + se=seNext; + } + AQH_Module_free(mRoot); + return 0; + } + else { + AQH_Module_free(mRoot); + return GWEN_ERROR_GENERIC; + } +} + + + +void logStart() +{ + FILE *f; + + f=fopen(AQHOME_CGI_LOGFILE, "a+"); + if (f!=NULL) { + fprintf(f, "Started.\n"); + fclose(f); + } +} + + + + + diff --git a/apps/aqhome-cgi/modules/0BUILD b/apps/aqhome-cgi/modules/0BUILD new file mode 100644 index 0000000..ac02ab6 --- /dev/null +++ b/apps/aqhome-cgi/modules/0BUILD @@ -0,0 +1,84 @@ + + + + + + + + $(gwenhywfar_cflags) + -I$(topsrcdir) + -I$(topbuilddir) + -I$(topsrcdir)/apps + -I$(topbuilddir)/apps + -I$(builddir) + -I$(srcdir) + + + + --include=$(builddir) + --include=$(srcdir) + + + + + + $(visibility_cflags) + + + + --api=AQHOME_API + + + + + + + + + + + + + + + + + + $(local/built_headers_pub) + + + + + mservice.h + mroot.h + + + + + mservice_p.h + mroot_p.h + + + + + $(local/typefiles) + + mservice.c + mroot.c + + + + + + + + + + + + static + + + + + diff --git a/apps/aqhome-cgi/modules/mroot.c b/apps/aqhome-cgi/modules/mroot.c new file mode 100644 index 0000000..751f6b0 --- /dev/null +++ b/apps/aqhome-cgi/modules/mroot.c @@ -0,0 +1,109 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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 "./mroot_p.h" + +#include "aqhome-cgi/service/module.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +/* ------------------------------------------------------------------------------------------------ + * global vars + * ------------------------------------------------------------------------------------------------ + */ + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName); +static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem); +static int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq); + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder) +{ + AQH_MODULE *m; + + m=AQH_ModService_new(sv, baseFolder); + AQH_ModService_SetHandleRequestFn(m, _handleRequest); + AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule); + + return m; +} + + + +AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName) +{ + return NULL; +} + + + +int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem) +{ + if (strcasecmp(sLastPathElem, "login")==0) + return _handleRqLogin(m, rq); + else if (strcasecmp(sLastPathElem, "signup")==0) { + } + else if (strcasecmp(sLastPathElem, "confirm")==0) { + } +} + + + +int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq) +{ + if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_GET) { + int rv; + + rv=AQH_ModService_RespondWithFile(m, rq, "login.html"); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + return 0; + } + else if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_POST) { + GWEN_DB_NODE *dbPost; + + dbPost=AQCGI_Request_GetDbPostBody(rq); + if (dbPost) { + + } + } + else { + } +} + + + + + + + + diff --git a/apps/aqhome-cgi/modules/mroot.h b/apps/aqhome-cgi/modules/mroot.h new file mode 100644 index 0000000..377a6fb --- /dev/null +++ b/apps/aqhome-cgi/modules/mroot.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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_CGI_MROOT_H +#define AQHOME_CGI_MROOT_H + +#include + +#include + +#include + + +AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder); + +AQH_MODULE *AQH_ModRoot_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName); +int AQH_ModRoot_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem); + + + +#endif + diff --git a/apps/aqhome-cgi/modules/mroot_p.h b/apps/aqhome-cgi/modules/mroot_p.h new file mode 100644 index 0000000..eae16f9 --- /dev/null +++ b/apps/aqhome-cgi/modules/mroot_p.h @@ -0,0 +1,18 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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_CGI_MROOT_P_H +#define AQHOME_CGI_MROOT_P_H + +#include "aqhome-cgi/modules/mroot.h" + + + + +#endif + diff --git a/apps/aqhome-cgi/modules/mservice.c b/apps/aqhome-cgi/modules/mservice.c new file mode 100644 index 0000000..a40bb17 --- /dev/null +++ b/apps/aqhome-cgi/modules/mservice.c @@ -0,0 +1,284 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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 "./mservice_p.h" + +#include "aqhome-cgi/service/module.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define AQH_MOD_SERVICE_HEADERFILE "header.html" +#define AQH_MOD_SERVICE_FOOTERFILE "footer.html" + + + +/* ------------------------------------------------------------------------------------------------ + * global vars + * ------------------------------------------------------------------------------------------------ + */ + +GWEN_INHERIT(AQH_MODULE, AQH_MOD_SERVICE) + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MODULE *AQH_ModService_new(AQH_SERVICE *sv, const char *baseFolder) +{ + AQH_MODULE *m; + AQH_MOD_SERVICE *xm; + + m=AQH_Module_new(); + GWEN_NEW_OBJECT(AQH_MOD_SERVICE, xm); + GWEN_INHERIT_SETDATA(AQH_MODULE, AQH_MOD_SERVICE, m, xm, _freeData); + + xm->service=sv; + xm->baseFolder=(baseFolder && *baseFolder)?strdup(baseFolder):NULL; + + return m; +} + + + +void _freeData(GWEN_UNUSED void *bp, void *p) +{ + AQH_MOD_SERVICE *xm; + + xm=(AQH_MOD_SERVICE*) p; + free(xm->baseFolder); + GWEN_FREE_OBJECT(xm); +} + + + +AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m) +{ + if (m) { + AQH_MOD_SERVICE *xm; + + xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m); + if (xm) { + return xm->service; + } + } + return NULL; +} + + + +const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m) +{ + if (m) { + AQH_MOD_SERVICE *xm; + + xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m); + if (xm) { + return xm->baseFolder; + } + } + return NULL; +} + + + +void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn) +{ + if (m) { + AQH_MOD_SERVICE *xm; + + xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m); + if (xm) { + xm->handleRequestFn=fn; + } + } +} + + + +void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn) +{ + if (m) { + AQH_MOD_SERVICE *xm; + + xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m); + if (xm) { + xm->loadSubModuleFn=fn; + } + } +} + + + +int AQH_ModService_AddHeader(AQH_MODULE *m, GWEN_BUFFER *dbuf) +{ + if (m && dbuf) { + AQH_MODULE *mParent; + + mParent=AQH_Module_Tree2_GetParent(m); + if (mParent) { + int rv; + + rv=AQH_ModService_AddHeader(mParent, dbuf); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + } + return AQH_ModService_ReadStaticFile(m, AQH_MOD_SERVICE_HEADERFILE, dbuf); + } + DBG_ERROR(NULL, "Argument missing"); + return GWEN_ERROR_INVALID; +} + + + +int AQH_ModService_AddFooter(AQH_MODULE *m, GWEN_BUFFER *dbuf) +{ + if (m && dbuf) { + AQH_MODULE *mParent; + int rv; + + rv=AQH_ModService_ReadStaticFile(m, AQH_MOD_SERVICE_FOOTERFILE, dbuf); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + + mParent=AQH_Module_Tree2_GetParent(m); + if (mParent) { + int rv; + + rv=AQH_ModService_AddFooter(mParent, dbuf); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + } + } + DBG_ERROR(NULL, "Argument missing"); + return GWEN_ERROR_INVALID; +} + + + +int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sFilename) +{ + GWEN_BUFFER *buf; + int rv; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + rv=AQH_ModService_AddHeader(m, buf); + if (rv<0) { + AQCGI_SendResponseWithStatus(rq, 500, "Internal error"); + GWEN_Buffer_free(buf); + return GWEN_ERROR_INTERNAL; + } + rv=AQH_ModService_ReadStaticFile(m, sFilename, buf); + if (rv<0) { + AQCGI_SendResponseWithStatus(rq, 500, "Internal error"); + GWEN_Buffer_free(buf); + return GWEN_ERROR_INTERNAL; + } + rv=AQH_ModService_AddFooter(m, buf); + if (rv<0) { + AQCGI_SendResponseWithStatus(rq, 500, "Internal error"); + GWEN_Buffer_free(buf); + return GWEN_ERROR_INTERNAL; + } + AQCGI_Request_SetBufferResponseBody(rq, buf); + AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html"); + return 0; +} + + + +int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem) +{ + if (m) { + AQH_MOD_SERVICE *xm; + + xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m); + if (xm && xm->handleRequestFn) + return xm->handleRequestFn(m, rq, sLastPathElem); + } + return GWEN_ERROR_NOT_IMPLEMENTED; +} + + + +AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName) +{ + if (m) { + AQH_MOD_SERVICE *xm; + + xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m); + if (xm && xm->loadSubModuleFn) + return xm->loadSubModuleFn(m, rq, sModuleName); + } + return NULL; +} + + + +int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *filename, GWEN_BUFFER *dbuf) +{ + if (m && filename && dbuf) { + AQH_MOD_SERVICE *xm; + + xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m); + if (xm) { + GWEN_BUFFER *fbuf; + int rv; + + fbuf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Buffer_AppendString(fbuf, xm->baseFolder); + GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S); + GWEN_Buffer_AppendString(fbuf, filename); + DBG_ERROR(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(fbuf)); + rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fbuf), dbuf); + if (rv<0) { + DBG_ERROR(NULL, "Read(%s): %d", GWEN_Buffer_GetStart(fbuf), rv); + GWEN_Buffer_free(fbuf); + return rv; + } + GWEN_Buffer_free(fbuf); + return 0; + } + } + DBG_ERROR(NULL, "Any arg is missing (or is not a AQH_MOD_SERVICE object)"); + return GWEN_ERROR_INTERNAL; +} + + + + + diff --git a/apps/aqhome-cgi/modules/mservice.h b/apps/aqhome-cgi/modules/mservice.h new file mode 100644 index 0000000..f263c71 --- /dev/null +++ b/apps/aqhome-cgi/modules/mservice.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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_CGI_MSERVICE_H +#define AQHOME_CGI_MSERVICE_H + +#include +#include + +#include + +#include + + +typedef int (*AQH_MODSERVICE_HANDLEREQUEST_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem); +typedef AQH_MODULE* (*AQH_MODSERVICE_LOADSUBMODULE_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName); + + + +AQH_MODULE *AQH_ModService_new(AQH_SERVICE *sv, const char *baseFolder); + +AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m); +const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m); + + +int AQH_ModService_AddHeader(AQH_MODULE *m, GWEN_BUFFER *dbuf); +int AQH_ModService_AddFooter(AQH_MODULE *m, GWEN_BUFFER *dbuf); + +AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName); +int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem); + +int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sFilename); +int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *filename, GWEN_BUFFER *dbuf); + + +void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn); +void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn); + + +#endif + diff --git a/apps/aqhome-cgi/modules/mservice_p.h b/apps/aqhome-cgi/modules/mservice_p.h new file mode 100644 index 0000000..45a460a --- /dev/null +++ b/apps/aqhome-cgi/modules/mservice_p.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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_CGI_MSERVICE_P_H +#define AQHOME_CGI_MSERVICE_P_H + +#include "aqhome-cgi/modules/mservice.h" + + +typedef struct AQH_MOD_SERVICE AQH_MOD_SERVICE; +struct AQH_MOD_SERVICE { + AQH_SERVICE *service; + char *baseFolder; + + AQH_MODSERVICE_HANDLEREQUEST_FN handleRequestFn; + AQH_MODSERVICE_LOADSUBMODULE_FN loadSubModuleFn; +}; + + + +#endif + diff --git a/apps/aqhome-cgi/modules/static/0BUILD b/apps/aqhome-cgi/modules/static/0BUILD new file mode 100644 index 0000000..1bdbf2d --- /dev/null +++ b/apps/aqhome-cgi/modules/static/0BUILD @@ -0,0 +1,7 @@ + + + + + en + + diff --git a/apps/aqhome-cgi/modules/static/en/0BUILD b/apps/aqhome-cgi/modules/static/en/0BUILD new file mode 100644 index 0000000..d99dbf2 --- /dev/null +++ b/apps/aqhome-cgi/modules/static/en/0BUILD @@ -0,0 +1,13 @@ + + + + + + header.html + footer.html + login.html + + + + + diff --git a/apps/aqhome-cgi/modules/static/en/footer.html b/apps/aqhome-cgi/modules/static/en/footer.html new file mode 100644 index 0000000..6c663b9 --- /dev/null +++ b/apps/aqhome-cgi/modules/static/en/footer.html @@ -0,0 +1,4 @@ + +