Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
minicaldav
https://docs.rs/minicaldav/latest
Admin
A minimal CalDAV client and iCal parser library for Rust with minimal dependencies.
Tokens:
18,409
Snippets:
95
Trust Score:
9.1
Update:
2 months ago
Context
Chat
Benchmark
89
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Perform CalDAV operations with minicaldav Source: https://docs.rs/minicaldav/latest/index.html Demonstrates how to authenticate, retrieve calendars, and fetch events from a CalDAV server using the ureq agent. ```rust let agent = ureq::Agent::new(); let url = url::Url::parse("http://mycaldav.com/").unwrap(); let username = "foo"; let password = "s3cret!"; let credentials = minicaldav::Credentials::Basic(username.into(), password.into()); let calendars = minicaldav::get_calendars(agent.clone(), &credentials, &url).unwrap(); for calendar in calendars { println!("{:?}", calendar); let credentials = minicaldav::Credentials::Basic(username.into(), password.into()); let (events, errors) = minicaldav::get_events(agent.clone(), &credentials, &calendar).unwrap(); for event in events { println!("{:?}", event); } for error in errors { println!("Error: {:?}", error); } } ``` -------------------------------- ### propfind_get Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Sends a PROPFIND request to a specified URL using HTTP Basic authentication and parses the XML response for a specific value. ```APIDOC ## Function: propfind_get ### Description Sends a PROPFIND request to the given URL using HTTP Basic authorization and searches the result XML for a value at the specified path. ### Signature `pub fn propfind_get(client: Agent, credentials: &Credentials, url: &Url, body: &str, prop_path: &[&str], depth: &str) -> Result<(String, xmltree::Element), Error>` ### Parameters - **client** (Agent) - The ureq Agent instance. - **credentials** (&Credentials) - Credentials used for HTTP Basic authentication. - **url** (&Url) - The CalDAV endpoint URL. - **body** (&str) - The CalDAV request body to send via PROPFIND. - **prop_path** (&[&str]) - The path in the response XML to extract the text value from. - **depth** (&str) - The value for the Depth HTTP header. ``` -------------------------------- ### Perform a PROPFIND request Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Sends a PROPFIND request to a CalDAV endpoint and parses the XML response to extract a specific value. ```rust pub fn propfind_get( client: Agent, credentials: &Credentials, url: &Url, body: &str, prop_path: &[&str], depth: &str, ) -> Result<(String, xmltree::Element), Error> { let auth = get_auth_header(credentials); let content = client .request("PROPFIND", url.as_str()) .set("Authorization", &auth) .set("Content-Type", "application/xml") .set("Depth", depth) .send_bytes(body.as_bytes())? .into_string() .map_err(|e| Error { kind: ErrorKind::Parsing, message: e.to_string(), })?; trace!("CalDAV propfind response: {:?}", content); let reader = content.as_bytes(); let root = xmltree::Element::parse(reader)?; let mut element = &root; let mut searched = 0; for prop in prop_path { for e in &element.children { if let Some(child) = e.as_element() { if child.name == *prop { searched += 1; element = child; break; } } } } if searched != prop_path.len() { Err(Error { kind: ErrorKind::Parsing, message: format!("Could not find data {:?} in PROPFIND response.", prop_path), }) } else { Ok(( element .get_text() .map(|s| s.to_string()) .unwrap_or_else(|| "".to_string()), root, )) } } ``` -------------------------------- ### Retrieve CalDAV URLs Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Helper functions to fetch the principal and calendar home set URLs from a CalDAV server. ```rust pub fn get_principal_url( client: Agent, credentials: &Credentials, url: &Url, ) -> Result<Url, Error> { let principal_url = propfind_get( client, credentials, url, USER_PRINCIPAL_REQUEST, &[ "response", "propstat", "prop", "current-user-principal", "href", ], "0", )? .0; Ok(url.join(&principal_url)?) } ``` ```rust pub fn get_home_set_url(client: Agent, credentials: &Credentials, url: &Url) -> Result<Url, Error> { let principal_url = get_principal_url(client.clone(), credentials, url).unwrap_or_else(|_| url.clone()); let homeset_url = propfind_get( client, credentials, &principal_url, HOMESET_REQUEST, &["response", "propstat", "prop", "calendar-home-set", "href"], "0", )? .0; Ok(url.join(&homeset_url)?) } ``` -------------------------------- ### propfind_get Function Signature Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.propfind_get.html The function signature for performing a PROPFIND request and parsing the XML response. ```rust pub fn propfind_get( client: Agent, credentials: &Credentials, url: &Url, body: &str, prop_path: &[&str], depth: &str, ) -> Result<(String, Element), Error> ``` -------------------------------- ### propfind_get Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.propfind_get.html Sends a PROPFIND request to a CalDAV endpoint and extracts a value from the response XML. ```APIDOC ## Function: propfind_get ### Description Sends a PROPFIND request to the given URL using HTTP Basic authorization and searches the result XML for a specific value. ### Signature `pub fn propfind_get(client: Agent, credentials: &Credentials, url: &Url, body: &str, prop_path: &[&str], depth: &str) -> Result<(String, Element), Error>` ### Arguments - **client** (Agent) - The ureq Agent used for the request. - **credentials** (&Credentials) - The username and password used for HTTP Basic authentication. - **url** (&Url) - The CalDAV endpoint URL. - **body** (&str) - The CalDAV request body to send via PROPFIND. - **prop_path** (&[&str]) - The path in the response XML to retrieve the XML text value from. - **depth** (&str) - The value for the Depth HTTP header. ``` -------------------------------- ### Implement Ical container methods Source: https://docs.rs/minicaldav/latest/src/minicaldav/ical.rs.html Provides methods for creating new containers, accessing children, and parsing ICAL data from an iterator. ```rust impl Ical { /// Create a new ical container. The name represents the value of the enclosing `BEGIN:` - `END:` pair. pub fn new(name: String) -> Self { Self { name, ..Default::default() } } /// Get the child container which has the given name. pub fn get(&self, child_name: &str) -> Option<&Ical> { self.children.iter().find(|&c| c.name == child_name) } /// Get the child container which has the given name. pub fn get_mut(&mut self, child_name: &str) -> Option<&mut Ical> { self.children.iter_mut().find(|c| c.name == child_name) } /// Parse the given lines to an ICAL container. pub fn parse(lines: &LineIterator) -> Result<Self, Error> { let mut ical: Option<Ical> = None; let mut line_buffer = String::new(); while let Some(line) = lines.next() { if line.trim().is_empty() { continue; } if let Some(line) = line.strip_prefix(' ') { if line_buffer.is_empty() { if let Some(last_prop) = ical.as_mut().and_then(|ical| ical.properties.pop()) { line_buffer.push_str(&last_prop.serialize()); } } line_buffer.push_str(line); continue; } else if !line.contains(':') && line_buffer.is_empty() { line_buffer.push_str(line); continue; } else if !line_buffer.is_empty() { let prop = Property::parse(&line_buffer)?; if let Some(ical) = ical.as_mut() { ical.properties.push(prop); } line_buffer = String::new(); } if !line.contains(':') { line_buffer.push_str(line); continue; } let prop = Property::parse(line)?; if ical.is_none() { if let Some(name) = prop.is("BEGIN") { ical = Some(Ical::new(name.trim().to_string())); } continue; } if prop.is("BEGIN").is_some() { let child = Ical::parse(lines.decrement())?; if let Some(ical) = ical.as_mut() { ical.children.push(child); } continue; } if let Some(name) = prop.is("END") { if ical.is_some() && Some(name.as_str()) == ical.as_ref().map(|ical| ical.name.trim()) { if let Some(ical) = ical { return Ok(ical); } } } if let Some(ical) = ical.as_mut() { ical.properties.push(prop); } else { warn!("minicaldav wants to add a property but it does not seem to collect properties right now.") } } if ical.is_some() { Err(Error::new(format!( "Missing END:{}", ical.map(|i| i.name).unwrap_or_else(|| "".to_string()) ))) } else { Err(Error::new("Invalid input".into())) } } /// Get ICAL formatted string of this container. pub fn serialize(&self) -> String { let mut string = String::new(); ``` -------------------------------- ### CalDAV XML Queries Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html XML query strings used for PROPFIND requests to discover calendar properties. ```xml <d:resourcetype /> <calendar-color xmlns="http://apple.com/ns/ical/" /> <c:supported-calendar-component-set /> </d:prop> </d:propfind> ``` ```xml pub static CALENDARS_QUERY: &str = r#" <c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav"> <d:prop> <d:getetag /> <d:displayname /> <calendar-color xmlns="http://apple.com/ns/ical/" /> <d:resourcetype /> <c:supported-calendar-component-set /> </d:prop> <c:filter> <c:comp-filter name="VCALENDAR" /> </c:filter> </c:calendar-query> "#; ``` -------------------------------- ### CalDAV XML Request Templates Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Static XML strings used for querying calendar events and todos from a CalDAV server. ```rust pub static CALENDAR_EVENTS_REQUEST: &str = r#" <c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav"> <d:prop> <d:getetag /> <c:calendar-data /> </d:prop> <c:filter> <c:comp-filter name="VCALENDAR"> <c:comp-filter name="VEVENT" /> </c:comp-filter> </c:filter> </c:calendar-query> "#; ``` ```rust pub static CALENDAR_TODOS_REQUEST: &str = r#" <c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav"> <d:prop> <d:getetag /> <c:calendar-data /> </d:prop> <c:filter> <c:comp-filter name="VCALENDAR"> <c:comp-filter name="VTODO" /> </c:comp-filter> </c:filter> </c:calendar-query> "#; ``` -------------------------------- ### Generate Authentication Header Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Constructs an HTTP Authorization header string based on the provided credentials. ```rust fn get_auth_header(credentials: &Credentials) -> String { match credentials { Credentials::Basic(username, password) => { format!( "Basic {}", base64::encode(format!("{}:{}", username, password)) ) } Credentials::Bearer(token) => format!("Bearer {}", token), } } ``` -------------------------------- ### Initialize LineIterator Source: https://docs.rs/minicaldav/latest/minicaldav/ical/struct.LineIterator.html Constructor for creating a new LineIterator instance from a string slice. ```rust pub fn new(lines: &'a str) -> Self ``` -------------------------------- ### get_home_set_url function signature Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.get_home_set_url.html The function signature for retrieving the homeset URL from a CalDAV server. ```rust pub fn get_home_set_url( client: Agent, credentials: &Credentials, url: &Url, ) -> Result<Url, Error> ``` -------------------------------- ### get_events function signature Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.get_events.html The function signature for retrieving events from a CalDAV server. ```rust pub fn get_events( client: Agent, credentials: &Credentials, base_url: &Url, calendar_url: &Url, ) -> Result<Vec<EventRef>, Error> ``` -------------------------------- ### get_todos Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.get_todos.html Retrieves ICAL formatted todos from the CalDAV server. ```APIDOC ## get_todos ### Description Get ICAL formatted todos from the CalDAV server. ### Signature `pub fn get_todos(client: Agent, credentials: &Credentials, base_url: &Url, calendar_ref: &CalendarRef) -> Result<Vec<EventRef>, Error>` ### Parameters - **client** (Agent) - The HTTP agent used for the request. - **credentials** (&Credentials) - The authentication credentials for the CalDAV server. - **base_url** (&Url) - The base URL of the CalDAV server. - **calendar_ref** (&CalendarRef) - A reference to the specific calendar to query. ### Returns - **Result<Vec<EventRef>, Error>** - A result containing a vector of EventRef objects on success, or an Error on failure. ``` -------------------------------- ### get_todos function signature Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.get_todos.html The function signature for retrieving to-do items from a CalDAV server. ```rust pub fn get_todos( client: Agent, credentials: &Credentials, base_url: &Url, calendar_ref: &CalendarRef, ) -> Result<Vec<EventRef>, Error> ``` -------------------------------- ### Fetch Calendars from CalDAV Endpoint Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Retrieves all calendars associated with the provided CalDAV base URL and credentials. ```rust pub fn get_calendars( agent: Agent, credentials: &Credentials, base_url: &Url, ) -> Result<Vec<Calendar>, Error> { let calendar_refs = caldav::get_calendars(agent, credentials, base_url)?; let mut calendars = Vec::new(); for calendar_ref in calendar_refs { calendars.push(Calendar { base_url: base_url.clone(), inner: calendar_ref, }); } Ok(calendars) } ``` -------------------------------- ### Calendar Structure Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Represents a remote CalDAV calendar with accessors for URL, name, and color. ```rust #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] pub struct Calendar { base_url: Url, inner: caldav::CalendarRef, } impl Calendar { pub fn url(&self) -> &Url { &self.inner.url } pub fn name(&self) -> &String { &self.inner.name } pub fn color(&self) -> Option<&String> { self.inner.color.as_ref() } } ``` -------------------------------- ### EventBuilder Implementation Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Builder pattern for constructing Event objects with specific properties like UID, summary, and priority. ```rust #[derive(Debug)] pub struct EventBuilder { url: Url, etag: Option<String>, properties: Vec<ical::Property>, } impl EventBuilder { fn build_event(self, name: String) -> Event { Event { etag: self.etag, url: self.url, ical: ical::Ical { name: "VCALENDAR".into(), properties: vec![], children: vec![ical::Ical { name, properties: self.properties, children: vec![], }], }, } } pub fn build(self) -> Event { self.build_event("VEVENT".into()) } pub fn build_todo(self) -> Event { self.build_event("VTODO".into()) } pub fn etag(mut self, etag: Option<String>) -> Self { self.etag = etag; self } pub fn uid(mut self, value: String) -> Self { self.properties.push(ical::Property { name: "UID".to_string(), value, attributes: HashMap::new(), }); self } pub fn timestamp(mut self, value: String) -> Self { self.properties.push(ical::Property { name: "DTSTAMP".to_string(), value, attributes: HashMap::new(), }); self } pub fn summary(mut self, value: String) -> Self { self.properties.push(ical::Property { name: "SUMMARY".to_string(), value, attributes: HashMap::new(), }); self } pub fn priority(mut self, value: String) -> Self { self.properties.push(ical::Property { name: "PRIORITY".to_string(), value, attributes: HashMap::new(), }); self } pub fn duedate(mut self, value: String) -> Self { ``` -------------------------------- ### Retrieve Calendars Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Function to fetch a list of calendars from a CalDAV server using provided credentials. ```rust pub fn get_calendars( client: Agent, credentials: &Credentials, base_url: &Url, ) -> Result<Vec<CalendarRef>, Error> { let mut calendars = Vec::new(); let result = match get_home_set_url(client.clone(), credentials, base_url) { Ok(homeset_url) => propfind_get( client.clone(), credentials, &homeset_url, CALENDARS_REQUEST, &[], "1", ), Err(_e) => propfind_get( client.clone(), credentials, base_url, CALENDARS_REQUEST, &[], "1", ), }; let root = if result.is_err() { propfind_get(client, credentials, base_url, CALENDARS_QUERY, &[], "1")?.1 } else { result?.1 }; for response in &root.children { if let Some(response) = response.as_element() { let name = response .get_child("propstat") .and_then(|e| e.get_child("prop")) .and_then(|e| e.get_child("displayname")) .and_then(|e| e.get_text()); let color = response .get_child("propstat") .and_then(|e| e.get_child("prop")) .and_then(|e| e.get_child("calendar-color")) .and_then(|e| e.get_text()); let is_calendar = response .get_child("propstat") .and_then(|e| e.get_child("prop")) .and_then(|e| e.get_child("resourcetype")) .map(|e| e.get_child("calendar").is_some()) .unwrap_or(false); let supports_vevents = response .get_child("propstat") .and_then(|e| e.get_child("prop")) .and_then(|e| e.get_child("supported-calendar-component-set")) .map(|e| { for c in &e.children { if let Some(child) = c.as_element() { if child.name == "comp" { if let Some(name) = child.attributes.get("name") { if (name == "VEVENT") || (name == "VTODO") { return true; } } } } } false }) .unwrap_or(false); let href = response.get_child("href").and_then(|e| e.get_text()); if !is_calendar || !supports_vevents { continue; } if let Some((href, name)) = href.and_then(|href| name.map(|name| (href, name))) { if let Ok(url) = base_url.join(&href) { calendars.push(CalendarRef { url, name: name.to_string(), color: color.map(|c| c.into()), }) } else { error!("Could not parse url: {}/{}", base_url, href); } } else { continue; } } } Ok(calendars) } ``` -------------------------------- ### get_home_set_url Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.get_home_set_url.html Retrieves the homeset URL for the given credentials from the CalDAV server. ```APIDOC ## get_home_set_url ### Description Retrieves the homeset URL for the given credentials from the CalDAV server. ### Signature `pub fn get_home_set_url(client: Agent, credentials: &Credentials, url: &Url) -> Result<Url, Error>` ### Parameters - **client** (Agent) - The client agent used for the request. - **credentials** (&Credentials) - The user credentials for authentication. - **url** (&Url) - The base URL of the CalDAV server. ### Returns - **Result<Url, Error>** - Returns the homeset URL on success, or an Error if the request fails. ``` -------------------------------- ### minicaldav::get_calendars Source: https://docs.rs/minicaldav/latest/src/minicaldav/lib.rs.html Retrieves a list of calendars from a specified CalDAV server URL using the provided credentials. ```APIDOC ## fn get_calendars ### Description Fetches all calendars available at the provided CalDAV server URL. ### Signature `pub fn get_calendars(agent: ureq::Agent, credentials: &Credentials, url: &url::Url) -> Result<Vec<Calendar>, Error>` ### Parameters - **agent** (ureq::Agent) - The HTTP agent used for requests. - **credentials** (&Credentials) - The authentication credentials (e.g., Basic). - **url** (&url::Url) - The base URL of the CalDAV server. ``` -------------------------------- ### get_events function signature Source: https://docs.rs/minicaldav/latest/minicaldav/fn.get_events.html The function signature for retrieving events from a calendar using an agent and credentials. ```rust pub fn get_events( agent: Agent, credentials: &Credentials, calendar: &Calendar, ) -> Result<(Vec<Event>, Vec<Error>), Error> ``` -------------------------------- ### Credentials Enum Definition Source: https://docs.rs/minicaldav/latest/minicaldav/enum.Credentials.html Defines the supported authentication credentials, including Basic and Bearer tokens. ```rust pub enum Credentials { Basic(String, String), Bearer(String), } ``` -------------------------------- ### HOMESET_REQUEST Constant Definition Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/static.HOMESET_REQUEST.html The static string constant used for CalDAV home set requests. ```rust pub static HOMESET_REQUEST: &str ``` -------------------------------- ### Retrieve Todos from Calendar Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Fetches and parses todos from a specific calendar, returning successfully parsed items and errors for those that failed. ```rust pub fn get_todos( agent: Agent, credentials: &Credentials, calendar: &Calendar, ) -> Result<(Vec<Event>, Vec<Error>), Error> { let todo_refs = caldav::get_todos(agent, credentials, &calendar.base_url, &calendar.inner)?; let mut todos = Vec::new(); let mut errors = Vec::new(); for todo_ref in todo_refs { let lines = ical::LineIterator::new(&todo_ref.data); match ical::Ical::parse(&lines) { Ok(ical) => todos.push(Event { url: todo_ref.url.clone(), etag: todo_ref.etag.clone(), ical, }), Err(e) => errors.push(Error::Ical(format!( "Could not parse todo {}: {:?}", todo_ref.data, e ))), } } Ok((todos, errors)) } ``` -------------------------------- ### Calendar and Event Data Structures Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Data structures representing calendar and event references. ```rust #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone)] pub struct CalendarRef { pub url: Url, pub name: String, pub color: Option<String>, } impl std::fmt::Debug for CalendarRef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("CalendarRef") .field("url", &self.url.to_string()) .field("name", &self.name) .finish() } } #[derive(Clone)] pub struct EventRef { pub etag: Option<String>, pub url: Url, pub data: String, } impl std::fmt::Debug for EventRef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EventRef") ``` -------------------------------- ### Event Structure and Property Management Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Defines a CalDAV event and provides methods for manipulating its properties, attributes, and iCalendar data. ```rust #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// An event in a CalDAV calendar. #[derive(Debug, Clone, Eq, PartialEq)] pub struct Event { etag: Option<String>, url: Url, ical: ical::Ical, } impl Event { /// Construct a new event. pub fn new(etag: Option<String>, url: Url, ical: ical::Ical) -> Self { Self { etag, url, ical } } /// The full url of this event. pub fn url(&self) -> &Url { &self.url } fn get_property(&self, name: &str, datatype: &str) -> Option<Property> { self.ical.get(datatype).and_then(|ical| { ical.properties.iter().find_map(|p| { if p.name == name { Some(Property::from(p.clone())) } else { None } }) }) } /// Get the property of the given name or `None`. pub fn pop_property(&mut self, name: &str) -> Option<Property> { self.ical.get_mut("VEVENT").and_then(|ical| { let index = ical.properties.iter().enumerate().find_map(|(i, p)| { if p.name == name { Some(i) } else { None } }); if let Some(index) = index { Some(Property::from(ical.properties.remove(index))) } else { None } }) } pub fn ical(&self) -> &Ical { &self.ical } pub fn add(&mut self, property: Property) { if let Some(ical) = self.ical.get_mut("VEVENT") { ical.properties.push(property.into()); } } pub fn property(&self, name: &str) -> Option<Property> { self.get_property(name, "VEVENT") } /// Get the property of the given name or `None`. pub fn property_todo(&self, name: &str) -> Option<Property> { self.get_property(name, "VTODO") } /// Get the value of the given property name or `None`. pub fn get(&self, name: &str) -> Option<&String> { self.ical.get("VEVENT").and_then(|ical| { ical.properties .iter() .find_map(|p| if p.name == name { Some(&p.value) } else { None }) }) } /// Set the value of the given property name or create a new property. pub fn set(&mut self, name: &str, value: &str) { match self .ical .get_mut("VEVENT") .and_then(|e| e.properties.iter_mut().find(|p| p.name == name)) { Some(p) => { p.value = value.into(); } None => self.add(Property::new(name, value)), } } pub fn set_property_attribute(&mut self, name: &str, attr_name: &str, attr_value: &str) { if let Some(p) = self .ical .get_mut("VEVENT") .and_then(|e| e.properties.iter_mut().find(|p| p.name == name)) { p.attributes.insert(attr_name.into(), attr_value.into()); } } /// Get all properties of this event. fn get_properties(&self, datatype: &str) -> Vec<(&String, &String)> { self.ical .get(datatype) .map(|ical| { ical.properties .iter() .map(|p| (&p.name, &p.value)) .collect::<Vec<(&String, &String)>>() }) .unwrap_or_else(|| { error!("Could not get properties: No VEVENT section."); Vec::new() }) } pub fn into_properties(self) -> Vec<Property> { for ical in self.ical.children { if ical.name == "VEVENT" { ``` -------------------------------- ### get_calendars function signature Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.get_calendars.html The function signature for retrieving calendars using an Agent, Credentials, and a base URL. ```rust pub fn get_calendars( client: Agent, credentials: &Credentials, base_url: &Url, ) -> Result<Vec<CalendarRef>, Error> ``` -------------------------------- ### USER_PRINCIPAL_REQUEST Definition Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/static.USER_PRINCIPAL_REQUEST.html The static string constant used for CalDAV principal requests. ```rust pub static USER_PRINCIPAL_REQUEST: &str ``` -------------------------------- ### Retrieve Events from Calendar Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Fetches and parses events from a specific calendar, returning successfully parsed items and errors for those that failed. ```rust pub fn get_events( agent: Agent, credentials: &Credentials, calendar: &Calendar, ) -> Result<(Vec<Event>, Vec<Error>), Error> { let event_refs = caldav::get_events(agent, credentials, &calendar.base_url, calendar.url())?; let mut events = Vec::new(); let mut errors = Vec::new(); for event_ref in event_refs { let lines = ical::LineIterator::new(&event_ref.data); match ical::Ical::parse(&lines) { Ok(ical) => events.push(Event { url: event_ref.url.clone(), etag: event_ref.etag.clone(), ical, }), Err(e) => errors.push(Error::Ical(format!( "Could not parse event {}: {:?}", event_ref.data, e ))), } } Ok((events, errors)) } ``` -------------------------------- ### Add iCalendar properties using builder methods Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html These methods allow for the fluent construction of iCalendar properties by appending them to the internal properties list. ```rust self.properties.push(ical::Property { name: "DUE".to_string(), value, attributes: HashMap::new(), }); self } pub fn status(mut self, value: String) -> Self { self.properties.push(ical::Property { name: "STATUS".to_string(), value, attributes: HashMap::new(), }); self } pub fn generic(mut self, name: String, value: String) -> Self { self.properties.push(ical::Property { name, value, attributes: HashMap::new(), }); self } pub fn location(mut self, value: Option<String>) -> Self { if let Some(value) = value { self.properties.push(ical::Property { name: "LOCATION".to_string(), value, attributes: HashMap::new(), }); } self } pub fn start(mut self, value: String, attributes: Vec<(&str, &str)>) -> Self { let mut attribs = HashMap::new(); for (k, v) in attributes { attribs.insert(k.into(), v.into()); } self.properties.push(ical::Property { name: "DTSTART".to_string(), value, attributes: attribs, }); self } pub fn end(mut self, value: String, attributes: Vec<(&str, &str)>) -> Self { let mut attribs = HashMap::new(); for (k, v) in attributes { attribs.insert(k.into(), v.into()); } self.properties.push(ical::Property { name: "DTEND".to_string(), value, attributes: attribs, }); self } pub fn description(mut self, value: Option<String>) -> Self { if let Some(value) = value { self.properties.push(ical::Property { name: "DESCRIPTION".to_string(), value, attributes: HashMap::new(), }); } self } pub fn rrule(mut self, value: Option<String>) -> Self { if let Some(value) = value { self.properties.push(ical::Property { name: "RRULE".to_string(), value, attributes: HashMap::new(), }); } self } } ``` -------------------------------- ### get_events Source: https://docs.rs/minicaldav/latest/minicaldav/caldav/fn.get_events.html Retrieves ICAL formatted events from the specified CalDAV server using the provided client, credentials, and URLs. ```APIDOC ## get_events ### Description Get ICAL formatted events from the CalDAV server. ### Signature `pub fn get_events(client: Agent, credentials: &Credentials, base_url: &Url, calendar_url: &Url) -> Result<Vec<EventRef>, Error>` ### Parameters - **client** (Agent) - The HTTP agent used for the request. - **credentials** (&Credentials) - The authentication credentials for the CalDAV server. - **base_url** (&Url) - The base URL of the CalDAV server. - **calendar_url** (&Url) - The specific URL of the calendar to fetch events from. ### Returns - **Result<Vec<EventRef>, Error>** - A result containing a vector of EventRef objects on success, or an Error on failure. ``` -------------------------------- ### Save Event to Server Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Serializes and saves an event to the CalDAV server, automatically incrementing the SEQUENCE property if present. ```rust pub fn save_event( agent: Agent, credentials: &Credentials, mut event: Event, ) -> Result<Event, Error> { for prop in &mut event.ical.properties { if prop.name == "SEQUENCE" { if let Ok(num) = prop.value.parse::<i64>() { prop.value = format!("{}", num + 1); } } } let event_ref = caldav::EventRef { data: event.ical.serialize(), etag: None, url: event.url, }; let event_ref = caldav::save_event(agent, credentials, event_ref)?; Ok(Event { etag: event_ref.etag, url: event_ref.url, ..event }) } ``` -------------------------------- ### get_todos Source: https://docs.rs/minicaldav/latest/index.html Retrieves all todos from a specific calendar. ```APIDOC ## get_todos ### Description Get all todos in the given Calendar. This function returns a tuple of all todos that could be parsed and all todos that couldn't. If anything besides parsing the todo data fails, an Err will be returned. ### Signature `pub fn get_todos(agent: ureq::Agent, credentials: &Credentials, calendar: &Calendar) -> Result<(Vec<Todo>, Vec<Error>), Error>` ``` -------------------------------- ### Retrieve CalDAV Data Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Functions to fetch and parse events or todos from a CalDAV server using HTTP REPORT requests. ```rust pub fn get_events( client: Agent, credentials: &Credentials, base_url: &Url, calendar_url: &Url, ) -> Result<Vec<EventRef>, Error> { let auth = get_auth_header(credentials); let content = client .request("REPORT", calendar_url.as_str()) .set("Authorization", &auth) .set("Depth", "1") .set("Content-Type", "application/xml") .send_bytes(CALENDAR_EVENTS_REQUEST.as_bytes())? .into_string() .map_err(|e| Error { kind: ErrorKind::Parsing, message: e.to_string(), })?; trace!("Read CalDAV events: {:?}", content); let reader = content.as_bytes(); let root = xmltree::Element::parse(reader)?; let mut events = Vec::new(); for c in &root.children { if let Some(child) = c.as_element() { let href = child.get_child("href").and_then(|e| e.get_text()); let etag = child .get_child("propstat") .and_then(|e| e.get_child("prop")) .and_then(|e| e.get_child("getetag")) .and_then(|e| e.get_text()) .map(|e| e.to_string()); let data = child .get_child("propstat") .and_then(|e| e.get_child("prop")) .and_then(|e| e.get_child("calendar-data")) .and_then(|e| e.get_text()); if href.is_none() || etag.is_none() || data.is_none() { continue; } if let Some((href, data)) = href.and_then(|href| data.map(|data| (href, data))) { if let Ok(url) = base_url.join(&href) { events.push(EventRef { url, data: data.to_string(), etag, }) } else { error!("Could not parse url {}/{}", base_url, href) } } } } Ok(events) } ``` ```rust pub fn get_todos( client: Agent, credentials: &Credentials, base_url: &Url, calendar_ref: &CalendarRef, ) -> Result<Vec<EventRef>, Error> { let auth = get_auth_header(credentials); let content = client .request("REPORT", calendar_ref.url.as_str()) .set("Authorization", &auth) .set("Depth", "1") .set("Content-Type", "application/xml") .send_bytes(CALENDAR_TODOS_REQUEST.as_bytes())? .into_string() .map_err(|e| Error { kind: ErrorKind::Parsing, message: e.to_string(), })?; trace!("Read CalDAV events: {:?}", content); let reader = content.as_bytes(); let root = xmltree::Element::parse(reader)?; let mut todos = Vec::new(); for c in &root.children { if let Some(child) = c.as_element() { let href = child.get_child("href").and_then(|e| e.get_text()); let etag = child .get_child("propstat") .and_then(|e| e.get_child("prop")) .and_then(|e| e.get_child("getetag")) .and_then(|e| e.get_text()) .map(|e| e.to_string()); ``` -------------------------------- ### CalDAV Request Constants Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html XML request bodies used for querying CalDAV server properties. ```rust pub static USER_PRINCIPAL_REQUEST: &str = r#" <d:propfind xmlns:d="DAV:"> <d:prop> <d:current-user-principal /> </d:prop> </d:propfind> "#; ``` ```rust pub static HOMESET_REQUEST: &str = r#" <d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav" > <d:self/> <d:prop> <c:calendar-home-set /> </d:prop> </d:propfind> "#; ``` ```rust pub static CALENDARS_REQUEST: &str = r#" <d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav" > <d:prop> <d:displayname /> ``` -------------------------------- ### Save or Update Event on CalDAV Server Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Performs a PUT request to create or update an event. Returns an EventRef containing the updated ETag from the server response. ```rust pub fn save_event( client: Agent, credentials: &Credentials, event_ref: EventRef, ) -> Result<EventRef, Error> { let auth = get_auth_header(credentials); let response = client .put(event_ref.url.as_str()) .set("Content-Type", "text/calendar") .set("Content-Length", &event_ref.data.len().to_string()) .set("Authorization", &auth) .send(event_ref.data.as_bytes())?; if let Some(etag) = response.header("ETag") { Ok(EventRef { etag: Some(etag.into()), ..event_ref }) } else { Ok(EventRef { etag: None, ..event_ref }) } } ``` -------------------------------- ### Error Handling Implementation Source: https://docs.rs/minicaldav/latest/src/minicaldav/api.rs.html Custom error enum for minicaldav operations with conversion implementations for underlying ical and caldav errors. ```rust /// Errors that may occur during minicalav operations. #[derive(Debug)] pub enum Error { Ical(String), Caldav(String), } impl std::error::Error for Error {} impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::Ical(msg) => write!(f, "CalDAV Error: '{}'", msg), Error::Caldav(msg) => write!(f, "ICAL Error: '{}'", msg), } } } impl From<caldav::Error> for Error { fn from(e: caldav::Error) -> Self { Error::Ical(e.message) } } impl From<ical::Error> for Error { fn from(e: ical::Error) -> Self { Error::Caldav(e.message) } } ``` -------------------------------- ### CalDAV Error Handling Structures Source: https://docs.rs/minicaldav/latest/src/minicaldav/caldav.rs.html Custom error types and trait implementations for mapping external library errors to the application's Error structure. ```rust #[derive(Debug)] pub struct Error { pub kind: ErrorKind, pub message: String, } #[derive(Debug)] pub enum ErrorKind { Http, Parsing, } impl From<ureq::Error> for Error { fn from(e: ureq::Error) -> Self { Self { kind: ErrorKind::Http, message: format!("{:?}", e), } } } impl From<xmltree::ParseError> for Error { fn from(e: xmltree::ParseError) -> Self { Self { kind: ErrorKind::Parsing, message: e.to_string(), } } } impl From<url::ParseError> for Error { fn from(e: url::ParseError) -> Self { Self { kind: ErrorKind::Parsing, message: e.to_string(), } } } ``` -------------------------------- ### Calendar Methods Source: https://docs.rs/minicaldav/latest/minicaldav/struct.Calendar.html Methods available on the Calendar struct to retrieve calendar metadata. ```APIDOC ## pub fn url(&self) -> &Url ### Description Returns the URL of the remote CalDAV calendar. ## pub fn name(&self) -> &String ### Description Returns the name of the calendar. ## pub fn color(&self) -> Option<&String> ### Description Returns the optional color associated with the calendar. ``` -------------------------------- ### pub fn save_event Source: https://docs.rs/minicaldav/latest/minicaldav/fn.save_event.html Saves the provided event to the CalDAV server. ```APIDOC ## pub fn save_event(agent: Agent, credentials: &Credentials, event: Event) -> Result<Event, Error> ### Description Saves the given event on the CalDAV server. ### Parameters - **agent** (Agent) - The agent used to communicate with the server. - **credentials** (&Credentials) - The authentication credentials for the CalDAV server. - **event** (Event) - The event object to be saved. ### Returns - **Result<Event, Error>** - Returns the saved Event on success, or an Error if the operation fails. ```