melib: Add FolderPermissions

permissions() method on BackendFolder and SetPermissions in
FolderOperation enum.
sql
Manos Pitsidianakis 2019-11-11 00:47:23 +02:00
parent 97e20b22a8
commit 5761f854e2
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 136 additions and 10 deletions

View File

@ -173,6 +173,7 @@ pub enum FolderOperation {
Subscribe,
Unsubscribe,
Rename(NewFolderName),
SetPermissions(FolderPermissions),
}
type NewFolderName = String;
@ -309,6 +310,8 @@ pub trait BackendFolder: Debug {
fn clone(&self) -> Folder;
fn children(&self) -> &Vec<FolderHash>;
fn parent(&self) -> Option<FolderHash>;
fn permissions(&self) -> FolderPermissions;
}
#[derive(Debug)]
@ -342,6 +345,10 @@ impl BackendFolder for DummyFolder {
fn parent(&self) -> Option<FolderHash> {
None
}
fn permissions(&self) -> FolderPermissions {
FolderPermissions::default()
}
}
pub fn folder_default() -> Folder {
@ -364,3 +371,30 @@ impl Default for Folder {
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,
}
}
}

View File

@ -123,7 +123,10 @@ impl MailBackend for ImapType {
let uid_store = self.uid_store.clone();
let folder_path = folder.path().to_string();
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 closure = move |_work_context| {
let connection = connection.clone();
@ -134,13 +137,19 @@ impl MailBackend for ImapType {
let mut conn = conn.unwrap();
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,
conn.send_command(format!("EXAMINE {}", folder_path).as_bytes())
conn.send_command(format!("SELECT {}", folder_path).as_bytes())
conn.read_response(&mut response)
);
let examine_response = protocol_parser::select_response(&response);
exit_on_error!(&tx, examine_response);
let examine_response = examine_response.unwrap();
debug!(
"folder: {} examine_response: {:?}",
folder_path, examine_response
);
let mut exists: usize = examine_response.uidnext - 1;
{
let mut uidvalidities = uid_store.uidvalidity.lock().unwrap();
@ -149,11 +158,22 @@ impl MailBackend for ImapType {
.entry(folder_hash)
.or_insert(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();
*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 {
let mut envelopes = vec![];
@ -285,11 +305,23 @@ impl MailBackend for ImapType {
let path = {
let folders = self.folders.lock().unwrap();
folders
.values()
.find(|v| v.name == folder)
let f_result = folders.values().find(|v| v.name == folder);
if f_result
.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())
.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 conn = self.connection.lock().unwrap();
@ -365,6 +397,9 @@ impl MailBackend for ImapType {
conn.send_command(format!("UNSUBSCRIBE \"{}\"", path,).as_bytes())?;
conn.read_response(&mut response)?;
}
SetPermissions(_new_val) => {
unimplemented!();
}
}
Ok(())
}

View File

@ -18,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* 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};
#[derive(Debug, Default, Clone)]
@ -29,6 +29,7 @@ pub struct ImapFolder {
pub(super) parent: Option<FolderHash>,
pub(super) children: Vec<FolderHash>,
pub permissions: Arc<Mutex<FolderPermissions>>,
pub exists: Arc<Mutex<usize>>,
}
@ -60,6 +61,7 @@ impl BackendFolder for ImapFolder {
name: self.name.clone(),
parent: self.parent,
children: self.children.clone(),
permissions: self.permissions.clone(),
exists: self.exists.clone(),
})
}
@ -67,4 +69,8 @@ impl BackendFolder for ImapFolder {
fn parent(&self) -> Option<FolderHash> {
self.parent
}
fn permissions(&self) -> FolderPermissions {
*self.permissions.lock().unwrap()
}
}

View File

@ -287,6 +287,7 @@ pub struct SelectResponse {
pub uidvalidity: usize,
pub uidnext: usize,
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()])
.to_full_result()
.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() {
debug!("select response: {}", l);
}

View File

@ -182,6 +182,7 @@ pub struct MaildirFolder {
path: PathBuf,
parent: Option<FolderHash>,
children: Vec<FolderHash>,
permissions: FolderPermissions,
}
impl MaildirFolder {
@ -229,6 +230,12 @@ impl MaildirFolder {
None
};
let read_only = if let Ok(metadata) = std::fs::metadata(&pathbuf) {
metadata.permissions().readonly()
} else {
true
};
let ret = MaildirFolder {
hash: h.finish(),
name: file_name,
@ -236,6 +243,16 @@ impl MaildirFolder {
fs_path: pathbuf,
parent,
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()?;
Ok(ret)
@ -290,10 +307,15 @@ impl BackendFolder for MaildirFolder {
path: self.path.clone(),
children: self.children.clone(),
parent: self.parent,
permissions: self.permissions,
})
}
fn parent(&self) -> Option<FolderHash> {
self.parent
}
fn permissions(&self) -> FolderPermissions {
self.permissions
}
}

View File

@ -27,7 +27,8 @@ use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::BackendOp;
use crate::backends::FolderHash;
use crate::backends::{
BackendFolder, Folder, MailBackend, RefreshEvent, RefreshEventConsumer, RefreshEventKind,
BackendFolder, Folder, FolderPermissions, MailBackend, RefreshEvent, RefreshEventConsumer,
RefreshEventKind,
};
use crate::conf::AccountSettings;
use crate::email::parser::BytesExt;
@ -86,6 +87,7 @@ struct MboxFolder {
content: Vec<u8>,
children: Vec<FolderHash>,
parent: Option<FolderHash>,
permissions: FolderPermissions,
}
impl BackendFolder for MboxFolder {
@ -114,6 +116,7 @@ impl BackendFolder for MboxFolder {
content: self.content.clone(),
children: self.children.clone(),
parent: self.parent,
permissions: self.permissions,
})
}
@ -124,6 +127,10 @@ impl BackendFolder for MboxFolder {
fn parent(&self) -> Option<FolderHash> {
self.parent
}
fn permissions(&self) -> FolderPermissions {
self.permissions
}
}
/// `BackendOp` implementor for Mbox
@ -574,6 +581,13 @@ impl MboxType {
.map(|f| f.to_string_lossy().into())
.unwrap_or(String::new());
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(
hash,
MboxFolder {
@ -583,6 +597,16 @@ impl MboxType {
content: Vec::new(),
children: Vec::new(),
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,
},
},
);
/*