//
// File: hdsMaster.cpp
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
//
// Description: Dissemino Web-Masters Management Facility - Manages website resources, such as pages, article groups and include blocks. Allocates ids and manages version numbers.
//
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <stdarg.h>
#include <dirent.h>
#include <netdb.h>
#include <signal.h>
#include "hzErrcode.h"
#include "hzTokens.h"
#include "hzTextproc.h"
#include "hzDissemino.h"
using namespace std ;
/*
** Variables
*/
static const hzString s_master_head_nav =
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
"<meta http-equiv=\"Expires\" content=\"-1\"/>\n"
"<meta http-equiv=\"Cache-Control\" content=\"no-cache\"/>\n"
"<meta http-equiv=\"Cache-Control\" content=\"no-store\"/>\n"
"<meta http-equiv=\"Pragma\" content=\"no-cache\"/>\n"
"<meta http-equiv=\"Pragma\" content=\"no-store\"/>\n"
"<style>\n"
"body { margin:0px; background-color:#FFFFFF; }\n"
".main { text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; color:#000000; }\n"
".title { text-decoration:none; font-family:verdana; font-size:15px; font-weight:normal; color:#000000; }\n"
".nbar { text-decoration:none; font-family:verdana; font-size:10px; font-weight:bold; color:#FFFFFF; cursor:hand; }\n"
".nfld { list-style-type:none; font-family:verdana; font-size:10px; font-weight:bold; color:#000000; cursor:hand; }\n"
".objtitle { height:30px; border:0px; margin:0px; list-style-type:none; background-color:#A0F0AF; overflow-x:none; overflow-y:none; }\n"
".navtree { height:calc(100% - 88px); border:1px; margin:0px; list-style-type:none; white-space:nowrap; background-color:#E0E0E0; overflow-x:auto; overflow-y:scroll; }\n"
".objpage { height:calc(100% - 118px); border:0px; margin:0px; list-style-type:none; white-space:nowrap; background-color:#A0F0AF; overflow-x:auto; overflow-y:auto; }\n"
".fixVP { height:calc(100% - 118px); width:auto; position:relative; background-color:#FFFFFF; overflow-x:hidden; overflow-y:hidden; table-layout:auto; border-collapse:collapse; }\n"
".fixVP th { text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; padding:2px; }\n"
".fixVP td { text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; padding:2px; }\n"
".fixVP tbody { overflow-y:auto; }\n"
".fixVP thead { background:white; color:#000000; }\n"
"</style>\n"
"<script>\n"
"function mgwp()\n"
"{\n"
" var screenW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;\n"
" var screenH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;\n"
" var txt;\n"
" var h;\n"
" h=screenH-88;\n"
" txt=h+\"px\";\n"
" var x=document.getElementById(\"navlhs\"); x.style.minHeight=txt; x.style.maxHeight=txt;\n"
" h=screenH-118;\n"
" txt=h+\"px\";\n"
" var y=document.getElementById(\"articlecontent\"); y.style.minHeight=txt; y.style.maxHeight=txt;\n"
"}\n"
"</script>\n"
"</head>\n\n"
"<body onload=\"mgwp()\" onpageshow=\"mgwp()\" onresize=\"mgwp()\">\n\n" ;
// ".fixVP { width:auto; position:fixed; background-color:#FFFFFF; overflow-x:hidden; overflow-y:hidden; table-layout:auto; border-collapse:collapse; }\n"
static const hzString s_master_entry_pt = "masterEntryPt" ;
static const hzString s_articleTitle = "x-title" ; // Name of HTTP header supplied upon request of an article, used to convey article title
static const hzString s_articleScript = "x-script" ; // Name of HTTP header supplied upon request of an article, used to convey article script
extern hzString _dsmScript_tog ; // Navtree toggle script
extern hzString _dsmScript_loadArticle ; // Navtree load article script
extern hzString _dsmScript_navtree ; // Navtree script
/*
** Prototypes
*/
hzEcode _masterAppParam (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterCfgList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterFldSpecs (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterEnumEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterClassEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterMbrEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterReposEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterFileList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
//hzEcode _masterUSL (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterStrGen (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterStrFix (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterEmaddr (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterDomain (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterMemstat (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterBanned (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterVisList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterResList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE) ;
hzEcode _masterCfgEdit (hzHttpEvent* pE, const hzString& cname) ;
hzEcode _masterMainMenu (hzHttpEvent* pE) ;
/*
** Init Functions
*/
void hdsApp::SetupMasterMenu (void)
{
// Setup the webmaster menu as a tree of C-Interface articles.
//
// This creates the master page templates for viewing/managing the data model. Includes the forms and form handlers for creating/editing classes, class members and repositories.
_hzfunc("hdsApp::SetupDataModel") ;
const hdbMember* pMbr ; // Class member
const hdbDatatype* pType ; // Data type (base class)
const hdbClass* pSub ; // Sub-class
const hdbEnum* pEnum ; // Data Enum
const hdbClass* pClass ; // Class
const hdbObjRepos* pRepos ; // Repository
//hdsArticle* pRoot ; // Tree item
//hdsArticle* pHead ; // Tree heading
//hdsArticle* pItem_E ; // Tree item "Enums"
//hdsArticle* pItem_C ; // Tree item "Classes"
//hdsArticle* pItem_R ; // Tree item "Repositories"
//hdsArticle* pItemCC ; // Tree item of current class
hdsArticleCIF* pArtCIF ; // Current article
hzString root ; // Header title
hzString H ; // Header ref name
hzString X ; // Subheader ref name
hzString Y ; // sub sub header ref name
hzString R ; // Article ref name
hzString T ; // Article title
hzString S ; // Temp string
uint32_t n ; // Loop iterator
uint32_t mbrNo ; // Member number
char namBuf[16] ; // Numeric based name
if (!this)
hzexit(E_SEQUENCE, "No application") ;
// Set name of hdsApp::m_DataModel to 'master'
m_DataModel.m_Groupname = "master" ;
//m_DataModel.m_USL.SetGroup(m_ArticleGroups.Count()) ;
m_ArticleGroups.Insert(m_DataModel.m_Groupname, &m_DataModel) ;
// LOAD TREE
root.Clear() ;
H = "Master_Main_Menu" ;
T = m_Appname ;
m_DataModel.AddHead(root, H, T, true) ;
root = H ;
// Add the menu items applicable at the Sphere level
H = "SphereLevel" ;
T = "Sphere Level Resources" ;
m_DataModel.AddHead(root, H, T, true) ;
R = "S.1" ; T = "Blacklisted IPs" ; pArtCIF = new hdsArticleCIF(R, T, &_masterBanned) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "S.2" ; T = "Memory Stats" ; pArtCIF = new hdsArticleCIF(R, T, &_masterMemstat) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "S.3" ; T = "Domain names" ; pArtCIF = new hdsArticleCIF(R, T, &_masterDomain) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "S.4" ; T = "Email addresses" ; pArtCIF = new hdsArticleCIF(R, T, &_masterEmaddr) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "S.5" ; T = "Strings (Fixed)" ; pArtCIF = new hdsArticleCIF(R, T, &_masterStrFix) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
// Add the resources and stats stuff
H = "AppResoures" ;
T = "Application Resources" ;
m_DataModel.AddHead(root, H, T, true) ;
R = "A.1" ; T = "Application Parameters" ; pArtCIF = new hdsArticleCIF(R, T, &_masterAppParam) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "A.2" ; T = "Config Files" ; pArtCIF = new hdsArticleCIF(R, T, &_masterCfgList) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "A.3" ; T = "Misc Fixed Files" ; pArtCIF = new hdsArticleCIF(R, T, &_masterFileList) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "A.4" ; T = "Pages" ; pArtCIF = new hdsArticleCIF(R, T, &_masterResList) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "A.5" ; T = "Article Groups" ; pArtCIF = new hdsArticleCIF(R, T, &_masterResList) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "A.6" ; T = "Site Visitors" ; pArtCIF = new hdsArticleCIF(R, T, &_masterVisList) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
R = "A.7" ; T = "Strings (Standard)" ; pArtCIF = new hdsArticleCIF(R, T, &_masterStrGen) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
//R = "A.8" ; T = "USL Assignments" ; pArtCIF = new hdsArticleCIF(R, T, &_masterUSL) ; m_DataModel.AddItem(H, R, T, pArtCIF, false) ;
// Add the Data Object Model stuff
H = "masterDOM" ;
T = "Data Object Model" ;
m_DataModel.AddHead(root, H, T, true) ;
// Any enums
//if (m_ADP.CountDataEnum()) { R = "enum" ; T = "Enums" ; pItem_E = m_DataModel.AddHead(H, R, T, true) ; }
//if (m_ADP.CountDataClass()) { R = "class" ; T = "Classes" ; pItem_C = m_DataModel.AddHead(H, R, T, true) ; }
//if (m_ADP.CountObjRepos()) { R = "repos" ; T = "Repositories" ; pItem_R = m_DataModel.AddHead(H, R, T, true) ; }
// Enums
if (m_ADP.CountDataEnum())
{
X = "enums" ;
T = "Enums" ;
m_DataModel.AddHead(H, X, T, true) ;
threadLog("%d enums\n", m_ADP.CountDataEnum()) ;
for (n = 0 ; n < m_ADP.CountDataEnum() ; n++)
{
pEnum = m_ADP.GetDataEnum(n) ;
if (pEnum)
{
sprintf(namBuf, "E.%d", n+1) ;
R = namBuf ;
T = pEnum->strType() ;
pArtCIF = new hdsArticleCIF(R, T, &_masterEnumEdit) ;
pArtCIF->m_flagVE |= VE_ACTIVE ;
m_DataModel.AddItem(X, R, T, pArtCIF, false) ;
}
}
}
// Classes
if (m_ADP.CountDataClass())
{
X = "class" ;
T = "Classes" ;
m_DataModel.AddHead(H, X, T, true) ;
threadLog("%d classes\n", m_ADP.CountDataClass()) ;
for (n = 0 ; n < m_ADP.CountDataClass() ; n++)
{
pClass = m_ADP.GetDataClass(n) ;
if (pClass)
{
sprintf(namBuf, "C.%d", pClass->ClassId()) ;
Y = namBuf ;
T = pClass->strType() ;
pArtCIF = new hdsArticleCIF(Y, T, &_masterClassEdit) ;
pArtCIF->m_flagVE |= VE_ACTIVE ;
m_DataModel.AddItem(X, Y, T, pArtCIF, false) ;
for (mbrNo = 0 ; mbrNo < pClass->MbrCount() ; mbrNo++)
{
pMbr = pClass->GetMember(mbrNo) ;
pType = pMbr->Datatype() ;
pSub = dynamic_cast<const hdbClass*>(pType) ;
if (pSub)
sprintf(namBuf, "C%d.S.%d",pClass->ClassId(), mbrNo) ;
else
sprintf(namBuf, "C%d.M.%d",pClass->ClassId(), mbrNo) ;
R = namBuf ;
T = pMbr->strName() ;
pArtCIF = new hdsArticleCIF(R, T, &_masterMbrEdit) ;
pArtCIF->m_flagVE |= VE_ACTIVE ;
m_DataModel.AddItem(Y, R, T, pArtCIF, false) ;
}
}
}
}
// Repositories
if (m_ADP.CountObjRepos())
{
X = "repos" ;
T = "Repositories" ;
m_DataModel.AddHead(H, X, T, true) ;
threadLog("%d repos\n", m_ADP.CountObjRepos()) ;
for (n = 0 ; n < m_ADP.CountObjRepos() ; n++)
{
pRepos = m_ADP.GetObjRepos(n) ;
if (pRepos)
{
sprintf(namBuf, "R.%d", n+1) ;
R = namBuf ;
T = pRepos->strName() ;
pArtCIF = new hdsArticleCIF(R, T, &_masterReposEdit) ;
pArtCIF->m_flagVE |= VE_ACTIVE ;
m_DataModel.AddItem(X, R, T, pArtCIF, false) ;
}
}
}
// CREATE PAGES and ARTICLES
threadLog("done\n") ;
}
/*
** Webmaster Display Functions
*/
hzEcode _masterLoginPage (hzHttpEvent* pE)
{
// Display the master account login form
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("hdsApp::_masterLoginPage") ;
hzChain C ; // Page output
hdsApp* pApp ; // Application
pApp = (hdsApp*) pE->m_pContextApp ;
C << s_master_head_nav ;
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n"
" <tr height=\"50\"><td align=\"center\" class=\"title\">Dissemino Master Account Login</td></tr>\n"
"</table>\n"
"<form method=\"POST\" action=\"master\">\n"
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
" <tr><td height=\"20\"> </td></tr>\n"
" <tr><td align=\"center\">" << pApp->m_Domain << "</td></tr>\n"
" <tr><td height=\"60\"> </td></tr>\n"
"</table>\n"
"<table width=\"66%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
" <tr height=\"25\"><td>Username: </td><td><input type=\"text\" name=\"username_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
" <tr height=\"25\"><td>Password: </td><td><input type=\"password\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"</table>\n"
"<table width=\"20%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
" <tr><td height=\"200\"> </td></tr>\n"
" <tr>\n"
" <td><input type=\"button\" onclick=\"location.href='/index.html';\" value=\"Abort\"/></td>\n"
" <td> </td>\n"
" <td align=\"right\"><input type=\"submit\" name=\"x-action\" value=\"Login\"></td>\n"
" </tr>\n"
"</table>\n"
"</form>\n"
"</body>\n"
"</html>\n" ;
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
hzEcode _masterProcAuth (hzHttpEvent* pE)
{
// Authenticate the master account login. If the supplied username and password is a match, display the master account main menu. If not redisplay the master account login
// page.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("hdsApp::_masterProcAuth") ;
hdsApp* pApp ; // Application
hdsInfo* pInfo ; // Session
hzAtom atom ; // For session value
hzString unam ; // Submitted username
hzString pass ; // Submitted password
hzString unamFld ; // Username field
hzString passFld ; // Password field
hzSysID newCookie ; // For cookie generation
hzIpaddr ipa ; // Client IP address
hzSDate expires ; // For cookie expiry
pApp = (hdsApp*) pE->m_pContextApp ;
unamFld = "username_master" ;
passFld = "password_master" ;
unam = pE->m_mapStrings[unamFld] ;
pass = pE->m_mapStrings[passFld] ;
threadLog("Trying username (%s) password (%s)\n", *unam, *pass) ;
threadLog("Trying username (%s) password (%s)\n", *pApp->m_MasterUser, *pApp->m_MasterPass) ;
if (unam == pApp->m_MasterUser && pass == pApp->m_MasterPass)
{
threadLog("MASTER LOGIN SUCCESS!!!\n") ;
pInfo = (hdsInfo*) pE->Session() ;
if (!pInfo)
{
newCookie = pApp->MakeCookie(pE->ClientIP(), pE->EventNo()) ;
expires.SysDate() ;
expires += 365 ;
pE->SetSessCookie(newCookie) ;
pInfo = new hdsInfo() ;
pE->SetSession(pInfo) ;
pApp->m_pLog->Out("%s: new cookie %016x new info %p\n", *_fn, newCookie, pInfo) ;
pApp->m_SessCookie.Insert(newCookie, pInfo) ;
}
pInfo->m_Access |= ACCESS_ADMIN ;
atom = pE->Referer() ;
pInfo->m_Sessvals.Insert(s_master_entry_pt, atom) ;
return _masterMainMenu(pE) ;
}
return _masterLoginPage(pE) ;
}
hzEcode _masterMainMenu (hzHttpEvent* pE)
{
// Display the master list of config files for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterMainMenu") ;
hzChain C ; // Page output
hdsApp* pApp ; // Application
//hdsArticle* pRoot ; // Tree item
//hdsArticle* pItem_E ; // Tree item "Enums"
hzString refname ; // Reference name of tree item
hzString title ; // Title of tree item
pApp = (hdsApp*) pE->m_pContextApp ;
C << s_master_head_nav ;
C << "\n<script language=\"javascript\">\n" ;
C << _dsmScript_tog ;
C << _dsmScript_loadArticle ;
C << _dsmScript_navtree ;
pApp->m_DataModel.ExportDataScript(C) ;
C << "</script>\n\n" ;
// Create HTML table for listing
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n"
" <tr height=\"44\"><td align=\"center\" class=\"title\">Webmaster Control Panel</td></tr>\n"
"</table>\n" ;
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n"
"<tr>\n"
" <td width=\"100%\">\n"
" <table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
" <tr>\n"
" <td width=\"20%\" valign=\"top\" class=\"main\">\n"
" <div id=\"navlhs\" class=\"navtree\">\n"
" <script type=\"text/javascript\">makeTree('master');</script>\n"
" </div>\n"
" </td>\n"
" <td width=\"80%\" valign=\"top\">\n"
" <table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
" <tr><td align=\"center\" class=\"title\"><div id=\"articletitle\" class=\"objtitle\"></div></td></tr>\n"
" <tr><td valign=\"top\" class=\"main\"><div id=\"articlecontent\" class=\"objpage\"></div></td></tr>\n"
" </table>\n"
" </td>\n"
" </tr>\n"
" </table>\n"
" </td>\n"
"</tr>\n"
"</table>\n" ;
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n"
" <tr height=\"44\"><td align=\"center\"><input type=\"button\" onclick=\"location.href='/masterLogout';\" value=\"Webmaster Account Exit\"/></td></tr>\n"
"</table>\n"
"</body>\n"
"</html>\n" ;
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
hzEcode _masterLogout (hzHttpEvent* pE)
{
// Log the user out from the master section. Then use a redirect to take user back to the 'master entry point' - the page they were on before entering the master section.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterLogout") ;
hdsApp* pApp ; // Application
hdsInfo* pInfo ; // Session
hzAtom atom ; // For session value
pApp = (hdsApp*) pE->m_pContextApp ;
pInfo = (hdsInfo*) pE->Session() ;
atom = pInfo->m_Sessvals[s_master_entry_pt] ;
pApp->m_SessCookie.Delete(pE->Cookie()) ;
delete pInfo ;
pE->SetSession(0) ;
return pE->Redirect(atom.Str(), 0, false) ;
}
/*
** C-Interface Article Functions
*/
hzEcode _masterAppParam (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the application parameters
_hzfunc(__func__) ;
hdsApp* pApp ; // Application
// Set the article title
pE->SetHdr(s_articleTitle, pArtCIF->m_Title) ;
// Set the article content
pApp = (hdsApp*) pE->m_pContextApp ;
C.Clear() ;
C << "<table>\n" ;
C.Printf("<tr><td>Name:</td> <td>%s</td><tr>\n", *pApp->m_Appname) ;
C.Printf("<tr><td>Docroot:</td> <td>%s</td><tr>\n", *pApp->m_Docroot) ;
C.Printf("<tr><td>Configs:</td> <td>%s</td><tr>\n", *pApp->m_Configdir) ;
C.Printf("<tr><td>Datadir:</td> <td>%s</td><tr>\n", *pApp->m_Datadir) ;
C.Printf("<tr><td>Logroot:</td> <td>%s</td><tr>\n", *pApp->m_Logroot) ;
C.Printf("<tr><td>Masterpath:</td> <td>%s</td><tr>\n", *pApp->m_MasterPath) ;
C.Printf("<tr><td>Masteruser:</td> <td>%s</td><tr>\n", *pApp->m_MasterUser) ;
C.Printf("<tr><td>Masterpass:</td> <td>%s</td><tr>\n", *pApp->m_MasterPass) ;
C.Printf("<tr><td>SmtpAddr:</td> <td>%s</td><tr>\n", *pApp->m_SmtpAddr) ;
C.Printf("<tr><td>SmtpUser:</td> <td>%s</td><tr>\n", *pApp->m_SmtpUser) ;
C.Printf("<tr><td>SmtpPass:</td> <td>%s</td><tr>\n", *pApp->m_SmtpPass) ;
C.Printf("<tr><td>UsernameFld:</td> <td>%s</td><tr>\n", *pApp->m_UsernameFld) ;
C.Printf("<tr><td>UserpassFld:</td> <td>%s</td><tr>\n", *pApp->m_UserpassFld) ;
C.Printf("<tr><td>Domain:</td> <td>%s</td><tr>\n", *pApp->m_Domain) ;
C.Printf("<tr><td>Loghits:</td> <td>%s</td><tr>\n", *pApp->m_AllHits) ;
C.Printf("<tr><td>Language:</td> <td>%s</td><tr>\n", *pApp->m_DefaultLang) ;
C.Printf("<tr><td>Login:</td> <td>%s</td><tr>\n", pApp->m_OpFlags & DS_APP_SUBSCRIBERS ? "true":"false") ;
C.Printf("<tr><td>Robot:</td> <td>%s</td><tr>\n", pApp->m_OpFlags & DS_APP_ROBOT ? "true":"false") ;
C.Printf("<tr><td>SiteGuide:</td> <td>%s</td><tr>\n", pApp->m_OpFlags & DS_APP_GUIDE ? "true":"false") ;
C.Printf("<tr><td>PortSTD:</td> <td>%d</td><tr>\n", pApp->m_nPortSTD) ;
C.Printf("<tr><td>PortSSL:</td> <td>%d</td><tr>\n", pApp->m_nPortSSL) ;
C << "</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterCfgList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master account list of config files for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("hdsApp::_masterCfgList") ;
hdsApp* pApp ; // Application
hzChain Z ; // XML Content of key resource (page/navbar/stylesheet etc)
hzDirent de ; // Config file info
hzXDate date ; // File date
hzString title ; // Article Title
uint32_t n ; // Loop iterator
hzEcode rc ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
// Set the article title
C.Clear() ;
C << "Config File Listing (" << FormalNumber(pApp->m_Configs.Count()) << " items)" ;
title = C ;
pE->SetHdr(s_articleTitle, title) ;
// Set the article content
C.Clear() ;
C <<
"<table width=\"100%\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"main\">\n"
"<tr>\n"
" <th>Last Modified</th>\n"
" <th>Size</th>\n"
" <th>Config File Name</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = 0 ; n < pApp->m_Configs.Count() ; n++)
{
/* FIX
de = pApp->m_Configs.GetObj(n) ;
date.SetByEpoch(de.Mtime()) ;
C.Printf("<tr><td>%s</td><td>%s</td><td><a href=\"/masterAction?CfgEdit=%d\">%s</a></td></tr>\n", *date, FormalNumber(de.Size()), n, de.txtName()) ;
*/
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterResList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master's list of resources for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterResList") ;
hdsApp* pApp ; // Application
hdsResource* pRes ; // Resource pointer
hzString title ; // Article title
uint32_t n ; // Loop iterator
hzEcode rc ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
// Set the article title
C.Clear() ;
C << "Resource Listing (" << FormalNumber(pApp->m_ResourcesPath.Count()) << " items)" ;
title = C ;
pE->SetHdr(s_articleTitle, title) ;
// Set the article content
C.Clear() ;
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<tr>\n"
" <th>Type</th>\n"
" <th>Title</th>\n"
" <th>URL</th>\n"
" <th>Hits</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = 0 ; n < pApp->m_ResourcesPath.Count() ; n++)
{
pRes = pApp->m_ResourcesPath.GetObj(n) ;
C << "<tr><td width=\"100\">" ;
switch (pRes->Whatami())
{
case DS_RES_PAGE: C << "PAGE</td>" ; break ;
case DS_RES_ARTICLE: C << "ARTICLE</td>" ; break ;
case DS_RES_FILE: C << "FILE</td>" ; break ;
case DS_RES_PAGE_CIF: C << "PAGE_CIF</td>" ; break ;
}
// If the resource is a page, give link to page editor
if (pRes->Whatami() == DS_RES_PAGE)
C.Printf("<td width=\"240\"><a href='#' onclick=\"loadArticle('/masterAction?editfile=%s');\">%s</a></td><td width=\"320\">%s</td>",
*pRes->m_Url, *pRes->m_Title, *pRes->m_Url) ;
else
C.Printf("<td width=\"240\">%s</td><td width=\"320\">%s</td>", *pRes->m_Title, *pRes->m_Url) ;
C.Printf("<td align=\"right\" width=\"140\">%s</td></tr>\n", FormalNumber(pRes->m_HitCount)) ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterDomain (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master's list of resources for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterDomain") ;
const char* i ; // String value
hzString S ; // Temp string
uint32_t n ; // Loop iterator
// Set the article title
C.Clear() ;
C << "Known Domains (" << FormalNumber(_hzGlobal_setDomains.Count()) << " items)" ;
S = C ;
pE->SetHdr(s_articleTitle, S) ;
// Set the article content
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th>String Number</th>\n"
" <th>String Value</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = 1 ; n <= _hzGlobal_setDomains.Count() ; n++)
{
S = FormalNumber(n) ;
i = _hzGlobal_setDomains.GetObj(n) ;
if (i)
C.Printf("\t<tr><td align=\"right\">%s</td><td>%s</td></tr>\n", *S, i) ;
else
C.Printf("\t<tr><td align=\"right\">%s</td><td>NULL</td></tr>\n", *S) ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterEmaddr (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master's list of resources for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterEmaddr") ;
hzString S ; // Temp string
hzEmaddr ema ; // Email address
uint32_t n ; // Loop iterator
// Set the article title
C.Clear() ;
C << "Known Email Addresses (" << FormalNumber(_hzGlobal_setEmaddrs.Count()) << " items)" ;
S = C ;
pE->SetHdr(s_articleTitle, S) ;
// Set the article content
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th>String Number</th>\n"
" <th>String Value</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = 1 ; n <= _hzGlobal_setEmaddrs.Count() ; n++)
{
S = FormalNumber(n) ;
ema = _hzGlobal_setEmaddrs.GetObj(n - 1) ;
if (ema)
C.Printf("\t<tr><td align=\"right\">%s</td><td>%s</td></tr>\n", *S, *ema) ;
else
C.Printf("\t<tr><td align=\"right\">%s</td><td>NULL</td></tr>\n", *S) ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterStrFix (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master's list of resources for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterStrList") ;
const char* i ; // String value
hzString S ; // Temp string
uint32_t n ; // Loop iterator
// Set the article title
C.Clear() ;
C << "Fixed String List (" << FormalNumber(_hzGlobal_setStrings.Count()) << " items)" ;
S = C ;
pE->SetHdr(s_articleTitle, S) ;
// Set the article content
C.Clear() ;
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th>String Number</th>\n"
" <th>String Value</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = 1 ; n <= _hzGlobal_setStrings.Count() ; n++)
{
S = FormalNumber(n) ;
i = _hzGlobal_setStrings.GetObj(n) ;
if (i)
C.Printf("\t<tr><td>%s</td><td>%s</td></tr>\n", *S, i) ;
else
C.Printf("\t<tr><td>%s</td><td>NULL</td></tr>\n", *S) ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterStrGen (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the current set of hzString instances.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterStrGen") ;
hzString title ; // Article title
// Set the article title
title = "Dynamic String Allocations" ;
pE->SetHdr(s_articleTitle, title) ;
// Set the article content
C.Clear() ;
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th>Size</th>\n"
" <th>Population</th>\n"
" <th>Free</th>\n"
" <th>Memory Used</th></tr>\n"
"</thead>\n"
"<tbody>\n" ;
ReportStringAllocations(C, true) ;
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterVisList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master's list of resources for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterVisList") ;
hdsApp* pApp ; // Application
hdsProfile* pProf ; // Visitor profile pointer
hzString title ; // Article title
uint32_t n ; // Loop iterator
hzEcode rc ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
// Set the article title
C.Clear() ;
C << "Dissemino Hit List (" << FormalNumber(pApp->m_Visitors.Count()) << " visitors)" ;
title = C ;
pE->SetHdr(s_articleTitle, title) ;
// Set the article content
C.Clear() ;
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th>IP addr</th>\n"
" <th>Locn</th>\n"
" <th>Robot</th>\n"
" <th>Favicon</th>\n"
" <th>Articles</th>\n"
" <th>Pages</th>\n"
" <th>Scripts</th>\n"
" <th>Images</th>\n"
" <th>Special</th>\n"
" <th>Fixed</th>\n"
" <th>Posts</th>\n"
" <th>Fail-G</th>\n"
" <th>Fail-P</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = 0 ; n < pApp->m_Visitors.Count() ; n++)
{
pProf = pApp->m_Visitors.GetObj(n) ;
C << "<tr align=\"right\">" ;
C.Printf("<td align=\"left\">%s</td>", pProf->m_addr.Full()) ;
C.Printf("<td align=\"left\">%s</td>", GetIpLocation(pProf->m_addr)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_robot)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_favicon)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_art)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_page)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_scr)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_img)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_spec)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_fix)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_post)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_G404)) ;
C.Printf("<td>%s</td>", FormalNumber(pProf->m_P404)) ;
C << "</tr>\n" ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterBanned (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display IP blacklist and number of attempts by each banned IP
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterBanned") ;
hzMapM<uint16_t,hzIpaddr> mapTmp ; // Temp map, in order of number of attempts
hzIpinfo ipi ; // IP address block note
hzIpaddr ipa ; // Blacklisted IP
hzString title ; // Article title
uint32_t n ; // Loop iterator
uint32_t nAtt ; // Number of attempts
hzEcode rc ; // Return code
// Re-order blacklist by number of attempts
for (n = 0 ; n < _hzGlobal_StatusIP.Count() ; n++)
{
ipa = _hzGlobal_StatusIP.GetKey(n) ;
ipi = _hzGlobal_StatusIP.GetObj(n) ;
mapTmp.Insert(ipi.m_nSince, ipa) ;
}
// Set the article title
C.Clear() ;
C << "Blacklisted IP Addresses (" << FormalNumber(mapTmp.Count()) << " items)" ;
title = C ;
pE->SetHdr(s_articleTitle, title) ;
// Set the article content
C.Clear() ;
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th>IP Address</th>\n"
" <th>No Attempts</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = mapTmp.Count()-1 ; n ; n--)
{
nAtt = mapTmp.GetKey(n) ;
ipa = mapTmp.GetObj(n) ;
C.Printf("<tr><td>%s</td><td align=\"right\">%s</td></tr>\n", ipa.Full(), FormalNumber(nAtt)) ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterMemstat (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
_hzfunc("_masterMemstat") ;
// Set the article title
pE->SetHdr(s_articleTitle, pArtCIF->m_Title) ;
// Set the article content
C.Clear() ;
ReportMemoryUsage(C, true) ;
//C <<
//"<center><td align=\"center\"><input type=\"button\" onclick=\"location.href='/masterMainMenu';\" value=\"Main Menu\"/></center>\n"
//"</body>\n"
//"</html>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
#if 0
hzEcode _masterUSL (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master's list of resources for the current website. These may be selected for editing.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterVisList") ;
hdsApp* pApp ; // Application
hdsUSL usl ; // USL
hzString str ; // String value
uint32_t n ; // Loop iterator
hzEcode rc ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
// Set the article title
C.Clear() ;
C << "USL Assignements (" << FormalNumber(pApp->m_pDfltLang->m_MiscStrings.Count()) << " items)" ;
str = C ;
pE->SetHdr(s_articleTitle, str) ;
// Create HTML table for listing
C.Clear() ;
C <<
"<table id=\"theTable\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th>Order</th>\n"
" <th>USL</th>\n"
" <th>String Value</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n" ;
for (n = 0 ; n < pApp->m_pDfltLang->m_MiscStrings.Count() ; n++)
{
//usl = pApp->m_pDfltLang->m_MiscStrings.GetKey(n) ;
str = pApp->m_pDfltLang->m_MiscStrings.GetObj(n) ;
if (str)
//C.Printf("\t<tr><td align=\"right\">%u</td><td>%s</td><td>%s</td></tr>\n", n, *usl, *str) ;
C.Printf("\t<tr><td align=\"right\">%u</td><td>%u</td><td>%s</td></tr>\n", n, n+1, *str) ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
#endif
hzEcode _masterFileList (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// Display the master's list files for the current website that may be selected for editing. These must not be data files (viewable under a separate
// master menu item) and nor must the be config files (editable under a separate master menu item), but they can be text files for any other purpose.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterFileList") ;
hdsApp* pApp ; // Application
hzChain Z ; // XML Content of key resource (page/navbar/stylesheet etc)
hzDirent de ; // Directory entry
hzString title ; // Article title
hzXDate date ; // File date (Mtime)
uint32_t n ; // Loop iterator
hzEcode rc ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
// Set the article title
C.Clear() ;
C.Printf("Misc Files (%d items)", pApp->m_Misc.Count()) ;
title = C ;
pE->SetHdr(s_articleTitle, title) ;
// Set the article content
C.Clear() ;
C <<
"<table align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"fixVP\">\n"
"<thead>\n"
"<tr>\n"
" <th width=180>Date</th>\n"
" <th width=150>Size</th>\n"
" <th width=350>Dir</th>\n"
" <th width=350>Filename</th>\n"
"</tr>\n"
"<thead>\n"
"<tbody>\n" ;
for (n = 0 ; n < pApp->m_Misc.Count() ; n++)
{
de = pApp->m_Misc.GetObj(n) ;
date.SetByEpoch(de.Mtime()) ;
C.Printf("<tr><td width=180>%s</td><td width=150>%s</td><td width=350>%s</td><td width=350><a href=\"/masterFileEdit-%d\">%s</a></td></tr>\n",
*date, FormalNumber(de.Size()), *de.Path(), n, de.txtName()) ;
}
C << "</tbody>\n</table>\n" ;
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
hzEcode _masterFileEdit (hzHttpEvent* pE)
{
// Display the master's edit resource page. This essentially comprises a large text box and a submit button. The text box is populated with the XML
// for the resource if it exists. Note that the argument is numeric and identifies the object (directory entry) in the m_Misc map.
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("_masterFileEdit") ;
ifstream is ; // For reading file in
hzChain C ; // Page output
hzChain Z ; // File content
hzMD5 md5 ; // MD5 for the old content
hzDirent de ; // Directory entry
hdsApp* pApp ; // Application
const char* pArg ; // File identifier
hzString fpath ; // File path of original
hzString fnew ; // File path plus .new
uint32_t posn ; // Posn of file in m_Misc
hzEcode rc ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
pArg = pE->GetResource() ;
pArg += 16 ;
if (pArg[0] && IsPosint(posn, pArg))
{
de = pApp->m_Misc.GetObj(posn) ;
fpath = de.Path() + "/" + de.strName() ;
fnew = fpath + ".new" ;
rc = TestFile(*fnew) ;
if (rc == E_OK)
fpath = fnew ;
is.open(*fpath) ;
if (is.fail())
Z << "Error: Cannot Open File" << fpath ;
else
{
Z << is ;
is.close() ;
}
}
// Set the article title
C.Clear() ;
if (!de.txtName())
fpath = "Dissemino Misc Files Editor: Untitled" ;
else
{
C.Printf("Dissemino Misc Files Editor: %s", *fnew) ;
fpath = C ;
}
fpath = C ;
pE->SetHdr(s_articleTitle, fpath) ;
// Set the article content
C << "<form method=\"POST\" action=\"masterFileEditHdl\">\n" ;
if (fnew)
C.Printf("<input type=\"hidden\" name=\"fname\" value=\"%s\"/>\n", *fnew) ;
else
C.Printf("Filename: <input type=\"text\" name=\"fname\"/>\n") ;
C <<
"<table width=\"96%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
"\t<td>\n"
"\t<textarea name=\"pgData\" rows=\"40\" cols=\"200\" class=\"main\">" ;
if (Z.Size())
C << Z ;
C << "</textarea>\n" ;
C <<
"\t</td>\n"
"</tr>\n"
"</table>\n"
"<table width=\"20%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
"<td align=\"left\"><input type=\"button\" onclick=\"location.href='/masterFileList';\" value=\"Abort Edit\"/></td>\n"
"<td align=\"rigth\"><input type=\"submit\" name=\"x-action\" value=\"Submit\"></td>\n"
"</tr>\n"
"</table>\n"
"</form>\n"
"</body>\n"
"</html>\n" ;
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
hzEcode _masterFileEditHdl (hzHttpEvent* pE)
{
// This just saves the file
ofstream os ; // Output file
hzChain C ; // Page output
hzChain Z ; // File content
hzString val ; // The submitted textarea
hzString S ; // Temp value
hzString fnew ; // File path plus .new
hzEcode rc ; // Return code
_hzfunc("_masterFileEditHdl") ;
// Get file name
S = "fname" ;
fnew = pE->m_mapStrings[S] ;
// Get new file data
S = "pgData" ;
val = pE->m_mapStrings[S] ;
Z = val ;
// Write data to file.new
fnew += ".new" ;
os.open(*fnew) ;
if (os.fail())
threadLog("Open file failed (%s)\n", *fnew) ;
else
{
os << Z ;
os.close() ;
}
// CHECK THIS
C << "<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n" ;
if (!fnew)
C << "\t<tr height=\"50\"><td align=\"center\" class=\"title\">Dissemino Misc Files Editor: Untitled</td></tr>\n" ;
else
C.Printf("\t<tr height=\"50\"><td align=\"center\" class=\"title\">Dissemino Misc Files Editor: %s</td></tr>\n", *fnew) ;
C << "</table>\n" ;
C << "<form method=\"POST\" action=\"masterFileEditHdl\">\n" ;
if (fnew)
C.Printf("<input type=\"hidden\" name=\"fname\" value=\"%s\"/>\n", *fnew) ;
else
C.Printf("Filename: <input type=\"text\" name=\"fname\"/>\n") ;
C <<
"<table width=\"96%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
"\t<td>\n"
"\t<textarea name=\"pgData\" rows=\"40\" cols=\"200\" class=\"main\">" ;
if (Z.Size())
C << Z ;
C << "</textarea>\n" ;
C <<
"\t</td>\n"
"</tr>\n"
"</table>\n"
"<table width=\"20%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
"<td align=\"left\"><input type=\"button\" onclick=\"location.href='/masterFileList';\" value=\"Back to files\"/></td>\n"
"<td align=\"rigth\"><input type=\"submit\" name=\"x-action\" value=\"Commit changes\"></td>\n"
"</tr>\n"
"</table>\n"
"</form>\n"
"</body>\n"
"</html>\n" ;
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
hzEcode _masterFldSpecs (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
hzEcode _masterEnumEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
_hzfunc(__func__) ;
const hdbEnum* pEnum = 0 ; // Data Enum
hdsApp* pApp ; // Application
hdsInfo* pInfo ; // Session
const char* pRes ; // Requested resource
const char* i ; // Requested resource iterator
hzString S ; // Temp string
//hzString entName ; // Name of enum/class/member/repos
uint32_t numId ; // Numeric id
uint32_t n ; // Loop iterator
// Enum is obtained by decoding the resoure query component
pInfo = (hdsInfo*) pE->Session() ;
if (!pInfo)
{
threadLog("Forbiden\n") ;
pE->SendAjaxResult(HTTPMSG_FORBIDDEN, "No Access") ;
return E_OK ;
}
pApp = (hdsApp*) pE->m_pContextApp ;
pRes = pE->GetResource() ;
pApp->m_pLog->Out("%s: Called with res = [%s] cif = [%s]\n", *_fn, pRes, *pArtCIF->m_Title) ;
// Locate Enum
i = *pArtCIF->m_Title ;
if (IsPosint(numId, i + 2))
pEnum = pApp->m_ADP.GetDataEnum(numId-1) ;
// if (pEnum)
// entName = pEnum->txtType() ;
// Set the article title
pE->SetHdr(s_articleTitle, pArtCIF->m_Title) ;
// Set the article content
C.Clear() ;
if (!pEnum)
C << "<p>No Enum found</p>\n" ;
else
{
C <<
"<table width=\"100%\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
" <th>Name</th>\n"
" <th>Value</th>\n"
"</tr>\n" ;
for (n = 0 ; n < pEnum->Count() ; n++)
{
S = pEnum->GetStr(n) ;
C.Printf("<tr><td>%d</td><td>%s</td></tr>\n", n+1, *S) ;
}
C << "</table>\n" ;
}
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterClassEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
_hzfunc(__func__) ;
const hdbClass* pClass = 0 ; // Class
const hdbMember* pMbr = 0 ; // Class member
hdsApp* pApp ; // Application
hdsInfo* pInfo ; // Session
const char* i ; // Requested class
hzString title ; // Name of class
uint32_t mbrNo ; // Member number
uint32_t numId ; // Numeric id
//uint32_t n ; // Loop iterator
pInfo = (hdsInfo*) pE->Session() ;
if (!pInfo)
{
threadLog("Forbiden\n") ;
pE->SendAjaxResult(HTTPMSG_FORBIDDEN, "No Access") ;
return E_OK ;
}
pApp = (hdsApp*) pE->m_pContextApp ;
// Obtain the class in question
i = *pArtCIF->m_Title ;
if (IsPosint(numId, i + 2))
pClass = pApp->m_ADP.GetDataClass(numId) ;
// Set the article title
C.Clear() ;
if (pClass)
C << "Editing Data Class " << pClass->txtType() ;
else
C << "Create New Data Class" ;
title = C ;
pE->SetHdr(s_articleTitle, title) ;
// Set the article content
if (pClass)
{
C.Clear() ;
C <<
"<table width=\"100%\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
" <th>Posn</th>\n"
" <th>Name</th>\n"
" <th>Data type</th>\n"
" <th>Pop Control</th>\n"
" <th>Description</th>\n"
"</tr>\n" ;
for (mbrNo = 0 ; mbrNo < pClass->MbrCount() ; mbrNo++)
{
pMbr = pClass->GetMember(mbrNo) ;
C << "<tr>" ;
C.Printf("<td align=\"right\">%d</td>", mbrNo) ;
C.Printf("<td><a href=\"#\" onclick=\"loadArticle('/master_dme-M.%d.%d');\">%s</a></td>", pClass->ClassId(), mbrNo, pMbr->txtName()) ;
C.Printf("<td>%s</td>", pMbr->Datatype()->txtType()) ;
C.Printf("<td>%s</td>", PopCtl2Txt(pMbr->PopCtl())) ;
C.Printf("<td>%s</td>", pMbr->txtDesc()) ;
C << "</tr>" ;
}
C << "</table>\n" ;
}
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterMbrEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
_hzfunc(__func__) ;
const hdbClass* pClass = 0 ; // Class
const hdbMember* pMbr = 0 ; // Class member
// Set the article title
pE->SetHdr(s_articleTitle, pArtCIF->m_Title) ;
// Set the article content
C.Clear() ;
if (pMbr)
C.Printf("<tr><td align=\"center\">%s::%s</td></tr>\n", pClass->txtType(), pMbr->txtName()) ;
else
C << "<tr><td align=\"center\">Class Member Editor</td></tr>\n" ;
C <<
"<tr><td height=\"60\"> </td></tr>\n"
"</table>\n"
"<table width=\"66%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n" ;
C <<
"<tr height=\"25\"><td>Name: </td><td><input type=\"text\" name=\"username_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Type: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Min Value: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Max Value: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Compusory: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Multiple: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterReposEdit (hzChain& C, hdsArticleCIF* pArtCIF, hzHttpEvent* pE)
{
// MUST DO THIS!
_hzfunc(__func__) ;
// Set the article title
pE->SetHdr(s_articleTitle, pArtCIF->m_Title) ;
// Set the article content
//const hdbObjRepos* pRepos = 0 ; // Repository
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
void hdsApp::MasterArticle (hzHttpEvent* pE)
{
// Serve an master article. These are articles in that a partial page is served by AJAX but they are an in-built feature of Dissemino rather than defined as
// a part of the application configs. At present the only example of AJAX in the master section is the Data Model Editing regime. Here, there is a host page
// and a navigation tree listing all data enums, classes and class members, and repositories in the current application data model. An article containing a
// form exists for each of the following:-
//
// 1) Addition of a new enum or displaying/editing an existing enum. The enum values are listed in a table with an blank row and an add button for adding
// new values. The values have a checkbox for setting them active/inactive and there is a checkbox for setting the enum as a whole to active/inactive.
// The URL of the blank article/form for adding a new enum is /master_dme_enum with no further arguments. This will be extended by -enum_name for an
// existing enum.
//
// 2) Addition of a new class or displaying/editing an existing class. The class members are listed in a table showing the data type and other parameters.
// The table cannot be edited in-situ. The class members, which can themselves be classes, are edited by clicking on the member name. The URL of the
// blank article/form for adding a new class is /master_dme_class and for an existing class this will be extended by -N where N is the class number.
//
// 3) Addition of a new class member or the editing of an existing one. This included the ability to set the member ative/inactive. The URL of the blank
// is /master_dme_mbr and for an existing member this will be extended by -N where N is the member number. Note it is not necessary to have a class id and
// a member id.
//
// 4) Addition of a new respository or the editing of an existing one. This must name a single host class.
_hzfunc("hdsApp::MasterArticle") ;
const hdbEnum* pEnum = 0 ; // Data Enum
const hdbClass* pClass = 0 ; // Class
const hdbMember* pMbr = 0 ; // Class member
const hdbObjRepos* pRepos = 0 ; // Repository
hzChain Z ; // For building partial HTML output
hdsInfo* pInfo ; // Session
const char* pRes ; // Requested resource
const char* i ; // Requested resource iterator
hzString entName ; // Name of enum/class/member/repos
hzString argA ; // 1st argument (e.g. lang subdir or article group name)
hzString argB ; // 2nd argument (e.g. article name)
hzString S ; // Temp string
uint32_t numId ; // Numeric id
uint32_t mbrNo ; // Member number
uint32_t n ; // Loop iterator
pInfo = (hdsInfo*) pE->Session() ;
// No HTTP session?
if (!pInfo)
{
threadLog("Forbiden\n") ;
pE->SendAjaxResult(HTTPMSG_FORBIDDEN, "No Access") ;
return ;
}
pRes = pE->GetResource() ;
if (memcmp(pRes, "/masterAction", 13))
{
// Not a web-master option so illegal
threadLog("No such path\n") ;
pE->SendAjaxResult(HTTPMSG_NOTFOUND, "No such path") ;
return ;
}
if (!pE->QueryLen())
{
threadLog("Called with no arguments\n") ;
pE->SendAjaxResult(HTTPMSG_NOTFOUND, "No such path") ;
return ;
}
argA = pE->m_mapStrings.GetKey(0) ;
argB = pE->m_mapStrings.GetObj(0) ;
if (argA == "editfile")
{
_masterCfgEdit(pE, argB) ;
return ;
}
// This may be a webmaster command unrelated to the data object model
// if (!memcmp(pRes + 8, "A.0", 4)) { _masterCfgList(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.1", 4)) { _masterResList(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.2", 4)) { _masterVisList(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.3", 4)) { _masterDomain(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.4", 4)) { _masterEmaddr(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.5", 4)) { _masterStrFix(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.6", 4)) { _masterStrGen(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.7", 4)) { _masterBanned(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.8", 4)) { _masterMemstat(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.9", 4)) { _masterUSL(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.10", 5)) { _masterFileList(pE) ; return ; }
// if (!memcmp(pRes + 8, "A.11", 5)) { _masterFileEdit(pE) ; return ; }
// URL not of the form /master_dme- ?
if (memcmp(pRes, "/master_dme-", 12))
{
threadLog("No such path\n") ;
pE->SendAjaxResult(HTTPMSG_NOTFOUND, "No such path") ;
return ;
}
// Invalid URL?
if (pRes[12] != 'E' && pRes[12] != 'C' && pRes[12] != 'M' && pRes[12] != 'R')
{
threadLog("No such path\n") ;
pE->SendAjaxResult(HTTPMSG_NOTFOUND, "No such path") ;
return ;
}
// DERIVE ENTITY. A is general article (not related to Data Object Model), E is enum, C is class, M is class member, R is repository.
if (pRes[13] == CHAR_PERIOD)
{
switch (pRes[12])
{
case 'E': if (IsPosint(numId, pRes + 14))
//pEnum = m_ADP.mapEnums.GetObj(numId) ;
pEnum = m_ADP.GetDataEnum(numId) ;
if (pEnum)
entName = pEnum->txtType() ;
break ;
case 'C': if (IsPosint(numId, pRes + 14))
{
for (n = 0 ; n < m_ADP.CountDataClass() ; n++)
{
pClass = m_ADP.GetDataClass(n) ;
if (pClass->ClassId() == numId)
{
entName = pClass->txtType() ;
break ;
}
}
if (!entName)
pClass = 0 ;
}
case 'M': if (IsPosint(numId, pRes + 14))
{
for (n = 0 ; n < m_ADP.CountDataClass() ; n++)
{
pClass = m_ADP.GetDataClass(n) ;
if (pClass->ClassId() == numId)
{
entName = pClass->txtType() ;
break ;
}
}
if (!entName)
pClass = 0 ;
//pClass = m_ADP.mapClasses.GetObj(numId-1) ;
if (pClass)
{
for (i = pRes + 14 ; *i && *i != CHAR_PERIOD ; i++) ;
if (*i == CHAR_PERIOD)
{
if (IsPosint(numId, i+1))
pMbr = pClass->GetMember(numId) ;
}
}
}
if (pMbr)
{ entName = pClass->txtType() ; entName += "::" ; entName += pMbr->strName() ; }
case 'R': if (IsPosint(numId, pRes + 14))
pRepos = m_ADP.GetObjRepos(numId) ;
if (pRepos)
entName = pRepos->strName() ;
}
}
// CREATE HTML
Z.Printf("<form method=\"POST\" action=\"%s\">\n", pRes) ;
Z << "<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n" ;
// Deal with non-data model requests
switch (pRes[9])
{
case 'E':
Z <<
"<tr><td align=\"center\">Enum Editor</td></tr>\n"
"<tr><td height=\"20\"> </td></tr>\n"
"</table>\n"
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n" ;
Z.Printf("<tr height=\"25\"><td>Name: </td><td><input type=\"text\" name=\"username_master\" size=\"40\" maxlen=\"40\" value=\"%s\"/></td></tr>\n", *entName) ;
Z <<
"</table>\n"
"<table width=\"100%\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n" ;
for (n = 0 ; n < pEnum->Count() ; n++)
{
S = pEnum->GetStr(n) ;
Z.Printf("<tr><td>%d</td><td>%s</td></tr>\n", n+1, *S) ;
}
break ;
case 'C':
Z <<
"<tr><td align=\"center\">Class Editor</td></tr>\n"
"<tr><td height=\"20\"> </td></tr>\n"
"</table>\n"
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n" ;
Z.Printf("<tr height=\"25\"><td>Name: </td><td><input type=\"text\" name=\"username_master\" size=\"40\" maxlen=\"40\" value=\"%s\"/></td></tr>\n", *entName) ;
Z <<
"</table>\n"
"<table width=\"100%\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
" <th>Posn</th>\n"
" <th>Name</th>\n"
" <th>Data type</th>\n"
" <th>MinP</th>\n"
" <th>MaxP</th>\n"
" <th>Description</th>\n"
"</tr>\n" ;
for (mbrNo = 0 ; mbrNo < pClass->MbrCount() ; mbrNo++)
{
pMbr = pClass->GetMember(mbrNo) ;
Z << "<tr>" ;
Z.Printf("<td align=\"right\">%d</td>", mbrNo) ;
Z.Printf("<td><a href=\"#\" onclick=\"loadArticle('/master_dme-M.%d.%d');\">%s</a></td>", pClass->ClassId(), mbrNo, pMbr->txtName()) ;
Z.Printf("<td>%s</td>", pMbr->Datatype()->txtType()) ;
Z.Printf("<td>%s</td>", PopCtl2Txt(pMbr->PopCtl())) ;
Z.Printf("<td>%s</td>", pMbr->txtDesc()) ;
Z << "</tr>" ;
}
break ;
case 'M':
if (pMbr)
Z.Printf("<tr><td align=\"center\">%s::%s</td></tr>\n", pClass->txtType(), pMbr->txtName()) ;
else
Z << "<tr><td align=\"center\">Class Member Editor</td></tr>\n" ;
Z <<
"<tr><td height=\"60\"> </td></tr>\n"
"</table>\n"
"<table width=\"66%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n" ;
Z <<
"<tr height=\"25\"><td>Name: </td><td><input type=\"text\" name=\"username_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Type: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Min Value: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Max Value: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Compusory: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n"
"<tr height=\"25\"><td>Multiple: </td><td><input type=\"select\" name=\"password_master\" size=\"40\" maxlen=\"40\"/></td></tr>\n" ;
break ;
case 'R': if (pRes[10] == CHAR_PERIOD)
{
if (IsPosint(numId, pRes + 11))
pRepos = m_ADP.GetObjRepos(numId) ;
}
break ;
}
Z <<
"</table>\n"
"</form>\n" ;
// Send result
if (entName)
pE->SetHdr("x-title", entName) ;
else
pE->SetHdr("x-title", pRes) ;
pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, Z, 0, false) ;
}
#if 0
hzEcode _masterDataModel (hzHttpEvent* pE)
{
// Display the currently applicable data model as a tree of classes, class members and repositories.
//
// The display comprises a tree on the LHS and a form on the RHS. The root node is automatically named after the application and is displayed as open. This
// will have a visible subnode of 'Classes' and if any classes have been defined, another of "Repositories". These will display the '+' expansion symbol if
// there are clases defined and/or repositories declared. Clinking on the subnode name will produce on the RHS, a blank form to create a new class or add a
// repostory.
//
// Under 'Classes' the tree uses the folder symbol to represent classes and the document symbol to represent class members. The class entries link to a form which
// Under "Repositories" the folder
//
// Argument: pE The HTTP event
//
// Returns: None
_hzfunc("hdsApp::_masterDataModel") ;
hdsNavtree T ; // Temp tree for object model display
hzChain Z ; // XML Content of key resource (page/navbar/stylesheet etc)
hzChain C ; // Page output
hzDirent de ; // Config file info
hdsApp* pApp ; // Application
hzXDate date ; // File date
hzString editorCls ; // Class editor base URL
hzString editorMbr ; // Class member editor base URL
hzString S ; // Temp string
hzEcode rc ; // Return code
// BUILD HTML
pApp = (hdsApp*) pE->m_pContextApp ;
C << s_master_head_std ;
C << "\n<script language=\"javascript\">\n" ;
C << _dsmScript_tog ;
C << _dsmScript_loadArticle ;
C << _dsmScript_navtree ;
pApp->m_DataModel.ExportDataScript(C) ;
C << "</script>\n\n" ;
// Create HTML table for listing
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n"
" <tr height=\"50\"><td align=\"center\" class=\"title\">Object Model Editor</td></tr>\n"
"</table>\n" ;
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
"<tr>\n"
" <td width=\"100%\">\n"
" <table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
" <tr>\n"
" <td width=\"20%\" valign=\"top\">\n"
" <div id=\"navlhs\" class=\"navtree\">\n"
" <script type=\"text/javascript\">makeTree('master');</script>\n"
" </div>\n"
" </td>\n"
" <td width=\"80%\" valign=\"top\">\n"
" <table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
" <tr height=\"44\"> <td align=\"center\" class=\"title\"> <div id=\"articletitle\"></div> </td></tr>\n"
" <tr> <td valign=\"top\" class=\"main\"> <div id=\"articlecontent\" class=\"objpage\"></div> </td></tr>\n"
" </table>\n"
" </td>\n"
" </tr>\n"
" </table>\n"
" </td>\n"
"</tr>\n"
"</table>\n" ;
// Show buttons
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n"
"<tr height=\"50\">\n"
" <td align=\"center\">\n" ;
C << "\t\t<input type=\"button\" onclick=\"location.href='/masterMainMenu';\" value=\"Master Account Menu\"/>" ;
if (pApp->m_CfgEdits.Count())
C << " <input type=\"button\" onclick=\"location.href='/masterMainMenu';\" value=\"Apply Changes\"/>" ;
C <<
"\n\t</td>\n"
"</tr>\n"
"</table>\n"
"</body>\n"
"</html>\n" ;
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
#endif
/*
** CONFIG CHANGES
*/
hzEcode _masterPageEdit (hzHttpEvent* pE, const hzString& rname)
{
// Display the form for creating a new page or editing an existing page. This essentially comprises a large text box, populated with the XML for the page (empty in the case of
// a new page). In addition there will be a 'Save' and a 'Test' button. Save simply saves the XML to a staging file for the page, which will exist until the page is committed.
// Test does not test the page but checks the proposed configs are viable. Pages are instead tested in a separate tab of the browser. This will return the same cookie i.e. the
// one associated with the webmaster session. The page displayed to a logged in webmaster will be the test version, if there is one.
//
//
_hzfunc("_masterPageEdit") ;
hzChain C ; // HTML chain
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterCfgEdit (hzHttpEvent* pE, const hzString& cname)
{
// Display the master edit config page. This essentially comprises a large text box and a submit button. The text box is populated with the XML for the resource if it exists.
//
// Argument: pE pE The HTTP event
// 2) cname Argument (part beyond URL /masterCfgEdit-)
//
// Returns: None
_hzfunc("hdsApp::_masterCfgEdit") ;
hdsApp* pApp ; // Application
ifstream is ; // Input stream
hzDirent de ; // Config file info
hzMD5 md5 ; // MD5 for the old content
hzAtom atom ; // For session values
hzChain C ; // HTML chain
hzChain Z ; // Config file content
const char* pArg ; // File identifier
hzString fpath ; // File path of original
hzString fnew ; // File path plus .new
uint32_t posn ; // Posn of file in m_Configs
hzEcode rc ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
pArg = pE->GetResource() ;
pArg += 12 ;
if (pArg[0] && IsPosint(posn, pArg))
{
//de = pApp->m_Configs.GetObj(posn) ;
fpath = pApp->m_Configdir + "/" ;
fpath += pApp->m_Configs.GetKey(posn) ;
//fpath = de.Path() + "/" + de.strName() ;
fnew = fpath + ".new" ;
rc = TestFile(*fnew) ;
if (rc == E_OK)
fpath = fnew ;
is.open(*fpath) ;
if (is.fail())
Z << "Error: Cannot Open File" << fpath ;
else
{
Z << is ;
is.close() ;
}
}
// Set the article title
C.Clear() ;
C << "Dissemino Config Editor: Page " << fpath ;
fnew = C ;
pE->SetHdr(s_articleTitle, fnew) ;
// Set the article content
C.Clear() ;
C << "<form method=\"POST\" action=\"masterCfgEditHdl1\">\n" ;
if (fpath)
C.Printf("<input type=\"hidden\" name=\"fname\" value=\"%s\"/>\n", *fpath) ;
else
C.Printf("Filename: <input type=\"text\" name=\"fname\"/>\n") ;
C << "<table width=\"96%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n" ;
C << "<tr>\n" ;
C << "<td>\n" ;
C << "<textarea name=\"pgData\" rows=\"40\" cols=\"200\" class=\"main\">" ;
if (Z.Size())
C << Z ;
C << "</textarea>\n" ;
C <<
"\t</td>\n"
"</tr>\n"
"</table>\n"
"<table width=\"20%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
"<td align=\"left\"><input type=\"button\" onclick=\"location.href='/masterCfgList';\" value=\"Back to Listings\"/></td>\n"
"<td align=\"rigth\"><input type=\"submit\" name=\"x-action\" value=\"Save Changes\"></td>\n"
"</tr>\n"
"</table>\n"
"</form>\n" ;
return pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
hzEcode _masterCfgEditHdl (hzHttpEvent* pE)
{
// Handle submission to the master 'stage 1' edit config file form.
//
// Begins with producing an MD5 from the text-box content. If this differs from the previous MD5 for 'pathname.new' or just 'pathname' if the .new does not
// yet exist, write out the contents to 'pathname.new'
//
// Config editing involves a sequence of events. The submit button in the stage 1 form will cause a HTTP POST event which will be processed by form-handler
// _masterCfgEditHdl1(). This takes the text-box content and produces an MD5. If the config file existed beforehand and the MD5 of the text-box content is a
// match to that of the original config file, _masterCfgEditHdl1() will redisplay the stage 1 config editor form along with a message "No changes detected".
// Where the MD5 is not a match, either because the origional config has been changed or is new, the text-box content is committed to disk and the stage 2
// config editor form is displayed. Note that the disk commit will copy the original file if it exists from 'pathname' to 'pathname.X' where X is the last
// modified date of the original expressed as YYYYMMDD-hhmmss. The content be it new or changed, is then written to pathname.new.
//
// The stage 2 form contains a test button which causes a HTTP POST event which will be processes by form-handler _masterCfgEditHd2(). This loads the config
// as an XML document and parses it using the same set of config read functions used at startup. If either the load or the parse fails, _masterCfgEditHd2()
// redisplays the stage 2 form with the error messages. If the load and the parse succeed _masterCfgEditHd2() redisplays the stage 2 form but this time with
// an 'adopt change' button. At this point the updated or new resources specified in the updated or new config are quarentined. Pressing the 'adopt change'
// button causes another HTTP POST event which will be processed by form-handler _masterCfgEditHd3(). This overwrites the config held at 'pathname' with the
// latest 'pathname.new' and moves the resources out of quarentine into mainstream.
hdsApp* pApp ; // Application
ofstream os ; // Output stream (to save file)
hzMD5 md5 ; // MD5 for the new content
hzDirent de ; // Config file info
hzChain C ; // Page output
hzChain Z ; // The XML to be tested
hzDocXml doc ; // The XML document for the resource
hzString S ; // Arg as string
hzString val ; // The submitted textarea
hzString fnew ; // Config file full pathname
hzEcode rc ; // Return code
_hzfunc("hdsApp::_masterCfgEditHdl") ;
pApp = (hdsApp*) pE->m_pContextApp ;
// Get file name
S = "fname" ;
fnew = pE->m_mapStrings[S] ;
// Get new file data
S = "pgData" ;
if (pE->m_mapChains.Exists(S))
Z = pE->m_mapChains[S] ;
else
{
val = pE->m_mapStrings[S] ;
Z = val ;
}
// Write data to file.new
fnew += ".new" ;
os.open(*fnew) ;
if (os.fail())
threadLog("Open file failed (%s)\n", *fnew) ;
else
{
os << Z ;
os.close() ;
}
if (!pApp->m_CfgEdits.Exists(de.strName()))
{
// We have not sought to edit this file before
pApp->m_CfgEdits.Insert(de.strName()) ;
}
// Compile HTML output
//C << s_master_head_std ;
C << "<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n" ;
if (!fnew)
C << "\t<tr height=\"50\"><td align=\"center\" class=\"title\">Dissemino Config Editor: Untitled</td></tr>\n" ;
else
C.Printf("\t<tr height=\"50\"><td align=\"center\" class=\"title\">Dissemino Config Editor: Page %s</td></tr>\n", *fnew) ;
C << "</table>\n" ;
C << "<form method=\"POST\">\n" ;
C.Printf("<p>Processing config file %s of %d bytes</p>\n", *fnew, Z.Size()) ;
C << "<textarea name=\"pgData\" rows=\"36\" cols=\"200\" class=\"main\">" ;
C << Z ;
C << "</textarea>\n" ;
C <<
"\t</td>\n"
"</tr>\n"
"</table>\n"
"<table width=\"20%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"main\">\n"
"<tr>\n"
"<td align=\"left\"><input type=\"button\" onclick=\"location.href='/masterCfgList';\" value=\"Back to Listings\"/></td>\n"
"<td align=\"rigth\"><input type=\"submit\" name=\"x-action\" value=\"Save Changes\"></td>\n"
"</tr>\n"
"</table>\n"
"</form>\n" ;
/*
rc = doc.Load(Z) ;
if (rc != E_OK)
{
C << "<p>Config did not load</p>\n" ;
C << doc.m_Error ;
}
else
{
pRoot = doc.GetRoot() ;
if (!pRoot)
{
C << "<p>Document has no root</p>\n" ;
C << m_cfgErr ;
rc = E_NODATA ;
}
else
{
rc = _readInclFile(pRoot) ;
if (rc != E_OK)
{
C << "<p>Document did not parse</p>\n" ;
C << m_cfgErr ;
}
}
C <<
"<table>\n"
"<tr>\n"
"\t<td align=\"center\">\n"
"\t<td><input type=\"button\" onclick=\"location.href='/masterCfgList';\" value=\"Abort Edit\"/></td>\n"
"\t<td width=\"20\"> </td>\n"
"\t<input type=\"submit\" formaction=\"masterCfgEditHdl1\" value=\"Submit\">\n" ;
if (rc == E_OK)
{
C <<
"\t<td width=\"20\"> </td>\n"
"\t<input type=\"submit\" formaction=\"masterCfgEditHdl2\" value=\"Apply\">\n" ;
}
C <<
"\t</td>\n"
"</tr>\n"
"</table>\n" ;
}
C <<
"</form>\n"
"</body>\n"
"</html>\n" ;
*/
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
hzEcode _masterCfgRestart (hzHttpEvent* pE)
{
// Checks for config updates and if any found, seeks to incorporate the changes into the live application.
//
// MD5 differences
hzVect<hzString> Dirs ; // All directories in m_Configdir ending in .new
hzVect<hzString> Files ; // All files in m_Configdir ending in .new
hdsApp* pApp ; // Application
hzDirent de ; // Directory entry
hzDocXml doc ; // The XML document for the resource
hzXmlNode* pRoot ; // Root node of document
hzChain C ; // For HTML output
hzString S ;
hzString fname ; // Name of .new file in config dir
uint32_t n ; // File iterator
hzEcode rc = E_OK ; // Return code
pApp = (hdsApp*) pE->m_pContextApp ;
ListDir(Dirs, Files, pApp->m_Configdir, "*.new") ;
// Compile HTML output
//C << s_master_head_std ;
C <<
"<table width=\"100%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#b3fff0\">\n"
" <tr height=\"50\"><td align=\"center\" class=\"title\">Dissemino Config Change Acceptor</td></tr>\n"
"</table>\n" ;
C.Printf("<p>Re-configuring for %d files in dir %s</p>\n", Files.Count(), *pApp->m_Configdir) ;
for (n = 0 ; rc == E_OK && n < Files.Count() ; n++)
{
S = Files[n] ;
//de = Files[n] ;
C.Printf("<p>Re-configuring for file %s</p>\n", *S) ;
if (de.strName().Contains("Main"))
continue ;
//fname = m_Configdir + "/" + de.Name() ;
fname = pApp->m_Configdir + "/" + S ;
rc = doc.Load(fname) ;
if (rc != E_OK)
{
C.Printf("<p>Config %s did not load</p>\n", *fname) ;
C << doc.Error() ;
continue ;
}
C.Printf("<p>Loaded Config %s</p>\n", *fname) ;
pRoot = doc.GetRoot() ;
if (!pRoot)
{
C << "<p>Document has no root</p>\n" ;
C << pApp->m_cfgErr ;
//rc = E_NODATA ;
continue ;
}
C.Printf("<p>Parsed Config %s</p>\n", *fname) ;
/*
* FIX
rc = pApp->_readInclFile(pRoot) ;
*/
// Any errors
if (rc != E_OK)
{
C << "<p>Document did not compile</p>\n" ;
C << pApp->m_cfgErr ;
continue ;
}
C.Printf("<p>Accepted Config %s</p>\n", *fname) ;
}
C << "</form>\n" ;
return pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}
#if 0
void hdsApp::ReportStatus (hzHttpEvent* pE)
{
// Display HTML Memory Usage Report
//
// Arguments: 1) pE The HTTP event being responded to
//
// Returns: None
hzChain C ; // Working chain for HTML output
ReportMemoryUsage(C, true) ;
ReportMutexContention(C, true) ;
pE->SendAjaxResult(HTTPMSG_OK, C) ;
}
#endif