mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
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:
committed by
holger krekel
parent
6c9e16d31a
commit
5d79690260
33
src/chat.rs
33
src/chat.rs
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
20
src/job.rs
20
src/job.rs
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
118
src/param.rs
118
src/param.rs
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user