1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_extensions.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir #if defined WNT 32*cdf0e10cSrcweir #ifdef _MSC_VER 33*cdf0e10cSrcweir #pragma warning(push, 1) /* disable warnings within system headers */ 34*cdf0e10cSrcweir #endif 35*cdf0e10cSrcweir #include <curl/curl.h> 36*cdf0e10cSrcweir #ifdef _MSC_VER 37*cdf0e10cSrcweir #pragma warning(pop) 38*cdf0e10cSrcweir #endif 39*cdf0e10cSrcweir #else 40*cdf0e10cSrcweir #include <curl/curl.h> 41*cdf0e10cSrcweir #endif 42*cdf0e10cSrcweir #include <com/sun/star/beans/PropertyValue.hpp> 43*cdf0e10cSrcweir #include <com/sun/star/container/XNameAccess.hpp> 44*cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 45*cdf0e10cSrcweir 46*cdf0e10cSrcweir #include "download.hxx" 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir namespace beans = com::sun::star::beans ; 49*cdf0e10cSrcweir namespace container = com::sun::star::container ; 50*cdf0e10cSrcweir namespace lang = com::sun::star::lang ; 51*cdf0e10cSrcweir namespace uno = com::sun::star::uno ; 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) 54*cdf0e10cSrcweir 55*cdf0e10cSrcweir 56*cdf0e10cSrcweir struct OutData 57*cdf0e10cSrcweir { 58*cdf0e10cSrcweir rtl::Reference< DownloadInteractionHandler >Handler; 59*cdf0e10cSrcweir rtl::OUString File; 60*cdf0e10cSrcweir rtl::OUString DestinationDir; 61*cdf0e10cSrcweir oslFileHandle FileHandle; 62*cdf0e10cSrcweir sal_uInt64 Offset; 63*cdf0e10cSrcweir osl::Condition& StopCondition; 64*cdf0e10cSrcweir CURL *curl; 65*cdf0e10cSrcweir 66*cdf0e10cSrcweir OutData(osl::Condition& rCondition) : FileHandle(NULL), Offset(0), StopCondition(rCondition), curl(NULL) {}; 67*cdf0e10cSrcweir }; 68*cdf0e10cSrcweir 69*cdf0e10cSrcweir //------------------------------------------------------------------------------ 70*cdf0e10cSrcweir 71*cdf0e10cSrcweir static void openFile( OutData& out ) 72*cdf0e10cSrcweir { 73*cdf0e10cSrcweir char * effective_url; 74*cdf0e10cSrcweir curl_easy_getinfo(out.curl, CURLINFO_EFFECTIVE_URL, &effective_url); 75*cdf0e10cSrcweir 76*cdf0e10cSrcweir double fDownloadSize; 77*cdf0e10cSrcweir curl_easy_getinfo(out.curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fDownloadSize); 78*cdf0e10cSrcweir 79*cdf0e10cSrcweir rtl::OString aURL(effective_url); 80*cdf0e10cSrcweir 81*cdf0e10cSrcweir // ensure no trailing '/' 82*cdf0e10cSrcweir sal_Int32 nLen = aURL.getLength(); 83*cdf0e10cSrcweir while( (nLen > 0) && ('/' == aURL[nLen-1]) ) 84*cdf0e10cSrcweir aURL = aURL.copy(0, --nLen); 85*cdf0e10cSrcweir 86*cdf0e10cSrcweir // extract file name last '/' 87*cdf0e10cSrcweir sal_Int32 nIndex = aURL.lastIndexOf('/'); 88*cdf0e10cSrcweir if( nIndex > 0 ) 89*cdf0e10cSrcweir { 90*cdf0e10cSrcweir out.File = out.DestinationDir + rtl::OStringToOUString(aURL.copy(nIndex), RTL_TEXTENCODING_UTF8); 91*cdf0e10cSrcweir 92*cdf0e10cSrcweir oslFileError rc; 93*cdf0e10cSrcweir 94*cdf0e10cSrcweir // Give the user an overwrite warning if the target file exists 95*cdf0e10cSrcweir const sal_Int32 openFlags = osl_File_OpenFlag_Write | osl_File_OpenFlag_Create; 96*cdf0e10cSrcweir do 97*cdf0e10cSrcweir { 98*cdf0e10cSrcweir rc = osl_openFile(out.File.pData, &out.FileHandle, openFlags); 99*cdf0e10cSrcweir 100*cdf0e10cSrcweir if( osl_File_E_EXIST == rc && ! out.Handler->downloadTargetExists(out.File) ) 101*cdf0e10cSrcweir { 102*cdf0e10cSrcweir out.StopCondition.set(); 103*cdf0e10cSrcweir break; 104*cdf0e10cSrcweir } 105*cdf0e10cSrcweir 106*cdf0e10cSrcweir } while( osl_File_E_EXIST == rc ); 107*cdf0e10cSrcweir 108*cdf0e10cSrcweir if( osl_File_E_None == rc ) 109*cdf0e10cSrcweir out.Handler->downloadStarted(out.File, (sal_Int64) fDownloadSize); 110*cdf0e10cSrcweir } 111*cdf0e10cSrcweir } 112*cdf0e10cSrcweir 113*cdf0e10cSrcweir //------------------------------------------------------------------------------ 114*cdf0e10cSrcweir 115*cdf0e10cSrcweir static inline rtl::OString 116*cdf0e10cSrcweir getStringValue(const uno::Reference< container::XNameAccess >& xNameAccess, const rtl::OUString& aName) 117*cdf0e10cSrcweir { 118*cdf0e10cSrcweir rtl::OString aRet; 119*cdf0e10cSrcweir 120*cdf0e10cSrcweir OSL_ASSERT(xNameAccess->hasByName(aName)); 121*cdf0e10cSrcweir uno::Any aValue = xNameAccess->getByName(aName); 122*cdf0e10cSrcweir 123*cdf0e10cSrcweir return rtl::OUStringToOString(aValue.get<rtl::OUString>(), RTL_TEXTENCODING_UTF8); 124*cdf0e10cSrcweir } 125*cdf0e10cSrcweir 126*cdf0e10cSrcweir //------------------------------------------------------------------------------ 127*cdf0e10cSrcweir 128*cdf0e10cSrcweir static inline sal_Int32 129*cdf0e10cSrcweir getInt32Value(const uno::Reference< container::XNameAccess >& xNameAccess, 130*cdf0e10cSrcweir const rtl::OUString& aName, sal_Int32 nDefault=-1) 131*cdf0e10cSrcweir { 132*cdf0e10cSrcweir OSL_ASSERT(xNameAccess->hasByName(aName)); 133*cdf0e10cSrcweir uno::Any aValue = xNameAccess->getByName(aName); 134*cdf0e10cSrcweir 135*cdf0e10cSrcweir sal_Int32 n=nDefault; 136*cdf0e10cSrcweir aValue >>= n; 137*cdf0e10cSrcweir return n; 138*cdf0e10cSrcweir } 139*cdf0e10cSrcweir 140*cdf0e10cSrcweir //------------------------------------------------------------------------------ 141*cdf0e10cSrcweir 142*cdf0e10cSrcweir static size_t 143*cdf0e10cSrcweir write_function( void *ptr, size_t size, size_t nmemb, void *stream ) 144*cdf0e10cSrcweir { 145*cdf0e10cSrcweir OutData *out = reinterpret_cast < OutData * > (stream); 146*cdf0e10cSrcweir 147*cdf0e10cSrcweir if( NULL == out->FileHandle ) 148*cdf0e10cSrcweir openFile(*out); 149*cdf0e10cSrcweir 150*cdf0e10cSrcweir sal_uInt64 nBytesWritten = 0; 151*cdf0e10cSrcweir 152*cdf0e10cSrcweir if( NULL != out->FileHandle ) 153*cdf0e10cSrcweir osl_writeFile(out->FileHandle, ptr, size * nmemb, &nBytesWritten); 154*cdf0e10cSrcweir 155*cdf0e10cSrcweir return (size_t) nBytesWritten; 156*cdf0e10cSrcweir } 157*cdf0e10cSrcweir 158*cdf0e10cSrcweir //------------------------------------------------------------------------------ 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir static int 161*cdf0e10cSrcweir progress_callback( void *clientp, double dltotal, double dlnow, double ultotal, double ulnow ) 162*cdf0e10cSrcweir { 163*cdf0e10cSrcweir (void) ultotal; 164*cdf0e10cSrcweir (void) ulnow; 165*cdf0e10cSrcweir 166*cdf0e10cSrcweir OutData *out = reinterpret_cast < OutData * > (clientp); 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir OSL_ASSERT( out ); 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir if( ! out->StopCondition.check() ) 171*cdf0e10cSrcweir { 172*cdf0e10cSrcweir double fPercent = 0; 173*cdf0e10cSrcweir if ( dltotal + out->Offset ) 174*cdf0e10cSrcweir fPercent = (dlnow + out->Offset) * 100 / (dltotal + out->Offset); 175*cdf0e10cSrcweir if( fPercent < 0 ) 176*cdf0e10cSrcweir fPercent = 0; 177*cdf0e10cSrcweir 178*cdf0e10cSrcweir // Do not report progress for redirection replies 179*cdf0e10cSrcweir long nCode; 180*cdf0e10cSrcweir curl_easy_getinfo(out->curl, CURLINFO_RESPONSE_CODE, &nCode); 181*cdf0e10cSrcweir if( (nCode != 302) && (nCode != 303) && (dltotal > 0) ) 182*cdf0e10cSrcweir out->Handler->downloadProgressAt((sal_Int8)fPercent); 183*cdf0e10cSrcweir 184*cdf0e10cSrcweir return 0; 185*cdf0e10cSrcweir } 186*cdf0e10cSrcweir 187*cdf0e10cSrcweir // If stop condition is set, return non 0 value to abort 188*cdf0e10cSrcweir return -1; 189*cdf0e10cSrcweir } 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir //------------------------------------------------------------------------------ 192*cdf0e10cSrcweir 193*cdf0e10cSrcweir void 194*cdf0e10cSrcweir Download::getProxyForURL(const rtl::OUString& rURL, rtl::OString& rHost, sal_Int32& rPort) const 195*cdf0e10cSrcweir { 196*cdf0e10cSrcweir if( !m_xContext.is() ) 197*cdf0e10cSrcweir throw uno::RuntimeException( 198*cdf0e10cSrcweir UNISTRING( "Download: empty component context" ), 199*cdf0e10cSrcweir uno::Reference< uno::XInterface >() ); 200*cdf0e10cSrcweir 201*cdf0e10cSrcweir uno::Reference< lang::XMultiComponentFactory > xServiceManager(m_xContext->getServiceManager()); 202*cdf0e10cSrcweir 203*cdf0e10cSrcweir if( !xServiceManager.is() ) 204*cdf0e10cSrcweir throw uno::RuntimeException( 205*cdf0e10cSrcweir UNISTRING( "Download: unable to obtain service manager from component context" ), 206*cdf0e10cSrcweir uno::Reference< uno::XInterface >() ); 207*cdf0e10cSrcweir 208*cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xConfigProvider( 209*cdf0e10cSrcweir xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.configuration.ConfigurationProvider" ), m_xContext ), 210*cdf0e10cSrcweir uno::UNO_QUERY_THROW); 211*cdf0e10cSrcweir 212*cdf0e10cSrcweir beans::PropertyValue aProperty; 213*cdf0e10cSrcweir aProperty.Name = UNISTRING( "nodepath" ); 214*cdf0e10cSrcweir aProperty.Value = uno::makeAny( UNISTRING("org.openoffice.Inet/Settings") ); 215*cdf0e10cSrcweir 216*cdf0e10cSrcweir uno::Sequence< uno::Any > aArgumentList( 1 ); 217*cdf0e10cSrcweir aArgumentList[0] = uno::makeAny( aProperty ); 218*cdf0e10cSrcweir 219*cdf0e10cSrcweir uno::Reference< container::XNameAccess > xNameAccess( 220*cdf0e10cSrcweir xConfigProvider->createInstanceWithArguments( 221*cdf0e10cSrcweir UNISTRING("com.sun.star.configuration.ConfigurationAccess"), aArgumentList ), 222*cdf0e10cSrcweir uno::UNO_QUERY_THROW ); 223*cdf0e10cSrcweir 224*cdf0e10cSrcweir OSL_ASSERT(xNameAccess->hasByName(UNISTRING("ooInetProxyType"))); 225*cdf0e10cSrcweir uno::Any aValue = xNameAccess->getByName(UNISTRING("ooInetProxyType")); 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir sal_Int32 nProxyType = aValue.get< sal_Int32 >(); 228*cdf0e10cSrcweir if( 0 != nProxyType ) // type 0 means "direct connection to the internet 229*cdf0e10cSrcweir { 230*cdf0e10cSrcweir if( rURL.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("http:")) ) 231*cdf0e10cSrcweir { 232*cdf0e10cSrcweir rHost = getStringValue(xNameAccess, UNISTRING("ooInetHTTPProxyName")); 233*cdf0e10cSrcweir rPort = getInt32Value(xNameAccess, UNISTRING("ooInetHTTPProxyPort")); 234*cdf0e10cSrcweir } 235*cdf0e10cSrcweir else if( rURL.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("https:")) ) 236*cdf0e10cSrcweir { 237*cdf0e10cSrcweir rHost = getStringValue(xNameAccess, UNISTRING("ooInetHTTPSProxyName")); 238*cdf0e10cSrcweir rPort = getInt32Value(xNameAccess, UNISTRING("ooInetHTTPSProxyPort")); 239*cdf0e10cSrcweir } 240*cdf0e10cSrcweir else if( rURL.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("ftp:")) ) 241*cdf0e10cSrcweir { 242*cdf0e10cSrcweir rHost = getStringValue(xNameAccess, UNISTRING("ooInetFTPProxyName")); 243*cdf0e10cSrcweir rPort = getInt32Value(xNameAccess, UNISTRING("ooInetFTPProxyPort")); 244*cdf0e10cSrcweir } 245*cdf0e10cSrcweir } 246*cdf0e10cSrcweir } 247*cdf0e10cSrcweir 248*cdf0e10cSrcweir //------------------------------------------------------------------------------ 249*cdf0e10cSrcweir 250*cdf0e10cSrcweir bool curl_run(const rtl::OUString& rURL, OutData& out, const rtl::OString& aProxyHost, sal_Int32 nProxyPort) 251*cdf0e10cSrcweir { 252*cdf0e10cSrcweir /* Need to investigate further whether it is necessary to call 253*cdf0e10cSrcweir * curl_global_init or not - leave it for now (as the ftp UCB content 254*cdf0e10cSrcweir * provider does as well). 255*cdf0e10cSrcweir */ 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir CURL * pCURL = curl_easy_init(); 258*cdf0e10cSrcweir bool ret = false; 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir if( NULL != pCURL ) 261*cdf0e10cSrcweir { 262*cdf0e10cSrcweir out.curl = pCURL; 263*cdf0e10cSrcweir 264*cdf0e10cSrcweir rtl::OString aURL(rtl::OUStringToOString(rURL, RTL_TEXTENCODING_UTF8)); 265*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_URL, aURL.getStr()); 266*cdf0e10cSrcweir 267*cdf0e10cSrcweir // abort on http errors 268*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_FAILONERROR, 1); 269*cdf0e10cSrcweir 270*cdf0e10cSrcweir // enable redirection 271*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_FOLLOWLOCATION, 1); 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir // write function 274*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_WRITEDATA, &out); 275*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_WRITEFUNCTION, &write_function); 276*cdf0e10cSrcweir 277*cdf0e10cSrcweir // progress handler - Condition::check unfortunatly is not defined const 278*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_NOPROGRESS, 0); 279*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_PROGRESSFUNCTION, &progress_callback); 280*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_PROGRESSDATA, &out); 281*cdf0e10cSrcweir 282*cdf0e10cSrcweir // proxy 283*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_PROXY, aProxyHost.getStr()); 284*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); 285*cdf0e10cSrcweir if( -1 != nProxyPort ) 286*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_PROXYPORT, nProxyPort); 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir if( out.Offset > 0 ) 289*cdf0e10cSrcweir { 290*cdf0e10cSrcweir // curl_off_t offset = nOffset; libcurl seems to be compiled with large 291*cdf0e10cSrcweir // file support (and we not) .. 292*cdf0e10cSrcweir sal_Int64 offset = (sal_Int64) out.Offset; 293*cdf0e10cSrcweir curl_easy_setopt(pCURL, CURLOPT_RESUME_FROM_LARGE, offset); 294*cdf0e10cSrcweir } 295*cdf0e10cSrcweir 296*cdf0e10cSrcweir CURLcode cc = curl_easy_perform(pCURL); 297*cdf0e10cSrcweir 298*cdf0e10cSrcweir // treat zero byte downloads as errors 299*cdf0e10cSrcweir if( NULL == out.FileHandle ) 300*cdf0e10cSrcweir openFile(out); 301*cdf0e10cSrcweir 302*cdf0e10cSrcweir if( CURLE_OK == cc ) 303*cdf0e10cSrcweir { 304*cdf0e10cSrcweir out.Handler->downloadFinished(out.File); 305*cdf0e10cSrcweir ret = true; 306*cdf0e10cSrcweir } 307*cdf0e10cSrcweir 308*cdf0e10cSrcweir if ( CURLE_PARTIAL_FILE == cc ) 309*cdf0e10cSrcweir { 310*cdf0e10cSrcweir // this sometimes happens, when a user throws away his user data, but has already 311*cdf0e10cSrcweir // completed the download of an update. 312*cdf0e10cSrcweir double fDownloadSize; 313*cdf0e10cSrcweir curl_easy_getinfo( pCURL, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fDownloadSize ); 314*cdf0e10cSrcweir if ( -1 == fDownloadSize ) 315*cdf0e10cSrcweir { 316*cdf0e10cSrcweir out.Handler->downloadFinished(out.File); 317*cdf0e10cSrcweir ret = true; 318*cdf0e10cSrcweir } 319*cdf0e10cSrcweir } 320*cdf0e10cSrcweir 321*cdf0e10cSrcweir // Avoid target file being removed 322*cdf0e10cSrcweir else if( (CURLE_ABORTED_BY_CALLBACK == cc) || out.StopCondition.check() ) 323*cdf0e10cSrcweir ret = true; 324*cdf0e10cSrcweir 325*cdf0e10cSrcweir // Only report errors when not stopped 326*cdf0e10cSrcweir else 327*cdf0e10cSrcweir { 328*cdf0e10cSrcweir rtl::OString aMessage(RTL_CONSTASCII_STRINGPARAM("Unknown error")); 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir const char * error_message = curl_easy_strerror(cc); 331*cdf0e10cSrcweir if( NULL != error_message ) 332*cdf0e10cSrcweir aMessage = error_message; 333*cdf0e10cSrcweir 334*cdf0e10cSrcweir if ( CURLE_HTTP_RETURNED_ERROR == cc ) 335*cdf0e10cSrcweir { 336*cdf0e10cSrcweir long nError; 337*cdf0e10cSrcweir curl_easy_getinfo( pCURL, CURLINFO_RESPONSE_CODE, &nError ); 338*cdf0e10cSrcweir 339*cdf0e10cSrcweir if ( 403 == nError ) 340*cdf0e10cSrcweir aMessage += rtl::OString( RTL_CONSTASCII_STRINGPARAM( " 403: Access denied!" ) ); 341*cdf0e10cSrcweir else if ( 404 == nError ) 342*cdf0e10cSrcweir aMessage += rtl::OString( RTL_CONSTASCII_STRINGPARAM( " 404: File not found!" ) ); 343*cdf0e10cSrcweir else if ( 416 == nError ) 344*cdf0e10cSrcweir { 345*cdf0e10cSrcweir // we got this error probably, because we already downloaded the file 346*cdf0e10cSrcweir out.Handler->downloadFinished(out.File); 347*cdf0e10cSrcweir ret = true; 348*cdf0e10cSrcweir } 349*cdf0e10cSrcweir else 350*cdf0e10cSrcweir { 351*cdf0e10cSrcweir aMessage += rtl::OString( RTL_CONSTASCII_STRINGPARAM( ":error code = " ) ); 352*cdf0e10cSrcweir aMessage += aMessage.valueOf( nError ); 353*cdf0e10cSrcweir aMessage += rtl::OString( RTL_CONSTASCII_STRINGPARAM( " !" ) ); 354*cdf0e10cSrcweir } 355*cdf0e10cSrcweir } 356*cdf0e10cSrcweir if ( !ret ) 357*cdf0e10cSrcweir out.Handler->downloadStalled( rtl::OStringToOUString(aMessage, RTL_TEXTENCODING_UTF8) ); 358*cdf0e10cSrcweir } 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir curl_easy_cleanup(pCURL); 361*cdf0e10cSrcweir } 362*cdf0e10cSrcweir 363*cdf0e10cSrcweir return ret; 364*cdf0e10cSrcweir } 365*cdf0e10cSrcweir 366*cdf0e10cSrcweir //------------------------------------------------------------------------------ 367*cdf0e10cSrcweir 368*cdf0e10cSrcweir bool 369*cdf0e10cSrcweir Download::start(const rtl::OUString& rURL, const rtl::OUString& rFile, const rtl::OUString& rDestinationDir) 370*cdf0e10cSrcweir { 371*cdf0e10cSrcweir OSL_ASSERT( m_aHandler.is() ); 372*cdf0e10cSrcweir 373*cdf0e10cSrcweir OutData out(m_aCondition); 374*cdf0e10cSrcweir rtl::OUString aFile( rFile ); 375*cdf0e10cSrcweir 376*cdf0e10cSrcweir // when rFile is empty, there is no remembered file name. If there is already a file with the 377*cdf0e10cSrcweir // same name ask the user if she wants to resume a download or restart the download 378*cdf0e10cSrcweir if ( !aFile.getLength() ) 379*cdf0e10cSrcweir { 380*cdf0e10cSrcweir // GetFileName() 381*cdf0e10cSrcweir rtl::OUString aURL( rURL ); 382*cdf0e10cSrcweir // ensure no trailing '/' 383*cdf0e10cSrcweir sal_Int32 nLen = aURL.getLength(); 384*cdf0e10cSrcweir while( (nLen > 0) && ('/' == aURL[ nLen-1 ]) ) 385*cdf0e10cSrcweir aURL = aURL.copy( 0, --nLen ); 386*cdf0e10cSrcweir 387*cdf0e10cSrcweir // extract file name last '/' 388*cdf0e10cSrcweir sal_Int32 nIndex = aURL.lastIndexOf('/'); 389*cdf0e10cSrcweir aFile = rDestinationDir + aURL.copy( nIndex ); 390*cdf0e10cSrcweir 391*cdf0e10cSrcweir // check for existing file 392*cdf0e10cSrcweir oslFileError rc = osl_openFile( aFile.pData, &out.FileHandle, osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); 393*cdf0e10cSrcweir osl_closeFile(out.FileHandle); 394*cdf0e10cSrcweir out.FileHandle = NULL; 395*cdf0e10cSrcweir 396*cdf0e10cSrcweir if( osl_File_E_EXIST == rc ) 397*cdf0e10cSrcweir { 398*cdf0e10cSrcweir if ( m_aHandler->checkDownloadDestination( aURL.copy( nIndex+1 ) ) ) 399*cdf0e10cSrcweir { 400*cdf0e10cSrcweir osl_removeFile( aFile.pData ); 401*cdf0e10cSrcweir aFile = rtl::OUString(); 402*cdf0e10cSrcweir } 403*cdf0e10cSrcweir else 404*cdf0e10cSrcweir m_aHandler->downloadStarted( aFile, 0 ); 405*cdf0e10cSrcweir } 406*cdf0e10cSrcweir else 407*cdf0e10cSrcweir { 408*cdf0e10cSrcweir osl_removeFile( aFile.pData ); 409*cdf0e10cSrcweir aFile = rtl::OUString(); 410*cdf0e10cSrcweir } 411*cdf0e10cSrcweir } 412*cdf0e10cSrcweir 413*cdf0e10cSrcweir out.File = aFile; 414*cdf0e10cSrcweir out.DestinationDir = rDestinationDir; 415*cdf0e10cSrcweir out.Handler = m_aHandler; 416*cdf0e10cSrcweir 417*cdf0e10cSrcweir if( aFile.getLength() > 0 ) 418*cdf0e10cSrcweir { 419*cdf0e10cSrcweir oslFileError rc = osl_openFile(aFile.pData, &out.FileHandle, osl_File_OpenFlag_Write); 420*cdf0e10cSrcweir 421*cdf0e10cSrcweir if( osl_File_E_None == rc ) 422*cdf0e10cSrcweir { 423*cdf0e10cSrcweir // Set file pointer to the end of the file on resume 424*cdf0e10cSrcweir if( osl_File_E_None == osl_setFilePos(out.FileHandle, osl_Pos_End, 0) ) 425*cdf0e10cSrcweir { 426*cdf0e10cSrcweir osl_getFilePos(out.FileHandle, &out.Offset); 427*cdf0e10cSrcweir } 428*cdf0e10cSrcweir } 429*cdf0e10cSrcweir else if( osl_File_E_NOENT == rc ) // file has been deleted meanwhile .. 430*cdf0e10cSrcweir out.File = rtl::OUString(); 431*cdf0e10cSrcweir } 432*cdf0e10cSrcweir 433*cdf0e10cSrcweir rtl::OString aProxyHost; 434*cdf0e10cSrcweir sal_Int32 nProxyPort = -1; 435*cdf0e10cSrcweir getProxyForURL(rURL, aProxyHost, nProxyPort); 436*cdf0e10cSrcweir 437*cdf0e10cSrcweir bool ret = curl_run(rURL, out, aProxyHost, nProxyPort); 438*cdf0e10cSrcweir 439*cdf0e10cSrcweir if( NULL != out.FileHandle ) 440*cdf0e10cSrcweir { 441*cdf0e10cSrcweir osl_syncFile(out.FileHandle); 442*cdf0e10cSrcweir osl_closeFile(out.FileHandle); 443*cdf0e10cSrcweir 444*cdf0e10cSrcweir // #i90930# Don't remove already downloaded bits, when curl_run reports an error 445*cdf0e10cSrcweir // because later calls might be successful 446*cdf0e10cSrcweir // if( ! ret ) 447*cdf0e10cSrcweir // osl_removeFile(out.File.pData); 448*cdf0e10cSrcweir } 449*cdf0e10cSrcweir 450*cdf0e10cSrcweir m_aCondition.reset(); 451*cdf0e10cSrcweir return ret; 452*cdf0e10cSrcweir } 453*cdf0e10cSrcweir 454*cdf0e10cSrcweir //------------------------------------------------------------------------------ 455*cdf0e10cSrcweir 456*cdf0e10cSrcweir void 457*cdf0e10cSrcweir Download::stop() 458*cdf0e10cSrcweir { 459*cdf0e10cSrcweir m_aCondition.set(); 460*cdf0e10cSrcweir } 461