Add Params::get_file(), ::get_path() and ::get_blob()

Turns out that anyone that uses these either justs wants a file or
wants a blob.  Consolidate those patterns into one place and simplify
all the callers.
This commit is contained in:
Floris Bruynooghe
2019-10-21 22:02:51 +02:00
committed by holger krekel
parent 6c9e16d31a
commit 5d79690260
6 changed files with 137 additions and 103 deletions

View File

@@ -677,20 +677,10 @@ fn prepare_msg_common(context: &Context, chat_id: u32, msg: &mut Message) -> Res
if msg.type_0 == Viewtype::Text {
// the caller should check if the message text is empty
} else if msgtype_has_file(msg.type_0) {
let param = msg.param.get(Param::File).ok_or_else(|| {
format_err!("Attachment missing for message of type #{}.", msg.type_0)
})?;
let file = ParamsFile::from_param(context, param)?;
let blob = match file {
ParamsFile::FsPath(path) => {
if msg.is_increation() {
BlobObject::from_path(context, path)?
} else {
BlobObject::create_from_path(context, path)?
}
}
ParamsFile::Blob(blob) => blob,
};
let blob = msg
.param
.get_blob(Param::File, context, !msg.is_increation())?
.ok_or_else(|| format_err!("Attachment missing for message of type #{}", msg.type_0))?;
msg.param.set(Param::File, blob.as_name());
if msg.type_0 == Viewtype::File || msg.type_0 == Viewtype::Image {
// Correct the type, take care not to correct already very special
@@ -892,21 +882,10 @@ fn do_set_draft(context: &Context, chat_id: u32, msg: &mut Message) -> Result<()
None => bail!("No text in draft"),
},
_ => {
let param = msg
let blob = msg
.param
.get(Param::File)
.get_blob(Param::File, context, !msg.is_increation())?
.ok_or_else(|| format_err!("No file stored in params"))?;
let file = ParamsFile::from_param(context, param)?;
let blob = match file {
ParamsFile::FsPath(path) => {
if msg.is_increation() {
BlobObject::from_path(context, path)?
} else {
BlobObject::create_from_path(context, path)?
}
}
ParamsFile::Blob(blob) => blob,
};
msg.param.set(Param::File, blob.as_name());
}
}

View File

@@ -1228,14 +1228,8 @@ unsafe fn create_or_lookup_group(
if part.typ == Viewtype::Image {
grpimage = part
.param
.get(Param::File)
.and_then(|param| ParamsFile::from_param(context, param).ok())
.and_then(|file| match file {
ParamsFile::FsPath(path) => {
BlobObject::create_from_path(context, path).ok()
}
ParamsFile::Blob(blob) => Some(blob),
});
.get_blob(Param::File, context, true)
.unwrap_or(None);
info!(context, "found image {:?}", grpimage);
changed = true;
}

View File

@@ -139,15 +139,7 @@ impl Job {
}
}
if let Some(filename) = self
.param
.get(Param::File)
.and_then(|param| ParamsFile::from_param(context, param).ok())
.map(|file| match file {
ParamsFile::FsPath(path) => path,
ParamsFile::Blob(blob) => blob.to_abs_path(),
})
{
if let Some(filename) = self.param.get_path(Param::File, context).unwrap_or(None) {
if let Ok(body) = dc_read_file(context, &filename) {
if let Some(recipients) = self.param.get(Param::Recipients) {
let recipients_list = recipients
@@ -573,15 +565,7 @@ pub fn job_send_msg(context: &Context, msg_id: u32) -> Result<(), Error> {
let mut mimefactory = MimeFactory::load_msg(context, msg_id)?;
if chat::msgtype_has_file(mimefactory.msg.type_0) {
let file_param = mimefactory
.msg
.param
.get(Param::File)
.and_then(|param| ParamsFile::from_param(context, param).ok())
.map(|file| match file {
ParamsFile::FsPath(path) => path,
ParamsFile::Blob(blob) => blob.to_abs_path(),
});
let file_param = mimefactory.msg.param.get_path(Param::File, context)?;
if let Some(pathNfilename) = file_param {
if (mimefactory.msg.type_0 == Viewtype::Image
|| mimefactory.msg.type_0 == Viewtype::Gif)

View File

@@ -145,13 +145,7 @@ impl Message {
}
pub fn get_file(&self, context: &Context) -> Option<PathBuf> {
self.param
.get(Param::File)
.map_or(None, |param| ParamsFile::from_param(context, param).ok())
.map(|file| match file {
ParamsFile::FsPath(path) => path,
ParamsFile::Blob(blob) => blob.to_abs_path(),
})
self.param.get_path(Param::File, context).unwrap_or(None)
}
/// Check if a message has a location bound to it.
@@ -241,12 +235,8 @@ impl Message {
pub fn get_filebytes(&self, context: &Context) -> u64 {
self.param
.get(Param::File)
.and_then(|param| ParamsFile::from_param(context, param).ok())
.map(|file| match file {
ParamsFile::FsPath(path) => path,
ParamsFile::Blob(blob) => blob.to_abs_path(),
})
.get_path(Param::File, context)
.unwrap_or(None)
.map(|path| dc_get_filebytes(context, &path))
.unwrap_or_default()
}
@@ -829,22 +819,14 @@ pub fn get_summarytext_by_raw(
.stock_str(StockMessage::AcSetupMsgSubject)
.to_string()
} else {
let file_name: String = if let Some(param) = param.get(Param::File) {
ParamsFile::from_param(context, param)
.ok()
.map(|file| match file {
ParamsFile::FsPath(path) => path,
ParamsFile::Blob(blob) => blob.to_abs_path(),
})
.and_then(|path| {
path.file_name()
.map(|fname| fname.to_string_lossy().into_owned())
})
} else {
None
}
.unwrap_or_else(|| "ErrFileName".to_string());
let file_name: String = param
.get_path(Param::File, context)
.unwrap_or(None)
.and_then(|path| {
path.file_name()
.map(|fname| fname.to_string_lossy().into_owned())
})
.unwrap_or_else(|| String::from("ErrFileName"));
let label = context.stock_str(if viewtype == Viewtype::Audio {
StockMessage::Audio
} else {

View File

@@ -11,7 +11,6 @@ use mmime::mailmime::write_mem::*;
use mmime::mmapstring::*;
use mmime::other::*;
use crate::blob::BlobObject;
use crate::chat::{self, Chat};
use crate::config::Config;
use crate::constants::*;
@@ -794,15 +793,10 @@ fn build_body_file(
msg: &Message,
base_name: &str,
) -> Result<(*mut Mailmime, String), Error> {
let param = msg
let blob = msg
.param
.get(Param::File)
.get_blob(Param::File, context, true)?
.ok_or_else(|| format_err!("msg has no filename"))?;
let file = ParamsFile::from_param(context, param)?;
let blob = match file {
ParamsFile::FsPath(path) => BlobObject::create_from_path(context, path)?,
ParamsFile::Blob(blob) => blob,
};
let suffix = blob.suffix().unwrap_or("dat");
// Get file name to use for sending. For privacy purposes, we do
@@ -908,14 +902,7 @@ pub(crate) fn vec_contains_lowercase(vec: &[String], part: &str) -> bool {
}
fn is_file_size_okay(context: &Context, msg: &Message) -> bool {
match msg
.param
.get(Param::File)
.and_then(|param| ParamsFile::from_param(context, param).ok())
.map(|file| match file {
ParamsFile::FsPath(path) => path,
ParamsFile::Blob(blob) => blob.to_abs_path(),
}) {
match msg.param.get_path(Param::File, context).unwrap_or(None) {
Some(path) => {
let bytes = dc_get_filebytes(context, &path);
bytes <= (49 * 1024 * 1024 / 4 * 3)

View File

@@ -194,6 +194,72 @@ impl Params {
self.get(key).and_then(|s| s.parse().ok())
}
/// Gets the given parameter and parse as [ParamsFile].
///
/// See also [Params::get_blob] and [Params::get_path] which may
/// be more convenient.
pub fn get_file<'a>(
&self,
key: Param,
context: &'a Context,
) -> Result<Option<ParamsFile<'a>>, BlobError> {
let val = match self.get(key) {
Some(val) => val,
None => return Ok(None),
};
ParamsFile::from_param(context, val).map(|file| Some(file))
}
/// Gets the parameter and returns a [BlobObject] for it.
///
/// This parses the parameter value as a [ParamsFile] and than
/// tries to return a [BlobObject] for that file. If the file is
/// not yet a valid blob, one will be created by copying the file
/// only if `create` is set to `true`, otherwise the a [BlobError]
/// will result.
///
/// Note that in the [ParamsFile::FsPath] case the blob can be
/// created without copying if the path already referes to a valid
/// blob. If so a [BlobObject] will be returned regardless of the
/// `create` argument.
pub fn get_blob<'a>(
&self,
key: Param,
context: &'a Context,
create: bool,
) -> Result<Option<BlobObject<'a>>, BlobError> {
let val = match self.get(key) {
Some(val) => val,
None => return Ok(None),
};
let file = ParamsFile::from_param(context, val)?;
let blob = match file {
ParamsFile::FsPath(path) => match create {
true => BlobObject::create_from_path(context, path)?,
false => BlobObject::from_path(context, path)?,
},
ParamsFile::Blob(blob) => blob,
};
Ok(Some(blob))
}
/// Gets the parameter and returns a [PathBuf] for it.
///
/// This parses the parameter value as a [ParamsFile] and returns
/// a [PathBuf] to the file.
pub fn get_path(&self, key: Param, context: &Context) -> Result<Option<PathBuf>, BlobError> {
let val = match self.get(key) {
Some(val) => val,
None => return Ok(None),
};
let file = ParamsFile::from_param(context, val)?;
let path = match file {
ParamsFile::FsPath(path) => path,
ParamsFile::Blob(blob) => blob.to_abs_path(),
};
Ok(Some(path))
}
/// Set the given paramter to the passed in `i32`.
pub fn set_int(&mut self, key: Param, value: i32) -> &mut Self {
self.set(key, format!("{}", value));
@@ -213,18 +279,18 @@ impl Params {
/// UTF-8 string it is always safe to convert the value contained
/// within the [ParamsFile::FsPath] back to a [String] or [&str].
/// Despite the type itself does not guarantee this.
#[derive(Debug)]
pub enum ParamsFile<'c> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParamsFile<'a> {
FsPath(PathBuf),
Blob(BlobObject<'c>),
Blob(BlobObject<'a>),
}
impl<'c> ParamsFile<'c> {
impl<'a> ParamsFile<'a> {
/// Parse the [Param::File] value into an object.
///
/// If the value was stored into the [Params] correctly this
/// should not fail.
pub fn from_param(context: &'c Context, src: &str) -> Result<ParamsFile<'c>, BlobError> {
pub fn from_param(context: &'a Context, src: &str) -> Result<ParamsFile<'a>, BlobError> {
let param = match src.starts_with("$BLOBDIR/") {
true => ParamsFile::Blob(BlobObject::from_name(context, src.to_string())?),
false => ParamsFile::FsPath(PathBuf::from(src)),
@@ -237,8 +303,10 @@ impl<'c> ParamsFile<'c> {
mod tests {
use super::*;
use std::fs;
use std::path::Path;
use crate::blob::BlobErrorKind;
use crate::test_utils::*;
#[test]
@@ -304,4 +372,44 @@ mod tests {
assert!(false, "Wrong enum variant");
}
}
// Tests for Params::get_file(), Params::get_path() and Params::get_blob().
#[test]
fn test_params_get_fileparam() {
let t = dummy_context();
let fname = t.dir.path().join("foo");
let mut p = Params::new();
p.set(Param::File, fname.to_str().unwrap());
let file = p.get_file(Param::File, &t.ctx).unwrap().unwrap();
assert_eq!(file, ParamsFile::FsPath(fname.clone()));
let path = p.get_path(Param::File, &t.ctx).unwrap().unwrap();
assert_eq!(path, fname);
// Blob does not exist yet, expect BlobError.
let err = p.get_blob(Param::File, &t.ctx, false).unwrap_err();
assert_eq!(err.kind(), BlobErrorKind::WrongBlobdir);
fs::write(fname, b"boo").unwrap();
let blob = p.get_blob(Param::File, &t.ctx, true).unwrap().unwrap();
assert_eq!(
blob,
BlobObject::from_name(&t.ctx, "foo".to_string()).unwrap()
);
// Blob in blobdir, expect blob.
let bar = t.ctx.get_blobdir().join("bar");
p.set(Param::File, bar.to_str().unwrap());
let blob = p.get_blob(Param::File, &t.ctx, false).unwrap().unwrap();
assert_eq!(
blob,
BlobObject::from_name(&t.ctx, "bar".to_string()).unwrap()
);
p.remove(Param::File);
assert!(p.get_file(Param::File, &t.ctx).unwrap().is_none());
assert!(p.get_path(Param::File, &t.ctx).unwrap().is_none());
assert!(p.get_blob(Param::File, &t.ctx, false).unwrap().is_none());
}
}