Merge pull request #236 from veeso/develop

0.13.0
This commit is contained in:
Christian Visintin
2024-03-02 20:27:16 +01:00
committed by GitHub
52 changed files with 1186 additions and 394 deletions
+16
View File
@@ -1,6 +1,7 @@
# Changelog # Changelog
- [Changelog](#changelog) - [Changelog](#changelog)
- [0.13.0](#0130)
- [0.12.3](#0123) - [0.12.3](#0123)
- [0.12.2](#0122) - [0.12.2](#0122)
- [0.12.1](#0121) - [0.12.1](#0121)
@@ -34,6 +35,21 @@
--- ---
## 0.13.0
Released on 03/03/2024
- Added CLI subcommands
- Changed `-t` to `theme`
- Changed `-u` to `update`
- Changed `-c` to `config`
- Introduced support for [WebDAV](https://www.rfc-editor.org/rfc/rfc4918)
- It is now possible also to connect directly to WebDAV server with the syntax `http(s)://username:password@google.com`
- Bugfix:
- [Issue 232](https://github.com/veeso/termscp/issues/232): AWS S3 wasn't working anymore due to rust-s3 outdate
- Dependencies:
- Added `remotefs-webdav 0.1.1`
## 0.12.3 ## 0.12.3
Released on 06/10/2023 Released on 06/10/2023
Generated
+521 -235
View File
File diff suppressed because it is too large Load Diff
+9 -8
View File
@@ -16,7 +16,7 @@ license = "MIT"
name = "termscp" name = "termscp"
readme = "README.md" readme = "README.md"
repository = "https://github.com/veeso/termscp" repository = "https://github.com/veeso/termscp"
version = "0.12.3" version = "0.13.0"
[package.metadata.rpm] [package.metadata.rpm]
package = "termscp" package = "termscp"
@@ -47,7 +47,7 @@ edit = "^0.1"
filetime = "^0.2" filetime = "^0.2"
hostname = "^0.3" hostname = "^0.3"
keyring = { version = "^2.0", optional = true } keyring = { version = "^2.0", optional = true }
lazy-regex = "^2.5" lazy-regex = "^3.1"
lazy_static = "^1.4" lazy_static = "^1.4"
log = "^0.4" log = "^0.4"
magic-crypt = "^3.1" magic-crypt = "^3.1"
@@ -56,10 +56,11 @@ notify-rust = { version = "^4.5", default-features = false, features = ["d"] }
open = "^5.0" open = "^5.0"
rand = "^0.8.5" rand = "^0.8.5"
remotefs = "^0.2.0" remotefs = "^0.2.0"
remotefs-aws-s3 = { version = "^0.2.1", default-features = false, features = [ remotefs-aws-s3 = { version = "^0.2.4", default-features = false, features = [
"find", "find",
"rustls", "rustls",
] } ] }
remotefs-webdav = "^0.1.1"
rpassword = "^7.0" rpassword = "^7.0"
self_update = { version = "^0.37", default-features = false, features = [ self_update = { version = "^0.37", default-features = false, features = [
"rustls", "rustls",
@@ -73,9 +74,9 @@ simplelog = "^0.12"
ssh2-config = "^0.2" ssh2-config = "^0.2"
tempfile = "^3.4" tempfile = "^3.4"
thiserror = "^1" thiserror = "^1"
toml = "^0.7" toml = "^0.8"
tui-realm-stdlib = "=1.2" tui-realm-stdlib = "^1.3.1"
tuirealm = "=1.8.0" tuirealm = "^1.9.1"
unicode-width = "^0.1" unicode-width = "^0.1"
version-compare = "^0.1" version-compare = "^0.1"
whoami = "^1.4" whoami = "^1.4"
@@ -83,10 +84,10 @@ wildmatch = "^2.1"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "^1.3" pretty_assertions = "^1.3"
serial_test = "^2.0" serial_test = "^3"
[build-dependencies] [build-dependencies]
cfg_aliases = "0.1" cfg_aliases = "0.2"
[features] [features]
default = ["smb", "with-keyring"] default = ["smb", "with-keyring"]
+4 -3
View File
@@ -1,7 +1,7 @@
# termscp # termscp
<p align="center"> <p align="center">
<img src="/assets/images/termscp.svg" width="256" height="256" /> <img src="/assets/images/termscp.svg" alt="termscp logo" width="256" height="256" />
</p> </p>
<p align="center">~ A feature rich terminal file transfer ~</p> <p align="center">~ A feature rich terminal file transfer ~</p>
@@ -63,7 +63,7 @@
</p> </p>
<p align="center">Developed by <a href="https://veeso.dev/" target="_blank">@veeso</a></p> <p align="center">Developed by <a href="https://veeso.dev/" target="_blank">@veeso</a></p>
<p align="center">Current version: 0.12.3 (06/10/2023)</p> <p align="center">Current version: 0.13.0 (03/03/2024)</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"
@@ -73,7 +73,7 @@
/></a> /></a>
<a href="https://github.com/veeso/termscp/stargazers" <a href="https://github.com/veeso/termscp/stargazers"
><img ><img
src="https://img.shields.io/github/stars/veeso/termscp.svg" src="https://img.shields.io/github/stars/veeso/termscp?style=flat"
alt="Repo stars" alt="Repo stars"
/></a> /></a>
<a href="https://crates.io/crates/termscp" <a href="https://crates.io/crates/termscp"
@@ -133,6 +133,7 @@ Termscp is a feature rich terminal file transfer and explorer, with support for
- **FTP** and **FTPS** - **FTP** and **FTPS**
- **S3** - **S3**
- **SMB** - **SMB**
- **WebDAV**
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI - 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
- Create, remove, rename, search, view and edit files - Create, remove, rename, search, view and edit files
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections - ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections
+1 -1
View File
@@ -40,7 +40,7 @@ mkdir -p ${PKGS_DIR}/deb/
mkdir -p ${PKGS_DIR}/aarch64-unknown-linux-gnu/ mkdir -p ${PKGS_DIR}/aarch64-unknown-linux-gnu/
docker run --name "$ARM64_DEB_NAME" -d "$ARM64_DEB_NAME" || docker start "$ARM64_DEB_NAME" docker run --name "$ARM64_DEB_NAME" -d "$ARM64_DEB_NAME" || docker start "$ARM64_DEB_NAME"
docker exec -it "$ARM64_DEB_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo build --release && cargo deb" docker exec -it "$ARM64_DEB_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo build --release && cargo deb"
docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}_arm64.deb ${PKGS_DIR}/deb/ docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}-1_arm64.deb ${PKGS_DIR}/deb/termscp_${VERSION}_arm64.deb
docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/aarch64-unknown-linux-gnu/ docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/aarch64-unknown-linux-gnu/
docker stop "$ARM64_DEB_NAME" docker stop "$ARM64_DEB_NAME"
# Make tar.gz # Make tar.gz
+1 -1
View File
@@ -38,7 +38,7 @@ mkdir -p ${PKGS_DIR}/deb/
mkdir -p ${PKGS_DIR}/x86_64-unknown-linux-gnu/ mkdir -p ${PKGS_DIR}/x86_64-unknown-linux-gnu/
docker run --name "$X86_64_DEB_NAME" -d "$X86_64_DEB_NAME" || docker start "$X86_64_DEB_NAME" docker run --name "$X86_64_DEB_NAME" -d "$X86_64_DEB_NAME" || docker start "$X86_64_DEB_NAME"
docker exec -it "$X86_64_DEB_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo build --release && cargo deb" docker exec -it "$X86_64_DEB_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo build --release && cargo deb"
docker cp ${X86_64_DEB_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}_amd64.deb ${PKGS_DIR}/deb/ docker cp ${X86_64_DEB_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}-1_amd64.deb ${PKGS_DIR}/deb/termscp_${VERSION}_amd64.deb
docker cp ${X86_64_DEB_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/x86_64-unknown-linux-gnu/ docker cp ${X86_64_DEB_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/x86_64-unknown-linux-gnu/
docker stop "$X86_64_DEB_NAME" docker stop "$X86_64_DEB_NAME"
# Make tar.gz # Make tar.gz
+2 -1
View File
@@ -63,7 +63,7 @@
</p> </p>
<p align="center">Entwickelt von <a href="https://veeso.dev/" target="_blank">@veeso</a></p> <p align="center">Entwickelt von <a href="https://veeso.dev/" target="_blank">@veeso</a></p>
<p align="center">Aktuelle Version: 0.12.3 (06/10/2023)</p> <p align="center">Aktuelle Version: 0.13.0 (03/03/2024)</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"
@@ -138,6 +138,7 @@ Termscp ist ein funktionsreicher Terminal-Dateitransfer und Explorer mit Unterst
- **FTP** und **FTPS** - **FTP** und **FTPS**
- **S3** - **S3**
- **SMB** - **SMB**
- **WebDAV**
- 🖥 Erkunden und bedienen Sie das Dateisystem der Fernbedienung und des lokalen Computers mit einer praktischen Benutzeroberfläche - 🖥 Erkunden und bedienen Sie das Dateisystem der Fernbedienung und des lokalen Computers mit einer praktischen Benutzeroberfläche
- Erstellen, Entfernen, Umbenennen, Suchen, Anzeigen und Bearbeiten von Dateien - Erstellen, Entfernen, Umbenennen, Suchen, Anzeigen und Bearbeiten von Dateien
- ⭐ Verbinden Sie sich über integrierte Lesezeichen und aktuelle Verbindungen mit Ihren Lieblingshosts - ⭐ Verbinden Sie sich über integrierte Lesezeichen und aktuelle Verbindungen mit Ihren Lieblingshosts
+14 -3
View File
@@ -6,6 +6,9 @@
- [AWS S3 address argument](#aws-s3-address-argument) - [AWS S3 address argument](#aws-s3-address-argument)
- [SMB address argument](#smb-address-argument) - [SMB address argument](#smb-address-argument)
- [How Password can be provided 🔐](#how-password-can-be-provided-) - [How Password can be provided 🔐](#how-password-can-be-provided-)
- [Subcommands](#subcommands)
- [Import a theme](#import-a-theme)
- [Install latest version](#install-latest-version)
- [S3 connection parameters](#s3-connection-parameters) - [S3 connection parameters](#s3-connection-parameters)
- [S3 credentials 🦊](#s3-credentials-) - [S3 credentials 🦊](#s3-credentials-)
- [File explorer 📂](#file-explorer-) - [File explorer 📂](#file-explorer-)
@@ -45,10 +48,7 @@ OR
- `-P, --password <password>` if address is provided, password will be this argument - `-P, --password <password>` if address is provided, password will be this argument
- `-b, --address-as-bookmark` resolve address argument as a bookmark name - `-b, --address-as-bookmark` resolve address argument as a bookmark name
- `-c, --config` Open termscp starting from the configuration page
- `-q, --quiet` Disable logging - `-q, --quiet` Disable logging
- `-t, --theme <path>` Import specified theme
- `-u, --update` Update termscp to latest version
- `-v, --version` Print version info - `-v, --version` Print version info
- `-h, --help` Print help page - `-h, --help` Print help page
@@ -131,6 +131,17 @@ Password can be basically provided through 3 ways when address argument is provi
- Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31`
- You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc. - You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc.
### Subcommands
#### Import a theme
Run termscp as `termscp theme <theme-file>`
#### Install latest version
Run termscp as `termscp update`
--- ---
## S3 connection parameters ## S3 connection parameters
+2 -1
View File
@@ -63,7 +63,7 @@
</p> </p>
<p align="center">Desarrollado por <a href="https://veeso.dev/" target="_blank">@veeso</a></p> <p align="center">Desarrollado por <a href="https://veeso.dev/" target="_blank">@veeso</a></p>
<p align="center">Versión actual: 0.12.3 (06/10/2023)</p> <p align="center">Versión actual: 0.13.0 (03/03/2024)</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"
@@ -138,6 +138,7 @@ Termscp es un explorador y transferencia de archivos de terminal rico en funcion
- **FTP** y **FTPS** - **FTP** y **FTPS**
- **S3** - **S3**
- **SMB** - **SMB**
- **WebDAV**
- 🖥 Explore y opere en el sistema de archivos de la máquina local y remota con una interfaz de usuario práctica - 🖥 Explore y opere en el sistema de archivos de la máquina local y remota con una interfaz de usuario práctica
- Cree, elimine, cambie el nombre, busque, vea y edite archivos - Cree, elimine, cambie el nombre, busque, vea y edite archivos
- ⭐ Conéctese a sus hosts favoritos y conexiones recientes - ⭐ Conéctese a sus hosts favoritos y conexiones recientes
+15 -3
View File
@@ -4,6 +4,7 @@
- [Uso ❓](#uso-) - [Uso ❓](#uso-)
- [Argumento dirección 🌎](#argumento-dirección-) - [Argumento dirección 🌎](#argumento-dirección-)
- [Argumento dirección por AWS S3](#argumento-dirección-por-aws-s3) - [Argumento dirección por AWS S3](#argumento-dirección-por-aws-s3)
- [Argumento de dirección de WebDAV](#argumento-de-dirección-de-webdav)
- [Argumento dirección por SMB](#argumento-dirección-por-smb) - [Argumento dirección por SMB](#argumento-dirección-por-smb)
- [Cómo se puede proporcionar la contraseña 🔐](#cómo-se-puede-proporcionar-la-contraseña-) - [Cómo se puede proporcionar la contraseña 🔐](#cómo-se-puede-proporcionar-la-contraseña-)
- [S3 parámetros de conexión](#s3-parámetros-de-conexión) - [S3 parámetros de conexión](#s3-parámetros-de-conexión)
@@ -45,10 +46,7 @@ OR
- `-P, --password <password>` si se proporciona la dirección, la contraseña será este argumento - `-P, --password <password>` si se proporciona la dirección, la contraseña será este argumento
- `-b, --address-as-bookmark` resuelve el argumento de la dirección como un nombre de marcador - `-b, --address-as-bookmark` resuelve el argumento de la dirección como un nombre de marcador
- `-c, --config` Abrir termscp comenzando desde la página de configuración
- `-q, --quiet` Deshabilitar el registro - `-q, --quiet` Deshabilitar el registro
- `-t, --theme <path>` Importar tema especificado
- `-u, --update` Actualizar termscp a la última versión
- `-v, --version` Imprimir información de la versión - `-v, --version` Imprimir información de la versión
- `-h, --help` Imprimir página de ayuda - `-h, --help` Imprimir página de ayuda
@@ -106,6 +104,20 @@ por ejemplo
s3://buckethead@eu-central-1:default:/assets s3://buckethead@eu-central-1:default:/assets
``` ```
#### Argumento de dirección de WebDAV
En caso de que quieras conectarte a WebDAV utiliza la siguiente sintaxis
```txt
http://<username>:<password>@<url></path>
```
o en caso de que quieras usar https
```txt
https://<username>:<password>@<url></path>
```
#### Argumento dirección por SMB #### Argumento dirección por SMB
SMB tiene una sintaxis diferente para el argumento de la dirección CLI, que es diferente si está en Windows u otros sistemas: SMB tiene una sintaxis diferente para el argumento de la dirección CLI, que es diferente si está en Windows u otros sistemas:
+2 -1
View File
@@ -63,7 +63,7 @@
</p> </p>
<p align="center">Développé par <a href="https://veeso.dev/" target="_blank">@veeso</a></p> <p align="center">Développé par <a href="https://veeso.dev/" target="_blank">@veeso</a></p>
<p align="center">Version actuelle: 0.12.3 (06/10/2023)</p> <p align="center">Version actuelle: 0.13.0 (03/03/2024)</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"
@@ -138,6 +138,7 @@ Termscp est un file transfer et explorateur de fichiers de terminal riche en fon
- **FTP** et **FTPS** - **FTP** et **FTPS**
- **S3** - **S3**
- **SMB** - **SMB**
- **WebDAV**
- 🖥 Explorer et opérer sur le système de fichiers distant et local avec une interface utilisateur pratique. - 🖥 Explorer et opérer sur le système de fichiers distant et local avec une interface utilisateur pratique.
- Créer, supprimer, renommer, rechercher, afficher et modifier des fichiers - Créer, supprimer, renommer, rechercher, afficher et modifier des fichiers
- ⭐ Connectez-vous à vos hôtes préférés via des signets et des connexions récentes. - ⭐ Connectez-vous à vos hôtes préférés via des signets et des connexions récentes.
+15 -3
View File
@@ -4,6 +4,7 @@
- [Usage ❓](#usage-) - [Usage ❓](#usage-)
- [Argument d'adresse 🌎](#argument-dadresse-) - [Argument d'adresse 🌎](#argument-dadresse-)
- [Argument d'adresse AWS S3](#argument-dadresse-aws-s3) - [Argument d'adresse AWS S3](#argument-dadresse-aws-s3)
- [Argument d'adresse WebDAV](#argument-dadresse-webdav)
- [Argument d'adresse SMB](#argument-dadresse-smb) - [Argument d'adresse SMB](#argument-dadresse-smb)
- [Comment le mot de passe peut être fourni 🔐](#comment-le-mot-de-passe-peut-être-fourni-) - [Comment le mot de passe peut être fourni 🔐](#comment-le-mot-de-passe-peut-être-fourni-)
- [S3 paramètres de connexion](#s3-paramètres-de-connexion) - [S3 paramètres de connexion](#s3-paramètres-de-connexion)
@@ -43,10 +44,7 @@ ou
- `-P, --password <password>` si l'adresse est fournie, le mot de passe sera cet argument - `-P, --password <password>` si l'adresse est fournie, le mot de passe sera cet argument
- `-b, --address-as-bookmark` résoudre l'argument d'adresse en tant que nom de signet - `-b, --address-as-bookmark` résoudre l'argument d'adresse en tant que nom de signet
- `-c, --config` Ouvrir termscp à partir de la page de configuration
- `-q, --quiet` Désactiver la journalisation - `-q, --quiet` Désactiver la journalisation
- `-t, --theme <path>` Importer le thème spécifié
- `-u, --update` Mettre à jour termscp vers la dernière version
- `-v, --version` Imprimer les informations sur la version - `-v, --version` Imprimer les informations sur la version
- `-h, --help` Imprimer la page d'aide - `-h, --help` Imprimer la page d'aide
@@ -104,6 +102,20 @@ e.g.
s3://buckethead@eu-central-1:default:/assets s3://buckethead@eu-central-1:default:/assets
``` ```
#### Argument d'adresse WebDAV
Dans le cas où vous souhaitez vous connecter à WebDAV, utilisez la syntaxe suivante
```txt
http://<username>:<password>@<url></path>
```
ou dans le cas où vous souhaitez utiliser https
```txt
https://<username>:<password>@<url></path>
```
#### Argument d'adresse SMB #### Argument d'adresse SMB
SMB a une syntaxe différente pour l'argument d'adresse CLI, qui est différente que vous soyez sur Windows ou sur d'autres systèmes : SMB a une syntaxe différente pour l'argument d'adresse CLI, qui est différente que vous soyez sur Windows ou sur d'autres systèmes :
+2 -1
View File
@@ -63,7 +63,7 @@
</p> </p>
<p align="center">Sviluppato da <a href="https://veeso.dev/" target="_blank">@veeso</a></p> <p align="center">Sviluppato da <a href="https://veeso.dev/" target="_blank">@veeso</a></p>
<p align="center">Versione corrente: 0.12.3 (06/10/2023)</p> <p align="center">Versione corrente: 0.13.0 (03/03/2024)</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"
@@ -138,6 +138,7 @@ Termscp è un file transfer ed explorer ricco di funzionalità, con supporto a S
- **FTP** and **FTPS** - **FTP** and **FTPS**
- **S3** - **S3**
- **SMB** - **SMB**
- **WebDAV**
- 🖥 Esplora e opera sia sul file system locale che su quello remoto con una UI di facile utilizzo. - 🖥 Esplora e opera sia sul file system locale che su quello remoto con una UI di facile utilizzo.
- Crea, rimuove, rinomina, cerca, visualizza e modifica file - Crea, rimuove, rinomina, cerca, visualizza e modifica file
- ⭐ Connettiti ai tuoi host preferiti tramite la funzionalità integrata dei segnalibri e delle connessioni recenti. - ⭐ Connettiti ai tuoi host preferiti tramite la funzionalità integrata dei segnalibri e delle connessioni recenti.
+15 -3
View File
@@ -4,6 +4,7 @@
- [Argomenti da linea di comando ❓](#argomenti-da-linea-di-comando-) - [Argomenti da linea di comando ❓](#argomenti-da-linea-di-comando-)
- [Argomento indirizzo 🌎](#argomento-indirizzo-) - [Argomento indirizzo 🌎](#argomento-indirizzo-)
- [Argomento indirizzo per AWS S3](#argomento-indirizzo-per-aws-s3) - [Argomento indirizzo per AWS S3](#argomento-indirizzo-per-aws-s3)
- [Argomento indirizzo per WebDAV](#argomento-indirizzo-per-webdav)
- [Indirizzo SMB](#indirizzo-smb) - [Indirizzo SMB](#indirizzo-smb)
- [Come fornire la password 🔐](#come-fornire-la-password-) - [Come fornire la password 🔐](#come-fornire-la-password-)
- [Parametri di connessione S3](#parametri-di-connessione-s3) - [Parametri di connessione S3](#parametri-di-connessione-s3)
@@ -43,10 +44,7 @@ O
- `-P, --password <password>` Se viene fornito l'argomento indirizzo, questa sarà la password utilizzata per autenticarsi - `-P, --password <password>` Se viene fornito l'argomento indirizzo, questa sarà la password utilizzata per autenticarsi
- `-b, --address-as-bookmark` risolve l'argomento indirizzo come nome di un segnalibro - `-b, --address-as-bookmark` risolve l'argomento indirizzo come nome di un segnalibro
- `-c, --config` Apri la configurazione di termscp
- `-q, --quiet` Disabilita i log - `-q, --quiet` Disabilita i log
- `-t, --theme <path>` Importa il tema al percorso fornito
- `-u, --update` Aggiorna termscp all'ultima versione
- `-v, --version` Mostra a video le informazioni sulla versione attualmente installata - `-v, --version` Mostra a video le informazioni sulla versione attualmente installata
- `-h, --help` Mostra la pagina di aiuto. - `-h, --help` Mostra la pagina di aiuto.
@@ -102,6 +100,20 @@ e.g.
s3://buckethead@eu-central-1:default:/assets s3://buckethead@eu-central-1:default:/assets
``` ```
#### Argomento indirizzo per WebDAV
Nel caso in cui si desideri connettersi a WebDAV utilizzare la seguente sintassi
```txt
http://<username>:<password>@<url></path>
```
oppure nel caso in cui si desideri utilizzare https
```txt
https://<username>:<password>@<url></path>
```
#### Indirizzo SMB #### Indirizzo SMB
SMB ha una sintassi differente rispetto agli altri protocolli e cambia in base al sistema operativo: SMB ha una sintassi differente rispetto agli altri protocolli e cambia in base al sistema operativo:
+28 -3
View File
@@ -4,8 +4,12 @@
- [Usage ❓](#usage-) - [Usage ❓](#usage-)
- [Address argument 🌎](#address-argument-) - [Address argument 🌎](#address-argument-)
- [AWS S3 address argument](#aws-s3-address-argument) - [AWS S3 address argument](#aws-s3-address-argument)
- [WebDAV address argument](#webdav-address-argument)
- [SMB address argument](#smb-address-argument) - [SMB address argument](#smb-address-argument)
- [How Password can be provided 🔐](#how-password-can-be-provided-) - [How Password can be provided 🔐](#how-password-can-be-provided-)
- [Subcommands](#subcommands)
- [Import a theme](#import-a-theme)
- [Install latest version](#install-latest-version)
- [S3 connection parameters](#s3-connection-parameters) - [S3 connection parameters](#s3-connection-parameters)
- [S3 credentials 🦊](#s3-credentials-) - [S3 credentials 🦊](#s3-credentials-)
- [File explorer 📂](#file-explorer-) - [File explorer 📂](#file-explorer-)
@@ -43,10 +47,7 @@ OR
- `-P, --password <password>` if address is provided, password will be this argument - `-P, --password <password>` if address is provided, password will be this argument
- `-b, --address-as-bookmark` resolve address argument as a bookmark name - `-b, --address-as-bookmark` resolve address argument as a bookmark name
- `-c, --config` Open termscp starting from the configuration page
- `-q, --quiet` Disable logging - `-q, --quiet` Disable logging
- `-t, --theme <path>` Import specified theme
- `-u, --update` Update termscp to latest version
- `-v, --version` Print version info - `-v, --version` Print version info
- `-h, --help` Print help page - `-h, --help` Print help page
@@ -104,6 +105,20 @@ e.g.
s3://buckethead@eu-central-1:default:/assets s3://buckethead@eu-central-1:default:/assets
``` ```
#### WebDAV address argument
In case you want to connect to webDAV use the following syntax
```txt
http://<username>:<password>@<url></path>
```
or in case you want to use https
```txt
https://<username>:<password>@<url></path>
```
#### SMB address argument #### SMB address argument
SMB has a different syntax for CLI address argument, which is different whether you're on Windows or other systems: SMB has a different syntax for CLI address argument, which is different whether you're on Windows or other systems:
@@ -129,6 +144,16 @@ Password can be basically provided through 3 ways when address argument is provi
- Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31`
- You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc. - You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc.
### Subcommands
#### Import a theme
Run termscp as `termscp theme <theme-file>`
#### Install latest version
Run termscp as `termscp update`
--- ---
## S3 connection parameters ## S3 connection parameters
+2 -1
View File
@@ -63,7 +63,7 @@
</p> </p>
<p align="center">由 <a href="https://veeso.dev/" target="_blank">@veeso</a> 开发</p> <p align="center">由 <a href="https://veeso.dev/" target="_blank">@veeso</a> 开发</p>
<p align="center">当前版本: 0.12.3 (06/10/2023)</p> <p align="center">当前版本: 0.13.0 (03/03/2024)</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"
@@ -140,6 +140,7 @@ termscp 是一个功能丰富的终端文件浏览和传输工具,支持 SCP/S
- **FTP** and **FTPS** - **FTP** and **FTPS**
- **S3** - **S3**
- **SMB** - **SMB**
- **WebDAV**
- 🖥 使用便捷的 UI 在远程和本地文件系统上浏览和操作 - 🖥 使用便捷的 UI 在远程和本地文件系统上浏览和操作
- 创建、删除、重命名、搜索、查看和编辑文件 - 创建、删除、重命名、搜索、查看和编辑文件
- ⭐ 通过“内置书签”和“最近连接”快速连接到您的主机 - ⭐ 通过“内置书签”和“最近连接”快速连接到您的主机
+14 -2
View File
@@ -4,6 +4,7 @@
- [用法](#用法) - [用法](#用法)
- [地址参数](#地址参数) - [地址参数](#地址参数)
- [AWS S3 地址参数](#aws-s3-地址参数) - [AWS S3 地址参数](#aws-s3-地址参数)
- [WebDAV 地址参数](#webdav-地址参数)
- [SMB 地址参数](#smb-地址参数) - [SMB 地址参数](#smb-地址参数)
- [如何输入密码](#如何输入密码) - [如何输入密码](#如何输入密码)
- [S3 连接参数](#s3-连接参数) - [S3 连接参数](#s3-连接参数)
@@ -43,9 +44,7 @@ termscp启动时可以使用以下选项:
- `-P, --password <password>` 登陆密码 - `-P, --password <password>` 登陆密码
- `-b, --address-as-bookmark` 将地址参数解析为书签名称 - `-b, --address-as-bookmark` 将地址参数解析为书签名称
- `-c, --config` 打开termscp时打开配置页面
- `-q, --quiet` 禁用日志 - `-q, --quiet` 禁用日志
- `-t, --theme <path>` 导入自定义主题
- `-v, --version` 打印版本信息 - `-v, --version` 打印版本信息
- `-h, --help` 打开帮助 - `-h, --help` 打开帮助
@@ -103,6 +102,19 @@ s3://<bucket-name>@<region>[:profile][:/wrkdir]
s3://buckethead@eu-central-1:default:/assets s3://buckethead@eu-central-1:default:/assets
``` ```
#### WebDAV 地址参数
如果您想要连接到 WebDAV,请使用以下语法
```txt
http://<username>:<password>@<url></path>
或者如果您想要使用 https
```
```txt
https://<username>:<password>@<url></path>
```
#### SMB 地址参数 #### SMB 地址参数
SMB 对 CLI 地址参数有不同的语法,无论您是在 Windows 还是其他系统上,这都是不同的: SMB 对 CLI 地址参数有不同的语法,无论您是在 Windows 还是其他系统上,这都是不同的:
+1 -1
View File
@@ -3,7 +3,7 @@
<head> <head>
<title> <title>
termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB | termscp termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB/WebDAV | termscp
</title> </title>
<meta property="og:description" <meta property="og:description"
content="termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. It is Linux, MacOS, FreeBSD, NetBSD and Windows compatible" /> content="termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. It is Linux, MacOS, FreeBSD, NetBSD and Windows compatible" />
+3 -3
View File
@@ -35,7 +35,7 @@
<span translate="getStarted.windows.moderation">Consider that Chocolatey moderation can take up to a few weeks <span translate="getStarted.windows.moderation">Consider that Chocolatey moderation can take up to a few weeks
since last release, so if the latest version is not available yet, since last release, so if the latest version is not available yet,
you can install it downloading the ZIP file from</span> you can install it downloading the ZIP file from</span>
<a href="https://github.com/veeso/termscp/releases/latest/download/termscp.0.12.3.nupkg" <a href="https://github.com/veeso/termscp/releases/latest/download/termscp.0.13.0.nupkg"
target="_blank">Github</a> target="_blank">Github</a>
<span translate="getStarted.windows.then">and then, from the ZIP directory, install it via</span> <span translate="getStarted.windows.then">and then, from the ZIP directory, install it via</span>
</p> </p>
@@ -75,7 +75,7 @@
On Debian based distros, you can install termscp using the Deb On Debian based distros, you can install termscp using the Deb
package via: package via:
</p> </p>
<pre><span class="function">wget</span> -O termscp.deb <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp_0.12.3_amd64.deb</span> <pre><span class="function">wget</span> -O termscp.deb <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp_0.13.0_amd64.deb</span>
sudo <span class="function">dpkg</span> -i <span class="string">termscp.deb</span></pre> sudo <span class="function">dpkg</span> -i <span class="string">termscp.deb</span></pre>
</div> </div>
<h3> <h3>
@@ -87,7 +87,7 @@ sudo <span class="function">dpkg</span> -i <span class="string">termscp.deb</spa
On RedHat based distros, you can install termscp using the RPM On RedHat based distros, you can install termscp using the RPM
package via: package via:
</p> </p>
<pre><span class="function">wget</span> -O termscp.rpm <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp-0.12.3-1.x86_64.rpm</span> <pre><span class="function">wget</span> -O termscp.rpm <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp-0.13.0-1.x86_64.rpm</span>
sudo <span class="function">rpm</span> -U <span class="string">termscp.rpm</span></pre> sudo <span class="function">rpm</span> -U <span class="string">termscp.rpm</span></pre>
</div> </div>
<h3> <h3>
+8 -5
View File
@@ -1,17 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<section id="intro" class="flex flex-col mx-auto items-center justify-center w-full px-4 dark:bg-brand dark:text-gray-100"> <section id="intro"
class="flex flex-col mx-auto items-center justify-center w-full px-4 dark:bg-brand dark:text-gray-100">
<h1 class="text-3xl text-center font-thin">termscp</h1> <h1 class="text-3xl text-center font-thin">termscp</h1>
<img class="w-[256px] h-auto m-auto" alt="logo" src="assets/images/termscp.webp" /> <img class="w-[256px] h-auto m-auto" alt="logo" src="assets/images/termscp.webp" />
<h2 class="text-xl font-thin text-center py-6" translate="intro.caption"> <h2 class="text-xl font-thin text-center py-6" translate="intro.caption">
A feature rich terminal UI file transfer and explorer with support for A feature rich terminal UI file transfer and explorer with support for
SCP/SFTP/FTP/S3/SMB SCP/SFTP/FTP/S3/SMB/WebDAV
</h2> </h2>
<button class="bg-brand hover:bg-gray-800 text-white font-thin text-xl py-2 px-4 rounded-xl max-w-fit"> <button class="bg-brand hover:bg-gray-800 text-white font-thin text-xl py-2 px-4 rounded-xl max-w-fit">
<a href="/get-started.html" class="no-underline" translate="intro.getStarted">Get started →</a> <a href="/get-started.html" class="no-underline" translate="intro.getStarted">Get started →</a>
</button> </button>
<div class="p-4 my-4 text-sm text-green-800 rounded-lg bg-green-50"> <div class="p-4 my-4 text-sm text-green-800 rounded-lg bg-green-50">
<p class="text-lg"> <p class="text-lg">
<span translate="intro.versionAlert">termscp 0.12.3 is NOW out! Download it from</span>&nbsp; <span translate="intro.versionAlert">termscp 0.13.0 is NOW out! Download it from</span>&nbsp;
<a href="/get-started.html" translate="intro.here">here!</a> <a href="/get-started.html" translate="intro.here">here!</a>
</p> </p>
</div> </div>
@@ -66,7 +67,8 @@
<div class="flex flex-row sm:flex-col justify-around gap-12"> <div class="flex flex-row sm:flex-col justify-around gap-12">
<div class="hook"> <div class="hook">
<h3 class="text-center text-gray-500 dark:text-gray-100 font-light text-xl"> <h3 class="text-center text-gray-500 dark:text-gray-100 font-light text-xl">
<a href="/get-started.html" class="no-underline hover:underline" translate="intro.footer.getStarted">Get started</a> <a href="/get-started.html" class="no-underline hover:underline" translate="intro.footer.getStarted">Get
started</a>
</h3> </h3>
</div> </div>
<div class="hook"> <div class="hook">
@@ -76,7 +78,8 @@
</div> </div>
<div class="hook"> <div class="hook">
<h3 class="text-center text-gray-500 dark:text-gray-100 font-light text-xl"> <h3 class="text-center text-gray-500 dark:text-gray-100 font-light text-xl">
<a href="/updates.html" class="no-underline hover:underline" translate="intro.footer.updates">Install updates</a> <a href="/updates.html" class="no-underline hover:underline" translate="intro.footer.updates">Install
updates</a>
</h3> </h3>
</div> </div>
</div> </div>
+5 -4
View File
@@ -3,13 +3,14 @@
<head> <head>
<title> <title>
termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB | termscp termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB/WebDAV | termscp
</title> </title>
<meta property="og:description" <meta property="og:description"
content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/S3/SMB. Command line file transfer with user interface compatible with all the operating systems." /> content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/S3/SMB/WebDAV. Command line file transfer with user interface compatible with all the operating systems." />
<meta name="description" <meta name="description"
content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/S3/SMB. Command line file transfer with user interface compatible with all the operating systems." /> content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/S3/SMB/WebDAV. Command line file transfer with user interface compatible with all the operating systems." />
<meta property="og:title" content="termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB | termscp" /> <meta property="og:title"
content="termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB/WebDAV | termscp" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index, follow" /> <meta name="robots" content="index, follow" />
+1 -1
View File
@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3", "caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3",
"getStarted": "Get started →", "getStarted": "Get started →",
"versionAlert": "termscp 0.12.3 is NOW out! Download it from", "versionAlert": "termscp 0.13.0 is NOW out! Download it from",
"here": "here", "here": "here",
"features": { "features": {
"handy": { "handy": {
+1 -1
View File
@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/S3", "caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/S3",
"getStarted": "Para iniciar →", "getStarted": "Para iniciar →",
"versionAlert": "termscp 0.12.3 ya está disponible! Descárgalo desde", "versionAlert": "termscp 0.13.0 ya está disponible! Descárgalo desde",
"here": "aquì", "here": "aquì",
"features": { "features": {
"handy": { "handy": {
+1 -1
View File
@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/S3", "caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/S3",
"getStarted": "Pour commencer →", "getStarted": "Pour commencer →",
"versionAlert": "termscp 0.12.3 est maintenant sorti! Télécharge-le depuis", "versionAlert": "termscp 0.13.0 est maintenant sorti! Télécharge-le depuis",
"here": "ici", "here": "ici",
"features": { "features": {
"handy": { "handy": {
+1 -1
View File
@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "Un file transfer ed explorer ricco di funzionalità con supporto per SFTP/SCP/FTP/S3", "caption": "Un file transfer ed explorer ricco di funzionalità con supporto per SFTP/SCP/FTP/S3",
"getStarted": "Installa termscp →", "getStarted": "Installa termscp →",
"versionAlert": "termscp 0.12.3 è ORA disponbile! Scaricalo da", "versionAlert": "termscp 0.13.0 è ORA disponbile! Scaricalo da",
"here": "qui", "here": "qui",
"features": { "features": {
"handy": { "handy": {
+1 -1
View File
@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/S3", "caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/S3",
"getStarted": "开始 →", "getStarted": "开始 →",
"versionAlert": "termscp 0.12.3 现已发布! 从下载", "versionAlert": "termscp 0.13.0 现已发布! 从下载",
"here": "这里", "here": "这里",
"features": { "features": {
"handy": { "handy": {
+64 -25
View File
@@ -34,36 +34,25 @@ Address syntax can be:
Please, report issues to <https://github.com/veeso/termscp> Please, report issues to <https://github.com/veeso/termscp>
Please, consider supporting the author <https://ko-fi.com/veeso>")] Please, consider supporting the author <https://ko-fi.com/veeso>")]
pub struct Args { pub struct Args {
#[argh( #[argh(subcommand)]
switch, pub nested: Option<ArgsSubcommands>,
short = 'b', /// resolve address argument as a bookmark name
description = "resolve address argument as a bookmark name" #[argh(switch, short = 'b')]
)]
pub address_as_bookmark: bool, pub address_as_bookmark: bool,
#[argh(switch, short = 'c', description = "open termscp configuration")] /// enable TRACE log level
pub config: bool, #[argh(switch, short = 'D')]
#[argh(switch, short = 'D', description = "enable TRACE log level")]
pub debug: bool, pub debug: bool,
#[argh(option, short = 'P', description = "provide password from CLI")] /// provide password from CLI
#[argh(option, short = 'P')]
pub password: Option<String>, pub password: Option<String>,
#[argh(switch, short = 'q', description = "disable logging")] /// disable logging
#[argh(switch, short = 'q')]
pub quiet: bool, pub quiet: bool,
#[argh(option, short = 't', description = "import specified theme")] /// set UI ticks; default 10ms
pub theme: Option<String>, #[argh(option, short = 'T', default = "10")]
#[argh(
switch,
short = 'u',
description = "update termscp to the latest version"
)]
pub update: bool,
#[argh(
option,
short = 'T',
default = "10",
description = "set UI ticks; default 10ms"
)]
pub ticks: u64, pub ticks: u64,
#[argh(switch, short = 'v', description = "print version")] /// print version
#[argh(switch, short = 'v')]
pub version: bool, pub version: bool,
// -- positional // -- positional
#[argh( #[argh(
@@ -73,6 +62,33 @@ pub struct Args {
pub positional: Vec<String>, pub positional: Vec<String>,
} }
#[derive(FromArgs)]
#[argh(subcommand)]
pub enum ArgsSubcommands {
Config(ConfigArgs),
LoadTheme(LoadThemeArgs),
Update(UpdateArgs),
}
#[derive(FromArgs)]
/// open termscp configuration
#[argh(subcommand, name = "config")]
pub struct ConfigArgs {}
#[derive(FromArgs)]
/// import the specified theme
#[argh(subcommand, name = "update")]
pub struct UpdateArgs {}
#[derive(FromArgs)]
/// import the specified theme
#[argh(subcommand, name = "theme")]
pub struct LoadThemeArgs {
#[argh(positional)]
/// theme file
pub theme: PathBuf,
}
pub struct RunOpts { pub struct RunOpts {
pub remote: Remote, pub remote: Remote,
pub ticks: Duration, pub ticks: Duration,
@@ -80,6 +96,29 @@ pub struct RunOpts {
pub task: Task, pub task: Task,
} }
impl RunOpts {
pub fn config() -> Self {
Self {
task: Task::Activity(NextActivity::SetupActivity),
..Default::default()
}
}
pub fn update() -> Self {
Self {
task: Task::InstallUpdate,
..Default::default()
}
}
pub fn import_theme(theme: PathBuf) -> Self {
Self {
task: Task::ImportTheme(theme),
..Default::default()
}
}
}
impl Default for RunOpts { impl Default for RunOpts {
fn default() -> Self { fn default() -> Self {
Self { Self {
+49
View File
@@ -11,6 +11,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::filetransfer::params::{ use crate::filetransfer::params::{
AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams as TransferSmbParams, AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams as TransferSmbParams,
WebDAVProtocolParams,
}; };
use crate::filetransfer::{FileTransferParams, FileTransferProtocol}; use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
@@ -114,6 +115,17 @@ impl From<FileTransferParams> for Bookmark {
local_path, local_path,
s3: None, s3: None,
}, },
ProtocolParams::WebDAV(parms) => Self {
protocol,
address: Some(parms.uri),
port: None,
username: Some(parms.username),
password: Some(parms.password),
remote_path,
local_path,
s3: None,
smb: None,
},
} }
} }
} }
@@ -161,6 +173,14 @@ impl From<Bookmark> for FileTransferParams {
Self::new(bookmark.protocol, ProtocolParams::Smb(params)) Self::new(bookmark.protocol, ProtocolParams::Smb(params))
} }
FileTransferProtocol::WebDAV => Self::new(
FileTransferProtocol::WebDAV,
ProtocolParams::WebDAV(WebDAVProtocolParams {
uri: bookmark.address.unwrap_or_default(),
username: bookmark.username.unwrap_or_default(),
password: bookmark.password.unwrap_or_default(),
}),
),
} }
.remote_path(bookmark.remote_path) // Set entry remote_path .remote_path(bookmark.remote_path) // Set entry remote_path
.local_path(bookmark.local_path) // Set entry local path .local_path(bookmark.local_path) // Set entry local path
@@ -390,6 +410,35 @@ mod tests {
assert_eq!(gparams.password.as_deref().unwrap(), "password"); assert_eq!(gparams.password.as_deref().unwrap(), "password");
} }
#[test]
fn ftparams_from_webdav() {
let bookmark: Bookmark = Bookmark {
address: Some(String::from("192.168.1.1")),
port: None,
protocol: FileTransferProtocol::WebDAV,
username: Some(String::from("root")),
password: Some(String::from("password")),
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
s3: None,
smb: None,
};
let params = FileTransferParams::from(bookmark);
assert_eq!(params.protocol, FileTransferProtocol::WebDAV);
assert_eq!(
params.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
params.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let gparams = params.params.webdav_params().unwrap();
assert_eq!(gparams.uri.as_str(), "192.168.1.1");
assert_eq!(gparams.username, "root");
assert_eq!(gparams.password, "password");
}
#[test] #[test]
fn ftparams_from_s3_bookmark() { fn ftparams_from_s3_bookmark() {
let bookmark: Bookmark = Bookmark { let bookmark: Bookmark = Bookmark {
-1
View File
@@ -3,7 +3,6 @@
//! `config` is the module which provides access to all the termscp configurations //! `config` is the module which provides access to all the termscp configurations
// export // export
pub use params::*;
pub mod bookmarks; pub mod bookmarks;
pub mod params; pub mod params;
+9
View File
@@ -12,7 +12,9 @@ use remotefs_smb::SmbOptions;
#[cfg(smb)] #[cfg(smb)]
use remotefs_smb::{SmbCredentials, SmbFs}; use remotefs_smb::{SmbCredentials, SmbFs};
use remotefs_ssh::{ScpFs, SftpFs, SshConfigParseRule, SshOpts}; use remotefs_ssh::{ScpFs, SftpFs, SshConfigParseRule, SshOpts};
use remotefs_webdav::WebDAVFs;
use super::params::WebDAVProtocolParams;
#[cfg(not(smb))] #[cfg(not(smb))]
use super::params::{AwsS3Params, GenericProtocolParams}; use super::params::{AwsS3Params, GenericProtocolParams};
#[cfg(smb)] #[cfg(smb)]
@@ -51,6 +53,9 @@ impl Builder {
(FileTransferProtocol::Smb, ProtocolParams::Smb(params)) => { (FileTransferProtocol::Smb, ProtocolParams::Smb(params)) => {
Box::new(Self::smb_client(params)) Box::new(Self::smb_client(params))
} }
(FileTransferProtocol::WebDAV, ProtocolParams::WebDAV(params)) => {
Box::new(Self::webdav_client(params))
}
(protocol, params) => { (protocol, params) => {
error!("Invalid params for protocol '{:?}'", protocol); error!("Invalid params for protocol '{:?}'", protocol);
panic!("Invalid protocol '{protocol:?}' with parameters of type {params:?}") panic!("Invalid protocol '{protocol:?}' with parameters of type {params:?}")
@@ -154,6 +159,10 @@ impl Builder {
SmbFs::new(credentials) SmbFs::new(credentials)
} }
fn webdav_client(params: WebDAVProtocolParams) -> WebDAVFs {
WebDAVFs::new(&params.username, &params.password, &params.uri)
}
/// Build ssh options from generic protocol params and client configuration /// Build ssh options from generic protocol params and client configuration
fn build_ssh_opts(params: GenericProtocolParams, config_client: &ConfigClient) -> SshOpts { fn build_ssh_opts(params: GenericProtocolParams, config_client: &ConfigClient) -> SshOpts {
let mut opts = SshOpts::new(params.address.clone()) let mut opts = SshOpts::new(params.address.clone())
+11
View File
@@ -18,6 +18,7 @@ pub enum FileTransferProtocol {
Scp, Scp,
Sftp, Sftp,
Smb, Smb,
WebDAV,
} }
// Traits // Traits
@@ -33,6 +34,7 @@ impl std::string::ToString for FileTransferProtocol {
FileTransferProtocol::Scp => "SCP", FileTransferProtocol::Scp => "SCP",
FileTransferProtocol::Sftp => "SFTP", FileTransferProtocol::Sftp => "SFTP",
FileTransferProtocol::Smb => "SMB", FileTransferProtocol::Smb => "SMB",
FileTransferProtocol::WebDAV => "WEBDAV",
}) })
} }
} }
@@ -47,6 +49,7 @@ impl std::str::FromStr for FileTransferProtocol {
"SCP" => Ok(FileTransferProtocol::Scp), "SCP" => Ok(FileTransferProtocol::Scp),
"SFTP" => Ok(FileTransferProtocol::Sftp), "SFTP" => Ok(FileTransferProtocol::Sftp),
"SMB" => Ok(FileTransferProtocol::Smb), "SMB" => Ok(FileTransferProtocol::Smb),
"WEBDAV" | "HTTP" | "HTTPS" => Ok(FileTransferProtocol::WebDAV),
_ => Err(s.to_string()), _ => Err(s.to_string()),
} }
} }
@@ -134,9 +137,17 @@ mod tests {
FileTransferProtocol::Ftp(false).to_string(), FileTransferProtocol::Ftp(false).to_string(),
String::from("FTP") String::from("FTP")
); );
assert_eq!(
FileTransferProtocol::WebDAV.to_string(),
String::from("WEBDAV")
);
assert_eq!(FileTransferProtocol::Scp.to_string(), String::from("SCP")); assert_eq!(FileTransferProtocol::Scp.to_string(), String::from("SCP"));
assert_eq!(FileTransferProtocol::Sftp.to_string(), String::from("SFTP")); assert_eq!(FileTransferProtocol::Sftp.to_string(), String::from("SFTP"));
assert_eq!(FileTransferProtocol::AwsS3.to_string(), String::from("S3")); assert_eq!(FileTransferProtocol::AwsS3.to_string(), String::from("S3"));
assert_eq!(FileTransferProtocol::Smb.to_string(), String::from("SMB")); assert_eq!(FileTransferProtocol::Smb.to_string(), String::from("SMB"));
assert_eq!(
FileTransferProtocol::WebDAV.to_string(),
String::from("WEBDAV")
);
} }
} }
+64
View File
@@ -21,6 +21,7 @@ pub enum ProtocolParams {
Generic(GenericProtocolParams), Generic(GenericProtocolParams),
AwsS3(AwsS3Params), AwsS3(AwsS3Params),
Smb(SmbParams), Smb(SmbParams),
WebDAV(WebDAVProtocolParams),
} }
/// Protocol params used by most common protocols /// Protocol params used by most common protocols
@@ -89,6 +90,7 @@ impl FileTransferParams {
ProtocolParams::AwsS3(params) => params.password_missing(), ProtocolParams::AwsS3(params) => params.password_missing(),
ProtocolParams::Generic(params) => params.password_missing(), ProtocolParams::Generic(params) => params.password_missing(),
ProtocolParams::Smb(params) => params.password_missing(), ProtocolParams::Smb(params) => params.password_missing(),
ProtocolParams::WebDAV(params) => params.password_missing(),
} }
} }
@@ -98,10 +100,29 @@ impl FileTransferParams {
ProtocolParams::AwsS3(params) => params.set_default_secret(secret), ProtocolParams::AwsS3(params) => params.set_default_secret(secret),
ProtocolParams::Generic(params) => params.set_default_secret(secret), ProtocolParams::Generic(params) => params.set_default_secret(secret),
ProtocolParams::Smb(params) => params.set_default_secret(secret), ProtocolParams::Smb(params) => params.set_default_secret(secret),
ProtocolParams::WebDAV(params) => params.set_default_secret(secret),
} }
} }
} }
/// Protocol params used by WebDAV
#[derive(Debug, Clone)]
pub struct WebDAVProtocolParams {
pub uri: String,
pub username: String,
pub password: String,
}
impl WebDAVProtocolParams {
fn set_default_secret(&mut self, secret: String) {
self.password = secret;
}
fn password_missing(&self) -> bool {
self.password.is_empty()
}
}
impl Default for FileTransferParams { impl Default for FileTransferParams {
fn default() -> Self { fn default() -> Self {
Self::new(FileTransferProtocol::Sftp, ProtocolParams::default()) Self::new(FileTransferProtocol::Sftp, ProtocolParams::default())
@@ -149,6 +170,15 @@ impl ProtocolParams {
_ => None, _ => None,
} }
} }
#[cfg(test)]
/// Retrieve WebDAV parameters if any
pub fn webdav_params(&self) -> Option<&WebDAVProtocolParams> {
match self {
ProtocolParams::WebDAV(params) => Some(params),
_ => None,
}
}
} }
// -- Generic protocol params // -- Generic protocol params
@@ -512,6 +542,40 @@ mod test {
); );
} }
#[test]
#[cfg(unix)]
fn set_default_secret_smb() {
let mut params = FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::Smb(SmbParams::new("localhost", "temp")),
);
params.set_default_secret(String::from("secret"));
assert_eq!(
params
.params
.smb_params()
.unwrap()
.password
.as_deref()
.unwrap(),
"secret"
);
}
#[test]
fn set_default_secret_webdav() {
let mut params = FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::WebDAV(WebDAVProtocolParams {
uri: "http://localhost".to_string(),
username: "user".to_string(),
password: "pass".to_string(),
}),
);
params.set_default_secret(String::from("secret"));
assert_eq!(params.params.webdav_params().unwrap().password, "secret");
}
#[test] #[test]
fn set_default_secret_generic() { fn set_default_secret_generic() {
let mut params = let mut params =
+1 -4
View File
@@ -1081,10 +1081,7 @@ mod tests {
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap(); let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
let host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap(); let host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
// Execute // Execute
#[cfg(unix)] assert!(host.exec("echo 5").ok().unwrap().as_str().contains("5"));
assert_eq!(host.exec("echo 5").ok().unwrap().as_str(), "5\n");
#[cfg(windows)]
assert_eq!(host.exec("echo 5").ok().unwrap().as_str(), "5\r\n");
} }
#[test] #[test]
+46 -47
View File
@@ -32,7 +32,7 @@ mod utils;
// namespaces // namespaces
use activity_manager::{ActivityManager, NextActivity}; use activity_manager::{ActivityManager, NextActivity};
use cli_opts::{Args, BookmarkParams, HostParams, Remote, RunOpts, Task}; use cli_opts::{Args, ArgsSubcommands, BookmarkParams, HostParams, Remote, RunOpts, Task};
use filetransfer::FileTransferParams; use filetransfer::FileTransferParams;
use system::logging::{self, LogLevel}; use system::logging::{self, LogLevel};
@@ -63,59 +63,57 @@ fn main() {
/// In case of success returns `RunOpts` /// In case of success returns `RunOpts`
/// in case something is wrong returns the error message /// in case something is wrong returns the error message
fn parse_args(args: Args) -> Result<RunOpts, String> { fn parse_args(args: Args) -> Result<RunOpts, String> {
let mut run_opts: RunOpts = RunOpts::default(); let run_opts = match args.nested {
// Version Some(ArgsSubcommands::Update(_)) => RunOpts::update(),
if args.version { Some(ArgsSubcommands::LoadTheme(args)) => RunOpts::import_theme(args.theme),
return Err(format!( Some(ArgsSubcommands::Config(_)) => RunOpts::config(),
"termscp - {TERMSCP_VERSION} - Developed by {TERMSCP_AUTHORS}", None => {
)); let mut run_opts: RunOpts = RunOpts::default();
} // Version
// Setup activity? if args.version {
if args.config { return Err(format!(
run_opts.task = Task::Activity(NextActivity::SetupActivity); "termscp - {TERMSCP_VERSION} - Developed by {TERMSCP_AUTHORS}",
} ));
// Logging }
if args.debug { // Logging
run_opts.log_level = LogLevel::Trace; if args.debug {
} else if args.quiet { run_opts.log_level = LogLevel::Trace;
run_opts.log_level = LogLevel::Off; } else if args.quiet {
} run_opts.log_level = LogLevel::Off;
// Match ticks }
run_opts.ticks = Duration::from_millis(args.ticks); // Match ticks
// @! extra modes run_opts.ticks = Duration::from_millis(args.ticks);
if let Some(theme) = args.theme.as_deref() { // Remote argument
run_opts.task = Task::ImportTheme(PathBuf::from(theme)); match parse_address_arg(&args) {
} Err(err) => return Err(err),
if args.update { Ok(Remote::None) => {}
run_opts.task = Task::InstallUpdate; Ok(remote) => {
} // Set params
// @! Ordinary mode run_opts.remote = remote;
// Remote argument // In this case the first activity will be FileTransfer
match parse_address_arg(&args) { run_opts.task = Task::Activity(NextActivity::FileTransfer);
Err(err) => return Err(err), }
Ok(Remote::None) => {} }
Ok(remote) => {
// Set params
run_opts.remote = remote;
// In this case the first activity will be FileTransfer
run_opts.task = Task::Activity(NextActivity::FileTransfer);
}
}
// Local directory // Local directory
if let Some(localdir) = args.positional.get(1) { if let Some(localdir) = args.positional.get(1) {
// Change working directory if local dir is set // Change working directory if local dir is set
let localdir: PathBuf = PathBuf::from(localdir); let localdir: PathBuf = PathBuf::from(localdir);
if let Err(err) = env::set_current_dir(localdir.as_path()) { if let Err(err) = env::set_current_dir(localdir.as_path()) {
return Err(format!("Bad working directory argument: {err}")); return Err(format!("Bad working directory argument: {err}"));
}
}
run_opts
} }
} };
Ok(run_opts) Ok(run_opts)
} }
/// Parse address argument from cli args /// Parse address argument from cli args
fn parse_address_arg(args: &Args) -> Result<Remote, String> { fn parse_address_arg(args: &Args) -> Result<Remote, String> {
if let Some(remote) = args.positional.get(0) { if let Some(remote) = args.positional.first() {
if args.address_as_bookmark { if args.address_as_bookmark {
Ok(Remote::Bookmark(BookmarkParams::new( Ok(Remote::Bookmark(BookmarkParams::new(
remote, remote,
@@ -197,5 +195,6 @@ fn run_activity(activity: NextActivity, ticks: Duration, remote: Remote) -> i32
Remote::None => {} Remote::None => {}
} }
manager.run(activity); manager.run(activity);
0 0
} }
+1 -1
View File
@@ -419,7 +419,7 @@ mod tests {
use tempfile::TempDir; use tempfile::TempDir;
use super::*; use super::*;
use crate::config::UserConfig; use crate::config::params::UserConfig;
use crate::utils::random::random_alphanumeric_with_len; use crate::utils::random::random_alphanumeric_with_len;
#[test] #[test]
+1 -1
View File
@@ -48,7 +48,7 @@ impl SshKeyStorage {
.query(host) .query(host)
.identity_file .identity_file
.as_ref() .as_ref()
.and_then(|x| x.get(0).cloned()); .and_then(|x| x.first().cloned());
key key
}) })
+10 -1
View File
@@ -4,7 +4,9 @@
// Locals // Locals
use super::{AuthActivity, FileTransferParams}; use super::{AuthActivity, FileTransferParams};
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams}; use crate::filetransfer::params::{
AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams, WebDAVProtocolParams,
};
impl AuthActivity { impl AuthActivity {
/// Delete bookmark /// Delete bookmark
@@ -164,6 +166,7 @@ impl AuthActivity {
ProtocolParams::AwsS3(params) => self.load_bookmark_s3_into_gui(params), ProtocolParams::AwsS3(params) => self.load_bookmark_s3_into_gui(params),
ProtocolParams::Generic(params) => self.load_bookmark_generic_into_gui(params), ProtocolParams::Generic(params) => self.load_bookmark_generic_into_gui(params),
ProtocolParams::Smb(params) => self.load_bookmark_smb_into_gui(params), ProtocolParams::Smb(params) => self.load_bookmark_smb_into_gui(params),
ProtocolParams::WebDAV(params) => self.load_bookmark_webdav_into_gui(params),
} }
} }
@@ -196,4 +199,10 @@ impl AuthActivity {
#[cfg(unix)] #[cfg(unix)]
self.mount_smb_workgroup(params.workgroup.as_deref().unwrap_or("")); self.mount_smb_workgroup(params.workgroup.as_deref().unwrap_or(""));
} }
fn load_bookmark_webdav_into_gui(&mut self, params: WebDAVProtocolParams) {
self.mount_webdav_uri(&params.uri);
self.mount_username(&params.username);
self.mount_password(&params.password);
}
} }
+42 -3
View File
@@ -11,7 +11,7 @@ use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue};
use super::{FileTransferProtocol, FormMsg, Msg, UiMsg}; use super::{FileTransferProtocol, FormMsg, Msg, UiMsg};
use crate::ui::activities::auth::{ use crate::ui::activities::auth::{
RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP, RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP,
RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV,
}; };
// -- protocol // -- protocol
@@ -31,9 +31,9 @@ impl ProtocolRadio {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(if cfg!(smb) { .choices(if cfg!(smb) {
&["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB"] &["SFTP", "SCP", "FTP", "FTPS", "S3", "WebDAV", "SMB"]
} else { } else {
&["SFTP", "SCP", "FTP", "FTPS", "S3"] &["SFTP", "SCP", "FTP", "FTPS", "S3", "WebDAV"]
}) })
.foreground(color) .foreground(color)
.rewind(true) .rewind(true)
@@ -50,6 +50,7 @@ impl ProtocolRadio {
RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true), RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true),
RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3, RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3,
RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb, RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb,
RADIO_PROTOCOL_WEBDAV => FileTransferProtocol::WebDAV,
_ => FileTransferProtocol::Sftp, _ => FileTransferProtocol::Sftp,
} }
} }
@@ -63,6 +64,7 @@ impl ProtocolRadio {
FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS, FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS,
FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3, FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3,
FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB, FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB,
FileTransferProtocol::WebDAV => RADIO_PROTOCOL_WEBDAV,
} }
} }
} }
@@ -788,3 +790,40 @@ impl Component<Msg, NoUserEvent> for InputSmbWorkgroup {
) )
} }
} }
#[derive(MockComponent)]
pub struct InputWebDAVUri {
component: Input,
}
impl InputWebDAVUri {
pub fn new(host: &str, color: Color) -> Self {
Self {
component: Input::default()
.borders(
Borders::default()
.color(color)
.modifiers(BorderType::Rounded),
)
.foreground(color)
.placeholder(
"http://localhost:8080",
Style::default().fg(Color::Rgb(128, 128, 128)),
)
.title("HTTP url", Alignment::Left)
.input_type(InputType::Text)
.value(host),
}
}
}
impl Component<Msg, NoUserEvent> for InputWebDAVUri {
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
handle_input_ev(
self,
ev,
Msg::Ui(UiMsg::WebDAVUriBlurDown),
Msg::Ui(UiMsg::WebDAVUriBlurUp),
)
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ pub use form::{
InputAddress, InputLocalDirectory, InputPassword, InputPort, InputRemoteDirectory, InputAddress, InputLocalDirectory, InputPassword, InputPort, InputRemoteDirectory,
InputS3AccessKey, InputS3Bucket, InputS3Endpoint, InputS3Profile, InputS3Region, InputS3AccessKey, InputS3Bucket, InputS3Endpoint, InputS3Profile, InputS3Region,
InputS3SecretAccessKey, InputS3SecurityToken, InputS3SessionToken, InputSmbShare, InputS3SecretAccessKey, InputS3SecurityToken, InputS3SessionToken, InputSmbShare,
InputUsername, ProtocolRadio, RadioS3NewPathStyle, InputUsername, InputWebDAVUri, ProtocolRadio, RadioS3NewPathStyle,
}; };
pub use popup::{ pub use popup::{
ErrorPopup, InfoPopup, InstallUpdatePopup, Keybindings, QuitPopup, ReleaseNotes, WaitPopup, ErrorPopup, InfoPopup, InstallUpdatePopup, Keybindings, QuitPopup, ReleaseNotes, WaitPopup,
+15
View File
@@ -15,6 +15,7 @@ impl AuthActivity {
FileTransferProtocol::Ftp(_) => 21, FileTransferProtocol::Ftp(_) => 21,
FileTransferProtocol::AwsS3 => 22, // Doesn't matter, since not used FileTransferProtocol::AwsS3 => 22, // Doesn't matter, since not used
FileTransferProtocol::Smb => 445, FileTransferProtocol::Smb => 445,
FileTransferProtocol::WebDAV => 80, // Doesn't matter, since not used
} }
} }
@@ -41,6 +42,7 @@ impl AuthActivity {
FileTransferProtocol::Ftp(_) FileTransferProtocol::Ftp(_)
| FileTransferProtocol::Scp | FileTransferProtocol::Scp
| FileTransferProtocol::Sftp => self.collect_generic_host_params(self.protocol), | FileTransferProtocol::Sftp => self.collect_generic_host_params(self.protocol),
FileTransferProtocol::WebDAV => self.collect_webdav_host_params(),
} }
} }
@@ -98,6 +100,19 @@ impl AuthActivity {
}) })
} }
pub(super) fn collect_webdav_host_params(&self) -> Result<FileTransferParams, &'static str> {
let params = self.get_webdav_params_input();
if params.uri.is_empty() {
return Err("Invalid URI");
}
Ok(FileTransferParams {
protocol: FileTransferProtocol::WebDAV,
params: ProtocolParams::WebDAV(params),
local_path: self.get_input_local_directory(),
remote_path: self.get_input_remote_directory(),
})
}
// -- update install // -- update install
/// If enabled in configuration, check for updates from Github /// If enabled in configuration, check for updates from Github
+7 -1
View File
@@ -29,7 +29,8 @@ const RADIO_PROTOCOL_SCP: usize = 1;
const RADIO_PROTOCOL_FTP: usize = 2; const RADIO_PROTOCOL_FTP: usize = 2;
const RADIO_PROTOCOL_FTPS: usize = 3; const RADIO_PROTOCOL_FTPS: usize = 3;
const RADIO_PROTOCOL_S3: usize = 4; const RADIO_PROTOCOL_S3: usize = 4;
const RADIO_PROTOCOL_SMB: usize = 5; const RADIO_PROTOCOL_WEBDAV: usize = 5;
const RADIO_PROTOCOL_SMB: usize = 6;
// -- components // -- components
#[derive(Debug, Eq, PartialEq, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
@@ -71,6 +72,7 @@ pub enum Id {
Title, Title,
Username, Username,
WaitPopup, WaitPopup,
WebDAVUri,
WindowSizeError, WindowSizeError,
} }
@@ -155,6 +157,8 @@ pub enum UiMsg {
ShowSaveBookmarkPopup, ShowSaveBookmarkPopup,
UsernameBlurDown, UsernameBlurDown,
UsernameBlurUp, UsernameBlurUp,
WebDAVUriBlurDown,
WebDAVUriBlurUp,
WindowResized, WindowResized,
} }
@@ -164,6 +168,7 @@ enum InputMask {
Generic, Generic,
AwsS3, AwsS3,
Smb, Smb,
WebDAV,
} }
// Store keys // Store keys
@@ -240,6 +245,7 @@ impl AuthActivity {
| FileTransferProtocol::Scp | FileTransferProtocol::Scp
| FileTransferProtocol::Sftp => InputMask::Generic, | FileTransferProtocol::Sftp => InputMask::Generic,
FileTransferProtocol::Smb => InputMask::Smb, FileTransferProtocol::Smb => InputMask::Smb,
FileTransferProtocol::WebDAV => InputMask::WebDAV,
} }
} }
} }
+14 -1
View File
@@ -70,6 +70,7 @@ impl AuthActivity {
InputMask::Generic => &Id::Password, InputMask::Generic => &Id::Password,
InputMask::Smb => &Id::Password, InputMask::Smb => &Id::Password,
InputMask::AwsS3 => &Id::S3Bucket, InputMask::AwsS3 => &Id::S3Bucket,
InputMask::WebDAV => &Id::Password,
}) })
.is_ok()); .is_ok());
} }
@@ -82,6 +83,7 @@ impl AuthActivity {
InputMask::Generic => &Id::Password, InputMask::Generic => &Id::Password,
InputMask::Smb => &Id::Password, InputMask::Smb => &Id::Password,
InputMask::AwsS3 => &Id::S3Bucket, InputMask::AwsS3 => &Id::S3Bucket,
InputMask::WebDAV => &Id::Password,
}) })
.is_ok()); .is_ok());
} }
@@ -177,6 +179,7 @@ impl AuthActivity {
#[cfg(windows)] #[cfg(windows)]
InputMask::Smb => &Id::RemoteDirectory, InputMask::Smb => &Id::RemoteDirectory,
InputMask::AwsS3 => panic!("this shouldn't happen (password on s3)"), InputMask::AwsS3 => panic!("this shouldn't happen (password on s3)"),
InputMask::WebDAV => &Id::RemoteDirectory,
}) })
.is_ok()); .is_ok());
} }
@@ -189,7 +192,8 @@ impl AuthActivity {
.active(match self.input_mask() { .active(match self.input_mask() {
InputMask::Generic => &Id::Username, InputMask::Generic => &Id::Username,
InputMask::Smb => &Id::SmbShare, InputMask::Smb => &Id::SmbShare,
InputMask::AwsS3 => panic!("this shouldn't happen (port on s3)"), InputMask::AwsS3 | InputMask::WebDAV =>
panic!("this shouldn't happen (port on s3)"),
}) })
.is_ok()); .is_ok());
} }
@@ -203,6 +207,7 @@ impl AuthActivity {
InputMask::Generic => &Id::Address, InputMask::Generic => &Id::Address,
InputMask::Smb => &Id::Address, InputMask::Smb => &Id::Address,
InputMask::AwsS3 => &Id::S3Bucket, InputMask::AwsS3 => &Id::S3Bucket,
InputMask::WebDAV => &Id::WebDAVUri,
}) })
.is_ok()); .is_ok());
} }
@@ -225,6 +230,7 @@ impl AuthActivity {
#[cfg(windows)] #[cfg(windows)]
InputMask::Smb => &Id::Password, InputMask::Smb => &Id::Password,
InputMask::AwsS3 => &Id::S3NewPathStyle, InputMask::AwsS3 => &Id::S3NewPathStyle,
InputMask::WebDAV => &Id::Password,
}) })
.is_ok()); .is_ok());
} }
@@ -332,9 +338,16 @@ impl AuthActivity {
InputMask::Generic => &Id::Port, InputMask::Generic => &Id::Port,
InputMask::Smb => &Id::SmbShare, InputMask::Smb => &Id::SmbShare,
InputMask::AwsS3 => panic!("this shouldn't happen (username on s3)"), InputMask::AwsS3 => panic!("this shouldn't happen (username on s3)"),
InputMask::WebDAV => &Id::WebDAVUri,
}) })
.is_ok()); .is_ok());
} }
UiMsg::WebDAVUriBlurDown => {
assert!(self.app.active(&Id::Username).is_ok());
}
UiMsg::WebDAVUriBlurUp => {
assert!(self.app.active(&Id::Protocol).is_ok());
}
UiMsg::WindowResized => { UiMsg::WindowResized => {
self.redraw = true; self.redraw = true;
} }
+73 -1
View File
@@ -12,7 +12,9 @@ use tuirealm::tui::widgets::Clear;
use tuirealm::{State, StateValue, Sub, SubClause, SubEventClause}; use tuirealm::{State, StateValue, Sub, SubClause, SubEventClause};
use super::{components, AuthActivity, Context, FileTransferProtocol, Id, InputMask}; use super::{components, AuthActivity, Context, FileTransferProtocol, Id, InputMask};
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams}; use crate::filetransfer::params::{
AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams, WebDAVProtocolParams,
};
use crate::filetransfer::FileTransferParams; use crate::filetransfer::FileTransferParams;
use crate::utils::ui::{Popup, Size}; use crate::utils::ui::{Popup, Size};
@@ -61,6 +63,7 @@ impl AuthActivity {
self.mount_smb_share(""); self.mount_smb_share("");
#[cfg(unix)] #[cfg(unix)]
self.mount_smb_workgroup(""); self.mount_smb_workgroup("");
self.mount_webdav_uri("");
// Version notice // Version notice
if let Some(version) = self if let Some(version) = self
.context() .context()
@@ -195,6 +198,18 @@ impl AuthActivity {
) )
.direction(Direction::Vertical) .direction(Direction::Vertical)
.split(auth_chunks[4]), .split(auth_chunks[4]),
InputMask::WebDAV => Layout::default()
.constraints(
[
Constraint::Length(3), // uri
Constraint::Length(3), // username
Constraint::Length(3), // password
Constraint::Length(3), // dir
]
.as_ref(),
)
.direction(Direction::Vertical)
.split(auth_chunks[4]),
}; };
// Create bookmark chunks // Create bookmark chunks
let bookmark_chunks = Layout::default() let bookmark_chunks = Layout::default()
@@ -230,6 +245,13 @@ impl AuthActivity {
self.app.view(&view_ids[2], f, input_mask[2]); self.app.view(&view_ids[2], f, input_mask[2]);
self.app.view(&view_ids[3], f, input_mask[3]); self.app.view(&view_ids[3], f, input_mask[3]);
} }
InputMask::WebDAV => {
let view_ids = self.get_webdav_view();
self.app.view(&view_ids[0], f, input_mask[0]);
self.app.view(&view_ids[1], f, input_mask[1]);
self.app.view(&view_ids[2], f, input_mask[2]);
self.app.view(&view_ids[3], f, input_mask[3]);
}
} }
// Bookmark chunks // Bookmark chunks
self.app.view(&Id::BookmarksList, f, bookmark_chunks[0]); self.app.view(&Id::BookmarksList, f, bookmark_chunks[0]);
@@ -794,6 +816,18 @@ impl AuthActivity {
.is_ok()); .is_ok());
} }
pub(super) fn mount_webdav_uri(&mut self, uri: &str) {
let addr_color = self.theme().auth_address;
assert!(self
.app
.remount(
Id::WebDAVUri,
Box::new(components::InputWebDAVUri::new(uri, addr_color)),
vec![]
)
.is_ok());
}
// -- query // -- query
/// Collect input values from view /// Collect input values from view
@@ -860,6 +894,18 @@ impl AuthActivity {
.password(password) .password(password)
} }
pub(super) fn get_webdav_params_input(&self) -> WebDAVProtocolParams {
let uri: String = self.get_webdav_uri();
let username = self.get_input_username().unwrap_or_default();
let password = self.get_input_password().unwrap_or_default();
WebDAVProtocolParams {
uri,
username,
password,
}
}
pub(super) fn get_input_remote_directory(&self) -> Option<PathBuf> { pub(super) fn get_input_remote_directory(&self) -> Option<PathBuf> {
match self.app.state(&Id::RemoteDirectory) { match self.app.state(&Id::RemoteDirectory) {
Ok(State::One(StateValue::String(x))) if !x.is_empty() => { Ok(State::One(StateValue::String(x))) if !x.is_empty() => {
@@ -878,6 +924,13 @@ impl AuthActivity {
} }
} }
pub(super) fn get_webdav_uri(&self) -> String {
match self.app.state(&Id::WebDAVUri) {
Ok(State::One(StateValue::String(x))) => x,
_ => String::new(),
}
}
pub(super) fn get_input_addr(&self) -> String { pub(super) fn get_input_addr(&self) -> String {
match self.app.state(&Id::Address) { match self.app.state(&Id::Address) {
Ok(State::One(StateValue::String(x))) => x, Ok(State::One(StateValue::String(x))) => x,
@@ -1011,6 +1064,7 @@ impl AuthActivity {
InputMask::AwsS3 => 12, InputMask::AwsS3 => 12,
InputMask::Generic => 12, InputMask::Generic => 12,
InputMask::Smb => 12, InputMask::Smb => 12,
InputMask::WebDAV => 12,
} }
} }
@@ -1069,6 +1123,7 @@ impl AuthActivity {
}; };
format!("\\\\{username}{}\\{}", params.address, params.share) format!("\\\\{username}{}\\{}", params.address, params.share)
} }
ProtocolParams::WebDAV(params) => params.uri,
} }
} }
@@ -1180,6 +1235,23 @@ impl AuthActivity {
} }
} }
fn get_webdav_view(&self) -> [Id; 4] {
match self.app.focus() {
Some(&Id::LocalDirectory) => [
Id::Username,
Id::Password,
Id::RemoteDirectory,
Id::LocalDirectory,
],
_ => [
Id::WebDAVUri,
Id::Username,
Id::Password,
Id::RemoteDirectory,
],
}
}
fn init_global_listener(&mut self) { fn init_global_listener(&mut self) {
use tuirealm::event::{Key, KeyEvent, KeyModifiers}; use tuirealm::event::{Key, KeyEvent, KeyModifiers};
assert!(self assert!(self
@@ -7,7 +7,7 @@ use tuirealm::props::{
Alignment, AttrValue, Attribute, Borders, Color, Style, Table, TextModifiers, Alignment, AttrValue, Attribute, Borders, Color, Style, Table, TextModifiers,
}; };
use tuirealm::tui::layout::Corner; use tuirealm::tui::layout::Corner;
use tuirealm::tui::text::{Span, Spans}; use tuirealm::tui::text::{Line, Span};
use tuirealm::tui::widgets::{List as TuiList, ListItem, ListState}; use tuirealm::tui::widgets::{List as TuiList, ListItem, ListState};
use tuirealm::{MockComponent, Props, State, StateValue}; use tuirealm::{MockComponent, Props, State, StateValue};
@@ -211,7 +211,7 @@ impl MockComponent for FileList {
) )
}) })
.collect(); .collect();
ListItem::new(Spans::from(columns)) ListItem::new(Line::from(columns))
}) })
.collect(), // Make List item from TextSpan .collect(), // Make List item from TextSpan
_ => Vec::new(), _ => Vec::new(),
@@ -245,7 +245,7 @@ impl MockComponent for FileList {
if matches!(attr, Attribute::Content) { if matches!(attr, Attribute::Content) {
self.states.init_list_states( self.states.init_list_states(
match self.props.get(Attribute::Content).map(|x| x.unwrap_table()) { match self.props.get(Attribute::Content).map(|x| x.unwrap_table()) {
Some(spans) => spans.len(), Some(line) => line.len(),
_ => 0, _ => 0,
}, },
); );
+8
View File
@@ -112,6 +112,7 @@ impl FileTransferActivity {
ProtocolParams::Generic(params) => params.address.clone(), ProtocolParams::Generic(params) => params.address.clone(),
ProtocolParams::AwsS3(params) => params.bucket_name.clone(), ProtocolParams::AwsS3(params) => params.bucket_name.clone(),
ProtocolParams::Smb(params) => params.address.clone(), ProtocolParams::Smb(params) => params.address.clone(),
ProtocolParams::WebDAV(params) => params.uri.clone(),
} }
} }
@@ -141,6 +142,13 @@ impl FileTransferActivity {
); );
format!("Connecting to \\\\{}\\{}…", params.address, params.share) format!("Connecting to \\\\{}\\{}…", params.address, params.share)
} }
ProtocolParams::WebDAV(params) => {
info!(
"Client is not connected to remote; connecting to {}",
params.uri
);
format!("Connecting to {}…", params.uri)
}
} }
} }
+3 -2
View File
@@ -13,7 +13,7 @@ use crate::explorer::GroupDirs as GroupDirsEnum;
use crate::filetransfer::FileTransferProtocol; use crate::filetransfer::FileTransferProtocol;
use crate::ui::activities::setup::{ use crate::ui::activities::setup::{
RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP, RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP,
RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV,
}; };
use crate::utils::parser::parse_bytesize; use crate::utils::parser::parse_bytesize;
@@ -67,7 +67,7 @@ impl DefaultProtocol {
.color(Color::Cyan) .color(Color::Cyan)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB"]) .choices(&["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB", "WebDAV"])
.foreground(Color::Cyan) .foreground(Color::Cyan)
.rewind(true) .rewind(true)
.title("Default protocol", Alignment::Left) .title("Default protocol", Alignment::Left)
@@ -78,6 +78,7 @@ impl DefaultProtocol {
FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS, FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS,
FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3, FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3,
FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB, FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB,
FileTransferProtocol::WebDAV => RADIO_PROTOCOL_WEBDAV,
}), }),
} }
} }
+1
View File
@@ -31,6 +31,7 @@ const RADIO_PROTOCOL_FTP: usize = 2;
const RADIO_PROTOCOL_FTPS: usize = 3; const RADIO_PROTOCOL_FTPS: usize = 3;
const RADIO_PROTOCOL_S3: usize = 4; const RADIO_PROTOCOL_S3: usize = 4;
const RADIO_PROTOCOL_SMB: usize = 5; const RADIO_PROTOCOL_SMB: usize = 5;
const RADIO_PROTOCOL_WEBDAV: usize = 6;
// -- components // -- components
#[derive(Debug, Eq, PartialEq, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
-3
View File
@@ -7,9 +7,6 @@ pub mod setup;
pub mod ssh_keys; pub mod ssh_keys;
pub mod theme; pub mod theme;
pub use setup::*;
pub use ssh_keys::*;
pub use theme::*;
use tuirealm::event::{Key, KeyEvent, KeyModifiers}; use tuirealm::event::{Key, KeyEvent, KeyModifiers};
use tuirealm::tui::widgets::Clear; use tuirealm::tui::widgets::Clear;
use tuirealm::{Frame, Sub, SubClause, SubEventClause}; use tuirealm::{Frame, Sub, SubClause, SubEventClause};
+4 -1
View File
@@ -10,7 +10,9 @@ use std::path::PathBuf;
use tuirealm::tui::layout::{Constraint, Direction, Layout}; use tuirealm::tui::layout::{Constraint, Direction, Layout};
use tuirealm::{State, StateValue}; use tuirealm::{State, StateValue};
use super::{components, Context, Id, IdCommon, IdConfig, SetupActivity, ViewLayout}; use super::{
components, Context, Id, IdCommon, IdConfig, SetupActivity, ViewLayout, RADIO_PROTOCOL_WEBDAV,
};
use crate::explorer::GroupDirs; use crate::explorer::GroupDirs;
use crate::filetransfer::FileTransferProtocol; use crate::filetransfer::FileTransferProtocol;
use crate::ui::activities::setup::{ use crate::ui::activities::setup::{
@@ -277,6 +279,7 @@ impl SetupActivity {
RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true), RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true),
RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3, RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3,
RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb, RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb,
RADIO_PROTOCOL_WEBDAV => FileTransferProtocol::WebDAV,
_ => FileTransferProtocol::Sftp, _ => FileTransferProtocol::Sftp,
}; };
self.config_mut().set_default_protocol(protocol); self.config_mut().set_default_protocol(protocol);
+69 -5
View File
@@ -14,7 +14,9 @@ use tuirealm::utils::parser as tuirealm_parser;
#[cfg(smb)] #[cfg(smb)]
use crate::filetransfer::params::SmbParams; use crate::filetransfer::params::SmbParams;
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams}; use crate::filetransfer::params::{
AwsS3Params, GenericProtocolParams, ProtocolParams, WebDAVProtocolParams,
};
use crate::filetransfer::{FileTransferParams, FileTransferProtocol}; use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
#[cfg(not(test))] // NOTE: don't use configuration during tests #[cfg(not(test))] // NOTE: don't use configuration during tests
use crate::system::config_client::ConfigClient; use crate::system::config_client::ConfigClient;
@@ -43,6 +45,16 @@ static REMOTE_GENERIC_OPT_REGEX: Lazy<Regex> = lazy_regex!(
r"(?:([^@]+)@)?(?:([^:]+))(?::((?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])))?(?::([^:]+))?" r"(?:([^@]+)@)?(?:([^:]+))(?::((?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])))?(?::([^:]+))?"
); );
/**
* Regex matches:
* - group 1: Username
* - group 2: Password
* - group 2: Uri
* - group 4: Some(path) | None
*/
static REMOTE_WEBDAV_OPT_REGEX: Lazy<Regex> =
lazy_regex!(r"(?:([^:]+):)(?:([^@]+)@)(?:([^/]+))(?:/(.+))?");
/** /**
* Regex matches: * Regex matches:
* - group 1: Bucket * - group 1: Bucket
@@ -145,14 +157,24 @@ pub fn parse_remote_opt(s: &str) -> Result<FileTransferParams, String> {
#[cfg(test)] // NOTE: during test set protocol just to Sftp #[cfg(test)] // NOTE: during test set protocol just to Sftp
let default_protocol: FileTransferProtocol = FileTransferProtocol::Sftp; let default_protocol: FileTransferProtocol = FileTransferProtocol::Sftp;
// Get protocol // Get protocol
let (protocol, s): (FileTransferProtocol, String) = let (protocol, remote): (FileTransferProtocol, String) =
parse_remote_opt_protocol(s, default_protocol)?; parse_remote_opt_protocol(s, default_protocol)?;
// Match against regex for protocol type // Match against regex for protocol type
match protocol { match protocol {
FileTransferProtocol::AwsS3 => parse_s3_remote_opt(s.as_str()), FileTransferProtocol::AwsS3 => parse_s3_remote_opt(remote.as_str()),
#[cfg(smb)] #[cfg(smb)]
FileTransferProtocol::Smb => parse_smb_remote_opts(s.as_str()), FileTransferProtocol::Smb => parse_smb_remote_opts(remote.as_str()),
protocol => parse_generic_remote_opt(s.as_str(), protocol), FileTransferProtocol::WebDAV => {
// get the differnece between s and remote
let prefix = if s.starts_with("https") {
"https"
} else {
"http"
};
parse_webdav_remote_opt(remote.as_str(), prefix)
}
protocol => parse_generic_remote_opt(remote.as_str(), protocol),
} }
} }
@@ -232,6 +254,29 @@ fn parse_generic_remote_opt(
} }
} }
fn parse_webdav_remote_opt(s: &str, prefix: &str) -> Result<FileTransferParams, String> {
match REMOTE_WEBDAV_OPT_REGEX.captures(s) {
Some(groups) => {
let username = groups.get(1).map(|x| x.as_str().to_string()).unwrap();
let password = groups.get(2).map(|x| x.as_str().to_string()).unwrap();
let uri = groups.get(3).map(|x| x.as_str().to_string()).unwrap();
let remote_path: Option<PathBuf> =
groups.get(4).map(|group| PathBuf::from(group.as_str()));
let params = ProtocolParams::WebDAV(WebDAVProtocolParams {
uri: format!("{}://{}", prefix, uri),
username,
password,
});
Ok(
FileTransferParams::new(FileTransferProtocol::WebDAV, params)
.remote_path(remote_path),
)
}
None => Err(String::from("Bad remote host syntax!")),
}
}
/// Parse remote options for s3 protocol /// Parse remote options for s3 protocol
fn parse_s3_remote_opt(s: &str) -> Result<FileTransferParams, String> { fn parse_s3_remote_opt(s: &str) -> Result<FileTransferParams, String> {
match REMOTE_S3_OPT_REGEX.captures(s) { match REMOTE_S3_OPT_REGEX.captures(s) {
@@ -553,6 +598,25 @@ mod tests {
assert!(parse_remote_opt(&String::from("scp://172.26.104.1:650000")).is_err()); assert!(parse_remote_opt(&String::from("scp://172.26.104.1:650000")).is_err());
} }
#[test]
fn test_should_parse_webdav_opt() {
let result =
parse_remote_opt("https://omar:password@myserver:4445/myshare/dir/subdir").unwrap();
let params = result.params.webdav_params().unwrap();
assert_eq!(params.uri.as_str(), "https://myserver:4445");
assert_eq!(params.username.as_str(), "omar");
assert_eq!(params.password.as_str(), "password");
let result =
parse_remote_opt("http://omar:password@myserver:4445/myshare/dir/subdir").unwrap();
let params = result.params.webdav_params().unwrap();
assert_eq!(params.uri.as_str(), "http://myserver:4445");
assert_eq!(params.username.as_str(), "omar");
assert_eq!(params.password.as_str(), "password");
}
#[test] #[test]
fn parse_aws_s3_opt() { fn parse_aws_s3_opt() {
// Simple // Simple
+2 -2
View File
@@ -60,8 +60,8 @@ where
} }
(None, _) => comps.push(Component::ParentDir), (None, _) => comps.push(Component::ParentDir),
(Some(a), Some(b)) if comps.is_empty() && a == b => (), (Some(a), Some(b)) if comps.is_empty() && a == b => (),
(Some(a), Some(b)) if b == Component::CurDir => comps.push(a), (Some(a), Some(Component::CurDir)) => comps.push(a),
(Some(_), Some(b)) if b == Component::ParentDir => return None, (Some(_), Some(Component::ParentDir)) => return None,
(Some(a), Some(_)) => { (Some(a), Some(_)) => {
comps.push(Component::ParentDir); comps.push(Component::ParentDir);
for _ in itb { for _ in itb {
+2 -2
View File
@@ -67,7 +67,7 @@ mod tests {
let child: Rect = Popup(Size::Percentage(75), Size::Percentage(30)).draw_in(area); let child: Rect = Popup(Size::Percentage(75), Size::Percentage(30)).draw_in(area);
assert_eq!(child.x, 43); assert_eq!(child.x, 43);
assert_eq!(child.y, 63); assert_eq!(child.y, 63);
assert_eq!(child.width, 271); assert_eq!(child.width, 272);
assert_eq!(child.height, 54); assert_eq!(child.height, 55);
} }
} }