object $root; var $root child_index = 0; var $root created_on = 0; var $root defined_settings = #[["help-node", #[['get, ['help_node]], ['set, ['set_help_node_setting]], ['parse, ['parse_help_node_setting]], ['format, ['format_help_node_setting]]]]]; var $root fertile = 1; var $root flags = ['methods, 'code, 'core, 'variables]; var $root help_node = 0; var $root inited = 0; var $root managed = 0; var $root manager = $root; var $root quota = 75000; var $root quota_exempt = 0; var $root settings = 0; var $root trusted = []; var $root trusted_by = 0; var $root writers = [$root]; var $root writes = 0; protected method ._all_defined_settings(): nooverride { var a, all, d; all = #[]; for a in (ancestors()) { catch any { for d in (dict_keys(a.defined_settings())) all = dict_add(all, d, a); } } return all; }; private method ._clean_root() { arg v, m; var obj, value; if ((value = get_var(v))) { value = value.valid_objects(); for obj in (value) { if (!(this() in obj.(m)())) value = value.setremove(obj); refresh(); } if (value) set_var(v, value); else clear_var(v); } }; private method ._clear_setting(): nooverride { arg name; if (settings && dict_contains(settings, name)) { settings = dict_del(settings, name); if (!settings) clear_var('settings); } }; public method ._display_ancestors() { arg space, checked, levels, maxlev; var c, anc, list, id, perms; id = ((space + this()) + " ") + ($object_lib.see_perms(this())); for anc in (dict_keys(checked)) { if (.has_ancestor(anc)) return []; // [id + " (above)"]; } if (((.parents()).length()) > 1) id += " (MI)"; list = [id]; space += " "; levels++; // check parents if ((!maxlev) || (maxlev != levels)) { for c in (.parents()) { list += c._display_ancestors(space, checked, levels, maxlev); checked = dict_add(checked, c, 1); pause(); } } return list; }; public method ._display_descendants() { arg space, checked, levels, maxlev; var c, anc, list, id, perms; id = ((space + this()) + " ") + ($object_lib.see_perms(this())); for anc in (dict_keys(checked)) { if (.has_ancestor(anc)) return []; // [id + " (above)"]; } if (((.parents()).length()) > 1) id += " (MI)"; list = [id]; space += " "; levels++; // check children if ((!maxlev) || (maxlev != levels)) { for c in (.children()) { list += c._display_descendants(space, checked, levels, maxlev); checked = dict_add(checked, c, 1); pause(); } } return list; }; public method ._get_method_info(): nooverride { arg anc, method; var code, lines, dis_flag, meth_args, flags, first_comment; code = anc.list_method(method); lines = code.length(); if (lines > 5) code = code.subrange(1, 5); flags = anc.method_flags(method); if (code) { meth_args = regexp(code[1], "arg ([^;]);"); if (meth_args) { meth_args = meth_args[1]; code = code.delete(1); } else { meth_args = ""; } if (code && ((!(code[1])) || (((code[1])[1]) == "v"))) code = code.delete(1); if (code && ((!(code[1])) || (((code[1])[1]) == "v"))) code = code.delete(1); first_comment = code ? ((code[1]) + " ") : " "; first_comment = (((first_comment[1]) == "/") || ((first_comment[1]) == "r")) ? first_comment : ""; } else { meth_args = ""; first_comment = ""; } return [anc, method, meth_args, flags, lines, first_comment]; }; public method .add_flag(): nooverride { arg flag; (> .perms(sender(), 'manager) <); (> $sys.touch('coreok) <); if ((flag == 'core) && (!($sys.is_system(sender())))) throw(~perm, "Only system objects can set the 'core flag."); (flag == 'fertile) && (> .perms(sender(), 'manager) <); // let them add any flag they want flags = (flags || []).setadd(flag); }; root method .add_managed_obj(): nooverride { managed = (managed || []).setadd(sender()); }; public method .add_method() { arg code, name, @evalonly; var l, m, line, errs; (> .perms(sender()) <); if (evalonly && (caller() == $programmer)) (> $sys.touch('lockok) <); else (> $sys.touch() <); // check for a few things only admins can do if (!(sender().is($admin))) { for l in [1 .. listlen(code)] { line = code[l]; if ((m = line.match_regexp("[^a-z0-9_.]anticipate_assignment\("))) { (> sender().tell($code_lib.point_to_line("ERROR: call to anticipate_assignment()", ((m[1])[1]) + 2, ((m[1])[2]) - 2, l, line)) <); throw(~perm, "anticipate_assignment() may only be used by an administrator."); } } } errs = (> add_method(code, name) <); for l in [1 .. listlen(errs)] { line = errs[l]; if (match_regexp(line, "Line [0-9]+: Unknown function length.")) { line = substr(line, 1, strlen(line) - 1); errs = replace(errs, l, line + "(), try listlen(), strlen() or buflen()"); } } return errs; }; public method .add_parent() { arg parent; (> .perms(sender(), 'manager) <); (> $sys.touch() <); (> parent.will_inherit(sender()) <); if (.has_ancestor(parent)) throw(~perm, ((this() + " already has ") + parent) + " as an ancestor."); .change_parents(parents() + [parent]); }; public method .add_trusted(): nooverride { arg obj; (caller() == definer()) || (> .perms(sender(), 'manager) <); (> $sys.touch('coreok) <); trusted = (trusted || []).setadd(obj); obj.add_trusted_obj(); }; root method .add_trusted_obj(): nooverride { trusted_by = (trusted_by || []).setadd(sender()); }; public method .add_var(): nooverride { arg name, @args; var tmp, kid; (> .perms(sender()) <); (> $sys.touch() <); if (!(tostr(name).valid_ident())) throw(~invident, name + " is not a valid ident."); (> add_var(name) <); // The following code is a kludge as we can't send a default value to the // primitive. if (args) { tmp = tosym((("__set_" + tostr(name)) + "_") + time()); catch any { add_method([((tostr(name) + " = ") + toliteral(args[1])) + ";"], tmp); .(tmp)(); if (((args.length()) > 1) && ((args[2]) == 'inherit)) { for kid in (.descendants()) kid.(tmp)(); } del_method(tmp); } with { del_method(tmp); rethrow(error()); } } }; root method .add_writable_obj(): nooverride { writes = (writes || []).setadd(sender()); }; public method .add_writer(): nooverride { arg obj; (> .perms(sender(), 'manager) <); (> $sys.touch('coreok) <); writers = (writers || []).setadd(obj); obj.add_writable_obj(); }; public method .all_defined_settings(): nooverride { if (!(.has_flag('variables, sender()))) throw(~perm, ((sender().namef('ref)) + " does not have permission to view settings on ") + (.name('ref))); return ._all_defined_settings(); }; public method .anc2(): nooverride { var i, c, parent, d; d = #[]; for parent in (parents()) d = dict_add(d, parent, 1); while ((| (c = dict_keys(d)[++i]) |)) { for parent in (c.parents()) { pause(); d = dict_add(d, parent, 1); } pause(); } return dict_keys(d); }; public method .ancestors(): nooverride { arg @args; return ancestors(@args); }; public method .ancestors_descending() { arg obj; var anc; return filter anc in (.ancestors()) where (anc.has_ancestor(obj)); }; public method .ancestors_to(): nooverride { arg checked, levels, maxlev; var c, list; list = [this()]; levels++; // check parents if ((!maxlev) || (maxlev != levels)) { for c in (.parents()) { list += [c.ancestors_to(checked, levels, maxlev)]; checked = checked.setadd(c); } } return list; }; public method .ancestry(): nooverride { arg gen; var i, out; out = []; if (type(gen) == 'objnum) { for i in (.ancestors()) { if (i.has_ancestor(gen)) out += [i]; } return out; } if (gen != 0) { for i in (.parents()) out = out.union(i.ancestry(gen - 1)); } return out; }; public method .as_this_run() { arg obj, method, args; if (!((caller() == $scheduler) || (caller().is($http_interface)))) throw(~perm, "Sender not allowed to gain access to object perms."); return (> obj.(method)(@args) <); }; public method .build_name() { arg @args; var output, type, part, rval; output = ""; for part in (args) { type = type(part); if (type == 'list) output += (| .(part[1])(@part.subrange(2)) |) || ""; else if (type == 'string) output += part; } return output; }; public method .change_manager(): nooverride { arg new; var old; if ((caller() != definer()) && (!($sys.is_system(sender())))) throw(~perm, "You must have system privileges to change the manager."); (> $sys.touch() <); if (type(new) != 'objnum) throw(~invarg, "Managers must be given as a single dbref."); old = .manager(); manager = new; old.del_managed_obj(); new.add_managed_obj(); }; root method .change_parents(): nooverride { arg parents; var old_a, old_p, a, obj, new_a, definer, branch, method, str; if (!parents) throw(~noparents, "Objects must have at least 1 parent"); // remember a few things old_a = setremove(ancestors(), this()); old_p = .parents(); branch = (.descendants()) + [this()]; // build the new ancestors list by hand, so we can figure out what is // changing, and uninitialize those ancestors that are going away new_a = []; for obj in (parents) new_a = new_a.union(obj.ancestors()); // uninit any ancestors going away for a in (old_a.set_difference(new_a)) { // call this ancestor's uninit on the obj and all its children method = tosym("uninit_" + (a.objname())); if ((definer = (| find_method(method) |))) { if (definer != a) { // scream madly and run around--everybody should know this str = "UNINIT ERROR: uninit method for " + a; str += (" in wrong place (" + definer) + ")"; (| (definer.manager()).tell(str) |); (| (a.manager()).tell(str) |); (| sender().tell(str) |); continue; } // call the uninit method on this object only catch any { .(method)(); } with { // try and let somebody know they made a boo-boo somewhere str = ((("UNINIT ERROR " + obj) + "<") + this()) + ">:"; (| (.manager()).tell(str) |); (| (.manager()).tell_traceback(traceback()) |); (| sender().tell(str) |); (| sender().tell_traceback(traceback()) |); (| sender().tell("Continuing chparent..") |); } } // cleanup any old obj vars left lying around // if (branch) // $sys.clear_definer_vars(a, branch); $sys.clear_definer_vars(a, [this()]); refresh(); } // make the change (> chparents(parents) <); // init anybody new to the family for a in (ancestors().set_difference(old_a)) { method = tosym("init_" + (a.objname())); if ((definer = (| find_method(method) |))) { if (definer != a) { // scream madly and run around--everybody should know this // (damn inlaws, can't ever get things right) str = "INIT ERROR: uninit method for " + a; str += (" in wrong place (" + definer) + ")"; (| (definer.manager()).tell(str) |); (| (a.manager()).tell(str) |); (| sender().tell(str) |); continue; } // introduce the new ancestor catch any { .(method)(); } with { // try and let somebody know they made a boo-boo somewhere str = ((("INIT ERROR " + obj) + "<") + this()) + ">:"; (| (.manager()).tell(str) |); (| (.manager()).tell_traceback(traceback()) |); (| sender().tell(str) |); (| sender().tell_traceback(traceback()) |); (| sender().tell("Continuing chparent..") |); } } refresh(); } }; public method .children(): nooverride { return children(); }; public method .chparents() { arg @parents; var parent, cur; if (!(| .perms(sender(), 'manager) |)) (> .perms(caller(), $root, $sys) <); (> $sys.touch() <); if (!parents) throw(~noparents, "There must be at least 1 parent for each object."); // Notify new parents of impending change. cur = parents(); for parent in (parents) { if (!(parent in cur)) (> parent.will_inherit(sender()) <); } // Everything's okay, go ahead and try it. .change_parents(parents); }; public method .clean_root() { var obj; // Called by $sys.clean_database() (> .perms(caller(), $sys) <); (| ._clean_root('trusted, 'trusted_by) |); (| ._clean_root('trusted_by, 'trusted) |); (| ._clean_root('writers, 'writes) |); (| ._clean_root('writes, 'writers) |); if (!manager) { manager = this(); .change_manager($reaper); } if (managed) { managed = managed.valid_objects(); for obj in (managed) { refresh(); if ((obj.manager()) != this()) managed = setremove(managed, obj); } if (!managed) clear_var('managed); } }; public method .clear_setting(): nooverride { arg name, definer; var info, args; (caller() == definer()) || (> .perms(sender()) <); info = (> definer.setting_info(name) <); if (dict_contains(info, 'clear)) { args = sublist(info['clear], 2); (> .((info['clear])[1])(name) <); } else if (settings && dict_contains(settings, name)) { settings = dict_del(settings, name); if (!settings) clear_var('settings); } }; public method .clear_variable(): nooverride { arg name; var n, obj; (> .perms(sender()) <); n = tosym("_clear_var_" + tostr(time())); catch any { .add_method([("clear_var(" + toliteral(name)) + ");"], n); for obj in (.descendants()) { (| obj.(n)() |); pause(); } (| del_method(n) |); } with { (| del_method(n) |); } }; root method .core_root() { (| clear_var('child_index) |) || (child_index = 0); }; public method .corify(): nooverride { var d; if (sender() != $sys) throw(~sysonly, "This should only be called by $sys.make_core()."); // reverse engineer it--if coreify_<object> exists, // call it on this object and all of its descendants. for d in (((.descendants()).setremove($sys)) + [$sys]) { .corify_descendants_of(d); refresh(); } }; private method .corify_descendants_of(): nooverride { arg obj; var d, name, l; name = (| tosym("core_" + (obj.objname())) |); catch ~methodnf { if ((> obj.find_method(name) <) != obj) { $sys.log(((("** Coremethod for " + obj) + " in wrong place (on ") + (obj.find_method(name))) + ") **"); return; } } with { return; } for d in ([obj] + (obj.descendants())) { catch any { (> d.(name)() <); } with { $sys.log(((("** ERROR encountered in " + d) + ".") + name) + "():"); for l in ($parse_lib.traceback(traceback())) $sys.log(l); } refresh(); } }; public method .created_on(): nooverride { return created_on; }; public method .data(): nooverride { arg @parent; var par, data, out; if (!(.has_flag('variables, sender()))) throw(~perm, ((sender().namef('ref)) + " is not allowed to read variables on ") + (.namef('ref))); if (parent) { if (type(parent[1]) != 'objnum) throw(~type, (parent[1]) + " is not an object."); return (> data(parent[1]) <); } else { data = (> data() <); out = #[]; for par in (data) { // if the parent doesn't exist anymore, just let them see the data. if ((!valid(par[1])) || ((par[1]).has_flag('variables, sender()))) out = out.add(par[1], par[2]); else out = out.add(par[1], ["*** Permission Denied ***"]); } return out; } }; public method .debug() { arg @stuff; var x, line, mngr, meth, stack; stack = stack(); meth = (| (((stack[2])[3]) + "() line ") + ((stack[2])[4]) |); if (meth) line = ((("DEBUG " + sender()) + ".") + meth) + ": "; else line = ("DEBUG " + sender()) + ": "; for x in (stuff) line = (line + " ") + toliteral(x); (| (.manager()).tell(line) |); }; public method .define_setting(): nooverride { arg name, @info; var i; (> .perms(sender()) <); if (info) { info = info[1]; for i in (info) { if (!(> .valid_setting_attr(@i) <)) info = dict_del(info, i[1]); } } else { info = #[]; } if ((.all_defined_settings()).contains(name)) throw(~setexists, ("Setting \"" + name) + "\" is already defined."); if (!($code_lib.valid_setting_id(name))) throw(~setbad, ("Setting name \"" + name) + "\" is unacceptable."); defined_settings = (.defined_settings()).add(name, info); return defined_settings[name]; }; public method .defined_settings(): nooverride { return defined_settings || #[]; }; public method .del_flag(): nooverride { arg flag; (> .perms(sender(), 'manager) <); (> $sys.touch('coreok) <); if ((flag == 'core) && (!($sys.writable_core()))) throw(~perm, this() + " is a core object, and the core isn't writable."); // let them add any flag they want flags = (flags || []).setremove(flag); }; root method .del_managed_obj(): nooverride { managed = (managed || []).setremove(sender()); if (!managed) clear_var('managed); }; public method .del_method() { arg name; (> .perms(sender()) <); (> del_method(name) <); }; public method .del_parent() { arg parent; var parents; (> .perms(sender(), 'manager) <); (> $sys.touch() <); if (!valid(parent)) throw(~type, "Not a valid parent, must send a valid object."); parents = .parents(); if (!(parent in parents)) throw(~parentnf, ((parent + " is not a parent of ") + this()) + "."); parents = parents.setremove(parent); (> .change_parents(parents) <); }; public method .del_trusted(): nooverride { arg obj; (> .perms(sender(), 'manager) <); (> $sys.touch('coreok) <); trusted = (trusted || []).setremove(obj); if (!trusted) clear_var('trusted); obj.del_trusted_obj(); }; root method .del_trusted_obj(): nooverride { trusted_by = (trusted_by || []).setremove(sender()); if (!trusted_by) clear_var('trusted_by); }; public method .del_var(): nooverride { arg name; var n, obj; (caller() == definer()) || (> .perms(sender()) <); (> $sys.touch() <); // try and clear the variable on all of the descendants, before deleting // the variable... (> .clear_variable(name) <); // now delete the variable (> del_var(name) <); }; root method .del_writable_obj(): nooverride { writes = (writes || []).setremove(sender()); if (!writes) clear_var('writes); }; public method .del_writer(): nooverride { arg obj; (caller() == definer()) || (> .perms(sender(), 'manager) <); writers = (writers || []).setremove(obj); (> $sys.touch('coreok) <); if (!writers) (| clear_var('writers) |); obj.del_writable_obj(); }; public method .descendants(): nooverride { var kids, i, c, child, d; d = #[]; for child in (children()) d = dict_add(d, child, 1); while ((| (c = dict_keys(d)[++i]) |)) { for child in (c.children()) { pause(); d = dict_add(d, child, 1); } pause(); } return dict_keys(d); }; public method .descendants_to(): nooverride { arg checked, levels, maxlev; var c, list; list = [this()]; levels++; // check parents if ((!maxlev) || (maxlev != levels)) { for c in (.children()) { list += [c.descendants_to(checked, levels, maxlev)]; checked = checked.setadd(c); } } return list; }; public method .destroy(): nooverride { // This doesn't actually destroy us immediately, but we will go away when // nothing is holding onto us any more. (> .perms(sender(), 'manager) <); if (.has_flag('core)) throw(~perm, "This object is a core object, and cannot be destroyed!"); (| .uninitialize('destroy) |); destroy(); }; public method .eval(): nooverride { arg code, @dest; var errors, result, method; dest = dest ? (dest[1]) : this(); if (!(sender() in [$scheduler, $root])) (> .perms(sender()) <); // Compile the code. method = tosym("tmp_eval_" + tostr(time())); errors = .add_method(code, method); if (errors) return ['errors, errors, 0, 0]; // Evaluate the expression. Be sure to remove it afterwards, so that no // one else can call it. catch any { result = (> dest.(method)() <); } with { (| del_method(method) |); rethrow(error()); } (| del_method(method) |); return ['result, result]; }; public method .examine() { return []; }; public method .find_method(): nooverride { arg name; if (!(.has_flag('methods, sender()))) throw(~perm, (sender() + " doesn't have permission to find methods on ") + this()); return (> find_method(name) <); }; public method .find_next_method(): nooverride { arg name, after; if (!(.has_flag('methods, sender()))) throw(~perm, (sender() + " doesn't have permission to find methods on ") + this()); return (> find_next_method(name, after) <); }; public method .flags(): nooverride { return flags || []; }; public method .format_descendants() { arg ind, done, depth, max, yes, no, above; var c, anc, list, id, perms, f, show, myflags; show = 1; myflags = .flags(); if (yes) { for f in (yes) { if (f in myflags) { show = 1; break; } else { show = 0.0; } } } for f in (.flags()) { if (no && (f in no)) { show = 0; break; } } if (show) { id = ((ind + this()) + " ") + ($object_lib.see_perms(this())); for anc in (dict_keys(done)) { if (has_ancestor(anc)) return above ? [id + " (ABOVE)"] : []; } if (listlen(parents()) > 1) id += " (MI)"; list = [id]; } else { list = []; } ind += " "; depth++; // check children if ((!max) || (max != depth)) { for c in (children()) { list += c.format_descendants(ind, done, depth, max, yes, no, above); done = dict_add(done, c, 1); pause(); } } return list; }; public method .format_help_node_setting() { arg node; if (node) return node.namef('ref); return ""; }; public method .format_setting(): nooverride { arg name, definer, value; var i, args; i = definer.setting_info(name); if (dict_contains(i, 'format)) { args = sublist(i['format], 2); catch ~methodnf return (> .((i['format])[1])(value, @args) <); with return (> $settings.((i['format])[1])(value, @args) <); } if (type(value) == 'objnum) return value.namef('ref); else return "" + value; }; public method .generations(): nooverride { arg gen; var p, out; out = [this()]; if (gen != 0) { for p in (.parents()) out = out.union(p.generations(gen - 1)); } return out; }; public method .get_default_setting(): nooverride { arg name; return settings[name]; }; public method .get_local_setting(): nooverride { arg name, definer; var i; i = definer.setting_info(name); if (dict_contains(i, 'access)) (> .((i['access])[1])(name, sender(), caller(), @sublist(i['access], 2)) <); return (| settings[name] |) || (> definer.get_default_setting(name) <); }; public method .get_obj_suffix() { arg @suffix; var objname, tmp; // Figure out the suffix from the arguments and child index. [(suffix ?= 0)] = suffix; if (suffix) { // so they dont confuse child_index: if (suffix.is_numeric()) throw(~perm, "You cannot specify a numeric suffix."); // so we get correct symbols & it is always lowercase: suffix = lowercase(strsed(suffix, "[^a-z0-9_]+", "", "g")); } else { // get the next valid objname objname = tostr((| .objname() |) || "unknown"); tmp = tosym(objname); while ((| lookup(tmp) |)) { child_index++; tmp = tosym((objname + "_") + tostr(child_index)); } suffix = tostr(child_index); } return suffix; }; public method .get_quota(): nooverride { arg @args; return quota; }; public method .get_setting(): nooverride { arg name, definer; var i; i = definer.setting_info(name); if (dict_contains(i, 'access)) (> .((i['access])[1])(name, sender(), caller(), @sublist(i['access], 2)) <); if (dict_contains(i, 'get)) return (> .((i['get])[1])(name, definer, @sublist(i['get], 2)) <); catch any return settings[name]; with return (> definer.get_default_setting(name) <); }; public method .get_setting_attr(): nooverride { arg name, attr; return (defined_settings[name])[attr]; }; public method .has_ancestor(): nooverride { arg obj; return (> has_ancestor(obj) <); }; public method .has_flag(): nooverride { arg flag, @sender; [(sender ?= sender())] = sender; if (flag == 'core) return flag in (.flags()); return (flag in (.flags())) || (.trusts(sender)); }; public method .help_node() { arg @args; return help_node; }; public method .hname() { arg @args; return ((("<a href=\"/bin/display?" + this()) + "\">") + this()) + "</a>"; }; root method .init_root(): nooverride { .change_manager(this()); flags = ['variables, 'methods, 'code]; created_on = time(); }; public method .initialize(): nooverride { var ancestors, pos, len, method, a, def; if ((caller() != $sys) && (sender() != this())) throw(~perm, "Caller is not $sys and sender is not this."); if (inited) throw(~perm, "Already initialized."); ancestors = ancestors(); len = ancestors.length(); for pos in [0 .. len - 1] { refresh(); a = ancestors[len - pos]; if (!(method = (| tosym("init_" + tostr(a.objname())) |))) continue; if ((def = (| find_method(method) |))) { if (def != a) { (| (def.manager()).tell(((("Initialization method for " + a) + " in wrong place (") + find_method(method)) + ")") |); } else { catch any { .(method)(); } with { if (def) { (| (def.manager()).tell(((("INIT ERROR " + this()) + "<") + def) + ">:") |); (| (def.manager()).tell_traceback(traceback()) |); } } } } } inited = 1; }; public method .is(): nooverride { arg @args; if (!args) throw(~invarg, "Must have one argument."); if (type(args[1]) == 'dictionary) return has_ancestor(args[2]); return has_ancestor(args[1]); }; public method .is_of(): nooverride { arg obj; return obj in ancestors(); }; public method .is_writable_by(): nooverride { arg obj; return (| obj in (.writers()) |) || ($sys.is_system(obj)); }; public method .list_method() { arg @args; if (!(.has_flag('code, sender()))) throw(~perm, (("Method code on " + (.namef('ref))) + " is not readable by ") + (sender().namef('ref))); return (> list_method(@args) <); }; public method .list_methods() { arg gen, def, fltr, match; var ancs, a, m, i, methods; if (!(.has_flag('methods, sender()))) throw(~perm, (sender() + " cannot view methods on ") + this()); if (def) ancs = [def]; else ancs = .(gen[1])(gen[2]) || [this()]; methods = #[]; for a in (ancs) { for m in (a.methods()) { if (tostr(m).(match)(fltr) != 0) { i = a.method_info(m); methods = methods.add_elem(i[5], [a, m, @i]); } } } return methods; }; public method .managed(): nooverride { return managed || []; }; public method .manager(): nooverride { return manager || $reaper; }; public method .match_children() { arg string; var children, child_names, c; children = .children(); child_names = children.mmap('name); // direct matches first. for c in (child_names) { if (c == string) return children[c in child_names]; } // ok, try partial matches for c in (child_names) { if ($string.match_begin(c, string)) return children[c in child_names]; } return 0; }; public method .match_descendants() { arg string; var match, child; match = .match_children(string); if (match) return match; for child in (.children()) { match = child.match_descendants(string); if (match) return match; } return 0; }; public method .method_access(): nooverride { arg method; if (!(.has_flag('methods, sender()))) throw(~perm, (sender() + " doesn't have permission to find methods on ") + this()); return (> method_access(method) <); }; public method .method_bytecode() { arg method; return (> method_bytecode(method) <); }; public method .method_flags(): nooverride { arg method; if (!(.has_flag('methods, sender()))) throw(~perm, (sender() + " doesn't have permission to find methods on ") + this()); return (> method_flags(method) <); }; public method .method_info(): nooverride { arg @args; return (> method_info(@args) <); }; public method .methods(): nooverride { if (!(.has_flag('methods, sender()))) throw(~perm, (sender() + " doesn't have permission to find methods on ") + this()); return methods(); }; public method .name() { arg @args; return tostr(this()); }; public method .namef() { arg type; return tostr(this()); }; public method .new() { arg @suffix; var obj, tmp, objname, mngr, na; // this difference between this and .spawn() is that you // can override this method to return a frob instead. (> .will_spawn(sender()) <); suffix = (> .get_obj_suffix(@suffix) <); return $sys.spawn_sender(suffix, sender()); }; public method .new_descendants() { var kid, kids; kids = #[]; for kid in (children()) { kids = kids.add(kid, 1); kids = kids.union(kid.new_descendants()); pause(); } return kids.keys(); }; public method .objname(): nooverride { return (> objname() <); }; public method .objnum(): nooverride { return objnum(); }; public method .parents(): nooverride { return parents(); }; public method .parse_help_node_setting() { arg value, @args; if (!value) return 0; value = (> $object_lib.to_dbref(value) <); if (!(value.is($help_node))) throw(~perm, (value.namef('ref)) + " is not a $help_node."); return value; }; public method .perms(): nooverride { arg what, @args; var flag; if (!args) args = ['writer]; if (type(args[1]) == 'symbol) { switch (args[1]) { case 'system: if (!($sys.is_system(what))) throw(~perm, ("Permission Denied: " + what) + " is not of the system.", what); case 'manager: if (((.manager()) != what) && (!($sys.is_system(what)))) throw(~perm, ("Permission Denied: " + what) + " is not the manager.", what); case 'trusts: if (!(.trusts(what))) throw(~perm, ("Permission Denied: " + what) + " is not a trustee.", what); case 'command: if ((what != $user) && (what != $body)) throw(~perm, what + " is not a valid command invoking object."); default: if (!(.is_writable_by(what))) throw(~perm, ("Permission Denied: " + what) + " is not a writer.", what); } } else if (type(what) == 'objnum) { if (!(what in args)) throw(~perm, (what + " is not one of: ") + ((args.mmap('namef, 'ref)).to_english()), what); } }; public method .quota(): nooverride { return quota; }; public method .quota_byte_usage(): nooverride { var total, obj; for obj in (.managed()) { if (!valid(obj)) continue; total += obj.size(); } return total; }; public method .quota_exempt(): nooverride { return quota_exempt; }; public method .quota_valid(): nooverride { if (quota_exempt) return 1; if (!(.is($user))) return 0; return (.quota_byte_usage()) < (.quota()); }; public method .rename_method() { arg now, new; (> .perms(sender()) <); (> $sys.touch() <); return (> rename_method(now, new) <); }; public method .set_flags(): nooverride { arg new_flags; (> .perms(sender(), 'manager) <); (> $sys.touch() <); if (type(new_flags) != 'list) throw(~invflags, "Flags must be submitted as a list of symbols."); if ((!new_flags) && flags) return clear_var('flags); if (('core in new_flags) && (!($sys.is_system(sender())))) throw(~perm, "Only system objects can set the 'core flag."); ('fertile in new_flags) && (> .perms(sender(), 'manager) <); flags = new_flags; }; protected method .set_help_node_setting() { arg name, definer, value; if (!value) (| clear_var('help_node) |); else help_node = value; }; public method .set_method_access(): nooverride { arg method, state; if (!(.is_writable_by(sender()))) throw(~perm, (sender() + " cannot write to ") + this()); (> $sys.touch() <); return (> set_method_access(method, state) <); }; public method .set_method_flags(): nooverride { arg method, flags; if (!(.is_writable_by(sender()))) throw(~perm, (sender() + " cannot write to ") + this()); (> $sys.touch() <); if (('locked in flags) && (!($sys.is_system(sender())))) throw(~perm, "Only administrators can set the locked method flag."); return (> set_method_flags(method, flags) <); }; public method .set_objname() { arg objname; (> .perms(sender()) <); if (.has_flag('core)) throw(~perm, this() + " is a core object; you cannot change its object name!"); (> $sys.touch() <); // Make sure first argument is a symbol. if (type(objname) != 'symbol) throw(~type, "New objname is not a symbol."); // Make sure everything is lowercase. objname = tosym(tostr(objname).lowercase()); // Do nothing if objname isn't different. if (objname == (| objname() |)) return; return (> set_objname(objname) <); }; public method .set_quota(): nooverride { arg value; (> .perms(caller(), $user, @$sys.system(), $root, $admin) <); quota = value; }; public method .set_quota_exempt(): nooverride { arg bool; (> .perms(caller(), $user, @$sys.system(), $root) <); if (bool) quota_exempt = 1; else (| clear_var('quota_exempt) |); }; public method .set_setting(): nooverride { arg name, definer, value; var i, args; (> .perms(sender()) <); i = (> definer.setting_info(name) <); if (dict_contains(i, 'parse)) { args = sublist(i['parse], 2); catch ~methodnf value = (> .((i['parse])[1])(value, @args) <); with value = (> $settings.((i['parse])[1])(value, @args) <); } if (dict_contains(i, 'set)) (> .((i['set])[1])(name, definer, value, @sublist(i['set], 2)) <); else settings = dict_add(settings || #[], name, value); }; public method .set_setting_attr(): nooverride { arg name, attr, value; var info; (> .perms(sender()) <); if ((!defined_settings) || (!dict_contains(defined_settings, name))) throw(~setnf, (("Setting \"" + name) + "\" is not defined on ") + this()); if (value && (!(> .valid_setting_attr(attr, value) <))) return; info = defined_settings[name]; if (!value) info = dict_del(info, attr); else info = dict_add(info, attr, value); defined_settings = dict_add(defined_settings, name, info); }; public method .setting_definer(): nooverride { arg name; var a; for a in (ancestors()) { if (dict_contains(a.defined_settings(), name)) return a; } throw(~setnf, ("Setting \"" + name) + "\" is not defined."); }; public method .setting_info(): nooverride { arg setting; return defined_settings[setting]; }; public method .settings(): nooverride { (> .perms(sender()) <); return settings || #[]; }; public method .size(): nooverride { arg @args; [(args ?= 'int)] = args; switch (args) { case 'string: return tostr(size()); case 'english: return size().to_english(); default: return size(); } }; public method .spawn(): nooverride { arg @suffix; var obj, tmp, objname, mngr, na; (> .will_spawn(sender()) <); suffix = (> .get_obj_suffix(@suffix) <); return $sys.spawn_sender(suffix, sender()); }; public method .test_method() { return "from root"; }; public method .trusted(): nooverride { arg @literal; if (literal) return trusted || []; return (trusted || []) + (.writers()); }; public method .trusted_by(): nooverride { return trusted_by || []; }; public method .trusts(): nooverride { arg obj; return (| obj in (.trusted()) |) || ((obj in [$scheduler, $directories]) || ($sys.is_system(obj))); }; public method .undefine_setting(): nooverride { arg name; var d; (> .perms(sender()) <); if (!((.defined_settings()).contains(name))) throw(~setnf, (("Setting \"" + name) + "\" is not defined by ") + this()); // clear it on all descendants, then us for d in ((.descendants()) + [this()]) { d._clear_setting(name); pause(); } // bye bye defined_settings = dict_del(defined_settings, name); if (!defined_settings) clear_var('defined_settings); }; root method .uninit_root(): nooverride { var obj; (| manager.del_managed_obj() |); catch any { for obj in (.managed()) obj.change_manager($reaper); } catch any { for obj in (.writers('literal)) .del_writer(obj); } catch any { for obj in (.writes()) obj.del_writer(this()); } catch any { for obj in (.trusted('literal)) .del_trusted(obj); } catch any { for obj in (.trusted_by()) obj.del_trusted(this()); } // tell $sys we are going away $sys.sender_going_away(); }; public method .uninitialize(): nooverride { arg @destroyed; var a, v, d, definer, method, descendants, str; (> .perms(caller(), $root, $sys) <); destroyed = destroyed ? 1 : 0; descendants = (.descendants()) + [this()]; // call [ancestors...].uninit_ancestor() on the object being destroyed for a in (ancestors()) { method = tosym("uninit_" + (a.objname())); if ((definer = (| find_method(method) |))) { if (definer != a) { // scream madly and run around--everybody should know this str = "UNINIT ERROR: uninit method for " + a; str += (" in wrong place (" + definer) + ")"; (| (definer.manager()).tell(str) |); (| (a.manager()).tell(str) |); (| sender().tell(str) |); continue; } catch any { .(method)(); } with { // try and let somebody know they made a boo-boo somewhere str = ((("UNINIT ERROR " + this()) + "<") + definer) + ">:"; if (definer) { (| (definer.manager()).tell(str) |); (| (definer.manager()).tell_traceback(traceback()) |); } (| sender().tell(str) |); (| sender().tell_traceback(traceback()) |); (| sender().tell("Continuing uninit..") |); } } refresh(); } // if we have descendants, clean anything from the object being dested method = tosym("uninit_" + (.objname())); if ((definer = (| find_method(method) |))) { if (definer != this()) { // scream madly and run around--everybody should know this str = "UNINIT ERROR: uninit method for " + a; str += (" in wrong place (" + definer) + ")"; (| (definer.manager()).tell(str) |); (| (.manager()).tell(str) |); (| sender().tell(str) |); } else { for d in (descendants) { catch any { d.(method)(); } with { // try and let somebody know they made a boo-boo somewhere str = ((("UNINIT ERROR " + d) + "<") + this()) + ">:"; (| (.manager()).tell(str) |); (| (.manager()).tell_traceback(traceback()) |); (| sender().tell(str) |); (| sender().tell_traceback(traceback()) |); (| sender().tell("Continuing uninit..") |); } refresh(); } } } // clear vars if ((!destroyed) && descendants) $sys.clear_definer_vars(this(), descendants); }; public method .valid_setting_attr(): nooverride { arg name, value; if (!(name in ['get, 'set, 'parse, 'clear, 'format, 'access])) throw(~setattr, "Invalid setting attribute '" + name); if (!value) return 0; else if (type(value) != 'list) throw(~setattr, "Setting attribute must be a list"); else if (type(value[1]) != 'symbol) throw(~setattr, "Setting attribute[1] is not a symbol"); return 1; }; public method .variable_info() { arg gen, def, fltr, match; var ancs, data, pp, p; if (!(.has_flag('variables, sender()))) throw(~perm, (sender() + " cannot read variables on ") + this()); if (def) ancs = [def]; else ancs = .(gen[1])(gen[2]) || [this()]; data = []; for pp in ((data().to_list()).reverse()) { if (valid(pp[1]) && ((pp[1]) in ancs)) { for p in (pp[2]) { if (tostr(p[1]).(match)(fltr) != 0) data += [[pp[1], @p]]; } } } return data; }; public method .variables(): nooverride { if (!(.has_flag('variables, sender()))) throw(~perm, (sender() + " doesn't have permission to find methods on ") + this()); return variables(); }; public method .will_inherit() { arg who; if (this() in (sender().parents())) throw(~perm, ((sender() + " already has ") + this()) + " as a parent."); if ((!(.has_flag('fertile, sender()))) && (!(.trusts(who)))) throw(~perm, ((this() + " refuses to be parent of ") + sender()) + "."); }; public method .will_spawn(): nooverride { arg who; if (!(.has_flag('fertile, who))) throw(~perm, "Not fertile or readable."); // available quota? if (!(who.quota_valid())) throw(~quota, "Sender does not have the available quota"); }; public method .writers(): nooverride { arg @literal; if (literal) return writers || []; // for speed, just add rather than setadd, use .compress() later if necessary return (writers || []) + [.manager(), this()]; }; public method .writes(): nooverride { (> .perms(sender(), 'trusts) <); return writes || []; };