diff --git a/Cargo.lock b/Cargo.lock index 003063d..2782d06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,22 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -12,10 +29,122 @@ version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "rgp" version = "0.1.0" dependencies = [ "lazy_static", "libc", + "simple_input", + "tempfile", +] + +[[package]] +name = "simple_input" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa41a909f42f472032b66a7de24725c5999edefe69f6fa21b1746ba840bb981b" + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 0ead06e..faf0a48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,5 @@ edition = "2018" [dependencies] libc = "*" lazy_static = "1.4.0" +simple_input = "0.4.0" +tempfile = "3.1.0" diff --git a/src/main.rs b/src/main.rs index 04d5bd3..d078a67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,15 +11,23 @@ #![feature(const_raw_ptr_to_usize_cast, extern_types, main, register_tool)] extern crate libc; +extern crate tempfile; +extern crate simple_input; #[macro_use] extern crate lazy_static; use std::env; +use std::path::Path; use std::process::exit; use std::thread::sleep; use std::time::Duration; use std::ffi::{CStr, CString}; +use std::fs::{self, File}; use std::mem; use std::ptr; +use std::io::{Write}; + +use simple_input::input; +use tempfile::NamedTempFile; extern "C" { pub type _IO_wide_data; @@ -210,16 +218,16 @@ pub type _IO_lock_t = (); pub type FILE = _IO_FILE; /* structs */ -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Link { pub next: Option>, pub which: Option, - pub key: libc::c_short, + pub key: usize, pub host: String, - pub port: *mut libc::c_char, - pub selector: *mut libc::c_char, + pub port: usize, + pub selector: String, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Config { pub start_uri: String, pub cmd_text: String, @@ -231,17 +239,17 @@ pub struct Config { pub verbose: String, } -pub static mut tmpfilename: [libc::c_char; 256] = [0; 256]; +pub static mut tmpfilename: String = String::new(); pub static mut links: Option> = None; pub static mut history: Option> = None; -pub static mut link_key: libc::c_int = 0; +pub static mut link_key: usize = 0; pub static mut current_host: [libc::c_char; 512] = [0; 512]; -pub static mut current_port: [libc::c_char; 64] = [0; 64]; -pub static mut current_selector: [libc::c_char; 1024] = [0; 1024]; -pub static mut parsed_host: [libc::c_char; 512] = [0; 512]; -pub static mut parsed_port: [libc::c_char; 64] = [0; 64]; -pub static mut parsed_selector: [libc::c_char; 1024] = [0; 1024]; -pub static mut bookmarks: [[libc::c_char; 512]; 20] = [[0; 512]; 20]; +pub static mut current_port: usize = 0; +pub static mut current_selector: String = String::new(); +pub static mut parsed_host: String = String::new(); +pub static mut parsed_port: usize = 0; +pub static mut parsed_selector: String = String::new(); +pub static mut bookmarks: [[u8; 512]; 20] = [[0; 512]; 20]; lazy_static! { pub static ref config: Config = Config { @@ -359,9 +367,7 @@ pub unsafe extern "C" fn parse_config_line(mut line: *const libc::c_char) { j + 1 as libc::c_int, ); if strcmp(token.as_mut_ptr(), bkey.as_mut_ptr()) == 0 { - value = &mut *(*bookmarks.as_mut_ptr().offset(j as isize)) - .as_mut_ptr() - .offset(0 as libc::c_int as isize) as *mut libc::c_char; + value = CString::new(bookmarks[j as usize]).unwrap().into_raw(); break; } else { j += 1 @@ -453,8 +459,7 @@ pub unsafe extern "C" fn init_config() { /* copy defaults */ i = 0 as libc::c_int; while i < 20 as libc::c_int { - bookmarks[i as usize][0 as libc::c_int as usize] = - 0 as libc::c_int as libc::c_char; + bookmarks[i as usize][0 as libc::c_int as usize] = 0; i += 1 } /* read configs */ @@ -473,8 +478,8 @@ pub unsafe extern "C" fn init_config() { } pub unsafe extern "C" fn dial( mut host: &str, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, + mut port: usize, + mut selector: &str, ) -> libc::c_int { let mut hints: addrinfo = addrinfo { ai_flags: 0, @@ -498,11 +503,11 @@ pub unsafe extern "C" fn dial( ); hints.ai_family = 0 as libc::c_int; hints.ai_socktype = SOCK_STREAM as libc::c_int; - if getaddrinfo(CString::new(host).unwrap().into_raw(), port, &mut hints, &mut res) != 0 as libc::c_int { + if getaddrinfo(CString::new(host).unwrap().into_raw(), CString::new(port.to_string()).unwrap().into_raw(), &mut hints, &mut res) != 0 as libc::c_int { eprintln!( "error: cannot resolve hostname '{}:{}': {}", host, - CStr::from_ptr(port).to_str().unwrap(), + port, CStr::from_ptr(strerror(*__errno_location())).to_str().unwrap() ); return -(1 as libc::c_int); @@ -578,183 +583,160 @@ pub unsafe extern "C" fn read_line( '\u{0}' as i32 as libc::c_char; return 1 as libc::c_int; } -pub unsafe extern "C" fn download_file( +pub unsafe fn download_file( mut host: &str, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, - mut fd: libc::c_int, -) -> libc::c_int { + mut port: usize, + mut selector: &str, + mut file: &mut File, +) -> bool { let mut srvfd: libc::c_int = 0; - let mut len: libc::c_int = 0; - let mut total: libc::c_ulong = 0 as libc::c_int as libc::c_ulong; - let mut buffer: [libc::c_char; 4096] = [0; 4096]; + let mut len: usize = 0; + let mut total: usize = 0; + let mut buffer: [u8; 4096] = [0; 4096]; if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { - printf( - b"downloading [%s]...\r\x00" as *const u8 as *const libc::c_char, - selector, - ); + println!("downloading [{}]...", selector); } srvfd = dial(&host, port, selector); if srvfd == -(1 as libc::c_int) { - printf( - b"\x1b[2Kerror: downloading [%s] failed\n\x00" as *const u8 - as *const libc::c_char, - selector, - ); - close(fd); - return 0 as libc::c_int; + println!("error: downloading [{}] failed", selector); + return false; } loop { len = read( srvfd, buffer.as_mut_ptr() as *mut libc::c_void, mem::size_of::<[libc::c_char; 4096]>() as libc::c_ulong, - ) as libc::c_int; - if !(len > 0 as libc::c_int) { + ) as usize; + if !(len > 0) { break; } - write(fd, buffer.as_mut_ptr() as *const libc::c_void, len as size_t); - total = total.wrapping_add(len as libc::c_ulong); + file.write(&buffer[..len]); + total += len; if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { - printf( - b"downloading [%s] (%ld kb)...\r\x00" as *const u8 as *const libc::c_char, - selector, - total.wrapping_div(1024 as libc::c_int as libc::c_ulong), - ); + println!("downloading [{}] ({} kb)...", selector, total / 1024); } } - close(fd); close(srvfd); if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { - printf( - b"\x1b[2Kdownloading [%s] complete\n\x00" as *const u8 as *const libc::c_char, - selector, - ); + println!("downloading [{}] complete", selector); } - return 1 as libc::c_int; + true } pub unsafe extern "C" fn download_temp( mut host: &str, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, -) -> libc::c_int { - let mut tmpfd: libc::c_int = 0; - strcpy( - tmpfilename.as_mut_ptr(), - b"/tmp/cgoXXXXXX\x00" as *const u8 as *const libc::c_char, - ); - tmpfd = mkstemp(tmpfilename.as_mut_ptr()); - if tmpfd == -(1 as libc::c_int) { - fputs( - b"error: unable to create tmp file\n\x00" as *const u8 as *const libc::c_char, - stderr, - ); - return 0 as libc::c_int; - } - if download_file(host, port, selector, tmpfd) == 0 { - unlink(tmpfilename.as_mut_ptr()); - return 0 as libc::c_int; + mut port: usize, + mut selector: &str, +) -> bool { + let mut tmpfile = match NamedTempFile::new() { + Ok(f) => f, + Err(_) => { + eprintln!("error: unable to create tmp file"); + return false + } + }; + tmpfilename = tmpfile.path().display().to_string(); + if !download_file(host, port, selector, tmpfile.as_file_mut()) { + fs::remove_file(&tmpfilename); + return false; } - return 1 as libc::c_int; + return true; } pub unsafe extern "C" fn make_key( - mut c1: libc::c_char, - mut c2: libc::c_char, - mut c3: libc::c_char, -) -> libc::c_int { - if c1 == 0 || c2 == 0 { - return -(1 as libc::c_int); + mut c1: char, + mut c2: char, + mut c3: char, +) -> Option { + if c1 == '\0' || c2 == '\0' { + return None; } - if c3 == 0 { - return (c1 as libc::c_int - 'a' as i32) - * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) - + (c2 as libc::c_int - 'a' as i32); + if c3 == '\0' { + Some( + (c1 as u8 - 'a' as u8) as usize + * ('z' as usize - 'a' as usize + 1) + + (c2 as u8 - 'a' as u8) as usize + ) } else { - return (c1 as libc::c_int - 'a' as i32 + 1 as libc::c_int) - * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) - * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) - + (c2 as libc::c_int - 'a' as i32) - * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) - + (c3 as libc::c_int - 'a' as i32); - }; + Some( + ((c1 as u8 - 'a' as u8) as usize + 1) + * ('z' as usize - 'a' as usize + 1) + * ('z' as usize - 'a' as usize + 1) + + ((c2 as u8 - 'a' as u8) as usize) + * ('z' as usize - 'a' as usize + 1) + + ((c3 as u8 - 'a' as u8) as usize) + ) + } } pub unsafe extern "C" fn make_key_str( - mut key: libc::c_int, - mut c1: *mut libc::c_char, - mut c2: *mut libc::c_char, - mut c3: *mut libc::c_char, + mut key: usize, + mut c1: &mut char, + mut c2: &mut char, + mut c3: &mut char, ) { if key - < ('z' as i32 - 'a' as i32 + 1 as libc::c_int) - * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + < ('z' as usize - 'a' as usize + 1 as usize) + * ('z' as usize - 'a' as usize + 1 as usize) { - *c1 = ('a' as i32 + key / ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) - as libc::c_char; - *c2 = ('a' as i32 + key % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) - as libc::c_char; - *c3 = 0 as libc::c_int as libc::c_char + *c1 = ('a' as usize + key / ('z' as usize - 'a' as usize + 1 as usize)) + as u8 as char; + *c2 = ('a' as usize + key % ('z' as usize - 'a' as usize + 1 as usize)) + as u8 as char; + *c3 = 0 as usize as u8 as char } else { - *c1 = ('a' as i32 + *c1 = ('a' as usize + key - / (('z' as i32 - 'a' as i32 + 1 as libc::c_int) - * ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) - - 1 as libc::c_int) as libc::c_char; - *c2 = ('a' as i32 - + key / ('z' as i32 - 'a' as i32 + 1 as libc::c_int) - % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) as libc::c_char; - *c3 = ('a' as i32 + key % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) - as libc::c_char + / (('z' as usize - 'a' as usize + 1 as usize) + * ('z' as usize - 'a' as usize + 1 as usize)) + - 1 as usize) as u8 as char; + *c2 = ('a' as usize + + key / ('z' as usize - 'a' as usize + 1 as usize) + % ('z' as usize - 'a' as usize + 1 as usize)) as u8 as char; + *c3 = ('a' as usize + key % ('z' as usize - 'a' as usize + 1 as usize)) + as u8 as char }; } pub unsafe fn add_link( mut which: libc::c_char, - mut name: *const libc::c_char, + mut name: String, mut host: String, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, + mut port: usize, + mut selector: String, ) { - let mut a: libc::c_char = 0 as libc::c_int as libc::c_char; - let mut b: libc::c_char = 0 as libc::c_int as libc::c_char; - let mut c: libc::c_char = 0 as libc::c_int as libc::c_char; - if host.is_empty() || port.is_null() || selector.is_null() { + let mut a: char = '\0'; + let mut b: char = '\0'; + let mut c: char = '\0'; + if host.is_empty() || port == 0 || selector.is_empty() { return; } let mut link = Link { which: Some(which as u8 as char), - key: link_key as libc::c_short, + key: link_key, host: host, - port: strdup(port), - selector: strdup(selector), + port: port, + selector: selector, next: if links.is_none() { None } else { links.clone() } }; + println!("links: {:?}", links); links = Some(Box::new(link)); + println!("links post: {:?}", links); let fresh4 = link_key; link_key = link_key + 1; make_key_str(fresh4, &mut a, &mut b, &mut c); - printf( - b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s\x1b[0m\n\x00" as *const u8 - as *const libc::c_char, - CString::new(config.color_selector.clone()).unwrap().into_raw(), - a as libc::c_int, - b as libc::c_int, - c as libc::c_int, - name, - ); + println!("{}{}{} {}", a, b, c, name); } pub unsafe extern "C" fn clear_links() { links = None; - link_key = 0 as libc::c_int; + link_key = 0; } pub unsafe extern "C" fn add_history() { let mut link: Link = Link { which: None, - key: 0 as libc::c_int as libc::c_short, + key: 0, host: CString::new(current_host.iter().take_while(|x| **x != 0).map(|x| *x as u8).collect::>()).unwrap().into_string().unwrap(), - port: strdup(current_port.as_mut_ptr()), - selector: strdup(current_selector.as_mut_ptr()), + port: current_port, + selector: current_selector.clone(), next: if history.is_none() { None } else { @@ -765,16 +747,12 @@ pub unsafe extern "C" fn add_history() { } pub unsafe extern "C" fn handle_directory_line(mut line: *mut libc::c_char) { let mut i: libc::c_int = 0; - let mut lp: *mut libc::c_char = 0 as *mut libc::c_char; - let mut last: *mut libc::c_char = 0 as *mut libc::c_char; - let mut fields: [*mut libc::c_char; 4] = [0 as *mut libc::c_char; 4]; + let mut lp: *mut u8 = 0 as *mut u8; + let mut last: *mut u8 = 0 as *mut u8; + let mut fields: [*mut u8; 4] = [0 as *mut u8; 4]; /* tokenize */ i = 0 as libc::c_int; - while i < 4 as libc::c_int { - fields[i as usize] = 0 as *mut libc::c_char; - i += 1 - } - last = &mut *line.offset(1 as libc::c_int as isize) as *mut libc::c_char; + last = &mut *line.offset(1 as libc::c_int as isize) as *mut i8 as *mut u8; lp = last; i = 0 as libc::c_int; while i < 4 as libc::c_int { @@ -784,7 +762,7 @@ pub unsafe extern "C" fn handle_directory_line(mut line: *mut libc::c_char) { if *lp as libc::c_int == '\u{0}' as i32 { break; } - *lp = '\u{0}' as i32 as libc::c_char; + *lp = '\0' as u8; i += 1 } lp = lp.offset(1) @@ -794,7 +772,7 @@ pub unsafe extern "C" fn handle_directory_line(mut line: *mut libc::c_char) { 105 | 51 => { printf( b" %s\n\x00" as *const u8 as *const libc::c_char, - fields[0 as libc::c_int as usize], + fields[0], ); } 46 => { @@ -804,17 +782,17 @@ pub unsafe extern "C" fn handle_directory_line(mut line: *mut libc::c_char) { 48 | 49 | 53 | 55 | 56 | 57 | 103 | 73 | 112 | 104 | 115 => { add_link( *line.offset(0 as libc::c_int as isize), - fields[0], - CString::from_raw(fields[2]).into_string().unwrap(), - fields[3], - fields[1], + CString::from_raw(fields[0] as *mut i8).into_string().unwrap(), + CString::from_raw(fields[2] as *mut i8).into_string().unwrap(), + CString::from_raw(fields[3] as *mut i8).into_string().unwrap().parse().unwrap(), + CString::from_raw(fields[1] as *mut i8).into_string().unwrap(), ); } _ => { printf( b"miss [%c]: %s\n\x00" as *const u8 as *const libc::c_char, *line.offset(0 as libc::c_int as isize) as libc::c_int, - fields[0 as libc::c_int as usize], + fields[0], ); } }; @@ -832,8 +810,8 @@ pub unsafe extern "C" fn is_valid_directory_entry( } pub unsafe extern "C" fn view_directory( mut host: &str, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, + mut port: usize, + mut selector: &str, mut make_current: libc::c_int, ) { let mut is_dir: libc::c_int = 0; @@ -858,21 +836,11 @@ pub unsafe extern "C" fn view_directory( host, ); /* clear links *AFTER* dialing out!! */ } /* quit if not successful */ - if port != current_port.as_mut_ptr() as *const libc::c_char { - snprintf( - current_port.as_mut_ptr(), - mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong, - b"%s\x00" as *const u8 as *const libc::c_char, - port, - ); + if port != current_port { + current_port = port; } - if selector != current_selector.as_mut_ptr() as *const libc::c_char { - snprintf( - current_selector.as_mut_ptr(), - mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, - b"%s\x00" as *const u8 as *const libc::c_char, - selector, - ); + if selector != current_selector { + current_selector = selector.to_string(); } } clear_links(); @@ -919,8 +887,8 @@ pub unsafe extern "C" fn view_directory( pub unsafe extern "C" fn view_file( mut cmd: *const libc::c_char, mut host: &str, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, + mut port: usize, + mut selector: &str, ) { let mut pid: pid_t = 0; let mut status: libc::c_int = 0; @@ -937,7 +905,7 @@ pub unsafe extern "C" fn view_file( selector, ); } - if download_temp(host, port, selector) == 0 { + if !download_temp(host, port, selector) { return; } /* parsed command line string */ @@ -974,7 +942,7 @@ pub unsafe extern "C" fn view_file( buffer[i as usize] = 0 as libc::c_int as libc::c_char; let fresh9 = j; j = j + 1; - argv[fresh9 as usize] = tmpfilename.as_mut_ptr(); + argv[fresh9 as usize] = CString::new(tmpfilename.clone()).unwrap().into_raw(); argv[j as usize] = 0 as *mut libc::c_char; /* fork and execute */ if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { @@ -998,11 +966,11 @@ pub unsafe extern "C" fn view_file( } sleep(Duration::from_secs(1)); waitpid(pid, &mut status, 0 as libc::c_int); - unlink(tmpfilename.as_mut_ptr()); + fs::remove_file(&tmpfilename); } pub unsafe extern "C" fn view_telnet( mut host: &str, - mut port: *const libc::c_char, + mut port: usize, ) { let mut pid: pid_t = 0; let mut status: libc::c_int = 0; @@ -1032,61 +1000,35 @@ pub unsafe extern "C" fn view_telnet( } pub unsafe extern "C" fn view_download( mut host: &str, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, + mut port: usize, + mut selector: &str, ) { - let mut fd: libc::c_int = 0; - let mut filename: [libc::c_char; 1024] = [0; 1024]; - let mut line: [libc::c_char; 1024] = [0; 1024]; - snprintf( - filename.as_mut_ptr(), - mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, - b"%s\x00" as *const u8 as *const libc::c_char, - strrchr(selector, '/' as i32).offset(1 as libc::c_int as isize), - ); - printf( - b"enter filename for download [%s]: \x00" as *const u8 as *const libc::c_char, - filename.as_mut_ptr(), - ); - if read_line( - 0 as libc::c_int, - line.as_mut_ptr(), - mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, - ) == 0 - { - puts(b"download aborted\x00" as *const u8 as *const libc::c_char); - return; - } - if strlen(line.as_mut_ptr()) > 0 as libc::c_int as libc::c_ulong { - strcpy(filename.as_mut_ptr(), line.as_mut_ptr()); - } - fd = open( - filename.as_mut_ptr(), - 0o100 as libc::c_int | 0o1 as libc::c_int, - 0o400 as libc::c_int | 0o200 as libc::c_int, - ); - if fd == -(1 as libc::c_int) { - printf( - b"error: unable to create file [%s]: %s\n\x00" as *const u8 - as *const libc::c_char, - filename.as_mut_ptr(), - strerror(*__errno_location()), - ); - return; - } - if download_file(host, port, selector, fd) == 0 { - printf( - b"error: unable to download [%s]\n\x00" as *const u8 as *const libc::c_char, - selector, - ); - unlink(filename.as_mut_ptr()); - return; + let mut filename: String = Path::new(selector).file_name().unwrap_or_default().to_string_lossy().into(); + let mut line: String = match input(&format!("enter filename for download [{}]: ", filename)).as_str() { + "" => { + println!("download aborted"); + return; + }, + x => x.into(), }; + filename = line; // TODO something stinky going on here + let mut file = match File::create(&filename) { + Ok(f) => f, + Err(_) => { + println!("error: unable to create file [{}]: {}", filename, CString::from_raw(strerror(*__errno_location())).into_string().unwrap()); + return; + }, + }; + // O_CREAT, O_NOCTTY, O_WRONLY, O_EXCL + if !download_file(host, port, selector, &mut file) { + println!("error: eunable to download [{}]", selector); + fs::remove_file(filename); + } } pub unsafe extern "C" fn view_search( mut host: &str, - mut port: *const libc::c_char, - mut selector: *const libc::c_char, + mut port: usize, + mut selector: &str, ) { let mut search_selector: [libc::c_char; 1024] = [0; 1024]; let mut line: [libc::c_char; 1024] = [0; 1024]; @@ -1107,32 +1049,30 @@ pub unsafe extern "C" fn view_search( selector, line.as_mut_ptr(), ); - view_directory(host, port, search_selector.as_mut_ptr(), 1 as libc::c_int); + view_directory(host, port, &CString::from_raw(search_selector.as_mut_ptr()).into_string().unwrap(), 1 as libc::c_int); } -pub unsafe extern "C" fn view_history(mut key: libc::c_int) { - let mut history_key: libc::c_int = 0 as libc::c_int; - let mut a: libc::c_char = 0; - let mut b: libc::c_char = 0; - let mut c: libc::c_char = 0; +pub unsafe extern "C" fn view_history(mut key: usize) { + let mut history_key: usize = 0; + let mut a: char = '\0'; + let mut b: char = '\0'; + let mut c: char = '\0'; let mut link: Option> = None; if history.is_none() { println!("(empty history)"); return; } - if key < 0 as libc::c_int { + if key < 0 { puts(b"(history)\x00" as *const u8 as *const libc::c_char); link = history.clone(); while let Some(l) = link { let fresh10 = history_key; history_key = history_key + 1; make_key_str(fresh10, &mut a, &mut b, &mut c); - printf( - b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s:%s/1%s\x1b[0m\n\x00" as *const u8 - as *const libc::c_char, - b"1;32\x00" as *const u8 as *const libc::c_char, - a as libc::c_int, - b as libc::c_int, - c as libc::c_int, + println!( + "{}{}{} {}:{}/{}", + a, + b, + c, (*l).host, (*l).port, (*l).selector, @@ -1147,7 +1087,7 @@ pub unsafe extern "C" fn view_history(mut key: libc::c_int) { view_directory( &(*l).host, (*l).port, - (*l).selector, + &(*l).selector, 0 as libc::c_int, ); return; @@ -1158,55 +1098,49 @@ pub unsafe extern "C" fn view_history(mut key: libc::c_int) { println!("history item not found"); }; } -pub unsafe extern "C" fn view_bookmarks(mut key: libc::c_int) { - let mut i: libc::c_int = 0; - let mut a: libc::c_char = 0; - let mut b: libc::c_char = 0; - let mut c: libc::c_char = 0; - if key < 0 as libc::c_int { +pub unsafe extern "C" fn view_bookmarks(mut key: usize) { + let mut i: usize = 0; + let mut a: char = '\0'; + let mut b: char = '\0'; + let mut c: char = '\0'; + if key < 0 { puts(b"(bookmarks)\x00" as *const u8 as *const libc::c_char); - i = 0 as libc::c_int; - while i < 20 as libc::c_int { - if bookmarks[i as usize][0 as libc::c_int as usize] != 0 { + i = 0; + while i < 20 { + if bookmarks[i as usize][0] != 0 { make_key_str(i, &mut a, &mut b, &mut c); - printf( - b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s\x1b[0m\n\x00" as *const u8 - as *const libc::c_char, - b"1;32\x00" as *const u8 as *const libc::c_char, - a as libc::c_int, - b as libc::c_int, - c as libc::c_int, - &mut *(*bookmarks.as_mut_ptr().offset(i as isize)) - .as_mut_ptr() - .offset(0 as libc::c_int as isize) as *mut libc::c_char, + println!( + "{}{}{} {}", + a, + b, + c, + CString::new(bookmarks[i as usize].iter().take_while(|x| **x != 0).cloned().collect::>()).unwrap().into_string().unwrap() ); } i += 1 } } else { - i = 0 as libc::c_int; - while i < 20 as libc::c_int { - if bookmarks[i as usize][0 as libc::c_int as usize] as libc::c_int != 0 + i = 0; + while i < 20 { + if bookmarks[i][0] != 0 && i == key { if parse_uri( - &mut *(*bookmarks.as_mut_ptr().offset(i as isize)) - .as_mut_ptr() - .offset(0 as libc::c_int as isize), - ) != 0 + CString::new(bookmarks[i].iter().take_while(|x| **x != 0).cloned().collect::>()) + .unwrap() + .into_string() + .unwrap()) { view_directory( - &CString::new(parsed_host.iter().take_while(|x| **x != 0).map(|x| *x as u8).collect::>()).unwrap().into_string().unwrap(), - parsed_port.as_mut_ptr(), - parsed_selector.as_mut_ptr(), + &parsed_host, + parsed_port, + &parsed_selector, 0 as libc::c_int, ); } else { - printf( - b"invalid gopher URI: %s\x00" as *const u8 as *const libc::c_char, - &mut *(*bookmarks.as_mut_ptr().offset(i as isize)) - .as_mut_ptr() - .offset(0 as libc::c_int as isize) as *mut libc::c_char, + println!( + "invalid gopher URI: {}", + CString::new(bookmarks[i].iter().take_while(|x| **x != 0).cloned().collect::>()).unwrap().into_string().unwrap() ); } return; @@ -1223,7 +1157,7 @@ pub fn pop_history() { unsafe { view_directory( &(*h).host, (*h).port, - (*h).selector, + &(*h).selector, 0 as libc::c_int, ); } /* history is history... :) */ @@ -1231,11 +1165,11 @@ pub fn pop_history() { }, } } -pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { +pub unsafe fn follow_link(mut key: usize) -> bool { let mut link: Option> = links.clone(); while let Some(ref l) = link { - if (*l).key as libc::c_int != key { + if (*l).key != key { link = (*l).next.clone() } else if let Some(w) = (*l).which { match w { @@ -1246,22 +1180,22 @@ pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { .into_raw(), &(*l).host, (*l).port, - (*l).selector, + &(*l).selector, ); } '1' => { view_directory( &(*l).host, (*l).port, - (*l).selector, + &(*l).selector, 1 as libc::c_int, ); } '7' => { - view_search(&(*l).host, (*l).port, (*l).selector); + view_search(&(*l).host, (*l).port, &(*l).selector); } '5' | '9' => { - view_download(&(*l).host, (*l).port, (*l).selector); + view_download(&(*l).host, (*l).port, &(*l).selector); } '8' => { view_telnet(&(*l).host, (*l).port); @@ -1273,7 +1207,7 @@ pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { .into_raw(), &(*l).host, (*l).port, - (*l).selector, + &(*l).selector, ); } 'h' => { @@ -1283,7 +1217,7 @@ pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { .into_raw(), &(*l).host, (*l).port, - (*l).selector, + &(*l).selector, ); } 's' => { @@ -1293,7 +1227,7 @@ pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { .into_raw(), &(*l).host, (*l).port, - (*l).selector, + &(*l).selector, ); } _ => { @@ -1303,123 +1237,79 @@ pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { ); } } - return 1 as libc::c_int; + return true; } /* return the array is broken after view! */ } - return 0 as libc::c_int; + return false; } -pub unsafe extern "C" fn download_link(mut key: libc::c_int) { +pub unsafe fn download_link(mut key: usize) { let mut link: Option> = links.clone(); while let Some(l) = link { - if (*l).key as libc::c_int != key { + if (*l).key != key { link = (*l).next } else { - view_download(&(*l).host, (*l).port, (*l).selector); + view_download(&(*l).host, (*l).port, &(*l).selector); return; } } println!("link not found"); } /* function prototypes */ -pub unsafe extern "C" fn parse_uri(mut uri: *const libc::c_char) -> libc::c_int { - let mut i: libc::c_int = 0; +pub unsafe fn parse_uri(mut uri: String) -> bool { + let mut tmp: &str = &uri[..]; /* strip gopher:// */ - if strncmp( - uri, - b"gopher://\x00" as *const u8 as *const libc::c_char, - 9 as libc::c_int as libc::c_ulong, - ) == 0 - { - uri = uri.offset(9 as libc::c_int as isize) - } - /* parse host */ - i = 0 as libc::c_int; - while *uri as libc::c_int != 0 - && *uri as libc::c_int != ':' as i32 - && *uri as libc::c_int != '/' as i32 - { - if *uri as libc::c_int != ' ' as i32 - && (i as libc::c_ulong) - < (mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong) - .wrapping_sub(1 as libc::c_int as libc::c_ulong) - { - let fresh11 = i; - i = i + 1; - parsed_host[fresh11 as usize] = *uri - } - uri = uri.offset(1) + if uri.starts_with("gopher://") { + tmp = &uri[9..]; } - if i > 0 as libc::c_int { - parsed_host[i as usize] = 0 as libc::c_int as libc::c_char - } else { - return 0 as libc::c_int; + parsed_host = tmp.chars().take_while(|x| !(*x == ':' || *x == '/')).collect(); + + if parsed_host.is_empty() { + return false } - /* parse port */ - if *uri as libc::c_int == ':' as i32 { - uri = uri.offset(1); - i = 0 as libc::c_int; - while *uri as libc::c_int != 0 && *uri as libc::c_int != '/' as i32 { - if *uri as libc::c_int != ' ' as i32 - && (i as libc::c_ulong) - < (mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong) - .wrapping_sub(1 as libc::c_int as libc::c_ulong) - { - let fresh12 = i; - i = i + 1; - parsed_port[fresh12 as usize] = *uri - } - uri = uri.offset(1) + + if tmp.contains(':') { + let port_string: String = tmp.chars().skip_while(|x| *x != ':').skip(1).take_while(|x| *x != '/').collect(); + + if port_string.is_empty() { + parsed_port = 70; + } else { + parsed_port = match port_string.parse() { + Ok(p) => p, + Err(_) => { + eprintln!("failed to parse port"); + exit(1); + } + }; } - parsed_port[i as usize] = 0 as libc::c_int as libc::c_char - } else { - snprintf( - parsed_port.as_mut_ptr(), - mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong, - b"%d\x00" as *const u8 as *const libc::c_char, - 70 as libc::c_int, - ); } + tmp = &tmp[tmp.find('/').unwrap_or(0)..]; /* parse selector (ignore slash and selector type) */ - if *uri != 0 { - uri = uri.offset(1) - } - if *uri != 0 { - uri = uri.offset(1) - } - i = 0 as libc::c_int; - while *uri as libc::c_int != 0 - && (i as libc::c_ulong) - < (mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong) - .wrapping_sub(1 as libc::c_int as libc::c_ulong) - { - parsed_selector[i as usize] = *uri; - uri = uri.offset(1); - i += 1 + if tmp.is_empty() || tmp.find('/').is_none() { + parsed_selector = "/".to_string(); + } else { + parsed_selector = tmp.into(); } - parsed_selector[i as usize] = '\u{0}' as i32 as libc::c_char; - return 1 as libc::c_int; + true } -unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> libc::c_int { - let mut i: libc::c_int = 0; - let mut line: [libc::c_char; 1024] = [0; 1024]; - let mut uri: *mut libc::c_char = 0 as *mut libc::c_char; +unsafe fn main_0(mut argc: usize, mut argv: Vec) -> libc::c_int { + let mut i: usize = 0; + let mut line: [u8; 1024] = [0; 1024]; + let mut uri: String = String::new(); /* copy defaults */ init_config(); - uri = CString::new(config.start_uri.clone()).unwrap().into_raw(); + uri = config.start_uri.clone(); /* parse command line */ - i = 1 as libc::c_int; + i = 1; while i < argc { - if *(*argv.offset(i as isize)).offset(0 as libc::c_int as isize) as libc::c_int - == '-' as i32 + if argv[i].chars().next() == Some('-') { - match *(*argv.offset(i as isize)).offset(1 as libc::c_int as isize) - as libc::c_int + match argv[i].chars().skip(1).next() { - 72 => { + Some('H') => { usage(); } - 118 => { + Some('v') => { banner(true); exit(0); } @@ -1428,24 +1318,24 @@ unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> lib } } } else { - uri = *argv.offset(i as isize) + uri = argv[i].clone(); } i += 1 } /* parse uri */ - if parse_uri(uri) == 0 { + if !parse_uri(uri) { banner(false); eprintln!( "invalid gopher URI: {}", - CStr::from_ptr(*argv.offset(i as isize)).to_str().unwrap() + argv[i], ); exit(1); } /* main loop */ view_directory( - &CString::new(parsed_host.iter().take_while(|x| **x != 0).map(|x| *x as u8).collect::>()).unwrap().into_string().unwrap(), - parsed_port.as_mut_ptr(), - parsed_selector.as_mut_ptr(), + &parsed_host, + parsed_port, + &parsed_selector, 0 as libc::c_int, ); /* to display the prompt */ loop { @@ -1453,19 +1343,19 @@ unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> lib b"\x1b[%sm%s:%s%s\x1b[0m \x00" as *const u8 as *const libc::c_char, CString::new(config.color_prompt.clone()).unwrap().into_raw(), current_host.as_mut_ptr(), - current_port.as_mut_ptr(), - current_selector.as_mut_ptr(), + current_port, + ¤t_selector, ); if read_line( 0 as libc::c_int, - line.as_mut_ptr(), + line.as_mut_ptr() as *mut i8, mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, ) == 0 { puts(b"QUIT\x00" as *const u8 as *const libc::c_char); return 0 as libc::c_int; } - i = strlen(line.as_mut_ptr()) as libc::c_int; + i = strlen(line.as_mut_ptr() as *mut i8) as usize; match line[0 as libc::c_int as usize] as libc::c_int { 63 => { puts(b"? - help\n* - reload directory\n< - go back in history\n.[LINK] - download the given link\nH - show history\nH[LINK] - jump to the specified history item\nG[URI] - jump to the given gopher URI\nB - show bookmarks\nB[LINK] - jump to the specified bookmark item\nC^d - quit\x00" @@ -1477,36 +1367,35 @@ unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> lib 42 => { view_directory( &CString::new(current_host.iter().take_while(|x| **x != 0).map(|x| *x as u8).collect::>()).unwrap().into_string().unwrap(), - current_port.as_mut_ptr(), - current_selector.as_mut_ptr(), + current_port, + ¤t_selector, 0 as libc::c_int, ); } 46 => { download_link(make_key( - line[1 as libc::c_int as usize], - line[2 as libc::c_int as usize], - line[3 as libc::c_int as usize], - )); + line[1] as char, + line[2] as char, + line[3] as char, + ).unwrap_or(0)); } 72 => { - if i == 1 as libc::c_int || i == 3 as libc::c_int || i == 4 as libc::c_int + if i == 1 || i == 3 || i == 4 { view_history(make_key( - line[1 as libc::c_int as usize], - line[2 as libc::c_int as usize], - line[3 as libc::c_int as usize], - )); + line[1] as char, + line[2] as char, + line[3] as char, + ).unwrap_or(0)); } } 71 => { - if parse_uri(&mut *line.as_mut_ptr().offset(1 as libc::c_int as isize)) - != 0 + if parse_uri(CString::from_raw(&mut *line.as_mut_ptr().offset(1 as libc::c_int as isize) as *mut u8 as *mut i8).into_string().unwrap()) { view_directory( - &CString::new(parsed_host.iter().take_while(|x| **x != 0).map(|x| *x as u8).collect::>()).unwrap().into_string().unwrap(), - parsed_port.as_mut_ptr(), - parsed_selector.as_mut_ptr(), + &parsed_host, + parsed_port, + &parsed_selector, 1 as libc::c_int, ); } else { @@ -1514,21 +1403,21 @@ unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> lib } } 66 => { - if i == 1 as libc::c_int || i == 3 as libc::c_int || i == 4 as libc::c_int + if i == 1 || i == 3 || i == 4 { view_bookmarks(make_key( - line[1 as libc::c_int as usize], - line[2 as libc::c_int as usize], - line[3 as libc::c_int as usize], - )); + line[1] as char, + line[2] as char, + line[3] as char, + ).unwrap_or(0)); } } _ => { follow_link(make_key( - line[0 as libc::c_int as usize], - line[1 as libc::c_int as usize], - line[2 as libc::c_int as usize], - )); + line[0] as char, + line[1] as char, + line[2] as char, + ).unwrap_or(0)); } } } @@ -1536,19 +1425,11 @@ unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> lib } #[main] pub fn main() { - let mut args: Vec<*mut libc::c_char> = Vec::new(); - for arg in env::args() { - args.push( - CString::new(arg) - .expect("Failed to convert argument into CString.") - .into_raw(), - ); - } - args.push(ptr::null_mut()); + let mut args: Vec = env::args().collect(); unsafe { exit(main_0( - (args.len() - 1) as libc::c_int, - args.as_mut_ptr() as *mut *mut libc::c_char, + args.len() - 1, + args, ) as i32) } }