mirror of
git://git.psyced.org/git/psyced
synced 2024-08-15 03:25:10 +00:00
572 lines
14 KiB
C
572 lines
14 KiB
C
|
// $Id: configure.c,v 1.58 2007/06/17 21:07:54 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 <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: "
|
||
|
// ""admin1", "admin2", "
|
||
|
// ""admin3")</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);
|
||
|
shutdown();
|
||
|
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"] || "", "\"", """),
|
||
|
"_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, "\"", """);
|
||
|
|
||
|
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;\"> </span></td></tr>\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s += "<tr><td colspan=2 align=center><p> </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
|