1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3 *
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 *
8 * OpenOffice.org - a multi-platform office productivity suite
9 *
10 * This file is part of OpenOffice.org.
11 *
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
15 *
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
21 *
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
26 *
27 ************************************************************************/
28
29
30 /**************************************************************************
31 TODO
32 **************************************************************************
33
34 *************************************************************************/
35 #include <memory>
36 #include <com/sun/star/util/DateTime.hpp>
37 #include "NeonUri.hxx"
38 #include "DAVResource.hxx"
39 #include "DAVProperties.hxx"
40 #include "DateTimeHelper.hxx"
41 #include "webdavprovider.hxx"
42 #include "ContentProperties.hxx"
43
44 using namespace com::sun::star;
45 using namespace webdav_ucp;
46
47 /*
48 =============================================================================
49
50 Property Mapping
51
52 =============================================================================
53 HTTP (entity header) WebDAV (property) UCB (property)
54 =============================================================================
55
56 Allow
57 Content-Encoding
58 Content-Language getcontentlanguage
59 Content-Length getcontentlength Size
60 Content-Location
61 Content-MD5
62 Content-Range
63 Content-Type getcontenttype MediaType
64 Expires
65 Last-Modified getlastmodified DateModified
66 creationdate DateCreated
67 resourcetype IsFolder,IsDocument,ContentType
68 displayname
69 ETag (actually getetag
70 a response header )
71 lockdiscovery
72 supportedlock
73 source
74 Title (always taken from URI)
75
76 =============================================================================
77
78 Important: HTTP headers will not be mapped to DAV properties; only to UCB
79 properties. (Content-Length,Content-Type,Last-Modified)
80 */
81
82
83 // ContentProperties Implementation.
84
85
86 // static member!
87 uno::Any ContentProperties::m_aEmptyAny;
88
ContentProperties(const DAVResource & rResource)89 ContentProperties::ContentProperties( const DAVResource& rResource )
90 : m_xProps( new PropertyValueMap ),
91 m_bTrailingSlash( false )
92 {
93 assert( !rResource.uri.isEmpty() && "ContentProperties ctor - Empty resource URI!" );
94
95 // Title
96 try
97 {
98 NeonUri aURI( rResource.uri );
99 m_aEscapedTitle = aURI.GetPathBaseName();
100
101 (*m_xProps)[ OUString("Title") ]
102 = PropertyValue(
103 uno::makeAny( aURI.GetPathBaseNameUnescaped() ), true );
104 }
105 catch ( DAVException const & )
106 {
107 (*m_xProps)[ OUString("Title") ]
108 = PropertyValue(
109 uno::makeAny(
110 OUString(
111 "*** unknown ***" ) ),
112 true );
113 }
114
115 for ( const auto& rProp : rResource.properties )
116 {
117 addProperty( rProp );
118 }
119
120 if ( rResource.uri.endsWith("/") )
121 m_bTrailingSlash = true;
122 }
123
124
ContentProperties(const OUString & rTitle,bool bFolder)125 ContentProperties::ContentProperties(
126 const OUString & rTitle, bool bFolder )
127 : m_xProps( new PropertyValueMap ),
128 m_bTrailingSlash( false )
129 {
130 (*m_xProps)[ OUString("Title") ]
131 = PropertyValue( uno::makeAny( rTitle ), true );
132 (*m_xProps)[ OUString("IsFolder") ]
133 = PropertyValue( uno::makeAny( bFolder ), true );
134 (*m_xProps)[ OUString("IsDocument") ]
135 = PropertyValue( uno::makeAny( !bFolder ), true );
136 }
137
138
ContentProperties(const OUString & rTitle)139 ContentProperties::ContentProperties( const OUString & rTitle )
140 : m_xProps( new PropertyValueMap ),
141 m_bTrailingSlash( false )
142 {
143 (*m_xProps)[ OUString("Title") ]
144 = PropertyValue( uno::makeAny( rTitle ), true );
145 }
146
147
ContentProperties()148 ContentProperties::ContentProperties()
149 : m_xProps( new PropertyValueMap ),
150 m_bTrailingSlash( false )
151 {
152 }
153
ContentProperties(const ContentProperties & rOther)154 ContentProperties::ContentProperties(const ContentProperties& rOther)
155 : m_aEscapedTitle(rOther.m_aEscapedTitle)
156 , m_xProps(rOther.m_xProps ? new PropertyValueMap(*rOther.m_xProps) : new PropertyValueMap)
157 , m_bTrailingSlash(rOther.m_bTrailingSlash)
158 {
159 }
160
161
contains(const OUString & rName) const162 bool ContentProperties::contains( const OUString & rName ) const
163 {
164 return get( rName ) != nullptr;
165 }
166
167
getValue(const OUString & rName) const168 const uno::Any & ContentProperties::getValue(
169 const OUString & rName ) const
170 {
171 const PropertyValue * pProp = get( rName );
172 if ( pProp )
173 return pProp->value();
174 else
175 return m_aEmptyAny;
176 }
177
178
get(const OUString & rName) const179 const PropertyValue * ContentProperties::get(
180 const OUString & rName ) const
181 {
182 PropertyValueMap::const_iterator it = m_xProps->find( rName );
183 const PropertyValueMap::const_iterator end = m_xProps->end();
184
185 if ( it == end )
186 {
187 it = std::find_if(m_xProps->cbegin(), end,
188 [&rName](const PropertyValueMap::value_type& rEntry) {
189 return rEntry.first.equalsIgnoreAsciiCase( rName );
190 });
191 if ( it != end )
192 return &(*it).second;
193
194 return nullptr;
195 }
196 else
197 return &(*it).second;
198 }
199
200
201 // static
UCBNamesToDAVNames(const uno::Sequence<beans::Property> & rProps,std::vector<OUString> & propertyNames)202 void ContentProperties::UCBNamesToDAVNames(
203 const uno::Sequence< beans::Property > & rProps,
204 std::vector< OUString > & propertyNames )
205 {
206
207 // Assemble list of DAV properties to obtain from server.
208 // Append DAV properties needed to obtain requested UCB props.
209
210
211 // DAV UCB
212 // creationdate <- DateCreated
213 // getlastmodified <- DateModified
214 // getcontenttype <- MediaType
215 // getcontentlength <- Size
216 // resourcetype <- IsFolder, IsDocument, ContentType
217 // (taken from URI) <- Title
218
219 bool bCreationDate = false;
220 bool bLastModified = false;
221 bool bContentType = false;
222 bool bContentLength = false;
223 bool bResourceType = false;
224
225 for ( const beans::Property & rProp : rProps )
226 {
227 if ( rProp.Name == "Title" )
228 {
229 // Title is always obtained from resource's URI.
230 continue;
231 }
232 else if ( rProp.Name == "DateCreated" || rProp.Name == DAVProperties::CREATIONDATE )
233 {
234 if ( !bCreationDate )
235 {
236 propertyNames.push_back( DAVProperties::CREATIONDATE );
237 bCreationDate = true;
238 }
239 }
240 else if ( rProp.Name == "DateModified" || rProp.Name == DAVProperties::GETLASTMODIFIED )
241 {
242 if ( !bLastModified )
243 {
244 propertyNames.push_back( DAVProperties::GETLASTMODIFIED );
245 bLastModified = true;
246 }
247 }
248 else if ( rProp.Name == "MediaType" || rProp.Name == DAVProperties::GETCONTENTTYPE )
249 {
250 if ( !bContentType )
251 {
252 propertyNames.push_back( DAVProperties::GETCONTENTTYPE );
253 bContentType = true;
254 }
255 }
256 else if ( rProp.Name == "Size" || rProp.Name == DAVProperties::GETCONTENTLENGTH )
257 {
258 if ( !bContentLength )
259 {
260 propertyNames.push_back( DAVProperties::GETCONTENTLENGTH );
261 bContentLength = true;
262 }
263 }
264 else if ( rProp.Name == "ContentType" || rProp.Name == "IsDocument" || rProp.Name == "IsFolder" || rProp.Name == DAVProperties::RESOURCETYPE )
265 {
266 if ( !bResourceType )
267 {
268 propertyNames.push_back( DAVProperties::RESOURCETYPE );
269 bResourceType = true;
270 }
271 }
272 else
273 {
274 propertyNames.push_back( rProp.Name );
275 }
276 }
277 }
278
279
280 // static
UCBNamesToHTTPNames(const uno::Sequence<beans::Property> & rProps,std::vector<OUString> & propertyNames)281 void ContentProperties::UCBNamesToHTTPNames(
282 const uno::Sequence< beans::Property > & rProps,
283 std::vector< OUString > & propertyNames )
284 {
285
286 // Assemble list of HTTP header names to obtain from server.
287 // Append HTTP headers needed to obtain requested UCB props.
288
289
290 // HTTP UCB
291 // Last-Modified <- DateModified
292 // Content-Type <- MediaType
293 // Content-Length <- Size
294
295 for ( const beans::Property & rProp : rProps )
296 {
297 if ( rProp.Name == "DateModified" )
298 {
299 propertyNames.emplace_back("Last-Modified" );
300 }
301 else if ( rProp.Name == "MediaType" )
302 {
303 propertyNames.emplace_back("Content-Type" );
304 }
305 else if ( rProp.Name == "Size" )
306 {
307 propertyNames.emplace_back("Content-Length" );
308 }
309 else
310 {
311 propertyNames.push_back( rProp.Name );
312 }
313 }
314 }
315
316
containsAllNames(const uno::Sequence<beans::Property> & rProps,std::vector<OUString> & rNamesNotContained) const317 bool ContentProperties::containsAllNames(
318 const uno::Sequence< beans::Property >& rProps,
319 std::vector< OUString > & rNamesNotContained ) const
320 {
321 rNamesNotContained.clear();
322
323 for ( const auto& rProp : rProps )
324 {
325 const OUString & rName = rProp.Name;
326 if ( !contains( rName ) )
327 {
328 // Not found.
329 rNamesNotContained.push_back( rName );
330 }
331 }
332
333 return rNamesNotContained.empty();
334 }
335
336
addProperties(const std::vector<OUString> & rProps,const ContentProperties & rContentProps)337 void ContentProperties::addProperties(
338 const std::vector< OUString > & rProps,
339 const ContentProperties & rContentProps )
340 {
341 for ( const OUString & rName : rProps )
342 {
343 if ( !contains( rName ) ) // ignore duplicates
344 {
345 const PropertyValue * pProp = rContentProps.get( rName );
346 if ( pProp )
347 {
348 // Add it.
349 addProperty( rName, pProp->value(), pProp->isCaseSensitive() );
350 }
351 else
352 {
353 addProperty( rName, uno::Any(), false );
354 }
355 }
356 }
357 }
358
359
addProperty(const DAVPropertyValue & rProp)360 void ContentProperties::addProperty( const DAVPropertyValue & rProp )
361 {
362 addProperty( rProp.Name, rProp.Value, rProp.IsCaseSensitive );
363 }
364
365
addProperty(const OUString & rName,const css::uno::Any & rValue,bool bIsCaseSensitive)366 void ContentProperties::addProperty( const OUString & rName,
367 const css::uno::Any & rValue,
368 bool bIsCaseSensitive )
369 {
370 if ( rName == DAVProperties::CREATIONDATE )
371 {
372 // Map DAV:creationdate to UCP:DateCreated
373 OUString aValue;
374 rValue >>= aValue;
375 util::DateTime aDate;
376 DateTimeHelper::convert( aValue, aDate );
377
378 (*m_xProps)[ OUString("DateCreated") ]
379 = PropertyValue( uno::makeAny( aDate ), true );
380 }
381 // else if ( rName.equals( DAVProperties::DISPLAYNAME ) )
382 // {
383 // }
384 // else if ( rName.equals( DAVProperties::GETCONTENTLANGUAGE ) )
385 // {
386 // }
387 else if ( rName == DAVProperties::GETCONTENTLENGTH )
388 {
389 // Map DAV:getcontentlength to UCP:Size
390 OUString aValue;
391 rValue >>= aValue;
392
393 (*m_xProps)[ OUString("Size") ]
394 = PropertyValue( uno::makeAny( aValue.toInt64() ), true );
395 }
396 else if ( rName.equalsIgnoreAsciiCase( "Content-Length" ) )
397 {
398 // Do NOT map Content-length entity header to DAV:getcontentlength!
399 // Only DAV resources have this property.
400
401 // Map Content-Length entity header to UCP:Size
402 OUString aValue;
403 rValue >>= aValue;
404
405 (*m_xProps)[ OUString("Size") ]
406 = PropertyValue( uno::makeAny( aValue.toInt64() ), true );
407 }
408 else if ( rName == DAVProperties::GETCONTENTTYPE )
409 {
410 // Map DAV:getcontenttype to UCP:MediaType (1:1)
411 (*m_xProps)[ OUString("MediaType") ]
412 = PropertyValue( rValue, true );
413 }
414 else if ( rName.equalsIgnoreAsciiCase( "Content-Type" ) )
415 {
416 // Do NOT map Content-Type entity header to DAV:getcontenttype!
417 // Only DAV resources have this property.
418
419 // Map DAV:getcontenttype to UCP:MediaType (1:1)
420 (*m_xProps)[ OUString("MediaType") ]
421 = PropertyValue( rValue, true );
422 }
423 // else if ( rName.equals( DAVProperties::GETETAG ) )
424 // {
425 // }
426 else if ( rName == DAVProperties::GETLASTMODIFIED )
427 {
428 // Map the DAV:getlastmodified entity header to UCP:DateModified
429 OUString aValue;
430 rValue >>= aValue;
431 util::DateTime aDate;
432 DateTimeHelper::convert( aValue, aDate );
433
434 (*m_xProps)[ OUString("DateModified") ]
435 = PropertyValue( uno::makeAny( aDate ), true );
436 }
437 else if ( rName.equalsIgnoreAsciiCase( "Last-Modified" ) )
438 {
439 // Do not map Last-Modified entity header to DAV:getlastmodified!
440 // Only DAV resources have this property.
441
442 // Map the Last-Modified entity header to UCP:DateModified
443 OUString aValue;
444 rValue >>= aValue;
445 util::DateTime aDate;
446 DateTimeHelper::convert( aValue, aDate );
447
448 (*m_xProps)[ OUString("DateModified") ]
449 = PropertyValue( uno::makeAny( aDate ), true );
450 }
451 // else if ( rName.equals( DAVProperties::LOCKDISCOVERY ) )
452 // {
453 // }
454 else if ( rName == DAVProperties::RESOURCETYPE )
455 {
456 OUString aValue;
457 rValue >>= aValue;
458
459 // Map DAV:resourcetype to UCP:IsFolder, UCP:IsDocument, UCP:ContentType
460 bool bFolder = aValue.equalsIgnoreAsciiCase( "collection" );
461
462 (*m_xProps)[ OUString("IsFolder") ]
463 = PropertyValue( uno::makeAny( bFolder ), true );
464 (*m_xProps)[ OUString("IsDocument") ]
465 = PropertyValue( uno::makeAny( !bFolder ), true );
466 (*m_xProps)[ OUString("ContentType") ]
467 = PropertyValue( uno::makeAny( bFolder
468 ? OUString( WEBDAV_COLLECTION_TYPE )
469 : OUString( WEBDAV_CONTENT_TYPE ) ), true );
470 }
471 // else if ( rName.equals( DAVProperties::SOURCE ) )
472 // {
473 // }
474 // else if ( rName.equals( DAVProperties::SUPPORTEDLOCK ) )
475 // {
476 // }
477
478 // Save property.
479 (*m_xProps)[ rName ] = PropertyValue( rValue, bIsCaseSensitive );
480 }
481
482
483 // CachableContentProperties Implementation.
484
485
486 namespace
487 {
isCachable(OUString const & rName,bool isCaseSensitive)488 bool isCachable( OUString const & rName,
489 bool isCaseSensitive )
490 {
491 static const OUString aNonCachableProps [] =
492 {
493 DAVProperties::LOCKDISCOVERY,
494
495 DAVProperties::GETETAG,
496 OUString( "ETag" ),
497
498 OUString( "DateModified" ),
499 OUString( "Last-Modified" ),
500 DAVProperties::GETLASTMODIFIED,
501
502 OUString( "Size" ),
503 OUString( "Content-Length" ),
504 DAVProperties::GETCONTENTLENGTH,
505
506 OUString( "Date" )
507 };
508
509 for (const auto & rNonCachableProp : aNonCachableProps)
510 {
511 if ( isCaseSensitive )
512 {
513 if ( rName == rNonCachableProp )
514 return false;
515 }
516 else
517 if ( rName.equalsIgnoreAsciiCase( rNonCachableProp ) )
518 return false;
519 }
520 return true;
521 }
522
523 } // namespace
524
525
CachableContentProperties(const ContentProperties & rProps)526 CachableContentProperties::CachableContentProperties(
527 const ContentProperties & rProps )
528 {
529 addProperties( rProps );
530 }
531
532
addProperties(const ContentProperties & rProps)533 void CachableContentProperties::addProperties(
534 const ContentProperties & rProps )
535 {
536 const std::unique_ptr< PropertyValueMap > & props = rProps.getProperties();
537
538 for ( const auto& rProp : *props )
539 {
540 if ( isCachable( rProp.first, rProp.second.isCaseSensitive() ) )
541 m_aProps.addProperty( rProp.first,
542 rProp.second.value(),
543 rProp.second.isCaseSensitive() );
544 }
545 }
546
547
addProperties(const std::vector<DAVPropertyValue> & rProps)548 void CachableContentProperties::addProperties(
549 const std::vector< DAVPropertyValue > & rProps )
550 {
551 for ( const auto& rProp : rProps )
552 {
553 if ( isCachable( rProp.Name, rProp.IsCaseSensitive ) )
554 m_aProps.addProperty( rProp );
555 }
556 }
557
558 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
559