1 /*
  2  * Copyright ©2012 SARA bv, The Netherlands
  3  *
  4  * This file is part of js-webdav-client.
  5  *
  6  * js-webdav-client is free software: you can redistribute it and/or modify
  7  * it under the terms of the GNU Lesser General Public License as published
  8  * by the Free Software Foundation, either version 3 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * js-webdav-client is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public License
 17  * along with js-webdav-client.  If not, see <http://www.gnu.org/licenses/>.
 18  */
 19 "use strict";
 20 
 21 // If nl.sara.webdav.Response is already defined, we have a namespace clash!
 22 if (nl.sara.webdav.Response !== undefined) {
 23   throw new nl.sara.webdav.Exception('Namespace nl.sara.webdav.Response already taken, could not load JavaScript library for WebDAV connectivity.', nl.sara.webdav.Exception.NAMESPACE_TAKEN);
 24 }
 25 
 26 /**
 27  * @class a WebDAV response
 28  *
 29  * @param  {Node}  [xmlNode]  Optional; the xmlNode describing the response object (should be compliant with RFC 4918)
 30  * @property  {String}  href                 The path of the resource
 31  * @property  {String}  status               The (HTTP) status code
 32  * @property  {String}  error                The error text
 33  * @property  {String}  responsedescription  The response description
 34  * @property  {String}  location             In case of a 3XX response, the value that would normally be in the 'Location' header
 35  */
 36 nl.sara.webdav.Response = function(xmlNode) {
 37   // First define private attributes
 38   Object.defineProperty(this, '_namespaces', {
 39     'value': {},
 40     'enumerable': false,
 41     'configurable': false,
 42     'writable': true
 43   });
 44   // Second define public attributes
 45   Object.defineProperty(this, 'href', {
 46     'value': null,
 47     'enumerable': true,
 48     'configurable': false,
 49     'writable': true
 50   });
 51   Object.defineProperty(this, 'status', {
 52     'value': null,
 53     'enumerable': true,
 54     'configurable': false,
 55     'writable': true
 56   });
 57   Object.defineProperty(this, 'error', {
 58     'value': null,
 59     'enumerable': true,
 60     'configurable': false,
 61     'writable': true
 62   });
 63   Object.defineProperty(this, 'responsedescription', {
 64     'value': null,
 65     'enumerable': true,
 66     'configurable': false,
 67     'writable': true
 68   });
 69   Object.defineProperty(this, 'location', {
 70     'value': null,
 71     'enumerable': true,
 72     'configurable': false,
 73     'writable': true
 74   });
 75 
 76   // Constructor logic
 77   if (typeof xmlNode !== 'undefined') {
 78     if ((xmlNode.namespaceURI !== 'DAV:') || (nl.sara.webdav.Ie.getLocalName(xmlNode) !== 'response')) {
 79       throw new nl.sara.webdav.Exception('Node is not of type DAV:response', nl.sara.webdav.Exception.WRONG_XML);
 80     }
 81     var data = xmlNode.childNodes;
 82     for (var i = 0; i < data.length; i++) {
 83       var child = data.item(i);
 84       if ((child.namespaceURI === null) || (child.namespaceURI !== 'DAV:')) { // Skip if not from the right namespace
 85         continue;
 86       }
 87       switch (nl.sara.webdav.Ie.getLocalName(child)) {
 88         case 'href':
 89         case 'status':
 90         case 'error':
 91         case 'responsedescription':
 92           // always CDATA, so just take the text
 93           this[nl.sara.webdav.Ie.getLocalName(child)] = child.childNodes.item(0).nodeValue;
 94           break;
 95         case 'location':
 96           this[nl.sara.webdav.Ie.getLocalName(child)] = child.childNodes.item(0).childNodes.item(0).nodeValue;
 97           break;
 98         case 'propstat': // propstat node should be parsed further
 99           var propstatChilds = child.childNodes;
100           // First find status, error, responsedescription and props (as Node objects, not yet as Property objects)
101           var status = null;
102           var errors = [];
103           var responsedescription = null;
104           var props = [];
105           for (var j = 0; j < propstatChilds.length; j++) { // Parse the child nodes of the propstat element
106             var propstatChild = propstatChilds.item(j);
107             if ((propstatChild.nodeType !== 1) || (propstatChild.namespaceURI !== 'DAV:')) {
108               continue;
109             }
110             switch (nl.sara.webdav.Ie.getLocalName(propstatChild)) {
111               case 'prop':
112                 for (var k = 0; k < propstatChild.childNodes.length; k++) {
113                   props.push(propstatChild.childNodes.item(k));
114                 }
115                 break;
116               case 'error':
117                 for (k = 0; k < propstatChild.childNodes.length; k++) {
118                   errors.push(propstatChild.childNodes.item(k));
119                 }
120                 break;
121                 break;
122               case 'status': // always CDATA, so just take the text
123                 status = propstatChild.childNodes.item(0).nodeValue;
124                 status = parseInt(status.substr(status.indexOf(' ') + 1, 3));
125                 break;
126               case 'responsedescription': // always CDATA, so just take the text
127                 responsedescription = propstatChild.childNodes.item(0).nodeValue;
128               break;
129             }
130           }
131 
132           // Then create and add a new property for each element found in DAV:prop
133           for (j = 0; j < props.length; j++) {
134             if (props[j].nodeType === 1) {
135               var property = new nl.sara.webdav.Property(props[j], status, responsedescription, errors);
136               this.addProperty(property);
137             }
138           }
139         break;
140       }
141     }
142   }
143 };
144 
145 //########################## DEFINE PUBLIC METHODS #############################
146 /**
147  * Adds a WebDAV property
148  *
149  * @param    {nl.sara.webdav.Property}  property  The property
150  * @returns  {nl.sara.webdav.Response}            The response itself for chaining methods
151  */
152 nl.sara.webdav.Response.prototype.addProperty = function(property) {
153   if (!nl.sara.webdav.Ie.isIE && !(property instanceof nl.sara.webdav.Property)) {
154     throw new nl.sara.webdav.Exception('Response property should be instance of Property', nl.sara.webdav.Exception.WRONG_TYPE);
155   }
156   var namespace = property.namespace;
157   if (typeof namespace !== 'string') {
158     namespace = '';
159   }
160   if (this._namespaces[namespace] === undefined) {
161     this._namespaces[namespace] = {};
162   }
163 
164   this._namespaces[namespace][property.tagname] = property;
165   return this;
166 };
167 
168 /**
169  * Gets a WebDAV property
170  *
171  * @param    {String}                   namespace  The namespace of the WebDAV property
172  * @param    {String}                   prop       The WebDAV property to get
173  * @returns  {nl.sara.webdav.Property}             The value of the WebDAV property or undefined if the WebDAV property doesn't exist
174  */
175 nl.sara.webdav.Response.prototype.getProperty = function(namespace, prop) {
176   if ((this._namespaces[namespace] === undefined) || (this._namespaces[namespace][prop] === undefined)) {
177     return undefined;
178   }
179   return this._namespaces[namespace][prop];
180 };
181 
182 /**
183  * Gets the namespace names
184  *
185  * @returns  {String[]}  The names of the different namespaces
186  */
187 nl.sara.webdav.Response.prototype.getNamespaceNames = function() {
188   return Object.keys(this._namespaces);
189 };
190 
191 /**
192  * Gets the property names of a namespace
193  *
194  * @param    {String}    namespace  The namespace of the WebDAV property
195  * @returns  {String[]}             The names of the different properties of a namespace
196  */
197 nl.sara.webdav.Response.prototype.getPropertyNames = function(namespace) {
198   if (this._namespaces[namespace] === undefined) {
199     return new Array();
200   }
201   return Object.keys(this._namespaces[namespace]);
202 };
203 
204 // End of library
205