1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::fmt;
use std::io::{Read, Write, Result};
use std::collections::HashMap;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate failure;
pub mod dimension;
pub use dimension::Dimension;
#[derive(Clone)]
struct ArgumentMap(HashMap<&'static str, String>);
impl ArgumentMap {
fn new() -> ArgumentMap {
ArgumentMap(HashMap::new())
}
fn insert(&mut self, key: &'static str, value: impl Into<String>) {
self.0.insert(key, value.into());
}
fn from_action(action: &TransferAction) -> ArgumentMap {
let mut args = ArgumentMap::new();
match action {
TransferAction::Download => {
args.insert("inline", "0");
},
TransferAction::Display { height, width, preserve_aspect_ratio } => {
if let Some(width) = width {
args.insert("width", *width);
}
if let Some(height) = height {
args.insert("height", *height);
}
if let Some(preserve_aspect_ratio) = *preserve_aspect_ratio {
args.insert("preserveAspectRatio", if preserve_aspect_ratio {
"1"
} else {
"0"
}
);
}
args.insert("inline", "1");
}
}
args
}
}
impl fmt::Display for ArgumentMap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0
.iter()
.map(|(name, value)| write!(f, "{}={};", name, value))
.collect()
}
}
#[derive(Clone)]
pub enum TransferAction {
Download,
Display {
width: Option<Dimension>,
height: Option<Dimension>,
preserve_aspect_ratio: Option<bool>
}
}
pub struct FileTransfer<'a> {
action: &'a TransferAction,
data: Box<dyn Read>,
name: Option<String>
}
impl<'a> FileTransfer<'a> {
pub fn new(action: &'a TransferAction, data: Box<dyn Read>, name: Option<String>) -> FileTransfer {
FileTransfer { action, data, name }
}
pub fn transfer(mut self, output: &mut dyn Write) -> Result<()> {
let mut args: ArgumentMap = ArgumentMap::from_action(self.action);
let encoded_name;
if let Some(name) = self.name {
encoded_name = base64::encode(&name);
args.insert("name", &encoded_name);
}
let mut contents = Vec::new();
let size = self.data.read_to_end(&mut contents)?;
let size_string = size.to_string();
args.insert("size", &size_string);
write!(output, "\x1b]1337;File={}:{}\x07", args, base64::encode(&contents))
}
}