Support mounting encrypted drive, fixes #144

This commit is contained in:
Jeremy Soller 2024-10-11 16:43:16 -06:00
parent 12d47c8c80
commit 583d3dfa0d
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
4 changed files with 70 additions and 6 deletions

View file

@ -35,6 +35,9 @@ create-archive = Create archive
empty-trash = Empty trash empty-trash = Empty trash
empty-trash-warning = Are you sure you want to permanently delete all the items in Trash? empty-trash-warning = Are you sure you want to permanently delete all the items in Trash?
## Mount Error Dialog
mount-error = Unable to access drive
## New File/Folder Dialog ## New File/Folder Dialog
create-new-file = Create new file create-new-file = Create new file
create-new-folder = Create new folder create-new-folder = Create new folder

View file

@ -274,6 +274,7 @@ pub enum Message {
Modifiers(Modifiers), Modifiers(Modifiers),
MoveToTrash(Option<Entity>), MoveToTrash(Option<Entity>),
MounterItems(MounterKey, MounterItems), MounterItems(MounterKey, MounterItems),
MountResult(MounterKey, MounterItem, Result<bool, String>),
NavBarClose(Entity), NavBarClose(Entity),
NavBarContext(Entity), NavBarContext(Entity),
NavMenuAction(NavMenuAction), NavMenuAction(NavMenuAction),
@ -405,6 +406,11 @@ pub enum DialogPage {
}, },
EmptyTrash, EmptyTrash,
FailedOperation(u64), FailedOperation(u64),
MountError {
mounter_key: MounterKey,
item: MounterItem,
error: String,
},
NetworkAuth { NetworkAuth {
mounter_key: MounterKey, mounter_key: MounterKey,
uri: String, uri: String,
@ -1630,6 +1636,15 @@ impl Application for App {
DialogPage::FailedOperation(id) => { DialogPage::FailedOperation(id) => {
log::warn!("TODO: retry operation {}", id); log::warn!("TODO: retry operation {}", id);
} }
DialogPage::MountError {
mounter_key,
item,
error: _,
} => {
if let Some(mounter) = MOUNTERS.get(&mounter_key) {
return mounter.mount(item).map(|_| message::none());
}
}
DialogPage::NetworkAuth { DialogPage::NetworkAuth {
mounter_key: _, mounter_key: _,
uri: _, uri: _,
@ -1834,6 +1849,22 @@ impl Application for App {
return Command::batch(commands); return Command::batch(commands);
} }
Message::MountResult(mounter_key, item, res) => match res {
Ok(true) => {
log::info!("connected to {:?}", item);
}
Ok(false) => {
log::info!("cancelled connection to {:?}", item);
}
Err(error) => {
log::warn!("failed to connect to {:?}: {}", item, error);
self.dialog_pages.push_back(DialogPage::MountError {
mounter_key,
item,
error,
});
}
},
Message::NetworkAuth(mounter_key, uri, auth, auth_tx) => { Message::NetworkAuth(mounter_key, uri, auth, auth_tx) => {
self.dialog_pages.push_back(DialogPage::NetworkAuth { self.dialog_pages.push_back(DialogPage::NetworkAuth {
mounter_key, mounter_key,
@ -3198,6 +3229,19 @@ impl Application for App {
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel), widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
) )
} }
DialogPage::MountError {
mounter_key: _,
item: _,
error,
} => widget::dialog(fl!("mount-error"))
.body(error)
.icon(widget::icon::from_name("dialog-error").size(64))
.primary_action(
widget::button::standard(fl!("try-again")).on_press(Message::DialogComplete),
)
.secondary_action(
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
),
DialogPage::NetworkAuth { DialogPage::NetworkAuth {
mounter_key, mounter_key,
uri, uri,
@ -3988,6 +4032,7 @@ impl Application for App {
subscriptions.push(mounter.subscription().map(move |mounter_message| { subscriptions.push(mounter.subscription().map(move |mounter_message| {
match mounter_message { match mounter_message {
MounterMessage::Items(items) => Message::MounterItems(key, items), MounterMessage::Items(items) => Message::MounterItems(key, items),
MounterMessage::MountResult(item, res) => Message::MountResult(key, item, res),
MounterMessage::NetworkAuth(uri, auth, auth_tx) => { MounterMessage::NetworkAuth(uri, auth, auth_tx) => {
Message::NetworkAuth(key, uri, auth, auth_tx) Message::NetworkAuth(key, uri, auth, auth_tx)
} }

View file

@ -212,6 +212,7 @@ enum Cmd {
enum Event { enum Event {
Changed, Changed,
Items(MounterItems), Items(MounterItems),
MountResult(MounterItem, Result<bool, String>),
NetworkAuth(String, MounterAuth, mpsc::Sender<MounterAuth>), NetworkAuth(String, MounterAuth, mpsc::Sender<MounterAuth>),
NetworkResult(String, Result<bool, String>), NetworkResult(String, Result<bool, String>),
} }
@ -324,7 +325,7 @@ impl Gvfs {
event_tx.send(Event::Items(items(&monitor, IconSizes::default()))).unwrap(); event_tx.send(Event::Items(items(&monitor, IconSizes::default()))).unwrap();
} }
Cmd::Mount(mounter_item) => { Cmd::Mount(mounter_item) => {
let MounterItem::Gvfs(item) = mounter_item else { continue }; let MounterItem::Gvfs(ref item) = mounter_item else { continue };
let ItemKind::Volume = item.kind else { continue }; let ItemKind::Volume = item.kind else { continue };
for (i, volume) in monitor.volumes().into_iter().enumerate() { for (i, volume) in monitor.volumes().into_iter().enumerate() {
if i != item.index { if i != item.index {
@ -338,14 +339,24 @@ impl Gvfs {
} }
log::info!("mount {}", name); log::info!("mount {}", name);
//TODO: do not use name as a URI for mount_op
let mount_op = mount_op(name.to_string(), event_tx.clone());
let event_tx = event_tx.clone();
let mounter_item = mounter_item.clone();
VolumeExt::mount( VolumeExt::mount(
&volume, &volume,
gio::MountMountFlags::NONE, gio::MountMountFlags::NONE,
//TODO: gio::MountOperation needed for network shares with auth Some(&mount_op),
gio::MountOperation::NONE,
gio::Cancellable::NONE, gio::Cancellable::NONE,
move |result| { move |res| {
log::info!("mount {}: result {:?}", name, result); log::info!("mount {}: result {:?}", name, res);
event_tx.send(Event::MountResult(mounter_item, match res {
Ok(()) => Ok(true),
Err(err) => match err.kind::<gio::IOErrorEnum>() {
Some(gio::IOErrorEnum::FailedHandled) => Ok(false),
_ => Err(format!("{}", err))
}
})).unwrap();
}, },
); );
} }
@ -355,7 +366,7 @@ impl Gvfs {
let mount_op = mount_op(uri.clone(), event_tx.clone()); let mount_op = mount_op(uri.clone(), event_tx.clone());
let event_tx = event_tx.clone(); let event_tx = event_tx.clone();
file.mount_enclosing_volume( file.mount_enclosing_volume(
gio::MountMountFlags::empty(), gio::MountMountFlags::NONE,
Some(&mount_op), Some(&mount_op),
gio::Cancellable::NONE, gio::Cancellable::NONE,
move |res| { move |res| {
@ -499,6 +510,10 @@ impl Mounter for Gvfs {
match event { match event {
Event::Changed => command_tx.send(Cmd::Rescan).unwrap(), Event::Changed => command_tx.send(Cmd::Rescan).unwrap(),
Event::Items(items) => output.send(MounterMessage::Items(items)).await.unwrap(), Event::Items(items) => output.send(MounterMessage::Items(items)).await.unwrap(),
Event::MountResult(item, res) => output
.send(MounterMessage::MountResult(item, res))
.await
.unwrap(),
Event::NetworkAuth(uri, auth, auth_tx) => output Event::NetworkAuth(uri, auth, auth_tx) => output
.send(MounterMessage::NetworkAuth(uri, auth, auth_tx)) .send(MounterMessage::NetworkAuth(uri, auth, auth_tx))
.await .await

View file

@ -85,6 +85,7 @@ pub type MounterItems = Vec<MounterItem>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum MounterMessage { pub enum MounterMessage {
Items(MounterItems), Items(MounterItems),
MountResult(MounterItem, Result<bool, String>),
NetworkAuth(String, MounterAuth, mpsc::Sender<MounterAuth>), NetworkAuth(String, MounterAuth, mpsc::Sender<MounterAuth>),
NetworkResult(String, Result<bool, String>), NetworkResult(String, Result<bool, String>),
} }