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