-- Leo's gemini proxy

-- Connecting to typed-hole.org:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

commit 01494ed5996aa62acc38996cebac6172bba60dd5

Author: Julien Blanchard <julien@sideburns.eu>

Date: Sat Jan 4 16:57:23 2020 +0100


Add finger:// support


diff --git a/src/absolute_url.rs b/src/absolute_url.rs

index 36cc921..7be9e27 100644

--- a/src/absolute_url.rs

+++ b/src/absolute_url.rs

@@ -1,3 +1,4 @@

+use crate::Finger;

use crate::Gemini;

use crate::Gopher;

use crate::Protocol;

@@ -7,6 +8,12 @@ pub trait AbsoluteUrl {

fn to_absolute_url(&self) -> Result<url::Url, url::ParseError>;

}


+impl AbsoluteUrl for Finger {

+ fn to_absolute_url(&self) -> Result<url::Url, url::ParseError> {

+ Ok(self.get_source_url())

+ }

+}

+

impl AbsoluteUrl for Gemini {

fn to_absolute_url(&self) -> Result<url::Url, url::ParseError> {

let url = self.get_source_str();

diff --git a/src/finger/client.rs b/src/finger/client.rs

new file mode 100644

index 0000000..3424dce

--- /dev/null

+++ b/src/finger/client.rs

@@ -0,0 +1,32 @@

+use std::io::{Read, Write};

+use std::net::TcpStream;

+use std::net::{ToSocketAddrs};

+use std::time::Duration;

+

+use crate::Protocol;

+

+pub fn get_data<T: Protocol>(url: T) -> Result<(Option<Vec<u8>>, Vec<u8>), String> {

+ let url = url.get_source_url();

+ let host = url.host_str().unwrap().to_string();

+ let username = url.username();

+ let urlf = format!("{}:79", host);

+ let socket = match urlf.to_socket_addrs() {

+ Ok(mut iter) => iter.next(),

+ Err(_) => None,

+ };

+

+ match socket {

+ Some(socket) => match TcpStream::connect_timeout(&socket, Duration::new(5, 0)) {

+ Ok(mut stream) => {

+ let request = format!("{}\r\n", username);

+ stream.write_all(request.as_bytes()).unwrap();

+ let mut res = vec![];

+ stream.read_to_end(&mut res).unwrap();

+

+ Ok((None, res))

+ },

+ Err(e) => Err(format!("Could not connect to {}\n{}", urlf, e)),

+ },

+ None => Err(format!("Could not connect to {}\n", urlf))

+ }

+}

diff --git a/src/finger/mod.rs b/src/finger/mod.rs

new file mode 100644

index 0000000..b9babe5

--- /dev/null

+++ b/src/finger/mod.rs

@@ -0,0 +1 @@

+pub mod client;

diff --git a/src/gemini/link.rs b/src/gemini/link.rs

index 0b3ecd6..5270694 100644

--- a/src/gemini/link.rs

+++ b/src/gemini/link.rs

@@ -5,6 +5,7 @@ use url::Url;


pub enum Link {

+ Finger(Url, String),

Gemini(Url, String),

Gopher(Url, String),

Http(Url, String),

@@ -50,6 +51,7 @@ fn make_link(url: String, label: String) -> Option<Link> {

let urlp = Url::parse(&url);

match urlp {

Ok(url) => match url.scheme() {

+ "finger" => Some(Link::Finger(url, label)),

"gemini" => Some(Link::Gemini(url, label)),

"gopher" => Some(Link::Gopher(url, label)),

"http" => Some(Link::Http(url, label)),

diff --git a/src/main.rs b/src/main.rs

index ab56d35..1ecc78a 100644

--- a/src/main.rs

+++ b/src/main.rs

@@ -20,18 +20,18 @@ use absolute_url::AbsoluteUrl;

mod bookmarks;

mod client;

mod colors;

+mod finger;

mod gemini;

mod gopher;

mod history;

use gemini::link::Link as GeminiLink;

use gopher::link::Link as GopherLink;

mod protocols;

-use protocols::{Protocol, Scheme, Gopher, Gemini};

+use protocols::{Finger, Gemini, Gopher, Protocol, Scheme};

mod status;

use status::Status;

mod tags;


-

fn main() {

// Start up the GTK3 subsystem.

gtk::init().expect("Unable to start GTK3. Error");

@@ -78,8 +78,15 @@ fn main() {

visit_url(&gui_clone, Gemini { source: url })

} else if url.starts_with("gopher://") {

visit_url(&gui_clone, Gopher { source: url })

+ } else if url.starts_with("finger://") {

+ visit_url(&gui_clone, Finger { source: url })

} else {

- visit_url(&gui_clone, Gemini { source: format!("gemini://{}", url) })

+ visit_url(

+ &gui_clone,

+ Gemini {

+ source: format!("gemini://{}", url),

+ },

+ )

};

});

}

@@ -95,9 +102,25 @@ fn go_back(gui: &Arc<Gui>) {

let previous = history::get_previous_url();

if let Some(url) = previous {

match url.scheme() {

- "gemini" => visit_url(gui, Gemini { source: url.to_string() }),

- "gopher" => visit_url(gui, Gopher { source: url.to_string() }),

- _ => ()

+ "finger" => visit_url(

+ gui,

+ Finger {

+ source: url.to_string(),

+ },

+ ),

+ "gemini" => visit_url(

+ gui,

+ Gemini {

+ source: url.to_string(),

+ },

+ ),

+ "gopher" => visit_url(

+ gui,

+ Gopher {

+ source: url.to_string(),

+ },

+ ),

+ _ => (),

}

}

}

@@ -108,7 +131,8 @@ fn update_url_field(gui: &Arc<Gui>, url: &str) {

}


fn add_bookmark(gui: &Arc<Gui>) {

- let current_url = history::get_current_url();

+ let url_bar = gui.url_bar();

+ let current_url = url_bar.get_text();

if let Some(url) = current_url {

bookmarks::add(&url);

info_dialog(&gui, "Bookmark added.");

@@ -130,15 +154,15 @@ fn show_bookmarks(gui: &Arc<Gui>) {

}


fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) {

- {

- if url.get_source_str() == "gemini://::bookmarks" {

- show_bookmarks(&gui);

- return;

- }

+ if url.get_source_str() == "gemini://::bookmarks" {

+ show_bookmarks(&gui);

+ return;

+ }


- let content_view = gui.content_view();

+ let content_view = gui.content_view();


- if url.get_scheme() == Scheme::Gemini {

+ match url.get_scheme() {

+ Scheme::Gemini => {

let absolute_url = url.to_absolute_url();


match absolute_url {

@@ -194,7 +218,8 @@ fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) {

error_dialog(&gui, &format!("\n{}\n", e));

}

}

- } else {

+ }

+ Scheme::Gopher => {

let absolute_url = url.to_absolute_url();

match absolute_url {

Ok(abs_url) => match gopher::client::get_data(url) {

@@ -217,7 +242,31 @@ fn visit_url<T: AbsoluteUrl + Protocol>(gui: &Arc<Gui>, url: T) {

error_dialog(&gui, &format!("\n{}\n", e));

}

}

- };

+ }

+ Scheme::Finger => {

+ let absolute_url = url.to_absolute_url();

+ match absolute_url {

+ Ok(abs_url) => match finger::client::get_data(url) {

+ Ok((_meta, new_content)) => {

+ history::append(abs_url.as_str());

+ update_url_field(&gui, abs_url.as_str());

+ let content_str = String::from_utf8_lossy(&new_content).to_string();

+

+ let parsed_content = gopher::parser::parse(content_str);

+ clear_buffer(&content_view);

+ draw_gopher_content(&gui, parsed_content);

+

+ content_view.show_all();

+ }

+ Err(e) => {

+ error_dialog(&gui, &format!("\n{}\n", e));

+ }

+ },

+ Err(e) => {

+ error_dialog(&gui, &format!("\n{}\n", e));

+ }

+ }

+ }

}

}


@@ -269,11 +318,7 @@ fn draw_gemini_content(

}

Ok(gemini::parser::TextElement::Text(text)) => {

let mut end_iter = buffer.get_end_iter();

- buffer.insert_markup(

- &mut end_iter,

- &format!("{}\n", text),

- );

-

+ buffer.insert_markup(&mut end_iter, &format!("{}\n", text));

}

Ok(gemini::parser::TextElement::LinkItem(link_item)) => {

draw_gemini_link(&gui, link_item);

@@ -295,10 +340,7 @@ fn draw_gopher_content(

match el {

Ok(gopher::parser::TextElement::Text(text)) => {

let mut end_iter = buffer.get_end_iter();

- buffer.insert_markup(

- &mut end_iter,

- &format!("{}\n", text),

- );

+ buffer.insert_markup(&mut end_iter, &format!("{}\n", text));

}

Ok(gopher::parser::TextElement::LinkItem(link_item)) => {

draw_gopher_link(&gui, link_item);

@@ -318,15 +360,17 @@ fn draw_gopher_content(


fn draw_gemini_link(gui: &Arc<Gui>, link_item: String) {

match GeminiLink::from_str(&link_item) {

- Ok(GeminiLink::Http(url, label)) => {

+ Ok(GeminiLink::Finger(url, label)) => {

let button_label = if label.is_empty() {

url.clone().to_string()

} else {

label

};

- let www_label = format!("{} [WWW]", button_label);

-

- insert_external_button(&gui, url, &www_label);

+ let finger_label = format!("{} [Finger]", button_label);

+ insert_gemini_button(&gui, url, finger_label);

+ }

+ Ok(GeminiLink::Gemini(url, label)) => {

+ insert_gemini_button(&gui, url, label);

}

Ok(GeminiLink::Gopher(url, label)) => {

let button_label = if label.is_empty() {

@@ -337,8 +381,15 @@ fn draw_gemini_link(gui: &Arc<Gui>, link_item: String) {

let gopher_label = format!("{} [Gopher]", button_label);

insert_gemini_button(&gui, url, gopher_label);

}

- Ok(GeminiLink::Gemini(url, label)) => {

- insert_gemini_button(&gui, url, label);

+ Ok(GeminiLink::Http(url, label)) => {

+ let button_label = if label.is_empty() {

+ url.clone().to_string()

+ } else {

+ label

+ };

+ let www_label = format!("{} [WWW]", button_label);

+

+ insert_external_button(&gui, url, &www_label);

}

Ok(GeminiLink::Relative(url, label)) => {

let new_url = Gemini { source: url }.to_absolute_url().unwrap();

@@ -397,6 +448,7 @@ fn insert_gemini_button(gui: &Arc<Gui>, url: Url, label: String) {


button.connect_clicked(clone!(@weak gui => move |_| {

match url.scheme() {

+ "finger" => visit_url(&gui, Finger { source: url.to_string() }),

"gemini" => visit_url(&gui, Gemini { source: url.to_string() }),

"gopher" => visit_url(&gui, Gopher { source: url.to_string() }),

_ => ()

diff --git a/src/protocols.rs b/src/protocols.rs

index 9b2b70c..7edaa29 100644

--- a/src/protocols.rs

+++ b/src/protocols.rs

@@ -8,6 +8,21 @@ pub trait Protocol {


pub struct Gemini { pub source: String }

pub struct Gopher { pub source: String }

+pub struct Finger { pub source: String }

+

+impl Protocol for Finger {

+ fn get_source_str(&self) -> &str {

+ &self.source

+ }

+

+ fn get_source_url(&self) -> Url {

+ Url::parse(&self.source).unwrap()

+ }

+

+ fn get_scheme(&self) -> Scheme {

+ Scheme::Finger

+ }

+}


impl Protocol for Gemini {

fn get_source_str(&self) -> &str {

@@ -39,6 +54,7 @@ impl Protocol for Gopher {


pub enum Scheme {

+ Finger,

Gemini,

Gopher

}



---

Served by Pollux Gemini Server.

-- Response ended

-- Page fetched on Mon May 27 20:29:37 2024