/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use super::{ImapResponse, capability::QuotaResourceName, quoted_string}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Arguments { pub tag: String, pub name: String, } pub struct QuotaItem { pub name: String, pub resources: Vec, } pub struct QuotaResource { pub resource: QuotaResourceName, pub total: u64, pub used: u64, } pub struct Response { pub quota_root_items: Vec, pub quota_items: Vec, } impl ImapResponse for Response { fn serialize(self) -> Vec { let mut buf = Vec::with_capacity(64); if !self.quota_root_items.is_empty() { buf.extend_from_slice(b"* QUOTAROOT"); for item in &self.quota_root_items { buf.push(b' '); quoted_string(&mut buf, item); } buf.extend_from_slice(b"\r\n"); } if !self.quota_items.is_empty() { for item in &self.quota_items { buf.extend_from_slice(b"* QUOTA "); quoted_string(&mut buf, &item.name); buf.extend_from_slice(b" ("); for (pos, resource) in item.resources.iter().enumerate() { if pos > 0 { buf.push(b' '); } let mut total = resource.total; let mut used = resource.used; match resource.resource { QuotaResourceName::Storage => { total /= 1024; used /= 1024; buf.extend_from_slice(b"STORAGE ") } QuotaResourceName::Message => buf.extend_from_slice(b"MESSAGE "), QuotaResourceName::Mailbox => buf.extend_from_slice(b"MAILBOX "), QuotaResourceName::AnnotationStorage => { buf.extend_from_slice(b"ANNOTATION-STORAGE ") } } buf.extend_from_slice(format!("{used} {total}").as_bytes()); } buf.extend_from_slice(b")\r\n"); } } buf } } #[cfg(test)] mod tests { use crate::protocol::{ImapResponse, capability::QuotaResourceName}; use super::{QuotaItem, QuotaResource}; #[test] fn serialize_quota() { for (response, expected) in [ ( super::Response { quota_root_items: vec!["INBOX".into(), "#test".into()], quota_items: vec![], }, "* QUOTAROOT \"INBOX\" \"#test\"\r\n", ), ( super::Response { quota_root_items: vec![], quota_items: vec![QuotaItem { name: "INBOX".into(), resources: vec![QuotaResource { resource: QuotaResourceName::Storage, total: 1073741824, used: 1048576, }], }], }, "* QUOTA \"INBOX\" (STORAGE 1024 1048576)\r\n", ), ( super::Response { quota_root_items: vec!["my mailbox".into(), "".into()], quota_items: vec![QuotaItem { name: "INBOX".into(), resources: vec![ QuotaResource { resource: QuotaResourceName::Storage, total: 1073741824, used: 1048576, }, QuotaResource { resource: QuotaResourceName::Message, total: 100, used: 2, }, ], }], }, concat!( "* QUOTAROOT \"my mailbox\" \"\"\r\n", "* QUOTA \"INBOX\" (STORAGE 1024 1048576 MESSAGE 2 100)\r\n" ), ), ] { assert_eq!(String::from_utf8(response.serialize()).unwrap(), expected); } } }