Gopher utilities #75

Parent #1Owner #2Flags readSource QuestCore.db

Aliases: Gopher utilities

17 verbs · 9 properties · 0 children

Verbs

VerbSpecFlagsDefinerLines
get_nowthis none thisrxd#7540
parsethis none thisrxd#7521
show_textthis none thisrxd#7531
typethis none thisrxd#7526
summarythis none thisrxd#7529
getthis none thisrxd#7533
clear_cachethis none thisrxd#7510
unparsethis none thisrxd#757
interpret_errorthis none thisrxd#7511
trustedthis none thisrxd#752
_textpthis none thisrxd#753
_mail_textthis none thisrxd#7514
init_for_corethis none thisrxd#754
display_cachethis none nonerxd#7525
get_cachethis none thisrxd#759
cache_entrythis none thisrxd#758
help_msgthis none thisrxd#751

Properties

PropertyDefinerFlagsOwnerValue
cache_requests#75r#2{}
cache_times#75r#2{}
cache_values#75r#2{}
limit#75rc#22000
cache_timeout#75r#2900
key#1c#20
aliases#1rc#2{"Gopher utilities"}
description#1rc#2
list of 30{"An interface to Gopher internet services.", "Copyright (c) 1992,1993 Grump,JoeFeedback@LambdaMOO.", "", "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\"", ""}
object_size#1r#36{13181, 1539462952}

Ancestry

Ancestors (nearest first): #1 Root Class

Children: none

Call graph

calls n75_0 #75:get_now n75_9 #75:trusted n75_0->n75_9 n72_2 #72:open n75_0->n72_2 n72_3 #72:close n75_0->n72_3 n75_2 #75:show_text n75_2->n72_2 n75_2->n72_3 n6_18 #6:tell n75_2->n6_18 n75_4 #75:summary n75_1 #75:parse n75_4->n75_1 n75_3 #75:type n75_4->n75_3 n75_5 #75:get n75_5->n75_0 n75_5->n75_9 n59_37 #59:task_valid n75_5->n59_37 n75_15 #75:cache_entry n75_5->n75_15 n75_6 #75:clear_cache n75_6->n75_9 n75_11 #75:_mail_text n75_11->n75_1 n75_11->n75_5 n75_10 #75:_textp n75_11->n75_10 n75_12 #75:init_for_core n75_12->n75_6 n1_28 #1:init_for_core n75_12->n1_28 n75_13 #75:display_cache n75_13->n6_18 n20_71 #20:redirect_ansi n75_13->n20_71 n43_6 #43:dhms n75_13->n43_6 n75_16 #75:help_msg n1_9 #1:description n75_16->n1_9

Source

get_now

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1"Usage:  get_now(site, port, message)";
2"Returns a list of strings, or an error if we couldn't connect.";
3{host, port, message, ?extra = {0}} = args;
4if (!this:trusted(caller_perms()))
5return E_PERM;
6elseif ((!match(host, $network.valid_host_regexp)) && (!match(host, "[0-9]+%.[0-9]+%.[0-9]+%.[0-9]+")))
7"allow either welformed internet hosts or explicit IP addresses.";
8return E_INVARG;
9elseif ((port < 100) && (!(port in {70, 80, 81, 79})))
10"disallow connections to low number ports; necessary?";
11return E_INVARG;
12endif
13opentime = time();
14con = $network:open(host, port);
15opentime = time() - opentime;
16if (typeof(con) == ERR)
17return con;
18endif
19notify(con, message);
20results = {};
21count = this.limit;
22"perhaps this isn't necessary, but if a gopher source is slowly spewing things, perhaps we don't want to hang forever -- perhaps this should just fork a process to close the connection instead?";
23now = time();
24timeout = 30;
25end = "^%.$";
26if (extra[1] == "2")
27end = "^[2-9]";
28endif
29while ((((typeof(string = `read(con) ! ANY') == STR) && (!match(string, end))) && ((count = count - 1) > 0)) && ((now + timeout) > (now = time())))
30if (string && (string[1] == "."))
31string = string[2..$];
32endif
33results = {@results, string};
34endwhile
35$network:close(con);
36if (opentime > 0)
37"This is to keep repeated calls to $network:open to 'slow responding hosts' from totally spamming.";
38suspend(0);
39endif
40return results;

parse

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1"parse gopher result line:";
2"return {host, port, tag, label}";
3"host/port/tag are what you send to the gopher server to get that line";
4"label is <type>/human readable entry";
5{string} = args;
6tab = index(string, "	");
7label = string[1..tab - 1];
8string = string[tab + 1..$];
9tab = index(string, "	");
10tag = string[1..tab - 1];
11string = string[tab + 1..$];
12tab = index(string, "	");
13host = string[1..tab - 1];
14if (host[$] == ".")
15host = host[1..$ - 1];
16endif
17string = string[tab + 1..$];
18tab = index(string, "	");
19port = toint(tab ? string[1..tab - 1] | string);
20return {host, port, tag, label};
21"ignore extra material after port, if any";

show_text

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1"$gopher:show_text(who, start, end, ..node..)";
2"like who:notify_lines($gopher:get(..node..)[start..end]), but pipelined";
3if (!caller_perms().wizard)
4return E_PERM;
5endif
6{who, start, end, @args} = args;
7con = $network:open(who, start);
8if (typeof(con) == ERR)
9player:tell("Sorry, can't get this information now.");
10return;
11endif
12notify(con, end);
13line = 0;
14sent = 0;
15end = end || this.limit;
16while (((string = `read(con) ! ANY') != ".") && (typeof(string) == STR))
17line = line + 1;
18if ((line >= start) && ((!end) || (line <= end)))
19sent = sent + 1;
20if (valid(who))
21if (string && (string[1] == "."))
22string = string[2..$];
23endif
24who:notify(string);
25else
26notify(who, string);
27endif
28endif
29endwhile
30$network:close(con);
31return sent;

type

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1type = args[1];
2if (type == "1")
3return "menu";
4elseif (type == "?")
5return "menu?";
6elseif (type == "0")
7return "text";
8elseif (type == "7")
9return "search";
10elseif (type == "9")
11return "binary";
12elseif (type == "2")
13return "phone directory";
14elseif (type == "4")
15return "binhex";
16elseif (type == "8")
17return "telnet";
18elseif (type == "I")
19return "image";
20elseif (type == " ")
21"not actually gopher protocol: used by 'goto'";
22return "";
23else
24return "unknown";
25endif
26"not done, need to fill out";

summary

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1"return a 'nice' string showing the information in a gopher node";
2if (typeof(parse = args[1]) == STR)
3parse = this:parse(parse);
4endif
5if (parse[1] == "!")
6return {"[remembered set]", "", ""};
7endif
8if (length(parse) > 3)
9label = parse[4];
10if (label)
11type = $gopher:type(label[1]);
12label = label[2..$];
13if (type == "menu")
14elseif (type == "search")
15label = (("<" + parse[3][rindex(parse[3], "	") + 1..$]) + "> ") + label;
16else
17label = (type + ": ") + label;
18endif
19else
20label = "(top)";
21endif
22else
23label = parse[3] + " (top)";
24endif
25port = "";
26if (parse[2] != 70)
27port = tostr(" ", parse[2]);
28endif
29return {tostr("[", parse[1], port, "]"), label, parse[3]};

get

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1"Usage: get(site, port, selection)";
2"returns a list of strings, or an error if it couldn't connect. Results are cached.";
3request = args[1..3];
4while ((index = request in this.cache_requests) && (this.cache_times[index] > time()))
5if (typeof(result = this.cache_values[index]) != INT)
6return result;
7endif
8if ($code_utils:task_valid(result))
9"spin, let other process getting same data win, or timeout";
10suspend(1);
11else
12"well, other process crashed, or terminated, or whatever.";
13this.cache_times[index] = 0;
14endif
15endwhile
16if (!this:trusted(caller_perms()))
17return E_PERM;
18endif
19while (this.cache_times && (this.cache_times[1] < time()))
20((ticks_left() < 4000) || (seconds_left() < 2)) && suspend(0);
21this.cache_times = listdelete(this.cache_times, 1);
22this.cache_values = listdelete(this.cache_values, 1);
23this.cache_requests = listdelete(this.cache_requests, 1);
24"caution: don't want to suspend between test and removal";
25endwhile
26((ticks_left() < 4000) || (seconds_left() < 2)) && suspend(0);
27this:cache_entry(@request);
28value = this:get_now(@args);
29((ticks_left() < 4000) || (seconds_left() < 2)) && suspend(0);
30index = this:cache_entry(@request);
31this.cache_times[index] = time() + ((typeof(value) == ERR) ? 120 | 1800);
32this.cache_values[index] = value;
33return value;

clear_cache

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1if (!this:trusted(caller_perms()))
2return E_PERM;
3endif
4if (!args)
5this.cache_values = this.cache_times = this.cache_requests = {};
6elseif (index = args[1..3] in this.cache_requests)
7this.cache_requests = listdelete(this.cache_requests, index);
8this.cache_times = listdelete(this.cache_times, index);
9this.cache_values = listdelete(this.cache_values, index);
10endif

unparse

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1"unparse(host, port, tag, label) => string";
2{host, port, tag, label} = args;
3if (tab = index(tag, "	"))
4"remove search terms from search nodes";
5tag = tag[1..tab - 1];
6endif
7return tostr(label, "	", tag, "	", host, "	", port);

interpret_error

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1"return an explanation for a 'false' $gopher:get result";
2value = args[1];
3if (value == E_INVARG)
4return "That gopher server is not reachable or is not responding.";
5elseif (value == E_QUOTA)
6return "Gopher connections cannot be made at this time because of system resource limitations!";
7elseif (typeof(value) == ERR)
8return tostr("The gopher request results in an error: ", value);
9else
10return "The gopher request has no results.";
11endif

trusted

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1"default -- gopher trusts everybody";
2return 1;

_textp

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1"_textp(parsed node)";
2"Return true iff the parsed info points to a text node.";
3return index("02", args[1][4][1]);

_mail_text

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1"_mail_text(parsed node)";
2"Return the text to be mailed out for the given node.";
3where = args[1];
4if (this:_textp(where))
5return $gopher:get(@where);
6else
7text = {};
8for x in ($gopher:get(@where))
9parse = $gopher:parse(x);
10sel = parse[4];
11text = {@text, "Type=" + sel[1], "Name=" + sel[2..$], "Path=" + parse[3], "Host=" + parse[1], "Port=" + tostr(parse[2]), "#"};
12endfor
13return text;
14endif

init_for_core

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1if (caller_perms().wizard)
2this:clear_cache();
3pass(@args);
4endif

display_cache

Spec this none noneFlags rxdOwner #2Definer #75

Referenced by

none

Source

1"Just for debugging -- shows what's in the gopher cache";
2req = this.cache_requests;
3tim = this.cache_times;
4val = this.cache_values;
5"save values in case cache changes while printing";
6player:tell("size -- expires -- host (port) ------ selector ------------");
7for i in [1..length(req)]
8re = req[i];
9host = $string_utils:left(re[1] + ((re[2] == 70) ? "" | tostr(" (", re[2], ")")), 24);
10expires = $string_utils:right($time_utils:dhms(tim[i] - time()), 8);
11va = val[i];
12if (typeof(va) == LIST)
13va = length(va);
14elseif (typeof(va) == ERR)
15va = toliteral(va);
16else
17va = tostr(va);
18endif
19selector = re[3];
20if (length(selector) > 40)
21selector = "..." + selector[$ - 37..$];
22endif
23player:tell($string_utils:right(va, 8), expires, " ", host, selector);
24endfor
25player:tell("--- end cache display -------------------------------------");

get_cache

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1"Usage: get_cache(site, port, selection)";
2"return current cache";
3request = args[1..3];
4if (index = request in this.cache_requests)
5if (this.cache_times[index] > now)
6return this.cache_values[index];
7endif
8endif
9return 0;

cache_entry

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

Source

1if (index = args in this.cache_requests)
2return index;
3else
4this.cache_times = {@this.cache_times, time() + 240};
5this.cache_values = {@this.cache_values, task_id()};
6this.cache_requests = {@this.cache_requests, args};
7return length(this.cache_requests);
8endif

help_msg

Spec this none thisFlags rxdOwner #2Definer #75

Referenced by

none

Source

1return this:description();