public void RetrievalofAllPendingToDos() { var xmlStr = @"<C:filter xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VCALENDAR"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VTODO""> <C:prop-filter name=""COMPLETED""> <C:is-not-defined/> </C:prop-filter> <C:prop-filter name=""STATUS""> <C:text-match negate-condition=""yes"">CANCELLED</C:text-match> </C:prop-filter> </C:comp-filter> </C:comp-filter></C:filter>"; var calStr = @"BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example Corp.//CalDAV Client//EN BEGIN:VTODO DTSTAMP:20060205T235335Z DUE;VALUE=DATE:20060104 STATUS:NEEDS-ACTION SUMMARY:Task #1 UID:[email protected] BEGIN:VALARM ACTION:AUDIO TRIGGER;RELATED=START:-PT10M END:VALARM END:VTODO END:VCALENDAR"; var calendar = new VCalendar(calStr); var xmlTree = XmlTreeStructure.Parse(xmlStr); var result = calendar.FilterResource(xmlTree); Assert.True(result); }
public async Task PropNameMethod(string url, string calendarResourceId, int?depth, XmlTreeStructure multistatusTree) { //Here it is created the response body for the collection or resource //It depends if calendarResourceId == null. var primaryResponse = await PropNameFillTree(url); //The response body is added to the result xml tree. multistatusTree.AddChild(primaryResponse); //Now I start putting all objectResource responses if the primary target was a collection //and if depth is greater than depth 0. #region Adding the responses for resources. if (calendarResourceId == null && depth == 1 || depth == -1) { var collection = _collectionRepository.Get(url); foreach (var calendarResource in collection.CalendarResources) { var resourceResponse = await PropNameFillTree(url + calendarResource.Name, calendarResource.Name); multistatusTree.AddChild(resourceResponse); } } #endregion }
/// <summary> /// Used to build a response with an error /// </summary> /// <param name="response">The response that comes from the controller</param> /// <param name="errorMessage">The message to put in the error.</param> /// <param name="errorCode">The code of the error.</param> /// <param name="href">The requested href.</param> /// <returns></returns> private async Task ReturnError(HttpResponse response, string errorMessage, int errorCode, string href) { //build the root of the xml var multistatusNode = new XmlTreeStructure("multistatus", "DAV:") { Namespaces = new Dictionary <string, string> { { "D", "DAV:" }, { "C", "urn:ietf:params:xml:ns:caldav" } } }; //each returned resource has is own response and href nodes var responseNode = new XmlTreeStructure("response", "DAV:"); var hrefNode = new XmlTreeStructure("href", "DAV:"); hrefNode.AddValue(href); //href is a child pf response responseNode.AddChild(hrefNode); IXMLTreeStructure statusNode = new XmlTreeStructure("status", "DAV:"); statusNode.AddValue($"HTTP/1.1 {errorCode} {errorMessage}"); responseNode.AddChild(statusNode); multistatusNode.AddChild(responseNode); await response.WriteAsync(multistatusNode.ToString()); }
public void UnitTest3() { var calStr = @"BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example Corp.//CalDAV Client//EN BEGIN:VTODO DTSTAMP:20060205T235300Z DUE;TZID=US/Eastern:20060106T120000 LAST-MODIFIED:20060205T235308Z SEQUENCE:1 STATUS:NEEDS-ACTION SUMMARY:Task #2 UID:[email protected] BEGIN:VALARM ACTION:AUDIO TRIGGER;RELATED=START:-PT10M END:VALARM END:VTODO END:VCALENDAR"; var xmlStr = @"<C:filter xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VCALENDAR"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VTODO""> <C:comp-filter name=""VALARM""> <C:time-range start=""20060106T100000Z"" end=""20060107T100000Z""/> </C:comp-filter> </C:comp-filter> </C:comp-filter></C:filter>"; var calendar = new VCalendar(calStr); var xmlTree = XmlTreeStructure.Parse(xmlStr); var result = calendar.FilterResource(xmlTree); Assert.True(result); }
public void UnitTest2() { var xmlStr = @"<C:filter xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VCALENDAR""> <C:comp-filter name=""VFREEBUSY""> <C:time-range start=""20060102T000000Z"" end=""20060103T000000Z""/> </C:comp-filter> </C:comp-filter> </C:filter>"; var calStr = @"BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example Corp.//CalDAV Client//EN BEGIN:VFREEBUSY ORGANIZER;CN=""Bernard Desruisseaux"":mailto:[email protected] UID:[email protected] DTSTAMP:20050530T123421Z DTSTART:20060101T100000Z DTEND:20060108T100000Z FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z END:VFREEBUSY END:VCALENDAR"; var calendar = VCalendar.Parse(calStr); var xmlTree = XmlTreeStructure.Parse(xmlStr); var result = calendar.FilterResource(xmlTree); Assert.True(result); }
public async Task ReadCalendarObjectResource(Dictionary <string, string> propertiesAndHeaders, HttpResponse response) { #region Extracting Properties string url; propertiesAndHeaders.TryGetValue("url", out url); #endregion //An easy way of accessing the headers of the http response response.GetTypedHeaders(); //StorageManagement.SetUserAndCollection(principalUrl, collectionName); //Must return the Etag header of the COR var calendarRes = _resourceRespository.Get(url); if (calendarRes == null || !StorageManagement.ExistCalendarObjectResource(url)) { response.StatusCode = (int)HttpStatusCode.NotFound; return; } var resourceBody = await StorageManagement.GetCalendarObjectResource(url); var etagProperty = calendarRes.Properties.FirstOrDefault(x => x.Name == "getetag"); if (etagProperty != null) { var etag = XmlTreeStructure.Parse(etagProperty.Value).Value; response.Headers["etag"] = etag; } await response.WriteAsync(resourceBody); }
/// <summary> /// Process the report depending on the values of the header /// and the body. /// </summary> /// <returns></returns> public async Task ProcessRequest(HttpContext httpContext) { var body = new StreamReader(httpContext.Request.Body).ReadToEnd(); // var node = xmlBody.Children.First(); var xmlBody = XmlTreeStructure.Parse(body); //take the target url that is the identifier of the collection var urlId = httpContext.Request.GetRealUrl(); //take the first node of the xml and process the request //by the name of the first node switch (xmlBody.NodeName) { case "calendar-query": await CalendarQuery(xmlBody, urlId, httpContext); break; case "calendar-multiget": await CalendarMultiget(xmlBody, httpContext); break; default: throw new NotImplementedException( $"The REPORT request {xmlBody.NodeName} with ns equal to {xmlBody.MainNamespace} is not implemented yet ."); } }
/// <summary> /// Take the calendar that passed the filter and /// create the multi-status xml. /// </summary> /// <param name="resources">The resources to be returned</param> /// <param name="calDataNode"> /// THis is the node with name ="prop" /// When used in a calendaring REPORT request, the CALDAV:calendar-data XML /// element specifies which parts of calendar object resources need to be returned in the /// response.If the CALDAV:calendar-data XML element doesn't contain any /// CALDAV:comp element, calendar object resources will be returned in their entirety. /// </param> /// <param name="httpContext"></param> /// <returns>The string representation of the multi-status Xml with the results.</returns> public async Task ReportResponseBuilder(IEnumerable <KeyValuePair <string, VCalendar> > resources, IXMLTreeStructure calDataNode, HttpContext httpContext) { var multistatusNode = new XmlTreeStructure("multistatus", "DAV:") { Namespaces = new Dictionary <string, string> { { "D", "DAV:" }, { "C", "urn:ietf:params:xml:ns:caldav" } } }; //take the node that specified the comp and properties //to return foreach (var resource in resources) { IXMLTreeStructure statusNode; //each returned resource has is own response and nodes var responseNode = new XmlTreeStructure("response", "DAV:"); var hrefNode = new XmlTreeStructure("href", "DAV:"); var href = resource.Key[0] != '/' ? "/" + resource.Key : resource.Key; hrefNode.AddValue(href); //href is a child pf response responseNode.AddChild(hrefNode); //if the resource is null it was not foound so // add an error status if (resource.Value == null) { statusNode = new XmlTreeStructure("status", "DAV:"); statusNode.AddValue("HTTP/1.1 404 Not Found"); responseNode.AddChild(statusNode); } else { var propstatNode = new XmlTreeStructure("propstat", "DAV:"); //that the requested data var propStats = await ProccessPropNode(calDataNode, resource); foreach (var propStat in propStats) { responseNode.AddChild(propStat); } } multistatusNode.AddChild(responseNode); } var responseText = multistatusNode.ToString(); var responseBytes = Encoding.UTF8.GetBytes(responseText); httpContext.Response.ContentLength = responseBytes.Length; await httpContext.Response.Body.WriteAsync(responseBytes, 0, responseBytes.Length); }
public void RecursiveSeekerTest3() { var calStr = @"BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example Corp.//CalDAV Client//EN BEGIN:VTIMEZONE LAST-MODIFIED:20040110T032845Z TZID:US/Eastern BEGIN:DAYLIGHT DTSTART:20000404T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 TZNAME:EDT TZOFFSETFROM:-0500 TZOFFSETTO:-0400 END:DAYLIGHT BEGIN:STANDARD DTSTART:20001026T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZNAME:EST TZOFFSETFROM:-0400 TZOFFSETTO:-0500 END:STANDARD END:VTIMEZONE BEGIN:VEVENT ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:[email protected] DTSTAMP:20060206T001220Z DTSTART;TZID=US/Eastern:20060104T100000 DURATION:PT1H LAST-MODIFIED:20060206T001330Z ORGANIZER:mailto:[email protected] SEQUENCE:1 STATUS:TENTATIVE SUMMARY:Event #3 UID:[email protected] X-ABC-GUID:[email protected] END:VEVENT END:VCALENDAR"; var xmlStr = @"<C:comp-filter name=""VCALENDAR"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VTODO""> <C:prop-filter name=""UID""> <C:text-match collation=""i;octet"" >[email protected]</C:text-match> </C:prop-filter> </C:comp-filter> </C:comp-filter>"; var calendar = new VCalendar(calStr); var xmlTree = XmlTreeStructure.Parse(xmlStr); IXMLTreeStructure tree; ICalendarComponent comp; var result = calendar.ComponentSeeker(xmlTree, out tree, out comp); Assert.False(result); /*Assert.Equal("VEVENT", comp.Name); * Assert.Equal("VEVENT", tree.Attributes["name"]);*/ }
private async Task <bool> BuiltResponseForSet(string url, string calendarResourceId, bool errorOccurred, IXMLTreeStructure setTree, IXMLTreeStructure response) { //For each property it is tried to remove, if not possible change the error occured to true and //continue setting dependency error to the rest. var prop = setTree.GetChild("prop"); var errorStack = new Stack <string>(); foreach (var property in prop.Children) { var propstat = new XmlTreeStructure("propstat", "DAV:"); var stat = new XmlTreeStructure("status", "DAV:"); var resProp = new XmlTreeStructure("prop", "DAV:"); resProp.AddChild(new XmlTreeStructure(property.NodeName, property.MainNamespace)); propstat.AddChild(stat); propstat.AddChild(resProp); response.AddChild(propstat); if (errorOccurred) { stat.Value = "HTTP/1.1 424 Failed Dependency"; } else { //Try to modify the specified property if it exist, if not try to create it //gets an error message from the stack in case of problems. errorOccurred = !(calendarResourceId != null ? await _resourceRespository.CreateOrModifyProperty(url, property.NodeName, property.MainNamespace, GetValueFromRealProperty(property), errorStack, false) : await _collectionRespository.CreateOrModifyProperty(url, property.NodeName, property.MainNamespace, GetValueFromRealProperty(property), errorStack, false)); //collection.CreateOrModifyProperty(property.NodeName, property.MainNamespace, // GetValueFromRealProperty(property), errorStack)); if (errorOccurred && errorStack.Count > 0) { stat.Value = errorStack.Pop(); } else { stat.Value = "HTTP/1.1 200 OK"; //db.SaveChanges(); } } } return(errorOccurred); }
public void FilterResourceTest1() { var calStr = @"BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example Corp.//CalDAV Client//EN BEGIN:VTIMEZONE LAST-MODIFIED:20040110T032845Z TZID:US/Eastern BEGIN:DAYLIGHT DTSTART:20000404T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 TZNAME:EDT TZOFFSETFROM:-0500 TZOFFSETTO:-0400 END:DAYLIGHT BEGIN:STANDARD DTSTART:20001026T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZNAME:EST TZOFFSETFROM:-0400 TZOFFSETTO:-0500 END:STANDARD END:VTIMEZONE BEGIN:VEVENT ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:[email protected] DTSTAMP:20060206T001220Z DTSTART;TZID=US/Eastern:20060104T100000 DURATION:PT1H LAST-MODIFIED:20060206T001330Z ORGANIZER:mailto:[email protected] SEQUENCE:1 STATUS:TENTATIVE SUMMARY:Event #3 UID:[email protected] X-ABC-GUID:[email protected] END:VEVENT END:VCALENDAR"; var xmlStr = @"<C:filter xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VCALENDAR"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VEVENT""> <C:prop-filter name=""ATTENDEE""> <C:text-match collation=""i;ascii-casemap"">mailto:[email protected]</C:text-match> <C:param-filter name=""PARTSTAT""> <C:text-match collation=""i;ascii-casemap"">NEEDS-ACTION</C:text-match> </C:param-filter> </C:prop-filter> </C:comp-filter> </C:comp-filter></C:filter>"; var calendar = new VCalendar(calStr); var xmlTree = XmlTreeStructure.Parse(xmlStr); var result = calendar.FilterResource(xmlTree); Assert.True(result); }
private async Task <bool> BuiltResponseForRemove(string url, string calendarResourceId, bool errorOccurred, IXMLTreeStructure removeTree, IXMLTreeStructure response) { //For each property it is tried to remove, if not possible change the error occured to true and //continue setting dependency error to the rest. var prop = removeTree.GetChild("prop"); var errorStack = new Stack <string>(); foreach (var property in prop.Children) { //The structure for the response does not change. //It is constructed with a propstat and the value is never showed in the prop element. var propstat = new XmlTreeStructure("propstat", "DAV:"); var stat = new XmlTreeStructure("status", "DAV:"); var resProp = new XmlTreeStructure("prop", "DAV:"); propstat.AddChild(stat); propstat.AddChild(resProp); resProp.AddChild(new XmlTreeStructure(property.NodeName, property.MainNamespace)); response.AddChild(propstat); //If an error occurred previously the stat if 424 Failed Dependency. if (errorOccurred) { stat.Value = "HTTP/1.1 424 Failed Dependency"; } else { //Try to remove the specified property, gets an error message from the stack in case of problems. errorOccurred = !(calendarResourceId != null ? await _resourceRespository.RemoveProperty(url, new KeyValuePair <string, string>(property.NodeName, property.MainNamespace), errorStack) : await _collectionRespository.RemoveProperty(url, new KeyValuePair <string, string>(property.NodeName, property.MainNamespace), errorStack)); //collection.RemoveProperty(property.NodeName, property.MainNamespace, errorStack)); if (errorOccurred && errorStack.Count > 0) { stat.Value = errorStack.Pop(); } else { stat.Value = "HTTP/1.1 200 OK"; // db.SaveChanges(); } } } return(errorOccurred); }
public async Task AllPropMethod(string url, string calendarResourceId, int?depth, List <KeyValuePair <string, string> > aditionalProperties, XmlTreeStructure multistatusTree) { //error flag //Here it is created the response body for the collection or resource //It depends if calendarResourceId == null. var primaryResponse = await AllPropFillTree(url, calendarResourceId, aditionalProperties); //The response body is added to the result xml tree. multistatusTree.AddChild(primaryResponse); //check if there was any error IXMLTreeStructure errorNode; var errorOcurred = primaryResponse.GetChildAtAnyLevel("responsedescription", out errorNode); //Now I start putting all objectResource responses if the primary target was a collection //and if depth is greater than depth 0. #region Adding the responses for resources. if (calendarResourceId == null && depth == 1 || depth == -1) { var collection = _collectionRepository.Get(url); foreach (var calendarResource in collection.CalendarResources) { //For every resource in the collection it is added a new xml "response" var resourceResponse = await AllPropFillTree(url + calendarResource.Name, calendarResource.Name, aditionalProperties); multistatusTree.AddChild(resourceResponse); //error check if (!errorOcurred) { errorOcurred = resourceResponse.GetChildAtAnyLevel("responsedescription", out errorNode); } } } if (errorOcurred) { //if an error occured it is added a new "responsedescription" with a message of the error //to the root of the tree. That is the "multistatus" xml. errorNode = new XmlTreeStructure("responsedescription", "DAV:"); errorNode.AddValue("There has been an error"); multistatusTree.AddChild(errorNode); } #endregion }
public async Task ProcessRequest(HttpRequest request, HttpResponse response) { //check the depth of the header // This report is only defined when the Depth header has value "0"; // other values result in a 400 (Bad Request) error response. if (request.Headers.ContainsKey("Depth")) { var depth = request.Headers["Depth"]; if (depth != "\"0\"") { response.StatusCode = 400; return; } } string href = request.Path; //TODO: take here the email of the user by calling //to the authentication api var userEmail = ""; response = null; //take the string representation of the body var bodyStr = request.Body.ToString(); var xmlbody = XmlTreeStructure.Parse(bodyStr); switch (xmlbody.NodeName) { case "acl-principal-prop-set": await AclPrincipalPropSet(xmlbody, response); break; case "principal-match": await PrincipalMatch(xmlbody, userEmail, href, response); break; case "principal-property-search": await PrincipalPropertySearch(xmlbody, request, response); break; case "principal-search-property-set": await PrincipalSearchPropertySet(response); break; } }
public void UnitTest4() { var doc = @"<?xml version=""1.0"" encoding=""utf-8"" ?> <C:calendar-query xmlns:D=""DAV:"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <D:prop> <D:getetag/> <C:calendar-data> <C:comp name=""VCALENDAR""> <C:prop name=""VERSION""/> <C:comp name=""VEVENT""> <C:prop name=""SUMMARY""/> <C:prop name=""UID""/> <C:prop name=""DTSTART""/> <C:prop name=""DTEND""/> <C:prop name=""DURATION""/> <C:prop name=""RRULE""/> <C:prop name=""RDATE""/> <C:prop name=""EXRULE""/> <C:prop name=""EXDATE""/> <C:prop name=""RECURRENCE-ID""/> </C:comp> <C:comp name=""VTIMEZONE""/> </C:comp> </C:calendar-data> </D:prop> <C:filter> <C:comp-filter name=""VCALENDAR""> <C:comp-filter name=""VEVENT""> <C:time-range start=""20060104T000000Z"" end=""20060105T000000Z""/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>"; var xDoc = XDocument.Parse(doc); xDoc.ToString(); var temp1 = xDoc.Root.Attributes().Where(x => x.IsNamespaceDeclaration); var item = xDoc.CreateWriter(); var result = XmlTreeStructure.Parse(doc); IXMLTreeStructure filter; Assert.True(result.GetChildAtAnyLevel("filter", out filter)); Assert.Equal(filter.GetChild("comp-filter").Attributes["name"], "VCALENDAR"); }
public void IXmlTreeStrucureToString() { var doc = @"<?xml version=""1.0"" encoding=""utf-8"" ?> <C:calendar-query xmlns:D=""DAV:"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <D:prop> <D:getetag/> <C:calendar-data> <C:comp name=""VCALENDAR""> <C:prop name=""VERSION""/> <C:comp name=""VEVENT""> <C:prop name=""SUMMARY""/> <C:prop name=""UID""/> <C:prop name=""DTSTART""/> <C:prop name=""DTEND""/> <C:prop name=""DURATION""/> <C:prop name=""RRULE""/> <C:prop name=""RDATE""/> <C:prop name=""EXRULE""/> <C:prop name=""EXDATE""/> <C:prop name=""RECURRENCE-ID""/> </C:comp> <C:comp name=""VTIMEZONE""/> </C:comp> </C:calendar-data> </D:prop> <C:filter> <C:comp-filter name=""VCALENDAR""> <C:comp-filter name=""VEVENT""> <C:time-range start=""20060104T000000Z"" end=""20060105T000000Z""/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>"; var xmlTreeStructure = XmlTreeStructure.Parse(doc); var xmlTreeStructure2 = XmlTreeStructure.Parse(xmlTreeStructure.ToString()); var xmlStr1 = xmlTreeStructure.ToString(); var xmlStr2 = xmlTreeStructure2.ToString(); Assert.Equal(xmlStr1, xmlStr2); }
public void PartialRetrievalofEventsbyTimeRange() { var xmlStr = @"<C:filter xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VCALENDAR"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <C:comp-filter name=""VEVENT""> <C:time-range start=""20060104T000000Z"" end=""20060105T000000Z""/> </C:comp-filter> </C:comp-filter></C:filter>"; var calStr = @"BEGIN:VCALENDAR VERSION:2.0 BEGIN:VTIMEZONE LAST-MODIFIED:20040110T032845Z TZID:US/Eastern BEGIN:DAYLIGHT DTSTART:20000404T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 TZNAME:EDT TZOFFSETFROM:-0500 TZOFFSETTO:-0400 END:DAYLIGHT BEGIN:STANDARD DTSTART:20001026T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZNAME:EST TZOFFSETFROM:-0400 TZOFFSETTO:-0500 END:STANDARD END:VTIMEZONE BEGIN:VEVENT DTSTART;TZID=US/Eastern:20060102T120000 DURATION:PT1H RRULE:FREQ=DAILY;COUNT=5 SUMMARY:Event #2 UID:[email protected] END:VEVENT END:VCALENDAR"; var calendar = new VCalendar(calStr); var xmlTree = XmlTreeStructure.Parse(xmlStr); var result = calendar.FilterResource(xmlTree); Assert.True(result); }
public void UnitTest3() { var doc = @"<?xml version=""1.0"" encoding=""utf-8"" ?> <C:calendar-query xmlns:D=""DAV:"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <D:prop> <D:getetag/> <C:calendar-data> <C:comp name=""VCALENDAR""> <C:prop name=""VERSION""/> <C:comp name=""VEVENT""> <C:prop name=""SUMMARY""/> <C:prop name=""UID""/> <C:prop name=""DTSTART""/> <C:prop name=""DTEND""/> <C:prop name=""DURATION""/> <C:prop name=""RRULE""/> <C:prop name=""RDATE""/> <C:prop name=""EXRULE""/> <C:prop name=""EXDATE""/> <C:prop name=""RECURRENCE-ID""/> </C:comp> <C:comp name=""VTIMEZONE""/> </C:comp> </C:calendar-data> </D:prop> <C:filter> <C:comp-filter name=""VCALENDAR""> <C:comp-filter name=""VEVENT""> <C:time-range start=""20060104T000000Z"" end=""20060105T000000Z""/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>"; var result = XmlTreeStructure.Parse(doc); IXMLTreeStructure filter; Assert.True(result.GetChildAtAnyLevel("filter", out filter)); Assert.NotNull(filter.GetChild("comp-filter")); }
public async Task <bool> PreconditionsOK(Dictionary <string, string> propertiesAndHeaders, HttpResponse response) { #region Extracting Properties var body = propertiesAndHeaders["body"]; var url = propertiesAndHeaders["url"]; #endregion if (fs.ExistCalendarCollection(url) || await _collectionRepository.Exist(url)) { response.StatusCode = (int)HttpStatusCode.Forbidden; response.Body.Write(@"<?xml version='1.0' encoding='UTF-8'?> <error xmlns='DAV:'> <resource-must-be-null/> </error>"); return(false); } if (!string.IsNullOrEmpty(body)) { var bodyTree = XmlTreeStructure.Parse(body); if (bodyTree == null) { response.StatusCode = (int)HttpStatusCode.Forbidden; response.Body.Write("Wrong Body"); return(false); } if (bodyTree.NodeName != "mkcalendar") { response.StatusCode = (int)HttpStatusCode.Forbidden; response.Body.Write("Wrong Body"); return(false); } } return(true); }
private static IXMLTreeStructure xmlWalker(XElement node) { var output = new XmlTreeStructure(node.Name.LocalName, null) { Namespaces = node.Attributes().Where(x => x.IsNamespaceDeclaration). ToDictionary(x => x.Name.LocalName, x => x.Value), Value = node.Value }; foreach (var attribute in node.Attributes().Where(x => !output.Namespaces.Keys.Contains(x.Name.LocalName))) { output.AddAttribute(attribute.Name.LocalName, attribute.Value); } var descendants = node.Elements(); var descNodes = node.DescendantNodes(); foreach (var descendant in descendants) { output.AddChild(xmlWalker(descendant)); } return(output); }
public void UnitTest2() { var tree = new XmlTreeStructure("node1", "DAV:", new Dictionary <string, string> { { "D", "DAV:" }, { "C", "urn:ietf:params:xml: ns: caldav" } }); tree.AddChild(new XmlTreeStructure("child1", null)). AddChild(new XmlTreeStructure("child2", null)); IXMLTreeStructure child2; tree.GetChildAtAnyLevel("child2", out child2); child2.AddChild(new XmlTreeStructure("child3", null)) .GetChild("child3").AddChild(new XmlTreeStructure("child4", null)); IXMLTreeStructure child4; tree.GetChildAtAnyLevel("child4", out child4); child4.AddChild(new XmlTreeStructure("child5", null)); var child6 = new XmlTreeStructure("child6", null); IXMLTreeStructure child5; tree.GetChildAtAnyLevel("child5", out child5); child5.AddChild(child6); IXMLTreeStructure child6_1; tree.GetChildAtAnyLevel("child6", out child6_1); IXMLTreeStructure test; tree.GetChildAtAnyLevel("prop", out test); Assert.Null(test); test = tree.GetChild("prop"); Assert.Null(test); Assert.Equal(child6_1, child6); }
/// <summary> /// Call the method to perform a PROFIND over a /// principal. /// Initially the client could do a PROFIND over /// the server to discover all the user calendars /// or could PORFIND directly over a calendar URL. /// </summary> /// <param name="httpContext"></param> /// <returns>The request</returns> public async Task Profind(HttpContext httpContext) { var requestPath = httpContext.Request.Path; var streamReader = new StreamReader(httpContext.Request.Body); //read the body of the request var bodyString = streamReader.ReadToEnd(); //try to authenticate the request either with the cookies or the user credentials var principal = _authenticate.AuthenticateRequest(httpContext); //if the principal is null then there is some problem with the authentication //so return //if (principal == null) // return; var body = XmlTreeStructure.Parse(bodyString); //take the requested properties var reqProperties = ExtractPropertiesNameMainNS(body); await BuildResponse(httpContext.Response, requestPath, reqProperties, principal); }
private void ChangeToDependencyError(XmlTreeStructure response) { //this method is the one in charge of fix the status messages //of all the properties that were fine before the error. foreach (var child in response.Children) { if (child.NodeName != "propstat") { continue; } var status = child.GetChild("status"); var statMessage = status.Value; //if the message is not OK means that we reach //the error and no more further message changing is needed. if (statMessage != "HTTP/1.1 200 OK") { return; } ((XmlTreeStructure)status).Value = "HTTP/1.1 424 Failed Dependency"; } }
/// <summary> /// Get the permission for the given principal /// in some resource. /// </summary> /// <param name="principal">The principal that wants to know his permissions.</param> /// <param name="property">The resource or collection's DAV:acl property</param> /// <returns>Return an I</returns> public static XmlTreeStructure GetCurrentUserPermissions(this Principal principal, Property property) { var pUrl = principal.PrincipalURL; var aclP = XDocument.Parse(property.Value).Root; IEnumerable <XElement> principalGrantPermissions = null; XName aceName = "ace"; //take the permission for the principal if any var descendants = aclP?.Descendants(); var aces = descendants.Where(x => x.Name.LocalName == aceName); var principalAce = aces.FirstOrDefault(ace => ace.Descendants() .FirstOrDefault(x => x.Name.LocalName == "href")?.Value == pUrl); if (principalAce != null) { principalGrantPermissions = principalAce.Descendants() .FirstOrDefault(x => x.Name.LocalName == "grant")?.Elements(); } //take the permission for all users if any var output = new XElement("current-user-privilege-set", new XAttribute(XNamespace.Xmlns + "D", "DAV:")); //add the permission to the response if (principalGrantPermissions != null) { foreach (var permission in principalGrantPermissions) { output.Add(permission); } } var outputStr = output.ToString(); var xmlTree = XmlTreeStructure.Parse(outputStr) as XmlTreeStructure; return(xmlTree); }
/// <summary> /// Create the DAV:current-user-principal. /// If not principalUrl is provided means that the /// user is not authenticated. /// </summary> /// <param name="principal"> /// The current principal url, or nothing if the principal is not /// authenticated. /// </param> /// <returns></returns> public static IXMLTreeStructure CreateCurrentUserPrincipal(Principal principal) { var output = new XmlTreeStructure("current-user-principal", "DAV:"); IXMLTreeStructure href; //if not principal URL is provided means that //the principal is not authenticated. if (principal != null) { href = new XmlTreeStructure("href", "DAV:") { Value = principal.PrincipalURL } } ; else { href = new XmlTreeStructure("unauthenticated", "DAV:"); } output.AddChild(href); return(output); }
/// <summary> /// Returns a Response XML element with all the property names /// and property values of the visible properties. /// </summary> /// <param name="url"></param> /// <param name="calendarResourceId">Name of the resource</param> /// <param name="additionalProperties">List of additional requested properties (key=name; value=namespace)</param> /// <returns></returns> private async Task <XmlTreeStructure> AllPropFillTree(string url, string calendarResourceId, List <KeyValuePair <string, string> > additionalProperties) { #region Adding the response of the collection or resource. //Adding standard structure for a "response" element. var treeChild = new XmlTreeStructure("response", "DAV:"); #region Adding the <D:href>/api/v1/collections/users|groups/principalId/{collectionName}/{calendarResourceId}?</D:href> var href = new XmlTreeStructure("href", "DAV:"); href.AddValue(SystemProperties._baseUrl + url); treeChild.AddChild(href); #endregion #region Adding the propstat #region Selecting properties var propertiesCol = new List <XmlTreeStructure>(); var propertiesOk = new List <XmlTreeStructure>(); var propertiesWrong = new List <XmlTreeStructure>(); var errorStack = new Stack <string>(); //Here all visible properties are retrieve plus a collection of extra properties that can be //defined in the request body. if (calendarResourceId == null) { var properties = await _collectionRepository.GetAllProperties(url); foreach (var property in properties) { //TODO: Check that the property is accessible beyond its visibility. var tempTree = property.Value == null ? new XmlTreeStructure(property.Name, property.Namespace) { Value = "" } : XmlTreeStructure.Parse(property.Value); propertiesCol.Add((XmlTreeStructure)tempTree); } //looking for additional properties if (additionalProperties != null && additionalProperties.Count > 0) { foreach (var addProperty in additionalProperties) { //gets the property from database var property = await _collectionRepository.GetProperty(url, addProperty); //Builds the xmlTreeExtructure checking that if the value is null thats because //the property was not found. IXMLTreeStructure prop; if (property != null) { prop = property.Value == null ? new XmlTreeStructure(property.Name, property.Namespace) { Value = "" } } : XmlTreeStructure.Parse(property.Value); else { prop = new XmlTreeStructure(addProperty.Key, addProperty.Value); } propertiesCol.Add((XmlTreeStructure)prop); } } } else { var properties = await _resourceRespository.GetAllProperties(url); foreach (var property in properties) { //TODO: Check that the property is accessible beyond its visibility. var tempTree = property.Value == null ? new XmlTreeStructure(property.Name, property.Namespace) { Value = "" } : XmlTreeStructure.Parse(property.Value); propertiesCol.Add((XmlTreeStructure)tempTree); } //looking for additional properties if (additionalProperties != null && additionalProperties.Count > 0) { foreach (var addProperty in additionalProperties) { //gets the property from database var property = await _resourceRespository.GetProperty(url, addProperty); //Builds the xmlTreeExtructure checking that if the value is null thats because //the property was not found. IXMLTreeStructure prop; if (property != null) { prop = property.Value == null ? new XmlTreeStructure(property.Name, property.Namespace) { Value = "" } } : XmlTreeStructure.Parse(property.Value); else { prop = new XmlTreeStructure(addProperty.Key, addProperty.Value); } propertiesCol.Add((XmlTreeStructure)prop); } } } //Here there are divided all properties between recovered and error recovering foreach (var propTree in propertiesCol) { if (propTree.Value != null) { propertiesOk.Add(propTree); } else { propertiesWrong.Add(propTree); } } #endregion #region Adding nested propOK //This procedure has been explained in another method. //Here the retrieve properties are grouped. var propstatOk = new XmlTreeStructure("propstat", "DAV:"); var propOk = new XmlTreeStructure("prop", "DAV:"); //Here i add all properties to the prop. foreach (var property in propertiesOk) { propOk.AddChild(property); } propstatOk.AddChild(propOk); #region Adding nested status OK var statusOk = new XmlTreeStructure("status", "DAV:"); statusOk.AddValue("HTTP/1.1 200 OK"); propstatOk.AddChild(statusOk); #endregion #endregion #region Adding nested propWrong //Here the properties that could not be retrieved are grouped. var propstatWrong = new XmlTreeStructure("propstat", "DAV:"); var propWrong = new XmlTreeStructure("prop", "DAV:"); //Here i add all properties to the prop. foreach (var property in propertiesWrong) { propWrong.AddChild(property); } propstatWrong.AddChild(propWrong); #region Adding nested status Not Found var statusWrong = new XmlTreeStructure("status", "DAV:"); statusWrong.AddValue("HTTP/1.1 400 Not Found"); propstatWrong.AddChild(statusWrong); #endregion #region Adding responseDescription when wrong //Here i add an description for explain the errors. //This should be aplied in all method with an similar structure but for the moment is only used here. //However this is not required. var responseDescrpWrong = new XmlTreeStructure("responsedescription", "DAV:"); responseDescrpWrong.AddValue("The properties doesn't exist"); propstatWrong.AddChild(responseDescrpWrong); #endregion #endregion //If any of the "status" group is empty, it is not included. if (propertiesOk.Count > 0) { treeChild.AddChild(propstatOk); } if (propertiesWrong.Count > 0) { treeChild.AddChild(propstatWrong); } #endregion return(treeChild); #endregion }
/// <summary> /// Build the xml of the body and write /// its string representation to the HttpRespose.Body /// </summary> /// <param name="response">The response of the request.</param> /// <param name="principalsAndProperties">The principals with its properties.</param> /// <returns></returns> public async Task WriteBody(HttpResponse response, Dictionary <Principal, IEnumerable <Property> > principalsAndProperties) { //build the root of the xml var multistatusNode = new XmlTreeStructure("multistatus", "DAV:") { Namespaces = new Dictionary <string, string> { { "D", "DAV:" }, { "C", "urn:ietf:params:xml:ns:caldav" } } }; //take the node that specified the comp and properties //to return foreach (var pp in principalsAndProperties) { IXMLTreeStructure statusNode; //each returned resource has is own response and href nodes var responseNode = new XmlTreeStructure("response", "DAV:"); var hrefNode = new XmlTreeStructure("href", "DAV:"); hrefNode.AddValue(pp.Key.PrincipalURL); //href is a child pf response responseNode.AddChild(hrefNode); //if the resource is null it was not foound so // add an error status if (pp.Value == null) { statusNode = new XmlTreeStructure("status", "DAV:"); statusNode.AddValue("HTTP/1.1 404 Not Found"); responseNode.AddChild(statusNode); } else { var propstatNode = new XmlTreeStructure("propstat", "DAV:"); var propNode = new XmlTreeStructure("prop", "DAV:"); //add the properties to the prop node. foreach (var property in pp.Value) { propNode.AddChild(XmlTreeStructure.Parse(property.Value)); } propstatNode.AddChild(propNode); //adding the status node // TODO: check the status!! statusNode = new XmlTreeStructure("status", "DAV:"); statusNode.AddValue("HTTP/1.1 200 OK"); propstatNode.AddChild(statusNode); responseNode.AddChild(propstatNode); } multistatusNode.AddChild(responseNode); await response.WriteAsync(multistatusNode.ToString()); } }
/// <summary> /// Returns a Response XML element with the name of all properties /// of a collection or resource. /// </summary> /// <param name="url"></param> /// <param name="calendarResourceId"></param> /// <returns></returns> private async Task <XmlTreeStructure> PropNameFillTree(string url, string calendarResourceId = null) { #region Adding the response of the collection or resource. //A "response" structure with all its children is build in this method. var treeChild = new XmlTreeStructure("response", "DAV:"); #region Adding the <D:href>/api/v1/caldav/{userEmail}/calendars/{collectionName}/{calendarResourceId}?</D:href> var href = new XmlTreeStructure("href", "DAV:"); href.AddValue(SystemProperties._baseUrl + url); treeChild.AddChild(href); #endregion #region Adding the propstat //in this section is where the "propstat" structure its build. var propstat = new XmlTreeStructure("propstat", "DAV:"); #region Adding nested status //each "propstat" has a "status" with the message that define it. //"propname" is always "200 OK" because you are only accessing the name of the established properties. var status = new XmlTreeStructure("status", "DAV:"); status.AddValue("HTTP/1.1 200 OK"); propstat.AddChild(status); #endregion #region Adding nested prop var prop = new XmlTreeStructure("prop", "DAV:"); List <XmlTreeStructure> properties; //Depending if the target is a collection or a resource this section //will find the object in the database and get from there all names of properties. if (calendarResourceId == null) { //var collection = _collectionRepository.Get(url).Result; properties = (await _collectionRepository.GetAllPropname(url)).Select(p => new XmlTreeStructure(p.Key, p.Value)) .ToList(); //properties = collection.GetAllPropertyNames(); } else { properties = (await _resourceRespository.GetAllPropname(url)).Select(p => new XmlTreeStructure(p.Key, p.Value)) .ToList(); } //Here i add all properties to the prop. foreach (var property in properties) { prop.AddChild(property); } propstat.AddChild(prop); #endregion treeChild.AddChild(propstat); #endregion return(treeChild); #endregion }
public void UnitTest1() { var xmlStr = @"<?xml version=""1.0"" encoding=""utf-8"" ?> <C:calendar-query xmlns:D=""DAV:"" xmlns:C=""urn:ietf:params:xml:ns:caldav""> <D:prop> <D:getetag/> <C:calendar-data> <C:comp name=""VCALENDAR""> <C:prop name=""VERSION""/> <C:comp name=""VEVENT""> <C:prop name=""SUMMARY""/> <C:prop name=""UID""/> <C:prop name=""DTSTART""/> <C:prop name=""DTEND""/> <C:prop name=""DURATION""/> <C:prop name=""RRULE""/> <C:prop name=""RDATE""/> <C:prop name=""EXRULE""/> <C:prop name=""EXDATE""/> <C:prop name=""RECURRENCE-ID""/> </C:comp> <C:comp name=""VTIMEZONE""/> </C:comp> </C:calendar-data> </D:prop> <C:filter> <C:comp-filter name=""VCALENDAR""> <C:comp-filter name=""VEVENT""> <C:time-range start=""20060104T000000Z"" end=""20060105T000000Z""/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>"; var calStr = @"BEGIN:VCALENDAR VERSION:2.0 BEGIN:VTIMEZONE LAST-MODIFIED:20040110T032845Z TZID:US/Eastern BEGIN:DAYLIGHT DTSTART:20000404T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 TZNAME:EDT TZOFFSETFROM:-0500 TZOFFSETTO:-0400 END:DAYLIGHT BEGIN:STANDARD DTSTART:20001026T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZNAME:EST TZOFFSETFROM:-0400 TZOFFSETTO:-0500 END:STANDARD END:VTIMEZONE BEGIN:VEVENT DTSTART;TZID=US/Eastern:20060102T120000 DURATION:PT1H RRULE:FREQ=DAILY;COUNT=5 SUMMARY:Event #2 UID:[email protected] END:VEVENT BEGIN:VEVENT DTSTART;TZID=US/Eastern:20060104T140000 DURATION:PT1H RECURRENCE-ID;TZID=US/Eastern:20060104T120000 SUMMARY:Event #2 bis UID:[email protected] END:VEVENT BEGIN:VEVENT DTSTART;TZID=US/Eastern:20060106T140000 DURATION:PT1H RECURRENCE-ID;TZID=US/Eastern:20060106T120000 SUMMARY:Event #2 bis bis UID:[email protected] END:VEVENT END:VCALENDAR"; var calendar = new VCalendar(calStr); var xmlTree = XmlTreeStructure.Parse(xmlStr); var result = calendar.FilterResource(xmlTree); Assert.True(result); }
/// <summary> /// Returns a Response XML tree for a prop request with all the property names /// and property values specified in the request. /// </summary> /// <param name="url"></param> /// <param name="calendarResourceId">Name of the resource</param> /// <param name="propertiesNameNamespace">List of requested properties (key=name; value=namespace)</param> /// <param name="principal"></param> /// <returns></returns> private async Task <XmlTreeStructure> PropFillTree(string url, string calendarResourceId, List <KeyValuePair <string, string> > propertiesNameNamespace, Principal principal) { //a "response xml element is added for each collection or resource" #region Adding the response of the collection or resource. var treeChild = new XmlTreeStructure("response", "DAV:"); #region Adding the <D:href>/api/v1/caldav/{userEmail}/calendars/{collectionName}/{calendarResourceId}?</D:href> //an href with the corresponding url is added to the response var href = new XmlTreeStructure("href", "DAV:"); href.AddValue(SystemProperties._baseUrl + url); treeChild.AddChild(href); #endregion #region Adding the propstats #region Selecting properties CalendarCollection collection; CalendarResource resource; var propertiesCol = new List <XmlTreeStructure>(); var propertiesOk = new List <XmlTreeStructure>(); var propertiesWrong = new List <XmlTreeStructure>(); var errorStack = new Stack <string>(); //the current-user-privilege-set is generated per request //it needs the DAV:acl property and the principalID Property aclProperty = null; //It take the list of requested properties and tries to get the corresponding property from db. //The methods are called for a resource or a collection accordingly its circumstances. //The properties are stored inside the propertiesCol. Where if the value is null it means that the collection could not be //retrieve. if (calendarResourceId == null) { collection = _collectionRepository.Get(url); if (propertiesNameNamespace != null) { foreach (var addProperty in propertiesNameNamespace) { //gets the property from database var property = await _collectionRepository.GetProperty(url, addProperty); //Builds the xmlTreeExtructure checking that if the value is null thats because //the property was not found. IXMLTreeStructure prop; if (property != null) { prop = property.Value == null ? new XmlTreeStructure(property.Name, property.Namespace) { Value = "" } } : XmlTreeStructure.Parse(property.Value); else { prop = new XmlTreeStructure(addProperty.Key, addProperty.Value); } propertiesCol.Add((XmlTreeStructure)prop); } //take the acl property aclProperty = collection.Properties.FirstOrDefault(x => x.Name == "acl"); } } else { resource = _resourceRespository.Get(url); if (propertiesNameNamespace != null) { foreach (var addProperty in propertiesNameNamespace) { //gets the property from database var property = await _resourceRespository.GetProperty(url, addProperty); //Builds the xmlTreeExtructure checking that if the value is null thats because //the property was not found. IXMLTreeStructure prop; if (property != null) { prop = property.Value == null ? new XmlTreeStructure(property.Name, property.Namespace) { Value = "" } } : XmlTreeStructure.Parse(property.Value); else { prop = new XmlTreeStructure(addProperty.Key, addProperty.Value); } propertiesCol.Add((XmlTreeStructure)prop); } //take the acl property aclProperty = resource.Properties.FirstOrDefault(x => x.Name == "acl"); } } //add the additional properties that are generated per request if (propertiesNameNamespace != null) { foreach (var pair in propertiesNameNamespace) { switch (pair.Key) { case "current-user-privilege-set": propertiesCol.RemoveAll(x => x.NodeName == pair.Key); propertiesCol.Add(principal.GetCurrentUserPermissions(aclProperty)); break; } } } //Here, properties are divided between recovered and error recovering foreach (var propTree in propertiesCol) { if (propTree.Value != null) { propertiesOk.Add(propTree); } else { propertiesWrong.Add(propTree); } } #endregion //For each returned status a "propstat" is created, containing a "prop" with all properties that belong to that current status. // And a "status" containing the message of the corresponding status. //Right Now there are only two "propstat" taking place OK and Wrong an therefore only two "status" //200 OK and 400 Not Found. //More should be added when ACL is working entairly. //TODO: Add the status forbidden for authentication permissions problems. #region Adding nested propOK var propstatOk = new XmlTreeStructure("propstat", "DAV:"); var propOk = new XmlTreeStructure("prop", "DAV:"); //Here i add all properties to the prop. foreach (var property in propertiesOk) { propOk.AddChild(property); } propstatOk.AddChild(propOk); //This when i group the OK properties #region Adding nested status OK var statusOk = new XmlTreeStructure("status", "DAV:"); statusOk.AddValue("HTTP/1.1 200 OK"); propstatOk.AddChild(statusOk); #endregion #endregion //Here the same is made. The Wrong properties are grouped. #region Adding nested propWrong var propstatWrong = new XmlTreeStructure("propstat", "DAV:"); var propWrong = new XmlTreeStructure("prop", "DAV:"); //Here i add all properties to the prop. foreach (var property in propertiesWrong) { propWrong.AddChild(property); } propstatWrong.AddChild(propWrong); #region Adding nested status Not Found var statusWrong = new XmlTreeStructure("status", "DAV:"); statusWrong.AddValue("HTTP/1.1 400 Not Found"); propstatWrong.AddChild(statusWrong); #endregion #region Adding responseDescription when wrong var responseDescrpWrong = new XmlTreeStructure("responsedescription", "DAV:"); responseDescrpWrong.AddValue("The properties doesn't exist"); propstatWrong.AddChild(responseDescrpWrong); #endregion #endregion //If anyone of the property groups is empty it is not included in the response. if (propertiesOk.Count > 0) { treeChild.AddChild(propstatOk); } if (propertiesWrong.Count > 0) { treeChild.AddChild(propstatWrong); } #endregion return(treeChild); #endregion }