<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: dotcomboom</title>
    <description>The latest articles on DEV Community by dotcomboom (@dotcomboom).</description>
    <link>https://dev.to/dotcomboom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F96085%2Ff0fdbe3a-360f-4b5a-b673-b72817999df8.jpg</url>
      <title>DEV Community: dotcomboom</title>
      <link>https://dev.to/dotcomboom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dotcomboom"/>
    <language>en</language>
    <item>
      <title>Pituophis: Setting up a Gopher server</title>
      <dc:creator>dotcomboom</dc:creator>
      <pubDate>Sat, 09 Mar 2019 02:47:11 +0000</pubDate>
      <link>https://dev.to/dotcomboom/pituophis-setting-up-a-gopher-server-17kl</link>
      <guid>https://dev.to/dotcomboom/pituophis-setting-up-a-gopher-server-17kl</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a tutorial for the Gopher library I wrote called &lt;a href="https://github.com/dotcomboom/pituophis" rel="noopener noreferrer"&gt;Pituophis&lt;/a&gt;, and is current as of version 0.95. While the API is more or less finalized, it may still be subject to change.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up a server
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Installing Pituophis
&lt;/h2&gt;

&lt;p&gt;If you haven't already, install Pituophis by running &lt;code&gt;pip3 install pituophis&lt;/code&gt;, or the equivalent for your Python 3 setup. You will most likely need Python 3.7 or later, because of its usage of asynchronous socket connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  The base script
&lt;/h2&gt;

&lt;p&gt;First, you'll need to crack open whatever comfortable environment you have and create a new Python file. Save it to a new directory, and then create a new one named "pub" inside of the same directory.&lt;/p&gt;

&lt;p&gt;This is what should go in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pituophis&lt;/span&gt;

&lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pub_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pub/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a Gopher server that will serve files from the &lt;code&gt;pub&lt;/code&gt; directory, that's it! Pituophis will also send the gophermap file in each directory if it's available. To run the server just save and then start the script. If you're using a port that is below 1024 (as port 70 is) you may need to run it with elevated privileges .&lt;/p&gt;

&lt;p&gt;The host, which is &lt;code&gt;127.0.0.1&lt;/code&gt; in the example, should be changed to whatever host clients will be connecting on. If you're only going to use the server on your machine, it's fine to leave it that, but if you're running it on a private or public IP address or domain name change it to that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alt handlers
&lt;/h2&gt;

&lt;p&gt;Pituophis also lets you use an alt handler, a function that will take in requests and then spit out what to send back. If Pituophis, for example, notices that a path does not exist in the publish directory, it will hand off the request to the alt handler.&lt;/p&gt;

&lt;p&gt;To use an alt handler, first define it and set it to be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pituophis&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pub_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pub/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alt_handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The alt handler can return False if it can't do anything with the request, so Pituophis will send back an error as usual.&lt;/p&gt;

&lt;p&gt;This example uses the alt handler to send back a menu displaying the request's attributes and a couple selectors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pituophis&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/stats&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Path: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Query: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Host: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Port: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Client: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;itype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;View server.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/server.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;itype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;View some text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;pituophis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pub_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pub/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alt_handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember, if a directory or file called &lt;code&gt;stats&lt;/code&gt; exists in the publish directory, the alt handler will not run, and that static file will be sent instead.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo1qaofxxv9sunancxyyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo1qaofxxv9sunancxyyd.png"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Gopher Protocol in Brief</title>
      <dc:creator>dotcomboom</dc:creator>
      <pubDate>Fri, 08 Mar 2019 22:57:45 +0000</pubDate>
      <link>https://dev.to/dotcomboom/the-gopher-protocol-in-brief-1d88</link>
      <guid>https://dev.to/dotcomboom/the-gopher-protocol-in-brief-1d88</guid>
      <description>&lt;p&gt;Gopher is a protocol for fetching information that dates back to 1993. It's often regarded as a predecessor of sorts to the HTTP protocol that serves as the backbone of the Web as we know it today, however its simplicity and structure gives it a lot of worth.&lt;/p&gt;

&lt;p&gt;Gopher is a very simple protocol to work with, and one lunch break could net you basically all you need to know about the protocol. Let me give a rundown.&lt;/p&gt;

&lt;p&gt;I'll use &lt;code&gt;(NL)&lt;/code&gt; in this article to refer to a newline. According to RFC 1436, this is the equivalent of &lt;code&gt;\r\n&lt;/code&gt;, or a Windows/DOS newline. Note that Gopher selectors use tab characters (&lt;code&gt;\t&lt;/code&gt;) instead of spaces to separate fields, so you'll need to replace them with tabs in the examples.&lt;/p&gt;

&lt;h1&gt;
  
  
  Request
&lt;/h1&gt;

&lt;p&gt;The client firsts make a connection to a remote host (a quite necessary step to be frank).&lt;/p&gt;

&lt;p&gt;Once this connection is established, the client sends text to the server with the path it wants to access, if applicable, a query string separated by a tab, and followed then a newline, like this:&lt;br&gt;
&lt;code&gt;/fruits   pineapple(NL)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, the client can just send a newline, and the server will treat it as listing root &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Response
&lt;/h1&gt;

&lt;p&gt;This is all the information the server needs to process the request. The server then sends over raw data, sometimes ending with a newline followed by a period character (as described in RFC 1436). It then closes the connection.&lt;/p&gt;

&lt;p&gt;Unlike HTTP, which uses headers for server responses, Gopher leaves it up to the client to interpret it; this is why a Gopher URL should have an item type in it so the client knows what it will receive.s That brings us to...&lt;/p&gt;
&lt;h1&gt;
  
  
  URL Schemas
&lt;/h1&gt;

&lt;p&gt;So, that means, instead of this to receive a text document:&lt;br&gt;
&lt;code&gt;gopher://gopher.floodgap.com/gopher/proxy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should use this, to explicitly tell the client that it'll receive plain text:&lt;br&gt;
&lt;code&gt;gopher://gopher.floodgap.com/0/gopher/proxy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Other (older?) implementations of the Gopher URL are like this, where the item type and path are not separated by a slash:&lt;br&gt;
&lt;code&gt;gopher://gopher.floodgap.com/0gopher/proxy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;While this is how it is laid out in RFC 4266, "The gopher URI Scheme", I am not in favor of it. Reason being is how using the malformed URL from earlier would tell the client that it is to fetch &lt;code&gt;opher/proxy&lt;/code&gt; and treat it as a &lt;code&gt;g&lt;/code&gt; (which happens to be the GIF) item type. Having the slash after the type would make it easier for the client to tell if a URL doesn't have an item type specified, since all types are one character.&lt;/p&gt;
&lt;h1&gt;
  
  
  Directories/Menus
&lt;/h1&gt;

&lt;p&gt;Gopher servers can send whatever files and raw data to the client, but what ties it all together are menus. Here's an example menu response, playing off of the fruits example from earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1Back to ThingSearch    /   thingsearch.uh  70
iHere are your results for "pineapple". /   error.host  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each line in a Gopher menu is a selector, which leads to a resource on a specific server. This can be the same host and port, or another server. Each field is separated by a tab, with the exception of the selector's display text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The type, which tells the client how to understand the resource when it is fetched from the server.&lt;/li&gt;
&lt;li&gt;The display text, without any tab characters. The general rule of thumb is that it should be formatted for a screen of 67 characters across at max. This is not necessarily for technical reasons, however.&lt;/li&gt;
&lt;li&gt;The path where the resource is located. In information selectors, this can be left blank.&lt;/li&gt;
&lt;li&gt;The host of the server.&lt;/li&gt;
&lt;li&gt;The port of the server, which is typically 70.&lt;/li&gt;
&lt;li&gt;An extra field could be used to signify that the resource is Gopher+-enabled, although clients that don't support it should be able to ignore it. This isn't shown in the example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the menu to be parsed correctly, all of these fields must be present, except the extra field for Gopher+, which is optional.&lt;/p&gt;

&lt;p&gt;I've separated a sample of the types that can be used in a menu into four basic categories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Item types
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0&lt;/code&gt;: Plain text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Menus:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt;: Directory/Menu&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;7&lt;/code&gt;: Search service (Directory/Menu that accepts a query)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Binaries:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;4&lt;/code&gt;: HQX file (old Mac archives)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;5&lt;/code&gt;: PC binary&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;9&lt;/code&gt;: Generic binary (your best bet)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g&lt;/code&gt;: GIF image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I&lt;/code&gt;: Generic image (be careful when parsing, Gopher item types are case-sensitive)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s&lt;/code&gt;: WAV sound (for MP3s and other formats, you should use type &lt;code&gt;9&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Information:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;3&lt;/code&gt;: An error&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt;: Informational text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;3&lt;/code&gt; and &lt;code&gt;i&lt;/code&gt; selectors, even being just information, should still have all of the above required fields filled in. (The path can be blank so long as the tabs are there.) The example above uses a fake host and port. It could be anything, doesn't matter all too much. This way, the few clients that don't interpret information selectors as such will at least have somewhere fake to link to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gophermaps
&lt;/h2&gt;

&lt;p&gt;A Gophermap is a file in a directory representing a Gopher menu used by many modern Gopher servers (Gophernicus, Pygopherd, and of course Bucktooth that introduced it). Gophermaps also have a simplified syntax, where the server acts as a preprocessor and will fill in fields and take care of things like relative directories as needed. Additionally, lines without tabs are turned into information selectors automatically.&lt;/p&gt;

&lt;p&gt;In a Gophermap, if you're linking to another resource on the same server, you could have a selector that's like this:&lt;br&gt;
&lt;code&gt;1Food food/&lt;/code&gt;&lt;br&gt;
and the server will take that and blow it up into a full Gopher selector, filling in the blanks:&lt;br&gt;
&lt;code&gt;1Food /things/food    127.0.0.1   70&lt;/code&gt;&lt;br&gt;
In this example, the Gophermap is in the directory &lt;code&gt;/things&lt;/code&gt;, the server fills that into the path so the client can understand it. The server knows that it is being advertised on host &lt;code&gt;127.0.0.1&lt;/code&gt; and port &lt;code&gt;70&lt;/code&gt; from its configuration, so it fills that in.&lt;/p&gt;

&lt;p&gt;Here's another example with some information:&lt;br&gt;
&lt;code&gt;The quick brown fox jumps over the lazy dog.&lt;/code&gt;&lt;br&gt;
Because it doesn't have any tab characters, this is turned into something along the lines of:&lt;br&gt;
&lt;code&gt;iThe quick brown fox jumps over the lazy dog. /   error.host(T)0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In essence, when using a Gophermap file, the server does the heavy lifting so the client doesn't need to make assumptions when parsing the final Gopher menu.&lt;/p&gt;

&lt;h1&gt;
  
  
  External links
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tools.ietf.org/html/rfc1436" rel="noopener noreferrer"&gt;RFC 1436 "The Internet Gopher Protocol"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tools.ietf.org/html/rfc2466" rel="noopener noreferrer"&gt;RFC 2466 "The gopher URI scheme"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sdf.org/?tutorials/gopher" rel="noopener noreferrer"&gt;The SDF's Gopher tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Gopher_(protocol)" rel="noopener noreferrer"&gt;Gopher on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common Gopher servers that use Gophermaps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="gopher://gopher.floodgap.com:70/1/buck"&gt;Bucktooth&lt;/a&gt; &lt;a href="https://gopherlens-py.dotcomboom.repl.co/?url=gopher://gopher.floodgap.com:70/1/buck" rel="noopener noreferrer"&gt;&lt;sup&gt;(proxy)&lt;/sup&gt;&lt;/a&gt; (Perl, introduced the Gophermap format)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jgoerzen/pygopherd" rel="noopener noreferrer"&gt;Pygopherd&lt;/a&gt; (Python 2.x)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/prologic/gophernicus" rel="noopener noreferrer"&gt;Gophernicus&lt;/a&gt; (C)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are a couple of my related projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://gmap.dotcomboom.repl.co" rel="noopener noreferrer"&gt;Gophermap Editor&lt;/a&gt; (HTML5)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dotcomboom/Pituophis" rel="noopener noreferrer"&gt;Pituophis&lt;/a&gt; (Python 3 client/server library)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gopher</category>
      <category>protocol</category>
      <category>sockets</category>
    </item>
  </channel>
</rss>
