dropbox_dir/
lib.rs

1#[macro_use]
2extern crate quick_error;
3extern crate serde;
4#[macro_use]
5extern crate serde_derive;
6extern crate serde_json;
7
8use std::env;
9use std::fs::File;
10use std::path::{Path, PathBuf};
11
12#[cfg(not(target_os = "windows"))]
13fn get_config_path() -> Option<PathBuf> {
14    let home = match env::home_dir() {
15        Some(path) => path,
16        None => return None,
17    };
18    let path = Path::new(&home).join(".dropbox/info.json");
19    if path.is_file() {
20        Some(path)
21    } else {
22        None
23    }
24}
25
26#[cfg(target_os = "windows")]
27fn get_config_path() -> Option<PathBuf> {
28    const CFG_PATH_SUFFIX: &'static str = "Dropbox/info.json";
29    let mut appdata = String::new();
30    let mut localappdata = String::new();
31    for (key, value) in env::vars() {
32        if key == "APPDATA" {
33            appdata = value;
34        } else if key == "LOCALAPPDATA" {
35            localappdata = value;
36        }
37        if appdata != "" && localappdata != "" {
38            break;
39        }
40    }
41
42    let roamingpath = Path::new(&appdata).join(CFG_PATH_SUFFIX);
43    let localpath = Path::new(&localappdata).join(CFG_PATH_SUFFIX);
44    if roamingpath.is_file() {
45        Some(roamingpath)
46    } else if localpath.is_file() {
47        Some(localpath)
48    } else {
49        None
50    }
51}
52
53#[derive(Debug, Deserialize)]
54struct Account {
55    path: String,
56    host: i64,
57    is_team: bool,
58    subscription_type: String,
59}
60
61#[derive(Debug, Deserialize)]
62pub struct Info {
63    personal: Option<Account>,
64    business: Option<Account>,
65}
66
67quick_error! {
68    #[derive(Debug)]
69    pub enum Error {
70        NotConfiguredError {
71            description("Dropbox not configured")
72        }
73        CantReadConfigError{
74            from(std::io::Error)
75            description("can't read configuration")
76        }
77        InvalidConfigError{
78            from(serde_json::Error)
79            description("configuration invalid")
80        }
81        AccountNotConfiguredError {
82            description("account type not configured")
83        }
84    }
85}
86
87/// Reads info from Dropbox configuration files.
88pub fn read_info() -> Result<Info, Error> {
89    let cfg_path = match get_config_path() {
90        Some(path) => path,
91        None => return Err(Error::NotConfiguredError),
92    };
93    let file = File::open(cfg_path)?;
94    let info: Info = serde_json::from_reader(file).unwrap();
95    Ok(info)
96}
97
98fn get_dir(account_type: &str) -> Result<String, Error> {
99    let info = read_info()?;
100    let data = match account_type {
101        "personal" => info.personal,
102        "business" => info.business,
103        _ => unreachable!(),
104    };
105    if let Some(account) = data {
106        Ok(account.path.clone())
107    } else {
108        Err(Error::AccountNotConfiguredError)
109    }
110}
111
112/// Gets the personal directory path.
113pub fn personal_dir() -> Result<String, Error> {
114    get_dir("personal")
115}
116
117/// Gets the business directory path.
118pub fn business_dir() -> Result<String, Error> {
119    get_dir("business")
120}
121
122pub struct SmartPath {
123    local_root: PathBuf,
124    target: PathBuf,
125}
126
127impl SmartPath {
128    fn new<S>(root: S, path: S) -> SmartPath
129    where
130        S: Into<String>,
131    {
132        let raw_target = PathBuf::from(path.into());
133        let target: PathBuf = if raw_target.starts_with("/") {
134            raw_target.strip_prefix("/").unwrap().into()
135        } else {
136            raw_target.clone()
137        };
138        SmartPath {
139            local_root: PathBuf::from(root.into()),
140            target: target,
141        }
142    }
143
144    /// Creates a new `SmartPath`, the `path` parameter represent a target inside the Dropbox
145    /// directory (personal).
146    pub fn new_personal<S>(path: S) -> Result<SmartPath, Error>
147    where
148        S: Into<String>,
149    {
150        let root = personal_dir()?;
151        Ok(SmartPath::new(root, path.into()))
152    }
153
154    /// Creates a new `SmartPath`, the `path` parameter represent a target inside the Dropbox
155    /// directory (business).
156    pub fn new_business<S>(path: S) -> Result<SmartPath, Error>
157    where
158        S: Into<String>,
159    {
160        let root = business_dir()?;
161        Ok(SmartPath::new(root, path.into()))
162    }
163
164    /// Gets the local absolute path of the target.
165    pub fn local(&self) -> PathBuf {
166        if self.target.components().count() > 0 {
167            self.local_root.join(&self.target)
168        } else {
169            self.local_root.clone()
170        }
171    }
172
173    /// Gets the remote path of the target.
174    pub fn remote(&self) -> PathBuf {
175        PathBuf::from("/").join(&self.target)
176    }
177}