use std::collections::HashMap; use crate::xml::TagList; use actix_web::{ body::BoxBody, http::{header::ContentType, StatusCode}, HttpRequest, HttpResponse, Responder, ResponseError, }; use quick_xml::name::Namespace; use rustical_xml::{XmlRootTag, XmlSerialize, XmlSerializeRoot}; #[derive(XmlSerialize)] pub struct PropTagWrapper(#[xml(flatten, ty = "untagged")] pub Vec); // RFC 2518 // #[derive(XmlSerialize)] pub struct PropstatElement { pub prop: PropType, #[xml(serialize_with = "xml_serialize_status")] pub status: StatusCode, } fn xml_serialize_status( status: &StatusCode, ns: Option, tag: Option<&[u8]>, namespaces: &HashMap, writer: &mut quick_xml::Writer, ) -> std::io::Result<()> { XmlSerialize::serialize(&format!("HTTP/1.1 {}", status), ns, tag, namespaces, writer) } #[derive(XmlSerialize)] #[xml(untagged)] pub enum PropstatWrapper { Normal(PropstatElement>), TagList(PropstatElement), } // RFC 2518 // #[derive(XmlSerialize)] #[xml(ns = "crate::namespace::NS_DAV")] pub struct ResponseElement { pub href: String, #[xml(serialize_with = "xml_serialize_optional_status")] pub status: Option, #[xml(flatten)] pub propstat: Vec>, } fn xml_serialize_optional_status( val: &Option, ns: Option, tag: Option<&[u8]>, namespaces: &HashMap, writer: &mut quick_xml::Writer, ) -> std::io::Result<()> { XmlSerialize::serialize( &val.map(|status| format!("HTTP/1.1 {}", status)), ns, tag, namespaces, writer, ) } impl Default for ResponseElement { fn default() -> Self { Self { href: String::new(), status: None, propstat: vec![], } } } // RFC 2518 // // Extended by sync-token as specified in RFC 6578 #[derive(XmlSerialize, XmlRootTag)] #[xml(root = b"multistatus", ns = "crate::namespace::NS_DAV")] #[xml(ns_prefix( crate::namespace::NS_DAV = b"", crate::namespace::NS_CARDDAV = b"CARD", crate::namespace::NS_CALDAV = b"CAL", crate::namespace::NS_CALENDARSERVER = b"CS" ))] pub struct MultistatusElement { #[xml(rename = b"response", flatten)] pub responses: Vec>, #[xml(rename = b"response", flatten)] pub member_responses: Vec>, pub sync_token: Option, } impl Default for MultistatusElement { fn default() -> Self { Self { responses: vec![], member_responses: vec![], sync_token: None, } } } impl Responder for MultistatusElement { type Body = BoxBody; fn respond_to(self, _req: &HttpRequest) -> HttpResponse { let mut output: Vec<_> = b"\n".into(); let mut writer = quick_xml::Writer::new_with_indent(&mut output, b' ', 4); if let Err(err) = self.serialize_root(&mut writer) { return crate::Error::from(err).error_response(); } HttpResponse::MultiStatus() .content_type(ContentType::xml()) .body(String::from_utf8(output).unwrap()) } }