melib/jmap: add byte operations
parent
a41dc6c38a
commit
791033d2fc
|
@ -54,6 +54,9 @@ macro_rules! _impl_get_mut {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod operations;
|
||||
use operations::*;
|
||||
|
||||
pub mod connection;
|
||||
use connection::*;
|
||||
|
||||
|
@ -168,6 +171,13 @@ macro_rules! get_conf_val {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Store {
|
||||
byte_cache: FnvHashMap<EnvelopeHash, EnvelopeCache>,
|
||||
id_store: FnvHashMap<EnvelopeHash, Id>,
|
||||
blob_id_store: FnvHashMap<EnvelopeHash, Id>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JmapType {
|
||||
account_name: String,
|
||||
|
@ -175,6 +185,7 @@ pub struct JmapType {
|
|||
is_subscribed: Arc<IsSubscribedFn>,
|
||||
server_conf: JmapServerConf,
|
||||
connection: Arc<JmapConnection>,
|
||||
store: Arc<RwLock<Store>>,
|
||||
folders: Arc<RwLock<FnvHashMap<FolderHash, JmapFolder>>>,
|
||||
}
|
||||
|
||||
|
@ -185,6 +196,7 @@ impl MailBackend for JmapType {
|
|||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||
let mut w = AsyncBuilder::new();
|
||||
let folders = self.folders.clone();
|
||||
let store = self.store.clone();
|
||||
let connection = self.connection.clone();
|
||||
let folder_hash = folder.hash();
|
||||
let handle = {
|
||||
|
@ -192,6 +204,7 @@ impl MailBackend for JmapType {
|
|||
let closure = move |_work_context| {
|
||||
tx.send(AsyncStatus::Payload(protocol::get(
|
||||
&connection,
|
||||
&store,
|
||||
&folders.read().unwrap()[&folder_hash],
|
||||
)))
|
||||
.unwrap();
|
||||
|
@ -231,7 +244,11 @@ impl MailBackend for JmapType {
|
|||
}
|
||||
|
||||
fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> {
|
||||
unimplemented!()
|
||||
Box::new(JmapOp::new(
|
||||
hash,
|
||||
self.connection.clone(),
|
||||
self.store.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
fn save(&self, bytes: &[u8], folder: &str, flags: Option<Flag>) -> Result<()> {
|
||||
|
@ -257,6 +274,7 @@ impl JmapType {
|
|||
|
||||
Ok(Box::new(JmapType {
|
||||
connection: Arc::new(JmapConnection::new(&server_conf, online.clone())?),
|
||||
store: Arc::new(RwLock::new(Store::default())),
|
||||
folders: Arc::new(RwLock::new(FnvHashMap::default())),
|
||||
account_name: s.name.clone(),
|
||||
online,
|
||||
|
|
|
@ -129,7 +129,7 @@ use std::hash::Hasher;
|
|||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EmailObject {
|
||||
#[serde(default)]
|
||||
id: Id,
|
||||
pub id: Id,
|
||||
#[serde(default)]
|
||||
mailbox_ids: HashMap<Id, bool>,
|
||||
#[serde(default)]
|
||||
|
@ -155,7 +155,7 @@ pub struct EmailObject {
|
|||
#[serde(default)]
|
||||
attachments: Vec<Value>,
|
||||
#[serde(default)]
|
||||
blob_id: String,
|
||||
pub blob_id: String,
|
||||
#[serde(default)]
|
||||
has_attachment: bool,
|
||||
#[serde(default)]
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* meli - jmap module.
|
||||
*
|
||||
* Copyright 2017 - 2019 Manos Pitsidianakis
|
||||
*
|
||||
* This file is part of meli.
|
||||
*
|
||||
* meli is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* meli is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::backends::BackendOp;
|
||||
use crate::email::*;
|
||||
use crate::error::{MeliError, Result};
|
||||
use std::cell::Cell;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
/// `BackendOp` implementor for Imap
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct JmapOp {
|
||||
hash: EnvelopeHash,
|
||||
connection: Arc<JmapConnection>,
|
||||
store: Arc<RwLock<Store>>,
|
||||
bytes: Option<String>,
|
||||
flags: Cell<Option<Flag>>,
|
||||
headers: Option<String>,
|
||||
body: Option<String>,
|
||||
}
|
||||
|
||||
impl JmapOp {
|
||||
pub fn new(
|
||||
hash: EnvelopeHash,
|
||||
connection: Arc<JmapConnection>,
|
||||
store: Arc<RwLock<Store>>,
|
||||
) -> Self {
|
||||
JmapOp {
|
||||
hash,
|
||||
connection,
|
||||
store,
|
||||
bytes: None,
|
||||
headers: None,
|
||||
body: None,
|
||||
flags: Cell::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BackendOp for JmapOp {
|
||||
fn description(&self) -> String {
|
||||
self.store
|
||||
.try_read()
|
||||
.and_then(|store_lck| Ok(store_lck.id_store[&self.hash].clone()))
|
||||
.unwrap_or(String::new())
|
||||
}
|
||||
|
||||
fn as_bytes(&mut self) -> Result<&[u8]> {
|
||||
if self.bytes.is_none() {
|
||||
let mut store_lck = self.store.write().unwrap();
|
||||
if !(store_lck.byte_cache.contains_key(&self.hash)
|
||||
&& store_lck.byte_cache[&self.hash].bytes.is_some())
|
||||
{
|
||||
let blob_id = &store_lck.blob_id_store[&self.hash];
|
||||
let res = self.connection
|
||||
.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&format!("https://jmap-proxy.local/raw/fc32dffe-14e7-11ea-a277-2477037a1804/{blob_id}/{name}", blob_id = blob_id, name = ""))
|
||||
.send();
|
||||
|
||||
let res_text = res?.text()?;
|
||||
|
||||
store_lck.byte_cache.entry(self.hash).or_default().bytes = Some(res_text);
|
||||
}
|
||||
self.bytes = store_lck.byte_cache[&self.hash].bytes.clone();
|
||||
}
|
||||
Ok(&self.bytes.as_ref().unwrap().as_bytes())
|
||||
}
|
||||
|
||||
fn fetch_flags(&self) -> Flag {
|
||||
Flag::default()
|
||||
}
|
||||
|
||||
fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, value: bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -314,24 +314,11 @@ pub fn get_message(conn: &JmapConnection, ids: &[String]) -> Result<Vec<Envelope
|
|||
.collect::<Vec<Envelope>>())
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*json!({
|
||||
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
|
||||
"methodCalls": [["Email/get", {
|
||||
"ids": ids,
|
||||
"properties": [ "threadId", "mailboxIds", "from", "subject",
|
||||
"receivedAt",
|
||||
"htmlBody", "bodyValues" ],
|
||||
"bodyProperties": [ "partId", "blobId", "size", "type" ],
|
||||
"fetchHTMLBodyValues": true,
|
||||
"maxBodyValueBytes": 256
|
||||
}, format!("m{}", seq).as_str()]],
|
||||
}))
|
||||
|
||||
*/
|
||||
|
||||
pub fn get(conn: &JmapConnection, folder: &JmapFolder) -> Result<Vec<Envelope>> {
|
||||
pub fn get(
|
||||
conn: &JmapConnection,
|
||||
store: &Arc<RwLock<Store>>,
|
||||
folder: &JmapFolder,
|
||||
) -> Result<Vec<Envelope>> {
|
||||
let email_query_call: EmailQueryCall = EmailQueryCall {
|
||||
filter: EmailFilterCondition::new().in_mailbox(Some(folder.id.clone())),
|
||||
collapse_threads: false,
|
||||
|
@ -349,7 +336,6 @@ pub fn get(conn: &JmapConnection, folder: &JmapFolder) -> Result<Vec<Envelope>>
|
|||
MessageProperty::From,
|
||||
MessageProperty::To,
|
||||
MessageProperty::Subject,
|
||||
MessageProperty::Date,
|
||||
MessageProperty::Preview,
|
||||
],
|
||||
};
|
||||
|
@ -382,8 +368,18 @@ pub fn get(conn: &JmapConnection, folder: &JmapFolder) -> Result<Vec<Envelope>>
|
|||
let mut v: MethodResponse = serde_json::from_str(&res_text).unwrap();
|
||||
let e = GetResponse::<EmailObject>::try_from(v.method_responses.pop().unwrap())?;
|
||||
let GetResponse::<EmailObject> { list, .. } = e;
|
||||
Ok(list
|
||||
let ids = list
|
||||
.iter()
|
||||
.map(|obj| (obj.id.clone(), obj.blob_id.clone()))
|
||||
.collect::<Vec<(Id, Id)>>();
|
||||
let ret = list
|
||||
.into_iter()
|
||||
.map(std::convert::Into::into)
|
||||
.collect::<Vec<Envelope>>())
|
||||
.collect::<Vec<Envelope>>();
|
||||
let mut store_lck = store.write().unwrap();
|
||||
for (env, (id, blob_id)) in ret.iter().zip(ids.into_iter()) {
|
||||
store_lck.id_store.insert(env.hash(), id);
|
||||
store_lck.blob_id_store.insert(env.hash(), blob_id);
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue