|
|
|
@ -279,6 +279,7 @@ pub struct Store {
|
|
|
|
|
pub id_store: Arc<FutureMutex<HashMap<EnvelopeHash, Id<email::EmailObject>>>>,
|
|
|
|
|
pub reverse_id_store: Arc<FutureMutex<HashMap<Id<email::EmailObject>, EnvelopeHash>>>,
|
|
|
|
|
pub blob_id_store: Arc<FutureMutex<HashMap<EnvelopeHash, Id<BlobObject>>>>,
|
|
|
|
|
pub name_store: Arc<FutureMutex<HashMap<EnvelopeHash, Box<str>>>>,
|
|
|
|
|
pub collection: Collection,
|
|
|
|
|
pub mailboxes: Arc<RwLock<HashMap<MailboxHash, JmapMailbox>>>,
|
|
|
|
|
pub mailboxes_index: Arc<RwLock<HashMap<MailboxHash, HashSet<EnvelopeHash>>>>,
|
|
|
|
@ -293,9 +294,38 @@ impl Store {
|
|
|
|
|
pub async fn add_envelope(&self, obj: email::EmailObject) -> Envelope {
|
|
|
|
|
let mut flags = Flag::default();
|
|
|
|
|
let mut labels: IndexSet<TagHash> = IndexSet::new();
|
|
|
|
|
let id;
|
|
|
|
|
let mailbox_ids;
|
|
|
|
|
let blob_id;
|
|
|
|
|
let id = obj.id.clone();
|
|
|
|
|
let mailbox_ids = obj.mailbox_ids.clone();
|
|
|
|
|
let blob_id = obj.blob_id.clone();
|
|
|
|
|
// Source: https://datatracker.ietf.org/doc/html/rfc8621#section-4.1.4
|
|
|
|
|
// name: "String|null"
|
|
|
|
|
// This is the decoded "filename" parameter of the Content-
|
|
|
|
|
// Disposition header field per [RFC2231], or (for compatibility with
|
|
|
|
|
// existing systems) if not present, then it's the decoded "name"
|
|
|
|
|
// parameter of the Content-Type header field per [RFC2047].
|
|
|
|
|
let name_fallback = |obj: &email::EmailObject| -> Box<str> {
|
|
|
|
|
if let Some(val) = obj.headers.get(HeaderName::CONTENT_TYPE) {
|
|
|
|
|
val.to_string().into()
|
|
|
|
|
} else {
|
|
|
|
|
"text/plain".to_string().into()
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
let name = if let Some(val) = obj.headers.get(HeaderName::CONTENT_DISPOSITION) {
|
|
|
|
|
use crate::email::attachment_types::ContentDisposition;
|
|
|
|
|
let mut cp = ContentDisposition::from(val);
|
|
|
|
|
if cp.kind.is_attachment() {
|
|
|
|
|
if let Some(fname) = cp.filename.take() {
|
|
|
|
|
fname.into()
|
|
|
|
|
} else {
|
|
|
|
|
name_fallback(&obj)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
name_fallback(&obj)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
name_fallback(&obj)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let mut tag_lck = self.collection.tag_index.write().unwrap();
|
|
|
|
|
for t in obj.keywords().keys() {
|
|
|
|
@ -320,11 +350,8 @@ impl Store {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id = obj.id.clone();
|
|
|
|
|
mailbox_ids = obj.mailbox_ids.clone();
|
|
|
|
|
blob_id = obj.blob_id.clone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut ret: Envelope = obj.into();
|
|
|
|
|
ret.set_flags(flags);
|
|
|
|
|
ret.tags_mut().extend(labels);
|
|
|
|
@ -332,6 +359,7 @@ impl Store {
|
|
|
|
|
let mut id_store_lck = self.id_store.lock().await;
|
|
|
|
|
let mut reverse_id_store_lck = self.reverse_id_store.lock().await;
|
|
|
|
|
let mut blob_id_store_lck = self.blob_id_store.lock().await;
|
|
|
|
|
let mut name_store_lck = self.name_store.lock().await;
|
|
|
|
|
let mailboxes_lck = self.mailboxes.read().unwrap();
|
|
|
|
|
let mut mailboxes_index_lck = self.mailboxes_index.write().unwrap();
|
|
|
|
|
for (mailbox_id, _) in mailbox_ids {
|
|
|
|
@ -346,6 +374,7 @@ impl Store {
|
|
|
|
|
reverse_id_store_lck.insert(id.clone(), ret.hash());
|
|
|
|
|
id_store_lck.insert(ret.hash(), id);
|
|
|
|
|
blob_id_store_lck.insert(ret.hash(), blob_id);
|
|
|
|
|
name_store_lck.insert(ret.hash(), name);
|
|
|
|
|
ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1217,6 +1246,7 @@ impl JmapType {
|
|
|
|
|
id_store: Default::default(),
|
|
|
|
|
reverse_id_store: Default::default(),
|
|
|
|
|
blob_id_store: Default::default(),
|
|
|
|
|
name_store: Default::default(),
|
|
|
|
|
mailboxes: Default::default(),
|
|
|
|
|
mailboxes_index: Default::default(),
|
|
|
|
|
mailbox_state: Default::default(),
|
|
|
|
|