Subversion Repositories heating

Rev

Rev 17 | Rev 19 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2015 by Andreas Theofilu. All rights reserved!
 *
 * All rights reserved. No warranty, explicit or implicit, provided.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Andreas Theofilu and his suppliers, if any.
 * The intellectual and technical concepts contained
 * herein are proprietary to Andreas Theofilu and its suppliers and
 * may be covered by European and Foreign Patents, patents in process,
 * and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Andreas Theofilu.
 * 
 * Author: Andreas Theofilu <andreas@theosys.at>
 */
#include <iostream>
#include <string>
#include <cstring>
#include <cctype>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <syslog.h>
#include <microhttpd.h>
#include "config.h"
#include "helper.h"
#include "controller.h"
#include "html.h"

using namespace std;

#define POSTBUFFERSIZE  512
#define MAXNAMESIZE     20
#define MAXANSWERSIZE   512

#define GET             0
#define POST            1

class HttpController : public DynamicController
{
        public:
                HttpController(string mp) { mainPage = mp; }

                virtual bool validPath(const char* path, const char* method)
                {
                        syslog(LOG_DEBUG, "path=%s, method=%s", path, method);

                        if(strcmp(path, "/") == 0 && strcmp("GET", method) == 0)
                        {
                                return true;
                        }

                        return false;
                }
        
                virtual void createResponse(struct MHD_Connection *connection,
                                        const char *url, const char * method, const char *upload_data,
                                        size_t *upload_data_size, std::stringstream& response)
                {
                        response << mainPage;
                }
        
        private:
                string mainPage;
};

html::html()
{
        enableDebug(Configure.debug);
        HeatConf = nullptr;
        glb_night = 0.0;
        glb_absent = 0.0;
        stop = false;
        daemon = nullptr;
}

html::~html()
{
HTCONF *akt = HeatConf;

        if (daemon)
                MHD_stop_daemon (daemon);

        while (akt)
        {
                HTCONF *p;

                p = akt->next;
                delete akt;
                akt = p;
        }
}

void html::run()
{
HttpController HtmlPage(mainPage);

        initPages();
        addController(&HtmlPage);
        daemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
                                                          Configure.html_port, NULL, NULL, &request_handler, this, MHD_OPTION_END);
        
        while (!stop)
                sleep(60);

        MHD_stop_daemon (daemon);
}

void html::initPages()
{
HTCONF *akt = HeatConf;

        // This is the main page
        mainPage = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
        mainPage.append ("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
        mainPage.append ("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"de\" lang=\"de\">\n\n");
        mainPage.append ("<head>\n");
        mainPage.append ("<title>Heizungsteuerung</title>\n");
        mainPage.append ("<META NAME=\"author\" CONTENT=\"Andreas Theofilu\">\n");
        mainPage.append ("<META NAME=\"publisher\" CONTENT=\"Andreas Theofilu (TheoSys)\">\n");
        mainPage.append ("<META NAME=\"copyright\" CONTENT=\"(C) 2015 by Andreas Theofilu\">\n");
        mainPage.append ("<meta name=\"Description\" content=\"Heating control\">\n");
        mainPage.append ("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
        mainPage.append ("<meta NAME=\"content-language\" content=\"de\">\n");
        mainPage.append ("</head>\n");
        mainPage.append ("<body>\n");
        
        mainPage.append ("<h1>Heizungsteuerung</h1>\n");
        mainPage.append ("<table border=1 cellpadding=0 cellspacing=0>\n");
        mainPage.append ("<tr><td>");
        
        mainPage.append ("<table border=0>\n");
        mainPage.append ("<tr><td>");
        mainPage.append ("<form action=\"/global\" method=\"post\">");
        mainPage.append ("<tr><td>Nachtabsenkung</td><td><input type=\"text\" id=\"gnight\" value=\"" + doubleToString(glb_night, 2) + "\"></td></tr>\n");
        mainPage.append ("<tr><td>Abwesend</td><td><input type=\"text\" id=\"gabsent\" value=\"" + doubleToString(glb_absent, 2) + "\"></td></tr>\n");
        mainPage.append ("</table></tr></td>\n");
        
        if (mode)
                mainPage.append ("<tr><td><input type=\"radio\" name=\"mode\" value=\"normal\" checked>Anwesend&nbsp;&nbsp;<input type=\"radio\" name=\"mode\" value=\"off\">Abwesend</td></tr>\n");
        else
                mainPage.append ("<tr><td><input type=\"radio\" name=\"mode\" value=\"normal\">Anwesend&nbsp;&nbsp;<input type=\"radio\" name=\"mode\" value=\"off\" checked>Abwesend</td></tr>\n");

        mainPage.append ("<tr><td><input type=\"submit\" value=\"Speichern\"></td></tr>\n</form>\n");
        mainPage.append ("</table>\n");
        
        mainPage.append ("<table border=1 cellpadding=0 cellspacing=0>\n");
        mainPage.append ("<tr><td>");
        
        mainPage.append ("<form = action=\"/room\" method=\"post\">");
        mainPage.append ("<table border=0>\n");
        mainPage.append ("<tr><td>Raum</td><td><select size=\"5\" name=\"room\" onChange=\"javascript:document.room.submit()\">\n");
        
        while (akt)
        {
                mainPage.append ("<option value=\"" + itostring(akt->rnum) + "\">" + ToString(akt->rname) +"</option>");
                akt = akt->next;
        }

        akt = HeatConf;
        mainPage.append ("</select></td></tr>\n");
        mainPage.append ("<tr><td>Solltemperatur</td><td><input type=\"text\" id=\"soll\" value=\"" + doubleToString(akt->soll, 2) + "\"></td></tr>\n");
        mainPage.append ("<tr><td>Nachtabsenkung</td><td><input type=\"text\" id=\"night\" value=\"" + doubleToString(akt->night, 2) + "\"></td></tr>\n");
        mainPage.append ("<tr><td>Abwesenheit</td><td><input type=\"text\" id=\"absent\" value=\"" + doubleToString(akt->minimal, 2) + "\"></td></tr>\n");
        mainPage.append ("<tr><td>&nbsp;</td><td><input type=\"submit\" value=\"Speichern\"></td></tr>\n");
        
        mainPage.append ("</table></td></tr></table>\n");
        mainPage.append ("</body>\n</html>\n");
}

html::HTCONF *html::addConfig(HTCONF *ht)
{
HTCONF *akt;

        akt = new HTCONF;
        memmove (akt, ht, sizeof(HTCONF));
        akt->next = nullptr;

        if (HeatConf == nullptr)
                HeatConf = akt;
        else
        {
                HTCONF *p;

                p = HeatConf;

                while (p->next)
                        p = p->next;

                p->next = akt;
        }

        debug("html::addConfig(): rname="+ToString(akt->rname)+", rnum="+itostring(akt->rnum));
        return akt;
}

/*
 * The following functions are callbacks for the HTML server
 */
int html::request_handler(void* cls, struct MHD_Connection* connection,
                                                           const char* url, const char* method, const char* version,
                                                           const char* upload_data, size_t* upload_data_size, void** ptr)
{
html *server = (html *)cls;
        
        Controller *controller = 0;

        for (int i = 0; i < (int)server->controllers.size(); i++)
        {
                Controller *c = server->controllers.at(i);

                if(c->validPath(url, method))
                {
                        controller = c;
                        break;
                }
        }
        
        if (!controller)
        {
                syslog(LOG_WARNING, "Path <%s> not found.", url);
                struct MHD_Response* response = MHD_create_response_from_buffer(0, 0, MHD_RESPMEM_PERSISTENT);
                return MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
        }
        
        return controller->handleRequest(connection, url, method, upload_data, upload_data_size);
}

void html::addController(Controller* controller)
{
        controllers.push_back(controller);
}

int html::send_page (struct MHD_Connection *connection, const char *page)
{
int ret;
struct MHD_Response *response;
        
        response = MHD_create_response_from_buffer (strlen (page), (void *)page, MHD_RESPMEM_PERSISTENT);

        if (!response)
                return MHD_NO;

        ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
        MHD_destroy_response (response);
        return ret;
}

/*
int html::iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
                          const char *filename, const char *content_type,
                          const char *transfer_encoding, const char *data, uint64_t off,
                          size_t size)
{
struct connection_info_struct *con_info = coninfo_cls;
        
        if (strcmp (key, "name") == 0)
        {
                if (size > 0 && size <= MAXNAMESIZE)
                {
                        char *answerstring;
                        answerstring = malloc (MAXANSWERSIZE);
                        
                        if (!answerstring)
                        {
                                syslog (LOG_DAEMON, "Error allocating memory for an answer string!");
                                return MHD_NO;
                        }
                        
                        snprintf (answerstring, MAXANSWERSIZE, mainPage.c_str(), data);
                        con_info->answerstring = answerstring;
                }
                else
                        con_info->answerstring = NULL;
                
                return MHD_NO;
        }
        
        return MHD_YES;
}

void request_completed (void *cls, struct MHD_Connection *connection,
                                   void **con_cls, enum MHD_RequestTerminationCode toe)
{
struct connection_info_struct *con_info = *con_cls;
        
        if (NULL == con_info)
                return;
        
        if (con_info->connectiontype == POST)
        {
                MHD_destroy_post_processor (con_info->postprocessor);
                
                if (con_info->answerstring)
                        free (con_info->answerstring);
        }
        
        free (con_info);
        *con_cls = NULL;
}

int html::answer_to_connection (void *cls, struct MHD_Connection *connection,
                                          const char *url, const char *method,
                                          const char *version, const char *upload_data,
                                          size_t *upload_data_size, void **con_cls)
{
        if (*con_cls == NULL)
        {
                struct connection_info_struct *con_info;
                
                con_info = malloc (sizeof (struct connection_info_struct));
                
                if (con_info == NULL)
                {
                        syslog (LOG_DAEMON, "Not enought memory for a HTML answer!");
                        return MHD_NO;
                }

                con_info->answerstring = NULL;
                
                if (strcmp (method, "POST") == 0)
                {
                        con_info->postprocessor = MHD_create_post_processor (connection, POSTBUFFERSIZE, iterate_post, (void *) con_info);
                        
                        if (NULL == con_info->postprocessor)
                        {
                                free (con_info);
                                return MHD_NO;
                        }
                        
                        con_info->connectiontype = POST;
                }
                else
                        con_info->connectiontype = GET;
                
                *con_cls = (void *)con_info;
                return MHD_YES;
        }
        
        if (strcmp (method, "GET") == 0)
                return send_page (connection, mainPage.c_str());
        
        if (strcmp (method, "POST") == 0)
        {
                struct connection_info_struct *con_info = *con_cls;
                
                if (*upload_data_size != 0)
                {
                        MHD_post_process (con_info->postprocessor, upload_data, *upload_data_size);
                        *upload_data_size = 0;
                        return MHD_YES;
                }
                else if (con_info->answerstring != NULL)
                        return send_page (connection, con_info->answerstring);
        }
        
        return send_page (connection, errorpage);
}
*/