Gopher utilities #69

Parent #72Owner #361Flags readSource hellcore/hellcore.db

Aliases: Gopher utilities

18 verbs · 17 properties · 0 children

Verbs

VerbSpecFlagsDefinerLines
get_nowthis none thisrxd#6940
parsethis none thisrxd#6921
show_textthis none thisrxd#6931
typethis none thisrxd#6926
summarythis none thisrxd#6929
getthis none thisrxd#6936
clear_cachethis none thisrxd#6910
unparsethis none thisrxd#697
interpret_errorthis none thisrxd#6911
trustedthis none thisrxd#692
_textpthis none thisrxd#693
_mail_textthis none thisrxd#6914
init_for_corethis none thisrxd#694
display_cachethis none nonerxd#6925
get_cachethis none thisrxd#699
cache_entrythis none thisrxd#698
help_msgthis none thisrxd#691
dailythis none thisrxd#6911

Properties

PropertyDefinerFlagsOwnerValue
cache_requests#69r#361{}
cache_times#69r#361{}
cache_values#69r#361{}
limit#69rc#3612000
cache_timeout#69r#361900
frozen#69rc#3611
help_msg#72rc#361<clear>
aliases#1rc#361{"Gopher utilities"}
description#1rc#361
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) 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#29{14019, 1298433815}
hidden_verbs#1rc#361<clear>
phelp_msg#1rc#361<clear>
weight#1rc#361<clear>
owner_verbs#1rc#361<clear>
plural_name#1rc#361<clear>
client_image#1rc#361<clear>
listening#1rc#361<clear>

Ancestry

Ancestors (nearest first): #72 Generic Utilities Package#1 root

Children: none

Call graph

calls n69_0 #69:get_now n69_9 #69:trusted n69_0->n69_9 n66_2 #66:open n69_0->n66_2 n66_3 #66:close n69_0->n66_3 n69_2 #69:show_text n69_2->n66_2 n69_2->n66_3 n107_43 #107:tell n69_2->n107_43 n69_4 #69:summary n69_1 #69:parse n69_4->n69_1 n69_3 #69:type n69_4->n69_3 n69_5 #69:get n69_5->n69_0 n69_5->n69_9 n51_37 #51:task_valid n69_5->n51_37 n48_8 #48:suspend_if_needed n69_5->n48_8 n69_15 #69:cache_entry n69_5->n69_15 n69_6 #69:clear_cache n69_6->n69_9 n69_11 #69:_mail_text n69_11->n69_1 n69_11->n69_5 n69_10 #69:_textp n69_11->n69_10 n69_12 #69:init_for_core n69_12->n69_6 n1_22 #1:init_for_core n69_12->n1_22 n69_13 #69:display_cache n69_13->n107_43 n20_1 #20:left n69_13->n20_1 n20_2 #20:right n69_13->n20_2 n35_6 #35:dhms n69_13->n35_6 n69_16 #69:help_msg n1_8 #1:description n69_16->n1_8 n69_17 #69:daily n69_17->n69_6 n69_17->n69_17

Source

get_now

Spec this none thisFlags rxdOwner #361Definer #69

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 #361Definer #69

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 #361Definer #69

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 #361Definer #69

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 #361Definer #69

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 #361Definer #69

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.";
3if (this.frozen)
4return E_QUOTA;
5endif
6request = args[1..3];
7while ((index = request in this.cache_requests) && (this.cache_times[index] > time()))
8if (typeof(result = this.cache_values[index]) != INT)
9return result;
10endif
11if ($code_utils:task_valid(result))
12"spin, let other process getting same data win, or timeout";
13suspend(1);
14else
15"well, other process crashed, or terminated, or whatever.";
16this.cache_times[index] = 0;
17endif
18endwhile
19if (!this:trusted(caller_perms()))
20return E_PERM;
21endif
22while (this.cache_times && (this.cache_times[1] < time()))
23$command_utils:suspend_if_needed(0);
24this.cache_times = listdelete(this.cache_times, 1);
25this.cache_values = listdelete(this.cache_values, 1);
26this.cache_requests = listdelete(this.cache_requests, 1);
27"caution: don't want to suspend between test and removal";
28endwhile
29$command_utils:suspend_if_needed(0);
30this:cache_entry(@request);
31value = this:get_now(@args);
32$command_utils:suspend_if_needed(0);
33index = this:cache_entry(@request);
34this.cache_times[index] = time() + ((typeof(value) == ERR) ? 120 | 1800);
35this.cache_values[index] = value;
36return value;

clear_cache

Spec this none thisFlags rxdOwner #361Definer #69

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 #361Definer #69

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 #361Definer #69

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 #361Definer #69

Referenced by

Source

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

_textp

Spec this none thisFlags rxdOwner #361Definer #69

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 #361Definer #69

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 #361Definer #69

Referenced by

none

Source

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

display_cache

Spec this none noneFlags rxdOwner #361Definer #69

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 #361Definer #69

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 #361Definer #69

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 #361Definer #69

Referenced by

none

Source

1return this:description();

daily

Spec this none thisFlags rxdOwner #361Definer #69

Referenced by

Source

1if (caller_perms().wizard)
2day = 24 * 3600;
3hour_of_day_GMT = 10;
4fork ((((hour_of_day_GMT * 60) * 60) + day) - (time() % day))
5this:daily();
6endfork
7this.frozen = 1;
8this:clear_cache();
9suspend(3900);
10this.frozen = 0;
11endif