/**************************************************************************** * 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 "./u_rooms.h" #include "./aqhomehttp.h" #include "aqhome/http/httpservice.h" #include "aqhome/http/httpservice_http.h" #include "aqhome/http/httpservice_conf.h" #include #include #include /* ------------------------------------------------------------------------------------------------ * defines * ------------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf); static void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf); static void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf); static GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id); static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf); static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf); static GWEN_MSG *_addRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_editRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv) { AQH_HTTP_URLHANDLER *uh; uh=AQH_HttpUrlHandler_new(sv); AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl); return uh; } int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { const char *protocol; const char *cmd; GWEN_MSG *msgOut; AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome"); AQH_HttpRequest_SetupUrlPathMembers(rq); protocol=AQH_HttpRequest_GetProtocol(rq); cmd=AQH_HttpRequest_GetCommand(rq); if (cmd && *cmd) { if (strcasecmp(cmd, "GET")==0) msgOut=_handleGet(uh, rq); else if (strcasecmp(cmd, "POST")==0) msgOut=_handlePost(uh, rq); else { msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL); } AQH_HttpRequest_SetResponseMsg(rq, msgOut); return 0; } else { DBG_ERROR(AQH_LOGDOMAIN, "No command in request"); return GWEN_ERROR_INVALID; } } GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { GWEN_BUFFER *pageBuf; int rv; GWEN_MSG *msgOut=NULL; const char *protocol; const GWEN_STRINGLIST *sl; protocol=AQH_HttpRequest_GetProtocol(rq); pageBuf=GWEN_Buffer_new(0, 256, 0, 1); rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf); if (rv<0) { DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers"); GWEN_Buffer_free(pageBuf); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL); } /* handle middle part (header - middle - footer) */ sl=AQH_HttpRequest_GetUrlPathMembers(rq); if (sl) { const char *s; s=GWEN_StringList_StringAt(sl, 1); if (!(s && *s)) s="list"; if (strcasecmp(s, "list")==0) _handleGetList(uh, rq, pageBuf); else if (strcasecmp(s, "add")==0) _handleGetAdd(uh, rq, pageBuf); else if (strcasecmp(s, "edit")==0) _handleGetEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0), pageBuf); else { DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s); GWEN_Buffer_free(pageBuf); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); } } else { DBG_ERROR(NULL, "No list of url members"); GWEN_Buffer_free(pageBuf); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL); } rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf); if (rv<0) { DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers"); GWEN_Buffer_free(pageBuf); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL); } msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf)); GWEN_Buffer_free(pageBuf); return msgOut; } GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { GWEN_DB_NODE *db; const GWEN_STRINGLIST *sl; const char *protocol; DBG_ERROR(NULL, "POST:"); db=AQH_HttpRequest_GetDbPostBody(rq); GWEN_DB_Dump(db, 2); protocol=AQH_HttpRequest_GetProtocol(rq); sl=AQH_HttpRequest_GetUrlPathMembers(rq); if (sl) { const char *s; s=GWEN_StringList_StringAt(sl, 1); if (s && *s) { if (strcasecmp(s, "add")==0) return _handlePostAdd(uh, rq); else if (strcasecmp(s, "edit")==0) return _handlePostEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0)); else { DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); } } else { DBG_ERROR(NULL, "Invalid url (2nd member missing)"); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); } } else { DBG_ERROR(NULL, "No list of url members"); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); } } void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf) { AQH_SERVICE *sv; uint32_t perms; DBG_ERROR(NULL, "LIST"); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & AQHOME_HTTP_PERMS_LIST_ROOMS) { AQH_STORAGE *sto; sv=AQH_HttpUrlHandler_GetHttpService(uh); sto=AqHomeHttpService_GetStorage(sv); if (sto) { const AQH_ROOM_LIST *rl; GWEN_Buffer_AppendArgs(pageBuf, "

%s

" "" "" " " "", I18N("Rooms"), I18N("Name"), I18N("Description")); GWEN_Buffer_AppendString(pageBuf, ""); rl=AQH_Storage_GetRoomList(sto); if (rl) { const AQH_ROOM *r; r=AQH_Room_List_First(rl); while(r) { long unsigned int id; const char *name; const char *descr; id=(long unsigned int) AQH_Room_GetId(r); name=AQH_Room_GetName(r); descr=AQH_Room_GetDescription(r); GWEN_Buffer_AppendArgs(pageBuf, "" "" "", id, name?name:"", descr?descr:"", id); r=AQH_Room_List_Next(r); } } GWEN_Buffer_AppendString(pageBuf, ""); GWEN_Buffer_AppendArgs(pageBuf, "
Id%s%s
%lu%s%s" "
%s
", I18N("Add Room")); } else { GWEN_Buffer_AppendString(pageBuf, "

Internal error.

"); } } else { GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to see list of rooms.")); } } void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf) { uint32_t perms; DBG_ERROR(NULL, "ADD"); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) { _writeAddPage(uh, rq, NULL, pageBuf); } else { DBG_INFO(NULL, "No permissions to add a room."); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to add a room.")); } } void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf) { uint32_t perms; DBG_ERROR(NULL, "EDIT"); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & AQHOME_HTTP_PERMS_EDIT_ROOM) { AQH_SERVICE *sv; AQH_STORAGE *sto; sv=AQH_HttpUrlHandler_GetHttpService(uh); sto=AqHomeHttpService_GetStorage(sv); if (sto) { if (id>0) { const AQH_ROOM *r; r=AQH_Storage_GetRoomById(sto, id); if (r) { GWEN_DB_NODE *db; int rv; db=GWEN_DB_Group_new("room"); rv=AQH_Room_toDb(r, db); if (rv>=0) _writeEditPage(uh, rq, NULL, pageBuf); else { DBG_ERROR(NULL, "Error writing room %d to db", id); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Internal error.")); } GWEN_DB_Group_free(db); } else { DBG_ERROR(NULL, "Room %d not found", id); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Room not found.")); } } else { DBG_ERROR(NULL, "Missing room id"); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Missing or invalid room id.")); } } else { DBG_ERROR(NULL, "No storage"); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Internal error.")); } } else { DBG_INFO(NULL, "No permissions to edit a room."); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to edit a room.")); } } int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) { const char *name=NULL; const char *descr=NULL; if (dbValues) { name=GWEN_DB_GetCharValue(dbValues, "name", 0, NULL); descr=GWEN_DB_GetCharValue(dbValues, "description", 0, NULL); } GWEN_Buffer_AppendArgs(pageBuf, "

%s


\n" "
" " " " " " " " " " " " " " " " " " " "
" " " "
", I18N("Create a Room"), I18N("Room Name"), name?name:"", I18N("Description"), descr?descr:"", I18N("Add Room")); return 0; } int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) { unsigned long int id; const char *name=NULL; const char *descr=NULL; if (dbValues) { id=GWEN_DB_GetIntValue(dbValues, "id", 0, 0); name=GWEN_DB_GetCharValue(dbValues, "name", 0, NULL); descr=GWEN_DB_GetCharValue(dbValues, "description", 0, NULL); } GWEN_Buffer_AppendArgs(pageBuf, "

%s


\n" "
" " " " " " " " " " " " " " " " " " " "
" " " "
", I18N("Edit a Room"), id, I18N("Room Name"), name?name:"", I18N("Description"), descr?descr:"", I18N("Submit")); return 0; } GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { const char *protocol; AQH_SERVICE *sv; uint32_t perms; protocol=AQH_HttpRequest_GetProtocol(rq); sv=AQH_HttpUrlHandler_GetHttpService(uh); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) { AQH_STORAGE *sto; sto=AqHomeHttpService_GetStorage(sv); if (sto) { return _addRoomCreateResponse(uh, rq); } else { DBG_ERROR(NULL, "No storage"); return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); } } else { return AQH_HttpService_CreateResponseMsg(sv, 403, "Forbidden", protocol, NULL); } } GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id) { const char *protocol; AQH_SERVICE *sv; uint32_t perms; protocol=AQH_HttpRequest_GetProtocol(rq); sv=AQH_HttpUrlHandler_GetHttpService(uh); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) { AQH_STORAGE *sto; sto=AqHomeHttpService_GetStorage(sv); if (sto) { return _editRoomCreateResponse(uh, rq, id); } else { DBG_ERROR(NULL, "No storage"); return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); } } else { return AQH_HttpService_CreateResponseMsg(sv, 403, "Forbidden", protocol, NULL); } } GWEN_MSG *_addRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { AQH_SERVICE *sv; const char *protocol; GWEN_DB_NODE *db; const char *roomName; const char *roomDescr; AQH_STORAGE *sto; sv=AQH_HttpUrlHandler_GetHttpService(uh); protocol=AQH_HttpRequest_GetProtocol(rq); db=AQH_HttpRequest_GetDbPostBody(rq); roomName=GWEN_DB_GetCharValue(db, "name", 0, NULL); roomDescr=GWEN_DB_GetCharValue(db, "description", 0, NULL); if (!(roomName && *roomName)) { DBG_INFO(NULL, "Missing room name"); return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Missing room name"), 1, db, _writeAddPage); } sto=AqHomeHttpService_GetStorage(sv); if (sto) { AQH_ROOM *r; int rv; r=AQH_Room_new(); AQH_Room_SetName(r, roomName); if (roomDescr && *roomDescr) AQH_Room_SetDescription(r, roomDescr); rv=AqHomeHttpService_LockStorage(sv); if (rv<0) { DBG_ERROR(NULL, "Error locking storage"); return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); } if (AQH_Storage_GetRoomByName(sto, roomName)!=NULL) { DBG_INFO(NULL, "Room \"%s\" already exists", roomName); AqHomeHttpService_UnlockStorage(sv); return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Room already exists"), 1, db, _writeAddPage); } AQH_Storage_AddRoom(sto, r); AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED); rv=AqHomeHttpService_UnlockStorage(sv); if (rv<0) { DBG_ERROR(NULL, "Error unlocking storage"); return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); } return AQH_HttpService_CreateRedirectingResponseMsg(sv, protocol, "/rooms/list"); } else return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); } GWEN_MSG *_editRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id) { AQH_SERVICE *sv; const char *protocol; GWEN_DB_NODE *db; const char *roomName; const char *roomDescr; AQH_STORAGE *sto; sv=AQH_HttpUrlHandler_GetHttpService(uh); protocol=AQH_HttpRequest_GetProtocol(rq); db=AQH_HttpRequest_GetDbPostBody(rq); roomName=GWEN_DB_GetCharValue(db, "name", 0, NULL); roomDescr=GWEN_DB_GetCharValue(db, "description", 0, NULL); if (!(roomName && *roomName)) { DBG_INFO(NULL, "Missing room name"); return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Missing room name"), 1, db, _writeAddPage); } sto=AqHomeHttpService_GetStorage(sv); if (sto) { AQH_ROOM *r; int rv; rv=AqHomeHttpService_LockStorage(sv); if (rv<0) { DBG_ERROR(NULL, "Error locking storage"); return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); } r=AQH_Storage_GetRoomById(sto, id); if (r==NULL) { AqHomeHttpService_UnlockStorage(sv); DBG_ERROR(NULL, "Room %d not found", id); return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Room not found"), 1, db, _writeEditPage); } /* edit room */ AQH_Room_SetName(r, roomName); if (roomDescr && *roomDescr) AQH_Room_SetDescription(r, roomDescr); AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED); rv=AqHomeHttpService_UnlockStorage(sv); if (rv<0) { DBG_ERROR(NULL, "Error unlocking storage"); return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); } return AQH_HttpService_CreateRedirectingResponseMsg(sv, protocol, "/rooms/list"); } else return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL); }