misc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.alexwennerberg.com/misc
Log | Files | Refs | README | LICENSE

finger.rs (2249B) - raw


      1 // A simple finger client written in Rust implementing rfc1288. Zero dependencies outside std. Compiles with rustc:
      2 // rustc finger.rs -o finger
      3 // Usage:
      4 // finger request@host
      5 // e.g.
      6 
      7 // finger aw@happynetbox.com
      8 
      9 // You could also just use netcat:
     10 
     11 // printf 'aw\r\n' | nc happnetbox.com 79
     12 
     13 // The finger protocol is featured heavily in Elif Batuman's Pulitizer Prize nominated novel The Idiot.
     14 // FINGER > FACEBOOK
     15 
     16 use std::io::prelude::*;
     17 use std::net::TcpStream;
     18 use std::process;
     19 use std::{env, io, str};
     20 
     21 // supports standard finger queries and URIs
     22 // From the drat spec:
     23 // https://datatracker.ietf.org/doc/html/draft-ietf-uri-url-finger-02
     24 // returns host, request
     25 fn get_params(query: &str) -> (&str, &str) {
     26     // is URI
     27     if query.starts_with("finger://") {
     28         // kinda ugly
     29         let i = query[9..].find("/").unwrap_or(query.len() - 9);
     30         return (&query[9..9 + i], &query[9 + i..].trim_matches('/'));
     31     } else {
     32         let user: &str;
     33         let host: &str;
     34         let params: Vec<&str> = query.split("@").collect();
     35         if params.len() == 1 {
     36             host = params[0];
     37             user = "";
     38         } else {
     39             user = params[0];
     40             host = params[1];
     41         }
     42         return (host, user);
     43     }
     44 }
     45 
     46 fn main() -> std::io::Result<()> {
     47     let args: Vec<String> = env::args().collect();
     48     if args.len() < 2 {
     49         println!("Usage: finger [request]@host or finger://host/request");
     50         process::exit(1);
     51     }
     52 
     53     let (host, user) = get_params(&args[1]);
     54 
     55     let dest: String;
     56     if !host.contains(":") {
     57         dest = format!("{}:79", host);
     58     } else {
     59         dest = host.to_owned();
     60     }
     61     let mut stream = TcpStream::connect(dest).expect("Couldn't connect to the server.");
     62 
     63     // Only supports queries of type Q1
     64     // https://datatracker.ietf.org/doc/html/rfc1288#section-2.3
     65     // Doesn't support long mode (/W) -- most servers online don't
     66     stream.write(user.as_bytes())?;
     67     stream.write(&[13, 10])?; // CLRF
     68     let mut line: Vec<u8> = vec![];
     69     // TODO -- filter out nonprintable
     70     stream.read_to_end(&mut line)?;
     71 
     72     // Assume UTF-8 input, against the spec, which predates UTF-8
     73     println!("{}", str::from_utf8(&line).unwrap());
     74     Ok(())
     75 }