text: A Gopher Client in Rust
  RFC Notes
  I'm going to implement a Gopher client in rust because it seems like a good project to try out. I'm going straight to the source for this which means that I'm going to implement the client based on my reading of the RFC. Which will be a first and I think quite fun. It's short RFC and the gopher protocol is very simple. I'm also going to use bare rust so I'll try to keep the number of dependencies down to 0.
  The RFC to read:
  - Protocol goes over TCP on port 70
  - Clients send strings called 'selector' to the server
  - The Server responds with text and terminating chracter is a period on a line by itself.
  - Connection is automatically closed.
  - Gopher is designed to appear like a filesystem
  - Each line in a gopher listing 5 parts
  - User visible name
  - User should only see the User Visible Name
  - Only time the Client sends back more than one string is on a search, selector is sent along with a space delimited string of words to search for
  - Server will respond with a regular listing but this may span multiple subnets and even the internet
  Example of a Gopher listing:
  F is tab, so a gopher listing is a tab delimited string, with each string being on a new line.
  TypeUser Visible NameFPathFDomain nameFPort
  - Note Type doesn't have a tab delimiter.
  Path is the selector string the client will send to the Domain Name on Port.
  - User should only see the User Visible Name.
  - If there is more tabs than this, ignore the rest.
  - Displaying the types is up to the client and the author's taste.
  - There can be root level Gopher servers that hold listings pointing to other Gopher servers, this should be load balanced.
  - Recommended to have an About document with contact information as well as what the server holds on each Gopher server in the top level.
  - The base types are 0 for files, 1 for directories and 7 for search.
  - Client can save the paths the User navigates to to form a stack
  - Client can cache stuff to skip network calls
  - Types that are not known can be marked as unknown or ignored, up to the client
  - New features to Gopher are only done via the types field, any further changes to Gopher will be server changes.
  This is the distilled down notes of the RFC and should be enough to get started. The design I'll go for is that of the Linux shell and I'll treat Gopher as a filesystem as the RFC mentioned.
  Something I've learned as I built the client and browsed around is the i type, it is sort of an unofficial addon to the gopher protocol such that you can attach links and text all in one document.
  A very hacky but smart solution to a problem and I'm curious who came up with it :)
  Alright! After a few days of playing with the Gopher protocol, I have the core of it working and added a whole bunch of things that I wanted as I was going around gopherholes.
  - Gopherholes are people's gopher directories/servers, maybe
  First of all, some caveats. This project really highlighted how much of a rust and it's style I still don't get. Every thing works but something about the code doesn't feel right and it bothers me.
  Second, I very much wrote this only for myself, so there isn't much in the way of robustness and error handling is only match statements and some if checks. I think that is something worth fixing.
  Third and lastly, I really enjoyed traveling the internet under my own power! Here I am viewing and reading people's thoughts with something that I wrote myself. As I read, I wanted features like bookmarks, and history and it was powerful to be able to just open up vim and add it.
  Gopher is a very human place, at least the places I was in, it's all people's thoughts and ideas and there is nothing industrial about it. I had learned about gopher on hackernews.
  The link points to a screenshot of a GUI browser pointed at baud.baby. I ended up learning about gopher and telneting in and I was hooked on his content. Just the writing style, and the fact I was telneting in scratched an itch that I always felt.
  I very much recommend implementing this on your own and then reading this to see where we may have done things differently.
  The full code is available in the third chapter.
  The full list of commands I've implemented are:
  - visit - Go to a gopherhole
  - ls - List current menu
  - cd - Switch into a directory
  - more - Read a document
  - add - Add a directory to our bookmarks
  - b - List our bookmarks
  - b{num} - Select a bookmark and go there
  - h - List the documents we've read
  - h{num} - Show the document that we read
  - where - Show where we currently are
  - bye - Quit our client
  - Search - Search the menu for something
  Feel free to add more or leave the one's you don't care for.
  The first 4 commands are really the ones you need for a minimal client.
  Anyway! Let's move to the code.
  I'm going to link the entire source at the bottom along with the one dependency which is libc in Cargo.toml.
  I'm not going to go over every line but just the functions I think were fun/hard to implement.
  The core of gopher is you connect on a port, submit a selector string and ideally get either a list of lines which is a navigation or you get a dump of text which is a document.
  With that said, the first step is to connect to a gopherhole and submit a selector string.
  The visit function opens a connection to a specified domain, port and submits the file_path. This is the selector but as I worked on the client, selector has other meanings for me(I was thinking of css and jquery) so I changed it to something that made more intuitive sense for me.
  Once we have our socket(stream) open we add a CRLF, carriage-return line-feed to our file_path and we write it as bytes to the socket. Voila! We have just done what everything does on the internet. You can't send anything but binary data over sockets so to send something we need to do the conversion. This is true for HTTP just as much as gopher!
  We then read from the socket and add everything to a vector. We could read this into an array but we don't know how much data we'll be getting back.
  We have now received binary data from the server! All we have to do is convert this binary data into text and we can then view the data. We use the from_utf8_lossy function because if there are letters we can't deal with, it will be replaced with a ?.
  We then return the data as a string to our calling function.
  The visit function is the core of our gopher client, I really like the term visit because browsing the gopherholes very much feels like visiting.
  Let's now look at what happens to the data we received from the server. One thing to note here is visit is assumed to always return data for a menu. I think this may be in the spec, but it could also not be.
  else if tokens[0] == "v" || tokens[0] == "visit" {
  In our program, when we type in visit, it will hit this if statement. We can do something like `visit baud.baby` and it will then run the visit function return with the menu for baud.baby.
  I ended up adding a promp, a list of places we are nested in and a history. Everything is a stack which is neat!
  The key part of this visit command is the parsing of the data.
  if gopher_type == "0".to_string() || gopher_type == "1".to_string() {
  We want to take the gopher menu data and create a GopherListing out of it. This way we can have a model for the data we receive. Our parsing function is very simple and the RFC make's quite clear that this was one of the goals.
  All the parser does is, split on tabs, if it is type 0 or 1, create a GopherListing. I know there are more types in the wild and i is very much used everywhere but I didn't want to deal with it so I stayed with the what made sense to me.
  Once we run our visit function, we then parse the data into a vector of gopher listings and then save that to our stack!
  - After finding that there were a number of gopherholes using the I type, I added a simple one line change to allow i types to get through the parsing step. As soon as I did, Type 1 Files, open into a listing of type I lines which I can see on the screen.
  The if statement simply lets i types get added to the GopherListing.
  LS - List Gopher Items
  Now that we have a vector of gopher listings, we can now start displaying them.
  This function will just print out the user visible name and the id. I had originally had just the visible name but I changed it quickly after getting tired of typing in the full name to view the document. I should have saw in the RFC that numbers as menu options is also a core part of gopher!
  This function actually does double duty as I also added rudimentary search here, this was a later addition.
  This function also removes some of the clutter that would happen if we printed the i types like normal, this way we don't add unuseable numbers for the i type lines.
  The ls command calls the display function with the last item on the stack. This means that we are saving all of our visits to various gopher holes so we don't have to do another network call.
  Now we can view a list of gopher items on our screen! The next step is to move into a type 1 gopher item which is a directory.
  Once we display the listing of gopher items, a user can now do `cd 2` to mean that they want to go inside the second line in the listing.
  So we first figure out where we're going. We find the listing in our vector and visit it. Now instead of passing CRLF to get the base menu, we will pass in what the listing has for it's file_path. Once we get the data back, we will do what we did in our visit command.
  We will add the listing to our pwd(path of working directory), we will then add it to our stack. Our stack is a vector of all the places we've been.
  Now the next time we go to do ls, to list our gopher items, we will pick up the listings in the last part of our stack which is the newest place we're in.
  Now we can travel down menus! The final thing we need to be able to do is view second type of gopher items - the documents!
  More - Viewing Gopher Documents
  More acts very similar to cd, we type in ` more 3` meaning we want to view 3, and if it is a type 0, it will output to the screen.
  We use the visit function again but the difference here is that instead of creating a GopherListing from the data, we will simply pass the data to our display_document function.
  The core of this function is that we split the data by newlines and display each line.
  The extra logic is for pagination. We get the height of the window and then only display the lines that fit. We allow the user to hit anything to go to the next page or q to exit in the middle. The window height is actually stolen from the term_size crate. The rust crates site, docs.rs is very easy to use and viewing the source of rust crates is quite friendly.
  This code was mostly taken from term_size because I didn't want to add any dependencies, adding libc in my mind isn't that bad and term_size was really just a wrapped for libc so I went directly to the source. There are some magic numbers here that I don't understand but it works!
  ! We have the core functions of our client at this point, we have the ability to connect to a gopherhole, display the menu, travel the menu, and view a document.
  That's it! In the next chapter, I'll go over some of the features I added such as history, bookmarks and search.
  Then we have our add command, `add .` allows us to add the current directory we are in to our book marks, we first add it to our file and then we also add it to our list of bookmarks.
  Just `b` by itself will trigger our display routine. If we enter b followed by a number, `b2`, this will select that location and move us there.