fingers

Finger client library in Rust
Log | Files | Refs | README | LICENSE

commit 60233de55abdb240e2ee0ef3e75d6acf3af79cfe
parent d3b74223f0809dcc507d778b943813194cc53d7b
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Wed,  1 Dec 2021 21:37:02 -0800

First attempt

Diffstat:
ACargo.lock | 7+++++++
MCargo.toml | 4++--
ALICENSE | 10++++++++++
MREADME | 7++++++-
Asrc/lib.rs | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.rs | 6++++--
6 files changed, 118 insertions(+), 5 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "fingers" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml @@ -2,7 +2,7 @@ name = "fingers" version = "0.1.0" edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +license = "0BSD" +description = "a finger client library" [dependencies] diff --git a/LICENSE b/LICENSE @@ -0,0 +1,10 @@ +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/README b/README @@ -1,5 +1,10 @@ finge.rs +======== -finger client/server library +finger client library + +0 dependencies outside stdlib WIP + +JOIN THE FINGER REVIVAL! diff --git a/src/lib.rs b/src/lib.rs @@ -0,0 +1,89 @@ +use std::io::prelude::*; +use std::net::{TcpStream, ToSocketAddrs}; +use std::str; +/// A finger client library +/// See https://datatracker.ietf.org/doc/html/rfc1288 +/// Be mature. +/// +/// Inspired by Elif Batuman's "The Idiot" +/// From the draft spec: +/// https://datatracker.ietf.org/doc/html/draft-ietf-uri-url-finger-02 +/// Returns username, host +use std::time::Duration; + +#[derive(Debug)] +pub enum Error { + InvalidFingerURL, + HostError, + IoError(std::io::Error), + Utf8Error(str::Utf8Error), +} + +impl From<str::Utf8Error> for Error { + fn from(err: str::Utf8Error) -> Error { + Error::Utf8Error(err) + } +} + +impl From<std::io::Error> for Error { + fn from(err: std::io::Error) -> Error { + Error::IoError(err) + } +} + +pub struct Request { + query: String, + host: String, + // TODO + // timeout: Option<u64>, // seconds + // max_response_len: Option<u64>, +} + +/// https://datatracker.ietf.org/doc/html/draft-ietf-uri-url-finger-02 +pub fn from_url(url: &str) -> Result<Request, Error> { + if url.starts_with("finger://") { + let i = url[9..].find("/").unwrap_or(url.len() - 9); + let host = &url[9..9 + i]; + let query = &url[9 + i..].trim_matches('/'); + return Ok(finger(query, host)); + } + return Err(Error::InvalidFingerURL); +} + +// TODO better host resolving +/// rfc1288 2.2 is ignored, queries are UTF-8 strings +/// Uses sensible defaults for timeout and response len +/// Host can include port. Defaults to 79 if not included +pub fn finger(query: &str, host: &str) -> Request { + let mut q = String::new(); + q.push_str(query); + if !q.ends_with("\r\n") { + q.push_str("\r\n") + } + + Request { + query: q.to_owned(), + host: host.to_owned(), + // timeout: Some(3), + // max_response_len: Some(1024 * 10), // 10KB + } +} +impl Request { + /// rfc1288 2.2 is ignored, we will allow UTF-8 + pub fn send(self) -> Result<String, Error> { + let dest: String; + if !self.host.contains(":") { + dest = format!("{}:79", self.host); + } else { + dest = self.host; + } + let server = dest.to_socket_addrs()?.next().ok_or(Error::HostError)?; + let mut stream = TcpStream::connect(&server)?; + + stream.write(self.query.as_bytes())?; + let mut line: Vec<u8> = vec![]; + stream.read_to_end(&mut line)?; + + return Ok(str::from_utf8(&line)?.to_owned()); + } +} diff --git a/src/main.rs b/src/main.rs @@ -1,3 +1,5 @@ -fn main() { - println!("Hello, world!"); +fn main() -> Result<(), fingers::Error> { + let result = fingers::finger("alex\r\n", "flounder.online").send()?; + println!("{}", result); + Ok(()) }