diff options
Diffstat (limited to '')
| -rw-r--r-- | src/bin/client/database.rs | 12 | ||||
| -rw-r--r-- | src/bin/client/repl.rs | 21 |
2 files changed, 32 insertions, 1 deletions
diff --git a/src/bin/client/database.rs b/src/bin/client/database.rs index 55051fb..e1fa42d 100644 --- a/src/bin/client/database.rs +++ b/src/bin/client/database.rs | |||
| @@ -104,3 +104,15 @@ pub fn forget_host(conn: &Connection, host: &str) -> Result<(), rusqlite::Error> | |||
| 104 | conn.execute("DELETE FROM credentials WHERE host = ?1", [host])?; | 104 | conn.execute("DELETE FROM credentials WHERE host = ?1", [host])?; |
| 105 | Ok(()) | 105 | Ok(()) |
| 106 | } | 106 | } |
| 107 | |||
| 108 | /// List all remembered hosts with their fingerprints. | ||
| 109 | pub fn get_all_hosts(conn: &Connection) -> Vec<(String, Option<String>)> { | ||
| 110 | let mut stmt = conn | ||
| 111 | .prepare("SELECT host, fingerprint FROM hosts ORDER BY last_used DESC") | ||
| 112 | .unwrap(); | ||
| 113 | let rows = stmt.query_map([], |row| { | ||
| 114 | Ok((row.get(0)?, row.get(1)?)) | ||
| 115 | }) | ||
| 116 | .unwrap(); | ||
| 117 | rows.filter_map(|r| r.ok()).collect() | ||
| 118 | } | ||
diff --git a/src/bin/client/repl.rs b/src/bin/client/repl.rs index 40b267e..dd55acc 100644 --- a/src/bin/client/repl.rs +++ b/src/bin/client/repl.rs | |||
| @@ -273,11 +273,15 @@ impl ClientState { | |||
| 273 | } | 273 | } |
| 274 | } | 274 | } |
| 275 | "connect" => { | 275 | "connect" => { |
| 276 | if self.stream.is_some() { | ||
| 277 | println!("\nAlready connected. Disconnect first."); | ||
| 278 | continue 'outer; | ||
| 279 | } | ||
| 276 | let addr_str = if parts.len() < 2 { | 280 | let addr_str = if parts.len() < 2 { |
| 277 | if let Some(h) = &self.addr { | 281 | if let Some(h) = &self.addr { |
| 278 | h.clone() | 282 | h.clone() |
| 279 | } else { | 283 | } else { |
| 280 | println!("\nNo host specified and no previous connection. Usage: connect <ip>:<port>"); | 284 | println!("\nNo host specified. Usage: connect <ip>:<port>"); |
| 281 | continue 'outer; | 285 | continue 'outer; |
| 282 | } | 286 | } |
| 283 | } else { | 287 | } else { |
| @@ -591,6 +595,20 @@ impl ClientState { | |||
| 591 | Err(e) => println!("\nFailed to forget host: {}", e), | 595 | Err(e) => println!("\nFailed to forget host: {}", e), |
| 592 | } | 596 | } |
| 593 | } | 597 | } |
| 598 | "hosts" => { | ||
| 599 | let hosts = database::get_all_hosts(&self.conn); | ||
| 600 | if hosts.is_empty() { | ||
| 601 | println!("\nNo remembered hosts."); | ||
| 602 | } else { | ||
| 603 | println!("\nRemembered hosts:"); | ||
| 604 | for (host, fp) in &hosts { | ||
| 605 | match fp { | ||
| 606 | Some(fp) => println!(" {} - {}", host, fp), | ||
| 607 | None => println!(" {} - (no fingerprint)", host), | ||
| 608 | } | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 594 | _ => help(), | 612 | _ => help(), |
| 595 | } | 613 | } |
| 596 | break; | 614 | break; |
| @@ -752,6 +770,7 @@ fn get_commands() -> Vec<String> { | |||
| 752 | "help".to_string(), | 770 | "help".to_string(), |
| 753 | "quit".to_string(), | 771 | "quit".to_string(), |
| 754 | "forget-host".to_string(), | 772 | "forget-host".to_string(), |
| 773 | "hosts".to_string(), | ||
| 755 | ] | 774 | ] |
| 756 | } | 775 | } |
| 757 | 776 | ||
