diff --git a/src/lib.rs b/src/lib.rs
index 0880ef3..0f3bfdc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,3 +23,4 @@ pub mod filetransfer;
pub mod fs;
pub mod host;
pub mod ui;
+pub mod utils;
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..8bd972e
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,178 @@
+//! ## Utils
+//!
+//! `utils` is the module which provides utilities of different kind
+
+/*
+*
+* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
+*
+* This file is part of "TermSCP"
+*
+* TermSCP is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* TermSCP is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with TermSCP. If not, see .
+*
+*/
+
+// Dependencies
+extern crate whoami;
+
+use crate::ui::activities::auth_activity::ScpProtocol;
+
+/// ### parse_remote_opt
+///
+/// Parse remote option string. Returns in case of success a tuple made of (address, port, protocol, username)
+/// For ssh if username is not provided, current user will be used.
+/// In case of error, message is returned
+/// If port is missing default port will be used for each protocol
+/// SFTP => 22
+/// FTP => 21
+/// The option string has the following syntax
+/// [protocol]://[username]@{address}:[port]
+/// The only argument which is mandatory is address
+/// NOTE: possible strings
+/// - 172.26.104.1
+/// - root@172.26.104.1
+/// - sftp://root@172.26.104.1
+/// - sftp://172.26.104.1:4022
+/// - sftp://172.26.104.1
+/// - ...
+///
+pub fn parse_remote_opt(
+ remote: &String,
+) -> Result<(String, u16, ScpProtocol, Option), String> {
+ let mut wrkstr: String = remote.clone();
+ let address: String;
+ let mut port: u16 = 22;
+ let mut protocol: ScpProtocol = ScpProtocol::Sftp;
+ let mut username: Option = None;
+ // Split string by '://'
+ let tokens: Vec<&str> = wrkstr.split("://").collect();
+ // If length is > 1, then token[0] is protocol
+ match tokens.len() {
+ 1 => {},
+ 2 => {
+ // Parse protocol
+ match tokens[0] {
+ "sftp" => {
+ // Set protocol to sftp
+ protocol = ScpProtocol::Sftp;
+ // Set port to default (22)
+ port = 22;
+ }
+ "ftp" | "ftps" => {
+ // Set protocol to fpt
+ protocol = ScpProtocol::Ftp;
+ // Set port to default (21)
+ port = 21;
+ }
+ _ => return Err(format!("Unknown protocol '{}'", tokens[0])),
+ }
+ wrkstr = String::from(tokens[1]); // Wrkstr becomes tokens[1]
+ },
+ _ => return Err(String::from("Bad syntax")), // Too many tokens...
+ }
+ // Set username to default if sftp
+ if protocol == ScpProtocol::Sftp {
+ // Set username to current username
+ username = Some(whoami::username());
+ }
+ // Split wrkstring by '@'
+ let tokens: Vec<&str> = wrkstr.split("@").collect();
+ match tokens.len() {
+ 1 => {}
+ 2 => {
+ // Username is first token
+ username = Some(String::from(tokens[0]));
+ // Update wrkstr
+ wrkstr = String::from(tokens[1]);
+ },
+ _ => return Err(String::from("Bad syntax")), // Too many tokens...
+ }
+ // Split wrkstring by ':'
+ let tokens: Vec<&str> = wrkstr.split(":").collect();
+ match tokens.len() {
+ 1 => {
+ // Address is wrkstr
+ address = wrkstr.clone();
+ }
+ 2 => {
+ // Address is first token
+ address = String::from(tokens[0]);
+ // Port is second str
+ port = match tokens[1].parse::() {
+ Ok(val) => val,
+ Err(_) => return Err(format!("Port must be a number in range [0-65535], but is '{}'", tokens[1]))
+ };
+ },
+ _ => return Err(String::from("Bad syntax")), // Too many tokens...
+ }
+ Ok((address, port, protocol, username))
+}
+
+#[cfg(test)]
+mod tests {
+
+ use super::*;
+
+ #[test]
+ fn test_utils_parse_remote_opt() {
+ // Base case
+ let result: (String, u16, ScpProtocol, Option) = parse_remote_opt(&String::from("172.26.104.1")).ok().unwrap();
+ assert_eq!(result.0, String::from("172.26.104.1"));
+ assert_eq!(result.1, 22);
+ assert_eq!(result.2, ScpProtocol::Sftp);
+ assert!(result.3.is_some());
+ // User case
+ let result: (String, u16, ScpProtocol, Option) = parse_remote_opt(&String::from("root@172.26.104.1")).ok().unwrap();
+ assert_eq!(result.0, String::from("172.26.104.1"));
+ assert_eq!(result.1, 22);
+ assert_eq!(result.2, ScpProtocol::Sftp);
+ assert_eq!(result.3.unwrap(), String::from("root"));
+ // User + port
+ let result: (String, u16, ScpProtocol, Option) = parse_remote_opt(&String::from("root@172.26.104.1:8022")).ok().unwrap();
+ assert_eq!(result.0, String::from("172.26.104.1"));
+ assert_eq!(result.1, 8022);
+ assert_eq!(result.2, ScpProtocol::Sftp);
+ assert_eq!(result.3.unwrap(), String::from("root"));
+ // Port only
+ let result: (String, u16, ScpProtocol, Option) = parse_remote_opt(&String::from("172.26.104.1:4022")).ok().unwrap();
+ assert_eq!(result.0, String::from("172.26.104.1"));
+ assert_eq!(result.1, 4022);
+ assert_eq!(result.2, ScpProtocol::Sftp);
+ assert!(result.3.is_some());
+ // Protocol
+ let result: (String, u16, ScpProtocol, Option) = parse_remote_opt(&String::from("ftp://172.26.104.1")).ok().unwrap();
+ assert_eq!(result.0, String::from("172.26.104.1"));
+ assert_eq!(result.1, 21); // Fallback to ftp default
+ assert_eq!(result.2, ScpProtocol::Ftp);
+ assert!(result.3.is_none()); // Doesn't fall back
+ // Protocol + user
+ let result: (String, u16, ScpProtocol, Option) = parse_remote_opt(&String::from("ftp://anon@172.26.104.1")).ok().unwrap();
+ assert_eq!(result.0, String::from("172.26.104.1"));
+ assert_eq!(result.1, 21); // Fallback to ftp default
+ assert_eq!(result.2, ScpProtocol::Ftp);
+ assert_eq!(result.3.unwrap(), String::from("anon"));
+ // All together now
+ let result: (String, u16, ScpProtocol, Option) = parse_remote_opt(&String::from("ftp://anon@172.26.104.1:8021")).ok().unwrap();
+ assert_eq!(result.0, String::from("172.26.104.1"));
+ assert_eq!(result.1, 8021); // Fallback to ftp default
+ assert_eq!(result.2, ScpProtocol::Ftp);
+ assert_eq!(result.3.unwrap(), String::from("anon"));
+
+ // bad syntax
+ assert!(parse_remote_opt(&String::from("://172.26.104.1")).is_err()); // Missing protocol
+ assert!(parse_remote_opt(&String::from("omar://172.26.104.1")).is_err()); // Bad protocol
+ assert!(parse_remote_opt(&String::from("172.26.104.1:abc")).is_err()); // Bad port
+ }
+
+}