melib: Add FolderPermissions
permissions() method on BackendFolder and SetPermissions in FolderOperation enum.jmap
parent
97e20b22a8
commit
5761f854e2
|
@ -173,6 +173,7 @@ pub enum FolderOperation {
|
||||||
Subscribe,
|
Subscribe,
|
||||||
Unsubscribe,
|
Unsubscribe,
|
||||||
Rename(NewFolderName),
|
Rename(NewFolderName),
|
||||||
|
SetPermissions(FolderPermissions),
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewFolderName = String;
|
type NewFolderName = String;
|
||||||
|
@ -309,6 +310,8 @@ pub trait BackendFolder: Debug {
|
||||||
fn clone(&self) -> Folder;
|
fn clone(&self) -> Folder;
|
||||||
fn children(&self) -> &Vec<FolderHash>;
|
fn children(&self) -> &Vec<FolderHash>;
|
||||||
fn parent(&self) -> Option<FolderHash>;
|
fn parent(&self) -> Option<FolderHash>;
|
||||||
|
|
||||||
|
fn permissions(&self) -> FolderPermissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -342,6 +345,10 @@ impl BackendFolder for DummyFolder {
|
||||||
fn parent(&self) -> Option<FolderHash> {
|
fn parent(&self) -> Option<FolderHash> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn permissions(&self) -> FolderPermissions {
|
||||||
|
FolderPermissions::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn folder_default() -> Folder {
|
pub fn folder_default() -> Folder {
|
||||||
|
@ -364,3 +371,30 @@ impl Default for Folder {
|
||||||
folder_default()
|
folder_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
pub struct FolderPermissions {
|
||||||
|
pub create_messages: bool,
|
||||||
|
pub remove_messages: bool,
|
||||||
|
pub set_flags: bool,
|
||||||
|
pub create_child: bool,
|
||||||
|
pub rename_messages: bool,
|
||||||
|
pub delete_messages: bool,
|
||||||
|
pub delete_mailbox: bool,
|
||||||
|
pub change_permissions: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FolderPermissions {
|
||||||
|
fn default() -> Self {
|
||||||
|
FolderPermissions {
|
||||||
|
create_messages: false,
|
||||||
|
remove_messages: false,
|
||||||
|
set_flags: false,
|
||||||
|
create_child: false,
|
||||||
|
rename_messages: false,
|
||||||
|
delete_messages: false,
|
||||||
|
delete_mailbox: false,
|
||||||
|
change_permissions: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -123,7 +123,10 @@ impl MailBackend for ImapType {
|
||||||
let uid_store = self.uid_store.clone();
|
let uid_store = self.uid_store.clone();
|
||||||
let folder_path = folder.path().to_string();
|
let folder_path = folder.path().to_string();
|
||||||
let folder_hash = folder.hash();
|
let folder_hash = folder.hash();
|
||||||
let folder_exists = self.folders.lock().unwrap()[&folder_hash].exists.clone();
|
let (permissions, folder_exists) = {
|
||||||
|
let f = &self.folders.lock().unwrap()[&folder_hash];
|
||||||
|
(f.permissions.clone(), f.exists.clone())
|
||||||
|
};
|
||||||
let connection = self.connection.clone();
|
let connection = self.connection.clone();
|
||||||
let closure = move |_work_context| {
|
let closure = move |_work_context| {
|
||||||
let connection = connection.clone();
|
let connection = connection.clone();
|
||||||
|
@ -134,13 +137,19 @@ impl MailBackend for ImapType {
|
||||||
let mut conn = conn.unwrap();
|
let mut conn = conn.unwrap();
|
||||||
debug!("locked for get {}", folder_path);
|
debug!("locked for get {}", folder_path);
|
||||||
|
|
||||||
|
/* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE only
|
||||||
|
* returns READ-ONLY for both cases) */
|
||||||
exit_on_error!(&tx,
|
exit_on_error!(&tx,
|
||||||
conn.send_command(format!("EXAMINE {}", folder_path).as_bytes())
|
conn.send_command(format!("SELECT {}", folder_path).as_bytes())
|
||||||
conn.read_response(&mut response)
|
conn.read_response(&mut response)
|
||||||
);
|
);
|
||||||
let examine_response = protocol_parser::select_response(&response);
|
let examine_response = protocol_parser::select_response(&response);
|
||||||
exit_on_error!(&tx, examine_response);
|
exit_on_error!(&tx, examine_response);
|
||||||
let examine_response = examine_response.unwrap();
|
let examine_response = examine_response.unwrap();
|
||||||
|
debug!(
|
||||||
|
"folder: {} examine_response: {:?}",
|
||||||
|
folder_path, examine_response
|
||||||
|
);
|
||||||
let mut exists: usize = examine_response.uidnext - 1;
|
let mut exists: usize = examine_response.uidnext - 1;
|
||||||
{
|
{
|
||||||
let mut uidvalidities = uid_store.uidvalidity.lock().unwrap();
|
let mut uidvalidities = uid_store.uidvalidity.lock().unwrap();
|
||||||
|
@ -149,11 +158,22 @@ impl MailBackend for ImapType {
|
||||||
.entry(folder_hash)
|
.entry(folder_hash)
|
||||||
.or_insert(examine_response.uidvalidity);
|
.or_insert(examine_response.uidvalidity);
|
||||||
*v = examine_response.uidvalidity;
|
*v = examine_response.uidvalidity;
|
||||||
}
|
|
||||||
{
|
let mut permissions = permissions.lock().unwrap();
|
||||||
|
permissions.create_messages = !examine_response.read_only;
|
||||||
|
permissions.remove_messages = !examine_response.read_only;
|
||||||
|
permissions.set_flags = !examine_response.read_only;
|
||||||
|
permissions.rename_messages = !examine_response.read_only;
|
||||||
|
permissions.delete_messages = !examine_response.read_only;
|
||||||
|
permissions.delete_messages = !examine_response.read_only;
|
||||||
let mut folder_exists = folder_exists.lock().unwrap();
|
let mut folder_exists = folder_exists.lock().unwrap();
|
||||||
*folder_exists = exists;
|
*folder_exists = exists;
|
||||||
}
|
}
|
||||||
|
/* reselecting the same mailbox with EXAMINE prevents expunging it */
|
||||||
|
exit_on_error!(&tx,
|
||||||
|
conn.send_command(format!("EXAMINE {}", folder_path).as_bytes())
|
||||||
|
conn.read_response(&mut response)
|
||||||
|
);
|
||||||
|
|
||||||
while exists > 1 {
|
while exists > 1 {
|
||||||
let mut envelopes = vec![];
|
let mut envelopes = vec![];
|
||||||
|
@ -285,11 +305,23 @@ impl MailBackend for ImapType {
|
||||||
let path = {
|
let path = {
|
||||||
let folders = self.folders.lock().unwrap();
|
let folders = self.folders.lock().unwrap();
|
||||||
|
|
||||||
folders
|
let f_result = folders.values().find(|v| v.name == folder);
|
||||||
.values()
|
if f_result
|
||||||
.find(|v| v.name == folder)
|
.map(|f| !f.permissions.lock().unwrap().create_messages)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return Err(MeliError::new(format!(
|
||||||
|
"You are not allowed to create messages in folder {}",
|
||||||
|
folder
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
f_result
|
||||||
.map(|v| v.path().to_string())
|
.map(|v| v.path().to_string())
|
||||||
.ok_or(MeliError::new(""))?
|
.ok_or(MeliError::new(format!(
|
||||||
|
"Folder with name {} not found.",
|
||||||
|
folder
|
||||||
|
)))?
|
||||||
};
|
};
|
||||||
let mut response = String::with_capacity(8 * 1024);
|
let mut response = String::with_capacity(8 * 1024);
|
||||||
let mut conn = self.connection.lock().unwrap();
|
let mut conn = self.connection.lock().unwrap();
|
||||||
|
@ -365,6 +397,9 @@ impl MailBackend for ImapType {
|
||||||
conn.send_command(format!("UNSUBSCRIBE \"{}\"", path,).as_bytes())?;
|
conn.send_command(format!("UNSUBSCRIBE \"{}\"", path,).as_bytes())?;
|
||||||
conn.read_response(&mut response)?;
|
conn.read_response(&mut response)?;
|
||||||
}
|
}
|
||||||
|
SetPermissions(_new_val) => {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
use crate::backends::{BackendFolder, Folder, FolderHash};
|
use crate::backends::{BackendFolder, Folder, FolderHash, FolderPermissions};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
|
@ -29,6 +29,7 @@ pub struct ImapFolder {
|
||||||
pub(super) parent: Option<FolderHash>,
|
pub(super) parent: Option<FolderHash>,
|
||||||
pub(super) children: Vec<FolderHash>,
|
pub(super) children: Vec<FolderHash>,
|
||||||
|
|
||||||
|
pub permissions: Arc<Mutex<FolderPermissions>>,
|
||||||
pub exists: Arc<Mutex<usize>>,
|
pub exists: Arc<Mutex<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +61,7 @@ impl BackendFolder for ImapFolder {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
parent: self.parent,
|
parent: self.parent,
|
||||||
children: self.children.clone(),
|
children: self.children.clone(),
|
||||||
|
permissions: self.permissions.clone(),
|
||||||
exists: self.exists.clone(),
|
exists: self.exists.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -67,4 +69,8 @@ impl BackendFolder for ImapFolder {
|
||||||
fn parent(&self) -> Option<FolderHash> {
|
fn parent(&self) -> Option<FolderHash> {
|
||||||
self.parent
|
self.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn permissions(&self) -> FolderPermissions {
|
||||||
|
*self.permissions.lock().unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,6 +287,7 @@ pub struct SelectResponse {
|
||||||
pub uidvalidity: usize,
|
pub uidvalidity: usize,
|
||||||
pub uidnext: usize,
|
pub uidnext: usize,
|
||||||
pub permanentflags: Flag,
|
pub permanentflags: Flag,
|
||||||
|
pub read_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -337,6 +338,10 @@ pub fn select_response(input: &str) -> Result<SelectResponse> {
|
||||||
flags(&l["* OK [PERMANENTFLAGS (".len()..l.find(')').unwrap()])
|
flags(&l["* OK [PERMANENTFLAGS (".len()..l.find(')').unwrap()])
|
||||||
.to_full_result()
|
.to_full_result()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
} else if l.contains("OK [READ-WRITE]") {
|
||||||
|
ret.read_only = false;
|
||||||
|
} else if l.contains("OK [READ-ONLY]") {
|
||||||
|
ret.read_only = true;
|
||||||
} else if !l.is_empty() {
|
} else if !l.is_empty() {
|
||||||
debug!("select response: {}", l);
|
debug!("select response: {}", l);
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,7 @@ pub struct MaildirFolder {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
parent: Option<FolderHash>,
|
parent: Option<FolderHash>,
|
||||||
children: Vec<FolderHash>,
|
children: Vec<FolderHash>,
|
||||||
|
permissions: FolderPermissions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaildirFolder {
|
impl MaildirFolder {
|
||||||
|
@ -229,6 +230,12 @@ impl MaildirFolder {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let read_only = if let Ok(metadata) = std::fs::metadata(&pathbuf) {
|
||||||
|
metadata.permissions().readonly()
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
let ret = MaildirFolder {
|
let ret = MaildirFolder {
|
||||||
hash: h.finish(),
|
hash: h.finish(),
|
||||||
name: file_name,
|
name: file_name,
|
||||||
|
@ -236,6 +243,16 @@ impl MaildirFolder {
|
||||||
fs_path: pathbuf,
|
fs_path: pathbuf,
|
||||||
parent,
|
parent,
|
||||||
children,
|
children,
|
||||||
|
permissions: FolderPermissions {
|
||||||
|
create_messages: !read_only,
|
||||||
|
remove_messages: !read_only,
|
||||||
|
set_flags: !read_only,
|
||||||
|
create_child: !read_only,
|
||||||
|
rename_messages: !read_only,
|
||||||
|
delete_messages: !read_only,
|
||||||
|
delete_mailbox: !read_only,
|
||||||
|
change_permissions: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
ret.is_valid()?;
|
ret.is_valid()?;
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
|
@ -290,10 +307,15 @@ impl BackendFolder for MaildirFolder {
|
||||||
path: self.path.clone(),
|
path: self.path.clone(),
|
||||||
children: self.children.clone(),
|
children: self.children.clone(),
|
||||||
parent: self.parent,
|
parent: self.parent,
|
||||||
|
permissions: self.permissions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent(&self) -> Option<FolderHash> {
|
fn parent(&self) -> Option<FolderHash> {
|
||||||
self.parent
|
self.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn permissions(&self) -> FolderPermissions {
|
||||||
|
self.permissions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
|
||||||
use crate::backends::BackendOp;
|
use crate::backends::BackendOp;
|
||||||
use crate::backends::FolderHash;
|
use crate::backends::FolderHash;
|
||||||
use crate::backends::{
|
use crate::backends::{
|
||||||
BackendFolder, Folder, MailBackend, RefreshEvent, RefreshEventConsumer, RefreshEventKind,
|
BackendFolder, Folder, FolderPermissions, MailBackend, RefreshEvent, RefreshEventConsumer,
|
||||||
|
RefreshEventKind,
|
||||||
};
|
};
|
||||||
use crate::conf::AccountSettings;
|
use crate::conf::AccountSettings;
|
||||||
use crate::email::parser::BytesExt;
|
use crate::email::parser::BytesExt;
|
||||||
|
@ -86,6 +87,7 @@ struct MboxFolder {
|
||||||
content: Vec<u8>,
|
content: Vec<u8>,
|
||||||
children: Vec<FolderHash>,
|
children: Vec<FolderHash>,
|
||||||
parent: Option<FolderHash>,
|
parent: Option<FolderHash>,
|
||||||
|
permissions: FolderPermissions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackendFolder for MboxFolder {
|
impl BackendFolder for MboxFolder {
|
||||||
|
@ -114,6 +116,7 @@ impl BackendFolder for MboxFolder {
|
||||||
content: self.content.clone(),
|
content: self.content.clone(),
|
||||||
children: self.children.clone(),
|
children: self.children.clone(),
|
||||||
parent: self.parent,
|
parent: self.parent,
|
||||||
|
permissions: self.permissions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +127,10 @@ impl BackendFolder for MboxFolder {
|
||||||
fn parent(&self) -> Option<FolderHash> {
|
fn parent(&self) -> Option<FolderHash> {
|
||||||
self.parent
|
self.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn permissions(&self) -> FolderPermissions {
|
||||||
|
self.permissions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `BackendOp` implementor for Mbox
|
/// `BackendOp` implementor for Mbox
|
||||||
|
@ -574,6 +581,13 @@ impl MboxType {
|
||||||
.map(|f| f.to_string_lossy().into())
|
.map(|f| f.to_string_lossy().into())
|
||||||
.unwrap_or(String::new());
|
.unwrap_or(String::new());
|
||||||
let hash = get_path_hash!(&ret.path);
|
let hash = get_path_hash!(&ret.path);
|
||||||
|
|
||||||
|
let read_only = if let Ok(metadata) = std::fs::metadata(&ret.path) {
|
||||||
|
metadata.permissions().readonly()
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
ret.folders.lock().unwrap().insert(
|
ret.folders.lock().unwrap().insert(
|
||||||
hash,
|
hash,
|
||||||
MboxFolder {
|
MboxFolder {
|
||||||
|
@ -583,6 +597,16 @@ impl MboxType {
|
||||||
content: Vec::new(),
|
content: Vec::new(),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
parent: None,
|
parent: None,
|
||||||
|
permissions: FolderPermissions {
|
||||||
|
create_messages: !read_only,
|
||||||
|
remove_messages: !read_only,
|
||||||
|
set_flags: !read_only,
|
||||||
|
create_child: !read_only,
|
||||||
|
rename_messages: !read_only,
|
||||||
|
delete_messages: !read_only,
|
||||||
|
delete_mailbox: !read_only,
|
||||||
|
change_permissions: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue