//! ## AuthActivity //! //! `auth_activity` is the module which implements the authentication activity /** * MIT License * * termscp - Copyright (c) 2021 Christian Visintin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // locals use super::{ AuthActivity, FileTransferParams, FileTransferProtocol, COMPONENT_BOOKMARKS_LIST, COMPONENT_INPUT_ADDR, COMPONENT_INPUT_BOOKMARK_NAME, COMPONENT_INPUT_PASSWORD, COMPONENT_INPUT_PORT, COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD, COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT, COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR, COMPONENT_TEXT_HELP, }; use crate::ui::keymap::*; use tuirealm::components::InputPropsBuilder; use tuirealm::{Msg, Payload, PropsBuilder, Value}; // -- update impl AuthActivity { /// ### update /// /// Update auth activity model based on msg /// The function exits when returns None pub(super) fn update(&mut self, msg: Option<(String, Msg)>) -> Option<(String, Msg)> { let ref_msg: Option<(&str, &Msg)> = msg.as_ref().map(|(s, msg)| (s.as_str(), msg)); // Match msg match ref_msg { None => None, // Exit after None Some(msg) => match msg { // Focus ( DOWN ) (COMPONENT_RADIO_PROTOCOL, &MSG_KEY_DOWN) => { // Give focus to port self.view.active(COMPONENT_INPUT_ADDR); None } (COMPONENT_INPUT_ADDR, &MSG_KEY_DOWN) => { // Give focus to port self.view.active(COMPONENT_INPUT_PORT); None } (COMPONENT_INPUT_PORT, &MSG_KEY_DOWN) => { // Give focus to port self.view.active(COMPONENT_INPUT_USERNAME); None } (COMPONENT_INPUT_USERNAME, &MSG_KEY_DOWN) => { // Give focus to port self.view.active(COMPONENT_INPUT_PASSWORD); None } (COMPONENT_INPUT_PASSWORD, &MSG_KEY_DOWN) => { // Give focus to port self.view.active(COMPONENT_RADIO_PROTOCOL); None } // Focus ( UP ) (COMPONENT_INPUT_PASSWORD, &MSG_KEY_UP) => { // Give focus to port self.view.active(COMPONENT_INPUT_USERNAME); None } (COMPONENT_INPUT_USERNAME, &MSG_KEY_UP) => { // Give focus to port self.view.active(COMPONENT_INPUT_PORT); None } (COMPONENT_INPUT_PORT, &MSG_KEY_UP) => { // Give focus to port self.view.active(COMPONENT_INPUT_ADDR); None } (COMPONENT_INPUT_ADDR, &MSG_KEY_UP) => { // Give focus to port self.view.active(COMPONENT_RADIO_PROTOCOL); None } (COMPONENT_RADIO_PROTOCOL, &MSG_KEY_UP) => { // Give focus to port self.view.active(COMPONENT_INPUT_PASSWORD); None } // Protocol - On Change (COMPONENT_RADIO_PROTOCOL, Msg::OnChange(Payload::One(Value::Usize(protocol)))) => { // If port is standard, update the current port with default for selected protocol let protocol: FileTransferProtocol = Self::protocol_opt_to_enum(*protocol); // Get port let port: u16 = self.get_input_port(); match Self::is_port_standard(port) { false => None, // Return None true => { self.update_input_port(Self::get_default_port_for_protocol(protocol)) } } } // bookmarks (COMPONENT_BOOKMARKS_LIST, &MSG_KEY_TAB) | (COMPONENT_RECENTS_LIST, &MSG_KEY_TAB) => { // Give focus to address self.view.active(COMPONENT_INPUT_ADDR); None } // Any , go to bookmarks (_, &MSG_KEY_TAB) => { self.view.active(COMPONENT_BOOKMARKS_LIST); None } // Bookmarks commands // / (COMPONENT_BOOKMARKS_LIST, &MSG_KEY_RIGHT) => { // Give focus to recents self.view.active(COMPONENT_RECENTS_LIST); None } (COMPONENT_RECENTS_LIST, &MSG_KEY_LEFT) => { // Give focus to bookmarks self.view.active(COMPONENT_BOOKMARKS_LIST); None } // (COMPONENT_BOOKMARKS_LIST, &MSG_KEY_DEL) | (COMPONENT_BOOKMARKS_LIST, &MSG_KEY_CHAR_E) => { // Show delete popup self.mount_bookmark_del_dialog(); None } (COMPONENT_RECENTS_LIST, &MSG_KEY_DEL) | (COMPONENT_RECENTS_LIST, &MSG_KEY_CHAR_E) => { // Show delete popup self.mount_recent_del_dialog(); None } // Enter (COMPONENT_BOOKMARKS_LIST, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => { self.load_bookmark(*idx); // Give focus to input password self.view.active(COMPONENT_INPUT_PASSWORD); None } (COMPONENT_RECENTS_LIST, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => { self.load_recent(*idx); // Give focus to input password self.view.active(COMPONENT_INPUT_PASSWORD); None } // Bookmark radio // Del bookmarks ( COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, Msg::OnSubmit(Payload::One(Value::Usize(index))), ) => { // hide bookmark delete self.umount_bookmark_del_dialog(); // Index must be 0 => YES match *index { 0 => { // Get selected bookmark match self.view.get_state(COMPONENT_BOOKMARKS_LIST) { Some(Payload::One(Value::Usize(index))) => { // Delete bookmark self.del_bookmark(index); // Update bookmarks self.view_bookmarks() } _ => None, } } _ => None, } } ( COMPONENT_RADIO_BOOKMARK_DEL_RECENT, Msg::OnSubmit(Payload::One(Value::Usize(index))), ) => { // hide bookmark delete self.umount_recent_del_dialog(); // Index must be 0 => YES match *index { 0 => { // Get selected bookmark match self.view.get_state(COMPONENT_RECENTS_LIST) { Some(Payload::One(Value::Usize(index))) => { // Delete recent self.del_recent(index); // Update bookmarks self.view_recent_connections() } _ => None, } } _ => None, } } // hide tab (COMPONENT_RADIO_BOOKMARK_DEL_RECENT, &MSG_KEY_ESC) => { self.umount_recent_del_dialog(); None } (COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, &MSG_KEY_ESC) => { self.umount_bookmark_del_dialog(); None } // Error message (COMPONENT_TEXT_ERROR, &MSG_KEY_ENTER) | (COMPONENT_TEXT_ERROR, &MSG_KEY_ESC) => { // Umount text error self.umount_error(); None } (COMPONENT_TEXT_ERROR, _) => None, // Help (_, &MSG_KEY_CTRL_H) => { // Show help self.mount_help(); None } (COMPONENT_TEXT_HELP, &MSG_KEY_ENTER) | (COMPONENT_TEXT_HELP, &MSG_KEY_ESC) => { // Hide text help self.umount_help(); None } // Enter setup (_, &MSG_KEY_CTRL_C) => { self.exit_reason = Some(super::ExitReason::EnterSetup); None } // Save bookmark; show popup (_, &MSG_KEY_CTRL_S) => { // Show popup self.mount_bookmark_save_dialog(); // Give focus to bookmark name self.view.active(COMPONENT_INPUT_BOOKMARK_NAME); None } (COMPONENT_INPUT_BOOKMARK_NAME, &MSG_KEY_DOWN) => { // Give focus to pwd self.view.active(COMPONENT_RADIO_BOOKMARK_SAVE_PWD); None } (COMPONENT_RADIO_BOOKMARK_SAVE_PWD, &MSG_KEY_UP) => { // Give focus to pwd self.view.active(COMPONENT_INPUT_BOOKMARK_NAME); None } // Save bookmark (COMPONENT_INPUT_BOOKMARK_NAME, Msg::OnSubmit(_)) | (COMPONENT_RADIO_BOOKMARK_SAVE_PWD, Msg::OnSubmit(_)) => { // Get values let bookmark_name: String = match self.view.get_state(COMPONENT_INPUT_BOOKMARK_NAME) { Some(Payload::One(Value::Str(s))) => s, _ => String::new(), }; let save_pwd: bool = matches!( self.view.get_state(COMPONENT_RADIO_BOOKMARK_SAVE_PWD), Some(Payload::One(Value::Usize(0))) ); // Save bookmark if !bookmark_name.is_empty() { self.save_bookmark(bookmark_name, save_pwd); } // Umount popup self.umount_bookmark_save_dialog(); // Reload bookmarks self.view_bookmarks() } // Hide save bookmark (COMPONENT_INPUT_BOOKMARK_NAME, &MSG_KEY_ESC) | (COMPONENT_RADIO_BOOKMARK_SAVE_PWD, &MSG_KEY_ESC) => { // Umount popup self.umount_bookmark_save_dialog(); None } // Quit dialog (COMPONENT_RADIO_QUIT, Msg::OnSubmit(Payload::One(Value::Usize(choice)))) => { // If choice is 0, quit termscp if *choice == 0 { self.exit_reason = Some(super::ExitReason::Quit); } self.umount_quit(); None } (COMPONENT_RADIO_QUIT, &MSG_KEY_ESC) => { self.umount_quit(); None } // On submit on any unhandled (connect) (_, Msg::OnSubmit(_)) | (_, &MSG_KEY_ENTER) => { // Match key for all other components self.save_recent(); let (address, port, protocol, username, password) = self.get_input(); // Set file transfer params to context let mut ft_params: &mut FileTransferParams = &mut self.context.as_mut().unwrap().ft_params.as_mut().unwrap(); ft_params.address = address; ft_params.port = port; ft_params.protocol = protocol; ft_params.username = match username.is_empty() { true => None, false => Some(username), }; ft_params.password = match password.is_empty() { true => None, false => Some(password), }; // Set exit reason self.exit_reason = Some(super::ExitReason::Connect); // Return None None } // => Quit (_, &MSG_KEY_ESC) => { self.mount_quit(); None } (_, _) => None, // Ignore other events }, } } fn update_input_port(&mut self, port: u16) -> Option<(String, Msg)> { match self.view.get_props(COMPONENT_INPUT_PORT) { None => None, Some(props) => { let props = InputPropsBuilder::from(props) .with_value(port.to_string()) .build(); self.view.update(COMPONENT_INPUT_PORT, props) } } } }