~exprez135/castor

6e8f2e8f1eaf241289c3aa27065c42c74148ec68 — Julien Blanchard 1 year, 5 months ago c3950b7
Clippy + fmt pass
M src/absolute_url.rs => src/absolute_url.rs +38 -8
@@ 79,7 79,10 @@ fn test_make_absolute_slash_path_no_current_host() {
    crate::history::clear();

    let url = "/foo";
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url();
    assert_eq!(absolute_url, Err(url::ParseError::RelativeUrlWithoutBase));
}
#[test]


@@ 87,7 90,10 @@ fn test_make_absolute_just_path_no_current_host() {
    crate::history::clear();

    let url = "foo";
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url();
    assert_eq!(absolute_url, Err(url::ParseError::RelativeUrlWithoutBase));
}
#[test]


@@ 97,7 103,11 @@ fn test_make_absolute_full_url() {
    crate::history::append("gemini://typed-hole.org");
    let url = "gemini://typed-hole.org/foo";
    let expected_url = Url::parse("gemini://typed-hole.org/foo").unwrap();
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url().unwrap();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url()
    .unwrap();
    assert_eq!(expected_url, absolute_url);
}
#[test]


@@ 107,7 117,11 @@ fn test_make_absolute_full_url_no_protocol() {
    crate::history::append("gemini://typed-hole.org");
    let url = "//typed-hole.org/foo";
    let expected_url = Url::parse("gemini://typed-hole.org/foo").unwrap();
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url().unwrap();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url()
    .unwrap();
    assert_eq!(expected_url, absolute_url);
}
#[test]


@@ 117,7 131,11 @@ fn test_make_absolute_slash_path() {
    crate::history::append("gemini://typed-hole.org");
    let url = "/foo";
    let expected_url = Url::parse("gemini://typed-hole.org/foo").unwrap();
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url().unwrap();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url()
    .unwrap();
    assert_eq!(expected_url, absolute_url);
}
#[test]


@@ 127,7 145,11 @@ fn test_make_absolute_just_path() {
    crate::history::append("gemini://typed-hole.org");
    let url = "foo";
    let expected_url = Url::parse("gemini://typed-hole.org/foo").unwrap();
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url().unwrap();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url()
    .unwrap();
    assert_eq!(expected_url, absolute_url);
}
#[test]


@@ 136,7 158,11 @@ fn test_make_absolute_full_url_no_current_host() {

    let url = "gemini://typed-hole.org/foo";
    let expected_url = Url::parse("gemini://typed-hole.org/foo").unwrap();
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url().unwrap();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url()
    .unwrap();
    assert_eq!(expected_url, absolute_url);
}
#[test]


@@ 145,6 171,10 @@ fn test_make_absolute_full_url_no_protocol_no_current_host() {

    let url = "//typed-hole.org/foo";
    let expected_url = Url::parse("gemini://typed-hole.org/foo").unwrap();
    let absolute_url = Gemini { source: String::from(url) }.to_absolute_url().unwrap();
    let absolute_url = Gemini {
        source: String::from(url),
    }
    .to_absolute_url()
    .unwrap();
    assert_eq!(expected_url, absolute_url);
}

M src/bookmarks.rs => src/bookmarks.rs +0 -1
@@ 5,7 5,6 @@ use std::fs::File;
use std::fs::OpenOptions;
use std::io::{Read, Write};


pub fn add(url: &str) {
    let mut file = bookmarks_file();
    let entry = format!("=> {}\n", url);

M src/client.rs => src/client.rs +1 -2
@@ 1,7 1,6 @@
use std::io::{Write};
use std::io::Write;
use tempfile::NamedTempFile;


pub trait Client {
    fn get_data(&self) -> Result<(Option<Vec<u8>>, Vec<u8>), String>;
}

M src/colors.rs => src/colors.rs +4 -1
@@ 24,7 24,10 @@ pub mod colors {
                        s.push_str("");
                    } else {
                        let color = colors.last().unwrap();
                        s.push_str(&format!("<span foreground={:?}>", ansi_color_to_hex(*color)))
                        s.push_str(&format!(
                            "<span foreground={:?}>",
                            ansi_color_to_hex(*color)
                        ))
                    }
                }
                Output::TextBlock(text) => {

M src/dialog.rs => src/dialog.rs +1 -1
@@ 1,6 1,6 @@
use gtk::prelude::*;
use std::sync::Arc;
use gtk::ResponseType;
use std::sync::Arc;

use url::{Position, Url};


M src/draw.rs => src/draw.rs +21 -25
@@ 1,6 1,6 @@
use glib::clone;
use gtk::TextBuffer;
use gtk::prelude::*;
use gtk::TextBuffer;
use std::str::FromStr;
use std::sync::Arc;
use url::Url;


@@ 11,7 11,6 @@ use crate::gopher::link::Link as GopherLink;
use crate::gui::Gui;
use crate::protocols::{Finger, Gemini, Gopher};


pub fn gemini_content(
    gui: &Arc<Gui>,
    content: Vec<Result<crate::gemini::parser::TextElement, crate::gemini::parser::ParseError>>,


@@ 85,28 84,25 @@ pub fn gemini_content(
            }
            Ok(crate::gemini::parser::TextElement::Text(text)) => {
                let mut end_iter = buffer.get_end_iter();
                match mono_toggle {
                    true => {
                        buffer.insert_markup(
                            &mut end_iter,
                            &format!(
                                "<span foreground=\"{}\" font_family=\"monospace\">{}</span>\n",
                                crate::settings::text_color(),
                                text
                            ),
                        );
                    }
                    false => {
                        buffer.insert_markup(
                            &mut end_iter,
                            &format!(
                                "<span foreground=\"{}\" font_family=\"{}\">{}</span>\n",
                                crate::settings::text_color(),
                                font_family,
                                text
                            ),
                        );
                    }
                if mono_toggle {
                    buffer.insert_markup(
                        &mut end_iter,
                        &format!(
                            "<span foreground=\"{}\" font_family=\"monospace\">{}</span>\n",
                            crate::settings::text_color(),
                            text
                        ),
                    );
                } else {
                    buffer.insert_markup(
                        &mut end_iter,
                        &format!(
                            "<span foreground=\"{}\" font_family=\"{}\">{}</span>\n",
                            crate::settings::text_color(),
                            font_family,
                            text
                        ),
                    );
                }
            }
            Ok(crate::gemini::parser::TextElement::LinkItem(link_item)) => {


@@ 137,7 133,7 @@ pub fn gemini_text_content(
                        text
                    ),
                );
            },
            }
            Ok(_) => (),
            Err(_) => println!("Something failed."),
        }

M src/finger/client.rs => src/finger/client.rs +1 -1
@@ 19,7 19,7 @@ pub fn get_data<T: Protocol>(url: T) -> Result<(Option<Vec<u8>>, Vec<u8>), Strin
        Some(socket) => match TcpStream::connect_timeout(&socket, Duration::new(5, 0)) {
            Ok(mut stream) => thread::spawn(move || {
                let username = if url.username() == "" {
                    url.path().replace("/","")
                    url.path().replace("/", "")
                } else {
                    String::from(url.username())
                };

M src/gemini/certificate.rs => src/gemini/certificate.rs +6 -4
@@ 1,6 1,6 @@
extern crate dirs;
use std::fs;
use openssl::pkcs12::Pkcs12;
use std::fs;

pub fn get_certificate(host: &str) -> Option<Pkcs12> {
    let mut key_path = dirs::home_dir().unwrap();


@@ 13,18 13,20 @@ pub fn get_certificate(host: &str) -> Option<Pkcs12> {

    let key = match fs::read(key_path.to_str().unwrap()) {
        Ok(file) => file,
        Err(_) => return None
        Err(_) => return None,
    };

    let cert = match fs::read(cert_path.to_str().unwrap()) {
        Ok(file) => file,
        Err(_) => return None
        Err(_) => return None,
    };

    let rsa_key = openssl::rsa::Rsa::private_key_from_pem(&key).expect("Invalid RSA key");
    let pkey = openssl::pkey::PKey::from_rsa(rsa_key).expect("Invalid PKey");
    let cert = openssl::x509::X509::from_pem(&cert).expect("Invalid certificate");

    let pkcs_cert = Pkcs12::builder().build("", "", &pkey, &cert).expect("Can't build PKCS12");
    let pkcs_cert = Pkcs12::builder()
        .build("", "", &pkey, &cert)
        .expect("Can't build PKCS12");
    Some(pkcs_cert)
}

M src/gemini/client.rs => src/gemini/client.rs +4 -7
@@ 15,13 15,10 @@ pub fn get_data<T: Protocol>(url: T) -> Result<(Option<Vec<u8>>, Vec<u8>), Strin
    builder.danger_accept_invalid_hostnames(true);
    builder.danger_accept_invalid_certs(true);

    match crate::gemini::certificate::get_certificate(host) {
        Some(cert) => {
            let der = cert.to_der().unwrap();
            let identity = native_tls::Identity::from_pkcs12(&der, "").unwrap();
            builder.identity(identity);
        }
        None => (),
    if let Some(cert) = crate::gemini::certificate::get_certificate(host) {
        let der = cert.to_der().unwrap();
        let identity = native_tls::Identity::from_pkcs12(&der, "").unwrap();
        builder.identity(identity);
    };

    let connector = builder.build().unwrap();

M src/gopher/client.rs => src/gopher/client.rs +1 -1
@@ 1,8 1,8 @@
use percent_encoding::percent_decode;
use std::thread;
use std::io::{Read, Write};
use std::net::TcpStream;
use std::net::ToSocketAddrs;
use std::thread;
use std::time::Duration;

use crate::Protocol;

M src/gopher/link.rs => src/gopher/link.rs +14 -8
@@ 34,7 34,10 @@ impl FromStr for Link {

                    if let Some(port) = port {
                        if path != "" {
                            match Url::parse(&format!("gopher://{}:{}/{}{}", host, port, selector, path)) {
                            match Url::parse(&format!(
                                "gopher://{}:{}/{}{}",
                                host, port, selector, path
                            )) {
                                Ok(url) => Ok(Link::Gopher(url, text)),
                                Err(e) => {
                                    println!("ERR {:?}", e);


@@ 77,13 80,16 @@ impl FromStr for Link {
                    };

                    if let Some(port) = port {
                      match Url::parse(&format!("gopher://{}:{}/{}{}", host, port, selector, path)) {
                          Ok(url) => Ok(Link::Image(url, text)),
                          Err(e) => {
                              println!("ERR {:?}", e);
                              Err(ParseError)
                          }
                      }
                        match Url::parse(&format!(
                            "gopher://{}:{}/{}{}",
                            host, port, selector, path
                        )) {
                            Ok(url) => Ok(Link::Image(url, text)),
                            Err(e) => {
                                println!("ERR {:?}", e);
                                Err(ParseError)
                            }
                        }
                    } else {
                        Err(ParseError)
                    }

M src/gui.rs => src/gui.rs +22 -6
@@ 3,7 3,6 @@ use gtk::{ApplicationWindow, Button, Entry, TextView};

use gdk::WindowExt;


pub struct Gui {
    window: ApplicationWindow,
    url_bar: Entry,


@@ 13,6 12,12 @@ pub struct Gui {
    show_bookmarks_button: Button,
}

impl Default for Gui {
    fn default() -> Self {
        Self::new()
    }
}

impl Gui {
    pub fn new() -> Gui {
        // Initialize the UI from the Glade XML.


@@ 22,10 27,18 @@ impl Gui {
        // Get handles for the various controls we need to use.
        let window: ApplicationWindow = builder.get_object("window").expect("Couldn't get window");
        let url_bar: Entry = builder.get_object("url_bar").expect("Couldn't get url_bar");
        let content_view: TextView = builder.get_object("content_view").expect("Couldn't get content_view");
        let back_button: Button = builder.get_object("back_button").expect("Couldn't get back_button");
        let add_bookmark_button: Button = builder.get_object("add_bookmark_button").expect("Couldn't get add_bookmark_button");
        let show_bookmarks_button: Button = builder.get_object("show_bookmarks_button").expect("Couldn't get show_bookmarks_button");
        let content_view: TextView = builder
            .get_object("content_view")
            .expect("Couldn't get content_view");
        let back_button: Button = builder
            .get_object("back_button")
            .expect("Couldn't get back_button");
        let add_bookmark_button: Button = builder
            .get_object("add_bookmark_button")
            .expect("Couldn't get add_bookmark_button");
        let show_bookmarks_button: Button = builder
            .get_object("show_bookmarks_button")
            .expect("Couldn't get show_bookmarks_button");

        Gui {
            window,


@@ 40,7 53,10 @@ impl Gui {
    pub fn start(&self) {
        glib::set_application_name("Castor Browser");
        self.window.set_role("Castor Browser");
        self.window.connect_delete_event(|_, _| { gtk::main_quit(); Inhibit(false) });
        self.window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });
        self.content_view.connect_motion_notify_event(|win, _| {
            let w = gtk::TextViewExt::get_window(win, gtk::TextWindowType::Text).unwrap();
            w.set_cursor(gdk::Cursor::new_from_name(&w.get_display(), "default").as_ref());

M src/history.rs => src/history.rs +1 -1
@@ 31,7 31,7 @@ pub fn get_current_url() -> Option<String> {
                Err(_) => None,
            }
        }
        None => None
        None => None,
    }
}


M src/main.rs => src/main.rs +14 -14
@@ 1,10 1,11 @@
extern crate gdk;
extern crate gio;
extern crate glib;
extern crate gtk;
extern crate gdk;
#[macro_use]
extern crate lazy_static;

use std::env;
use std::str::FromStr;
use std::sync::Arc;



@@ 36,19 37,18 @@ fn main() {
    // Create the main window.
    let gui = Arc::new(Gui::new());

    // Set background color+
    match settings::background_color() {
        Some(color) => {
            let provider = gtk::CssProvider::new();
            provider.load_from_data(format!("textview text {{ background-color: {}; }}", color).as_bytes()).expect("Failed to load CSS");

            gtk::StyleContext::add_provider_for_screen(
                &gdk::Screen::get_default().expect("Error initializing gtk css provider."),
                &provider,
                gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
            );
        }
        None => (),
    // Set background color
    if let Some(color) = settings::background_color() {
        let provider = gtk::CssProvider::new();
        provider
            .load_from_data(format!("textview text {{ background-color: {}; }}", color).as_bytes())
            .expect("Failed to load CSS");

        gtk::StyleContext::add_provider_for_screen(
            &gdk::Screen::get_default().expect("Error initializing gtk css provider."),
            &provider,
            gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
        );
    }

    // Bind back button

M src/protocols.rs => src/protocols.rs +10 -4
@@ 6,9 6,15 @@ pub trait Protocol {
    fn get_scheme(&self) -> Scheme;
}

pub struct Gemini { pub source: String }
pub struct Gopher { pub source: String }
pub struct Finger { pub source: String }
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 {


@@ 56,5 62,5 @@ impl Protocol for Gopher {
pub enum Scheme {
    Finger,
    Gemini,
    Gopher
    Gopher,
}

M src/settings.rs => src/settings.rs +35 -35
@@ 48,7 48,7 @@ struct Monospace {
pub fn start_url() -> Option<String> {
    match read().general {
        Some(general) => general.start_url,
        None => None
        None => None,
    }
}



@@ 56,9 56,9 @@ pub fn h1_color() -> String {
    match read().colors {
        Some(colors) => match colors.h1 {
            Some(color) => color,
            None => String::from("#9932CC")
            None => String::from("#9932CC"),
        },
        None => String::from("#9932CC")
        None => String::from("#9932CC"),
    }
}



@@ 66,9 66,9 @@ pub fn h2_color() -> String {
    match read().colors {
        Some(colors) => match colors.h2 {
            Some(color) => color,
            None => String::from("#FF1493")
            None => String::from("#FF1493"),
        },
        None => String::from("#FF1493")
        None => String::from("#FF1493"),
    }
}



@@ 76,9 76,9 @@ pub fn h3_color() -> String {
    match read().colors {
        Some(colors) => match colors.h3 {
            Some(color) => color,
            None => String::from("#87CEFA")
            None => String::from("#87CEFA"),
        },
        None => String::from("#87CEFA")
        None => String::from("#87CEFA"),
    }
}



@@ 86,9 86,9 @@ pub fn list_color() -> String {
    match read().colors {
        Some(colors) => match colors.list {
            Some(color) => color,
            None => String::from("green")
        }
        None => String::from("green")
            None => String::from("green"),
        },
        None => String::from("green"),
    }
}



@@ 96,16 96,16 @@ pub fn text_color() -> String {
    match read().colors {
        Some(colors) => match colors.text {
            Some(color) => color,
            None => String::from("black")
        }
        None => String::from("black")
            None => String::from("black"),
        },
        None => String::from("black"),
    }
}

pub fn background_color() -> Option<String> {
    match read().colors {
        Some(colors) => colors.background,
        None => None
        None => None,
    }
}



@@ 113,9 113,9 @@ pub fn h1_character() -> String {
    match read().characters {
        Some(characters) => match characters.h1 {
            Some(character) => character,
            None => String::new()
        }
        None => String::new()
            None => String::new(),
        },
        None => String::new(),
    }
}



@@ 123,9 123,9 @@ pub fn h2_character() -> String {
    match read().characters {
        Some(characters) => match characters.h2 {
            Some(character) => character,
            None => String::new()
        }
        None => String::new()
            None => String::new(),
        },
        None => String::new(),
    }
}



@@ 133,9 133,9 @@ pub fn h3_character() -> String {
    match read().characters {
        Some(characters) => match characters.h3 {
            Some(character) => character,
            None => String::new()
        }
        None => String::new()
            None => String::new(),
        },
        None => String::new(),
    }
}



@@ 143,9 143,9 @@ pub fn list_character() -> String {
    match read().characters {
        Some(characters) => match characters.list {
            Some(character) => character,
            None => String::from("■")
        }
        None => String::from("■")
            None => String::from("■"),
        },
        None => String::from("■"),
    }
}



@@ 153,9 153,9 @@ pub fn finger_monospace() -> bool {
    match read().monospace {
        Some(monospace) => match monospace.finger {
            Some(setting) => setting,
            None => true
        }
        None => true
            None => true,
        },
        None => true,
    }
}



@@ 163,9 163,9 @@ pub fn gemini_monospace() -> bool {
    match read().monospace {
        Some(monospace) => match monospace.gemini {
            Some(setting) => setting,
            None => true
        }
        None => true
            None => true,
        },
        None => true,
    }
}



@@ 173,9 173,9 @@ pub fn gopher_monospace() -> bool {
    match read().monospace {
        Some(monospace) => match monospace.gopher {
            Some(setting) => setting,
            None => true
        }
        None => true
            None => true,
        },
        None => true,
    }
}