Title: Adhering to RFC1436 Created: 2017-11-12 Author: zlg Edited: 2020-05-23 I've been meaning to shape up my gopherhole to better adhere to the Gopher standard. I felt that outlining the steps I went through may help others get in line with the standard, if they feel it's something that they can accomplish. Skip this article if you don't care about technical mumbo-jumbo like protocols and standards. RFC1436 is available just about anywhere else that hosts RFCs, but perhaps the most relevant location for us Gopher fans is Floodgap itself, which hosts a copy in gopherspace. [1] The IETF (Internet Engineering Task Force) maintains RFCs via HTTP, and naturally Gopher's RFC can be found there too. [2] The first step is to find a way to interface with the gopherhole where you see all of its output. The telnet client is perfect for testing. On Gentoo, there are a few options for telnet clients, but I use net-misc/netkit-telnetd. The spec mentions telnet in section 1.b, too. Here's an excerpt of testing my own gopherhole: (Tabs are represented with [TAB] to improve legibility.) (Also, lines are intentionally long to correctly represent the protocol.) ~~~~ $ telnet zlg.space 70 Trying [REDACTED]... Connected to zlg.space. Escape character is '^]'. / i You've reached the gopherhole of...[TAB]-[TAB]-[TAB]0 i ____ _ _ _ _ _ ___[TAB]-[TAB]-[TAB]0 i |_ /___ | | (_) |__ ___ _ _| |_(_)_ _ ___ / __|__ _ _ __ ___ _ _[TAB]-[TAB]-[TAB]0 i / // -_) | |__| | '_ \/ -_) '_| _| | ' \/ -_) | (_ / _` | ' \/ -_) '_|[TAB]-[TAB]-[TAB]0 i /___\___| |____|_|_.__/\___|_| \__|_|_||_\___| \___\__,_|_|_|_\___|_|[TAB]-[TAB]-[TAB]0 i[TAB]-[TAB]-[TAB]0 i games, GNU/Linux, programming, design[TAB]-[TAB]-[TAB]0 i[TAB]-[TAB]-[TAB]0 0About this server[TAB]/about.txt[TAB]zlg.space[TAB]70 0About me[TAB]/me.txt[TAB]zlg.space[TAB]70 0Current Backlog[TAB]/backlog.cgi[TAB]zlg.space[TAB]70 i[TAB]-[TAB]-[TAB]0 iCONTENT[TAB]-[TAB]-[TAB]0 1Video Game FAQs[TAB]/faqs[TAB]zlg.space[TAB]70 1Articles[TAB]/articles[TAB]zlg.space[TAB]70 1Images[TAB]/images[TAB]zlg.space[TAB]70 hCode[TAB]URL:https://git.zlg.space[TAB]zlg.space[TAB]70 1Projects[TAB]/files[TAB]zlg.space[TAB]70 i[TAB]-[TAB]-[TAB]0 iANCILLARY[TAB]-[TAB]-[TAB]0 0"What's my IP?"[TAB]/ip.cgi[TAB]zlg.space[TAB]70 1Other Gopherholes[TAB]/links[TAB]zlg.space[TAB]70 1Guestbook[TAB]/guestbook.dcgi[TAB]zlg.space[TAB]70 Connection closed by foreign host. ~~~~ (Note: sgopherd does not appear to terminate its output with "." on the last line, as the spec suggests. It closes the connection upon reaching the end of a file instead, which is probably a bit more sane and less prone to accidental end-of-output. It also allows for fingerd support, which afaik is archaic, but who knows, maybe it'll see a comeback, too!) As you can see, it spits out the raw text emitted by the gopher server. The first line after "Escape character is" is where you enter your request, where I chose "/", the path for the top-level page. (An empty line (technically CR+LF) is equivalent to "/") It's similar to HTTP's GET data (everything after "?" in a Web URL) in that it sends it to the server, and the server spits out the data for you. It remembers nothing about state. There are no cookies, no MIME-type headers, no text-encoding, nothing. Because of this, gopher servers are idempotent by default. That is, if you issue the same request, you'll always get the same data. State is introduced through storage mechanisms and specific type-7 or type-9 requests, in which the state is still stored on and interpreted by the server. Interestingly, the type of your request is irrelevant. If I wanted to check the Guestbook, I would not enter "/1/guestbook.dcgi", as one would with a gopher browser. Just "/guestbook.dcgi" is good enough; the important logic is on the server, where it belongs. So, what does this have to do with getting your gopherhole in line with the spec? If you pipe telnet's output to another program, or redirect its output to a file, you can test that output against any scripts you make for gopher compliance. For example, you can count the number of characters appearing after the 'i' and before the first tab in an informational (display) line to make sure it's under a certain threshold. You could massage erroneous tabs into a number of spaces, or pass it through a custom linter, which will show you errors. In any case, having the raw protocol data is useful for bringing your gopherhole up to par. Next, let's talk nitty-gritty details that are buried in the spec, i.e. things a gopherhole admin can make use of. THE NITTY-GRITTY The executive summary for *implementing* a gopherhole comes down to this: * An "About this server" entry is recommended as the first 'link'; (S 3.3) This page should have contact information and a 'last modified' line * Gateway servers are preferred over new item types (S 3.4) * New item types are preferred for new features (S 4) (This is strangely contradictory; personally I find new item types more compelling and forward-thinking.) * User-display strings (that is, everything we see in a gopher listing) should be kept at or under 70 characters wide. Clients may truncate wherever. (S 3.9) (Individual file types do not appear to be limited, though keeping with the 70-character limitation is probably in good taste. 80 characters is still a common practice and thus acceptable to most.) * Client display strings should conform with the Latin1 character set (S 4, after "DirEntity") * Selector strings should stay under 255 characters long (S 4, "Directory Entity") * Text files with lines starting with "." should prepend an additional "." to prevent early disconnection by (some) clients. (S 4, "Textfile Entity") CREATING A STYLE Now we know what the standard suggests. How much of that is relevant to 2017 computing? In many circles, 80 characters is still standard. Adjusting your gopher listings to 70 characters isn't a big deal. Most text files are drafted at 80 or fewer characters, so modifying those to suit a specific protocol seems counter-intuitive. The Latin1 character set is a bit of a problem, as it doesn't allow for international communication. It's clear that the spec was a little US-centric at the time (it was only 1993), and Unicode hadn't reached wide adoption yet. (Trivia: Rob Pike and Ken Thompson created UTF-8 for Plan9 in 1992, see [3]) If Gopher was drafted in the last 10 years (or more), it would've likely settled on some variant of Unicode in order to support non-English speaking people. To that end, I think it's safe for us to use UTF-8 (or some compatible variant) and add a note somewhere on our gopherholes to indicate such choice, so clients may configure themselves to support a wide array of languages. Limiting ourselves to Latin1 goes against the intent of the standard, which is more important than the letter of it. This is one of those parts of the spec that should really be updated. STICKING TO THE STYLE In my case, the first "gotcha" is the main header for the gopherhole. A lot of us use text-based art (ASCII, Shift-JIS, UTF-8, whatever) to convey a "logo" or header. Mine is (obviously) more than 70 characters wide, so it was back to the drawing board with me. This was a great opportunity to re-do the header and flex some art skills. It took me about an hour, but I've settled on this: ~~~~ _, .---,----.-----,---. _./ '._ \ ____ _ , ' ___ | -==-- --='________===- | |_ /| | / __| / _. | / /_| |__( (_-. | -='__`==- : /____|____|\___| | /'\ | , ' . , : ( @ ) ___ `----"---'----^----' \,/,/_.' .:._._,.-n.,_-.:. . | | -. . || . -vV/ `-_-.--.,--v--'o\_vVv\v|v(-v|v\|/vVvVv\vV\/._vVVvvVv\|/v\/v\|/Vv- 'o. .'o.O`. ./ .' Welcome to zlg.space, port 70. ~~~~ With the header out of the way, it's time to think about the display of your Gopher menus. It's entirely a style choice, but I'm a fan of "less is more". I won't bore you with details; if you're seeing this article, the gopherhole has been updated to match my adaptation to the spec. EDITOR SETTINGS Any competent text editor will allow you to set things up in a way that you don't accidentally go past 70 characters, or save in the wrong encoding. This article is outside the scope of that, but all you really need is to set hard-wrapping to 70 characters and convert all tabs to spaces. I use Vim with these settings: expandtab tabstop=4 softtabstop=4 shiftwidth=4 textwidth=70 formatprg=par-format\ w70 See `:help [foo]` (where [foo] is the option) to learn more about these settings. Drew Neil, author of Practical Vim and the Vimcasts website [4] has crafted a ton of useful resources for those looking to get the most out of their Vimming. I don't get anything for mentioning his work; it's just been super useful to me over the years. CLOSING This article is already quite large, so I have nothing to add. If you enjoyed this article, consider leaving a message on the Guestbook or respond to me from your own Gopherhole and link it in the comments! I'm happy to read what others respond with. FOOTNOTES I did not use the "section" symbol in my citations because it may not display correctly on client machines. You can test this by looking at this glyph: ยง. If it does not look like a fancy "S" with a gap in the middle, your client does not support UTF-8. I have used "S" for citations instead. Yes, this is ironic considering my thoughts on Latin1. [1]: gopher://gopher.floodgap.com/0/gopher/tech/rfc1436.txt [2]: https://tools.ietf.org/html/rfc1436 [3]: http://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt [4]: http://vimcasts.org