pub mod create_calendar;
pub mod find_calendar_home_set;
pub mod find_calendars;
pub mod get_calendar_resources;
pub mod get_supported_calendar_data;
pub mod get_supported_components;
pub mod get_user_address_set;
pub mod list_calendar_resources;
pub use create_calendar::{CreateCalendar, CreateCalendarResponse};
pub use find_calendar_home_set::{FindCalendarHomeSet, FindCalendarHomeSetResponse};
pub use find_calendars::{FindCalendars, FindCalendarsResponse};
pub use get_calendar_resources::{GetCalendarResources, GetCalendarResourcesResponse};
pub use get_supported_calendar_data::{
CalendarDataType, GetSupportedCalendarData, GetSupportedCalendarDataResponse,
};
pub use get_supported_components::{GetSupportedComponents, GetSupportedComponentsResponse};
pub use get_user_address_set::{GetUserAddressSet, GetUserAddressSetResponse};
pub use list_calendar_resources::{
ComponentFilterError, InvalidComponentType, InvalidTimeRange, ListCalendarResources,
ListCalendarResourcesResponse, VALID_COMPONENT_TYPES,
};
use std::ops::Deref;
use http::Response;
use hyper::{Uri, body::Incoming};
use tower_service::Service;
use crate::{
common::ServiceForUrlError,
dav::WebDavClient,
names,
sd::{BootstrapError, DiscoverableService, FindContextUrlResult, find_context_url},
xmlutils::XmlNode,
};
#[derive(Debug)]
pub struct CalDavClient<C>
where
C: Service<http::Request<String>, Response = Response<Incoming>> + Sync + Send + 'static,
{
pub webdav_client: WebDavClient<C>,
}
impl<C> Deref for CalDavClient<C>
where
C: Service<http::Request<String>, Response = Response<Incoming>> + Sync + Send,
{
type Target = WebDavClient<C>;
fn deref(&self) -> &Self::Target {
&self.webdav_client
}
}
impl<C> CalDavClient<C>
where
C: Service<http::Request<String>, Response = Response<Incoming>> + Sync + Send,
<C as Service<http::Request<String>>>::Error: std::error::Error + Send + Sync,
{
pub fn new(webdav_client: WebDavClient<C>) -> CalDavClient<C> {
CalDavClient { webdav_client }
}
pub async fn bootstrap_via_service_discovery(
mut webdav_client: WebDavClient<C>,
) -> Result<CalDavClient<C>, BootstrapError> {
let service = service_for_url(&webdav_client.base_url)?;
match find_context_url(&webdav_client, service).await {
FindContextUrlResult::BaseUrl => {}
FindContextUrlResult::Found(url) => webdav_client.base_url = url,
FindContextUrlResult::NoneFound => return Err(BootstrapError::NoUsableUrl),
FindContextUrlResult::Error(err) => return Err(err.into()),
}
Ok(CalDavClient { webdav_client })
}
}
impl<C> Clone for CalDavClient<C>
where
C: Service<http::Request<String>, Response = Response<Incoming>> + Sync + Send + Clone,
{
fn clone(&self) -> CalDavClient<C> {
CalDavClient {
webdav_client: self.webdav_client.clone(),
}
}
}
pub fn service_for_url(url: &Uri) -> Result<DiscoverableService, ServiceForUrlError> {
match url
.scheme()
.ok_or(ServiceForUrlError::MissingScheme)?
.as_ref()
{
"https" | "caldavs" => Ok(DiscoverableService::CalDavs),
"http" | "caldav" => Ok(DiscoverableService::CalDav),
_ => Err(ServiceForUrlError::UnknownScheme),
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CalendarComponent {
VEvent,
VTodo,
VJournal,
VFreeBusy,
VAvailability,
Other(String),
}
impl CalendarComponent {
#[must_use]
pub fn as_str(&self) -> &str {
match self {
CalendarComponent::VEvent => "VEVENT",
CalendarComponent::VTodo => "VTODO",
CalendarComponent::VJournal => "VJOURNAL",
CalendarComponent::VFreeBusy => "VFREEBUSY",
CalendarComponent::VAvailability => "VAVAILABILITY",
CalendarComponent::Other(name) => name,
}
}
}
#[must_use]
pub fn supported_calendar_component_set(components: &'_ [CalendarComponent]) -> XmlNode<'_> {
let children = components
.iter()
.map(|component| {
XmlNode::new(&names::COMP).with_attributes(vec![("name", component.as_str())])
})
.collect();
XmlNode::new(&names::SUPPORTED_CALENDAR_COMPONENT_SET).with_children(children)
}