psyced/world/net/http/configure.c
2013-11-16 03:05:47 +01:00

573 lines
14 KiB
C

// $Id: configure.c,v 1.59 2008/04/22 22:43:56 lynx Exp $ // vim:syntax=lpc
//
// web configurator interface. does a lot of cool things for you,
// and it should always learn to do some more. if you don't need or
// like it, simply don't load it (from init.ls, or by fetching the url).
//
#include <ht/http.h>
#include <net.h>
#include <driver.h>
#if HAS_PORT(HTTP_PORT, HTTP_PATH) || HAS_PORT(HTTPS_PORT, HTTP_PATH)
#include <text.h>
#include <person.h>
#include <misc.h>
inherit NET_PATH "sockets";
#ifdef WEB_CONFIGURE
// should this use something else?
# define CONFIGFILE CONFIG_PATH "local.h"
volatile protected mapping description;
void create() {
sTextPath(0, 0, "html");
description = ([
// this has all moved into psyced.ini
// "CHATNAME" : "Name of this Chat Community",
// "DEFPLACE" : "Standard place unregistered users go to",
// "ADMINISTRATORS" : "List of administrators <small>(example: "
// "&quot;admin1&quot;, &quot;admin2&quot;, "
// "&quot;admin3&quot;)</small>",
// "__DOMAIN_NAME__" : "Domain name of this server",
// "SERVER_HOST" : "Address of this server",
// "OSTYPE" : "Your Operating System",
// "MACHTYPE" : "The flavour of your processor",
// optimise on tunings, like this one?
"MAX_VISIBLE_USERS" : "MAX_VISIBLE_USERS",
// a bit absurd: specify a file on the fs instead of having a motd textarea
"MOTD_FILE" : "The file that contains the IRC-MOTD",
]);
}
denyAccess(prot) {
hterror(prot, 200, "You are not allowed to use the configure-page. "
"You need to be from <i>localhost</i> to do that.");
}
parseConfig(fname) {
mapping cv;
int size;
cv = ([ ]);
if (file_size(fname) <= 0) {
return ([ ]);
}
foreach(string line : explode(read_file(fname), "\n")) {
mixed key, value;
if (sscanf(line, "#define%t%s%t%s", key, value)
|| sscanf(line, "#define%t%s", key)
|| sscanf(line, "#%tdefine%t%s%t%s", key, value)
|| sscanf(line, "#%tdefine%t%s", key)
) {
//if (dummy=="" && index(key, ' ')==-1 && index(key, '\t')==-1)
// && (member(description, key) != -1))
cv[key] = value;
}
}
return cv;
}
saveConfig(string fname, mapping config, mapping del) {
string file, key, value, tail;
int added;
unless (mappingp(del)) {
del = ([ ]);
}
if (file_size(fname) <= 0) {
if (abbrev("place/", fname)) {
file = w("_PAGES_configure_room_new");
} else {
return;
}
} else {
file = read_file(fname);
}
added = 0;
foreach (key, value : config) {
// re scheint keine + syntax zu beherrschen
P2(("===> %O\n", value))
if (to_string(to_int(value)) != value && value != "") {
unless (value[0] == '"')
value = "\"" + value;
unless (value[<1] == '"')
value += "\"";
}
if (sizeof(regexp(({ file }),
"#([ \t]*)define([ \t][ \t]*)"+key+
"([ \t][ \t]*)[^\n]*"))) {
tail = "([ \t][ \t]*)[^\n]*";
} else if (sizeof(regexp(({ file }),
"#([ \t]*)define([ \t][ \t]*)"+key))) {
tail = "";
} else {
// adden
file = regreplace(file,
"#include <place.gen>",
"#define "+key+" "+
(value != "" ? " "+value : "")+
"\n#include <place.gen>", 0);
added = 1;
}
unless (value == "" && added == 0) {
file = regreplace(file,
"#([ \t]*)define([ \t][ \t]*)"+key+tail,
"#\\1define "+key+"\t"+value, 0);
} else if (added == 0){
file = regreplace(file,
"#([ \t]*)define([ \t][ \t]*)"+key+tail,
"#\\1define "+key, 0);
}
// old ldmud requires 4th argument
// if (t == file) printf("Could not change %s into %O\n", key, value);
}
foreach (key, value : del) {
file = regreplace(file,
"#([ \t]*)define([ \t][ \t]*)"+key+"[^\n]*\n",
"", 0);
}
rm(fname);
write_file(fname, file);
return w("_PAGES_configure_advice_restart") + "<font size=6><pre>\n" +
"Congratulations, this is your new configuration file:\n" +
"</pre><font color=green><plaintext>\n" + file;
}
htget(prot, query, headers, qs) {
string s; // output buffer
int trustworthy = legal_host(query_ip_number(), HTTP_PORT, "http", 0);
if (trustworthy < 7) {
denyAccess(prot);
return 1;
}
if (file_size(CONFIGFILE) <= 0) {
hterror(prot, 404, "You don't have any configfile, do you?");
return 1;
}
htok3(prot, "text/html", "Cache-Control: no-cache\n");
switch (query["option"]) {
case "user_mgm":
s = w("_PAGES_configure_user",
([ "_title" : "User Management" ]));
break;
case "list_users":
write(w("_PAGES_configure_user_list",
([ "_title" : "User List" ])));
list_sockets();
return 1;
case "block_modify":
if (query["ip"] && query["ip"] != 0) {
object ob;
DAEMON_PATH "hosts"->modify(query["ip"]);
foreach (ob : users()) {
if (abbrev(query["ip"], query_ip_number(ob))) {
log_file("BEHAVIOUR",
"[%s] %O blocks %O (%s)\n",
ctime(), ME, ob, query["ip"]);
ob -> sanction("kill");
}
}
}
case "list_blocks":
write(w("_PAGES_configure_user_block_head",
([ "_title" : "Block Management",
"_submit_value" : "Submit" ])));
DAEMON_PATH "hosts"->list();
return 1;
case "user_password":
s = w("_PAGES_configure_user_password",
([ "_title" : "Reset Password",
"_submit_value" : "Edit" ]));
break;
case "user_password_edit":
{
object o;
unless (o = find_person(query["nick"])) {
unless (o = summon_person(query["nick"])) {
s = w("_PAGES_configure_user_password_failure",
([ "_title" : "Reset Password" ]));
break;
}
}
if (o->isNewbie()) {
destruct(o);
s = w("_PAGES_configure_user_password_failure",
([ "_title" : "Reset Password" ]));
break;
}
s = w("_PAGES_configure_user_password_edit",
([ "_title" : "Reset Password",
"_submit_value" : "Reset Password",
"_nick" : query["nick"] ]));
break;
}
case "user_password_save":
{
object o;
if (! query["password"] || strlen(query["password"]) <= 2) {
s = w("_PAGES_configure_user_password_failure_bad",
([ "_title" : "Reset Password" ]));
break;
}
unless (o = find_person(query["nick"])) {
unless (o = summon_person(query["nick"])) {
s = w("_PAGES_configure_user_password_failure",
([ "_title" : "Reset Password" ]));
break;
}
}
if (o->isNewbie()) {
destruct(o);
s = w("_PAGES_configure_user_password_failure",
([ "_title" : "Reset Password" ]));
break;
}
o->vSet("password", query["password"]);
o->save();
s = w("_PAGES_configure_user_password_save",
([ "_title" : "Reset Password",
"_nick" : query["nick"],
"_password" : query["password"] ]));
break;
}
case "basic_mgm":
s = w("_PAGES_configure_basic",
([ "_title" : "Basic Server Management" ]));
break;
case "restart":
s = w("_PAGES_configure_head",
([ "_title" : "Restart" ]));
s += "<b>Your chatserver is being restarted.</b>";
// write at the bottom wouldn't be called after shutdown, would it?
write(s);
server_shutdown("restart by web configuration", 1);
return 1;
case "list_udp":
{
mapping ports;
string port;
s = w("_PAGES_configure_basic_udp_head",
([ "_title" : "List UDP Ports" ]));
ports = DAEMON_PATH "udp"->listPorts(1);
foreach (port : m_indices(ports)) {
s += w("_PAGES_configure_basic_udp_entry",
ports[port]);
}
s += w("_PAGES_configure_basic_udp_tail");
break;
}
case "room_mgm":
s = w("_PAGES_configure_room",
([ "_title" : "Room Management" ]));
break;
case "room_owned":
s = w("_PAGES_configure_room_owned",
([ "_title" : "Manage Owned Rooms",
"_submit_value" : "Edit / Add" ]));
break;
case "room_owned_save":
{
mapping del;
del = ([ ]);
m_delete(query, "option");
if (query["delete"]) {
rm("place/" + lower_case(query["NAME"]) + ".c");
s = w("_PAGES_configure_room_deleted",
([ "_title" : "Room Deleted",
"_name" : query["NAME"] ]));
break;
}
if (query["ALLOW_EXTERNAL"]) {
query["ALLOW_EXTERNAL"] = "";
} else {
del += ([ "ALLOW_EXTERNAL" ]);
}
if (query["REGISTERED"]) {
query["REGISTERED"] = "";
} else {
del += ([ "REGISTERED" ]);
}
s = w("_PAGES_configure_head",
([ "_title" : "Owned Room Management" ]));
s += saveConfig("place/" + lower_case(query["NAME"]) + ".c", query, del);
break;
}
case "room_owned_edit":
{
mapping rs;
string name;
mixed t;
rs = parseConfig("place/" + lower_case(query["NAME"]) + ".c");
P2(("===> %O\n", rs))
unless ((t = isRoomType("OWNED", rs)) == 1) {
if (t != -1) {
s = w("_PAGES_configure_room_error_type",
([ "_title" : "Manage Owned Rooms",
"_name" : query["NAME"],
"_expected" : "Owned",
"_type" : t
]));
} else {
s = w("_PAGES_configure_room_error_type_undefined",
([ "_title" : "Manage Owned Rooms",
"_name" : query["NAME"],
"_expected" : "Owned" ]));
}
break;
}
if (rs["NAME"]) {
name = replace(rs["NAME"], "\"", "");
} else {
name = query["NAME"] || "";
}
s = w("_PAGES_configure_room_owned_edit",
([ "_title" : "Manage Owned Rooms",
"_submit_value" : "Save",
"_name" : name,
"_registered" : member(rs, "REGISTERED") ? " checked" : "",
"_owned" : replace(rs["OWNED"] || "", "\"", "&quot;"),
"_external" : member(rs, "ALLOW_EXTERNAL") ? " checked" : "" ]));
break;
}
case "room_public":
s = w("_PAGES_configure_room_public",
([ "_title" : "Manage Public Rooms",
"_submit_value" : "Edit / Add" ]));
break;
case "room_public_save":
{
mapping del;
del = ([ ]);
m_delete(query, "option");
if (query["delete"]) {
rm("place/" + lower_case(query["NAME"]) + ".c");
s = w("_PAGES_configure_room_deleted",
([ "_title" : "Room Deleted",
"_name" : query["NAME"] ]));
break;
}
if (query["HISTORY"]) {
query["HISTORY"] = "";
} else {
del += ([ "HISTORY" ]);
}
if (query["ALLOW_EXTERNAL"]) {
query["ALLOW_EXTERNAL"] = "";
} else {
del += ([ "ALLOW_EXTERNAL" ]);
}
if (query["REGISTERED"]) {
query["REGISTERED"] = "";
} else {
del += ([ "REGISTERED" ]);
}
s = w("_PAGES_configure_head",
([ "_title" : "Public Room Management" ]));
s += saveConfig("place/" + lower_case(query["NAME"]) + ".c", query, del);
break;
}
case "room_public_edit":
{
mapping rs;
string name;
mixed t;
rs = parseConfig("place/" + lower_case(query["NAME"]) + ".c");
P2(("===> %O\n", rs))
unless (intp(t = isRoomType("PUBLIC", rs))) {
s = w("_PAGES_configure_room_error_type",
([ "_title" : "Manage Public Rooms",
"_name" : query["NAME"],
"_expected" : "Public",
"_type" : t
]));
break;
}
if (rs["NAME"]) {
name = replace(rs["NAME"], "\"", "");
} else {
name = query["NAME"] || "";
}
s = w("_PAGES_configure_room_public_edit",
([ "_title" : "Manage Public Rooms",
"_submit_value" : "Save",
"_name" : name,
"_history" : member(rs, "HISTORY") ? " checked" : "",
"_registered" : member(rs, "REGISTERED") ? " checked" : "",
"_external" : member(rs, "ALLOW_EXTERNAL") ? " checked" : "" ]));
break;
}
case "save_config":
{
s = w("_PAGES_configure_head",
([ "_title" : "Edit Config" ]));
s += saveConfig(CONFIGFILE, query);
break;
}
#if 0
// was um alles in der welt soll das?
case "set":
m_delete(query, "option");
break; // gehört da n break hin?
#endif
case "edit_config":
{
mapping cv;
cv = parseConfig(CONFIGFILE);
// sowas gehört in externe dateien.. am besten .fmt wegen
// mehrsprachigkeit und layouting und template syntax und und..
s = w("_PAGES_configure_head", ([ "_title" : "Edit Config" ]));
s += "<div align=\"center\" style=\"float:clear; text-align:center;\">\n"
"<table bgcolor=\"#004411\" cellspacing=0 cellpadding=3>\n"
"<form method=GET action=configure name=zero>\n"
"<input type=hidden name=option value=\"save_config\">\n";
foreach(string key, string value : cv) {
if (value) {
value = replace(value, "\"", "&quot;");
s += "<tr><td style=\"border-left: 1px solid #f90; border-top: 1px solid #f90;\"><b>" + key + ":</b></td><td style=\"border-top: 1px solid #f90; border-right: 1px solid #f90;\"><input type=\"text\" value=\"" + value
+ "\" name=\"" + key + "\"></td></tr>\n"
"<tr><td colspan=2 style=\"padding-left:10px; border-bottom: 1px solid #fc0; border-right: 1px solid #f90; border-left: 3px solid #fc0;\">" + (description[key] || "") + "</td></tr>\n"
"<tr><td><span style=\"font-size:1px;\">&nbsp;</span></td></tr>\n";
}
}
s += "<tr><td colspan=2 align=center><p>&nbsp;</p>";
s += w("_PAGES_configure_submit",
([ "_submit_value" : "Save" ]));
s += "</td></tr>\n"
"</form></table>\n"
"</div>\n";
break;
}
default:
s = w("_PAGES_configure_menu", ([ "_title" : "Menu" ]));
}
write(s);
}
#else
htget(prot, query, headers, qs) {
hterror(prot, 501, "This server hasn't enabled webbased administration");
}
#endif
isRoomType(expected, mapping rs) {
string type;
unless (sizeof(rs)) {
return 1;
}
foreach (type : filter(({ "OWNED", "MODERATED", "NEWSFEED_RSS",
"SLAVE", "CONNECTED_IRC", "THREADS",
"GAMESERV", "LINK", "PUBLIC" }),
lambda( ({ 'x }), ({#'?, ({ #'!=, 'x, expected }) })) )) {
if(member(rs, type))
return type[0..0] + lower_case(type[1..]);
}
if (member(rs, expected)) {
return 1;
}
return -1;
}
w(mc, mixed vars, bla) {
if (bla) {
vars = bla;
}
if (mc == "_list_user_technical") {
unless (mappingp(vars))
vars = ([ ]);
write(psyctext(T(mc, ""), vars));
return;
}
unless (mappingp(vars)) {
return T(mc, "");
}
return psyctext(T(mc, ""), vars);
}
// only used for HOSTS_D
pr(mc, text, vars) {
string s, ip, reason;
// we'll keep it this way, yet
switch (mc) {
case "_list_hosts_disabled":
s = "";
foreach (ip, reason: vars) {
s += w(mc,
([ "_ip" : ip,
"_reason" : reason ]));
}
}
write(s);
}
#endif