b1fca01996-11-12Per Hedbor inherit "config/builders";
8691921997-06-12Henrik Grubbström (Grubba) string cvs_version = "$Id: mainconfig.pike,v 1.42 1997/06/12 00:34:23 grubba Exp $";
b1fca01996-11-12Per Hedbor inherit "roxenlib";
fd0b6f1996-12-02Per Hedbor inherit "config/draw_things";
b1fca01996-11-12Per Hedbor 
5e89211997-02-13Per Hedbor import Array;
aaef2a1997-03-02Henrik Grubbström (Grubba) import Stdio;
19f5911997-03-03Henrik Grubbström (Grubba) /* Work-around for Simulate.perror */ #define perror roxen_perror
5e89211997-02-13Per Hedbor 
b1fca01996-11-12Per Hedbor #include <confignode.h> #include <module.h>
1e257d1996-12-03Per Hedbor #define dR "00"
bd25601996-12-05Per Hedbor #define dG "06"
ae32fc1996-12-05Per Hedbor #define dB "30"
1e257d1996-12-03Per Hedbor  #define bdR "00"
2de6921996-12-03Per Hedbor #define bdG "50" #define bdB "90"
1e257d1996-12-03Per Hedbor 
38dca81996-12-10Per Hedbor #define BODY "<body "+(roxen->QUERY(BG)?"background=/image/background.gif ":"")+"bgcolor=#"+dR+dG+dB+" text=#ffffff link=#ffffaa vlink=#ffffaa alink=#f0e0f0>"
b1fca01996-11-12Per Hedbor  #define TABLEP(x, y) (id->supports->tables ? x : y)
b2c3871996-12-04Per Hedbor #define PUSH(X) do{res+=({(X)});}while(0)
b1fca01996-11-12Per Hedbor  int bar=time(1);
b2c3871996-12-04Per Hedbor class Node {
b1fca01996-11-12Per Hedbor  inherit "struct/node";
aaef2a1997-03-02Henrik Grubbström (Grubba)  import Simulate;
b1fca01996-11-12Per Hedbor  mixed original;
676c231996-12-06Per Hedbor  int changed, moredocs;
b1fca01996-11-12Per Hedbor 
14179b1997-01-29Per Hedbor  int bar=time();
b1fca01996-11-12Per Hedbor  function saver = lambda(object o) { if(o->changed) o->change(-o->changed); }; string|array error; void change(int i) { changed += i; if(up) up->change(i); } private string show_me(string s) { string name=path(1); if(folded)
b2c3871996-12-04Per Hedbor  return ("<a name=\""+name+"\">\n" "<a href=\"/(unfold)" + name + "?"+(bar++)+ "\">\n<img border=0 align=baseline src=/auto/unfold" +(changed?"2":"")+" alt=\""+(changed?"*-":"--")+"\">" "</a>\n "+s+"\n");
b1fca01996-11-12Per Hedbor  else
b2c3871996-12-04Per Hedbor  return ("<a name=\""+name+"\">\n" "<a href=\"/(fold)" + name + "?"+(bar++)+ "\">\n<img border=0 src=/auto/fold"+(changed?"2":"")
1e257d1996-12-03Per Hedbor  +" alt="+(changed?"**":"\"\\/\"")+">"
b2c3871996-12-04Per Hedbor  "</a>\n "+s+"\n");
b1fca01996-11-12Per Hedbor  } string describe(int i) {
b2c3871996-12-04Per Hedbor  array (string) res=({""});
b1fca01996-11-12Per Hedbor  object node,prevnode; mixed tmp; if(describer) tmp = describer(this_object()); #ifdef NODE_DEBUG else
676c231996-12-06Per Hedbor  {
b1fca01996-11-12Per Hedbor  perror("No describer in node "+path(1)+"\n");
676c231996-12-06Per Hedbor  return 0; }
b1fca01996-11-12Per Hedbor #endif if(arrayp(tmp) && sizeof(tmp))
676c231996-12-06Per Hedbor  PUSH(tmp[0] + "<dt>" + (i?tmp[i]:show_me(tmp[1])) + "\n");
b1fca01996-11-12Per Hedbor  else if(stringp(tmp) && strlen(tmp))
676c231996-12-06Per Hedbor  PUSH("<dt>"+(i?tmp:show_me(tmp)) + "\n");
b1fca01996-11-12Per Hedbor  else if(!tmp) return ""; if(!folded) {
b2c3871996-12-04Per Hedbor  PUSH("<dl><dd>\n");
b1fca01996-11-12Per Hedbor  node = down; while(node) { if(!objectp(node)) // ERROR! Destructed node in tree! { if(objectp(prevnode)) prevnode->next=0; node=0; break; } prevnode = node; node = node->next;
b2c3871996-12-04Per Hedbor  PUSH(prevnode->describe());
b1fca01996-11-12Per Hedbor  }
b2c3871996-12-04Per Hedbor  PUSH("</dl>\n\n");
b1fca01996-11-12Per Hedbor  }
b2c3871996-12-04Per Hedbor  return res*"";
b1fca01996-11-12Per Hedbor  } object config() { object node; node=this_object(); while(node) if(node->type == NODE_CONFIGURATION) return node->data; else node=node->up; } void save() { object node; node=down; // depth-first save. while(node) { if(node->changed) node->save(); node=node->next; } if(saver) saver(this_object()); }
b2c3871996-12-04Per Hedbor }
b1fca01996-11-12Per Hedbor 
5e4ede1996-11-12Per Hedbor object root=Node();
b1fca01996-11-12Per Hedbor int expert_mode; void create() { build_root(root); init_ip_list(); call_out(init_ip_list, 0); }
b2c3871996-12-04Per Hedbor #define BUTTON(ACTION,TEXT,ALIGN) do{PUSH("<a href=\"/(ACTION)"+(o?o->path(1):"/")+"?"+(bar++)+"\"><img border=0 hspacing=0 vspacing=0 src=/auto/button/"+(lm?"lm/":"")+replace(TEXT," ","%20")+" alt=\""+(lm?"/ ":" ")+TEXT+" /\""+(("ALIGN"-" ")=="left"?"":" align="+("ALIGN"-" "))+"></a>");lm=0;}while(0)
fdee9d1996-12-02Per Hedbor  inline string shutdown_restart(string save, int compact,void|object o)
b1fca01996-11-12Per Hedbor {
1e257d1996-12-03Per Hedbor  return /*"<br clear=all>"*/"";
b1fca01996-11-12Per Hedbor } string default_head(string h, string|void save) {
b2c3871996-12-04Per Hedbor  return ("<head><title>"+h+"</title></head>\n"+ BODY+"\n");
b1fca01996-11-12Per Hedbor } object find_node(string l) { array tmp = l/"/"-({""}); object o; if(!sizeof(tmp)) return root; for(o=root; sizeof(tmp) && (o=o->descend(tmp[0],1)); tmp=tmp[1..1000]); if(!o) return 0; return o; } mapping file_image(string img) { object o; o=open("roxen-images/"+img, "r"); if (!o) return 0; return ([ "file":o, "type":"image/" + ((img[-1]=='f')?"gif":"jpeg"), ]); } #define CONFIG_URL roxen->config_url() mapping save_it(object id, object o) { id->referer = ({ CONFIG_URL + o->path(1) }); root->save();
14179b1997-01-29Per Hedbor  roxen->update_supports_from_roxen_com(); roxen->initiate_configuration_port( 0 );
b1fca01996-11-12Per Hedbor } mapping stores( string s ) { return ([ "data":replace(s, "$docurl", roxen->docurl), "type":"text/html", "extra_heads": ([ "Title":"Roxen Challenger maintenance",
9165e01996-12-06Per Hedbor // "Expires":http_date(time(1)+2), // "Pragma":"no-cache",
b1fca01996-11-12Per Hedbor  "Last-Modified":http_date(time(1)), ]) ]); }
14179b1997-01-29Per Hedbor object find_module(string name, object in)
b1fca01996-11-12Per Hedbor { mapping mod; object o; string s; int i; name = lower_case(name); if(!sscanf(name, "%s#%d", name, i)) { #ifdef MODULE_DEBUG #if defined(DEBUG) && (DEBUG > 1000) perror("Modulename not in short form: "+name+"\n"); #endif #endif
14179b1997-01-29Per Hedbor  foreach(values(in->modules), mod)
b1fca01996-11-12Per Hedbor  { if(mod->copies) { foreach(values(mod->copies), o) if(lower_case(s=name_of_module(o)) == name) return o; } else if(mod->enabled && (lower_case(s=name_of_module(mod->enabled))==name)) return mod->enabled; } } else { mapping modules; #ifdef MODULE_DEBUG #if defined(DEBUG) && (DEBUG > 1000) perror("Modulename in short form: "+name+"#"+i+"\n"); #endif #endif
14179b1997-01-29Per Hedbor  modules = in->modules;
b1fca01996-11-12Per Hedbor  if(modules[name]) { if(modules[name]->copies) return modules[name]->copies[i]; else if(modules[name]->enabled) return modules[name]->enabled; } } return 0; } mixed decode_form_result(string var, int type, object node, mapping allvars) { switch(type) {
f6d62d1997-03-26Per Hedbor  case TYPE_CUSTOM: return node->data[ VAR_MISC ][2]( var, type, node, allvars );
b1fca01996-11-12Per Hedbor  case TYPE_MODULE_LIST:
5e89211997-02-13Per Hedbor  return map(var/"\000", find_module);
b1fca01996-11-12Per Hedbor  case TYPE_MODULE:
14179b1997-01-29Per Hedbor  return find_module(var, node->config());
b1fca01996-11-12Per Hedbor  case TYPE_PORTS: /* Encoded like this: new_port --> Add a new port ok[_<ID>] --> Save the value for all or one port delete_<ID> --> Delete a port ---- { A port is defined by: port_<ID> == INT protocol_<ID> == STRING ip_number_<ID> == STRING arguments_<ID> == STRING } ---- */ if(allvars->new_port) return node->data[VAR_VALUE] + ({ ({ 80, "http", "ANY", "" }) }); array op = copy_value(node->data[VAR_VALUE]); int i; for(i = 0; i<sizeof(op); i++) { if(!allvars["delete_"+i]) { if(allvars["other_"+i] && (allvars["other_"+i] != op[i][2])) { allvars["ip_number_"+i] = allvars["other_"+i]; ip_number_list += ({ allvars["other_"+i] }); } op[i][0] = (int)allvars["port_"+i]||op[i][0]; op[i][1] = allvars["protocol_"+i]||op[i][1]; op[i][2] = allvars["ip_number_"+i]||op[i][2]; op[i][3] = allvars["arguments_"+i]||op[i][3]; } else // Delete this port. op[i]=0; } return op - ({ 0 }); case TYPE_DIR_LIST: array foo;
5e89211997-02-13Per Hedbor  foo=map((var-" ")/",", lambda(string var, object node) {
b1fca01996-11-12Per Hedbor  if (!strlen( var ) || file_size( var ) != -2) { if(node->error) node->error += ", " +var + " is not a directory"; else node->error = var + " is not a directory"; return 0; } if(var[-1] != '/') return var + "/"; return var; }, node); if(sizeof(foo-({0})) != sizeof(foo)) return 0; return foo; case TYPE_DIR:
48fa361997-04-05Per Hedbor  array st;
8e727d1997-03-11Per Hedbor  if (!strlen( var ) || !(st = file_stat( var )) || (st[1] != -2))
b1fca01996-11-12Per Hedbor  { node->error = var + " is not a directory"; return 0; } if(var[-1] != '/') return var + "/"; return var; case TYPE_TEXT_FIELD: var -= "\r";
8e727d1997-03-11Per Hedbor  case TYPE_FONT:
b1fca01996-11-12Per Hedbor  case TYPE_STRING: case TYPE_FILE: case TYPE_LOCATION: return var; case TYPE_PASSWORD: return crypt(var); case TYPE_FLAG: return lower_case(var) == "yes"; case TYPE_INT: int tmp; if (!sscanf( var, "%d", tmp )) { node->error= var + " is not an integer"; return 0; } return tmp; case TYPE_FLOAT: float tmp; if (!sscanf( var, "%f", tmp )) { node->error= var + " is not a arbitary precision floating point number"; return 0; } return tmp; case TYPE_INT_LIST: if(node->data[VAR_MISC]) return (int)var; else
5e89211997-02-13Per Hedbor  return map((var-" ")/",", lambda(string s){
b1fca01996-11-12Per Hedbor  return (int)s; }); case TYPE_STRING_LIST: if(node->data[VAR_MISC]) return var; else return (var-" ")/","; case TYPE_COLOR: int red, green, blue; if (sscanf( var, "%d:%d:%d", red, green, blue ) != 3 || red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) { node->error = var + " is not a valid color specification"; return 0; } return (red << 16) + (green << 8) + blue; } error("Unknown type.\n"); } mapping std_redirect(object o, object id) { string loc, l2; if(!o) o=root; if(id && sizeof(id->referer)) loc=((((((id->referer*" ")/"#")[0])/"?")[0])+"?"+(bar++) +"#"+o->path(1)); else loc = CONFIG_URL+o->path(1)[1..10000]+"?"+bar++; if(sscanf(loc, "%s/(%*s)%s",l2, loc) == 3) loc = l2 + loc; // Remove the prestate. // http://www:22020//Configuration/ -> http://www:22202/Configurations/ loc = replace(replace(replace(loc, "://", ""), "//", "/"), "", "://"); return http_redirect(http_decode_string(loc)); } string configuration_list() { string res=""; object o; foreach(roxen->configurations, o) res += "<option>Copy of '"+o->name+"'"; return res; } string new_configuration_form() {
5e89211997-02-13Per Hedbor  return replace(default_head("")+ read_bytes("etc/newconfig.html"), ({"$COPIES","$configurl"}),
b1fca01996-11-12Per Hedbor  ({configuration_list(),CONFIG_URL})) +
38dca81996-12-10Per Hedbor  "\n\n</body>";
b1fca01996-11-12Per Hedbor } mapping module_nomore(string name, int type, object conf) { mapping module; object o; // perror("Module: "+name+"\n"); if((module = conf->modules[name]) && (!module->copies && module->enabled)) return module; if(((type & MODULE_DIRECTORIES) && (o=conf->dir_module))
f2549a1997-06-09Henrik Grubbström (Grubba)  || ((type & MODULE_AUTH) && (o=conf->auth_module)) || ((type & MODULE_TYPES) && (o=conf->types_module))
b1fca01996-11-12Per Hedbor  || ((type & MODULE_MAIN_PARSER) && (o=conf->parse_module))) return conf->modules[conf->otomod[o]]; } mixed new_module_copy(object node, string name, object id) { object orig; int i; mapping module; module = node->config()->modules[name]; switch(node->type) { default: error("Foo? Illegal node in new_module_copy\n"); case NODE_MODULE_COPY: node=node->up; case NODE_MODULE_MASTER_COPY: case NODE_MODULE: node=node->up; case NODE_CONFIGURATION: } if(module) if(module->copies) while(module->copies[i]) i++;
14179b1997-01-29Per Hedbor  orig = node->config()->enable_module(name+"#"+i);
a52cc61996-11-20Per Hedbor 
14179b1997-01-29Per Hedbor  if(!orig) return http_string_answer("This module could not be enabled.\n");
a52cc61996-11-20Per Hedbor 
14179b1997-01-29Per Hedbor  module = node->config()->modules[name];
b1fca01996-11-12Per Hedbor  node = node->descend(module->name); // Now it is the (probably unbuilt) module main node... node->data = module; node->describer = describe_module; node->type = NODE_MODULE; build_module(node); // We want to see the new module.. node->folded=0; // If the module have copies, select the actual copy added.. if(module->copies) node = node->descend((string)i, 1); // Now it is the module.. // We want to see this one immediately.
5b38191996-12-13Per Hedbor  if(node) { node->folded = 0; // Mark the node and all its parents as modified. node->change(1); }
b1fca01996-11-12Per Hedbor  return std_redirect(root, id); } mixed new_module_copy_copy(object node, object id) { return new_module_copy(node, node->data->sname, id); } string new_module_form(object id, object node) { int i; mixed a,b;
fd0b6f1996-12-02Per Hedbor  string q;
b1fca01996-11-12Per Hedbor  array mods;
fd0b6f1996-12-02Per Hedbor  array (string) res;
b1fca01996-11-12Per Hedbor  if(!roxen->allmodules || sizeof(id->pragma)) {
8e727d1997-03-11Per Hedbor  werror("CONFIG: Rescanning modules.\n"); roxen->current_configuration = node->config(); roxen->rescan_modules(); roxen->current_configuration = 0; werror("CONFIG: Done.\n");
b1fca01996-11-12Per Hedbor  } a=roxen->allmodules; mods=sort_array(indices(a), lambda(string a, string b, mapping m) { return m[a][0] > m[b][0]; }, a);
fd0b6f1996-12-02Per Hedbor  res = ({default_head("Add a module")+"\n\n"+ "<h2>Select a module to add from the list below</h2>" });
b1fca01996-11-12Per Hedbor 
fd0b6f1996-12-02Per Hedbor  foreach(mods, q) {
5f450a1996-12-02Per Hedbor  if(b = module_nomore(q, a[q][2], node->config()))
b1fca01996-11-12Per Hedbor  {
fd0b6f1996-12-02Per Hedbor  if(b->sname != q) res += ({("<p>"+ (roxen->QUERY(BS)?"<h2>"+a[q][0]+"</h2>":
8691921997-06-12Henrik Grubbström (Grubba)  "<img alt=\""+a[q][0]+"\" src=/auto/module/" + a[q][2]+"/"+
f92b7a1997-05-26Henrik Grubbström (Grubba)  q+" height=24 width=500>")+ "<br><blockquote>" + a[q][1] + "<p><i>A module of the same type is already enabled (" + b->name + "). <a href=\"/(delete)" + node->descend(b->name, 1)->path(1) + "?" + (bar++) +
b1fca01996-11-12Per Hedbor  "\">Disable that module</a> if you want this one insted</i>"
5b38191996-12-13Per Hedbor  "\n<p><br><p></blockquote>")});
fd0b6f1996-12-02Per Hedbor  } else {
99283f1996-12-02Per Hedbor  res += ({"<p><a href=/(newmodule)"+node->path(1)+"?"+q+"=1>"+
8aff8d1996-12-02Per Hedbor  (roxen->QUERY(BS)?"<h2>"+a[q][0]+"</h2>":
fd0b6f1996-12-02Per Hedbor  "<img border=0 alt=\""+a[q][0]+"\" src=/auto/module/"+
8691921997-06-12Henrik Grubbström (Grubba)  a[q][2]+"/"+q+" height=24 width=500>")+
5b38191996-12-13Per Hedbor  "</a><blockquote><br>"+a[q][1]+"<p><br><p></blockquote>"});
b1fca01996-11-12Per Hedbor  }
fd0b6f1996-12-02Per Hedbor  }
5b38191996-12-13Per Hedbor  return res*"";
b1fca01996-11-12Per Hedbor } mapping new_module(object id, object node) { string varname; if(!sizeof(id->variables)) return stores(new_module_form(id, node)); varname=indices(id->variables)[0]; return new_module_copy(node, varname, id); } int low_enable_configuration(string name, string type) { object node; if(strlen(name) && name[-1] == '~') name = ""; if(search(name, "/")!= -1) return 0; foreach(roxen->configurations, node) if(node->name == name) return 0; switch(name) { case "": case " ": case "\t": case "CVS": case "Global Variables": case "global variables": case "Global variables": return 0; break; default: object o, confnode; switch(lower_case((type/" ")[0])) { default: /* Minimal configuration */
14179b1997-01-29Per Hedbor  o=roxen->enable_configuration(name);
b1fca01996-11-12Per Hedbor  break; case "standard":
14179b1997-01-29Per Hedbor  o = roxen->enable_configuration(name); o->enable_module("cgi#0"); o->enable_module("contenttypes#0"); o->enable_module("ismap#0"); o->enable_module("pikescript#0"); o->enable_module("htmlparse#0"); o->enable_module("directories#0"); o->enable_module("userdb#0"); o->enable_module("userfs#0"); // I _think_ we want this. o->enable_module("filesystem#0");
b1fca01996-11-12Per Hedbor  break; case "ipp":
14179b1997-01-29Per Hedbor  o=roxen->enable_configuration(name); o->enable_module("contenttypes#0"); o->enable_module("ismap#0"); o->enable_module("htmlparse#0"); o->enable_module("directories#0"); o->enable_module("filesystem#0");
b1fca01996-11-12Per Hedbor  break; case "proxy":
14179b1997-01-29Per Hedbor  o=roxen->enable_configuration(name); o->enable_module("proxy#0"); o->enable_module("gopher#0"); o->enable_module("ftpgateway#0"); o->enable_module("contenttypes#0"); o->enable_module("wais#0");
b1fca01996-11-12Per Hedbor  break; case "copy": string from; mapping tmp; sscanf(type, "%*s'%s'", from); tmp = roxen->copy_configuration(from, name); if(!tmp) error("No configuration to copy from!\n");
48fa361997-04-05Per Hedbor  tmp["spider#0"]->LogFile = "../logs/"+roxenp()->short_name(name)+"/Log"; roxenp()->save_it(name);
b1fca01996-11-12Per Hedbor  roxen->enable_configuration(name); } confnode = root->descend("Configurations"); node=confnode->descend(name); node->describer = describe_configuration; node->saver = save_configuration; node->data = roxen->configurations[-1]; node->type = NODE_CONFIGURATION; build_configuration(node); node->folded=0; node->change(1); if(o = node) { if(o=o->descend( "Global", 1 )) { o->folded = 0; if(o->descend( "Server URL", 1 )) { o->descend( "Server URL" )->folded = 0; o->descend( "Server URL" )->change(1); } if(o->descend( "Listen ports", 1 )) { o->descend( "Listen ports" )->folded = 0; o->descend( "Listen ports" )->change(1); } } } if(lower_case((type/" ")[0])=="standard" && (o=node)) { if(o=o->descend( "Filesystem", 1 )) { o->folded=0; if(o=o->descend( "0", 1)) { o->folded=0; if(o=o->descend( "Search path", 1)) { o->folded=0; o->change(1); } } } } } return 1; } mapping new_configuration(object id) { if(!sizeof(id->variables)) return stores(new_configuration_form()); if(!id->variables->name) return stores(default_head("Bad luck")+
38dca81996-12-10Per Hedbor  "<blockquote><h1>No configuration name?</h1>"
b1fca01996-11-12Per Hedbor  "Either you entered no name, or your WWW-browser "
19104e1996-12-07Per Hedbor  "failed to include it in the request</blockquote>");
b1fca01996-11-12Per Hedbor  id->variables->name=(replace(id->variables->name,"\000"," ")/" "-({""}))*" "; if(!low_enable_configuration(id->variables->name, id->variables->type)) return stores(default_head("Bad luck") +
38dca81996-12-10Per Hedbor  "<blockquote><h1>Illegal configuration name</h1>"
b1fca01996-11-12Per Hedbor  "The name of the configuration must contain characters" " other than space and tab, it should not end with " "~, and it must not be 'CVS', 'Global Variables' or " "'global variables', nor the name of an existing "
19104e1996-12-07Per Hedbor  "configuration, and the character '/' cannot be included</blockquote>");
b1fca01996-11-12Per Hedbor  return std_redirect(root->descend("Configurations"), id); } int conf_auth_ok(mixed auth) { if(!(auth && sizeof(auth)>1)) return 0; if(sscanf(auth[1], "%s:%s", auth[0], auth[1]) < 2) return 0; if((auth[0] == roxen->QUERY(ConfigurationUser)) && crypt(auth[1], roxen->QUERY(ConfigurationPassword))) return 1; } mapping initial_configuration(object id) { object n2; string res, error; if(id->prestate->initial && id->variables->pass) { error=""; if(id->variables->pass != id->variables->pass2) error = "You did not type the same password twice.\n"; if(!strlen(id->variables->pass)) error += "You must specify a password.\n"; if(!strlen(id->variables->user)) error += "You must specify a username.\n"; if(!strlen(error)) { object node; /* build_root(root);*/ // Should find the real node instead of assuming 'Globals'... node = find_node("/Globals"); node->folded=0; node->change(1); if(!node) return stores("Fatal configuration error, no 'Globals' node found.\n"); roxen->QUERY(ConfigurationPassword) = crypt(id->variables->pass); roxen->QUERY(ConfigurationUser) = id->variables->user; n2 = node->descend("Configuration interface", 1)->descend("Password", 1); n2->data[VAR_VALUE]=roxen->QUERY(ConfigurationPassword); n2->change(1); n2 = node->descend("Configuration interface", 1)->descend("User", 1); n2->data[VAR_VALUE] = roxen->QUERY(ConfigurationUser); n2->change(1); root->save(); return std_redirect(root, id); } }
88e1cb1996-12-07David Hedbor  res = default_head("Welcome to Roxen Challenger");
b1fca01996-11-12Per Hedbor 
675b351996-11-13David Hedbor  res += read_bytes("etc/welcome.html");
b1fca01996-11-12Per Hedbor  if(error && strlen(error))
38dca81996-12-10Per Hedbor  res += "<blockquote>\n<p><b>"+error+"</b>";
b1fca01996-11-12Per Hedbor  res += ("<pre>" "<font size=+1>" "<form action=/(initial)/Globals/>" " User name <input name=user type=string>\n" " Password <input name=pass type=password>\n" " Again <input name=pass2 type=password>\n"
f92b7a1997-05-26Henrik Grubbström (Grubba) // Avoid this trap for people who like to shoot themselves in the foot.
c6d6a71996-12-02Peter Bortas // /Peter // "IP-pattern <input name=pattern type=string>\n"
b1fca01996-11-12Per Hedbor  " <input type=submit value=\"Use these values\">\n"
19104e1996-12-07Per Hedbor  "</form></font></pre></blockquote>");
b1fca01996-11-12Per Hedbor  return stores(res); } object module_of(object node) { while(node) { if(node->type == NODE_MODULE_COPY) return node->data; if(node->type == NODE_MODULE_MASTER_COPY) return node->data->master; node = node->up; } return roxen; } string extract_almost_top(object node) {
1e257d1996-12-03Per Hedbor  if(!node) return ""; for(;node && (node->up!=root);node=node->up); if(!node) return "";
b1fca01996-11-12Per Hedbor  return node->path(1); }
1e257d1996-12-03Per Hedbor  string tablist(array(string) nodes, array(string) links, int selected) { array res = ({}); for(int i=0; i<sizeof(nodes); i++) if(i!=selected)
f320281997-05-28Per Hedbor  PUSH("<a href=\""+links[i]+"\"><img alt=\"_/"+ nodes[i][1..strlen(nodes[i])-2]+"\\__\" src=/auto/unselected/"+ replace(nodes[i]," ","%20")+" border=0></a>");
1e257d1996-12-03Per Hedbor  else
f320281997-05-28Per Hedbor  PUSH("<a href=\""+links[i]+"\"><b><img alt=\"_/"+ nodes[i][1..strlen(nodes[i])-2]+"\\__\" src=/auto/selected/"+ replace(nodes[i]," ","%20")+" border=0></b></a>"); //PUSH("<br>");
1e257d1996-12-03Per Hedbor  return res*""; }
b1fca01996-11-12Per Hedbor mapping (string:string) selected_nodes = ([ "Configurations":"/Configurations", "Globals":"/Globals", "Status":"/Status", "Errors":"/Errors",
1e257d1996-12-03Per Hedbor ]);
b1fca01996-11-12Per Hedbor 
5e89211997-02-13Per Hedbor array tabs = ({
1e257d1996-12-03Per Hedbor  "Configurations", "Globals", "Status", "Errors",
b1fca01996-11-12Per Hedbor });
5e89211997-02-13Per Hedbor array tab_names = ({
2de6921996-12-03Per Hedbor  " Virtual servers ", " Global variables ", " Status info ", " Error log ",
1e257d1996-12-03Per Hedbor });
b1fca01996-11-12Per Hedbor  string display_tabular_header(object node) { string p, s;
1e257d1996-12-03Per Hedbor  array links = ({ selected_nodes[tabs[0]]+"?"+(bar++), selected_nodes[tabs[1]]+"?"+(bar++), selected_nodes[tabs[2]]+"?"+(bar++), selected_nodes[tabs[3]]+"?"+(bar++), });
f320281997-05-28Per Hedbor  if(node != root) { s = extract_almost_top(node) - "/"; selected_nodes[s] = node->path(1); links[search(tabs,s)]="/"+s+"/"+"?"+(bar++); }
1e257d1996-12-03Per Hedbor  return tablist(tab_names, links, search(tabs,s));
b1fca01996-11-12Per Hedbor } // Return the number of unfolded nodes on the level directly below the passed // node. int nunfolded(object o) { int i; if(o = o->down) do { i+=!o->folded; } while(o=o->next); return i; }
fd0b6f1996-12-02Per Hedbor 
5e89211997-02-13Per Hedbor object module_font = get_font("base_server/config/font",0,0,0,"left",1.0,1.0); object button_font = get_font("base_server/config/button_font",0,0,0,"left",1.0,1.0);
fd0b6f1996-12-02Per Hedbor  mapping auto_image(string in, object id) { string key, value;
1e257d1996-12-03Per Hedbor  array trans = ({ (int)("0x"+dR),(int)("0x"+dG),(int)("0x"+dB) });
fd0b6f1996-12-02Per Hedbor  mapping r; mixed e;
1e257d1996-12-03Per Hedbor  object i;
f320281997-05-28Per Hedbor  string img_key = "auto/"+replace(in,"/","_")+".gif"-" "; if(e=file_image(img_key)) return e;
a6cdc51996-12-04Per Hedbor  if(!sscanf(in, "%s/%s", key, value)) key=in;
1e257d1996-12-03Per Hedbor 
fd0b6f1996-12-02Per Hedbor  switch(key) { case "module":
8691921997-06-12Henrik Grubbström (Grubba)  sscanf(value, "%*d/%s", value); i = draw_module_header(roxen->allmodules[value][0], roxen->allmodules[value][2], module_font); break;
1e257d1996-12-03Per Hedbor 
fdee9d1996-12-02Per Hedbor  case "button":
8691921997-06-12Henrik Grubbström (Grubba)  int lm,rm; if(sscanf(value, "lm/%s", value)) lm=1; if(sscanf(value, "rm/%s", value)) rm=1; i=draw_config_button(value,button_font,lm,rm); break;
1e257d1996-12-03Per Hedbor  case "fold": case "fold2":
8691921997-06-12Henrik Grubbström (Grubba)  i = draw_fold((int)reverse(key)); break;
1e257d1996-12-03Per Hedbor  case "unfold": case "unfold2":
8691921997-06-12Henrik Grubbström (Grubba)  i = draw_unfold((int)reverse(key)); break;
1e257d1996-12-03Per Hedbor  case "back":
8691921997-06-12Henrik Grubbström (Grubba)  i = draw_back((int)reverse(key)); break;
1e257d1996-12-03Per Hedbor  case "selected":
8691921997-06-12Henrik Grubbström (Grubba)  i=draw_selected_button(value,button_font); break;
fdee9d1996-12-02Per Hedbor 
1e257d1996-12-03Per Hedbor  case "unselected":
8691921997-06-12Henrik Grubbström (Grubba)  i=draw_unselected_button(value,button_font); break;
fd0b6f1996-12-02Per Hedbor  }
676c231996-12-06Per Hedbor  if(i) {
f320281997-05-28Per Hedbor  object o = open("roxen-images/"+img_key,"wct"); e=i->map_closest(i->select_colors(64)+({trans}))->togif(@trans); i=0; if(o) { o->write(e); o=0; } #ifdef DEBUG else {perror("Cannot open file for "+in+"\n");} #endif return http_string_answer(e,"image/gif");
676c231996-12-06Per Hedbor  }
f320281997-05-28Per Hedbor  return 0;
fd0b6f1996-12-02Per Hedbor }
fdee9d1996-12-02Per Hedbor 
b2c3871996-12-04Per Hedbor string remove_font(string t, mapping m, string c) { return "<b>"+c+"</b>"; }
ae32fc1996-12-05Per Hedbor int nfolded(object o) { int i; if(o = o->down) do { i+=!!o->folded; } while(o=o->next); return i; } int nfoldedr(object o) { object node; int i; i = o->folded; node=o->down; while(node) { i+=nfoldedr(node); node=node->next; } return i; }
b1fca01996-11-12Per Hedbor mapping configuration_parse(object id) {
fdee9d1996-12-02Per Hedbor  array (string) res=({}); string tmp;
b1fca01996-11-12Per Hedbor  // Is it an image?
fdee9d1996-12-02Per Hedbor  if(sscanf(id->not_query, "/image/%s", tmp)) return file_image(tmp) || (["data":"No such image"]);
b1fca01996-11-12Per Hedbor  object o; int i; id->since = 0; // We do not want 'get-if-modified-since' to work here. // Permisson denied by address? if(id->remoteaddr) if(strlen(roxen->QUERY(ConfigurationIPpattern)) &&
5e4ede1996-11-12Per Hedbor  !glob(roxen->QUERY(ConfigurationIPpattern),id->remoteaddr))
b1fca01996-11-12Per Hedbor  return stores("Permission denied.\n"); // Permission denied by userid? if(!id->misc->read_allow) { if(!(strlen(roxen->QUERY(ConfigurationPassword)) && strlen(roxen->QUERY(ConfigurationUser)))) return initial_configuration(id); // Never configured before else if(!conf_auth_ok(id->auth)) return http_auth_failed("Roxen server maintenance"); // Denied } else {
5e4ede1996-11-12Per Hedbor  id->prestate = aggregate_multiset(@indices(id->prestate) &({"fold","unfold"}));
b1fca01996-11-12Per Hedbor  if(sizeof(id->variables)) // This is not 100% neccesary, really. id->variables = ([ ]); }
f320281997-05-28Per Hedbor  // Automatically generated image?
fdee9d1996-12-02Per Hedbor  if(sscanf(id->not_query, "/auto/%s", tmp)) return auto_image(tmp,id) || (["data":"No such image"]);
fd0b6f1996-12-02Per Hedbor 
b1fca01996-11-12Per Hedbor  o = find_node(id->not_query); // Find the requested node (from the filename) if(!o) // Bad node, perhaps an old bookmark or something. { id->referer = ({ }); return std_redirect(0, id); } else if(o == root) { // The URL is http://config-url/, not one of the top nodes, but // _above_ them. This is supposed to be some nice introductory // text about the configuration interface...
88e1cb1996-12-07David Hedbor  return http_string_answer(default_head("Roxen Challenger")+
5e89211997-02-13Per Hedbor  display_tabular_header(root)+ read_bytes("etc/config.html"),"text/html");
b1fca01996-11-12Per Hedbor  } if(sizeof(id->prestate)) { switch(indices(id->prestate)[0]) { // It is possible to mark variables as 'VAR_EXPERT', this // will make it impossible to configure them whithout the // 'expert' mode. It can be useful. case "expert": expert_mode = 1; break; case "noexpert": expert_mode = 0; break; // Fold and unfold nodes, this is _very_ simple, once all the // supporting code was writte. case "fold": o->folded=1; break; case "unfold": o->folded=0; break;
676c231996-12-06Per Hedbor  case "moredocs": o->moredocs=1; break; case "lessdocs": o->moredocs=0; break;
b1fca01996-11-12Per Hedbor  case "foldall": o->map(lambda(object o) { o->folded=1; }); break; case "unfoldmodified": o->map(lambda(object o) { if(o->changed) o->folded=0; }); break; // There is no button for this in the configuration interface, // the results are quite horrible, especially when applied to // one of the top nodes. case "unfoldall": o->map(lambda(object o) { o->folded=0; }); break;
ae32fc1996-12-05Per Hedbor  case "unfoldlevel": object node; node=o->down; while(node) { node->folded=0; node = node->next; } break;
b1fca01996-11-12Per Hedbor  // And now the actual actions.. // Re-read a module from disk // This is _not_ as easy as it sounds, since quite a lot of
17495a1997-06-02Henrik Grubbström (Grubba)  // caches and stuff have to be invalidated..
b1fca01996-11-12Per Hedbor  case "refresh": case "reload": object mod; string name, modname; mapping cmod; mod = module_of(o); if(!mod || mod==roxen) error("This module cannot be updated.\n");
14179b1997-01-29Per Hedbor  name = module_short_name(mod, o->config());
b1fca01996-11-12Per Hedbor  if(!name) error("This module cannot be updated"); sscanf(name, "%s#%*s", modname);
14179b1997-01-29Per Hedbor 
b1fca01996-11-12Per Hedbor  if(!(cmod = o->config()->modules[ modname ])) error("This module cannot be updated"); o->save(); cache_remove("modules", modname);
f2549a1997-06-09Henrik Grubbström (Grubba)  // Not usefull since load_module() also does it. // _master->set_inhibit_compile_errors("");
b1fca01996-11-12Per Hedbor 
14179b1997-01-29Per Hedbor  if(!o->config()->load_module(modname))
b1fca01996-11-12Per Hedbor  { mapping rep; rep = http_string_answer("The reload of this module failed.\n" "This is (probably) the reason:\n<pre>"
f2549a1997-06-09Henrik Grubbström (Grubba)  + roxen->last_error + "</pre>" ); // _master->set_inhibit_compile_errors(0);
b1fca01996-11-12Per Hedbor  return rep; }
f2549a1997-06-09Henrik Grubbström (Grubba)  // _master->set_inhibit_compile_errors(0);
b1fca01996-11-12Per Hedbor  object mod;
14179b1997-01-29Per Hedbor  if(!o->config()->disable_module(name))error("Failed to disable module.\n"); if(!(mod=o->config()->enable_module(name)))error("Failed to enable module.\n");
b1fca01996-11-12Per Hedbor  o->clear();
14179b1997-01-29Per Hedbor // roxen->fork_it();
b1fca01996-11-12Per Hedbor  if(mappingp(o->data)) { o->data = o->config()->modules[modname]; build_module(o); } else { object n = o->up; n->clear(); n->data = n->config()->modules[modname]; build_module(n); } break; /* Shutdown Roxen... */ case "shutdown": return roxen->shutdown(); /* Restart Roxen, somewhat more nice. */ case "restart": return roxen->restart(); /* Rename a configuration. Not Yet Used... */ case "rename": if(o->type == NODE_CONFIGURATION) { mv("configurations/"+o->data->name, "configurations/"+id->variables->name); o->data->name=id->variables->name; } break; /* This only asks "do you really want to...", it does not delete * the node */ case "delete":
fdee9d1996-12-02Per Hedbor  PUSH(default_head("Roxen Configuration"));
1e257d1996-12-03Per Hedbor // PUSH("<hr noshade>");
b1fca01996-11-12Per Hedbor  switch(o->type) { case NODE_CONFIGURATION:
fdee9d1996-12-02Per Hedbor  PUSH("<font size=+2>Do you really want to delete the configuration "+ o->data->name + ", all its modules and their copies?" "\n\n<p></font>");
b1fca01996-11-12Per Hedbor  break; case NODE_MODULE_MASTER_COPY: case NODE_MODULE:
fdee9d1996-12-02Per Hedbor  PUSH("<font size=+2>Do you really want to delete the module "+ o->data->name + ", and its copies?\n\n<p></font>");
b1fca01996-11-12Per Hedbor  break; case NODE_MODULE_COPY_VARIABLES: case NODE_MODULE_COPY:
fdee9d1996-12-02Per Hedbor  PUSH("<font size=+2>Do you really want to delete this copy " " of the module "+ o->up->data->name + "?\n\n<p></font>");
b1fca01996-11-12Per Hedbor  break; case NODE_CONFIGURATIONS: return stores("You don't want to do that...\n"); }
19104e1996-12-07Per Hedbor  PUSH("<blockquote><font size=+2><i>This action cannot be undone.\n\n<p></font>"+
fdee9d1996-12-02Per Hedbor  TABLEP("<table>", "") +"<tr><td><form action="+ o->path(1)+">" "<input type=submit value=\"No, I do not want to delete it\"> " "</form></td><td><form action=/(really_delete)"+o->path(1)+ "><input type=submit value=\"Go ahead\"></form></td></tr> "
19104e1996-12-07Per Hedbor  "</table></blockquote>");
b1fca01996-11-12Per Hedbor 
fdee9d1996-12-02Per Hedbor  return stores(res*"");
b1fca01996-11-12Per Hedbor  break; /* When this has been called, the node will be * _very_ deleted * The amount of work needed to delete a node does vary * depending on the node, since there is no 'zap' function in * the nodes at the moment. I will probably move this code into * function-pointers in the nodes. */ case "really_delete": id->referer = ({ CONFIG_URL + o->up->path(1) }); switch(o->type) { case NODE_CONFIGURATION: object oroot; for(i=0; i<sizeof(roxen->configurations); i++) if(roxen->configurations[i] == o->data) break; if(i==sizeof(roxen->configurations)) error("Configuration not found.\n"); roxen->remove_configuration(o->data->name); if(roxen->configurations[i]->ports_open)
5e89211997-02-13Per Hedbor  map(values(roxen->configurations[i]->ports_open), destruct);
b1fca01996-11-12Per Hedbor  destruct(roxen->configurations[i]); roxen->configurations = roxen->configurations[..i-1] + roxen->configurations[i+1..]; o->change(-o->changed); o->dest(); break; case NODE_MODULE_COPY_VARIABLE: case NODE_MODULE_COPY_VARIABLES: // Ehum? Lets zap the module instead of it's variables... o=o->up; case NODE_MODULE_COPY: string name; object n;
14179b1997-01-29Per Hedbor  name = module_short_name(o->data, o->config());
f2f72b1997-02-07Niels Möller  o->config()->disable_module(name);
b1fca01996-11-12Per Hedbor  // Remove the suitable part of the configuration file.
f2f72b1997-02-07Niels Möller  roxen->remove(name, o->config());
b1fca01996-11-12Per Hedbor  o->change(-o->changed); n=o->up; o->dest(); if(!objectp(n)) { o=root; // Error, really, no parent module for this module class. } else { if(!sizeof(n->data->copies)) { // No more instances in this module, let's zap the whole class. /* object hmm=n->config(); if(!hmm) error("Cannot find configuration node for module.\n"); */ // The configuration node. n->config() seems to be // n->up->data... o=n->up; n->change(-n->changed); n->dest(); build_configuration(o); return std_redirect(o, 0); // Bugs and returns to the top if id is set... } else o = n; } break; case NODE_MODULE_MASTER_COPY: case NODE_MODULE: // A 'one of a kind' module. if(o->data->copies) { if(sizeof(o->data->copies)) { int i; array a,b; a=indices(o->data->copies); b=values(o->data->copies); name=o->config()->otomod[b[0]]; i=sizeof(a); while(i--) {
14179b1997-01-29Per Hedbor  o->config()->disable_module(name+"#"+a[i]); roxen->remove(name+"#"+a[i], o->config());
b1fca01996-11-12Per Hedbor  } } else if(o->data->master) { name=o->config()->otomod[o->data->enabled]; } } else if(o->data->enabled) { name=o->config()->otomod[o->data->enabled];
14179b1997-01-29Per Hedbor  o->config()->disable_module(name+"#0"); roxen->remove(name+"#0", o->config());
b1fca01996-11-12Per Hedbor  } o->change(-o->changed); o->dest(); break; } break; // Create a new configuration. All the work is done in another // function.. This _should_ be the case with some of the other // actions too. case "newconfig": id->referer = ({ CONFIG_URL + o->path(1) }); return new_configuration(id); // Save changes done to the node 'o'. Currently 'o' is the root // node most of the time, thus saving _everything_. case "save": if(save_it(id, o)) return 0; break; // Set the password and username, the first time, or when // the action 'changepass' is requested. case "initial": case "changepass": return initial_configuration(id); // Hmm. No idea, really. Beats me :-) /Per case "new": o->new(); break; // Add a new module to the current configuration. case "newmodule": id->referer = ({ CONFIG_URL + o->path(1) }); return new_module(id,o); // Add a new copy of the current module to the current configuration. case "newmodulecopy": id->referer = ({ CONFIG_URL + o->path(1) }); new_module_copy_copy(o, id); break; // Set a variable to a new (or back to an old..) value. case "set": mixed tmp; o->error = 0; if(sizeof(id->variables)) tmp=decode_form_result(values(id->variables)[0], o->data[VAR_TYPE], o, id->variables); else tmp=0; if(!module_of(o)) perror("No module for this node.\n"); if(!o->error && module_of(o) && module_of(o)->check_variable) o->error = module_of(o)->check_variable(o->data[VAR_SHORTNAME], tmp); if(!o->error) if(!equal(tmp, o->data[VAR_VALUE])) { if(!o->original) o->original = o->data[VAR_VALUE]; o->data[VAR_VALUE]=tmp; if(equal(o->original, tmp)) o->change(-1); else if(!o->changed) o->change(1); } break; } return std_redirect(o, id); }
fdee9d1996-12-02Per Hedbor  PUSH(default_head("Roxen server configuration", root->changed?o->path(1):0));
676c231996-12-06Per Hedbor  PUSH("<dl>\n");
ae32fc1996-12-05Per Hedbor  PUSH("\n"+display_tabular_header( o )+"\n");
676c231996-12-06Per Hedbor  PUSH("<p>"); if(o->up != root && o->up)
fdee9d1996-12-02Per Hedbor  PUSH("<a href=\""+ o->up->path(1)+"?"+(bar++)+"\">"
b2c3871996-12-04Per Hedbor  "<img src=/auto/back alt='[Up]' align=left hspace=0 border=0></a>\n");
b1fca01996-11-12Per Hedbor  if(i=o->folded) o->folded=0;
b2c3871996-12-04Per Hedbor  string tmp = o->describe(1); if(!id->supports->font) tmp = parse_html(tmp, ([]),(["font":remove_font, ])); PUSH(tmp);
b1fca01996-11-12Per Hedbor  o->folded=i;
38dca81996-12-10Per Hedbor  PUSH("</dl>");
e439c01996-12-10Per Hedbor  PUSH("<p><br clear=all>&nbsp;\n");
a6cdc51996-12-04Per Hedbor  int lm=1;
b1fca01996-11-12Per Hedbor  if(o->type == NODE_CONFIGURATIONS)
fdee9d1996-12-02Per Hedbor  BUTTON(newconfig, "New virtual server", left);
b1fca01996-11-12Per Hedbor  if(o->type == NODE_CONFIGURATION)
fdee9d1996-12-02Per Hedbor  BUTTON(newmodule, "New module", left);
b1fca01996-11-12Per Hedbor  if(o->type == NODE_MODULE) {
5b38191996-12-13Per Hedbor  BUTTON(delete, "Delete module", left);
b1fca01996-11-12Per Hedbor  if(o->data->copies)
1e257d1996-12-03Per Hedbor  BUTTON(newmodulecopy, "Copy module", left);
b1fca01996-11-12Per Hedbor  } i=0; if(o->type == NODE_MODULE_MASTER_COPY || o->type == NODE_MODULE_COPY || o->type == NODE_MODULE_COPY_VARIABLES) {
5b38191996-12-13Per Hedbor  BUTTON(delete, "Delete module", left); BUTTON(refresh, "Reload module", left);
b1fca01996-11-12Per Hedbor  } if(o->type == NODE_CONFIGURATION)
a6cdc51996-12-04Per Hedbor  BUTTON(delete,"Delete this server", left);
b1fca01996-11-12Per Hedbor 
fdee9d1996-12-02Per Hedbor  if(nunfolded(o))
ae32fc1996-12-05Per Hedbor  BUTTON(foldall, "Fold all",left);
b1fca01996-11-12Per Hedbor  if(o->changed)
ae32fc1996-12-05Per Hedbor  BUTTON(unfoldmodified, "Unfold modified", left); if(nfolded(o)) BUTTON(unfoldlevel, "Unfold level", left);
38dca81996-12-10Per Hedbor // else if(nfoldedr(o)) // BUTTON(unfoldall, "Unfold all", left);
ae32fc1996-12-05Per Hedbor 
e439c01996-12-10Per Hedbor  if(!lm) { PUSH("<img border=0 alt=\"\" hspacing=0 vspacing=0 src=/auto/button/rm/%20>"); PUSH("</nobr><br clear=all>"); lm=1; }
b1fca01996-11-12Per Hedbor 
1e257d1996-12-03Per Hedbor  if((o->changed||root->changed))
5b38191996-12-13Per Hedbor  {
a6cdc51996-12-04Per Hedbor  BUTTON(save, "Save", left);
5b38191996-12-13Per Hedbor  PUSH("<img border=0 alt=\"\" hspacing=0 vspacing=0 src=/auto/button/%20%20%20%20%20%20>"); }
1e257d1996-12-03Per Hedbor  BUTTON(restart, "Restart", left); BUTTON(shutdown,"Shutdown", left);
b2c3871996-12-04Per Hedbor  PUSH("<img border=0 alt=\"\" hspacing=0 vspacing=0 src=/auto/button/rm/%20>");
fdee9d1996-12-02Per Hedbor  PUSH("</nobr><br clear=all>");
38dca81996-12-10Per Hedbor // PUSH("<p align=right><font size=-1 color=blue><a href=$docurl><font color=blue>"+roxen->real_version +"</font></a></font></p>");
b2c3871996-12-04Per Hedbor  PUSH("</body>\n");
fdee9d1996-12-02Per Hedbor  return stores(res*"");
b1fca01996-11-12Per Hedbor }