LCOV - code coverage report
Current view: top level - ucb/source/ucp/webdav-neon - NeonSession.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 3 725 0.4 %
Date: 2014-04-11 Functions: 2 62 3.2 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include <boost/unordered_map.hpp>
      31             : #include <vector>
      32             : #include <string.h>
      33             : #include "osl/diagnose.h"
      34             : #include "osl/time.h"
      35             : #include <rtl/string.h>
      36             : #include <ne_socket.h>
      37             : #include <ne_auth.h>
      38             : #include <ne_redirect.h>
      39             : #include <ne_ssl.h>
      40             : 
      41             : // old neon versions forgot to set this
      42             : extern "C" {
      43             : #include <ne_compress.h>
      44             : }
      45             : 
      46             : #include "libxml/parser.h"
      47             : #include "rtl/ustrbuf.hxx"
      48             : #include "comphelper/processfactory.hxx"
      49             : #include "comphelper/sequence.hxx"
      50             : #include <comphelper/stl_types.hxx>
      51             : #include "ucbhelper/simplecertificatevalidationrequest.hxx"
      52             : 
      53             : #include "DAVAuthListener.hxx"
      54             : #include "NeonTypes.hxx"
      55             : #include "NeonSession.hxx"
      56             : #include "NeonInputStream.hxx"
      57             : #include "NeonPropFindRequest.hxx"
      58             : #include "NeonHeadRequest.hxx"
      59             : #include "NeonUri.hxx"
      60             : #include "LinkSequence.hxx"
      61             : #include "UCBDeadPropertyValue.hxx"
      62             : 
      63             : #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
      64             : #include <com/sun/star/security/XCertificate.hpp>
      65             : #include <com/sun/star/security/CertificateValidity.hpp>
      66             : #include <com/sun/star/security/CertificateContainerStatus.hpp>
      67             : #include <com/sun/star/security/CertificateContainer.hpp>
      68             : #include <com/sun/star/security/XCertificateContainer.hpp>
      69             : #include <com/sun/star/ucb/Lock.hpp>
      70             : #include <com/sun/star/beans/NamedValue.hpp>
      71             : #include <com/sun/star/xml/crypto/SEInitializer.hpp>
      72             : 
      73             : #include <boost/bind.hpp>
      74             : 
      75             : using namespace com::sun::star;
      76             : using namespace webdav_ucp;
      77             : 
      78             : #ifndef EOL
      79             : #    define EOL "\r\n"
      80             : #endif
      81             : 
      82           0 : struct RequestData
      83             : {
      84             :     // POST
      85             :     OUString aContentType;
      86             :     OUString aReferer;
      87             : 
      88           0 :     RequestData() {}
      89           0 :     RequestData( const OUString & rContentType,
      90             :                  const OUString & rReferer )
      91           0 :     : aContentType( rContentType ), aReferer( rReferer ) {}
      92             : };
      93             : 
      94             : struct equalPtr
      95             : {
      96           0 :     bool operator()( const ne_request* p1, const ne_request* p2 ) const
      97             :     {
      98           0 :         return p1 == p2;
      99             :     }
     100             : };
     101             : 
     102             : struct hashPtr
     103             : {
     104           0 :     size_t operator()( const ne_request* p ) const
     105             :     {
     106           0 :         return (size_t)p;
     107             :     }
     108             : };
     109             : 
     110             : typedef boost::unordered_map
     111             : <
     112             :     ne_request*,
     113             :     RequestData,
     114             :     hashPtr,
     115             :     equalPtr
     116             : >
     117             : RequestDataMap;
     118             : 
     119           0 : static sal_uInt16 makeStatusCode( const OUString & rStatusText )
     120             : {
     121             :     // Extract status code from session error string. Unfortunately
     122             :     // neon provides no direct access to the status code...
     123             : 
     124           0 :     if ( rStatusText.getLength() < 3 )
     125             :     {
     126             :         OSL_FAIL(
     127             :             "makeStatusCode - status text string to short!" );
     128           0 :         return 0;
     129             :     }
     130             : 
     131           0 :     sal_Int32 nPos = rStatusText.indexOf( ' ' );
     132           0 :     if ( nPos == -1 )
     133             :     {
     134             :         OSL_FAIL( "makeStatusCode - wrong status text format!" );
     135           0 :         return 0;
     136             :     }
     137             : 
     138           0 :     return sal_uInt16( rStatusText.copy( 0, nPos ).toInt32() );
     139             : }
     140             : 
     141           0 : static bool noKeepAlive( const uno::Sequence< beans::NamedValue >& rFlags )
     142             : {
     143           0 :     if ( !rFlags.hasElements() )
     144           0 :         return false;
     145             : 
     146             :     // find "KeepAlive" property
     147           0 :     const beans::NamedValue* pAry(rFlags.getConstArray());
     148           0 :     const sal_Int32          nLen(rFlags.getLength());
     149             :     const beans::NamedValue* pValue(
     150             :         std::find_if(pAry,pAry+nLen,
     151             :                      boost::bind(comphelper::TNamedValueEqualFunctor(),
     152             :                                  _1,
     153           0 :                                  OUString("KeepAlive"))));
     154           0 :     if ( pValue != pAry+nLen && !pValue->Value.get<sal_Bool>() )
     155           0 :         return true;
     156             : 
     157           0 :     return false;
     158             : }
     159             : 
     160           0 : struct NeonRequestContext
     161             : {
     162             :     uno::Reference< io::XOutputStream >    xOutputStream;
     163             :     rtl::Reference< NeonInputStream >      xInputStream;
     164             :     const std::vector< OUString > * pHeaderNames;
     165             :     DAVResource *                          pResource;
     166             : 
     167           0 :     NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm )
     168             :     : xOutputStream( xOutStrm ), xInputStream( 0 ),
     169           0 :       pHeaderNames( 0 ), pResource( 0 ) {}
     170             : 
     171           0 :     NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm )
     172             :     : xOutputStream( 0 ), xInputStream( xInStrm ),
     173           0 :       pHeaderNames( 0 ), pResource( 0 ) {}
     174             : 
     175           0 :     NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm,
     176             :                         const std::vector< OUString > & inHeaderNames,
     177             :                         DAVResource & ioResource )
     178             :     : xOutputStream( xOutStrm ), xInputStream( 0 ),
     179           0 :       pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
     180             : 
     181           0 :     NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm,
     182             :                         const std::vector< OUString > & inHeaderNames,
     183             :                         DAVResource & ioResource )
     184             :     : xOutputStream( 0 ), xInputStream( xInStrm ),
     185           0 :       pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {}
     186             : };
     187             : 
     188             : // A simple Neon response_block_reader for use with an XInputStream
     189           0 : extern "C" int NeonSession_ResponseBlockReader(void * inUserData,
     190             :                                                const char * inBuf,
     191             :                                                size_t inLen )
     192             : {
     193             :     // neon sometimes calls this function with (inLen == 0)...
     194           0 :     if ( inLen > 0 )
     195             :     {
     196             :         NeonRequestContext * pCtx
     197           0 :             = static_cast< NeonRequestContext * >( inUserData );
     198             : 
     199             :         rtl::Reference< NeonInputStream > xInputStream(
     200           0 :             pCtx->xInputStream );
     201             : 
     202           0 :         if ( xInputStream.is() )
     203           0 :             xInputStream->AddToStream( inBuf, inLen );
     204             :     }
     205           0 :     return 0;
     206             : }
     207             : 
     208             : // A simple Neon response_block_reader for use with an XOutputStream
     209           0 : extern "C" int NeonSession_ResponseBlockWriter( void * inUserData,
     210             :                                                 const char * inBuf,
     211             :                                                 size_t inLen )
     212             : {
     213             :     // neon calls this function with (inLen == 0)...
     214           0 :     if ( inLen > 0 )
     215             :     {
     216             :         NeonRequestContext * pCtx
     217           0 :             = static_cast< NeonRequestContext * >( inUserData );
     218             :         uno::Reference< io::XOutputStream > xOutputStream
     219           0 :             = pCtx->xOutputStream;
     220             : 
     221           0 :         if ( xOutputStream.is() )
     222             :         {
     223           0 :             const uno::Sequence< sal_Int8 > aSeq( (sal_Int8 *)inBuf, inLen );
     224           0 :             xOutputStream->writeBytes( aSeq );
     225           0 :         }
     226             :     }
     227           0 :     return 0;
     228             : }
     229             : 
     230           0 : extern "C" int NeonSession_NeonAuth( void *       inUserData,
     231             : #if defined NE_FEATURE_SSPI && ! defined SYSTEM_NEON
     232             :                                      const char * inAuthProtocol,
     233             : #endif
     234             :                                      const char * inRealm,
     235             :                                      int          attempt,
     236             :                                      char *       inoutUserName,
     237             :                                      char *       inoutPassWord )
     238             : {
     239             : /* The callback used to request the username and password in the given
     240             :  * realm. The username and password must be copied into the buffers
     241             :  * which are both of size NE_ABUFSIZ.  The 'attempt' parameter is zero
     242             :  * on the first call to the callback, and increases by one each time
     243             :  * an attempt to authenticate fails.
     244             :  *
     245             :  * The callback must return zero to indicate that authentication
     246             :  * should be attempted with the username/password, or non-zero to
     247             :  * cancel the request. (if non-zero, username and password are
     248             :  * ignored.)  */
     249             : 
     250           0 :     NeonSession * theSession = static_cast< NeonSession * >( inUserData );
     251             :     DAVAuthListener * pListener
     252           0 :         = theSession->getRequestEnvironment().m_xAuthListener.get();
     253           0 :     if ( !pListener )
     254             :     {
     255             :         // abort
     256           0 :         return -1;
     257             :     }
     258           0 :     OUString theUserName;
     259           0 :     OUString thePassWord;
     260             : 
     261           0 :     if ( attempt == 0 )
     262             :     {
     263             :         // neon does not handle username supplied with request URI (for
     264             :         // instance when doing FTP over proxy - last checked: 0.23.5 )
     265             : 
     266             :         try
     267             :         {
     268           0 :             NeonUri uri( theSession->getRequestEnvironment().m_aRequestURI );
     269           0 :             OUString aUserInfo( uri.GetUserInfo() );
     270           0 :             if ( !aUserInfo.isEmpty() )
     271             :             {
     272           0 :                 sal_Int32 nPos = aUserInfo.indexOf( '@' );
     273           0 :                 if ( nPos == -1 )
     274             :                 {
     275           0 :                     theUserName = aUserInfo;
     276             :                 }
     277             :                 else
     278             :                 {
     279           0 :                     theUserName = aUserInfo.copy( 0, nPos );
     280           0 :                     thePassWord = aUserInfo.copy( nPos + 1 );
     281             :                 }
     282           0 :             }
     283             :         }
     284           0 :         catch ( DAVException const & )
     285             :         {
     286             :             // abort
     287           0 :             return -1;
     288             :         }
     289             :     }
     290             :     else
     291             :     {
     292             :         // username buffer is prefilled with user name from last attempt.
     293           0 :         theUserName = OUString::createFromAscii( inoutUserName );
     294             :         // @@@ Neon does not initialize password buffer (last checked: 0.22.0).
     295             :         //thePassWord = OUString::createFromAscii( inoutPassWord );
     296             :     }
     297             : 
     298           0 :     bool bCanUseSystemCreds = false;
     299             : 
     300             : #if defined NE_FEATURE_SSPI && ! defined SYSTEM_NEON
     301             :     bCanUseSystemCreds
     302             :         = (attempt == 0) && // avoid endless loops
     303             :           ne_has_support( NE_FEATURE_SSPI ) && // Windows-only feature.
     304             :           ( ( ne_strcasecmp( inAuthProtocol, "NTLM" ) == 0 ) ||
     305             :             ( ne_strcasecmp( inAuthProtocol, "Negotiate" ) == 0 ) );
     306             : #endif
     307             : 
     308             :     int theRetVal = pListener->authenticate(
     309             :                             OUString::createFromAscii( inRealm ),
     310           0 :                             theSession->getHostName(),
     311             :                             theUserName,
     312             :                             thePassWord,
     313           0 :                             bCanUseSystemCreds);
     314             : 
     315             :     OString aUser(
     316           0 :         OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) );
     317           0 :     if ( aUser.getLength() > ( NE_ABUFSIZ - 1 ) )
     318             :     {
     319             :         OSL_FAIL(
     320             :             "NeonSession_NeonAuth - username to long!" );
     321           0 :         return -1;
     322             :     }
     323             : 
     324             :     OString aPass(
     325           0 :         OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) );
     326           0 :     if ( aPass.getLength() > ( NE_ABUFSIZ - 1 ) )
     327             :     {
     328             :         OSL_FAIL(
     329             :             "NeonSession_NeonAuth - password to long!" );
     330           0 :         return -1;
     331             :     }
     332             : 
     333             :     strcpy( inoutUserName, // #100211# - checked
     334           0 :             OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ).getStr() );
     335             : 
     336             :     strcpy( inoutPassWord, // #100211# - checked
     337           0 :             OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ).getStr() );
     338             : 
     339           0 :     return theRetVal;
     340             : }
     341             : 
     342             : namespace {
     343           0 :     OUString GetHostnamePart( const OUString& _rRawString )
     344             :     {
     345           0 :         OUString sPart;
     346           0 :         OUString sPartId("CN=");
     347           0 :         sal_Int32 nContStart = _rRawString.indexOf( sPartId );
     348           0 :         if ( nContStart != -1 )
     349             :         {
     350           0 :             nContStart += sPartId.getLength();
     351           0 :             sal_Int32 nContEnd = _rRawString.indexOf( ',', nContStart );
     352           0 :             sPart = _rRawString.copy( nContStart, nContEnd - nContStart );
     353             :         }
     354           0 :         return sPart;
     355             :     }
     356             : } // namespace
     357             : 
     358           0 : extern "C" int NeonSession_CertificationNotify( void *userdata,
     359             :                                                 int failures,
     360             :                                                 const ne_ssl_certificate *cert )
     361             : {
     362             :     OSL_ASSERT( cert );
     363             : 
     364           0 :     NeonSession * pSession = static_cast< NeonSession * >( userdata );
     365           0 :     uno::Reference< security::XCertificateContainer > xCertificateContainer;
     366             :     try
     367             :     {
     368           0 :         xCertificateContainer = security::CertificateContainer::create( pSession->getComponentContext() );
     369             :     }
     370           0 :     catch ( uno::Exception const & )
     371             :     {
     372             :     }
     373             : 
     374           0 :     if ( !xCertificateContainer.is() )
     375           0 :         return 1;
     376             : 
     377           0 :     failures = 0;
     378             : 
     379           0 :     char * dn = ne_ssl_readable_dname( ne_ssl_cert_subject( cert ) );
     380           0 :     OUString cert_subject( dn, strlen( dn ), RTL_TEXTENCODING_UTF8, 0 );
     381             : 
     382           0 :     ne_free( dn );
     383             : 
     384             :     security::CertificateContainerStatus certificateContainer(
     385           0 :         xCertificateContainer->hasCertificate(
     386           0 :             pSession->getHostName(), cert_subject ) );
     387             : 
     388           0 :     if ( certificateContainer != security::CertificateContainerStatus_NOCERT )
     389             :         return
     390             :             certificateContainer == security::CertificateContainerStatus_TRUSTED
     391             :             ? 0
     392           0 :             : 1;
     393             : 
     394           0 :     uno::Reference< xml::crypto::XSEInitializer > xSEInitializer;
     395             :     try
     396             :     {
     397           0 :         xSEInitializer = xml::crypto::SEInitializer::create( pSession->getComponentContext() );
     398             :     }
     399           0 :     catch ( uno::Exception const & )
     400             :     {
     401             :     }
     402             : 
     403           0 :     if ( !xSEInitializer.is() )
     404           0 :         return 1;
     405             : 
     406             :     uno::Reference< xml::crypto::XXMLSecurityContext > xSecurityContext(
     407           0 :         xSEInitializer->createSecurityContext( OUString() ) );
     408             : 
     409             :     uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnv(
     410           0 :         xSecurityContext->getSecurityEnvironment() );
     411             : 
     412             :     //The end entity certificate
     413           0 :     char * eeCertB64 = ne_ssl_cert_export( cert );
     414             : 
     415           0 :     OString sEECertB64( eeCertB64 );
     416             : 
     417             :     uno::Reference< security::XCertificate > xEECert(
     418           0 :         xSecurityEnv->createCertificateFromAscii(
     419           0 :             OStringToOUString( sEECertB64, RTL_TEXTENCODING_ASCII_US ) ) );
     420             : 
     421           0 :     ne_free( eeCertB64 );
     422           0 :     eeCertB64 = 0;
     423             : 
     424           0 :     std::vector< uno::Reference< security::XCertificate > > vecCerts;
     425           0 :     const ne_ssl_certificate * issuerCert = cert;
     426             :     do
     427             :     {
     428             :         //get the intermediate certificate
     429             :         //the returned value is const ! Therfore it does not need to be freed
     430             :         //with ne_ssl_cert_free, which takes a non-const argument
     431           0 :         issuerCert = ne_ssl_cert_signedby( issuerCert );
     432           0 :         if ( NULL == issuerCert )
     433           0 :             break;
     434             : 
     435           0 :         char * imCertB64 = ne_ssl_cert_export( issuerCert );
     436           0 :         OString sInterMediateCertB64( imCertB64 );
     437           0 :         ne_free( imCertB64 );
     438             : 
     439             :         uno::Reference< security::XCertificate> xImCert(
     440           0 :             xSecurityEnv->createCertificateFromAscii(
     441           0 :                 OStringToOUString( sInterMediateCertB64, RTL_TEXTENCODING_ASCII_US ) ) );
     442           0 :         if ( xImCert.is() )
     443           0 :             vecCerts.push_back( xImCert );
     444             :     }
     445             :     while ( true );
     446             : 
     447           0 :     sal_Int64 certValidity = xSecurityEnv->verifyCertificate( xEECert,
     448           0 :         ::comphelper::containerToSequence( vecCerts ) );
     449             : 
     450           0 :     if ( pSession->isDomainMatch(
     451           0 :         GetHostnamePart( xEECert.get()->getSubjectName() ) ) )
     452             :     {
     453             :         // if host name matched with certificate then look if the
     454             :         // certificate was ok
     455           0 :         if( certValidity == security::CertificateValidity::VALID )
     456           0 :             return 0;
     457             :     }
     458             : 
     459             :     const uno::Reference< ucb::XCommandEnvironment > xEnv(
     460           0 :         pSession->getRequestEnvironment().m_xEnv );
     461           0 :     if ( xEnv.is() )
     462             :     {
     463           0 :         failures = static_cast< int >( certValidity );
     464             : 
     465             :         uno::Reference< task::XInteractionHandler > xIH(
     466           0 :             xEnv->getInteractionHandler() );
     467           0 :         if ( xIH.is() )
     468             :         {
     469             :             rtl::Reference< ucbhelper::SimpleCertificateValidationRequest >
     470             :                 xRequest( new ucbhelper::SimpleCertificateValidationRequest(
     471           0 :                     (sal_Int32)failures, xEECert, pSession->getHostName() ) );
     472           0 :             xIH->handle( xRequest.get() );
     473             : 
     474             :             rtl::Reference< ucbhelper::InteractionContinuation > xSelection
     475           0 :                 = xRequest->getSelection();
     476             : 
     477           0 :             if ( xSelection.is() )
     478             :             {
     479             :                 uno::Reference< task::XInteractionApprove > xApprove(
     480           0 :                     xSelection.get(), uno::UNO_QUERY );
     481           0 :                 if ( xApprove.is() )
     482             :                 {
     483           0 :                     xCertificateContainer->addCertificate(
     484           0 :                         pSession->getHostName(), cert_subject,  sal_True );
     485           0 :                     return 0;
     486             :                 }
     487             :                 else
     488             :                 {
     489             :                     // Don't trust cert
     490           0 :                     xCertificateContainer->addCertificate(
     491           0 :                         pSession->getHostName(), cert_subject, sal_False );
     492           0 :                     return 1;
     493           0 :                 }
     494           0 :             }
     495             :         }
     496             :         else
     497             :         {
     498             :             // Don't trust cert
     499           0 :             xCertificateContainer->addCertificate(
     500           0 :                 pSession->getHostName(), cert_subject, sal_False );
     501           0 :             return 1;
     502           0 :         }
     503             :     }
     504           0 :     return 1;
     505             : }
     506             : 
     507           0 : extern "C" void NeonSession_PreSendRequest( ne_request * req,
     508             :                                             void * userdata,
     509             :                                             ne_buffer * headers )
     510             : {
     511             :     // userdata -> value returned by 'create'
     512             : 
     513           0 :     NeonSession * pSession = static_cast< NeonSession * >( userdata );
     514           0 :     if ( pSession )
     515             :     {
     516             :         // If there is a proxy server in between, it shall never use
     517             :         // cached data. We always want 'up-to-date' data.
     518           0 :         ne_buffer_concat( headers, "Pragma: no-cache", EOL, NULL );
     519             :         // alternative, but understoud by HTTP 1.1 servers only:
     520             :         // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL );
     521             : 
     522             :         const RequestDataMap * pRequestData
     523             :             = static_cast< const RequestDataMap* >(
     524           0 :                 pSession->getRequestData() );
     525             : 
     526           0 :         RequestDataMap::const_iterator it = pRequestData->find( req );
     527           0 :         if ( it != pRequestData->end() )
     528             :         {
     529           0 :             if ( !(*it).second.aContentType.isEmpty() )
     530             :             {
     531           0 :                 char * pData = headers->data;
     532           0 :                 if ( strstr( pData, "Content-Type:" ) == NULL )
     533             :                 {
     534             :                     OString aType
     535           0 :                         = OUStringToOString( (*it).second.aContentType,
     536           0 :                                                   RTL_TEXTENCODING_UTF8 );
     537             :                     ne_buffer_concat( headers, "Content-Type: ",
     538           0 :                                       aType.getStr(), EOL, NULL );
     539             :                 }
     540             :             }
     541             : 
     542           0 :             if ( !(*it).second.aReferer.isEmpty() )
     543             :             {
     544           0 :                 char * pData = headers->data;
     545           0 :                 if ( strstr( pData, "Referer:" ) == NULL )
     546             :                 {
     547             :                     OString aReferer
     548           0 :                         = OUStringToOString( (*it).second.aReferer,
     549           0 :                                                   RTL_TEXTENCODING_UTF8 );
     550             :                     ne_buffer_concat( headers, "Referer: ",
     551           0 :                                       aReferer.getStr(), EOL, NULL );
     552             :                 }
     553             :             }
     554             :         }
     555             : 
     556             :         const DAVRequestHeaders & rHeaders
     557           0 :             = pSession->getRequestEnvironment().m_aRequestHeaders;
     558             : 
     559           0 :         DAVRequestHeaders::const_iterator it1( rHeaders.begin() );
     560           0 :         const DAVRequestHeaders::const_iterator end1( rHeaders.end() );
     561             : 
     562           0 :         while ( it1 != end1 )
     563             :         {
     564             :             OString aHeader
     565           0 :                 = OUStringToOString( (*it1).first,
     566           0 :                                           RTL_TEXTENCODING_UTF8 );
     567             :             OString aValue
     568           0 :                 = OUStringToOString( (*it1).second,
     569           0 :                                           RTL_TEXTENCODING_UTF8 );
     570             :             ne_buffer_concat( headers, aHeader.getStr(), ": ",
     571           0 :                               aValue.getStr(), EOL, NULL );
     572             : 
     573           0 :             ++it1;
     574           0 :         }
     575             :     }
     576           0 : }
     577             : 
     578             : // static members
     579             : bool NeonSession::m_bGlobalsInited = false;
     580             : //See https://bugzilla.redhat.com/show_bug.cgi?id=544619#c4
     581             : //neon is threadsafe, but uses gnutls which is only thread-safe
     582             : //if initialized to be thread-safe. cups, unfortunately, generally
     583             : //initializes it first, and as non-thread-safe, leaving the entire
     584             : //stack unsafe
     585           1 : osl::Mutex aGlobalNeonMutex;
     586           1 : NeonLockStore NeonSession::m_aNeonLockStore;
     587             : 
     588           0 : NeonSession::NeonSession( const rtl::Reference< DAVSessionFactory > & rSessionFactory,
     589             :                           const OUString& inUri,
     590             :                           const uno::Sequence< beans::NamedValue >& rFlags,
     591             :                           const ucbhelper::InternetProxyDecider & rProxyDecider )
     592             :     throw ( DAVException )
     593             :     : DAVSession( rSessionFactory )
     594             :     , m_nProxyPort( 0 )
     595             :     , m_aFlags( rFlags )
     596             :     , m_pHttpSession( 0 )
     597           0 :     , m_pRequestData( new RequestDataMap )
     598           0 :     , m_rProxyDecider( rProxyDecider )
     599             : {
     600           0 :     NeonUri theUri( inUri );
     601           0 :     m_aScheme    = theUri.GetScheme();
     602           0 :     m_aHostName  = theUri.GetHost();
     603           0 :     m_nPort      = theUri.GetPort();
     604           0 : }
     605             : 
     606           0 : NeonSession::~NeonSession( )
     607             : {
     608           0 :     if ( m_pHttpSession )
     609             :     {
     610             :         {
     611           0 :             osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
     612           0 :             ne_session_destroy( m_pHttpSession );
     613             :         }
     614           0 :         m_pHttpSession = 0;
     615             :     }
     616           0 :     delete static_cast< RequestDataMap * >( m_pRequestData );
     617           0 : }
     618             : 
     619           0 : void NeonSession::Init( const DAVRequestEnvironment & rEnv )
     620             :     throw ( DAVException )
     621             : {
     622           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
     623           0 :     m_aEnv = rEnv;
     624           0 :     Init();
     625           0 : }
     626             : 
     627           0 : void NeonSession::Init()
     628             :     throw ( DAVException )
     629             : {
     630           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
     631             : 
     632           0 :     bool bCreateNewSession = false;
     633             : 
     634           0 :     if ( m_pHttpSession == 0 )
     635             :     {
     636             :         // Ensure that Neon sockets are initialized
     637           0 :         osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
     638           0 :         if ( !m_bGlobalsInited )
     639             :         {
     640           0 :             if ( ne_sock_init() != 0 )
     641             :                 throw DAVException( DAVException::DAV_SESSION_CREATE,
     642             :                                     NeonUri::makeConnectionEndPointString(
     643           0 :                                                     m_aHostName, m_nPort ) );
     644             : 
     645             :             // #122205# - libxml2 needs to be initialized once if used by
     646             :             // multithreaded programs like OOo.
     647           0 :             xmlInitParser();
     648             : #if OSL_DEBUG_LEVEL > 0
     649             :             // for more debug flags see ne_utils.h; NE_DEBUGGING must be defined
     650             :             // while compiling neon in order to actually activate neon debug
     651             :             // output.
     652             :             ne_debug_init( stderr, NE_DBG_FLUSH
     653             :                            | NE_DBG_HTTP
     654             :                            // | NE_DBG_HTTPBODY
     655             :                            // | NE_DBG_HTTPAUTH
     656             :                            // | NE_DBG_XML
     657             :                            // | NE_DBG_XMLPARSE
     658             :                            | NE_DBG_LOCKS
     659             :                            | NE_DBG_SSL
     660             :                          );
     661             : #endif
     662           0 :             m_bGlobalsInited = true;
     663             :         }
     664             : 
     665           0 :         const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
     666             : 
     667           0 :         m_aProxyName = rProxyCfg.aName;
     668           0 :         m_nProxyPort = rProxyCfg.nPort;
     669             : 
     670             :         // Not yet initialized. Create new session.
     671           0 :         bCreateNewSession = true;
     672             :     }
     673             :     else
     674             :     {
     675             :         // #112271# Check whether proxy settings are still valid (They may
     676             :         // change at any time). If not, create new Neon session.
     677             : 
     678           0 :         const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings();
     679             : 
     680           0 :         if ( ( rProxyCfg.aName != m_aProxyName )
     681           0 :              || ( rProxyCfg.nPort != m_nProxyPort ) )
     682             :         {
     683           0 :             m_aProxyName = rProxyCfg.aName;
     684           0 :             m_nProxyPort = rProxyCfg.nPort;
     685             : 
     686             :             // new session needed, destroy old first
     687             :             {
     688           0 :                 osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
     689           0 :                 ne_session_destroy( m_pHttpSession );
     690             :             }
     691           0 :             m_pHttpSession = 0;
     692           0 :             bCreateNewSession = true;
     693             :         }
     694             :     }
     695             : 
     696           0 :     if ( bCreateNewSession )
     697             :     {
     698             :         // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to
     699             :         //     build the complete request URI (including user:pass), but
     700             :         //     currently (0.22.0) neon does not allow to pass the user info
     701             :         //     to the session
     702             : 
     703             :         {
     704           0 :             osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
     705             :             m_pHttpSession = ne_session_create(
     706             :                 OUStringToOString( m_aScheme, RTL_TEXTENCODING_UTF8 ).getStr(),
     707             :                 /* theUri.GetUserInfo(),
     708             :                    @@@ for FTP via HTTP proxy, but not supported by Neon */
     709             :                 OUStringToOString( m_aHostName, RTL_TEXTENCODING_UTF8 ).getStr(),
     710           0 :                 m_nPort );
     711             :         }
     712             : 
     713           0 :         if ( m_pHttpSession == 0 )
     714             :             throw DAVException( DAVException::DAV_SESSION_CREATE,
     715             :                                 NeonUri::makeConnectionEndPointString(
     716           0 :                                     m_aHostName, m_nPort ) );
     717             : 
     718             :         // Register the session with the lock store
     719           0 :         m_aNeonLockStore.registerSession( m_pHttpSession );
     720             : 
     721           0 :         if ( m_aScheme.equalsIgnoreAsciiCase(
     722           0 :             OUString(  "https"  ) ) )
     723             :         {
     724             :             // Set a failure callback for certificate check
     725             :             ne_ssl_set_verify(
     726           0 :                 m_pHttpSession, NeonSession_CertificationNotify, this);
     727             : 
     728             :             // Tell Neon to tell the SSL library used (OpenSSL or
     729             :             // GnuTLS, I guess) to use a default set of root
     730             :             // certificates.
     731           0 :             ne_ssl_trust_default_ca(m_pHttpSession);
     732             :         }
     733             : 
     734             :         // Add hooks (i.e. for adding additional headers to the request)
     735             : 
     736             : #if 0
     737             :         /* Hook called when a request is created. */
     738             :         //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
     739             :         //                 const char *method, const char *path);
     740             : 
     741             :         ne_hook_create_request( m_pHttpSession, create_req_hook_fn, this );
     742             : #endif
     743             : 
     744             :         /* Hook called before the request is sent.  'header' is the raw HTTP
     745             :          * header before the trailing CRLF is added: add in more here. */
     746             :         //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
     747             :         //               ne_buffer *header);
     748             : 
     749           0 :         ne_hook_pre_send( m_pHttpSession, NeonSession_PreSendRequest, this );
     750             : #if 0
     751             :         /* Hook called after the request is sent. May return:
     752             :          *  NE_OK     everything is okay
     753             :          *  NE_RETRY  try sending the request again.
     754             :          * anything else signifies an error, and the request is failed. The
     755             :          * return code is passed back the _dispatch caller, so the session error
     756             :          * must also be set appropriately (ne_set_error).
     757             :          */
     758             :         //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
     759             :         //               const ne_status *status);
     760             : 
     761             :         ne_hook_post_send( m_pHttpSession, post_send_req_hook_fn, this );
     762             : 
     763             :         /* Hook called when the request is destroyed. */
     764             :         //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
     765             : 
     766             :         ne_hook_destroy_request( m_pHttpSession, destroy_req_hook_fn, this );
     767             : 
     768             :         /* Hook called when the session is destroyed. */
     769             :         //typedef void (*ne_destroy_sess_fn)(void *userdata);
     770             : 
     771             :         ne_hook_destroy_session( m_pHttpSession, destroy_sess_hook_fn, this );
     772             : #endif
     773             : 
     774           0 :         if ( !m_aProxyName.isEmpty() )
     775             :         {
     776             :             ne_session_proxy( m_pHttpSession,
     777             :                               OUStringToOString(
     778             :                                   m_aProxyName,
     779             :                                   RTL_TEXTENCODING_UTF8 ).getStr(),
     780           0 :                               m_nProxyPort );
     781             :         }
     782             : 
     783             :         // avoid KeepAlive?
     784           0 :         if ( noKeepAlive(m_aFlags) )
     785           0 :             ne_set_session_flag( m_pHttpSession, NE_SESSFLAG_PERSIST, 0 );
     786             : 
     787             :         // Register for redirects.
     788           0 :         ne_redirect_register( m_pHttpSession );
     789             : 
     790             :         // authentication callbacks.
     791             : #if 1
     792           0 :         ne_add_server_auth( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
     793           0 :         ne_add_proxy_auth ( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this );
     794             : #else
     795             :         ne_set_server_auth( m_pHttpSession, NeonSession_NeonAuth, this );
     796             :         ne_set_proxy_auth ( m_pHttpSession, NeonSession_NeonAuth, this );
     797             : #endif
     798           0 :     }
     799           0 : }
     800             : 
     801           0 : sal_Bool NeonSession::CanUse( const OUString & inUri,
     802             :                               const uno::Sequence< beans::NamedValue >& rFlags )
     803             : {
     804             :     try
     805             :     {
     806           0 :         NeonUri theUri( inUri );
     807           0 :         if ( ( theUri.GetPort() == m_nPort ) &&
     808           0 :              ( theUri.GetHost() == m_aHostName ) &&
     809           0 :              ( theUri.GetScheme() == m_aScheme ) &&
     810           0 :              ( rFlags == m_aFlags ) )
     811           0 :             return sal_True;
     812             :     }
     813           0 :     catch ( DAVException const & )
     814             :     {
     815           0 :         return sal_False;
     816             :     }
     817           0 :     return sal_False;
     818             : }
     819             : 
     820           0 : sal_Bool NeonSession::UsesProxy()
     821             : {
     822           0 :     Init();
     823           0 :     return  !m_aProxyName.isEmpty() ;
     824             : }
     825             : 
     826           0 : void NeonSession::OPTIONS( const OUString & inPath,
     827             :                            DAVCapabilities & outCapabilities,
     828             :                            const DAVRequestEnvironment & rEnv )
     829             :     throw( DAVException )
     830             : {
     831           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
     832             : 
     833           0 :     Init( rEnv );
     834             : 
     835             :     HttpServerCapabilities servercaps;
     836           0 :     memset( &servercaps, 0, sizeof( servercaps ) );
     837             : 
     838             :     int theRetVal = ne_options( m_pHttpSession,
     839             :                                 OUStringToOString(
     840             :                                     inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
     841           0 :                                 &servercaps );
     842             : 
     843           0 :     HandleError( theRetVal, inPath, rEnv );
     844             : 
     845           0 :     outCapabilities.class1     = !!servercaps.dav_class1;
     846           0 :     outCapabilities.class2     = !!servercaps.dav_class2;
     847           0 :     outCapabilities.executable = !!servercaps.dav_executable;
     848           0 : }
     849             : 
     850           0 : void NeonSession::PROPFIND( const OUString & inPath,
     851             :                             const Depth inDepth,
     852             :                             const std::vector< OUString > & inPropNames,
     853             :                             std::vector< DAVResource > & ioResources,
     854             :                             const DAVRequestEnvironment & rEnv )
     855             :     throw ( DAVException )
     856             : {
     857           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
     858             : 
     859           0 :     Init( rEnv );
     860             : 
     861           0 :     int theRetVal = NE_OK;
     862             :     NeonPropFindRequest theRequest( m_pHttpSession,
     863             :                                     OUStringToOString(
     864             :                                         inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
     865             :                                     inDepth,
     866             :                                     inPropNames,
     867             :                                     ioResources,
     868           0 :                                     theRetVal );
     869             : 
     870           0 :     HandleError( theRetVal, inPath, rEnv );
     871           0 : }
     872             : 
     873           0 : void NeonSession::PROPFIND( const OUString & inPath,
     874             :                             const Depth inDepth,
     875             :                             std::vector< DAVResourceInfo > & ioResInfo,
     876             :                             const DAVRequestEnvironment & rEnv )
     877             :     throw( DAVException )
     878             : {
     879           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
     880             : 
     881           0 :     Init( rEnv );
     882             : 
     883           0 :     int theRetVal = NE_OK;
     884             :     NeonPropFindRequest theRequest( m_pHttpSession,
     885             :                                     OUStringToOString(
     886             :                                         inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
     887             :                                     inDepth,
     888             :                                     ioResInfo,
     889           0 :                                     theRetVal );
     890             : 
     891           0 :     HandleError( theRetVal, inPath, rEnv );
     892           0 : }
     893             : 
     894           0 : void NeonSession::PROPPATCH( const OUString & inPath,
     895             :                              const std::vector< ProppatchValue > & inValues,
     896             :                              const DAVRequestEnvironment & rEnv )
     897             :     throw( DAVException )
     898             : {
     899             :     /* @@@ Which standard live properties can be set by the client?
     900             :            This is a known WebDAV RFC issue ( verified: 04/10/2001 )
     901             :            --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html
     902             : 
     903             :         mod_dav implementation:
     904             : 
     905             :         creationdate        r ( File System prop )
     906             :         displayname         w
     907             :         getcontentlanguage  r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
     908             :         getcontentlength    r ( File System prop )
     909             :         getcontenttype      r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS )
     910             :         getetag             r ( File System prop )
     911             :         getlastmodified     r ( File System prop )
     912             :         lockdiscovery       r
     913             :         resourcetype        r
     914             :         source              w
     915             :         supportedlock       r
     916             :         executable          w ( #ifndef WIN32 )
     917             : 
     918             :         All dead properties are of course writable.
     919             :     */
     920             : 
     921           0 :     int theRetVal = NE_OK;
     922             : 
     923             :     int n;  // for the "for" loop
     924             : 
     925             :     // Generate the list of properties we want to set.
     926           0 :     int nPropCount = inValues.size();
     927             :     ne_proppatch_operation* pItems
     928           0 :         = new ne_proppatch_operation[ nPropCount + 1 ];
     929           0 :     for ( n = 0; n < nPropCount; ++n )
     930             :     {
     931           0 :         const ProppatchValue & rValue = inValues[ n ];
     932             : 
     933             :         // Split fullname into namespace and name!
     934           0 :         ne_propname * pName = new ne_propname;
     935           0 :         DAVProperties::createNeonPropName( rValue.name, *pName );
     936           0 :         pItems[ n ].name = pName;
     937             : 
     938           0 :         if ( rValue.operation == PROPSET )
     939             :         {
     940           0 :             pItems[ n ].type = ne_propset;
     941             : 
     942           0 :             OUString aStringValue;
     943           0 :             if ( DAVProperties::isUCBDeadProperty( *pName ) )
     944             :             {
     945             :                 // DAV dead property added by WebDAV UCP?
     946           0 :                 if ( !UCBDeadPropertyValue::toXML( rValue.value,
     947           0 :                                                    aStringValue ) )
     948             :                 {
     949             :                     // Error!
     950           0 :                     pItems[ n ].value = 0;
     951           0 :                     theRetVal = NE_ERROR;
     952           0 :                     nPropCount = n + 1;
     953           0 :                     break;
     954             :                 }
     955             :             }
     956           0 :             else if ( !( rValue.value >>= aStringValue ) )
     957             :             {
     958             :                 // complex properties...
     959           0 :                 if ( rValue.name == DAVProperties::SOURCE )
     960             :                 {
     961           0 :                     uno::Sequence< ucb::Link > aLinks;
     962           0 :                     if ( rValue.value >>= aLinks )
     963             :                     {
     964           0 :                         LinkSequence::toXML( aLinks, aStringValue );
     965             :                     }
     966             :                     else
     967             :                     {
     968             :                         // Error!
     969           0 :                         pItems[ n ].value = 0;
     970           0 :                         theRetVal = NE_ERROR;
     971           0 :                         nPropCount = n + 1;
     972           0 :                         break;
     973           0 :                     }
     974             :                 }
     975             :                 else
     976             :                 {
     977             :                     OSL_FAIL( "NeonSession::PROPPATCH - unsupported type!" );
     978             :                     // Error!
     979           0 :                     pItems[ n ].value = 0;
     980           0 :                     theRetVal = NE_ERROR;
     981           0 :                     nPropCount = n + 1;
     982           0 :                     break;
     983             :                 }
     984             :             }
     985           0 :             pItems[ n ].value
     986             :                 = strdup( OUStringToOString( aStringValue,
     987           0 :                                                   RTL_TEXTENCODING_UTF8 ).getStr() );
     988             :         }
     989             :         else
     990             :         {
     991           0 :             pItems[ n ].type  = ne_propremove;
     992           0 :             pItems[ n ].value = 0;
     993             :         }
     994             :     }
     995             : 
     996           0 :     if ( theRetVal == NE_OK )
     997             :     {
     998           0 :         osl::Guard< osl::Mutex > theGuard( m_aMutex );
     999             : 
    1000           0 :         Init( rEnv );
    1001             : 
    1002           0 :         pItems[ n ].name = 0;
    1003             : 
    1004             :         theRetVal = ne_proppatch( m_pHttpSession,
    1005             :                                   OUStringToOString(
    1006             :                                       inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1007           0 :                                   pItems );
    1008             :     }
    1009             : 
    1010           0 :     for ( n = 0; n < nPropCount; ++n )
    1011             :     {
    1012           0 :         free( (void *)pItems[ n ].name->name );
    1013           0 :         delete pItems[ n ].name;
    1014           0 :         free( (void *)pItems[ n ].value );
    1015             :     }
    1016             : 
    1017           0 :     delete [] pItems;
    1018             : 
    1019           0 :     HandleError( theRetVal, inPath, rEnv );
    1020           0 : }
    1021             : 
    1022           0 : void NeonSession::HEAD( const OUString &  inPath,
    1023             :                         const std::vector< OUString > & inHeaderNames,
    1024             :                         DAVResource & ioResource,
    1025             :                         const DAVRequestEnvironment & rEnv )
    1026             :     throw( DAVException )
    1027             : {
    1028           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1029             : 
    1030           0 :     Init( rEnv );
    1031             : 
    1032           0 :     int theRetVal = NE_OK;
    1033             :     NeonHeadRequest theRequest( m_pHttpSession,
    1034             :                                 inPath,
    1035             :                                 inHeaderNames,
    1036             :                                 ioResource,
    1037           0 :                                 theRetVal );
    1038             : 
    1039           0 :     HandleError( theRetVal, inPath, rEnv );
    1040           0 : }
    1041             : 
    1042             : uno::Reference< io::XInputStream >
    1043           0 : NeonSession::GET( const OUString & inPath,
    1044             :                   const DAVRequestEnvironment & rEnv )
    1045             :     throw ( DAVException )
    1046             : {
    1047           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1048             : 
    1049           0 :     Init( rEnv );
    1050             : 
    1051           0 :     rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
    1052           0 :     NeonRequestContext aCtx( xInputStream );
    1053             :     int theRetVal = GET( m_pHttpSession,
    1054             :                          OUStringToOString(
    1055             :                              inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1056             :                          NeonSession_ResponseBlockReader,
    1057             :                          false,
    1058           0 :                          &aCtx );
    1059             : 
    1060           0 :     HandleError( theRetVal, inPath, rEnv );
    1061             : 
    1062           0 :     return uno::Reference< io::XInputStream >( xInputStream.get() );
    1063             : }
    1064             : 
    1065           0 : void NeonSession::GET( const OUString & inPath,
    1066             :                        uno::Reference< io::XOutputStream > & ioOutputStream,
    1067             :                        const DAVRequestEnvironment & rEnv )
    1068             :     throw ( DAVException )
    1069             : {
    1070           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1071             : 
    1072           0 :     Init( rEnv );
    1073             : 
    1074           0 :     NeonRequestContext aCtx( ioOutputStream );
    1075             :     int theRetVal = GET( m_pHttpSession,
    1076             :                          OUStringToOString(
    1077             :                              inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1078             :                          NeonSession_ResponseBlockWriter,
    1079             :                          false,
    1080           0 :                          &aCtx );
    1081             : 
    1082           0 :     HandleError( theRetVal, inPath, rEnv );
    1083           0 : }
    1084             : 
    1085             : uno::Reference< io::XInputStream >
    1086           0 : NeonSession::GET( const OUString & inPath,
    1087             :                   const std::vector< OUString > & inHeaderNames,
    1088             :                   DAVResource & ioResource,
    1089             :                   const DAVRequestEnvironment & rEnv )
    1090             :     throw ( DAVException )
    1091             : {
    1092           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1093             : 
    1094           0 :     Init( rEnv );
    1095             : 
    1096           0 :     ioResource.uri = inPath;
    1097           0 :     ioResource.properties.clear();
    1098             : 
    1099           0 :     rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
    1100           0 :     NeonRequestContext aCtx( xInputStream, inHeaderNames, ioResource );
    1101             :     int theRetVal = GET( m_pHttpSession,
    1102             :                          OUStringToOString(
    1103             :                              inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1104             :                          NeonSession_ResponseBlockReader,
    1105             :                          true,
    1106           0 :                          &aCtx );
    1107             : 
    1108           0 :     HandleError( theRetVal, inPath, rEnv );
    1109             : 
    1110           0 :     return uno::Reference< io::XInputStream >( xInputStream.get() );
    1111             : }
    1112             : 
    1113           0 : void NeonSession::GET( const OUString & inPath,
    1114             :                        uno::Reference< io::XOutputStream > & ioOutputStream,
    1115             :                        const std::vector< OUString > & inHeaderNames,
    1116             :                        DAVResource & ioResource,
    1117             :                        const DAVRequestEnvironment & rEnv )
    1118             :     throw ( DAVException )
    1119             : {
    1120           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1121             : 
    1122           0 :     Init( rEnv );
    1123             : 
    1124           0 :     ioResource.uri = inPath;
    1125           0 :     ioResource.properties.clear();
    1126             : 
    1127           0 :     NeonRequestContext aCtx( ioOutputStream, inHeaderNames, ioResource );
    1128             :     int theRetVal = GET( m_pHttpSession,
    1129             :                          OUStringToOString(
    1130             :                              inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1131             :                          NeonSession_ResponseBlockWriter,
    1132             :                          true,
    1133           0 :                          &aCtx );
    1134             : 
    1135           0 :     HandleError( theRetVal, inPath, rEnv );
    1136           0 : }
    1137             : 
    1138           0 : void NeonSession::PUT( const OUString & inPath,
    1139             :                        const uno::Reference< io::XInputStream > & inInputStream,
    1140             :                        const DAVRequestEnvironment & rEnv )
    1141             :     throw ( DAVException )
    1142             : {
    1143           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1144             : 
    1145           0 :     uno::Sequence< sal_Int8 > aDataToSend;
    1146           0 :     if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) )
    1147           0 :         throw DAVException( DAVException::DAV_INVALID_ARG );
    1148             : 
    1149           0 :     Init( rEnv );
    1150             : 
    1151             :     int theRetVal = PUT( m_pHttpSession,
    1152             :                          OUStringToOString(
    1153             :                              inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1154             :                          reinterpret_cast< const char * >(
    1155           0 :                             aDataToSend.getConstArray() ),
    1156           0 :                          aDataToSend.getLength() );
    1157             : 
    1158           0 :     HandleError( theRetVal, inPath, rEnv );
    1159           0 : }
    1160             : 
    1161             : uno::Reference< io::XInputStream >
    1162           0 : NeonSession::POST( const OUString & inPath,
    1163             :                    const OUString & rContentType,
    1164             :                    const OUString & rReferer,
    1165             :                    const uno::Reference< io::XInputStream > & inInputStream,
    1166             :                    const DAVRequestEnvironment & rEnv )
    1167             :     throw ( DAVException )
    1168             : {
    1169           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1170             : 
    1171           0 :     uno::Sequence< sal_Int8 > aDataToSend;
    1172           0 :     if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
    1173           0 :         throw DAVException( DAVException::DAV_INVALID_ARG );
    1174             : 
    1175           0 :     Init( rEnv );
    1176             : 
    1177           0 :     rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
    1178           0 :     NeonRequestContext aCtx( xInputStream );
    1179             :     int theRetVal = POST( m_pHttpSession,
    1180             :                           OUStringToOString(
    1181             :                               inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1182             :                           reinterpret_cast< const char * >(
    1183           0 :                               aDataToSend.getConstArray() ),
    1184             :                           NeonSession_ResponseBlockReader,
    1185             :                           &aCtx,
    1186             :                           rContentType,
    1187           0 :                           rReferer );
    1188             : 
    1189           0 :     HandleError( theRetVal, inPath, rEnv );
    1190             : 
    1191           0 :     return uno::Reference< io::XInputStream >( xInputStream.get() );
    1192             : }
    1193             : 
    1194           0 : void NeonSession::POST( const OUString & inPath,
    1195             :                         const OUString & rContentType,
    1196             :                         const OUString & rReferer,
    1197             :                         const uno::Reference< io::XInputStream > & inInputStream,
    1198             :                         uno::Reference< io::XOutputStream > & oOutputStream,
    1199             :                         const DAVRequestEnvironment & rEnv )
    1200             :     throw ( DAVException )
    1201             : {
    1202           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1203             : 
    1204           0 :     uno::Sequence< sal_Int8 > aDataToSend;
    1205           0 :     if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) )
    1206           0 :         throw DAVException( DAVException::DAV_INVALID_ARG );
    1207             : 
    1208           0 :     Init( rEnv );
    1209             : 
    1210           0 :     NeonRequestContext aCtx( oOutputStream );
    1211             :     int theRetVal = POST( m_pHttpSession,
    1212             :                           OUStringToOString(
    1213             :                               inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
    1214             :                           reinterpret_cast< const char * >(
    1215           0 :                               aDataToSend.getConstArray() ),
    1216             :                           NeonSession_ResponseBlockWriter,
    1217             :                           &aCtx,
    1218             :                           rContentType,
    1219           0 :                           rReferer );
    1220             : 
    1221           0 :     HandleError( theRetVal, inPath, rEnv );
    1222           0 : }
    1223             : 
    1224           0 : void NeonSession::MKCOL( const OUString & inPath,
    1225             :                          const DAVRequestEnvironment & rEnv )
    1226             :     throw ( DAVException )
    1227             : {
    1228           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1229             : 
    1230           0 :     Init( rEnv );
    1231             : 
    1232             :     int theRetVal = ne_mkcol( m_pHttpSession,
    1233             :                               OUStringToOString(
    1234           0 :                                   inPath, RTL_TEXTENCODING_UTF8 ).getStr() );
    1235             : 
    1236           0 :     HandleError( theRetVal, inPath, rEnv );
    1237           0 : }
    1238             : 
    1239           0 : void NeonSession::COPY( const OUString & inSourceURL,
    1240             :                         const OUString & inDestinationURL,
    1241             :                         const DAVRequestEnvironment & rEnv,
    1242             :                         sal_Bool inOverWrite )
    1243             :     throw ( DAVException )
    1244             : {
    1245           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1246             : 
    1247           0 :     Init( rEnv );
    1248             : 
    1249           0 :     NeonUri theSourceUri( inSourceURL );
    1250           0 :     NeonUri theDestinationUri( inDestinationURL );
    1251             : 
    1252             :     int theRetVal = ne_copy( m_pHttpSession,
    1253             :                              inOverWrite ? 1 : 0,
    1254             :                              NE_DEPTH_INFINITE,
    1255             :                              OUStringToOString(
    1256           0 :                                  theSourceUri.GetPath(),
    1257             :                                  RTL_TEXTENCODING_UTF8 ).getStr(),
    1258             :                              OUStringToOString(
    1259           0 :                                  theDestinationUri.GetPath(),
    1260           0 :                                  RTL_TEXTENCODING_UTF8 ).getStr() );
    1261             : 
    1262           0 :     HandleError( theRetVal, inSourceURL, rEnv );
    1263           0 : }
    1264             : 
    1265           0 : void NeonSession::MOVE( const OUString & inSourceURL,
    1266             :                         const OUString & inDestinationURL,
    1267             :                         const DAVRequestEnvironment & rEnv,
    1268             :                         sal_Bool inOverWrite )
    1269             :     throw ( DAVException )
    1270             : {
    1271           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1272             : 
    1273           0 :     Init( rEnv );
    1274             : 
    1275           0 :     NeonUri theSourceUri( inSourceURL );
    1276           0 :     NeonUri theDestinationUri( inDestinationURL );
    1277             :     int theRetVal = ne_move( m_pHttpSession,
    1278             :                              inOverWrite ? 1 : 0,
    1279             :                              OUStringToOString(
    1280           0 :                                  theSourceUri.GetPath(),
    1281             :                                  RTL_TEXTENCODING_UTF8 ).getStr(),
    1282             :                              OUStringToOString(
    1283           0 :                                  theDestinationUri.GetPath(),
    1284           0 :                                  RTL_TEXTENCODING_UTF8 ).getStr() );
    1285             : 
    1286           0 :     HandleError( theRetVal, inSourceURL, rEnv );
    1287           0 : }
    1288             : 
    1289           0 : void NeonSession::DESTROY( const OUString & inPath,
    1290             :                            const DAVRequestEnvironment & rEnv )
    1291             :     throw ( DAVException )
    1292             : {
    1293           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1294             : 
    1295           0 :     Init( rEnv );
    1296             : 
    1297             :     int theRetVal = ne_delete( m_pHttpSession,
    1298             :                                OUStringToOString(
    1299           0 :                                    inPath, RTL_TEXTENCODING_UTF8 ).getStr() );
    1300             : 
    1301           0 :     HandleError( theRetVal, inPath, rEnv );
    1302           0 : }
    1303             : 
    1304             : namespace
    1305             : {
    1306           0 :     sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart,
    1307             :                                               int timeout )
    1308             :     {
    1309             :         TimeValue aEnd;
    1310           0 :         osl_getSystemTime( &aEnd );
    1311             : 
    1312             :         // Try to estimate a safe absolute time for sending the
    1313             :         // lock refresh request.
    1314           0 :         sal_Int32 lastChanceToSendRefreshRequest = -1;
    1315           0 :         if ( timeout != NE_TIMEOUT_INFINITE )
    1316             :         {
    1317           0 :             sal_Int32 calltime = aEnd.Seconds - rStart.Seconds;
    1318           0 :             if ( calltime <= timeout )
    1319             :             {
    1320             :                 lastChanceToSendRefreshRequest
    1321           0 :                     = aEnd.Seconds + timeout - calltime;
    1322             :             }
    1323             :             else
    1324             :             {
    1325             :                 OSL_TRACE( "No chance to refresh lock before timeout!" );
    1326             :             }
    1327             :         }
    1328           0 :         return lastChanceToSendRefreshRequest;
    1329             :     }
    1330             : 
    1331             : } // namespace
    1332             : 
    1333             : // Set new lock
    1334           0 : void NeonSession::LOCK( const OUString & inPath,
    1335             :                         ucb::Lock & rLock,
    1336             :                         const DAVRequestEnvironment & rEnv )
    1337             :     throw ( DAVException )
    1338             : {
    1339           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1340             : 
    1341           0 :     Init( rEnv );
    1342             : 
    1343             :     /* Create a depth zero, exclusive write lock, with default timeout
    1344             :      * (allowing a server to pick a default).  token, owner and uri are
    1345             :      * unset. */
    1346           0 :     NeonLock * theLock = ne_lock_create();
    1347             : 
    1348             :     // Set the lock uri
    1349             :     ne_uri aUri;
    1350             :     ne_uri_parse( OUStringToOString( makeAbsoluteURL( inPath ),
    1351             :                                           RTL_TEXTENCODING_UTF8 ).getStr(),
    1352           0 :                   &aUri );
    1353           0 :     theLock->uri = aUri;
    1354             : 
    1355             :     // Set the lock depth
    1356           0 :     switch( rLock.Depth )
    1357             :     {
    1358             :     case ucb::LockDepth_ZERO:
    1359           0 :         theLock->depth = NE_DEPTH_ZERO;
    1360           0 :         break;
    1361             :     case ucb::LockDepth_ONE:
    1362           0 :         theLock->depth = NE_DEPTH_ONE;
    1363           0 :         break;
    1364             :     case ucb::LockDepth_INFINITY:
    1365           0 :         theLock->depth = NE_DEPTH_INFINITE;
    1366           0 :         break;
    1367             :     default:
    1368           0 :         throw DAVException( DAVException::DAV_INVALID_ARG );
    1369             :     }
    1370             : 
    1371             :     // Set the lock scope
    1372           0 :     switch ( rLock.Scope )
    1373             :     {
    1374             :     case ucb::LockScope_EXCLUSIVE:
    1375           0 :         theLock->scope = ne_lockscope_exclusive;
    1376           0 :         break;
    1377             :     case ucb::LockScope_SHARED:
    1378           0 :         theLock->scope = ne_lockscope_shared;
    1379           0 :         break;
    1380             :     default:
    1381           0 :         throw DAVException( DAVException::DAV_INVALID_ARG );
    1382             :     }
    1383             : 
    1384             :     // Set the lock timeout
    1385           0 :     theLock->timeout = (long)rLock.Timeout;
    1386             : 
    1387             :     // Set the lock owner
    1388           0 :     OUString aValue;
    1389           0 :     rLock.Owner >>= aValue;
    1390             :     theLock->owner =
    1391             :         ne_strdup( OUStringToOString( aValue,
    1392           0 :                                            RTL_TEXTENCODING_UTF8 ).getStr() );
    1393             :     TimeValue startCall;
    1394           0 :     osl_getSystemTime( &startCall );
    1395             : 
    1396           0 :     int theRetVal = ne_lock( m_pHttpSession, theLock );
    1397             : 
    1398           0 :     if ( theRetVal == NE_OK )
    1399             :     {
    1400             :         m_aNeonLockStore.addLock( theLock,
    1401             :                                   this,
    1402             :                                   lastChanceToSendRefreshRequest(
    1403           0 :                                       startCall, theLock->timeout ) );
    1404             : 
    1405           0 :         uno::Sequence< OUString > aTokens( 1 );
    1406           0 :         aTokens[ 0 ] = OUString::createFromAscii( theLock->token );
    1407           0 :         rLock.LockTokens = aTokens;
    1408             : 
    1409             :         OSL_TRACE( "NeonSession::LOCK: created lock for %s. token: %s",
    1410             :                    OUStringToOString( makeAbsoluteURL( inPath ),
    1411             :                                            RTL_TEXTENCODING_UTF8 ).getStr(),
    1412           0 :                    theLock->token );
    1413             :     }
    1414             :     else
    1415             :     {
    1416           0 :         ne_lock_destroy( theLock );
    1417             : 
    1418             :         OSL_TRACE( "NeonSession::LOCK: obtaining lock for %s failed!",
    1419             :                    OUStringToOString( makeAbsoluteURL( inPath ),
    1420             :                                            RTL_TEXTENCODING_UTF8 ).getStr() );
    1421             :     }
    1422             : 
    1423           0 :     HandleError( theRetVal, inPath, rEnv );
    1424           0 : }
    1425             : 
    1426             : // Refresh existing lock
    1427           0 : sal_Int64 NeonSession::LOCK( const OUString & inPath,
    1428             :                              sal_Int64 nTimeout,
    1429             :                              const DAVRequestEnvironment & rEnv )
    1430             :     throw ( DAVException )
    1431             : {
    1432           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1433             : 
    1434             :     // Try to get the neon lock from lock store
    1435             :     NeonLock * theLock
    1436           0 :         = m_aNeonLockStore.findByUri( makeAbsoluteURL( inPath ) );
    1437           0 :     if ( !theLock )
    1438           0 :          throw DAVException( DAVException::DAV_NOT_LOCKED );
    1439             : 
    1440           0 :     Init( rEnv );
    1441             : 
    1442             :     // refresh existing lock.
    1443           0 :     theLock->timeout = static_cast< long >( nTimeout );
    1444             : 
    1445             :     TimeValue startCall;
    1446           0 :     osl_getSystemTime( &startCall );
    1447             : 
    1448           0 :     int theRetVal = ne_lock_refresh( m_pHttpSession, theLock );
    1449             : 
    1450           0 :     if ( theRetVal == NE_OK )
    1451             :     {
    1452             :         m_aNeonLockStore.updateLock( theLock,
    1453             :                                      lastChanceToSendRefreshRequest(
    1454           0 :                                          startCall, theLock->timeout ) );
    1455             :     }
    1456             : 
    1457           0 :     HandleError( theRetVal, inPath, rEnv );
    1458             : 
    1459           0 :     return theLock->timeout;
    1460             : }
    1461             : 
    1462             : // Refresh existing lock
    1463           0 : bool NeonSession::LOCK( NeonLock * pLock,
    1464             :                         sal_Int32 & rlastChanceToSendRefreshRequest )
    1465             : {
    1466           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1467             : 
    1468             : #if OSL_DEBUG_LEVEL > 0
    1469             :     char * p = ne_uri_unparse( &(pLock->uri) );
    1470             :     OSL_TRACE( "NeonSession::LOCK: Refreshing lock for %s.", p );
    1471             :     ne_free( p );
    1472             : #endif
    1473             : 
    1474             :     // refresh existing lock.
    1475             : 
    1476             :     TimeValue startCall;
    1477           0 :     osl_getSystemTime( &startCall );
    1478             : 
    1479           0 :     if ( ne_lock_refresh( m_pHttpSession, pLock ) == NE_OK )
    1480             :     {
    1481             :         rlastChanceToSendRefreshRequest
    1482           0 :             = lastChanceToSendRefreshRequest( startCall, pLock->timeout );
    1483             : 
    1484             :         OSL_TRACE( "Lock successfully refreshed." );
    1485           0 :         return true;
    1486             :     }
    1487             :     else
    1488             :     {
    1489             :         OSL_TRACE( "Lock not refreshed!" );
    1490           0 :         return false;
    1491           0 :     }
    1492             : }
    1493             : 
    1494           0 : void NeonSession::UNLOCK( const OUString & inPath,
    1495             :                           const DAVRequestEnvironment & rEnv )
    1496             :     throw ( DAVException )
    1497             : {
    1498           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1499             : 
    1500             :     // get the neon lock from lock store
    1501             :     NeonLock * theLock
    1502           0 :         = m_aNeonLockStore.findByUri( makeAbsoluteURL( inPath ) );
    1503           0 :     if ( !theLock )
    1504           0 :         throw DAVException( DAVException::DAV_NOT_LOCKED );
    1505             : 
    1506           0 :     Init( rEnv );
    1507             : 
    1508           0 :     int theRetVal = ne_unlock( m_pHttpSession, theLock );
    1509             : 
    1510           0 :     if ( theRetVal == NE_OK )
    1511             :     {
    1512           0 :         m_aNeonLockStore.removeLock( theLock );
    1513           0 :         ne_lock_destroy( theLock );
    1514             :     }
    1515             :     else
    1516             :     {
    1517             :         OSL_TRACE( "NeonSession::UNLOCK: unlocking of %s failed.",
    1518             :                    OUStringToOString( makeAbsoluteURL( inPath ),
    1519             :                                            RTL_TEXTENCODING_UTF8 ).getStr() );
    1520             :     }
    1521             : 
    1522           0 :     HandleError( theRetVal, inPath, rEnv );
    1523           0 : }
    1524             : 
    1525           0 : bool NeonSession::UNLOCK( NeonLock * pLock )
    1526             : {
    1527           0 :     osl::Guard< osl::Mutex > theGuard( m_aMutex );
    1528             : 
    1529             : #if OSL_DEBUG_LEVEL > 0
    1530             :     char * p = ne_uri_unparse( &(pLock->uri) );
    1531             :     OSL_TRACE( "NeonSession::UNLOCK: Unlocking %s.", p );
    1532             :     ne_free( p );
    1533             : #endif
    1534             : 
    1535           0 :     if ( ne_unlock( m_pHttpSession, pLock ) == NE_OK )
    1536             :     {
    1537             :         OSL_TRACE( "UNLOCK succeeded." );
    1538           0 :         return true;
    1539             :     }
    1540             :     else
    1541             :     {
    1542             :         OSL_TRACE( "UNLOCK failed!" );
    1543           0 :         return false;
    1544           0 :     }
    1545             : }
    1546             : 
    1547           0 : void NeonSession::abort()
    1548             :     throw ( DAVException )
    1549             : {
    1550             :     SAL_INFO("ucb.ucp.webdav", "neon commands cannot be aborted");
    1551           0 : }
    1552             : 
    1553           0 : const ucbhelper::InternetProxyServer & NeonSession::getProxySettings() const
    1554             : {
    1555           0 :     if ( m_aScheme == "http" || m_aScheme == "https" )
    1556             :     {
    1557             :         return m_rProxyDecider.getProxy( m_aScheme,
    1558             :                                          m_aHostName,
    1559           0 :                                          m_nPort );
    1560             :     }
    1561             :     else
    1562             :     {
    1563             :         return m_rProxyDecider.getProxy( m_aScheme,
    1564             :                                          OUString() /* not used */,
    1565           0 :                                          -1 /* not used */ );
    1566             :     }
    1567             : }
    1568             : 
    1569             : namespace {
    1570             : 
    1571           0 : bool containsLocktoken( const uno::Sequence< ucb::Lock > & rLocks,
    1572             :                         const char * token )
    1573             : {
    1574           0 :     for ( sal_Int32 n = 0; n < rLocks.getLength(); ++n )
    1575             :     {
    1576             :         const uno::Sequence< OUString > & rTokens
    1577           0 :             = rLocks[ n ].LockTokens;
    1578           0 :         for ( sal_Int32 m = 0; m < rTokens.getLength(); ++m )
    1579             :         {
    1580           0 :             if ( rTokens[ m ].equalsAscii( token ) )
    1581           0 :                 return true;
    1582             :         }
    1583             :     }
    1584           0 :     return false;
    1585             : }
    1586             : 
    1587             : } // namespace
    1588             : 
    1589           0 : bool NeonSession::removeExpiredLocktoken( const OUString & inURL,
    1590             :                                           const DAVRequestEnvironment & rEnv )
    1591             : {
    1592           0 :     NeonLock * theLock = m_aNeonLockStore.findByUri( inURL );
    1593           0 :     if ( !theLock )
    1594           0 :         return false;
    1595             : 
    1596             :     // do a lockdiscovery to check whether this lock is still valid.
    1597             :     try
    1598             :     {
    1599             :         // @@@ Alternative: use ne_lock_discover() => less overhead
    1600             : 
    1601           0 :         std::vector< DAVResource > aResources;
    1602           0 :         std::vector< OUString > aPropNames;
    1603           0 :         aPropNames.push_back( DAVProperties::LOCKDISCOVERY );
    1604             : 
    1605           0 :         PROPFIND( rEnv.m_aRequestURI, DAVZERO, aPropNames, aResources, rEnv );
    1606             : 
    1607           0 :         if ( aResources.empty() )
    1608           0 :             return false;
    1609             : 
    1610             :         std::vector< DAVPropertyValue >::const_iterator it
    1611           0 :             = aResources[ 0 ].properties.begin();
    1612             :         std::vector< DAVPropertyValue >::const_iterator end
    1613           0 :             = aResources[ 0 ].properties.end();
    1614             : 
    1615           0 :         while ( it != end )
    1616             :         {
    1617           0 :             if ( (*it).Name.equals( DAVProperties::LOCKDISCOVERY ) )
    1618             :             {
    1619           0 :                 uno::Sequence< ucb::Lock > aLocks;
    1620           0 :                 if ( !( (*it).Value >>= aLocks ) )
    1621           0 :                     return false;
    1622             : 
    1623           0 :                 if ( !containsLocktoken( aLocks, theLock->token ) )
    1624             :                 {
    1625             :                     // expired!
    1626           0 :                     break;
    1627             :                 }
    1628             : 
    1629             :                 // still valid.
    1630           0 :                 return false;
    1631             :             }
    1632           0 :             ++it;
    1633             :         }
    1634             : 
    1635             :         // No lockdiscovery prop in propfind result / locktoken not found
    1636             :         // in propfind result -> not locked
    1637             :         OSL_TRACE( "NeonSession::removeExpiredLocktoken: Removing "
    1638             :                    " expired lock token for %s. token: %s",
    1639             :                    OUStringToOString( inURL,
    1640             :                                            RTL_TEXTENCODING_UTF8 ).getStr(),
    1641             :                    theLock->token );
    1642             : 
    1643           0 :         m_aNeonLockStore.removeLock( theLock );
    1644           0 :         ne_lock_destroy( theLock );
    1645           0 :         return true;
    1646             :     }
    1647           0 :     catch ( DAVException const & )
    1648             :     {
    1649             :     }
    1650           0 :     return false;
    1651             : }
    1652             : 
    1653             : // Common error handler
    1654           0 : void NeonSession::HandleError( int nError,
    1655             :                                const OUString & inPath,
    1656             :                                const DAVRequestEnvironment & rEnv )
    1657             :     throw ( DAVException )
    1658             : {
    1659           0 :     m_aEnv = DAVRequestEnvironment();
    1660             : 
    1661             :     // Map error code to DAVException.
    1662           0 :     switch ( nError )
    1663             :     {
    1664             :         case NE_OK:
    1665           0 :             return;
    1666             : 
    1667             :         case NE_ERROR:        // Generic error
    1668             :         {
    1669             :             OUString aText = OUString::createFromAscii(
    1670           0 :                 ne_get_error( m_pHttpSession ) );
    1671             : 
    1672           0 :             sal_uInt16 code = makeStatusCode( aText );
    1673             : 
    1674           0 :             if ( code == SC_LOCKED )
    1675             :             {
    1676           0 :                 if ( m_aNeonLockStore.findByUri(
    1677           0 :                          makeAbsoluteURL( inPath ) ) == 0 )
    1678             :                 {
    1679             :                     // locked by 3rd party
    1680           0 :                     throw DAVException( DAVException::DAV_LOCKED );
    1681             :                 }
    1682             :                 else
    1683             :                 {
    1684             :                     // locked by ourself
    1685           0 :                     throw DAVException( DAVException::DAV_LOCKED_SELF );
    1686             :                 }
    1687             :             }
    1688             : 
    1689             :             // Special handling for 400 and 412 status codes, which may indicate
    1690             :             // that a lock previously obtained by us has been released meanwhile
    1691             :             // by the server. Unfortunately, RFC is not clear at this point,
    1692             :             // thus server implementations behave different...
    1693           0 :             else if ( code == SC_BAD_REQUEST || code == SC_PRECONDITION_FAILED )
    1694             :             {
    1695           0 :                 if ( removeExpiredLocktoken( makeAbsoluteURL( inPath ), rEnv ) )
    1696           0 :                     throw DAVException( DAVException::DAV_LOCK_EXPIRED );
    1697             :             }
    1698             : 
    1699           0 :             throw DAVException( DAVException::DAV_HTTP_ERROR, aText, code );
    1700             :         }
    1701             :         case NE_LOOKUP:       // Name lookup failed.
    1702             :             throw DAVException( DAVException::DAV_HTTP_LOOKUP,
    1703             :                                 NeonUri::makeConnectionEndPointString(
    1704           0 :                                     m_aHostName, m_nPort ) );
    1705             : 
    1706             :         case NE_AUTH:         // User authentication failed on server
    1707             :             throw DAVException( DAVException::DAV_HTTP_AUTH,
    1708             :                                 NeonUri::makeConnectionEndPointString(
    1709           0 :                                     m_aHostName, m_nPort ) );
    1710             : 
    1711             :         case NE_PROXYAUTH:    // User authentication failed on proxy
    1712             :             throw DAVException( DAVException::DAV_HTTP_AUTHPROXY,
    1713             :                                 NeonUri::makeConnectionEndPointString(
    1714           0 :                                     m_aProxyName, m_nProxyPort ) );
    1715             : 
    1716             :         case NE_CONNECT:      // Could not connect to server
    1717             :             throw DAVException( DAVException::DAV_HTTP_CONNECT,
    1718             :                                 NeonUri::makeConnectionEndPointString(
    1719           0 :                                     m_aHostName, m_nPort ) );
    1720             : 
    1721             :         case NE_TIMEOUT:      // Connection timed out
    1722             :             throw DAVException( DAVException::DAV_HTTP_TIMEOUT,
    1723             :                                 NeonUri::makeConnectionEndPointString(
    1724           0 :                                     m_aHostName, m_nPort ) );
    1725             : 
    1726             :         case NE_FAILED:       // The precondition failed
    1727             :             throw DAVException( DAVException::DAV_HTTP_FAILED,
    1728             :                                 NeonUri::makeConnectionEndPointString(
    1729           0 :                                     m_aHostName, m_nPort ) );
    1730             : 
    1731             :         case NE_RETRY:        // Retry request (ne_end_request ONLY)
    1732             :             throw DAVException( DAVException::DAV_HTTP_RETRY,
    1733             :                                 NeonUri::makeConnectionEndPointString(
    1734           0 :                                     m_aHostName, m_nPort ) );
    1735             : 
    1736             :         case NE_REDIRECT:
    1737             :         {
    1738           0 :             NeonUri aUri( ne_redirect_location( m_pHttpSession ) );
    1739             :             throw DAVException(
    1740           0 :                 DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() );
    1741             :         }
    1742             :         default:
    1743             :         {
    1744             :             OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" );
    1745             :             throw DAVException( DAVException::DAV_HTTP_ERROR,
    1746             :                                 OUString::createFromAscii(
    1747           0 :                                     ne_get_error( m_pHttpSession ) ) );
    1748             :         }
    1749             :     }
    1750             : }
    1751             : 
    1752             : namespace {
    1753             : 
    1754           0 : void runResponseHeaderHandler( void * userdata,
    1755             :                                const char * value )
    1756             : {
    1757           0 :     OUString aHeader( OUString::createFromAscii( value ) );
    1758           0 :     sal_Int32 nPos = aHeader.indexOf( ':' );
    1759             : 
    1760           0 :     if ( nPos != -1 )
    1761             :     {
    1762           0 :         OUString aHeaderName( aHeader.copy( 0, nPos ) );
    1763             : 
    1764             :         NeonRequestContext * pCtx
    1765           0 :             = static_cast< NeonRequestContext * >( userdata );
    1766             : 
    1767             :         // Note: Empty vector means that all headers are requested.
    1768           0 :         bool bIncludeIt = ( pCtx->pHeaderNames->empty() );
    1769             : 
    1770           0 :         if ( !bIncludeIt )
    1771             :         {
    1772             :             // Check whether this header was requested.
    1773             :             std::vector< OUString >::const_iterator it(
    1774           0 :                 pCtx->pHeaderNames->begin() );
    1775             :             const std::vector< OUString >::const_iterator end(
    1776           0 :                 pCtx->pHeaderNames->end() );
    1777             : 
    1778           0 :             while ( it != end )
    1779             :             {
    1780             :                 // header names are case insensitive
    1781           0 :                 if ( (*it).equalsIgnoreAsciiCase( aHeaderName ) )
    1782             :                 {
    1783           0 :                     aHeaderName = (*it);
    1784           0 :                     break;
    1785             :                 }
    1786           0 :                 ++it;
    1787             :             }
    1788             : 
    1789           0 :             if ( it != end )
    1790           0 :                 bIncludeIt = true;
    1791             :         }
    1792             : 
    1793           0 :         if ( bIncludeIt )
    1794             :         {
    1795             :             // Create & set the PropertyValue
    1796           0 :             DAVPropertyValue thePropertyValue;
    1797           0 :             thePropertyValue.IsCaseSensitive = false;
    1798           0 :             thePropertyValue.Name = aHeaderName;
    1799             : 
    1800           0 :             if ( nPos < aHeader.getLength() )
    1801           0 :                 thePropertyValue.Value <<= aHeader.copy( nPos + 1 ).trim();
    1802             : 
    1803             :             // Add the newly created PropertyValue
    1804           0 :             pCtx->pResource->properties.push_back( thePropertyValue );
    1805           0 :         }
    1806           0 :     }
    1807           0 : }
    1808             : 
    1809             : } // namespace
    1810             : 
    1811           0 : int NeonSession::GET( ne_session * sess,
    1812             :                       const char * uri,
    1813             :                       ne_block_reader reader,
    1814             :                       bool getheaders,
    1815             :                       void * userdata )
    1816             : {
    1817             :     //struct get_context ctx;
    1818           0 :     ne_request * req = ne_request_create( sess, "GET", uri );
    1819             :     int ret;
    1820             : 
    1821             :     ne_decompress * dc
    1822           0 :         = ne_decompress_reader( req, ne_accept_2xx, reader, userdata );
    1823             : 
    1824             :     {
    1825           0 :         osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
    1826           0 :         ret = ne_request_dispatch( req );
    1827             :     }
    1828             : 
    1829           0 :     if ( getheaders )
    1830             :     {
    1831           0 :         void *cursor = NULL;
    1832             :         const char *name, *value;
    1833           0 :         while ( ( cursor = ne_response_header_iterate(
    1834             :                                req, cursor, &name, &value ) ) != NULL )
    1835             :         {
    1836             :             char buffer[8192];
    1837             : 
    1838           0 :             ne_snprintf(buffer, sizeof buffer, "%s: %s", name, value);
    1839           0 :             runResponseHeaderHandler(userdata, buffer);
    1840             :         }
    1841             :     }
    1842             : 
    1843           0 :     if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
    1844           0 :         ret = NE_ERROR;
    1845             : 
    1846           0 :     if ( dc != 0 )
    1847           0 :         ne_decompress_destroy(dc);
    1848             : 
    1849           0 :     ne_request_destroy( req );
    1850           0 :     return ret;
    1851             : }
    1852             : 
    1853           0 : int NeonSession::PUT( ne_session * sess,
    1854             :                       const char * uri,
    1855             :                       const char * buffer,
    1856             :                       size_t size)
    1857             : {
    1858           0 :     ne_request * req = ne_request_create( sess, "PUT", uri );
    1859             :     int ret;
    1860             : 
    1861           0 :     ne_lock_using_resource( req, uri, 0 );
    1862           0 :     ne_lock_using_parent( req, uri );
    1863             : 
    1864           0 :     ne_set_request_body_buffer( req, buffer, size );
    1865             : 
    1866             :     {
    1867           0 :         osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
    1868           0 :         ret = ne_request_dispatch( req );
    1869             :     }
    1870             : 
    1871           0 :     if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
    1872           0 :         ret = NE_ERROR;
    1873             : 
    1874           0 :     ne_request_destroy( req );
    1875           0 :     return ret;
    1876             : }
    1877             : 
    1878           0 : int NeonSession::POST( ne_session * sess,
    1879             :                        const char * uri,
    1880             :                        const char * buffer,
    1881             :                        ne_block_reader reader,
    1882             :                        void * userdata,
    1883             :                        const OUString & rContentType,
    1884             :                        const OUString & rReferer )
    1885             : {
    1886           0 :     ne_request * req = ne_request_create( sess, "POST", uri );
    1887             :     //struct get_context ctx;
    1888             :     int ret;
    1889             : 
    1890           0 :     RequestDataMap * pData = 0;
    1891             : 
    1892           0 :     if ( !rContentType.isEmpty() || !rReferer.isEmpty() )
    1893             :     {
    1894             :         // Remember contenttype and referer. Data will be added to HTTP request
    1895             :         // header in in 'PreSendRequest' callback.
    1896           0 :         pData = static_cast< RequestDataMap* >( m_pRequestData );
    1897           0 :         (*pData)[ req ] = RequestData( rContentType, rReferer );
    1898             :     }
    1899             : 
    1900             :     //ctx.total = -1;
    1901             :     //ctx.fd = fd;
    1902             :     //ctx.error = 0;
    1903             :     //ctx.session = sess;
    1904             : 
    1905             :     ///* Read the value of the Content-Length header into ctx.total */
    1906             :     //ne_add_response_header_handler( req, "Content-Length",
    1907             :     //                 ne_handle_numeric_header, &ctx.total );
    1908             : 
    1909           0 :     ne_add_response_body_reader( req, ne_accept_2xx, reader, userdata );
    1910             : 
    1911           0 :     ne_set_request_body_buffer( req, buffer, strlen( buffer ) );
    1912             : 
    1913             :     {
    1914           0 :         osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
    1915           0 :         ret = ne_request_dispatch( req );
    1916             :     }
    1917             : 
    1918             :     //if ( ctx.error )
    1919             :     //    ret = NE_ERROR;
    1920             :     //else
    1921           0 :     if ( ret == NE_OK && ne_get_status( req )->klass != 2 )
    1922           0 :         ret = NE_ERROR;
    1923             : 
    1924           0 :     ne_request_destroy( req );
    1925             : 
    1926           0 :     if ( pData )
    1927             :     {
    1928             :         // Remove request data from session's list.
    1929           0 :         RequestDataMap::iterator it = pData->find( req );
    1930           0 :         if ( it != pData->end() )
    1931           0 :             pData->erase( it );
    1932             :     }
    1933             : 
    1934           0 :     return ret;
    1935             : }
    1936             : 
    1937             : bool
    1938           0 : NeonSession::getDataFromInputStream(
    1939             :     const uno::Reference< io::XInputStream > & xStream,
    1940             :     uno::Sequence< sal_Int8 > & rData,
    1941             :     bool bAppendTrailingZeroByte )
    1942             : {
    1943           0 :     if ( xStream.is() )
    1944             :     {
    1945           0 :         uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY );
    1946           0 :         if ( xSeekable.is() )
    1947             :         {
    1948             :             try
    1949             :             {
    1950             :                 sal_Int32 nSize
    1951           0 :                     = sal::static_int_cast<sal_Int32>(xSeekable->getLength());
    1952             :                 sal_Int32 nRead
    1953           0 :                     = xStream->readBytes( rData, nSize );
    1954             : 
    1955           0 :                 if ( nRead == nSize )
    1956             :                 {
    1957           0 :                     if ( bAppendTrailingZeroByte )
    1958             :                     {
    1959           0 :                         rData.realloc( nSize + 1 );
    1960           0 :                         rData[ nSize ] = sal_Int8( 0 );
    1961             :                     }
    1962           0 :                     return true;
    1963             :                 }
    1964             :             }
    1965           0 :             catch ( io::NotConnectedException const & )
    1966             :             {
    1967             :                 // readBytes
    1968             :             }
    1969           0 :             catch ( io::BufferSizeExceededException const & )
    1970             :             {
    1971             :                 // readBytes
    1972             :             }
    1973           0 :             catch ( io::IOException const & )
    1974             :             {
    1975             :                 // getLength, readBytes
    1976             :             }
    1977             :         }
    1978             :         else
    1979             :         {
    1980             :             try
    1981             :             {
    1982           0 :                 uno::Sequence< sal_Int8 > aBuffer;
    1983           0 :                 sal_Int32 nPos = 0;
    1984             : 
    1985           0 :                 sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 );
    1986           0 :                 while ( nRead > 0 )
    1987             :                 {
    1988           0 :                     if ( rData.getLength() < ( nPos + nRead ) )
    1989           0 :                         rData.realloc( nPos + nRead );
    1990             : 
    1991           0 :                     aBuffer.realloc( nRead );
    1992           0 :                     memcpy( (void*)( rData.getArray() + nPos ),
    1993           0 :                                     (const void*)aBuffer.getConstArray(),
    1994           0 :                                     nRead );
    1995           0 :                     nPos += nRead;
    1996             : 
    1997           0 :                     aBuffer.realloc( 0 );
    1998           0 :                     nRead = xStream->readSomeBytes( aBuffer, 65536 );
    1999             :                 }
    2000             : 
    2001           0 :                 if ( bAppendTrailingZeroByte )
    2002             :                 {
    2003           0 :                     rData.realloc( nPos + 1 );
    2004           0 :                     rData[ nPos ] = sal_Int8( 0 );
    2005             :                 }
    2006           0 :                 return true;
    2007             :             }
    2008           0 :             catch ( io::NotConnectedException const & )
    2009             :             {
    2010             :                 // readBytes
    2011             :             }
    2012           0 :             catch ( io::BufferSizeExceededException const & )
    2013             :             {
    2014             :                 // readBytes
    2015             :             }
    2016           0 :             catch ( io::IOException const & )
    2017             :             {
    2018             :                 // readBytes
    2019             :             }
    2020           0 :         }
    2021             :     }
    2022           0 :     return false;
    2023             : }
    2024             : 
    2025             : sal_Bool
    2026           0 : NeonSession::isDomainMatch( const OUString& certHostName )
    2027             : {
    2028           0 :     OUString hostName = getHostName();
    2029             : 
    2030           0 :     if (hostName.equalsIgnoreAsciiCase( certHostName ) )
    2031           0 :         return sal_True;
    2032             : 
    2033           0 :     if ( certHostName.startsWith( "*" ) &&
    2034           0 :          hostName.getLength() >= certHostName.getLength()  )
    2035             :     {
    2036           0 :         OUString cmpStr = certHostName.copy( 1 );
    2037             : 
    2038           0 :         if ( hostName.matchIgnoreAsciiCase(
    2039           0 :                 cmpStr, hostName.getLength() -  cmpStr.getLength() ) )
    2040           0 :             return sal_True;
    2041             :     }
    2042           0 :     return sal_False;
    2043             : }
    2044             : 
    2045           0 : OUString NeonSession::makeAbsoluteURL( OUString const & rURL ) const
    2046             : {
    2047             :     try
    2048             :     {
    2049             :         // Is URL relative or already absolute?
    2050           0 :         if ( rURL[ 0 ] != '/' )
    2051             :         {
    2052             :             // absolute.
    2053           0 :             return OUString( rURL );
    2054             :         }
    2055             :         else
    2056             :         {
    2057             :             ne_uri aUri;
    2058           0 :             memset( &aUri, 0, sizeof( aUri ) );
    2059             : 
    2060           0 :             ne_fill_server_uri( m_pHttpSession, &aUri );
    2061             :             aUri.path
    2062             :                 = ne_strdup( OUStringToOString(
    2063           0 :                     rURL, RTL_TEXTENCODING_UTF8 ).getStr() );
    2064           0 :             NeonUri aNeonUri( &aUri );
    2065           0 :             ne_uri_free( &aUri );
    2066           0 :             return aNeonUri.GetURI();
    2067             :         }
    2068             :     }
    2069           0 :     catch ( DAVException const & )
    2070             :     {
    2071             :     }
    2072             :     // error.
    2073           0 :     return OUString();
    2074           3 : }
    2075             : 
    2076             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10