diff --git a/MCServer/webadmin/files/background.gif b/MCServer/webadmin/files/background.gif
new file mode 100644
index 000000000..cab9bed56
Binary files /dev/null and b/MCServer/webadmin/files/background.gif differ
diff --git a/MCServer/webadmin/files/favicon.ico b/MCServer/webadmin/files/favicon.ico
new file mode 100644
index 000000000..ea4bde926
Binary files /dev/null and b/MCServer/webadmin/files/favicon.ico differ
diff --git a/MCServer/webadmin/files/logo.png b/MCServer/webadmin/files/logo.png
new file mode 100644
index 000000000..50733e824
Binary files /dev/null and b/MCServer/webadmin/files/logo.png differ
diff --git a/MCServer/webadmin/files/mc-logo.png b/MCServer/webadmin/files/mc-logo.png
new file mode 100644
index 000000000..9a77a490f
Binary files /dev/null and b/MCServer/webadmin/files/mc-logo.png differ
diff --git a/MCServer/webadmin/files/style.css b/MCServer/webadmin/files/style.css
new file mode 100644
index 000000000..e7ffe3999
--- /dev/null
+++ b/MCServer/webadmin/files/style.css
@@ -0,0 +1,326 @@
+/* reset CSS */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%;
+ vertical-align: baseline;
+ background: transparent;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+
+/* remember to define focus styles! */
+:focus {
+ outline: 0;
+}
+
+/* remove textarea resize at Safari */
+textarea {
+ resize: none;
+}
+
+/* remember to highlight inserts somehow! */
+ins {
+ text-decoration: none;
+}
+del {
+ text-decoration: line-through;
+}
+
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+
+/*
+ Origional from http://www.perspectived.com/
+ Modified by Ben Phelps
+ Made for FakeTruth - MCServer
+*/
+
+/* Basic ---------------------------------------- */
+
+.clear { clear: both; }
+
+body {
+ background: white;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ color: #646464;
+ text-align: center;
+}
+
+#wrapper {
+ text-align: left;
+ width: 930px;
+ margin: 0 auto;
+}
+
+/* Logo ---------------------------------------- */
+
+h1 {
+ margin: 15px 0 10px 5px;
+ width: 180px;
+ height: 36px;
+ background: url(logo.png) no-repeat left top;
+}
+
+h1 a {
+ display: block;
+ width: 225px;
+ height: 28px;
+}
+
+h1 span { display: none; }
+
+a {
+ color: #646464;
+}
+
+/* Container ---------------------------------------- */
+
+#containerHolder {
+ background: #eee;
+ padding: 5px;
+}
+
+
+#container {
+ background: #fff url(background.gif) repeat-y left top;
+ border: 1px solid #ddd;
+ width: 918px;
+
+}
+
+#connectHolder {
+ background: #eee;
+ padding: 5px;
+ margin-bottom:8px;
+}
+
+
+#connect {
+ border: 1px solid #ddd;
+ background-color: #fff;
+ padding:5px;
+ width: 908px;
+}
+
+.pics {
+ height: 375px;
+ width: 600px;
+}
+
+.pics img {
+ padding: 5px;
+ border: 1px solid #ddd;
+ background-color: #eee;
+ width: 600px;
+ height: 375px;
+ margin-left: 15px;
+}
+
+/* Login -------------------------------------- */
+
+#loginLogo {
+ margin: 0 auto;
+ margin-top:100px;
+ width: 180px;
+ height: 36px;
+ background-image: url(logo.png);
+}
+
+#loginHolder {
+ background: #eee;
+ padding: 5px;
+ width: 310px;
+ margin: 0 auto;
+ height: 90px;
+ margin-top:20px;
+}
+
+#login {
+ padding:10px;
+ width: 288px;
+ height: 68px;
+ border: 1px solid #ddd;
+ background:#fff;
+ text-align: left;
+}
+
+
+/* Sidebar ---------------------------------------- */
+
+#sidebar {
+ width: 179px;
+ float: left;
+}
+
+#sidebar .sideNav { width: 179px; }
+
+#sidebar .sideNav li { border-bottom: 1px solid #ddd; width: 179px; }
+
+#sidebar .sideNav li a {
+ display: block;
+ color: #646464;
+ background: #f6f6f6;
+ text-decoration: none;
+ height: 29px;
+ line-height: 29px;
+ padding: 0 19px;
+ width: 141px;
+}
+
+#sidebar .sideNav li a:hover { background: #fdfcf6; }
+
+#sidebar .sideNav li a.active, #sidebar .sideNav li a.active:hover {
+ background: #f0f7fa;
+ color: #c66653;
+}
+
+/* Breadcrumb ---------------------------------------- */
+
+h2 {
+ width: 718px;
+ float: right;
+ color: #646464;
+ font-size: 16px;
+ line-height: 16px;
+ font-weight: bold;
+ margin: 20px 0 0 0;
+ padding: 0 0 10px 0;
+ border-bottom: 1px solid #ddd;
+}
+
+h2 a {
+ color: #646464;
+ text-decoration: none;
+}
+
+h2 a.active { color: #c66653; }
+
+h2 a:hover { text-decoration: underline; }
+
+/* Content ---------------------------------------- */
+
+#main {
+ width: 700px;
+ float: right;
+ padding: 0 19px 0 0;
+}
+
+#main p {
+
+ padding: 10px;
+
+}
+
+h3 {
+ font-size: 14px;
+ line-height: 14px;
+ font-weight: bold;
+ color: #5494af;
+ padding: 0 0 0 10px;
+ margin: 20px 0 10px;
+}
+
+h4 {
+ padding: 0 0 0 10px;
+ margin: 20px 0 10px;
+}
+
+#main ul {
+ padding: 0 0 0 10px;
+ list-style-type: circle;
+ list-style-position: inside;
+}
+
+#main table {
+ border-top: 1px solid #ddd;
+ width: 700px;
+}
+
+#main table tr th {
+ text-align: left;
+ background: #f6f6f6;
+ padding: 0px 20px;
+ height: 20px;
+ line-height: 20px;
+ border-bottom: 1px solid #ddd;
+}
+
+#main table tr td {
+ background: #f6f6f6;
+ padding: 0px 20px;
+ height: 29px;
+ line-height: 29px;
+ border-bottom: 1px solid #ddd;
+}
+
+#main table tr.odd td {
+ background: #fbfbfb;
+}
+
+#main table tr:hover td { background: #fdfcf6; }
+
+#main table .action {
+ text-align: right;
+ padding: 0 20px 0 10px;
+}
+
+#main table tr .action a { margin: 0 0 0 10px; text-decoration: none; color: #9b9b9b; }
+#main table tr:hover .action .edit { color: #c5a059; }
+#main table tr:hover .action .delete { color: #a02b2b; }
+#main table tr:hover .action .view { color: #55a34a; }
+
+#main table tr:hover .action a:hover { text-decoration: underline; }
+
+fieldset {
+ border: 1px solid #ddd;
+ padding: 19px;
+ margin: 0 0 20px 0;
+ background: #fbfbfb;
+}
+
+form p { margin: 0 0 14px 0; float: left; width: 100%; }
+
+label {
+ display: block;
+ width: 100%;
+ margin: 0 0 7px 0;
+ line-height: 12px;
+}
+
+/* Footer ---------------------------------------- */
+
+#footer {
+ margin: 10px 0 30px 0;
+ font-size: 11px;
+ line-height: 11px;
+ color: #9B9B9B;
+ padding: 0 0 0 5px;
+}
+
+#footer a { color: #9B9B9B; }
+
+#footer a:hover { text-decoration: none; }
diff --git a/MCServer/webadmin/login_template.html b/MCServer/webadmin/login_template.html
new file mode 100644
index 000000000..913a85db0
--- /dev/null
+++ b/MCServer/webadmin/login_template.html
@@ -0,0 +1,25 @@
+
+
+ MCServer WebAdmin - Login
+
+
+
+
+
+
+
+
+ MCServer - WebAdmin
+
+
+
+
+
diff --git a/MCServer/webadmin/template.lua b/MCServer/webadmin/template.lua
index a066d8b33..a7480f83e 100644
--- a/MCServer/webadmin/template.lua
+++ b/MCServer/webadmin/template.lua
@@ -57,7 +57,7 @@ end
function ShowPage(WebAdmin, TemplateRequest)
SiteContent = {}
local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path)
- local Title = "MCServer"
+ local Title = "MCServer WebAdmin"
local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage()
local NumChunks = cRoot:Get():GetTotalChunkCount()
local PluginPage = WebAdmin:GetPage(TemplateRequest.Request)
@@ -74,339 +74,9 @@ function ShowPage(WebAdmin, TemplateRequest)
-
+
]] .. Title .. [[
-
-
-
+
@@ -421,16 +91,16 @@ function ShowPage(WebAdmin, TemplateRequest)
]])
-
+
local AllPlugins = WebAdmin:GetPlugins()
for key,value in pairs(AllPlugins) do
local PluginWebTitle = value:GetWebTitle()
local TabNames = value:GetTabNames()
if (GetTableSize(TabNames) > 0) then
- Output(""..PluginWebTitle.." ");
+ Output(""..PluginWebTitle.." \n");
for webname,prettyname in pairs(TabNames) do
- Output("" .. prettyname .. " ")
+ Output("" .. prettyname .. " \n")
end
end
end
@@ -464,4 +134,4 @@ function ShowPage(WebAdmin, TemplateRequest)
]])
return table.concat(SiteContent)
-end
\ No newline at end of file
+end
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index 23eedbd14..341c64236 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -131,8 +131,24 @@ bool cWebAdmin::Start(void)
m_TemplateScript.RegisterAPILibs();
if (!m_TemplateScript.LoadFile(FILE_IO_PREFIX "webadmin/template.lua"))
{
- LOGWARN("Could not load WebAdmin template \"%s\", using default template.", FILE_IO_PREFIX "webadmin/template.lua");
+ LOGWARN("Could not load WebAdmin template \"%s\". WebAdmin disabled!", FILE_IO_PREFIX "webadmin/template.lua");
m_TemplateScript.Close();
+ m_HTTPServer.Stop();
+ return false;
+ }
+
+ if (!LoadLoginTemplate())
+ {
+ LOGWARN("Could not load WebAdmin login template \"%s\", using fallback template.", FILE_IO_PREFIX "webadmin/login_template.html");
+
+ // Sets the fallback template:
+ m_LoginTemplate = \
+ "MCServer WebAdmin " \
+ "" \
+ "" \
+ " ";
}
m_IsRunning = m_HTTPServer.Start(*this);
@@ -159,6 +175,28 @@ void cWebAdmin::Stop(void)
+bool cWebAdmin::LoadLoginTemplate(void)
+{
+ cFile File(FILE_IO_PREFIX "webadmin/login_template.html", cFile::fmRead);
+ if (!File.IsOpen())
+ {
+ return false;
+ }
+
+ AString TemplateContent;
+ if (File.ReadRestOfFile(TemplateContent) == -1)
+ {
+ return false;
+ }
+
+ m_LoginTemplate = TemplateContent;
+ return true;
+}
+
+
+
+
+
void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request)
{
if (!a_Request.HasAuth())
@@ -298,17 +336,11 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque
void cWebAdmin::HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request)
{
UNUSED(a_Request);
- static const char LoginForm[] = \
- "MCServer WebAdmin " \
- "" \
- "" \
- " ";
+
cHTTPResponse Resp;
Resp.SetContentType("text/html");
a_Connection.Send(Resp);
- a_Connection.Send(LoginForm, sizeof(LoginForm) - 1);
+ a_Connection.Send(m_LoginTemplate);
a_Connection.FinishResponse();
}
@@ -316,6 +348,94 @@ void cWebAdmin::HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest &
+void cWebAdmin::HandleFileRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request)
+{
+ AString FileURL = a_Request.GetURL();
+ std::replace(FileURL.begin(), FileURL.end(), '\\', '/');
+
+ // Remove all leading backslashes:
+ if (FileURL[0] == '/')
+ {
+ size_t FirstCharToRead = FileURL.find_first_not_of('/');
+ if (FirstCharToRead != AString::npos)
+ {
+ FileURL = FileURL.substr(FirstCharToRead);
+ }
+ }
+
+ // Remove all "../" strings:
+ ReplaceString(FileURL, "../", "");
+
+ bool LoadedSuccessfull = false;
+ AString Content = "404 Not Found ";
+ AString Path = Printf(FILE_IO_PREFIX "webadmin/files/%s", FileURL.c_str());
+ if (cFile::IsFile(Path))
+ {
+ cFile File(Path, cFile::fmRead);
+ AString FileContent;
+ if (File.IsOpen() && (File.ReadRestOfFile(FileContent) != -1))
+ {
+ LoadedSuccessfull = true;
+ Content = FileContent;
+ }
+ }
+
+ // Find content type (The currently method is very bad. We should change it later)
+ AString ContentType = "text/html";
+ size_t LastPointPosition = Path.find_last_of('.');
+ if (LoadedSuccessfull && (LastPointPosition != AString::npos) && (LastPointPosition < Path.length()))
+ {
+ AString FileExtension = Path.substr(LastPointPosition + 1);
+ ContentType = GetContentTypeFromFileExt(FileExtension);
+ }
+
+ // Send the response:
+ cHTTPResponse Resp;
+ Resp.SetContentType(ContentType);
+ a_Connection.Send(Resp);
+ a_Connection.Send(Content);
+ a_Connection.FinishResponse();
+}
+
+
+
+
+
+AString cWebAdmin::GetContentTypeFromFileExt(const AString & a_FileExtension)
+{
+ static bool IsInitialized = false;
+ static std::map ContentTypeMap;
+ if (!IsInitialized)
+ {
+ // Initialize the ContentTypeMap:
+ ContentTypeMap["png"] = "image/png";
+ ContentTypeMap["fif"] = "image/fif";
+ ContentTypeMap["gif"] = "image/gif";
+ ContentTypeMap["jpeg"] = "image/jpeg";
+ ContentTypeMap["jpg"] = "image/jpeg";
+ ContentTypeMap["jpe"] = "image/jpeg";
+ ContentTypeMap["tiff"] = "image/tiff";
+ ContentTypeMap["ico"] = "image/ico";
+ ContentTypeMap["csv"] = "image/comma-separated-values";
+ ContentTypeMap["css"] = "text/css";
+ ContentTypeMap["js"] = "text/javascript";
+ ContentTypeMap["txt"] = "text/plain";
+ ContentTypeMap["rtx"] = "text/richtext";
+ ContentTypeMap["xml"] = "text/xml";
+ }
+
+ AString FileExtension = StrToLower(a_FileExtension);
+ if (ContentTypeMap.find(a_FileExtension) == ContentTypeMap.end())
+ {
+ return "text/html";
+ }
+ return ContentTypeMap[FileExtension];
+}
+
+
+
+
+
sWebAdminPage cWebAdmin::GetPage(const HTTPRequest & a_Request)
{
sWebAdminPage Page;
@@ -382,6 +502,7 @@ AString cWebAdmin::GetDefaultPage(void)
+
AString cWebAdmin::GetBaseURL( const AString& a_URL)
{
return GetBaseURL(StringSplit(a_URL, "/"));
@@ -528,7 +649,7 @@ void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest &
}
else
{
- // TODO: Handle other requests
+ HandleFileRequest(a_Connection, a_Request);
}
// Delete any request data assigned to the request:
@@ -551,4 +672,3 @@ void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, size_t a_Size)
-
diff --git a/src/WebAdmin.h b/src/WebAdmin.h
index aefc1d145..94b95dbcf 100644
--- a/src/WebAdmin.h
+++ b/src/WebAdmin.h
@@ -116,6 +116,9 @@ public:
/** Stops the HTTP server, if it was started. */
void Stop(void);
+ /** Loads the login template. Returns true if the loading succeeds, false if not. */
+ bool LoadLoginTemplate(void);
+
void AddPlugin(cWebPlugin * a_Plugin);
void RemovePlugin(cWebPlugin * a_Plugin);
@@ -146,6 +149,9 @@ public:
/** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */
static AString GetBaseURL(const AStringVector & a_URLSplit);
+ /** Returns the content type from the file extension. If the extension isn't in the list, the function returns "text/html" */
+ static AString GetContentTypeFromFileExt(const AString & a_FileExtension);
+
protected:
/** Common base class for request body data handlers */
class cRequestData
@@ -205,6 +211,9 @@ protected:
/** The Lua template script to provide templates: */
cLuaState m_TemplateScript;
+ /** The template that provides the login site: */
+ AString m_LoginTemplate;
+
/** The HTTP server which provides the underlying HTTP parsing, serialization and events */
cHTTPServer m_HTTPServer;
@@ -214,6 +223,9 @@ protected:
/** Handles requests for the root page */
void HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
+ /** Handles requests for a file */
+ void HandleFileRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
+
// cHTTPServer::cCallbacks overrides:
virtual void OnRequestBegun (cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override;
virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override;