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

Generated by: LCOV version 1.10