The reason for this restriction is related to the source of the name
"WebGhost Viewer." When objects in the MOO change in some way, MOO
users expect it's because someone in the MOO has changed them or
because the object is somehow "active." If objects could be
manipulated by anonymous web transactions, it would appear as if the
object were being controlled by something outside the self-contained
reality that is the MOO. This would damage the integrity of the VR
visualization.
Instead, you can consider anonymous web transactions as being
initiated by "ghosts," who are able to see into and wander the MOO
but not manipulate anything inside. They have no "body" to
manipulate with. Note that there is a @web-option that allows MOO
users to detect when a web ghost visits the room, and it is possible
to implement some forms of "clairvoance" to allow people inside the
MOO to communicate to those outside in a near-real time manner. This
may be added in future version of the Biogate system.
The $anon_webviewer presents an HTML page similar in format to the
$standard_webviewer. However, it carries several verbs that have the
same name found on other BioGate System objects used for
authenticated transactions. Some, like the web_viewer_buttons verb
(corresponding to $player:web_viewer_buttons), are used to build up
the final web page. Others perform the equivalent of commands, like
interpret_teleport (which performs functions equivalent to the
$teleporter system).
There is a $anon_webviewer.ghost_home property that you can set to
the room (OBJ) that all web ghosts originate at when they enter the
MOO. This is different from $teleporter.central_room and
$player_start to allow you to present specialized messages (in the
room's description text) for anonymous web visitors.
The $anon_webviewer.max_lag value (NUM) is the maximum lag in
seconds, as compared to $lag_meter.samples[$], beyond which the
$anon_webviewer refuses to allow anonymous transactions.
Note that the WebGhost Viewer is provided as a useful anonymous web
viewer but that wizards may make their own child of $webapp and set
the $anon_webviewer pointer to it. This allows MOOs to have their
own custom anonymous webviewer, with whatever features they wish.
All of the utilities below refer to `caller' to locate the home object. Thus verbs to manipulate a given biglist must be located on or inherited by its home object itself. The home object needs to define the following verbs
:_make(@args) => new property on home object with value args
:_kill(prop) delete a given property that was created by :_make
:_get(prop) => home.prop
:_put(prop,@args) set home.prop = args
:_ord(element) given something that is of the form of a biglist element
return the corresponding ordinal (for sorting purposes).
If you never intend to use :find_ord, then this can be a
routine that always returns 0 or some other random value.
See $generic_biglist_home or $big_mail_recipient for examples.
Those of the following routines that take a biglist argument are expecting
either {} (empty biglist) or some biglist returned by one of the other routines
:length(biglist) => length(biglist) (i.e., number of elements)
:find_nth(biglist,n) => biglist[n]
:find_ord(biglist,k,comp) => n where n is
the largest such that home:(comp)(k,home:_ord(biglist[n])) is false, or
the smallest such that home:(comp)(k,home:_ord(biglist[n+1])) is true.
Always returns a value between 0 and length(biglist) inclusive.
This assumes biglist to be sorted in order of increasing :_ord values
with respect to home:(comp)().
Standard situation is :_ord returns a number and comp is a < verb.
:start(biglist,s,e) => {biglist[s..?],@handle} or {}
:next(@handle) => {biglist[?+1..??],@newhandle} or {}
These two are used for iterating over a range of elements of a biglist
The canonical incantation for doing
for elt in (biglist[first..last])
...
endfor
is
handle = :start(biglist,first,last);
while(handle)
for elt in (handle[1])
...
endfor
handle = :next(@listdelete(handle,1));
endwhile
The following all destructively modify their biglist argument(s) L (and M).
:set_nth(L,n,value) => L[n] = value
replaces the indicated element
:insert_before(L,M,n) => {@L[1..n-1],@M,@L[n..length(L)]}
:insert_after (L,M,n) => {@L[1..n], @M,@L[n+1..length(L)]}
takes two distinct biglists, inserts one into the other at the given point
returns the resulting consolidated biglist
:extract_range(L,m,n) => {{@L[1..m-1],@L[n+1..]}, L[m..n]}
breaks the given biglist into two distinct biglists.
:delete_range(L,m,n[,leafkiller]) => {@L[1..m-1],@L[n+1..]}
:keep_range (L,m,n[,leafkiller]) => L[m..n]
like extract_range only we destroy what we don't want.
:insertlast(L,value) => {@L,value}
inserts a new element at the end of biglist.
If find_ord is to continue to work properly, it is assumed that the
home:_ord(elt) is greater (comp-wise) than all of the :_ord values
of elements currently in the biglist.
:kill(L[,leafkiller])
destroys all nodes used by biglist.
Calls home:leafkiller on each element.
By default, the eduCore measures people's byte usage but controls
quota through object-quota mechanisms. However, wizards can modify
this behavior so that byte-quota is used instead.
By default, the eduCore comes set to use object-based quota. Under
this scheme, builders are granted a certain number of objects they
can build, and those objects can have any amount of text or other
customization on them. However, many MOOs will want to use
byte-based quota, where builders can make any number of objects, but
have a limit to the total amount of bytes those objects can take up
in memory. To change the MOO to use byte-based quota, use the
following commands:
@set #0.quota_utils to $byte_quota_utils
@set $object_quota_utils.byte_based to 1
@set $byte_quota_utils.byte_based to 1
start $byte_quota_utils
If there is already a byte measurement task running, "start
$byte_quota_utils" will issue a warning, but you can ignore it.
NOTE: Changing over from object-based to byte-based quota after the
MOO has been running a while can be quota a hassle, since you'll have
to reissue everyone quota limits by hand. You should make this
decision before you open your MOO.
To set the amount of quota builders start with, use:
@set $byte_quota_utils.default_quota to {50000, 0, 0, 1}
where in that example, new builders have 50,000 bytes of quota to
start with.
Available commands:
start-measuring $byte_quota_utils
This starts the periodic measurement task if such a task isn't
already scheduled. It can be used to set a time for the task to run
different from the default one, or to start the task anew if for some
reason the task was killed.
do_summary <object> with $byte_quota_utils
Related Topics:
@quota -- the command used to find and set use @quota levels
@measure -- measures byte usage of individual objects or all a person's owned objects
In addition to the command verbs described under `help containers'
and the _msg properties described in `help container-messages',
the following verbs and properties are available for use within programs
.opened == TRUE iff the container is open
.dark == TRUE iff the contents of the container may be seen
.opaque - describes the correlation between .open and .dark
== 0 container is always !dark
== 1 container is dark iff it is closed
== 2 container is always dark
:set_opaque(newvalue)
changes the .opaque value for the container
=> newvalue or E_PERM or E_INVARG
:set_opened(newvalue)
opens/closes the container (updates .open and .dark) according to newvalue
=> newvalue or E_PERM
:is_openable_by(who)
what the :open command uses to test whether the person should be able to open
the container. By default this refers to .open_key (set by
@(un)lock_for_open), but the object owner is free to customize this.
N.B.: There is no way to directly set .dark; .dark can be changed only by
changing one of .opaque or .opened. Use :set_opaque(0) and :set_opaque(2)
to have .dark change independently of the value of .opened.
NOTE: THIS OBJECT IS ESSENTIALLY OBSOLETED BY THE raise() BUILT-IN FUNCTION IN SERVER VERSION 1.8.0, BUT IS RETAINED FOR BACKWARD COMPATABILITY.
The Error Generator, $error, may be used to automatically generate errors. This is particularly useful if you are working in a !d verb but have occasion to -want- to crash with traceback. To raise a specific error, use $error:raise(error type) - for example, $error:raise(E_PERM) will produce traceback resulting from a Permission Denied error.
Random notes about $error:
+ The complete list of errors is stored in $error.names.
+ The seemingly useless :accept() verb on $error is so that $error:E_RECMOVE and $error:E_NACC will be guaranteed success (success meaning, of course, a termination by traceback).
+ There is, unfortunately, no way to raise the error E_NONE.
The standard verbs that are called in exit movement are:
:move(object) - moves the object via this exit
:invoke() - equivalent to :move(player)
When an exit is invoked on a particular object (via exit:move(object)), the following occurs.
(1) The exit may be locked against the object, in which case we print the
nogo messages and quit.
(2) (room=exit.dest):bless_for_entry(object) is called. Assuming that exit is recognized by room as being a legitimate entrance (i.e., is in room.entrances), this will enable room:accept(object) to return true.
(3) object:moveto(room) is called and the various messages (see `help exit-messages') are :announced/:told. Note that this, in accordance with the way the builtin move() (and hence the default :moveto()) works, we get a call to room:accept(object) which checks for the room itself being locked against the object, and otherwise returns true if the blessing in the previous step worked. The move is performed, here:exitfunc(object) and room:enterfunc(object) are called. In particular, room:enterfunc clears the blessing bestowed in (2) now that it is no longer needed.
In general, the move may fail, in which case we :announce the (o)nogo_msgs.
In order to function as feature object commads, verbs on the feature must:
1. Be executable (+x).
2. Have a argument set for which a valid command is possible (i.e. not `this none this').
3. Have a verb name that is not already used by a verb that the standard MOO server matching will find, or on any object ahead of the feature in the user's .features property (a list of features they've added).
Features have an unusual `help' system, such that the help text
displayed is the contents of <feature>.help_msg, followed by the
header comments from each verb that has been flagged using the
$feature:@add_feature_verb command. Feature creators do not have to
use @afv to make the commands usable as a feature, but only to flag
them for the help system.
Note that verbs on $feature should not use `player' or `caller' for
security, but should use caller_perms() instead (as with all +x verbs
where the caller is not predictable).
Some properties:
.feature_ok
The value returned by <feature>:feature_ok by default.
.guest_feature_ok
This feature object may be used by guests.
.feature_info_byte_limit
The maximum number of bytes a feature can store on a person's
character object through the <player>:set_feature_info command, if
that person has added the feature object to their list of features.
Note that this restriction is only in effect if byte-based quota is
enabled for the MOO.
Some verbs:
feature_ok
Called when someone tries to add a feature object, and must return true if they are to be allowed. Returns the value of <feature>.feature_ok by default.
:feature_add
Called after a feature has been added to someone's list of features.
:feature_remove
Called when someone removes a feature object from their list.
:player_connected
:player_disconnected
Called when a person connects to or disconnects from their character.
Related Topics:
features -- help for users and some notes for programmers
frameset
This is an instruction to create a <FRAMESET> HTML document, defining
the frames and the URLs of the pages to be loaded into each. For
instance, a two frame page with a web document display above and a
java telnet client below might be specified. The
$frame_manager:make_frameset verb does the actual work.
javaclient
This command returns the HTML document containing appropriate <EMBED>
tags for placing a Java telnet client in the specified frame. The
$frame_manager determines which $jclient_handler to use with the
$frame_manager:get_jclient_html verb.
preload
This command retrieves the "preload" page to be displayed in the web
document frame until the full layout is complete. Completion is
generally marked by a call from the Java telnet client to display a
new page in the "html_frame" of the display. The preload page is
defined by the particular $jclient_handler that is being included on
the page in the "interaction_frame" frame. The
$frame_manager:preload_page verb creates the text.
:find(string) => datum, $ambiguous_match or $failed_match
:find_key(string) => full string key, $ambiguous_match or $failed_match
:find_exact(string) => datum or $failed_match (no partial matches)
:find_all(string) => list of all data corresponding to matching strings
:find_all_keys(string) => list of all matching strings
:insert(string,datum)
if the string is already present in the db,
changes the associated datum and returns {old_datum};
otherwise enters a new {string,datum} pair and return 0.
:delete(string)
if there is a datum associated with string,
remove this association and return {datum}; otherwise return 0.
:delete2(string,datum)
if the given datum is associated with string,
removes that association and return {datum},
if some other datum is associated with string, just return {other datum}
otherwise return 0.
:clearall([4|3])
removes all associations from the database.
optional argument changes the type of the database
(4 is normal, 3 is a kludge for when the data are simply boolean flags
i.e., this is a set of strings rather than a string-indexed array;
more on this below)
count [entries|chars] in this
provide some vague statistics about how big this thing is.
N.B. As entries get made, properties belonging to $generic_db.owner will be created on the db object itself. These properties will be created having flags as specified by .node_perms, which by default is "r", but can be changed to "" should you want to ensure that randoms don't have access to the raw information.
Implementation notes
- - - - - - - - - -
The representation is as a `trie', a tree in which each internal node corresponds to a prefix shared by two or more strings in the db.
Each internal node is kept in a property named " "+<prefix>, where <prefix> is a prefix shared by all strings in the subtree under this node.
The property value is a 4 element list
this.(" "+<prefix>)[1] = <common>
maximal continuation shared by all strings beginning with prefix
i.e., all these names actually begin with <prefix>+<common>
this.(" "+<prefix>)[2] = <continuations>
string of all characters <c> that can follow <prefix>+<common> for which
there is more than one string in the db beginning with <prefix>+<common>+<c>
this.(" "+<prefix>)[3] = <exact_matches>
list of all strings in this subtree for which
the character (or lack thereof) following the <prefix>+<common> substring
suffices to determine the string.
this.(" "+<prefix>)[4] = <data>
list of data corresponding to the strings in [3].
Child nodes are this.(" "+<prefix>+<common>+<c>)
for all <c> in this.(" "+<prefix>)[2].
The root node is this.(" ").
If, e.g., there are 2 or more strings in the db beginning with a,
there will be a node this.(" a").
If all of these strings actually begin with "ani", then this.(" a")[1]=="ni".
The db consisting of the 5 correspondences
{"animal", #1}
{"anime", #2}
{"anil", #3}
{"anile", #4}
{"banal", #5}
would be represented
this.(" ") =={"", "a", {"banal"}, {#5}}
this.(" a") =={"ni","lm", {}, {}}
this.(" anim")=={"", "", {"animal","anime"},{#1,#2}}
this.(" anil")=={"", "", {"anil","anile"}, {#3,#4}}
In some cases one may merely wish to hold a collection of strings without trying to associate a particular datum with each string. One may then instead set up a db without the fourth field on each of the properties. In this case the datum is taken to be the found string itself and that is what gets returned by :find*() in the event of a successful search. :find and :find_key are then equivalent as are :find_all and :find_all_keys. To setup the db this way, do a :clearall(3). :clearall(4) reverts to the above described type of db with a separately kept datum. Note that you can't change the type without emptying the db. 3 and 4 are currently the only db types allowed.
say <text> w*hat
emote <text> abort
lis*t [<range>] [nonum] q*uit,done,pause
ins*ert [<ins>] ["<text>]
n*ext,p*rev [n] ["<text>]
del*ete [<range>]
f*ind /<str>[/[c][<range>]]
s*ubst /<str1>/<str2>[/[g][c][<range>]]
m*ove,c*opy [<range>] to <ins>
join*l [<range>]
fill [<range>] [@<col>]
ind*ent [<range>] @<col> [<filler>]
$editor_help.(cmdname) descrbes cmdname
$editor_help.insert descrbes insertion points (<ins>)
$editor_help.ranges descrbes range specifications (<range>)
You'll notice that nowhere does it say how to load in a given list of strings or how and where one may save said list away when one is done editing. These commands are supplied by the child editor object. The generic editor contains only the code for editing lines, though it defines additional functions for use by the children:
:loaded(player)
returns the index (player in this.active) if text has been loaded
from somewhere, otherwise returns 0.
Note that, by default, there is a difference between
having nothing loaded (:text(who)==0) and
having loaded something with no text (:text(who)=={}).
If you don't care about this distinction in a particular case,
just do (player in this.active) instead of this:loaded(player).
If you don't want your editor to make this distinction at all, do
@stateprop texts={} for <youreditor>
which changes the initial value of :text() to {}
In all functions below, 'who' is the index returned by :loaded(player)
BTW, be careful about using `player' in non-user (i.e., +x this-none-this) verbs - much better to have the user verb get the index with :loaded() and then pass that around.
Also be careful about suspend() and verbs that call suspend(). In particular, the character's index in the .active list can change during the suspend interval, so you must be sure to obtain the index (e.g., using :loaded()) again after the suspend() returns.
For your non-user verbs, we have
:ok(who)
returns E_PERM if the caller is not an editor verb and E_RANGE
if 'who' does not point to a valid session.
which should take care of the more egregious security holes (but maybe not the less egregious ones). For getting and loading text, we have
:text(who)
the current text string list or 0 if nothing loaded yet.
:load(who,text)
loads the given list of strings as the text to be edited.
this also resets the 'changed' flag and pushes the insertion
point to the end.
and various flags and properties (all of the set_* routines return E_PERM when not called from an editor verb, E_RANGE if who is out of bounds, E_INVARG if something is wrong with the 2nd arg, or the new value, which may not necessarily be the same as the 2nd arg (e.g., set_insertion(..,37) on a 5 line text buffer returns 6).
:changed(who)
has the text been altered since the last save/load?
(the child editor gets to define what "save" means).
:set_changed(who,value)
Any child editor command that is considered to save the text should do a
:set_changed(who,0).
Note that if the changed flag is 0, the session will be flushed when
the character leaves the editor, so you may also want certain commands to
do set_changed(who,1)...
:origin(who)
room where the person came from.
:set_origin(who,room)
can be used to change the room the person will return to when finished
editing. Since origin gets set even in cases where the person teleports
into the editor you probably won't usually need to do this.
:insertion(who)
current insertion point.
:set_insertion(who,linenumber)
linenumber needs to be a positive integer and will get
:readable(who)
whether the current editing session has been made globally readable.
:set_readable(who,boolean)
change the readability of the current editing session.
This is used by the publish/perish verbs.
We also provide
:invoke(...)
If the person has a previous unsaved (i.e., :changed()!=0)
session, we return to it, moving the character object to the editor.
If the person is already in the editor, this has no effect other
than to print a few nasty messages. In any case a :changed()
session must be aborted or set_changed(,0) before anything else
can be started
Otherwise, we pass the arguments (which are assumed to be the
result of some munging of the command line) to :parse_invoke(),
move the character to the editor and load whatever parse_invoke()
specified. The only interpretation the generic editor makes on
the arguments is that if the boolean value of the first is true,
this indicates that the person wanted to load something as
opposed to resume a previous session. Usually a command calling
:invoke will have a true (i.e., nonzero number, nonempty list or
string) first arg iff the command line is nonempty, in which case
'args' works fine for this purpose.
If the command parses sucessfully (:parse_invoke() returns a list),
we move the character to the editor if necessary and then call
:init_session() to set things up.
The child editor is assumed to provide
:parse_invoke(...)
given :invoke()'s arguments, determines what the person wants to edit.
It either returns 0 and reports syntax errors to `player',
or it returns some list that :init_session() will understand.
:init_session(who,@spec)
where spec is something that was returned by :parse_invoke().
Loads the text and sets the stateprops (below) to indicate that
we are working on whatever it is we're suppose to be working on.
:working_on(who)
returns a string X as in "You are working on X."
This is called by the 'w*hat' command, among other things.
Child editors may have their own properties giving state information for the various editing sessions. The value of each such property will be a list giving a value for each person in the editor. For each such property, you should, once the editor object has been created, initialize the property to {} and do one of
@stateprop <propname> for <editor>
@stateprop <propname>=<default-value> for <editor>
(0 is the default <default-value>)
Henceforth, adding and deleting new editing sessions will amend the list held by the given property. The value of the property for a given session can be obtained via this.<propname>[player in this.active] and can be changed with a corresponding listset() call. The usual idiom for an editor command is
if(!(who=this:loaded(player)))
player:tell(nothing_loaded_msg());
else
... various references to this.<propname>[who] ...
endif
To remove such a property from the list of such state properties:
@rmstateprop <propname> from <editor>
Note that you can only do this with properties defined on the child editor itself.
Sometimes you may wish to @stateprop a new property on an editor where active editing sessions exist. @stateprop will fail if the property in question does not hold a list of the correct length (== length(editor.active); one value for each editing session). You need to either give the @flush command to clear out all sessions and boot all characters currently in the editor or somehow manually initialize the property to a list of appropriate values and pray that nobody enters/exits the editor between the property initialization and the @stateprop command - this problem can be avoided by doing an eval() that does all of the initializations (beware of suspends()) and calls :set_stateprops directly.
Incidentally, the @flush command may be used at any time to clean out the editor or to remove all sessions older than a given date.
There are also numerous _msg properties that may be customized
@depart announced at the origin when :invoke() is called.
@return announced at the origin the character is returned there.
@nothing_loaded printed when user attempts editing
before anything has been loaded.
@no_text response to 'list' when :text()=={}
@no_change printed by 'what' when :changed()==0
@change printed by 'what' when :changed()==1
@no_littering printed upon leaving the editor with :changed()==1.
@previous_session printed by :invoke() when the person tries to start a
new session without aborting or saving the old one
The general procedure for creating a child editor:
. @create $generic_editor named <editor>
. define additional <editor> verbs/properties
At the very least you need 'edit' and 'save' commands.
Usually you can get away with just having 'edit' call :invoke();
Presumably, you'll need at least a command to load text from somewhere
as well as a command to save it back out.
. define a verb (somewhere) to invoke the editor
This could be just a one-liner that calls <editor>:invoke(args,verb).
Either that or
. you have to set up an exit somewhere whose destination is <editor>
. you have to advertise the object number so that people can
teleport to it.
. @stateprop x for <editor>
. if you want the 'abort' command to boot the person from the editor do
<editor>.exit_on_abort = 1;
. set <editor>.commands to be the list of additional commands defined
by <editor>.
Each element of the list is itself a list of the form {name,args}.
set <editor>.commands2 to be the list of commands that should appear
in the `look' listing, and should be a list of strings appearing
as names in .commands on either <editor> or some editor ancestor.
look at $verb_editor or $note_editor for an example.
. If you want to have help text for new verbs you define, create a child of
$generic_help and add properties to this object for each of the topics
that you want to provide help text.
Finally, set <editor>.help = {this object} so that the help system
knows to consult this object.
When a person uses the "help" command, the system:
1. retrieves a list of help databases to search, with
$code_utils:help_db_list();
2. queries those help database's for matching topics using
$code_utils:help_db_search();
2.a. each database is checked in the order given
(<db>:find_topics), with $help always being the final database
checked, until one returns a non-false value;
2.b. if $help is reached, it also checks to see if the topic name
matches any object in the person's vicinity, and returns that as
the topic if a match is found;
3. passes the result to player.location:help_huh() (if it exists)
in case the result should be modified;
4. if no topics were identified so far, asks $help:cmd_verb_help()
to find a match to any matching verb on the `player' or
`player.location' that has header documentation;
5. if still no matching topic is found, let
$wiz_utils:missed_help() know, if
$wiz_utils.missed_help_logging_enabled is true;
6. if a match was found, then call the help database that reported
the match (<db>:get_topic) and ask for the help text itself;
6.a. If the database is $help, and the help topic matched is
actually a nearby object, then <object>:help_msg() is called
to retrieve the help text if that verb exists;
6.b. If <object>:help_msg() doesn't exist or returns false, then
the text of <object>.help_msg is used.
A help database (in the sense of anything that is usable by $player:help()) is any object having the following three verbs:
:find_topics([string])
where string is a supposed help topic, returns a list of strings,
i.e., actual help topics that this db knows about, or some boolean
false value in the event that this db is clueless...
If no arguments are given, this should return a list of all topics
in the db
:get_topic(string)
given one of the strings returned by :find_topics this either
returns a list of strings (text to be spewed to the user) or
returns 1 to indicate that it has already taken care of printing
information to the user.
:dump_topic(string)
like get_topic, but instead returns the raw text of a help topic
as a (download/upload) script
In short if :find_topic reports that a particular db knows about a given topic
it returns the full topic name, so that :get_topic may be called on it later.
:dump_topic is used by maintainers (see $wiz:@gethelp) to edit help topics.
$generic_help and $help
-----------------------
The Generic Help Database, $generic_help, is the parent class of a particular kind of help database of which $help is an instance. On help databases of this type, every help topic has a corresponding property, interpreted as follows:
this.(topic) = string
one-line help text.
this.(topic) = {"*<verb>*",@args}
call this:<verb>(args,dblist) to get text where dblist is the list of
help objects that would have been consulted had the topic not been found
on this object.
this.(topic) = other list of strings
multi-line help text
For the {"*<verb>*",...} form, the current verbs available are
{"*forward*", topic, @rest}
- get help text for topic and then append the lines of `rest'.
rest may, in turn, begin with a "*<verb>*"...
{"*pass*", topic, @rest}
- get help text for topic from the first help database after this one
that actually has help text for topic, and then append lines of `rest'.
As with "*forward*" rest may, in turn, begin with a "*<verb>*"...
{"*subst*", @lines}
- All occurences of %[exp] in lines are replaced with the value of exp
which is assumed to evaluate to a string.
All lines beginning with %;exp are replaced with the value of exp
which is assumed to evaluate to a list of strings.
Evaluation is done using $no_one's permissions so exp in either case
can only refer to public information.
{*verbheader*, object:verb, @rest}
- returns the verb header documentation lines for object:verb, with @rest appended
{"*index*", title}
- returns a list of all topics in this database, arranged in columns.
title is used as a heading for this index.
Individual help dbs are free to define additional verbs that may be used in this context. $help itself defines the following additional such verbs:
{"*index_list*"}
- returns a list of all index topics in all databases in the search list.
An index topic is one whose actual text is {"*index*", something}.
When creating a help db, you should be sure to make an index topic.
{"*full_index*"}
- prints indices for all help databases in the search list.
It should be noted (once again) that help databases need not be children of $generic_help, so long as they have :find_topics/:get_topic/:dump_topic working as specified above.
Instead of needing several properties, only one is required to store a list containing values for all of the options. An "option package" (pkg, below) is then an object of this class, which provides routines for manipulating such lists.
The set of option names is divided into a set of "real" options, those whose names will actually appear in a given list, and "extras" which are either synonyms for or represent combinations of real options.
pkg:add_name(name) adds name to .names (remove it from .extras if there)
pkg:add_name(name,1) adds name to .extras (remove it from .names if there)
=> 1 - ok, 0 - already added, E_INVARG - illegal name, E_PERM
pkg:remove_name(name) remove name from either .names or .extras
=> 1 - ok, 0 - not present, E_PERM
(I added the commands "@addname <option> to <pkg>" and "@rmname <option> from <pkg>" to call these. EM)
Every option added should have an associated .show_foo property added to the pkg object (by hand). For instance,
pkg.show_foo = {"Your foo setting is off.", "Your foo setting is on."}
where the first string is the -foo setting and the second the +foo setting.
Options with more complex settings (eg. @myoption complex="this is complex") should
implement a :show_foo verb as described below.
For setting or retrieving values we have
pkg:get(options,name)
=> value (or 0 if name isn't a real option)
pkg:set(options,name,value)
=> revised options (or string error message if something goes wrong)
where "options" is generally "player.display_options" or whatever option property is being processed.
Note that simple boolean options can be checked using
if (foo in player.pkg_options)
However, this breaks the encapsulation of the system, and therefore using pkg:get() is preferred.
A sample usage is: if ($mail_options:get(player.mail_options,"netmail"))
Most option packages have associated verbs on $player, that simplify this. For instance,
if (player:mail_option("sticky"))
There are related verbs for: edit_option, display_option, list_option
By default, a given option can only be a boolean flag, having one of the values 0 (absent from the list), or 1 (present in the list). :set translates 0/""/{} to 0 and any other non-object value to 1.
One may however designate a wider range of possible values for an option "foo" by either installing one of
pkg.type_foo
- list of allowed types,
e.g., {NUM,STR} => must be a number or a string
e.g., {OBJ,{OBJ}} => must be an object or a list of objects
for anything fancier use:
pkg:check_foo(value)
=> string error message or {value munged as desired}
In general, the only restriction on option values is that 0 is the only false value; setting an option to "" or {} sets it to 0. Every option defaults to 0, and no matter what you install as .type_foo or :check_foo(), 0 will always be a legal value for option "foo".
When presented with an option that is in .extras, :set will typecheck the value as described, however, then :actual(name, value) will be called to obtain a list of {name-of-real-option, value} pairs indicating which combination of real options should be set.
Other verbs
pkg:parse(args,...)
parses the command line arguments of a @whatever_option command
=> {optionname, value} if the person wants to set an option
=> {optionname} if the person wants to view an option
=> string error message otherwise
one may install pkg:parse_foo to parse arguments for option "foo"
!foo => {"foo",0} (:parse_foo not called)
foo= => {"foo",0} (:parse_foo not called)
-foo => {"foo",0} (:parse_foo not called)
+foo => pkg:parse_foo("foo",1)
foo=word => pkg:parse_foo("foo","word")
foo word1 word2 => pkg:parse_foo("foo",{"word1","word2"})
foo is word1 word2 => pkg:parse_foo("foo",{"word1","word2"})
pkg:show(options,name|list of names)
=> list of strings describing the current value of the named option(s).
calls pkg:show_foo(options,list of names) or
refers to pkg.show_foo to describe option "foo"
The pkg:show_foo verb (if any) should return
=> {foo, string describing current setting for option foo}
(I added the command "@document <option> on <pkg>" for adding and changing the documentation on simple on/off options. EM)
(see sources for details... at some point I'll finish writing this... -Rog)
See: $generic_option
This object contains just the raw verbs for getting data from gopher servers and parsing the results. Look at #50122 (Generic Gopher Slate) on LambdaMOO for one example of a user interface.
:get(site, port, selection)
Get data from gopher server: returns a list of strings, or an error if it couldn't connect. Results are cached.
:get_now(site, port, selection)
Used by $gopher:get. Arguments are the same: this actually gets the
data without checking the cache. (Don't call this, since the
caching is important to reduce lag.)
:show_text(who, start, end, site, port, selection)
Requires wiz-perms to call.
like who:notify_lines($gopher:get(..node..)[start..end])
:clear_cache()
Erase the gopher cache.
:parse(string)
Takes a directory line as returned by $gopher:get, and return a list
{host, port, selector, label}
host, port, and selector are what you send to :get.
label is a string, where the first character is the type code.
:type(char)
returns the name of the gopher type indicated by the character, e.g.
$gopher:type("I") => "image"
See: $generic_help
The routine form for a URL to retrieve a help text is:
http://moo.du.org:8000/help/no_object/topic?mail
where in this example the help text for the "mail" topic is returned.
The form for returning the header text for a verb is:
http://moo.du.org:8000/help/no_object/topic?$string_utils:space
The system can also return texts associated with objects:
http://moo.du.org:8000/help/20
to return the help text for object #20 (usually $string_utils).
For objects that have their own help databases associated with them,
you can obtain the help text for a topic in one of those specialized
databases with:
http://moo.du.org:8000/help/50/topic?fill
where in this case the object is the Verb Editor (#50), and "fill" is
the topic name.
The Help Text WebViewer also includes a search field, where people
can enter the name of a topic to display. At this time, the
WebViewer does not do keyword searches, although this functionality
could be added.
In order to minimize the potential for lagging the MOO through high
anonymous access of the WebViewer, the object will only accept at
most a certain number of simultaneous anonymous transactions. This
is set by $help_webviewer.max_anon_calls property (set to 4 by
default). Note that if an anonymous transaction is interrupted due
to a traceback error, that call's record will not be cleared, and as
a result the object will not know that it isn't still processing that
transaction. As a result, the $help_webviewer.current_anon_calls
property will no go back down to zero. Should several of these
events occur, the Help Text Webviewer may refuse any new anonymous
transcations, even though it isn't really processing any currently.
To fix this, just "@set $help_webviewer.current_anon_calls to 0" to
reset the value.
To indicate what objects should be cleaned:
:add_cleanup(object[, requestor[, where]])
Ask the housekeeper to clean 'object' for 'requestor' to 'where'.
Requestor defaults to `player'.
Where defaults to object.location.
:remove_cleanup(what[, requestor])
Remove 'what' from the cleanup list at 'requestor's request.
Will remove it only if 'requestor' made the original request and owns
the object or the destination.
To actually get the housekeeper to clean stuff up:
:cleanup([insist])
Clean up character's objects. Argument is 'up' or 'up!' for manually
requested cleanups. 'up!' means to clean things even if it's against
the housekeeper's better judgement.
:replace(object[, insist])
Clean up the indicated object. 'insist' is as in :cleanup.
:continuous()
Starts the housekeeper cleaning continuously, killing any previous
continuous task. This should be called only when starting up a new MOO,
or if something has gone wrong, as normally it will just keep going
without any help.
:litterbug()
Clean up all the places in housekeeper.public_places by getting rid of
all contents not in their .residents lists. This is called by
:continuous, so it doesn't need to be called directly.
To find out what's being cleaned to where for whom:
:cleanup_list([whom])
Show 'player' the personal cleanup list for 'whom', or the housekeeper's
complete list if no argument is given.
:clean_status()
Show 'player' a brief summary of eir personal cleanup list.
Although it doesn't yet have any HTML-specific commands, these may be
added in the future to facilitate its use in creating HTML texts.
However, you can always create the HTML text in your favorite editor,
then paste the part between the <BODY and </BODY> tags into the HTML
editor to attach that HTML text to an object.
1) http://HOSTNAME:PORT
2) http://HOSTNAME:PORT/?WEBPASS
3) http://HOSTNAME:PORT/xxWEBPASS
4) http://HOSTNAME:PORT/xxWEBPASS/CODE
5) http://HOSTNAME:PORT/xxWEBPASS/CODE/OBJECT
6) http://HOSTNAME:PORT/xxWEBPASS/CODE/OBJECT/REST
7) http://HOSTNAME:PORT/xxWEBPASS/CODE/OBJECT/REST?SEARCH
Where HOSTNAME is currently bioinfo.weizmann.ac.il,
PORT is 8888,
xx are two random characters,
WEBPASS is the user's web password and may be blank,
CODE is the web application's identity,
OBJECT is an object number (without the #),
and REST is anything else you append to the URL.
When the MOO receives a web connection, it parses it as described
above, and does the following:
- a URL of type 1) will simply show the MOO's gateway page, unless
there is a form attached (which is then evaluated for
authentication information).
- a URL of type 2) or 3) will check the webpass.
- if it's omitted then either web cookie or web "domain"
authentication is used.
- if it's bad, it will show the MOO's identification screen.
- if it's OK, it will show the list of web applications.
- a URL of types 4), 5), 6) or 7) will check the CODE.
- if there isn't a code of a valid web app, it will show the list
of apps.
- if it's a valid code, it will call the application's :method_get
or :method_post giving it as parameters: (who, what, rest,
search), which are: the user whose webpass is being used,
the object number that was parsed, the REST, and the SEARCH
if any.
_____________________________
Web transactions typically follow the pathway:
$http_port
|
V
/$http_handler:handle_http10
\$http_handler:handle_http09
|
| <-> parse_line
|
| <-> /web_authenticate
| \cookie_authenticate
|
| <-> init_taskprop
V
:process <-> /$webapp:method_get <-> /object:html
| \$webapp:method_post | object:do_post
| \object:get_vrml
|
| The `process' verb determines which $webapp to call and
| processes the result into its final form.
|
make_headerlist
|
V
tell_quick_and_die
_____________________________
These properties are defined on $http_handler
task_details
task_index
These store information about the open web transactions
that can be retrieved with $http_handler;retrieve_taskprop.
Also, any verb called during the transaction can submit new
task properties that can then be retrieved by any other
verb when called. Some default properties can only be
retreived by wizardly verbs.
total_webcalls
Total number of web transactions handled by this object
since its installation.
webpass_handler
The object number of the webpass handler object. The
webpass handler is not corified.
gateway_html
The default web page displayed when someone connects to
$network.site on a port with an $http_port object
listening. This should have a form allowing authentication
(see the default value for an example).
wizwebpass_disallowed
Almost obsoleted mechanism for regulating which
authentication system wizards may use to open a web window
for their wiz character.
version
The currently installed version of the BioGate system.
output_timeout
If a transaction takes longer than this number of seconds,
it is assumed to have failed (probably due to a traceback),
and the connection is broken.
password_failed_text
Text returned if a web transaction is incorrectly
authenitcated.
exempt_from_pads
By default, the $http_handler assumes transactions are
requests for HTML documents, and builds a proper header and
footer with the appropriate tags. Some transactions, like
VRML requests, shouldn't have these and are "exempted from
pads." Although the $std_vrml10viewer and $frame_manager
are automatically exempt, any other kids of the $webapp you
want exempted should be added here.
anon_access_limits
A list of two elements, that set usage limits beyond which
unauthenticated transactions are rejected. The first
element is the maxiumum number of concurrent web
transactions and the second is the maximum MOO lag in
seconds.
lag_meter
Object that tracks and reports lag. Found in most MOOs
though not part of LambdaCore. If not set, lag-based
features are disabled.
too_much_load_text
HTML doc sent when the MOO has too high a load to process
unauthenticated HTTP transactions.
java_clients
List of Java telnet client handlers allowed to use the web
system.
javaclient_codebase
The subdirectory at the MOO's site where java clients are
found. Used as $network.site +
$http_handler.javaclient_codebase +
$jclient_handler.client_name
login_is_http09
If true, treats call transactions that come through $login
as HTTP/0.9 (rarely used).
port_handlers
List of objects permitted to call the handle_http09 and
handle_http10 verbs. Generally kids of $http_port, and
sometimes $login.
auth_ports
Almost obsoleted mechanism for regulating which
authentication system wizards may use to open a web window
for their wiz character.
robots_txt
Sent upon requests for "/robots.txt" and tells web spiders
not to scan the MOO for web pages (which could cause CPU and
networking load problems). Note that you can use this to
restrict web spiders and other web cataloging robots to only
portions of your MOO. By default, everything but the gateway
page is off limits. For details on constructing a robots.txt
entry, see:
http://info.webcrawler.com/mak/projects/robots/robots.html
The $http_port:do_login_command verb is the main workhorse of the
object. It parses the incoming transaction's first line to
determine the method (GET/POST), the URI (specifies the requested
resource), and the protocol version (generally 1.0). Transactions
are then passed to $http_handler:handle_http09 or
$http_handler:handle_http10 depending on the HTTP version of the
incoming transaction.
User commands (wizardly use only) on the $http_port are:
@set-port <port number> on <listener>
set the port to listen on
@startlistening on <listener>
the object starts listening
@stoplistening on <listener>
the object stops listening
These have executable equivalents, useful if your MOO automatically
starts listening with an $http_port upon startup. These
are: set_port, listen, and unlisten.
Verbs on the $jclient_handler work with the Cup-O MUD client by
default, but can be overridden on child objects to give new
functionality.
page.
The "client_name" property must be set for the client handler to
function. This is actually the subdirectory and class file name to
be appended to $http_handler.java_clients when forming the URL for
retrieving the Java code.
For instance:
$network.site = moo.site.org
$http_port.handles_port = 8000
$http_handler.java_clients = "/java/"
<jclient_handler>.client_name = "CupOmud/CupOmud"
Would yield the URL:
http://moo.site.org:8000/java/CupOmud/CupOmud.class
The "default_preload_page" property contains the text to be displayed
in the web page frame of the user's web browser window until the
telnet client finishes loading and issues a "display URL" command of
its own. You can use the default value if you wish.
The "client_windowname" and "html_windowname" properties give the
names of the frames that will hold the client applet and the HTML
text display, respectively.
The "float_client_frame" verb returns true if the client will be set
in a floating independent frame. Typically it just returns the value
of the "float_client_frame" property, but may also check user
preferences to determine a result.
The "make_applet_html" verb is called by the $frame_manager and
returns the HTML document containing <EMBED> tags that will load the
Java telnet client.
The "update_webframe" verb sends a command (using MCP in the case of
Cup-O MUD) to the the client that causes it to force the web browser
to load a new HTML document into a specified frame.
The "user_autoconnected" verb is called when a person first connects
to the MOO through a Java telnet client, typically through the
$login:preapproved system.
The "preload_page" verb returns the HTML document to be displayed in
the usual web page frame until the first "display URL" command is
issued by the Java telnet client.
.default_rooms
These are rooms all users see with the @rooms command, and to which
they can @go. Add and remove rooms with the @addroom and @rmroom
command.
.guest_lines
This property is a list of texts randomly chosen among to be
displayed when a guest connects (see $limbo.con_guest). Each new
section starts with a period, so a line without a period as the
first character indicates a continuation line. This property can
be customized.
If your guests connect in quiet cubicles, these texts are
irrelevent.
.purge_candidates
.vspo_purge_candidates
.purge_deadline
.purge_time
.purge_exceptions
.purge_notice_txt
.to_be_purged
The purge system is a still incomplete set of utilities intended to
aid in identifying and recycling outdated, unused characters and
their posessions. The properties in this section can be ignored,
at this time.
.desc_txt
.info_txt
.gend_txt
.home_txt
.wrap_txt
.msgs_txt
.no_bother_txt
.header
.presskey
This section is for an as yet incomplete system, and its
values can be ignored at this time.
This section contains various messages displayed occasionally to
characters with $player.newbie set true. Users can set this with
"@newbie on|off" and it's intended as a gentle reminder to people
to customize their characters. The $player:newbie_prompt scans the
user's characteristics to determine which message should be
displayed.
.banish_text
The .banish_text is displayed to guests who are banished by users
with the @banish command. This can be customized.
.tag_notify
The .tag_notify property stores character objnums to be notified
when they next connect that they have been @tag'd.
.banishing_disabled
.tagging_disabled
The .banishing_disabled and .tagging_disabled properties store
local user restrictions on banishing and tagging. See the help
texts for the commands that modify these properties, @notag and
#nobanish.
.first_time_connect_script
This is a script, which if set is displayed to people the first
time they connect. See $guest.login_script for and example of the
format. This system is currently under revision.
.converted_msg
.oconverted_msg
The .converted_msg and .oconverted_msg texts are displayed when a
VSPO character is made into a regular character. These can be
customized.
.auto_guest_log
Guests from sites whose names match the strings in this list are
automatically logged when they connect, as if someone immediately
typed @witness right after they connected. The logs are not
stored unless someone uses @banish on them. The verb
$local:check_auto_guest_log checks this property. This property
can be customized by hand (using @set).
.projects
.projects_mail_recipient
These properties are part of the wizard projects system. See "help
@projects" for more info.
.out_exit_target
This is used by the @testexits command to check if rooms are
properly linked to the main MOO with exists aliases as "out."
It's only relevent if you have such a construction policy, that
people should be able to reach the room this property identifies,
by repeatedly typing "out" until they arrive. If the MOO lacks
such a policy, both this property and the $builder:@testexits
command can be removed.
.checkpoint_started_msg
.checkpoint_finished_msg
.broadcast_checkpoint_messages
This section causes every connected user to be told when
checkpoints start and end. Some administrators may find it
appeases the users a bit if your MOO lags a lot during
checkpoints, since people will at least understand why. If
.broadcast_checkpoint_messages is true, then the two messages are
displayed appropriately. All three of these properties can be
customized by hand (using @set).
.nope_header_txt
.nope_footer_txt
.nope_txt_substitutions
.name_nope_txt
.reason_nope_txt
.info_nope_txt
.vspo_nope_txt
These properties are used by the @rejected command system to create
an email to send (with $wiz_utils:compose_nope_txt). They can all
be customized for the MOO, generally with @edit. The .nope_header_txt
is always used at the top of the letter, and the .nope_footer_txt
always included at the end. In between are any of the
<reason>_nope_txt properties chosen by the person rejecting the
application. See "help $local:nope_header_txt" for details of how
to use the .nope_txt_substitutions property.
.new_player_email_txt
This property holds the text of the email sent to characters newly
made with @created. It should be customized for the MOO.
.idle_check_enabled
.idle_check_interval
.idle_limits
.idle_boot_protect
.idle_warning_text
If .idle_check_enabled is true, then people idle for longer than
the values in .idle_limits are warned (with .idle_warning_text)
and then disconnected, unless their character's object number is
in the .idle_boot_protect list or they are a Wizard or Manager.
Characters are checked for idleness every .idle_check_interval
seconds. By default, the values in .idle_limits (read by
$wiz_utils:idle_check, where there is further documentation) are a
warning after 55 minutes and booted after 60 minutes idle.
.autosubscribe_lists
This is a list of oject numbers, each of which should be a child of
$mail_recipient. All newly created characters are automatically
subscribed to the mail-folders in this list. It should be
customized by hand (using @set).
.character_lists
This is a list of property references in the form { {$pointer STR,
propname STR}, ... } referencing lists of character object numbers
that should be cleaned when a character is recycled. It should be
customized only if the core is modified such that new lists of
character objnums are used. Quoting from $player:recycle...
The next lines remove the character from various other places
where character references appear. It presumes the caller
will have perms to modify these, else they're skipped.
.rintintin
This property is used by $player.@locate only, to insure people
only have one such search running at a time. The property is
unused until $player:@locate is modified to fit corification and
not routinely deleted during core extraction.
.not_builder_msg
This is the message displayed when someone who is not a builder
tries to use the @dig or @create command. It should be customized
for the MOO so that people are told how they may get builder
permissions.
.last_creation_check
.mailto_creation_check
These properties are used by the object creation check system,
which sends daily mail to all characters listed in
.mailto_creation_check about what objects have been created during
the last 24 hours. This can be useful for noting what areas of
the MOO are being build, and who is working on what. The object
creation check system is run once per day, launched by the
$local:checkpoint_hook verb. The .mailto_creation_check property
can by edited by hand (using @set).
.scandal_mongers
.watch_mail_interval
.watched
.logs
The log mailing system is currently under development. Unless the
$wiz_utils:period verb is running (activated by hand), it won't
function.
Every .watch_mail_interval seconds, the $wiz_utils:periodic verb
runs. Each character listed in .watched (each of which presumably
has permanent logging activated; i.e. their $player.permanent_log
property is set) has their collected log sent to each person
listed in .scandal_mongers, and their $player.log property is
transferred to .logs and then cleared. Note that if mailed
logging is activated, the $local.logs will grow endlessly until it
is cleared by hand (with "@set $local.logs to {}").
.email_address_required
If this is set, then people with a blank email address
($player.email_address=="") are issued the message in
$local.email_missing_text when they connect.
.trustees
This property is specific to DU MOO and is removed during the
eduCore extraction process.
COMMANDS FOR UNCONNECTED USERS
Recall that for each line that an unconnected person types, the server parses that line into words (the same way normal commands are parsed into a list of words that is then assigned to `args') and then #0:do_login_command is called.
:parse_command (@args) => {verb, @args}
given the sequence of arguments that were fed to #0:do_login_command
this returns the name of a verb on $login to be called together with a
list of arguments to be passed to it.
By default this just returns args iff args[1] names an actual verb on $login that is +x and has args {"any","none","any"}. Otherwise, it returns one of
.blank_command - verb to call if command line is empty
.bogus_command - verb to call if command line otherwise unintelligible
In both cases :parse_command returns a verbname followed by the entire args list passed to it (including the would-be verb at the beginning if any).
Currently the following verbs are availabe to non-connected people
h*elp @h*elp - print .welcome_message
? - print a short list of available commands
w*ho @w*ho - print a list of logged in people (excluding wizards)
co*nnect @co*nnect - connect to an existing character
cr*eate @cr*eate - create a new character
up*time @up*time - tell how long the server has been running
version @version - tell which version of the server is running
q*uit @q*uit - logoff
Adding a new command is fairly straightforward; just create a verb on $login, making sure a previous verb doesn't already match the name you want to give it. Then give it args of "any" "none "any" and make sure it is +x. Such a verb should begin with `if (caller != #0) return E_PERM; ...' so as to prevent anyone other from a not-logged-in person from making use of it.
CUSTOMIZATIONS
.welcome_message
- the message for "help" to print.
.create_enabled
== 0 => `create' prints .registration_string if one tries to use it
== 1 => anyone from a non-blacklisted site (see `help blacklist')
may use `create' to make a new character
.registration_address
- an email address for character creation requests
.registration_string
- string to print to people to give them information about how to get
a character created for them, .registration_address is substituted
for %e, % for %%
.newt_registration_string
- string to print to @newted characters (see `help @newt').
same substitutions as for .registration_string.
Other verbs
:registration_string() => .registration_string with substitutions
:newt_registration_string() => .newt_registration_string with substitutions
:player_creation_enabled(connection)
decides whether someone on connection should be allowed to create
a character. If you decide this shouldn't depend strictly on the blacklist
and on the value of .create_enabled, here's where the extra code can go.
:check_for_shutdown()
prints a warning message to append to the login banner in the event
that the server will be going down soon.
:check_player_db()
prints a warning message to append to the login banner in the event
that $player_db is being reloaded to warn people that their character
names might not be recognized.
SITE LOCKS
see `help blacklist'
This object contains a two distinct sets of routines:
1. utilities for performing basic mailsystem functions, e.g.,
matching on recipient names, resolving mail forwarding,
formatting messages, sending messages
Recipient Matching
match - match on a $mail_recipient
match_recipient - match on either a $mail_recipient or a character object
match_failed - print angry messages to the user for $failed/ambiguous_match
look_self - provides a list of available $mail_recipients
check_names
touch
accept
Message Format
make_message - produces a message in the canonical transmission format
name - single recipient => string for address field
name_list - list of recipients => string for address field
parse_address_field - address field string => object list
Sending Messages
send_message - advertised message sending routine.
raw_send - raw message sending routine
(only called by $mail_editor:send and this:send_message)
resolve_addr - converts a given list recipients into a list of actual
recipients and objects to be notified.
sends_to - Does X forward (transitively) to Y
Mail Options
option
option_verbose
2. canonical versions of mail_recipient verbs
Ideally, the verbs to perform operations on a given mail recipient would be located on the recipient itself, except for the fact that these verbs also need to be located on characters, which for various reasons, shouldn't be children of $mail_recipient. Multiple inheritance would solve our problems, but we don't have it yet. Ergo, both $mail_recipient and $player refer to the following verbs here:
display_seq_full print entire text of messages (@read)
display_seq_headers print headers of messages (@mail)
rm_message_seq remove messages (@rmm)
undo_rmm undo last rm_message_seq (@unrmm)
expunge_rmm flush removed messages (@unrmm expunge)
list_rmm list removed messages (@unrmm list)
renumber renumber messages (@renumber)
msg_summary_line msg header => display_seq_headers/list_rmm summary line
parse_message_seq command line msg sequence spec => message sequence
new_message_num => message number of next new message
length_all_msgs => number of messages (total)
length_num_le => number of messages numbered <= some number
length_date_le => number of messages dated <= some date
exists_num_eq => true iff there exists a messsage with the given number
from_msg_seq => message sequence of msgs from given sender(s)
to_msg_seq => message sequence of msgs to given recipient(s)
subject_msg_seq => message sequence of msgs with subjects containing text
body_msg_seq => message sequence of msgs with bodies containing text
messages_in_seq => list of {message number, message} pairs
messages == :messages_in_seq(1,:length_all_msgs()+1) (obsolete)
The $mail_agent versions of these verbs are set_task_perms(caller_perms()) and perform their operations on caller, which in turn is assumed to have done any necessary security checks.
The "headerlist_len" property is the length of the headers list
displayed when someone browses a folder.
The "guest_subscribed_folders" is the list of mail folders (as a
LIST of OBJ numbers) that guest and anonymous web users are shown as
their "subscribed" folders. They can access the others (that are
public) through the "list all folders" link, but this is basically
One source of confusion is that the terms "mail recipient", "mail folder", "mailing list", and "mail collection" really all refer to the same kind of object. It so happens that $mail_recipient serve several distinct functions and we tend to use whatever term happens to best match the application under discussion, e.g., it's a "mailing list" if we're playing with its .mail_forward property but it's also a "mail folder" if we're examining the messages that have been saved in it.
Note that, by default, a freshly created recipient is accessibly only by you. If you wish to make a publically accessible recipient, set .readers=1. Furthermore, if you want to allow a message on your recipient to be removed by its sender without your intervention, set .rmm_own_msgs=1. Finally, in order for other people to be able to refer to your recipient by name, the object must reside in $mail_agent. $mail_agent will not accept the object unless it has an actual description and a name distinct from all other mail recipient names/aliases.
Topics:
MR-access -- controlling read, write and send access to a recipient
MR-naming -- naming conventions and how to match on recipient names
MR-sequences -- message sequence arguments to $mail_recipient verbs
MR-reading -- reading messages/headers on recipients
MR-searching -- searching message lists for patterns in certain fields
MR-writing -- removing and renumbering messages
MR-subscribing -- updating .mail_forward, .mail_notify
and the story of .current_message
MR-setup -- Setting or changing the configuration for a mail recipient
Some Manager commands may be available to all managers, irregardless
of their assigned responsibilities.
Related Topics:
@manager -- wizardly command for managing Managers
This system will eventually be adjusted to supply location-sensitive
maps, keyed to the user's location, but for now using "map" alone
returns the map in the "text" property of $map. It will also be
integrated with the $domain system. the MOO in general.
Using "@edit map" edits the main map, which is returned when someone
just types "map" without specifying any particular one. Other maps
are entered as properties on the $map object, with the property name
as the name of the map to the map library. To add a new map, you
can:
@addmap <note> to $map
where <note> is any $note whose text is the ASCII art map that should
be added. After entering the command, you'll be prompted for the
name of the map, which should have no spaces in it.
from:<who> - created by <who>
subject:<who> - character created named <who>
body:<email> - posting for person with given <email>
from:<who> - progbit set by <who>
subject:<who> - progbit set on character named <who>
1. @create $news_item called <whatever>
2. @edit <whatever>
(compose the body of the news item and save it
3. @announcement <whatever> is <message displayed to users at login>
4. @addnews <whatever>
The @addnews command moves the news item to the News Article Database
($news), and announces the new news item to all connected users.
Note that if you edit a news item that has previously been added to
the news database (with @addnews) and save the changes, the news item
will be considered `fresh out of the press' once again, and announced
to everyone all over again. You can use `@contents $news' to see
what news item objects are currently published.
News articles are note objects, made from the Generic News Item ($news_item).
Below is a brief description of the two user-verbs associated with $news.
$news:@addnews
Syntax: | @addnews <news>
Add <news> to the news article database ($news). <news> should be a child of the $new_item (the Generic News Item) |
$news:@rmnews
Syntax: | @rmnews <news-index>
Remove <news-index> from the news article database ($news). |
(1) Its origin is sufficiently uncertain so that there is no obvious way of deciding whose permissions it should run under.
(2) The code itself is potentially malicious, i.e., to the extent that one does not want to be evaluating it using one's own permissions.
set_task_perms($no_one); is thus the canonical idiom in wizard code for rendering anything that follows mostly harmless. For use by ordinary programmers, we have:
$no_one:eval(string)
which attempts to evaluate an arbitrary string using $no_one's permissions.
string is either an expression or ";" followed by one or more statements, of which the final semicolon may be omitted. return values are what eval() would return (either {1,value} or {0,@error_messages}).
To set the initial amount of object quota people have, set the
following properties:
$object_quota_utils.default_player_quota
$object_quota_utils.default_builder_quota
$object_quota_utils.default_programmer_quota
using "@set $object_quota_utils.default_player_quota to 0" for
instance. To be extra cautious, you should set the same values on
each character class generic:
$player.ownership_quota
$builder.ownership_quota
$builder.ownership_quota
$prog.ownership_quota
See `help $byte_quota_utils' for information about byte-based quota.
Commands availble are:
look $player_db
Shows when the last check and last load were performed.
@check $player_db
Checks the database for recycled or @toad'ed characters and removes
them.
@reload $player_db
Completely clears and reloads the $player_db with all currently
valid character's names and aliases.
Executable verbs supplied include
:find(string) => character obj or $ambiguous_match or $failed_match
:find_exact(string) => character obj or $failed_match (does not do partial matches)
:find_all(string) => list of all matching registered characters
:insert(string, who)
records that string is now a name or alias of <who>
:delete(string)
removes string from the db
:available(string)
returns 1 if string is available as a character name or alias,
an object if string is in use, or 0 if string is otherwise unavailable.
:load()
resets the db, inserting all current registered character names and aliases. The time() of the last load is stored in $player_db.last_load
:check()
checks for recycled and toaded players that managed not to get
expunged from the db. The time() of the last check is stored in $player_db.last_check
The internal representation and all of the above verbs (except :load() and
:available()) are as described for $generic_db.
It should be noted that for any application that involves resolving a character name from a command line, you should be using $string_utils:match_player() rather than $player_db:find(), since the former will deal correctly with other ways of referring to people apart from their names and aliases (e.g., literal object numbers, "me", "$no_one"...).
:load() needs to be done periodically as it is possible for the $player_db
to get out of synch with reality. In particular, there is currently no way
to block someone writing his own character's :recycle() verb that neglects to
remove that person's names from the $player_db.
While a :load() is in progress the .frozen property is set to 1 to indicate that any results of :find*() are not to be trusted.
Rather than having the server built-in recycle() and create() functions handle the creation and destruction of objects, a recycling center has been created to simulate these actions by changing objects that would have been recycled into children of $garbage (The Generic Garbage Object) and making them owned by Hacker, and then when they're needed again, to avoid a raw create() command, those objects are given to whoever's asking for them.
Most Useful Verbs
-----------------
$recycler:_recycle( object )
This will effectively recycle an object. (As a point of fact, it changes ownership of the object to Hacker and makes the object a child of $garbage.) It handles .ownership_quota and .owned_objects properly. Generally, use this instead of a recycle() in your verbs.
$recycler:_create( parent object [ , new owner object ] )
This effectively creates an object (with the specified parent, if possible, and with the specified owner, if possible; these are the same restrictions as on the server create() builtin). This is what should generally be used instead of create() in your programming.
$recycler:valid ( object )
This is a variant of the server built-in valid() except that it handles the $garbage objects as well. It returns a 1 if the object specified -is- valid and is -not- a $garbage object.
Other Notes
-----------
request <object> from <recycler>
This is not an internal verb (it's !x). It is, however, a command-line verb that can be used to request a specific object from the recycler. It's also useful for the creation of objects like a Magic Number Repository. When the object is removed from the recycler, the .announce_removal_msg is announced to the room if it's set (it's piped through $string_utils for pronoun substitution).
NOTE: This verb has been disabled from the original LambdaCore version. See $recycler:take_object instead.
show-history <recycler>
This is a wizardly verb which allows wizards to check the `history list' of the recycler. The history maintains the latest ($recycler.nhist) entries.
$recycler.orphans
This maintains a list of objects for which the recreation process got mangled. It ought to be checked every once in a while to see what's up.
@clear-orphans from <recycler>
This command will step you through each item in <recycler>.orphans, providing information and making a recommendation about how to deal with that object. It also allows you to remove the item from the list.
Executable verbs are:
add(who OBJ, email STR, comment STR) -> none
Add a new character email registration.
find(email STR) -> { {who OBJ [,comment STR]}, ...}
Returns a list of character object numbers (with associated
comment, if any), that have been associated with the specified
`email' address. Note that some may correspond to characters that
have been recycled. Returns $failed_match if no match, or
$ambiguous_match if the `email' is a prefix for more than one
registered email address..
find_exact(email STR)
Like :find but returns list of characters that match or
$failed_match (nerver $ambiguous_match).
find_all(email STR)
Like :find but returns all registered entries with addresses for
which `email' is a prefix. Note that only searching by userid is
really an appropriate use for this. Use :suspicious_address for a
method that properly examines the internet address structure.
suspicious_address(email STR) -> {email STR, ...}
Returns a list of email addresses that are related to the specified
one, suggesting they may belong to the same person. For instance,
searching for "person@school.edu" will also match
"person@node.school.edu".
suspicious_userid(userid STR) -> BOOL
Return true if userid is root or postmaster or something like that.
describe_registration(find_result LIST) -> description LIST
Accepts the successful results of one of the :find verbs, and returns
a list of strings giving a plain language description of the
information.
Each line has the form:
<character> (<objnum>) current email: <email> [<comment>]
$request_booth:@addq*uestion
Syntax: | @addq*uestion <subject> |
Adds a question about <subject> to the character application for
guests or VSPOs. The verb prompts you for the exact wording of the
question and a string that will appear as an entry-prompt (the words
you see in the first half of the standard [] prompt).
$request_booth:@removeq*uestion @rmq*uestion
Syntax: | @removeq*uestion <subject> |
Get rid of the question for <subject> in the character application form for guests and VSPOs. If you aren't sure what subjects there are enter '@listq subjects' and you'll get a list of them, complete with indices.
$request_booth:@moveq*uestion
Syntax: | @moveq*uestion <index1> to <index2> |
Moves the question currently at position <index1> in the character
application for guests and VSPOs to the position <index2>.
$request_booth:@listq*uestions
Syntax: | @listq*uestions [<subject>|<index>|subjects|all] |
This verb allows you to view those questions contained in the
character application form for guests and VSPOs.
Args: 'all'|<none> to see a list of subjects and corresponding questions
<subject>|<index> list the question and prompt for a specific subject.
'subjects' list question subjects and their indices.
The following additional properties are defined on the $request_booth
and should be appropriately customized using the @edit command (e.g.
@edit $request_booth.introduction_msg):
$request_booth.introduction_msg
$request_booth.vspo_introduction_msg
One of these messages is displayed to the applicant when they use
the @request command and are moved into the $request_booth. If
they are a VSPO applying for a regular character, they see the
vspo_introduction_msg, else they see the introduction_msg. It
should explain that they are going to be asked some questions,
and why.
$request_booth.last_words
Displayed after the person has completed the application, just
before they are returned to the room they came from. It should
give the person some idea when they can expect to hear from you.
(1) Announcements
:announce (@text) => broadcasts to all except `player'
:announce_all (@text) => broadcasts to all
:announce_all_but (objects,@text) => broadcasts to all except those in objects
say, emote
(2) Command recovery
:huh (verb,args) - server hook: last chance to make sense of verb
:here_huh (verb,args) - room's last attempt to parse something
:here_explain_syntax (this,verb,args) - attempts to explain usage of verb
(3) Residency
free_home - true => @sethome allows anyone to set his .home to be here
residents - objects on this list may teleport in and/or set their homes here.
:accept_for_abode(player)
=> true if person should be allowed to set .home to this room.
@resident*s
(4) Looking
dark - true => contents are not visible
ctype - 1..4 for four different styles of .contents lists
:match (string) => exit or object in room's .contents
:tell_contents (objects,ctype) - format objects according to ctype, tell `player'
l*ook
(5) Entrance and exit.
:accept (object) - Called by move() and :moveto() before an object enters a room, if false is returned, movement is prevented. Protocol permits this verb to make noise (though this is discouraged) as this is the only place the room will learn the object's original location.
:acceptable (object) - Called by verbs which wish to check whether movement will be possible. Protocol prohibits this verb from making noise and requires it to return the same value as :accept would for the same arguments.
:is_unlocked_for (object) - interface with the @lock protocol. Returns true or false depending on the state of locks for the object with the room. Other things may prevent entrance even if this returns true. Protocol prohibits this verb from making noise.
:enterfunc (object) - called after entrance has succeeded. Noise is fine.
:exitfunc (object) - called after an object has successfully left. Noisemaking is fine.
(6) Topology and Movement via Exits
See `help $exit' for an explanation of how the generic $exit works.
free_entry - true => `teleporting' in is allowed
false => only residents may teleport in
exits - list of invokable exits leading from this room
entrances - list of recognized exits leading to this room
blessed_object - object currently entering via an exit
blessed_task - task_id for entering object
:match_exit (string) => exit whose name matches string
:bless_for_entry (object) - set up room to accept object arriving from entrance
:add_exit (exit)
:add_entrance (exit)
:remove_exit (exit)
:remove_entrance (exit)
e/east/w/west/s/south/n/north/ne/northeast/nw/northwest/se/southeast/sw/southwest/u/up/d/down, go, @add-exit, @add-entrance, @remove-exit, @remove-entrance, @exits, @entrances
(7) Ejection
victim_ejection_msg/oejection_msg/ejection_msg
:*_msg() messages
@eject
A "section" can be defined by an object's programmer to be any bit of text associated with that object which might be appropriate for editing, such as chapters in a book or notices on a notice board, which aren't necessarily directly associated with individual properties on that object. It is intended to be called via $player:@edit with the syntax '@edit <object>|<section>' (i.e. '@edit book|1', for chapter 1 of a book named "book").
Pretty much any generic which is appropriate can be easily modified to take advantage of this editor simply by providing the following verbs:
:get_section(<section-name> [,<test>]) - Retrieve the text of a section identified by the string <section-name>. If no such section exists, this verb should return E_INVARG instead. the second parameter (<test>), if supplied, is a boolean value indicating that the call to this verb is only to determine whether such a section exists, and the actual text need not be returned (this type of call is used by the Section Editor to determine whether a section is valid before actually invoking the editor. Most applications can ignore any second argument. Indication is given simply in case a particular implementation involves a lot of processing or time-consuming operations to obtain the actual text of a section)
:set_section(<section-name>, <text>) - save new text for the section <section-name>. Implementations should check the type of the <text> parameter if it is important, as the Section Editor (like the Text Editor) can operate in either "string" or "list" mode.
(optional) :section_msg(<section-name>) - Return a string indicating the appropriate way to refer to <section-name>. If this verb is not present, a string of the form "section <section-name>" is used. (for example, a book's :section_msg verb might return a string of the form "chapter <chapter-number> (<heading>)" instead of the default, providing a more informative and descriptive identificaiton of what's being edited.)
(Note: All calls to :get_section and :set_section are made with caller_perms() set to the player who's doing the editing.)
:add(sitename, who)
records the fact that character connected from sitename.
:load()
clears the db and reloads all of the character connection info.
.domain
default domain for unqualified sitenames given to :add.
For each domain we keep a list of characters and subdomains.
For example, :add("doc.ic.ac.uk",#666) enters #666 on the lists for "doc.ic.ac.uk", and, if we have to create an entry for "doc.ic.ac.uk", we enter "doc" on the list for "ic.ac.uk", "ic" on the list for "ac.uk", etc.... In this case, :find("ic") will return the "ic.ac.uk" list if there is no other domain in $site_db starting with "ic". Note that the "ic.ac.uk" list may contain both objects, i.e., namely people that have connected from the site "ic.ac.uk", and strings, i.e., subdomains of "ic.ac.uk" like "doc".
:find_exact(string) => character/subdomain list or $failed_match
:find_all_keys(string) => list of all domains that begin with string
:find_key (string) => unique domain that begins with string,
$ambiguous_match or $failed_match
The other $generic_db functions (:find, :find_all) are also available, though admittedly less useful.
The $standard_webviewer is called by $http_handler:process through
the usual indentification of the ".code" property, which is "viewer"
by default. The :method_get (or :method_post) verb is called with
args {who, what OBJ, rest STR, search STR, form STR}, where "what" is
the object to be viewed. If no object is specified, the user's
location (player.location) is assumed. Note that authentication is
performed earlier by the $http_handler, which sets the "player" value
before the call. The :method_get verb builds the various portions of
the final web page, then combines them and returns the text and a
title for the web window ({title STR, text LIST}).
The :method_post verb is only called when the user selects an item
on the optional "command form" that may be included in the basic web
page by the "commandform" web option, if the user chooses.
The components of the web page are assembled as follows:
1. If there are option toggles, indicated by flanking "+" symbols in
the "rest" portion, these are used to set user display options.
2. The "focus" object's HTML text is retrieved by a call to
what:html(rest, search, line). If the value returned is a list
of STRings, it is assumed to be an HTML text fragment. If it is
in the form {where OBJ, what OBJ} then it is a redirection to a
new "what" with a new base location (replacing
"player.location"), and the new what:html() is called without
additional arguments. The inability to redirect the
rest/search/form arguments is for security purposes. A maximum
of four redirections is permitted. If what:html() returns the
value $nothing, then "what" and "where" are set to
"player.location" and a fresh call (without args) to what:html()
is performed.
3. The attributes to be inserted into the page's <BODY> tag are
retrieved from web setting named "bodytag_attributes" if one is set
[what:get_web_setting()]. Also, the "hide_banner" web setting is
checked for.
4. The "button bar" is generated by a call to
player:web_viewer_buttons(viewer.code STR, what OBJ).
5. A map is inserted if the "map" web option has been set, which is
generated by $teleporter:html(who, 0, 0).
6. The "You are at" and "examining...<what>" lines are generated as
links to the $object_browser view of the given objects.
7. The list of exits is generated by
$standard_webviewer:generate_exitlist(where).
8. A list of carried object is included if the "inv" web option is
set, generated by $web_utils:list_english_list_with_urls(player OBJ,
viewer.code STR, objects LIST).
9. The "command form" is generated if the "commandform" web option is
set, and generated by $standard_webviewer:command_form().
10. An <EMBED> portion for the VRML view is included if the
"embedVRML" web option is set, generated by
$standard_webviewer:embedVRML(what).
11. Finally, the fragments are assembled in the appropriate order and
the complete web page body is returned to the $http_handler.
It is usually invoked with a URL in the form:
http://moo.site.org:8000/99anon/vrml10/5555/room.wrl
Where "anon" specifies an unauthenticated transaction, "5555" is the
room or other object whose VRML description will be returned, and
"room.wrl" is appended for web browsers that use the file extension
instead of the MIME information in the HTTP header to determine
processing. All HTP/1.0 transactions processed by the
$std_vrml10viewer are of "x-world/x-vrml" MIME type.
The transactions follow the general form:
$http_handler
A
|
V
$std_vrml10viewer:method_get
A
|
V
<room>:get_vrml <-> .vrml_interior_desc
A
| The room retrieves the VRML file fragment for each
| object inside, and adds cameras for each child
| of $player. It also adds a standard "to web page" link
| and a "to outside room" link of the room is "interior."
|
V
<objects>:get_vrml() <-> :get_vrml_desc
:get_vrml_translation
:get_vrml_rotation
:get_vrml_scale
Key data is stored on #1.vrml_desc, #1.vrml_coords, and
#1.vrml_settings. The first is a list of strings, comprising the
VRML file fragment describing the object's structure. The vrml_settings contains various VRML-related settings that are specific to the room. See the help text for "@set-vrml" to see which are currently defined for all rooms.
The vrml_coords property has the form:
{ {NUM, NUM, NUM}, {NUM, NUM, NUM}, {NUM, NUM, NUM} }
Where the first triplet is the XYZ translations from the room's
origin in milliunits, the second set is the XYZ rotations from the
origin in millirads, and the third set is the XYZ scaling in
milliunits. This allows a minimum translation of 1 milliunit and a
maximum of2147483. In most cases, a VRML unit is perceived as about
.75 meters, giving a translation range between .75 mm and 1612 km.
The main verbs on the $teleporter are:
$teleporter:teleport_user(who OBJ, where OBJ [, @ optional messages])
This is the non-web utility for moving characters, and performs all
appropriate testing of if the character was successfully moved and
presenting appropriate messages to their former and subsequent
location. If no optional messages are given, then those on the
character or the $teleporter are used as needed. See the help for
$teleporter:teleport_user for details of the optional messages.
$teleporter:move_user_for_web(who OBJ, where OBJ)
This verb performs user character movement for the web system,
including the VRML system. It is not generally used by other
systems, which should use $teleporter:teleport_user instead.
There are several properties on the $teleporter, some of which are
important for the web system.
.image_map - A STR with the URL of the MOO's default image map,
presented as part of the Web Viewer page if no room enclosing the
character has its own image_map property.
.imagemap_regions - A LIST in the form used by
$web_utils:interpret_map that divides the graphic given by the
image_map property into selectable regions.
.imagemap_rooms - A LIST of OBJ's, with each object a room
corresponding to the indexed region in the imagemap_regions property
(ie. the first room given is the place to move users who select the
first region specified in imagemap_regions).
.central_room - An OBJ specifying where the "center" of the MOO is.
This is used by some Web Viewers to present a button that returns
people to the MOO's center. Set to #11 by default, and generally
equal to $player_start.
default_mapsize - A LIST in the form {NUM, NUM} cotaining the
{length, width} in pixels of the image specified by the "image_map"
property. Some web viewers will force all image maps to this size,
which helps keep the display consistant. Note that if your map does
not conform to this size, the regions in the imagemap_regions may not
be correctly selected.
Customizable properties:
.recycle_age
.max_quota
.expire_email_txt
.keepowned_expire_email_txt
.first_warning_time
.second_warning_time
.student_expire_mail_txt
.last_warning_txt
.admin_mail_recipient
.default_expiration_duration
.student_expire_confunc_text
.default_FOs
.groupowner_advance_time
.groupowner_advance_txt
.groupowners_visible
Structure of $vspo_registry.groups is:
.groups[group][1] OBJ group owner
.groups[group][2] STR group name
.groups[group][3] LIST group VSPO members {OBJ, OBJ, ...}
.groups[group][4] INT expiration date in time() format
.groups[group][5] LIST group non-owner controllers {OBJ, OBJ, ...}
.groups[group][6] LIST group flags {STR, STR, ...}
.groups[group][7][1] INT creation date in time() format
.groups[group][7][2] OBJ group creator
.groups[group][7][3] LIST group description {STR, STR, ...}
.groups[group][7][4] STR type of class
.groups[group][7][5] STR group charge type
.groups[group][7][6] STR group suffix
The webapp to use in a transaction is specified by the CODE portion
of the URL, given the general format:
http://HOSTNAME:PORT/xxWEBPASS/CODE/OBJECT/REST?SEARCH
The $http_handler:process verb determines which webapp is targeted by
checking the "code" property of each child of $webapp, and matching
the values. Note that if you want to restrict valid webapps to only
first generation decendents of $webapp, you should modify the
appropriate lines in $http_handler:process and
$http_handler:provide_menu so that the list of valid webapps is
children($webapp) instead of $object_utils:descendents($webapp).
Once the appropriate webapp has been identified, a call is made to
either its "method_get" or "method_post" verb, depending ont he type
of the transaction. Webapps may have a single verb with both names
as aliases. The call has the form:
method_get(who, what, rest, search)
method_post(who, what, rest, search, line)
where:
who - originally set to `player' and now no longer used but
retained for backward compatability.
what - the object specified as OBJECT in the URI, or #0 if the
object is not valid.
rest - The REST portion of the URI.
search - The SEARCH portion of the URI.
line - The unparsed form line of a method POST transaction,
generally processed by the webapp with
$web_utils:parse_form.
The webapp is expected to use this information to create the text
that is the result of the HTTP transaction. By default, the webapp
is expected to return the <BODY> portion of the text for an HTML
document, and the $http_handler:process verb adds the <HEAD> and
other information. However, webapps listed in
$http_handler.exempt_from_pads are not treated this way, and the text
they return is directly sent to the transaction port.
Webapps that return HTML document text should do so in the form:
{ "<title>", {<lines of text>} }
Where <lines of text> are the strings composing the HTML text, and
<title> is the title that will head the web browser's window. See
the help for "$web_utils:format_webapp_result_to_html" for details of
the formats $http_handler:process will accept results in from a
webapp.
*Player-Creation-Log ($new_player_log)
A low-level record of all created MOO characters. Not usually
someone one would subscribe to.
*New-Prog-Log ($new_prog_log)
Record of who's been given MOO programmer permissions.
*wizards ($system_mail_recipient)
For messages to and between MOO Wizard characters. This mail
folder can be posted to but not read by the general MOO community.
*Quota-Log ($quota_log)
Record of whose quota has been changed and why.
*Site-Locks ($site_log)
Notes on annoying sites and user connection restrictions.
*tags ($tag_log)
A database of tags. Not normally accessed through the mail
system commands, although it's a child of $mail_recipient.
Administrators will want to subscribe to $witness_logs and not this.
*Helpful-People (&helpful-people_list)
A mailing list for issues relating to Helpful People and the
Helpful Person System. This is a public mail folder.
*VSPO-administration ($vspo_admin_list)
A mailing list that receives administrative messages regrading
the VSPO system.
*account-locks ($account_locks)
This logs various site and user connection restriction changes.
*undecided ($undecided)
A temporary place for character applications still under
consideration.
*Character-Request-Pool ($request_pool)
Requests for MOO characters are sent here.
*Manager-Log ($manager_log)
This mail folder records addition and removal of managerial
responsibilities for people of the $manager character class.
*created ($created_chars)
This is a list of character applications that have been accepted.
*rejected ($rejected_chars)
This is a list of character applications that have been rejected.
*witness-logs ($witness_logs)
Logs of guest witnessing are sent here after a guest boot, and
also registered user @witness'ing.
*Wiz-Projects (&ProjectsList)
A platform where updates regarding the progress of projects that
wizards are working on are pooled. This system is working, but
still under development to extend it to Managers also.
This text describes what properties need to be initialized after you
have installed the BioGate System in your MOO. It provides a list of some
items you can customize. A more detailed description of nearly every
property in the BioGate System can be found in the help texts
installed in $core_help for each of the BioGate System objects. The
properties listed here are only the one's that must be customized for
the system to function properly, and for which setup instructions are
not given elsewhere in the installation package instructions.
On $http_handler
----------------
lag_meter
Object number of a lag meter object, with a .samples property
listing recent lag values. This object is common in MOOs, but if
you don't have one, this property can just be set to a #-1 value.
gateway_html
A text displayed as the MOO's web gateway page if there is no FUP
system installed or no web/gateway.html file accessible. See the
text of the sample gateway.html file for embedded comments
describing the contents of that page.
webpass_handler
The object number of the Webpass Handler object installed with the
BioGate System.
On $web_utils
-------------
page_banner
A fragment of HTML used to insert a "banner" across the top of each
web page the MOO generates. This is NOT just a URL, but is a
compelte <IMG> tag. The reason is that instead of just an image,
you may want to use an imagemap or something more complex as the
banner. The entire value for this property is inserted into the
web page whole.
interior_rooms
A list of object numbers for rooms that are "interior" or
"portable" (in the usual MOO lingo). These are rooms with a verb
having the name or alias "exit" for which that command can be used
to exit the room into the enclosing room. By knowing which rooms
have this feature, the Biogate System knows to add an "exit" link
to the list of exists displayed, even though the exit named "exit"
isn't generally displayed by the usual MOO $room exits listing.
web_helppage
The URL for a "help page" for this MOO, which usually should have
instructions for new MOO users.
MOO_home_page
The URL of the MOO's "home page," which can be different from its
web gateway page or identical.
uparrow_icon
The URL for an icon embedded on web pages to indicate "go to the
top of the page." Available to help promote a common look among
MOO-generated web pages, but ignored if this value is set to an
empty string.
std_bgcolor
std_textcolor
std_linkcolor
std_vlinkcolor
std_alinkcolor
std_bkgnd
These are strings giving various default web page display values,
that can help you establish a basaic "look" for web pages the MOO
generates. However, they can be overridden by various means, and
really just serve to promote a basic appearance. The only one most
people will want to set is the .std._bkgnd property, which should
be the URL for an image to be used as the standard background for
all MOO-generated web pages that don't override the default.
wizards_choice
Object number of a "Wizard's Choice" object, whose :html verb
generates a page pointing out some of the more interesting sites to
visit in the MOO. Used by the $anon_webviewer and
$standard_webviewer to generate their button bar. If set to #-1,
then no "Wizard's Choice" link is included in the button bar.
On $teleporter
--------------
image_map
The URL for an image to be used as a map of the MOO, and added to
the bottom of pages generated by the $standard_webviewer and
$anon_webviewer. Other properties on $teleporter give further
information concerning this imagemap.
central_room
The "center" of the MOO. May be $player_start or some other room.
Used by the $teleporter with certain web objects that send the user
to the "central room" if one has been designated.
default_mapsize
The size to display the MOO imagemap at.
imagemap_regions
An ordered list of imagemap regions in $web_utils:interpret_map
format. Indexed to the .imagemap_rooms property, so that each
region corresponds to a room.
imagemap_rooms
A list of rooms to teleport the user to when they select different
regions of the imagemap. Those regions, indexed to this list of
rooms, are specified in the .imagemap_regions property.
On $anon_webviewer
------------------
ghost_home
The object number of the room where people using the WebGhost
Viewer start. By default, it's the same as $player_start.
The general flow during a web transaction is:
port-handler -> $http_handler <-> web-application
The $http_handler sends out the retrieved information and then breaks
the connection.
In addition, the web-application commonly will call individual
objects. For instance, the $standard_webviewer calls <object>:html()
and the $std_vrml10viewer calls <object:get_vrml() to retrieve
appropriate information about the object's current state. Objects
usually supply fragments of the final text that is compiled by the
web-application and sent back to the $http_handler.
The following components of the web system have their own core help
texts:
$http_port -- listens on a MOO port for HTTP transactions
$http_handler -- determines what type of resource is being requested
(eg. HTML or VRML), retrieves the relevent data
(possibly using a $webapp), sends out the info and
closes the connection
$webapp -- The "web applications" that generate the text
returned for a web transaction.
$frame_manager -- Performs various functions related to building
frames on the user's web page and placing the proper
information in each.
$jclient_handler -- Carries the verbs and data used to allow telnet
clients written in Java to connect to the MOO,
and interact appropriately. Each telnet client
uses a different child of the $jclient_handler.
$std_vrml10viewer -- This webapp displays a static VRML/1.0 view of a
given room. Although it will pass VRML/2.0
information, it doesn't have any facilities for
live VRML display control. It does dynamically
create the room view, though, so
the returned VRML file describes the room at the
moment of the request.
$html_editor -- A child of the generic editor that specifically
writes to object's associated URL/HTML data
(#1.url).
$web_options -- Options package for setting various
user-customizable aspects of the web system.
$web_utils -- A collection of utility verbs used by the web
system and web system programmers
Webpass Handler - The object that stores temporary web passwords for
users interacting with the MOO's web system (no
further help text is available for this object).
Referenced as $http_handler.webpass_handler
$teleporter -- The General Teleporter object is used by the web
system to move characters when they teleport. It
is a general purpose tool for this, though, and
can be used by non-BioGate systems.
$anon_webviewer -- A Web Viewer that allows anonymous web
transactions to be used to browse the MOO. This
web viewer presents the MOO's rooms much like the
$standard_webviewer, but doesn't require the
transactions be authenticated. It does not allow
users to manipulate objects, only to examine them
in ways that don't change any of their
characteristics.
$standard_webviewer -- The default web viewer for browsing the MOO
with authenticated transactions. It dynamically
creates web pages displaying the rooms and other
objects found in the MOO.
integrated-web-telnet -- Describes the innards of the integrated
web/telnet system, using the Cup-O MUD Java
telnet client as an example.
Additional topics:
web -- introduction to the MOO's web system
@web-options -- user options for cutomizing web system actions
web-programming -- how to program objects to be "web aware"
web-security -- how the web system's authentication system works
OVERVIEW
The purpose of the core extracting system is to create a "DU Core"
which contains the core objects and utilities which can be used by
other MOOs, without containing DU specific objects. Utilities are
included to assure that the core functions satisfactorily after being
extracted, without having to be extensively modified after creation.
Thus, the underlying DU database contains all the information needed
to create and appropriately initialize a new core DB.
The core database is created by running a minimal DB on a remote MOO,
opening a network connection to it, and then transferring all the
core objects to it. All property and verb changes needed to
initialize the object for the new core are made by the verbs doing
the transfer, and all absolute number references in properties are
checked and changed where appropriate. The object itself on the
source MOO is not modified, the information about any needed property
or verb initialization is taken from the object's "initcore_data"
property. After all objects are transferred to the remote MOO, the
init_for_core verbs on all objects there is run do whatever
initialization is required beyond simple property or verb changes
(such as moving things, etc.) This is quite different from the
standard LamdbaCore method, where the new core is created by deleting
all non-core objects from the MOO, renumbering the remaining core
objects, updating the object number references on #0, running
init_for_core verbs to initialize the objects, and then dumping the
database.
The DU core system also uses the object's "unique_id" property to
determine if it is in the core. Non-core objects have their
unique_id set to 0 when they are created (or they should). All core
objects have a unique_id set to a list of three elements: (1) the
unique name for the object (or the $name for objects named on #0);
(2) the core set identifier which is used to indicate whether this is
part of the basic core or a "core option" which can be optionally
included or not; and (3) date this object was transferred from a core
extraction, or 0 if it is on the source MOO. This differs from the
LamdbaCore system, which uses all objects defined as a property on #0
(i.e, as $<name>), or their parents, as the set included on the core.
In the DU system, objects which are not on #0 can be included in the
core even if they are not parents of such objects, and objects on #0
need not be included. However, in the latter case, care should be
taken that references to the corresponding $<name>'s not be in the
core objects,
The DU core system, and its associated utilities, are designed so
that if the core objects have their initcore_data property and (where
applicable) init_for_core verbs set properly, they should function
without need for further modification after being transferred to the
new core MOO. Several utility verbs are available to test the
property initialization in the initcore_data for an object, which
give warnings if there are object numbers which would be undefined on
the new core, or if there are properties with an excessive amount of
data that perhaps shouldn't be part of the core. Utilities are also
available to check the verbs for absolute object number references,
or references to $names which will not be on the new core.
The system also allows "core options", i.e., sets of objects that you
can optionally include in the core or not, depending on its intended
use. For example, teaching tools and generics could be included in a
core intended for educational use, but not included in a core
extracted for other purposes. The second string in the initcore_data
list identifies the core option that the object is associated with.
If that string matches the base core option id ("DUcore" at DU), then
the object is included on all cores regardless of which options are
selected.
Most of the verbs, properties, and utilities for the core preparation
system are on $core_utils, which is a FO which a wizard must add to
his features to extract a core database. However, verbs to corify an
object, define an object as part of a core option, or to define a new
core option set, are on $wiz. All of the user-callable verbs should
have a "help" stating what they do. "Help $core_utils" will give a
summary of the verbs on that FO. "@about $core_utils" will output
this text, and "@mailme $core_utils" will mail it.
MAKING AN OBJECT PART OF THE CORE
SETTING INITCORE_DATA. As part of making an object part of the core,
you have to put all the necessary property and verb initializations
in the object's .initcore_data property. This property should
contain text (a list of strings) giving the specifications for
changes to be made in properties or verbs in objects when they are
transferred to the new core. It can be used to specify which verbs
or properties are not to be included, property initializations, or
reprogrammed verbs. For example, a typical line would be '<property
name> = <initial value>', such as initializing a list to {}, etc.
For a DB object, it might specify that no properties defined on the
object are to be transferred except perhaps for a specified few.
This property thus serves the same function as the init_for_core verb
did in the LambdaCore system, making separate init_for_core verbs
unnecessary for most objects. See 'help initcore-data' for a
detailed description of how to set up this property. NO WIZARD
SHOULD CORIFY AN OBJECT WITHOUT UNDERSTANDING INITCORE_DATA.
TO CORIFY AN OBJECT. The objects which are included in the core are
specified using the @corify or @uncorify command. The player must be
a wizard but need not have the $core_utils as a feature. For more
information on these commands, see 'help $core_utils:<verb>'.
The '@corify <object> as [$]<unique name> [<core option set>]'
command is used to make an object a part of the core (or a core
option set) which was not such previously, or to change the core
option set of an already corified object. If a core option set is
not specified, the object is part of the base core, i.e., it is part
of the core regardless of which core options are selected. The
'unique name' must be different for each core object, regardless of
whether it is in the base core or a core option. If a '$' precedes
it, it is added as a property on #0 with that name (i.e., it is
'corified' in the Lambdacore sense).
The @corify command sets the unique_id of the property to {<unique
name>,<core option set>, 0}. If the object is to be part of the base
core, the <core option set> string in the unique_id is the string at
$core_utils.core_id, which is "DUcore" at DU. The command also puts
the object number on the DB objects for the main core or the core
option set (see below), and updates any relevant properties on
$core_utils, as appropriate.
The '@uncorify <object>' command removes an object from the core, but
does not recycle it, nor does it remove it from #0 (it's $name), if
applicable. The object's core option set identifier in its unique_id
(the second element) is set to "", and its object number is removed
from the DB for the core option set it was on.
The @corify command checks the properties as processed by the
initcore_data on the object and gives warning messages for any object
numbers in the properties which may not be defined when the object is
transferred to a new core. It also checks all verbs in the object
for absolute object number of $name references which may not be on
the new core.
The @check-for-core command can be used to re-check the property
initialization or verbs in an object that is already corified. This
is useful if @corify indicated problems which had to be fixed, or to
periodically check objects which have been modified.
NOTE: If you get a traceback running @corify or @check-for-core, run
'@list-core-objects' and try again. If that fails, try
@search-core-objects (which takes longer). These commands are
necessary to assure that the data bases used by the core checking
system are up-to-date. They are described below.
The @core-id command can be used to identify whether a particular
object is a core object or part of a core option set (see below), and
to determine if it can be referenced by a $<name>. It is also useful
for getting the object number of a core object given its "core id
name", which is the name in its unique_id[1].
CORE OPTION SETS
A core option set is a group of objects which are not essential to
the core but can be included as options. Each core option set
(including the base core set) has a database object defining the
object numbers in that in its properties, and also containing text
describing it. To use core option sets, one must (1) use
@create-core-option to create the core option set database and input
its descriptive text, and then (2) use @corify to identify which
objects are on that set. An object can be taken off the set by using
@uncorify, or using @corify to assign it to another option set or the
base core.
Note that the processing of the initialization assignments in the
.initcore_data property can allow for properties to be initialized or
transferred differently depending on whether a particular core option
set is selected. For example, it may be appropriate to remove verbs
on base core objects which are used only if a particular option is
selected. This can be done using the %if <option> ... %endif
construct in initcore_data. See 'help initcore'.
The @core-options command can be used to list the currently selected
and available core option sets. A 'selected' core option set is one
whose objects will be included in the next core extraction, as
discussed later.
CREATING A CORE OPTION SET. To create a new option set, use the
command '@create-core-option <name>', where <name> is the name of the
option set. Each core option has a unique name, which must be
different from the unique name in the unique name (unique_id[1]) of
all the other core objects, as well as from any other core option
set. The command will then do the following:
- Create a new database for this option, as a descendent of the
Generic Core Option Database. This object is automatically added to
this new core option set (so is a useful place for putting an
init_for_core verb that may be needed to initialize the set, such as
moving members into the appropriate locations).
- Updates the properties on $core_utils which give the lists of all
available core options. By default, a newly create core option set
is not selected for use and its objects will not be included in the
next core extraction unless it was selected using the
@select-core-option command (see below).
- Prompts the user to give a short 1-line description of the set
which is output with the @core-options command which lists the
selected and available core options (see below).
- Prompts the user to give the full about_text property which
documents the option set. This is the text which is output with
@about <option DB> or @mailme <option DB>. You should have prepared
this documentation text before you run @create-core-option so you'll
be ready to paste it in when prompted.
An @abort at the prompts for the short_description or about_text will
terminate the command, but the option set will be fully created and
ready to use. However, you will need to input these properties
manually. The short_description property must be a single string,
but about_text is a list of strings. At a minimum, the
short_description property must be defined. The about_text can be
updated later as the set becomes documented.
DELETING A CORE OPTION SET. The command @delete-core-option is used
to remove a core option set from the available core options. The
user is asked if the DB is to be recycled. He/she must select 'yes'
or it won't be removed. Then the user is asked if the references to
the object are to be removed from the unique_id[2]'s of all the
objects in the set. If "yes" is selected, these are set to ""
indicating they are no longer on the core. If "no" is selected, the
name of this set is still on the objects, but since the option DB
doesn't exist, the core utilities don't recognize them as part of any
valid core option, and they can't be included on the core. If a new
core option set is created with this same name, these objects would
become part of that set. However, they won't be on the DB. The
'search-core-objects' command will fix this (see below).
SELECTING A CORE OPTION SET. The command @select-core-option <name>
selects an option set to be included in the core.
@unselect-core-option <name> unselects it. You need to have the
$core_utils as a feature to use these commands. Use of this feature
should be reserved to the person actually in charge of creating the
core database.
PREPARING AND CHECKING THE SOURCE DATABASE.
Although the @corify and @check-for-core prepare core objects and
update the core utilities database on an object-by-object basis,
before actually extracting a core it is a good idea to be sure the
core utilities and various core options databases are completely
up-to-date, and to check all the core objects. Commands to do this
are summarized below.
'@search-core-objects' and '@list-core-objects' are the basic
commands for assuring that the core utilities and core options
databases are completely consistent with the source MOO and up to
date. This must be done before transferring a core database, and
also may be necessary for the core object checking verbs used by
@corify and @check-for-core to work. @search-core-objects searches
all objects in the database, checks their unique_id's, and updates
the core databases accordingly. This takes a long time, but should
always be run shortly before starting the core DB transfer process.
'@list-core-objects takes the list of core objects from the core
option databases, and is sufficient as long as these databases are
correct. (@corify and @uncorify should keep them up to date, but if
the unique_id's of objects were changed manually, or if any core
objects were recycled, then the databases would be inaccurate, and
this can only be corrected by '@search-core-objects'.) A note named
'core-list' is also produced, giving a listing of core objects and
other relevant information.
The '@test-initcore' command should also be run (after running one of
the above) to check for problems in the selected set of core objects.
If run without any arguments, it is the same is running
@check-for-core on ALL the selected core objects. In addition to
producing output with the warning messages, it also saves the warning
messages about bad object number references in properties (but not in
verbs) on the on $core_utils.unreferenced_log which can be viewed
using the @core-logs command.
The @check-verbs' command can also be used to scan objects for
undefined object references in verbs. If an object name or core id
name is given, then only the verbs in that object are scanned, and
the results are output to the player. If no arguments are given,
then verbs in all selected core objects (objects in base core +
selected core options) are scanned, and the results go to
$core_utils.unreferenced_log, where they can be viewed by the
'@core-logs' command.
Note that the wizard has to have $core_utils as a feature to run
these commands, and all those discussed below.
CORE DB TRANSFER PROCESS
As indicated above, the core database extraction is carried out by
transferring, via a network connection, the verbs and (initialized)
properties of the core objects from the running source MOO to a
recipient MOO initially running a minimal DB. Because this is
essentially a bootstrap process starting with a minimal DB with
essentially nothing, the recipient MOO is referred to as the BootMOO
in the subsequent discussion. Once the core is transferred to the
BootMOO, it will be referred to as the Core MOO.
To do the transfer process, the wizard must have $core_utils as a
feature. If you wish to use your programmer character for the
transfer process (which is time-consuming), use @add-owner <name> for
$core_utils, then add $core_utils as a feature of that character.
Then your character can add this feature, and use do the transfer
commands.
SETTING UP MINIMAL DB The starting point in the core transfer
process is to set up and run a minimal DB MOO at a site which can be
reached by the source MOO via a network connection. The server
should use all the extensions and features as the server running the
source MOO. Note that a special minimal DB must be used - where the
only object is #0, and the only verbs are an empty #0:eval and a
#0:do_login_command whose verb code consists only of "return #0;".
Such a minimal DB is on $core_utils.minimal_db, and can be e-mailed
using '@mailme minimal on $core_utils'. Once the minimal DB is
copied to the appropriate site, the BootMOO can be run by using the
usual commands to start the MOO program with the input file being the
minimal DB. One can connect to this MOO to make sure it is working,
but all you will see is 'I couldn't understand that.' messages; no
commands work except .program.
The actual work is done by connecting to the BootMOO through a
network connection running on the source MOO. Before doing this, THE
PROPERTY $CORE_UTILS.BOOTMOO_ADDRESS MUST BE SET TO THE ADDRESS OF
THE BOOTMOO, given as a list containing a string with the address and
a number containing the port, e.g, @set $core_utils:bootmoo_address
to {"computer.site.domain",7777}.
The command 'connect-bootmoo' (in the source MOO) will connect you to
the BootMOO. If it isn't running or you gave a bad address or it is
not accessible over the network, you'll get a traceback. If
successful, everything you type will go to the bootmoo, and
everything it outputs back to you will be preceded with a string like
'#-12345: ', where object number is the connection object ("player")
at the source MOO. (This is like an un-logged-in player - you will
see it as a "dead" player on the @forked output.) WHEN IN THIS MODE,
EVERYTHING YOU TYPE GOES TO THE BOOTMOO EXCEPT COMMANDS WHICH START
WITH '%'. However, you will see output to you from the MOO, such as
pages, etc. You will need to get out of this mode to respond.
To get out of the BootMOO connection mode without actually closing
the connection, give a single '%' (+ return) command. Use
'connect-bootmoo' to resume the connection where you left off.
Additional BootMOO commands, in the order you'd normally give them,
are as follows. (They are shown in caps for emphasis, but case
doesn't matter.)
%BOOT ... This boots a brand-new minimal DB by programming all the
verbs on #0 needed to do the transfer. You must give this command
first, and then not again. The commands sent to the minimal DB to
bootstrap it is on the property $core_utils.bootcode. No
'handshaking' is done; you'll know its done when you stop seeing
output - the last message output is "Ok. #0 (System
):boot_inits_for_core programmed.".
%INITIALIZE ... Creates and initializes all the selected core
objects on the BootMOO, but doesn't transfer any verbs or properties.
If any objects have been created or transferred before, they are
deleted. Use this right after %boot, or if you want to start fresh.
This may take 2-3 minutes. The message 'Finished with
initialization' will indicate it is finished.
%TRANSFER, %TRANSFER_ALL, %TRANSFER <object id> ... Starts
transferring properties and verbs for either the next untransferred
core object, all untransferred core objects, or the core object whose
unique_id[1] is the given <object id>. Note that this spams the user
continuously with messages indicate when each property or verb has
been transferred. (For this reason, it is best run using a secondary
character so the wizard can do other work through a different
connection while this is going on.) Transferring a large object such
as $player may take about a half an hour or so. '%transfer_all may
take perhaps half a day. This process can take many hours to
complete, though it can be aborted. The 'stop_transfer' command
given by another $core_utils feature owner will stop a %transfer_all
after the current object is completed. (That's why it's useful to
use a secondary character to run this command.) NOTE: do not
transfer objects out of order. The parent should be transferred
before any of its descendants. Refer to the <object id> only to
re-transfer an object that was transferred before, but somehow failed
or needs to be done again.
%UPDATE, %UPDATE_ALL ... Transfers all properties and verbs on the
next (or all) core object which either hasn't been transferred, or
whose last_modified property has changed on the source MOO since it
was transferred. Essentially operates the same as %transfer or
%transfer_all except that the latter doesn't transfer objects which
have been transferred before but may have changed.
%GET_NEW_NUMBER ... Gets from the BootMOO the number of objects
which have been transferred and need to be transferred. This
information is displayed using the @core-logs command. Useful if the
logs were cleared using @clear-core-logs. This is not normally
needed, since this is updated automatically anytime %transfer or
%update is run.
%FINISH_UP ... Completes the MOO initialization process and runs
the init_for_core verbs on all objects. First checks to be sure
everything has been transferred, and gives an error message if not.
This should usually be run again if any objects have been updated
(using %update), unless you know that the transferred objects don't
have an init_for_core verb, or aren't modified by any other object's
init_for_core. After this is run, the MOO is ready for normal
logins.
% ... As indicated above, allows the user to suspend the network
connection so he can interact with the source MOO normally.
'Connect-bootmoo' will resume the connection mode to the existing
connection.
%QUIT ... Closes the network connection ends the connection mode.
The BootMOO or core MOO is still running. 'Connect-bootmoo' will
start a new connection, and the user will have to either do the
minimal DB login (if %boot but not %finish_up has been run) or the
system core login (if %finish_up has run) to resume the transfer or
shut down the MOO - see below.
%CLOSE ... Shuts down the BootMOO or Core MOO and closes the
network connection. The partially or completely transferred database
is saved in the output DB.
After the verbs on #0 have been transferred, you may get the message
'property not found' after each command. This is due to the
#0:do_command verb, and does no harm in this process, and can be
ignored.
If someone connects to the BootMOO in the state it is in between
running %boot and %finish_up, the 'welcome screen' will be something
like:
Not logged in.
Your ID = #-3
Max Object = #184
To log in, give the command 'minimal DB login'. Anything else will
just result in this output being repeated. Note that when you log in
this way, the player is the system object (#0), and you do not have
access to the normal player commands even if $player may have been
transferred.
If you have run %finish_up, normally you would be finished with the
core creation process. However, if you need to update some objects
(such as may have initialization problems) AND NOTHING HAS BEEN DONE
TO THE SOURCE MOO THAT YOU DON'T MIND OVER-WRITING with fresh core
objects and re-initialization, you can connect again as the system
object by giving the command 'system <core id> login', where <core
id> is the name on $core_utils.core_id, which is also the
unique_id[2] of all the base (non-optional) core objects. For
example, for the DUcore the command would be 'system DUcore login'.
(Alternately, if the property $login.system_password is nonblank,
then the login should be system <password>', where <password> is the
password stored (in crypted form) on that property. Normally, that
property should be set as blank in $login.initcore_data to simplify
system logins for a new core, but it should be set to "impossible
password to type" once the MOO is customized.) Note that this will
fail if #0 is not a player (see below). Once you have done that, you
can run %update, %finish_up and even %initialize and %transfer_all
again.
INVALID OBJECTS. If a transferred property has an object number
which does not exist on the new core MOO, a message will be output
during the transfer (and in the logs) saying so. A 'placeholder'
object is created at the new Core MOO for this unreferenced object,
and the object number in the property becomes the object number of
the placeholder. The placeholders are all descendants of a 'Generic
Undefined Object Number Reference' object,
(unique_id[1]="undefined"), and thus can be located in this way. The
placeholder's name contains the name of the object it represents and
its description contains its object number at the source MOO, but
none of its properties or verbs are transferred. Any objects with
properties referencing such invalid objects should have their
initcore_data edited ON THE SOURCE MOO to eliminate them, and be
re-transferred.
CHECKING STATUS. The '@core-logs' command can be used to check the
status of a transfer and determine if any invalid object number
references were encountered, or if any transfer attempts failed, and
how much is left to transfer. (It is also useful for checking core
objects, as discussed above.) the '@clear-core-logs command resets
it. The number of objects transferred or needing to be transferred
is updated during the next %transfer or %update command.
A wizard other than the one running the transfer can check on the
status of the transfer process using the @check-transfer' command.
This indicates which object, property, or verb was the last
processed.
DEALING WITH PROBLEMS. The transfer process has an elementary form
of handshaking' where the transfer verbs wait for output from the
BootMOO starting with "Ok" or "Error" to indicate the status of data
sent to it. If no such output is received, the process hangs up.
The @abort-bootmoo' command can then be used to simulate receipt of
an Error" record from the BootMOO, and end the hang-up.
The @stop-transfer' command can be used if you want to stop a long
multi-object transfer. The transfer of the object currently being
processed is completed, but the next object is not transferred.
You must exit from the connect-bootmoo mode (using %") before giving
these commands, or (if the transfer is being done by a secondary
character), the separate wizard character may give them.
COMPLETING THE CORE MOO
Once the transfer is complete and %finish_up has been successfully
run, you can log in as #2 and complete the core preparation as a
normal wizard. In the core MOO, #2 is 'Owner', and its password is
blank (""), so to log in as #2 give the command 'connect owner' at
the login screen.
Check the new MOO for problems. If there is a problem with an object
FIX IT ON THE SOURCE MOO AND TRANSFER IT AGAIN; DON'T FIX IT ON THE
CORE MOO. For example, if properties are not being initialized
property and have object numbers of non-core objects, fix the
initcore_data on the source MOO, check it with @check-for-core, and
(if it checks ok) transfer it again.
Once the core MOO is transferred and verified, the final task is to
remove the bootstrap verbs from #0, and remove the its wizard and
player status. This is done by logging in as a wizard and doing the
@disable-system-login' command. Make sure the transfer is completed
OK and all errors have been corrected before doing this, because the
system login is necessary to do the core transfer, and it is
difficult to re-enable this. Messages output after
@disable-system-login is complete give the steps involved.
UPDATING THE CORE MOO AFTER IT HAS BEEN CUSTOMIZED
The core objects in the new MOO can be updated after it has been
customized, provided that changes have not been made to them that are
necessary for the desired customizations. LOGINS AS THE SYSTEM
OBJECT SHOULD NOT BE USED FOR THIS PURPOSE, since this process may
cause loss of custom information. Instead, a separate process, using
logins as a special player object designated system-updater (and
corified as $system_updater), is used. Other than this separate
login, the update process is very similar to the core transfer
process, except that some of the commands used for core transfer are
not available to the system-updater. Since the MOO which will
receive the updates may no longer be a core MOO, it is referred to as
the "destination" MOO in the subsequent discussion.
PREPARING FOR SYSTEM UPDATES. Only persons who have wizard
characters on both the source and destination MOO can do the updates.
To do the transfer, you must be able to log in as system-updater on
the destination MOO. To do this, you must first log on the
destination MOO as your wizard character, then give the command
@system-updater'. It will tell you if some other wizard is using its
password. If so, check and make sure you're not working at
cross-purposes. Then give the command @system-updater me'. This
copies your password to that of system-updater, so you can log in as
this character using your own password. Once this is done, your
wizard character is no longer needed at the destination MOO, though
you will find it useful for testing and making any adjustments
needed.
To start the update process, log into the source MOO as either a
wizard character or a second character which is an additional owner
of $core_utils. In either case, this character must have $core_utils
as a feature.
Use @core-options' to select the core options to be transferred to
the destination MOO. The options chosen should be the same or a
supersede of those used when the core for the destination MOO was
created, and must be compatible. NOTE: If adding new core option,
make sure the existing core does not have objects whose
.initcore_data have conditional input which depends on whether that
is an option. If it does, any core object with such input must be
re-transferred. However, the system doesn't know when that is
necessary, so you will have to %transfer (not %update) them by name.
All custom properties on those objects would be lost. It is not
recommended that core options involving conditionals on base core
objects be added to an existing MOO.
Note also that system-updater does not run init_for_core verbs, even
for newly transferred objects. If it is absolutely essential that
init_for_core be run for a new object, or re-run for a modified one,
then the wizard character (not system-updater) must do it manually.
However, the %finish_up' command used by system-updater does run
init_after_transfer' verbs on the core objects, so if initialization
is required (which does not involve loss of custom information), such
a verb can be created on the object for this purpose. (For example,
normally core objects are owned by either $owner or $hacker, so for
$system_updater to be owned by itself, a
$system_updater:init_after_transfer verb was created has the
necessary call to $wiz_utils:grant.)
Once the desired core options are chosen, run@search-core-objects' to
make sure the core-database in $core_utils are up-to-date.
UPDATING PROCESS. At the source MOO, give the connect-bootmoo'
command to log in, just as in a core transfer. But at the welcome
screen, do connect system-updater <password>', where <password> is
your own wizard password at the destination MOO. System-updater's
confunc causes @search-core-objects' to be automatically run, and no
commands can be given until this is finished. This is necessary so
the updater can be confident that the properties in $core_utils which
list the core objects at the destination MOO are up-to-date and
complete. Thus, if the destination MOO is large, the confunc may
take a while to complete. Once it is complete, system-updater is
connected to $player_start, and can give the update commands,
described below. Unlike the system object logins, system-updater can
also give all the player and room commands available to any
programmer. Although the system-updater is not a wizard as such, it
has access to verbs which can change any object. Because of this,
only wizards should use this character, and all connected wizards are
notified when system-updater logs on and off.
It is best but not essential that the destination MOO not be occupied
by too many other players when the update is being done. BUT SEE
WARNINGS BELOW. To avoid other players (or the system) sending
output to system-updater which may be mixed with data being sent to
the source MOO, system-updater's notify() verb gags all players but
itself. This can be changed by giving the command @set me.gagall to
0', but this is not recommended. Gagging is turned back on again
when system-updater logs on.
Once system-updater is logged into the destination MOO through
running connect-bootmoo at the source MOO, much of the same commands
as given in the core transfer process can be given. However, in some
cases, the commands operate slightly differently. These are as
follows:
%UPDATE, %UPDATE_ALL. If given without an argument, one or
all of the core objects which have changed (as indicated by their
.last_Modified property), or which have been newly created, are
updated. This involves transferring all their verbs and
non-initialized properties. Unlike %UPDATE when logged in as
system, properties which are initialized in the object's
.initcore_data property (except for "name" and "alias") are not
transferred. These properties are assumed to be customized on
the destination MOO, so updating them would not be desired. If
%UPDATE is given with an object id (it's unique_id[1]), that
object is updated regardless of it's last_modified property.
%TRANSFER, %TRANSFER_ALL. If given without an argument, one
or all of the core objects which have been newly created are
updated. If given with an object id, the object is updated
regardless. In this case, properties which are initialized in
the object's .initcore_data are also transferred. THEREFORE, DO
NOT USE THIS NAMING EXISTING OBJECTS ON THE DESTINATION MOO WHICH
HAVE CUSTOM PROPERTIES you want to preserve. However, this must
be used (with the object named) to re-transfer any core-object
whose .initcore_data have conditional statements involving core
options which have been added since the core was created.
Specifying %transfer' without a name is safe, since this would
affect only objects which are newly created, i.e., core objects
which did not exist when the core was originally created.
%FINISH_UP. This should be done after all objects are
updated. The system will check to make sure all newly created
objects have been transferred, but not whether all updates have
been completed. (To make sure all updates are completed, give
either %update_all or %update without an object id. If nothing
is transferred, then everything should be updated.) This runs
init_after_transfer verbs on all core objects, and makes sure #0
is set up OK for normal logins. Note this is different from when
%finish_up is run during a core transfer, where init_for_core is
run for all objects. Since running init_for_core verbs can
result in loss of custom information, they should not be run in
MOOs which have already been customized.
%QUIT, %, %GET_NEW_NUMBERS. These operate exactly the same
way as for core transfers. The first closes the connection, the
second temporarily suspends connect-bootmoo without closing the
connection, and the third updates the database on the source MOO
concerning objects on the destination without transferring
anything. See above for details.
%CLOSE. This operates like %QUIT. System-updater cannot
shut down the destination MOO.
%BOOT, %INITIALIZE. These commands, which are available
during the core transfer using the system login, SHOULD NEVER BE
USED WHEN DOING A TRANSFER AS SYSTEM-UPDATER. To protect the
database against the effects of these destructive commands,
system-updater is immediately booted if they are given.
The normal process after connection is to do "%transfer_all" to
assure that all new objects are transferred, then "%update_all" to
assure that everything else is updated. If any objects need to be
specifically transferred and re-initialized, then %transfer <object
id> should be used. Finally run "%finish_up" to do any
re-initializations that may be required, and then %quit to log out.
Although the updates can be done when both the destination as well as
the source MOO are running normally, IT IS STRONGLY RECOMMENDED THAT
THE DESTINATION MOO DATABASE BE SAVED IMMEDIATELY BEFORE THE UPDATES,
AND THAT ORDINARY USERS EITHER NOT BE ALLOWED TO LOG IN, OR TOLD THAT
THEIR WORK MAY BE LOST. After the update, the destination MOO should
be thoroughly tested, and if it looks like it was seriously damaged,
the saved database should be restored. It may be that certain
objects should not be updated, or may have to be appropriately
changed on the source MOO before re-transfer. Only after thorough
testing should the destination MOO be put back into normal operation.
_______________
Additional Help
$core_utils -- specific documentation of $core_utils feature object commands
initcore-data -- description of the .initcore_data property
core-options -- controlling which segments of the MOO are included in a core
unique-id -- description of the .unique_id property
The following commands are used to display, create, or delete core options:
@core-options
Lists the available core options, and the ones that have been selected for inclusion in the next core extraction.
@create-core-option <name>
Creates and names a new core option set, and creates the database object used to keep track of which objects are on it. Each core option has a unique name to identify it. This name cannot be the same as the core id name of any other core objects. (See 'help unique-id'.) The user is prompted to give a short 1-line description of the set which is output with the @core-options command, and the more extensive '@about' text to document it. You should have prepared this documentation text before you run @create-core-option so you'll be ready to paste it in when prompted.
@delete-core-option <name>
Removes a core option set and deletes its database object. The user is asked if the references to the object are to be removed from the unique_id[2]'s of all the objects in the set. If so, these are set to "" indicating they are no longer on the core. Otherwise, the name of this set is still on the objects, but since the option DB doesn't exist, the core utilities don't recognize them as part of any valid core option.
The @corify command is used to identify objects as part of particular core options, or to change the option they are a part of. See 'help @corify'. The @uncorify command can be used to remove an object from any core option.
However, the system may be enabled by entering:
@set $login.create_enabled to 1
The system can be disabled with: @set $login.create_enabled to 0
If the creation system is disabled, then people using the `create'
command at the welcome screen will see the message set with:
@set $login.registration_string "Put your message here."
WHAT TO DO WHEN THERE ARE TOO MANY FILES TO RESYNC
When there are a *lot* of messages, and therefore a lot of files, the MOO can sometimes run out of seconds just trying to get a list of them. This typically happens when the mail folder resynchronizes itself to generate a file listing, or is expunging deleted messages. When this happens, you should either, 1. archive the mail folder and start a new one, or 2. tell the person with all those messages to @netforward and delete some.
However, if you need to just get the synchronization done, or if it is a long-term archive to which new messages are no longer being posted, you can create a "hard" directory list that the disk-mail system will use if it's there. This listing won't be updated if new messages are posted or messages are deleted, so it is only good as a temporary measure or for an archive.
To create a "hard" directory listing:
1. Log onto the server on which the MOO is running, and "cd" to the "files" subdirectory of the directory in which the MOO database is run from (e.g. cd "~du/moo/files/mail").
2. Change to the directory for the problematic mail recipient. For instance, if the problem was *general (#1017), you would "cd #1017" to do this.
3. Type "ls > .file.list" to make a "hard" directory list
4. Force the MOO's mail folder to resynchronize. For instance, you could type "@mail on *general" for resync *general. If you are creating a permanent "hard" directory for an archive, you're done. Otherwise, go on.
5. Wait for the resynchronization is compelte. In the example here, that would be demonstrated when the MOO showed you the list of messages on *general.
6. Remove the temporary file by typing "rm .file.list" on the server.
7. Back up to the mail subdirectory ("cd ..") and repeat the process with all mail recipients that are unable to resynchronize or expunge themselves without running out of time.
When someone gets a chance, they should write a "help $disk_mail_agent" text, to explain in detail how the system works.
All MOOmail commands that accept a MOO character name or mail folder
as the recipient may be given an Internet email address instead. For
instance, just as users can "@send Jane" to send a internal MOOmail
message to the character named Jane, they can "@send
johnd@outside.net" to send an Internet email message to the person at
the "johnd@outside.net" address.
Similarly, people outside the MOO can send email to specific
characters within the MOO, and that mail will be accepted by the
Email Permeability System and presented to that character as MOOmail.
The outside person would typically send to "jane@moomail.oursite.edu"
in order to send a message to the character named "Jane" at the MOO
running at the "oursite.edu" site. The specific format of the
address depends on how the sendmail.conf file has been modified on
the UNIX system where the MOO's mail is received. The
$network.inet_mail_host property carries the correct site to use for
addressing Internet email to MOO characters and mail folders.
Finally, MOO mail folders may also receive email from the Internet,
typically with something like "announcements-list@moomail.oursite.edu"
being the format to send Internet email to the *announcements mail
folder (the "-list" appended to the name indicates a mail folder).
This function, together with the ability of mail folders to send
Internet email directly, allows mail folders to serve as the in-MOO
proxy for an outside email list. For instance, a mail folder that
was subscribed to an outside email list, and also forwarded messages
to that list, would function in that way. Any users who subscribed
to the in-MOO mail folder would essentially be subscribing to that
external email list, and mail sent to the MOO mail folder would be
forwarded to that external list.
For Administrators:
Note that #0.mail_agent ($mail_agent) must be set to the
$inet_mail_agent for the Email Permeability system to function. Any
$mail_recipients in the old $mail_agent should be moved to the new
one.
Access to email permeability functions may be restricted or provided
to all MOO users and mail folders. This is controlled by an
"inet_mail" property found on $player and on $mail_recipient. It is
a LIST, which may contain any or none of "can_receive" indicating the
object may receive incoming Internet email, and "can_send" indicating
it can send mail to Internet addresses.
The @email-access command on $wizard is provided to set this
property, which can be set directly on $player or $mail_folder for
broadly enabling the email permeability functions.
The $network.inet_mail_host property (a STR) must be set in order to
enable outgoing email to have a proper "reply-to" address. This
property should be the Internet site where mail to a MOO character or
mail folder is to be sent (i.e. the MOO's outside maildrop). There
must, of course, be a $popmail_MOOagent that will retrieve the mail
from that site, and the specified site should have its sendmail.conf
modified to accept mail for the MOO. This property is also used to
create the "postmaster@site" address for email the MOO bounces for
some reason.
See `help $popmail_MOOagent' and `help $pop3_utils' for information
about properties on those objects that must be set to enable the MOO
to retrieve its mail from the outside mail drop site.
For Programmers:
Additional detailed information about each part of the system is
available on the appropriate MOO objects. The specific objects,
properties, and verbs that are unique to the Internet Email
Permeability System are:
$core_help.email-permeability
POP3 email utilities ($pop3_utils)
Internet Forwarding Mail Recipient ($inet_mail_recipient)
POP3 email to MOO agent ($popmail_MOOagent)
Internet Email Mail Agent ($inet_mail_agent)
Core Help ($core_help)
.email-permeability
Wizard Help ($wiz_help)
.@email-access
generic player ($player)
.inet_mail
Generic Mail Recipient ($mail_recipient)
.inet_mail
Network Utilities ($network)
.inet_mail_host
Outside the MOO, the sendmail.conf of the MOO's mail-drop must be modified.
In addition, the following existing verbs and properties were
modified to support email permeability:
System Object ($sys)
.mail_agent
generic player ($player)
:notify_mail
:@nn
Generic Mail Recipient ($mail_recipient)
:is_usable_by
Mail Room ($mail_editor)
:parse_invoke
:parse_recipients
:parse_msg_headers
Network Utilities ($network)
.initcore_data
:return_address_for
:invalid_email_address
General Help Database ($help)
.mail
.@send
Commands:
@banish -- boot a guest off and save the collected @witness log
@guests -- lists all connected @guests and their origin site
@request -- what guests use to request characters (moves them to the $request_booth)
@make-guest -- make a new guest character, adding to the available set
@blacklist -- restrict guest access from an internet site
Significant properties:
$guest.domain_login_threshold
The maximum number of guests that can connect from a single
domain. Useful for preventing "mobbing" of the MOO by guests from
one site. (NUM)
$guest.default_gender
The default gender for guests. (STR)
$guest.default_description
The default description for guests. (LIST)
guest.extra_confunc_msg
A message displayed to all guests when they connect. (STR)
$guest.toomany_message
Displayed when all the guests characters are taken and someone
tries to connect as a guest. (STR)
$guest.default_drawing_mode
Are guests shown ASCII art drawings by default. (BOOL)
$guest.default_user_options
The default value for $guest.user_options. (LIST)
$guest.huh_help
If 1, give guests some hints if they type in something the MOO
doesn't understand. (BOOL)
Additional topics:
guest-banishing -- about using the @banish command
$request_booth -- the place people who @request are moved, and
the object that presents an application for
them to fill out. It has many settings that
should be customized for the MOO.
creation_enabled -- for allowing people to make characters for
themselves right from the welcome screen
(rarely useful).
access-restrictions -- a summary of access restriction commands
relevent for all character types
The DU core extraction system uses the .initcore_data property on each object to give property and verb initialization information necessary for the object to operate properly in a newly extracted core. This property should contain text (a list of strings) giving the specifications for changes to be made in properties or verbs in objects when they are transferred to the new core. It can be used to specify which verbs or properties are not to be included, property initializations, or reprogrammed verbs. For example, a typical line would be '<property name> = <initial value>', such as initializing a list to {}, etc. For a DB object, it might specify that no properties defined on the object are to be transferred except perhaps for a specified few. This property thus serves the same function as the init_for_core verb did in the LambdaCore system, making separate init_for_core verbs unnecessary for most objects.
The following are valid inputs in an .initcore_data property:
<name> = <value> ............... Initializes a property. <value> must be a
string which is decodable as a value in an
eval. It should NOT contain absolute
object numbers.
% <comments> ................... to add comments which are ignored.
%delprop <property to delete> .. to delete or clear a property.
%delverb <verb to delete> ...... to delete a verb. The verb must be
identified by its name + all aliases as
given in verbs().
%verbcode <verb to re-program> .. to change verb code. The verb must be
<verb code> identified by its name + all aliases
%end as given in verbs().
%noverbs ....................... to delete all verbs defined on the object.
%clearprops .................... to clear or delete all properties except
those listed, builtin properties,
unique_id, last_modified, creation_date,
and initcore_data.
%noprops ....................... Delete all properties defined on the
object except those whose values are given
explicitly. (Inherited properties are not
cleared.)
%saveprop <property to save> ... (used in conjunction with %noprops) Do not
delete this property.
%saveverb <verb to save> ....... (Used in conjunction with %noverbs) Do not
delete this verb.
%nocopydb ...................... Don't copy any properties whose name start
with a blank.
%if [!|-]<option> ............... following code to '%endif' is to be used
if the indicated core option is (or isn't)
selected.
%endif .......................... ends '%if' block.
The command '@check-for-core <object>' can be used to determine if the object has problems with property initialization, and if there are errors in the object's .initcore_data property. If there is output saying **new** or that something is set to a different object number, it means that there are absolute object number references in the object. This almost always means that the property involved needs to be initialized in the .initcore_data text.
This text describes the system that builds and manages the integrated
interface display. See the BioGate System installation instructions
for instructions on setup.
The trajectory of the web transaction that creates the user display
is as follows:
<http_port>:do_login_command -> $http_handler:handle_http10
:handle_http10 checks if the transaction is an authentication
request (empty URI with a form submitted), and if it is then looks,
using a call to $http_handler:preprocess_URL, to see if there is an
"integrated_web_interface" form entry (the value is ignored. This
may be present because the name of the SUBMIT button for the
integrated interface on the web Gateway page is
"integrated_web_interface" so if the user selects that button then a
form entry with that name will be included. If they select the
button for an independent web window (usually named
"independent_web_window") then that would be the form entry included
instead).
If the integrated web interface has been selected, the
authentication is set to $no_one (anonymous), the URI is set to
"/frame_mgr/0/frameset" and the transaction continues based on the
new value.
-> $http_handler:process -> $frame_manager:method_post
-> $frame_manager:make_frameset
The :make_frameset verb builds the HTML page including the <FRAMESET>
tags, defining the frames layout. It checks the submitted form for
an entry named "client" and uses the value (a number) to determine
the object number of the $jclient_handler to use. It also identifies
an "interaction_frame_height" that is the percentage of the browser
window taken up by the interaction frame, and any @weboption settings
to be initialized after the user connects.
The :make_frameset verb then calls the
<jclient_handler>:preload_page to retrieve the URL for the HTML doc
displayed in the web frame until the telnet client connects and sends
its first "display url" command. The :preload_page verb checks the
<jclient_handler>.default_preload_page property. If it's a STR then
it is assumed to be a URL for the preload page, else if it is a LIST
it is assumed to be the text of
The :make_frameset verb specifies a URL for the interaction frame
that includes the form data as a "method GET"-encoded form (appended
to the URL after a "?"). This URL will cause the browser to retrieve
a web page generated by $frame_manager:get_jclient_html the HTML page
itself, in a separate transaction initiated automatically by the web
browser when it seeks to fill the frames..
The :get_jclient_html verb calls <jclient_handler>:make_applet_html
to retrieve the HTML text to be loaded into the "interaction frame"
that contains the Java Telnet applet itself. This text typically
contains the <APPLET> section that loads the applet. The
:make_applet_html verb extracts various applet settings from the
submitted form, which are specific to the applet it handles. If the
applet is capable of issuing a command upon connection tot he MOO,
the :make_applet_html verb can use the user_name and password fields
to issue a "preapproved <username> <password>" line that will
automatically connect to the correct user. The password is a
temporary password valid for only a few minutes after its generation,
and issued specifically to allow the applet to automatically connect
without giving away the user's true connect password.
To summarize, the presence of field named "integrated_web_system"
in the submitted Gateway form leads to a <FRAMESET> page being
issued. The web frame contents are determined by
<jclient_handler>:preload_page and the interaction frame's contents
are determined by <jclient_handler>make_applet_html. Once the telnet
applet connects, it is expected to issue an MCP "display-url"
directive that replaces the top frame's contents with a view of the
room the newly connected character is in.
This *transmission* format is distinct from the *storage* format, though, for convenience this same format is often used as well for storing messages in users' collections and ordinary $mail_recipient children though, in general, there is no requirement that this be the case.
A transmitted message is a list in the following form
date (number),
the time() value at the time the message was sent.
from (string),
the sending object (address list form)
if this is not a character, an additional header will indicate the
current ownership of the object.
to (string),
recipients (address list form) which can either be characters
or $mail_recipient descendents.
subject (string),
subject of the message, or " " if there is no subject,
@additional optional headers (list of strings),
each header has the form "<header-name>: text" where <header-name>:
is padded out to a width of 10 columns for the convenience of
:display_message. Currently "Reply-to: <address list>" is the only
additional header in use,
"",
@body of message (list of strings)
Note that the from, to and subject lines do *not* include a header name like "From:", "To:", or "Subject:". The @'s indicate that the lists in question get spliced in (as usual), thus the entire message is a list whose first element is a number and the rest are strings.
The address lists that appear in the from and to lines is a string in the form a sequence of object ids, each enclosed in parentheses and preceded by optional text, e.g.,
"*Core-DB-Issues (#8175), Rog (#4292), and Haakon (#2)"
The text is intended to give the current name of each object for the benefit of human readers, but is actually ignored by all header parsing routines. The convention is that the text is either a character name or a * followed by a mailing list name.
:new_message_num()
=> number that will be assigned to the next incoming message.
By default this returns the maximum of the message numbers appearing in
messages or .messages_going, incremented by 1. If the recipient is a character
then the value returned will be 1 higher if it conflicts with the person's
current message number for him/herself.
:receive_message(msg,sender)
By default this first calls this:new_message_num to obtain a message number to assign to the incoming message and then appends {num,msg} to this.messages.
`sender', the original sender, is supplied in case one wants different
action depending on who is sending the message (e.g., mail-gagging).
The return value should be an error or string if :receive_message is considered to have failed in some way. Otherwise, a number should be returned - this number is given to any :notify_mail routines that are called and is expected to either be 0 or the number assigned to the incoming message.
Note that :receive_message can do arbitrary things, including resending the same message to a new destination. Hacking :receive_message to resend messages is different from using .mail_forward in the following respects
(1) the resent message is considered to be a distinct message having this
object as its "author" - i.e., the From: line will necessarily be
different.
(2) since this "forwarding" is invisible to the mailsystem,
there is no protection against loops and multiple copies.
:mail_forward([from])
should return either
. a list of objects (either characters or $mail_recipients)
to which mail for this recipient will be redirected.
. a string error message to be printed to the person sending the message.
If this recipient is one of the original destinations (i.e., not the
result of a previous forwarding), no mail is actually sent.
If :mail_forward returns a nonempty list, the recipient itself will *not*
actually receive the mail message unless it is included in the list.
#-1 is allowed to be on the list; it is ignored but does make the list
nonempty. Thus, having :mail_forward() return {#-1} is the canonical way
to have arriving mail disappear without being kept or forwarded.
:mail_notify([from])
should return a list of objects that are to be told about any mail sent
to this recipient (whether or not the recipient actually receives it).
Said objects must have a :notify_mail verb, but other from that, there
is no restriction on what these can be.
object:notify_mail is called with the arguments
(sender,recipients,msgnumbers) where
recipients == list of recipients including object in .mail_notify
msgsnumbers == corresponding list of :receive_message return values
(or 0 if :receive_message is not actually called, which
will be the case if the recipient forwards without keeping)
When called as part of a mail send, the `from' argument is the immediate predecessor on the forwarding chain. The default versions of these verbs return the values of .mail_forward and .mail_notify respectively (pronoun_subbing if the value is a string), unless this is a moderated mailing list and `from' is an unapproved sender (see `help MR-access') in which case the following verbs are called instead:
:moderator_forward(from)
what :mail_forward should return for mail coming from unapproved senders
This returns .moderator_forward (pronoun_subbed if a string) by default.
:moderator_notify(from)
what :mail_notify should return for mail coming from unapproved senders
This returns .moderator_notify (pronoun_subbed if a string) by default.
Since the :mail_forward verbs only see the previous sender in the forwarding chain, if, e.g, B is moderated but A can send to B (i.e., B:mail_forward(A) returns an actual list), then any mail sent to A goes to B even if the original sender isn't normally allowed to send to B directly.
These verbs should all allow `from' to be omitted in which case they should return as if `from' were a generic approved sender (e.g., wizard).
It should rarely be necessary to actually modify any of :*_forward/*_notify verbs, since one has a fair amount of control over their behavior via the following properties
.mail_forward
.mail_notify
.moderated (see `help MR-access')
.moderator_forward
.moderator_notify
This is the canonical way to send a mail message from a program.
This calls $mail_agent:make_message to format the arguments into an actual message (see `help mail-format') and then $mail_agent:raw_send to do the actual sending which goes as follows:
(1) Call :mail_forward on all recipients add any new recipients thus obtained to final recipient list, keep calling mail:forward on the new recipients until we obtain no additional recipients. If one of the initial recipients is invalid, is not a user character or $mail_recipient, or has its mail_forward return a string error, then we print the error message and abort at this point with no mail being sent. If one of the later recipients bombs similarly, error messages are printed, but in this case mail still goes out to the other recipients.
(2) Call :mail_notify on all recipients encountered in stage (1) to get a list of objects to notify.
(3) All final recipients receive the message (see `help receive-mail')
(4) All notifications are delivered (using :notify_mail())
We return {0, @failed_recipients} if we bombed out at step 1.
Otherwise return {1, @actual_rcpts} indicating what mail was sent.
mail-sending -- how to send mail from a program; what happens.
mail-forwarding -- how to do mail forwarding/notification (the simple version)
mail-resolve -- how mail forwarding/notification works, in gory detail
mail-receiving -- what :receive_message should do
mail-format -- format of transmitted messages
$mail_recipient -- generic non-user character mail recipient
$mail_agent -- mail utility object
$disk_mail_agent -- a $mail_agent for FUP-based external mail
DAILY
@forked
Check the @forked list and become familiar with what tasks are
usually there. Sometimes tasks will hang in endless loops and the
@forked list is the only place they will appear. The task's code can
be checked, and the programmer can be contacted to insure tasks that
don't get cleared are supposed to be continuously running. Use the
@tasks command if the @forked list is long.
@memory
Check @memory and note if the RAM or disk usage has changed
dramatically from previous values. RAM usage may not be enabled on
your server, but disk DB size should be. Large increases in size
usually indicates that either someone has created a huge object, or
that there is a running task storing some huge value.
@big-objects
Use @big-objects to see what the largest objects in the DB are. If
you do not have byte-based quota, users may occasionally create
(accidentally or on purpose) a large object that you may wish to have
them recycle.
Checkpointing
Use `look #0' to check the system object for the time of last
backup and to verify it succeeded. If checkpoints fail, a message is
also generally sent to *wizards. Note the amount of time the
checkpoint took to run. When checkpoints start taking unusually
long, it's typically curable by restarting the MOO (presumably there
is a memory leak responsible).
Use `@trend-db' to note the size on disk of recent checkpoint
files. Rapid size increases (more than 5%) are an indication that
either someone has created something that uses a lot of data (in
which case it may show with `@big-objects' on the next daily
measurement) or there is a memory leak. If nothing shows with
`@big-objects' look again at the @forked list for new tasks. You may
need to check the code for any new ones to see if they are building
some variable, usually a LIST, that is growing out of control. If
none of these are the case, you may want to restart the MOO since
this typically cures server-based memory leaks.
WEEKLY
Database Backups
Once a week, at least, someone should check the MOO's backups on
the server, to see if they are getting archived properly.
MONTHLY
Once every month or two, the MOO server should generally be shut down
and restarted, to clear out memory leaks. You should find that the
in-memory size of the MOO and the checkpoint time decrease (sometimes
up to 15%) after such a restart. If the the restart results in an
in-memory size decrease of more than 20%, there is probably a serious
memory leak and you may want to consult with people experienced in
MOO server internals.
QUARTERLY
Checking the Character Registry Database
It's usually worthwhile to update the Character Registry Database
quarterly or so, and clear out names and addresses for recycled
characters. This is faster than the yearly @reload activity. Use
`@verify $player-db' to check the Character Registry Database for
recycled characters.
Verify Rooms without Domains
If the MOO is using the domain system (see "help domain-system"),
has a $domain.domainless set, and uses "out" aliased exits to assign
domains, you should verify the domainless rooms periodically and
assign them to domains as appropriate. Determine the object number
for the "Domainless Rooms Domain" (@d $domain.domainless), and then
use "@verify <domain>" to have each room automaticaly evaluated.
YEARLY
Mail Folder Archiving
When the mail folders get extremely large, they are very time
consuming to search. An effective method for keeping popular mail
folders small is to annually rename them with "-archive#" at the end,
and start a new mail folder with the original name. If you do this
for one of the mail folders that new users are automatically
subscribed to, you will want to update the $local.autosubscribe_lists
list.
Reloading the Character, Site, and Registration Databases
The databases that store all character names ($player_db), places
they've connected from ($site_db), and all registered email addresses
($registration_db) continue to grow unless they are reloaded
periodically. Reloading them generally needs to be done every one or
two years. Since they serve an important security function, keeping
records of recent changes to critical data, they probably shouldn't
be cleared more often than annually. Use the "@reload" command on
each to reload each database (e.g. @reload $player_db).
You should reload these databases when few or no people are
connected. Various functions, including new character creation and
connecting to characters, may be disrupted while they are reloading.
Note that if you start running out of ticks when new characters are
created, it might be that one of these databases has grown too large
and needs to be reloaded.
Flushing the Editors
Use "@peepeditor in <editor>" to check each of the $note_editor,
$mail_editor, $list_editor, $html_editor, and $verb_editor for
sessions that are invalid (the session belongs to a non-$player
object) or ancient (sessions older than 6-12 months, depending on
your policy). Use "@flush <editor> for <object>" to delete a stored
editing session that are invalid or ancient.
ON STARTUP
The following tasks should initiate automatically upon startup,
and appear in the @forked list:
$byte_quota_utils:measurement_task
Performs periodic measurement of objects' size, adjusting people's
`size_quota' to reflect the update. Use `start $byte_quota_utils'
if this task dies.
$wiz_utils:idle_check
This checks if people are idle longer than the specified limits,
gives them a warning, and then disconnects them. If the task doesn't
initiate properly, you can use `@start-idlechecking on $local' to
start it.
$player_start:keep_clean
This verb keeps the player start room clean of all but connected
players and resident objects.
$net_ncp:netwho_poll
$eDUnet:network_pollmaster
These may be active if your MOO is part of an EduNet system.
$lag_meter:lag_cycle
This is the $lag_meter task that measures how long after being
scheduled forked or suspended tasks are actually being run. When lag
iz zero, they run at exactly the scheduled time. If the lag_cycle
task has died or not started, you can use `@startup $lag_meter' to
initiate lag measurement.
By default, these verbs refer to the following properties:
writers - list of people other from the owner who can do anything
readers - if == 1, indicates a public mailing list.
list of additional readers (by default anyone who receives mail
sent to the list can read the saved messages).
moderated - if false, indicates a normal mail recipient everyone can send to.
otherwise this should be a list of approved senders (or
1 if noone but the owner and wizards can send).
restricted - list of people who specifically may not send to the list
Terminology:
A mailing list is "public" if everyone can read it.
A mailing list is "moderated" if not everyone can send to it.
Note that while being able to write to a recipient implies being able to read from it or send to it, neither of read-ability or send-ability implies the other.
It is highly recommended that if you are creating custom mail recipients with variable reader/sender lists, i.e., you find you need to write your own :is_readable/usable/writabe_by verbs, you are best off if such verbs are of the form
return pass(@args) || << your_test(args[1]) >>
and have .writers == .readers == {} and .moderated == 1. This will ensure
(1) wizards having write access
--- necessary in order for :receive_message to work
(2) writers being able to read and send (the converse being a ludicrous
situation),
(3) persons on the mail_forward list of someone with reader access will also
have read access (convenient).
The $mail_recipient was extended to allow Manager class access,
though the .manager_readers, .manager_writers, .manager_unsealed_for,
and .manager_moderators properties. These are LISTs with each
element a STR naming a property on $manager that indicates a
managerial area of responsibility. Any $manager in a listed area of
responsibility has access corresponding to the readers, writers, or
moderators abilities. The .unsealed_for indicates those managers can
read sealed msgs.
The .aliases field holds the names by which one may refer to the list, but only those names not containing spaces actually count for anything. As with certain other types of objects (e.g., character objects), set_aliases() needs to be called in order to change the .aliases field.
$mail_agent:match(name)
is the canonical way to obtain the objectid of a mailing list
given the name ("*" is assumed; an initial "*" will be dropped).
$mail_agent:match_recipient(name)
is the canonical way to obtain the object id of a list or person
matching the given name. An initial "*" indicates that this is
supposed to be a list.
$mail_agent:match_failed(objid,name)
is the mail_recipient counterpart to $command_utils:object_match_failed
:display_seq_headers (message sequence, current message number, last_read_date)
Does a @mail listing of the given message sequence. If current message
number is given and the sequence includes it, we mark it with a `>'.
Likewise if the sequence includes any new messages (i.e., dated after
last_read_date), these are also indicated as such.
display_seq_full (message sequence, preamble)
Does a @read listing of the given message sequence. Each message is preceded
by preamble.
=> {new current message number, new last_read_date}
:messages_in_seq (index)
=> {n, msg}
:messages_in_seq (message sequence)
=> {{n_1,msg_1},{n_2,msg_2},...}
where the n_i are message numbers and the msg_i are messages in transmission
format (see `help mail-format')
:list_rmm ()
Does an `@unrmm list' listing of messages in .messages_going
from_msg_seq (objectid or list [,mask])
=> message sequence: messages from (one of) the given objectid(s)
%from_msg_seq (string or list [,mask])
=> message sequence: messages with (one of) the given string(s)
in the From: line
to_msg_seq (objectid or list [,mask])
=> message sequence: messages to (one of) the given objectid(s)
%to_msg_seq (string or list [,mask])
=> message sequence: messages with (one of) the given string(s)
in the To: line
subject_msg_seq (string [,mask])
=> message sequence: messages with given string occurring in Subject:
body_msg_seq (string [,mask])
=> message sequence: messages with given string occurring in body of message
In all cases `mask' is a message sequence which one may supply to limit the range of the search. One way of looking at it is that the message sequence to be returned is first intersected with mask.
Message sequences can in turn be obtained from routines like rcpt:parse_message_seq, which takes a command-line description of a message sequence on that particular recipient and returns the corresponding message sequence handle.
The actual form of a message sequence (though you shouldn't actually need to make use of this) is that of a set of integers in the format used by $seq_utils (see `help $seq_utils'). It should however be noted that these integers are *not* themselves message numbers, but rather indices into the list of saved messages. For example, if a particular recipient holds 5 messages numbered 1,3,5,7,9. Then the message sequence handle representing messages 3,5,7 collectively, would be {2,5} which is $seq_utils-ese for the range 2..4, namely the second, third and fourth messages saved on that recipient.
The following verbs are available for obtaining indices to use in message sequences
:length_all_msgs() => total number of messages, or equivalently,
=> index of last message
:length_num_le(n) => number of messages numbered <= n, or equivalently,
=> index of highest numbered message <= n
:exists_num_eq(n) => 0 unless there exists a message numbered n in which
case we return the index of that message.
:length_date_le(date) => number of messages dated <= date, or equivalently,
=> index of most recent message dated <= date
:length_date_gt(date) => number of messages dated > date
Note that r:length_date_gt(date) == r:length_all_msgs()-r:length_date_le(date).
The only reason :length_date_gt is provided as a separate routine is in order
to do quick checks for the existence of new mail (as @rn needs to do).
See: mail-recipients in Builder Help
(1) Hard subscribed == being on the recipient's .mail_forward list so that mail sent to this list is forwarded to one's own .messages as well (see `help mail-forwarding').
(2) Soft subscribed == keeping track of a current message for this recipient and (optionally) being on the recipient's .mail_notify list.
Each character has a .current_message property that contains, for each recipient the person cares to keep track of, a current message number and a last read date.
player:current_message(rcpt) (somewhat obsolete)
=> person's current message number for rcpt
player:get_current_message(rcpt)
=> person's {current message number for rcpt, last-read-date for rcpt}
player:make_current_message(rcpt)
=> adds a current_message entry for rcpt (NOOP if rcpt == player)
player:set_current_message(rcpt,n|E_NONE,[,date])
=> sets person's current message number for rcpt to n iff n!=E_NONE
updates the last-read-date for rcpt to date iff date > last-read-date
player:kill_current_message(rcpt)
=> removes current-message info for rcpt (NOOP if rcpt == player)
On $mail_recipient, .mail_forward and .mail_notify are -c so one needs to use the following verbs to actually modify them.
:add_forward(@new_recipients)
:delete_forward(@recpients)
:add_notify(@new_notifiees)
:delete_notify(@notifiees)
A recipient's owner is, of course, allowed to make arbitrary changes to .mail_forward and .mail_notify. However, the default versions of these verbs also allow anyone to add him/herself to a recipient's .mail_forward or .mail_notify if the recipient is readable (see `help MR-access') by him/her.
Likewise anyone may use the :delete* verbs to delete him/herself from any .mail_forward/.mail_notify list, regardless of his actual access to the list.
Note for wizards:
You can set the list of mail folders to which new characters are
automatically subscribed by changing the
$wiz_utils.autosubscribe_lists value (set to {} by default).
:rm_message_seq (message sequence)
Does an @rmmail. Messages in message sequence are removed from this
recipient's saved .messages and written to .messages_going.
:undo_rmm ()
Does an @unrmm. Messages in .messages_going are copied back to .messages.
:expunge_rmm ()
Does an @unrmm expunge. Blows away .messages_going.
:renumber ()
Does a @renumber.
(*) LOC:match("X")
- what you get looking for something that is inside LOC and named "X".
By default, this looks through LOC.contents to find a unique object
having a name or alias that has "X" as a prefix.
Essentially, you can think of :match as a contents-matching verb, though, e.g., for rooms you also get matches on exits as well.
(*) LOC:match_object("X", YOU) [YOU defaults to `player']
(*) YOU:my_match_object("X", LOC) [LOC defaults to player.location]
- what YOU get being located at LOC and looking for something named "X".
By default these both return $string_utils:match_object("X",LOC,YOU)
(*) $string_utils:match_object("X", LOC, YOU)
- what you *would* get *if* YOU were a typical user, YOU were inside LOC,
YOU were looking for something named "X", *and* LOC were a typical place.
In other words, $string_utils:match_object describes the :match_object() algorithm for "typical places" and the :my_match_object for "typical user characters":
(1) check for "X" being one of "", "me", "here", "$something", or "#n"
(2) try YOU:match("X") i.e., something in your inventory (maybe)
(3) try LOC:match("X") i.e., some object in the room (maybe)
The distinction between these location:match_object and player:my_match_object has to do with whether the user character object or the location should determine what the matching algorithm is. Which one you should use depends on the command that you are writing. If you are writing a command with a virtual-reality flavor, then you should be respecting the room owner's idea of which objects you can "see" and thus the command should be calling the location's :match_object verb. If you are writing a building/programming command where it is appropriate for the character object to determine the matching algorithm - whether because the current location is irrelevant, not to be trusted, or both - then the character's :my_match_object verb should be called.
Examples:
`look diamond in box'
calls box:match("diamond"). This is a match on the contents of box.
`take ball',
calls player.location:match_object("ball")
to determine which "ball" to take. Note that if the room is dark,
we might not be able to find any "ball".
`@program widget:foo',
calls player:my_match_object("widget") to get the character's own idea
of what "widget" should be. Note that if I were carrying something
named "widget" and expecting to be programming a :foo() verb on it,
it would be potentially disastrous should the room where I am decide
for me to be programming something else (not even necessarily
called "widget").
Object Matching Failures
------------------------
As with other matching routines, one gets back
$failed_match in the case of no matching object
$ambiguous_match in the case of more than one matching object
$nothing in the case of a blank string argument
or an object-id. In these first 3 cases, one usually wants to translate these nonresults to the user character; this is what $command_utils:object_match_failed. The standard idiom to mimic what the builtin parser does, say, with the direct object is
dobj = foo:match_???(dobjstr);
if($command_utils:object_match_failed(dobj, dobjstr))
"...give up. nothing to do. error message has already printed...";
else
"...dobj is something useful. Continue...";
...
endif
Unique_id[1]: A string giving a unique name for the object. This is also refered to as the object's 'core name'. It must be different for each object.
Uniuqe_id[2]: A string identifying whether this is part of the basic core which must be in any core database, or whether the object is part of a "core option" set, which can be optionally included or not. If the string is the same as $core_utils.core_id, the object is part of the base core. If it is a blank string, it is not a core object. If it is anything else, it is part of a core option set of that name. (See 'help @core-options')
Unique_id[3]: The date this object was transferred from a core extraction, or 0 if it is on the source MOO.
This differs from the LamdbaCore system, which uses all objects defined as a property on #0 (i.e, as $<name>), or their parents, as the set included on the core. In the this system, objects which are not on #0 can be included in the core even if they are not parents of such objects, and objects on #0 need not be included. However, in the latter case, care should be taken that references to the corresponding $<name>'s not be in the core objects,
See @about $core_utils or @mailme $core_utils for more details.
1. URL-embedded "webpass" system
In this system, a password is embedded into the URL for the
transaction. A webpass of "anon" or "anonymous" always gives the
transaction the permissions of $noone. The webpass is a temporary
value associated with the user for the duration of the session. It
is erased from the $http_handler.webpass_handler database when the
user disconnects from their character. Since the temporary webpass
appears within the URL, visible to whoever is looking over the user's
shoulder, it is not as secure as the web cookie system.
2. web cookie system
In this system, a temporary webpass is generated but appears as a web
cookie within the header lines of the transaction, and not in the
URL. If an $http_port is set to use web cookies and the user's
browser doesn't recognize them, then the system automatically uses
URL-embeded webpasses instead. Detection of the browser's web cookie
function is performed by sending a cookie (named "cookies_ok") with
the gateway page, and then checking for it on the subsequent
authentication form submission. If the browser can't handle web
cookies, then the system automatically switched to URL-embedding of
the webpass. The web cookie system is considered the most secure and
recommended for general use.
Note that users can "clear" their authentication in two ways under
the web cookie system. One is to chose the "List of Application"
where there is a button that performs this task. The other is to
return the the MOO's gateway page. A "clear" cookie is always sent
to the user's browser when that page is sent by the MOO, insuring
that the user can reauthenticate without any lingering cookies to
complicate the process.
3. "web authentication" system
This uses the authentication method given in the HTTP/1.0
specification. As stated there, it is not intended for highly secure
activity since the password is essentially sent in the clear, even
though it is hidden from the casual user by its incorporation into
the HTTP header lines. In this system, the user is presented by the
browser with a request for their character's name and password. This
information is thereafter included in every transaction to the MOO
until the browser is reinitialized, generally by quitting and
restarting. For this reason, this "web authentication" method is not
recommended, although it is a capability of the BioGate System.
See: biogate-system