Update ooo320-m1
[ooovba.git] / extensions / source / update / feed / updatefeed.cxx
blobe0182745d49e62865bad35b6b5b2fa5a77901c1a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: updatefeed.cxx,v $
10 * $Revision: 1.11.52.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
34 #include <cppuhelper/implbase1.hxx>
35 #include <cppuhelper/implbase5.hxx>
36 #include <cppuhelper/implementationentry.hxx>
37 #include <com/sun/star/beans/Property.hpp>
38 #include <com/sun/star/beans/XPropertySetInfo.hpp>
39 #include <com/sun/star/beans/PropertyValue.hpp>
40 #include <com/sun/star/container/XNameAccess.hpp>
41 #include <com/sun/star/deployment/UpdateInformationEntry.hpp>
42 #include <com/sun/star/deployment/UpdateInformationProvider.hpp>
43 #include <com/sun/star/io/XActiveDataSink.hpp>
44 #include <com/sun/star/io/XInputStream.hpp>
45 #include <com/sun/star/lang/XComponent.hpp>
46 #include <com/sun/star/lang/XServiceInfo.hpp>
47 #include <com/sun/star/task/XPasswordContainer.hpp>
48 #include "com/sun/star/task/NoMasterException.hpp"
49 #include "com/sun/star/ucb/AuthenticationRequest.hpp"
50 #ifndef _COM_SUN_STAR_UCB_XCOMMMANDENVIRONMENT_HPP_
51 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
52 #endif
53 #ifndef _COM_SUN_STAR_UCB_XWEBDAVCOMMMANDENVIRONMENT_HPP_
54 #include <com/sun/star/ucb/XWebDAVCommandEnvironment.hpp>
55 #endif
56 #ifndef _COM_SUN_STAR_UCB_XCOMMMANDPROCESSOR2_HPP_
57 #include <com/sun/star/ucb/XCommandProcessor2.hpp>
58 #endif
59 #ifndef _COM_SUN_STAR_UCB_XCONTENTIDNETIFIERFACTORY_HPP_
60 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
61 #endif
62 #include <com/sun/star/ucb/XContentProvider.hpp>
63 #include "com/sun/star/ucb/XInteractionSupplyAuthentication.hpp"
64 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
65 #include <com/sun/star/ucb/OpenMode.hpp>
66 #include <com/sun/star/sdbc/XRow.hpp>
67 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
68 #include <com/sun/star/xml/xpath/XXPathAPI.hpp>
70 #include <rtl/ref.hxx>
71 #include <rtl/memory.h>
72 #include <rtl/bootstrap.hxx>
73 #include <rtl/ustrbuf.hxx>
74 #include <osl/process.h>
75 #include <osl/conditn.hxx>
77 #ifndef _ZLIB_H
78 #ifdef SYSTEM_ZLIB
79 #include "zlib.h"
80 #else
81 #include "zlib/zlib.h"
82 #endif
83 #endif
85 namespace beans = com::sun::star::beans ;
86 namespace container = com::sun::star::container ;
87 namespace deployment = com::sun::star::deployment ;
88 namespace io = com::sun::star::io ;
89 namespace lang = com::sun::star::lang ;
90 namespace task = com::sun::star::task ;
91 namespace ucb = com::sun::star::ucb ;
92 namespace uno = com::sun::star::uno ;
93 namespace xml = com::sun::star::xml ;
94 namespace sdbc = com::sun::star::sdbc ;
96 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
98 //------------------------------------------------------------------------------
100 namespace
103 #ifdef DEBUG
105 class InputStreamWrapper : public ::cppu::WeakImplHelper1< io::XInputStream >
107 uno::Reference< io::XInputStream > m_xStream;
109 public:
110 InputStreamWrapper(const uno::Reference< io::XInputStream >& rxStream) :
111 m_xStream(rxStream) {};
113 virtual sal_Int32 SAL_CALL readBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
114 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
116 sal_Int32 n = m_xStream->readBytes(aData, nBytesToRead);
117 OSL_TRACE( aData.get()->elements );
118 return n;
120 virtual sal_Int32 SAL_CALL readSomeBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
121 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
123 sal_Int32 n = m_xStream->readSomeBytes(aData, nMaxBytesToRead);
124 OSL_TRACE( aData.get()->elements );
125 return n;
127 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
128 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
129 { m_xStream->skipBytes(nBytesToSkip); };
130 virtual sal_Int32 SAL_CALL available()
131 throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
132 { return m_xStream->available(); };
133 virtual void SAL_CALL closeInput( )
134 throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
138 #define INPUT_STREAM(i) new InputStreamWrapper(i)
139 #else
140 #define INPUT_STREAM(i) i
141 #endif
143 //------------------------------------------------------------------------------
145 class ActiveDataSink : public ::cppu::WeakImplHelper1< io::XActiveDataSink >
147 uno::Reference< io::XInputStream > m_xStream;
149 public:
150 ActiveDataSink() {};
152 inline operator uno::Reference< io::XActiveDataSink > () { return this; };
154 virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream()
155 throw (uno::RuntimeException) { return m_xStream; };
156 virtual void SAL_CALL setInputStream( uno::Reference< io::XInputStream > const & rStream )
157 throw (uno::RuntimeException) { m_xStream = rStream; };
160 //------------------------------------------------------------------------------
162 class InflateInputStream : public ::cppu::WeakImplHelper1< io::XInputStream >
164 uno::Reference< io::XInputStream > m_xStream;
166 uno::Sequence < sal_Int8 > m_aBuffer;
167 sal_Int32 m_nOffset;
168 bool m_bRead;
170 rtl::OUString m_aContentEncoding;
172 void readIntoMemory();
174 public:
175 InflateInputStream(const uno::Reference< io::XInputStream >& rxStream,const rtl::OUString& rContentEncoding) :
176 m_xStream(rxStream), m_nOffset(0), m_bRead(false), m_aContentEncoding(rContentEncoding) {};
178 virtual sal_Int32 SAL_CALL readBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
179 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException);
180 virtual sal_Int32 SAL_CALL readSomeBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
181 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
182 { readIntoMemory(); return readBytes(aData, nMaxBytesToRead ); };
183 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
184 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
186 readIntoMemory();
187 if( m_nOffset + nBytesToSkip < m_aBuffer.getLength() )
188 m_nOffset += nBytesToSkip;
189 else
190 m_nOffset = m_aBuffer.getLength();
192 virtual sal_Int32 SAL_CALL available()
193 throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
194 { readIntoMemory(); return m_aBuffer.getLength() - m_nOffset; };
195 virtual void SAL_CALL closeInput( )
196 throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
197 { m_xStream->closeInput(); };
201 sal_Int32 SAL_CALL
202 InflateInputStream::readBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
203 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
205 readIntoMemory();
206 sal_Int32 nAvailable = available();
207 sal_Int32 nBytesToCopy = nAvailable < nBytesToRead ? nAvailable : nBytesToRead;
208 if( nBytesToCopy > 0 )
210 aData.realloc(nBytesToCopy);
211 rtl_copyMemory(aData.getArray(), m_aBuffer.getConstArray() + m_nOffset, nBytesToCopy);
212 m_nOffset += nBytesToCopy;
215 return nBytesToCopy;
218 void InflateInputStream::readIntoMemory()
220 if( !m_bRead && m_xStream.is() )
222 const sal_Int32 nBytesRequested = 4096;
224 uno::Sequence < sal_Int8 > aTempBuffer(nBytesRequested);
225 uno::Sequence < sal_Int8 > aCompressedBuffer;
226 sal_Int32 nBytesRead;
228 m_bRead = true;
232 nBytesRead = m_xStream->readBytes(aTempBuffer, nBytesRequested);
234 if( nBytesRead > 0 )
236 sal_Int32 nOffset = aCompressedBuffer.getLength();
237 aCompressedBuffer.realloc( nOffset + nBytesRead );
239 rtl_copyMemory(aCompressedBuffer.getArray() + nOffset, aTempBuffer.getConstArray(), nBytesRead);
242 while( nBytesRead == nBytesRequested );
244 z_stream *pStream = new z_stream;
245 /* memset to 0 to set zalloc/opaque etc */
246 rtl_zeroMemory (pStream, sizeof(*pStream));
248 int windowSize = 15;
249 int headerOffset = 0;
251 if( m_aContentEncoding.equalsAscii("gzip") )
253 sal_uInt8 magic[2];
254 magic[0] = *((sal_uInt8 *) aCompressedBuffer.getConstArray());
255 magic[1] = *((sal_uInt8 *) aCompressedBuffer.getConstArray() + 1);
257 if( (magic[0] == 0x1f) && (magic[1] == 0x8b) )
259 windowSize = -14;
260 headerOffset = 10;
264 pStream->next_in = (unsigned char *) aCompressedBuffer.getConstArray();
265 pStream->avail_in = aCompressedBuffer.getLength();
267 pStream->next_in += headerOffset;
268 pStream->avail_in -= headerOffset;
270 if( Z_OK == inflateInit2(pStream, windowSize) )
272 int result;
276 sal_Int32 nOffset = m_aBuffer.getLength();
277 m_aBuffer.realloc(nOffset + 4096);
279 pStream->next_out = reinterpret_cast < unsigned char* > ( m_aBuffer.getArray() + nOffset );
280 pStream->avail_out = 4096;
282 result = ::inflate(pStream, Z_FINISH);
284 if( result == Z_STREAM_END )
285 break;
287 } while( result == Z_BUF_ERROR );
289 inflateEnd(pStream);
290 m_aBuffer.realloc(pStream->total_out);
294 if (pStream != NULL)
296 delete pStream;
297 pStream = NULL;
302 //------------------------------------------------------------------------------
304 class UpdateInformationProvider :
305 public ::cppu::WeakImplHelper5< deployment::XUpdateInformationProvider,
306 ucb::XCommandEnvironment,
307 ucb::XWebDAVCommandEnvironment,
308 lang::XServiceInfo,
309 task::XInteractionHandler >
311 public:
312 static uno::Reference< uno::XInterface > createInstance(const uno::Reference<uno::XComponentContext>& xContext);
314 static uno::Sequence< rtl::OUString > getServiceNames();
315 static rtl::OUString getImplName();
317 uno::Reference< xml::dom::XElement > getDocumentRoot(const uno::Reference< xml::dom::XNode >& rxNode);
318 uno::Reference< xml::dom::XNode > getChildNode(const uno::Reference< xml::dom::XNode >& rxNode, const rtl::OUString& rName);
321 // XUpdateInformationService
322 virtual uno::Sequence< uno::Reference< xml::dom::XElement > > SAL_CALL
323 getUpdateInformation(
324 uno::Sequence< rtl::OUString > const & repositories,
325 rtl::OUString const & extensionId
326 ) throw (uno::Exception, uno::RuntimeException);
328 virtual void SAL_CALL cancel()
329 throw (uno::RuntimeException);
331 virtual void SAL_CALL setInteractionHandler(
332 uno::Reference< task::XInteractionHandler > const & handler )
333 throw (uno::RuntimeException);
335 virtual uno::Reference< container::XEnumeration > SAL_CALL
336 getUpdateInformationEnumeration(
337 uno::Sequence< rtl::OUString > const & repositories,
338 rtl::OUString const & extensionId
339 ) throw (uno::Exception, uno::RuntimeException);
341 // XCommandEnvironment
342 virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler()
343 throw ( uno::RuntimeException );
345 virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler()
346 throw ( uno::RuntimeException ) { return uno::Reference< ucb::XProgressHandler >(); };
348 // XWebDAVCommandEnvironment
349 virtual uno::Sequence< beans::NamedValue > SAL_CALL getUserRequestHeaders(
350 const rtl::OUString&, const rtl::OUString& )
351 throw ( uno::RuntimeException ) { return m_aRequestHeaderList; };
353 // XServiceInfo
354 virtual rtl::OUString SAL_CALL getImplementationName()
355 throw (uno::RuntimeException);
356 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
357 throw (uno::RuntimeException);
358 virtual uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames()
359 throw (uno::RuntimeException);
361 // XInteractionHandler
362 virtual void SAL_CALL handle( const uno::Reference< task::XInteractionRequest >& rRequest )
363 throw( uno::RuntimeException );
365 protected:
367 virtual ~UpdateInformationProvider();
368 static uno::Any getConfigurationItem(uno::Reference<lang::XMultiServiceFactory> const & configurationProvider, rtl::OUString const & node, rtl::OUString const & item);
370 private:
371 uno::Reference< io::XInputStream > load(const rtl::OUString& rURL);
373 void storeCommandInfo( sal_Int32 nCommandId,
374 uno::Reference< ucb::XCommandProcessor > const & rxCommandProcessor);
376 bool initPasswordContainer( uno::Reference< task::XPasswordContainer > * pContainer );
378 UpdateInformationProvider(const uno::Reference<uno::XComponentContext>& xContext,
379 const uno::Reference< ucb::XContentIdentifierFactory >& xContentIdFactory,
380 const uno::Reference< ucb::XContentProvider >& xContentProvider,
381 const uno::Reference< xml::dom::XDocumentBuilder >& xDocumentBuilder,
382 const uno::Reference< xml::xpath::XXPathAPI >& xXPathAPI);
384 const uno::Reference< uno::XComponentContext> m_xContext;
386 const uno::Reference< ucb::XContentIdentifierFactory > m_xContentIdFactory;
387 const uno::Reference< ucb::XContentProvider > m_xContentProvider;
388 const uno::Reference< xml::dom::XDocumentBuilder > m_xDocumentBuilder;
389 const uno::Reference< xml::xpath::XXPathAPI > m_xXPathAPI;
391 uno::Sequence< beans::NamedValue > m_aRequestHeaderList;
393 uno::Reference< ucb::XCommandProcessor > m_xCommandProcessor;
394 uno::Reference< task::XInteractionHandler > m_xInteractionHandler;
396 osl::Mutex m_aMutex;
397 osl::Condition m_bCancelled;
399 sal_Int32 m_nCommandId;
402 //------------------------------------------------------------------------------
404 class UpdateInformationEnumeration : public ::cppu::WeakImplHelper1< container::XEnumeration >
406 public:
407 UpdateInformationEnumeration(const uno::Reference< xml::dom::XNodeList >& xNodeList,
408 const uno::Reference< UpdateInformationProvider > xUpdateInformationProvider) :
409 m_xUpdateInformationProvider(xUpdateInformationProvider),
410 m_xNodeList(xNodeList),
411 m_nNodes(xNodeList.is() ? xNodeList->getLength() : 0),
412 m_nCount(0)
416 virtual ~UpdateInformationEnumeration() {};
418 // XEnumeration
419 sal_Bool SAL_CALL hasMoreElements() throw (uno::RuntimeException) { return m_nCount < m_nNodes; };
420 uno::Any SAL_CALL nextElement() throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
422 OSL_ASSERT( m_xNodeList.is() );
423 OSL_ASSERT( m_xUpdateInformationProvider.is() );
425 if( !(m_nCount < m_nNodes ) )
426 throw container::NoSuchElementException(rtl::OUString::valueOf(m_nCount), *this);
430 deployment::UpdateInformationEntry aEntry;
432 uno::Reference< xml::dom::XNode > xAtomEntryNode( m_xNodeList->item(m_nCount++) );
434 uno::Reference< xml::dom::XNode > xSummaryNode(
435 m_xUpdateInformationProvider->getChildNode( xAtomEntryNode, UNISTRING( "summary/text()" ) )
438 if( xSummaryNode.is() )
439 aEntry.Description = xSummaryNode->getNodeValue();
441 uno::Reference< xml::dom::XNode > xContentNode(
442 m_xUpdateInformationProvider->getChildNode( xAtomEntryNode, UNISTRING( "content" ) ) );
444 if( xContentNode.is() )
445 aEntry.UpdateDocument = m_xUpdateInformationProvider->getDocumentRoot(xContentNode);
447 return uno::makeAny(aEntry);
450 // action has been aborted
451 catch( ucb::CommandAbortedException const & e)
452 { throw lang::WrappedTargetException( UNISTRING( "Command aborted" ), *this, uno::makeAny(e) ); }
454 // let runtime exception pass
455 catch( uno::RuntimeException const & ) { throw; }
457 // document not accessible
458 catch( uno::Exception const & e)
459 { throw lang::WrappedTargetException( UNISTRING( "Document not accessible" ), *this, uno::makeAny(e) ); }
462 private:
463 const uno::Reference< UpdateInformationProvider > m_xUpdateInformationProvider;
464 const uno::Reference< xml::dom::XNodeList > m_xNodeList;
465 const sal_Int32 m_nNodes;
466 sal_Int32 m_nCount;
469 //------------------------------------------------------------------------------
471 class SingleUpdateInformationEnumeration : public ::cppu::WeakImplHelper1< container::XEnumeration >
473 public:
474 SingleUpdateInformationEnumeration(const uno::Reference< xml::dom::XElement >& xElement)
475 : m_nCount(0) { m_aEntry.UpdateDocument = xElement; };
476 virtual ~SingleUpdateInformationEnumeration() {};
478 // XEnumeration
479 sal_Bool SAL_CALL hasMoreElements() throw (uno::RuntimeException) { return 0 == m_nCount; };
480 uno::Any SAL_CALL nextElement() throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
482 if( m_nCount > 0 )
483 throw container::NoSuchElementException(rtl::OUString::valueOf(m_nCount), *this);
485 ++m_nCount;
486 return uno::makeAny(m_aEntry);
489 private:
490 sal_uInt8 m_nCount;
491 deployment::UpdateInformationEntry m_aEntry;
495 //------------------------------------------------------------------------------
497 UpdateInformationProvider::UpdateInformationProvider(
498 const uno::Reference<uno::XComponentContext>& xContext,
499 const uno::Reference< ucb::XContentIdentifierFactory >& xContentIdFactory,
500 const uno::Reference< ucb::XContentProvider >& xContentProvider,
501 const uno::Reference< xml::dom::XDocumentBuilder >& xDocumentBuilder,
502 const uno::Reference< xml::xpath::XXPathAPI >& xXPathAPI
503 ) : m_xContext(xContext), m_xContentIdFactory(xContentIdFactory),
504 m_xContentProvider(xContentProvider), m_xDocumentBuilder(xDocumentBuilder),
505 m_xXPathAPI(xXPathAPI), m_aRequestHeaderList(2)
507 uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
508 if( !xServiceManager.is() )
509 throw uno::RuntimeException(
510 UNISTRING("unable to obtain service manager from component context"),
511 uno::Reference< uno::XInterface >());
513 uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider(
514 xServiceManager->createInstanceWithContext(
515 UNISTRING("com.sun.star.configuration.ConfigurationProvider"),
516 xContext ),
517 uno::UNO_QUERY_THROW);
519 rtl::OUStringBuffer buf;
520 rtl::OUString name;
521 getConfigurationItem(
522 xConfigurationProvider,
523 UNISTRING("org.openoffice.Setup/Product"),
524 UNISTRING("ooName")) >>= name;
525 buf.append(name);
526 buf.append(sal_Unicode(' '));
527 rtl::OUString version;
528 getConfigurationItem(
529 xConfigurationProvider,
530 UNISTRING("org.openoffice.Setup/Product"),
531 UNISTRING("ooSetupVersion")) >>= version;
532 buf.append(version);
533 rtl::OUString edition(
534 UNISTRING(
535 "${${BRAND_BASE_DIR}/program/edition/edition.ini:"
536 "EDITIONNAME}"));
537 rtl::Bootstrap::expandMacros(edition);
538 if (edition.getLength() != 0) {
539 buf.append(sal_Unicode(' '));
540 buf.append(edition);
542 rtl::OUString extension;
543 getConfigurationItem(
544 xConfigurationProvider,
545 UNISTRING("org.openoffice.Setup/Product"),
546 UNISTRING("ooSetupExtension")) >>= extension;
547 if (extension.getLength() != 0) {
548 buf.append(sal_Unicode(' '));
549 buf.append(extension);
551 rtl::OUString product(buf.makeStringAndClear());
553 rtl::OUString aBaseBuildId( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
554 rtl::Bootstrap::expandMacros( aBaseBuildId );
556 rtl::OUString aBrandBuildId( UNISTRING( "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
557 rtl::Bootstrap::expandMacros( aBrandBuildId );
559 rtl::OUString aUserAgent( UNISTRING( "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") ":UpdateUserAgent}" ) );
560 rtl::Bootstrap::expandMacros( aUserAgent );
562 if ( ! aBaseBuildId.equals( aBrandBuildId ) )
564 sal_Int32 nIndex = aUserAgent.indexOf( aBrandBuildId, 0 );
565 if ( nIndex != -1 )
566 aUserAgent = aUserAgent.replaceAt( nIndex, aBrandBuildId.getLength(), aBaseBuildId );
569 for (sal_Int32 i = 0;;) {
570 i = aUserAgent.indexOfAsciiL(
571 RTL_CONSTASCII_STRINGPARAM("<PRODUCT>"), i);
572 if (i == -1) {
573 break;
575 aUserAgent = aUserAgent.replaceAt(
576 i, RTL_CONSTASCII_LENGTH("<PRODUCT>"), product);
577 i += product.getLength();
580 m_aRequestHeaderList[0].Name = UNISTRING("Accept-Language");
581 m_aRequestHeaderList[0].Value = getConfigurationItem( xConfigurationProvider, UNISTRING("org.openoffice.Setup/L10N"), UNISTRING("ooLocale") );
582 m_aRequestHeaderList[1].Name = UNISTRING("Accept-Encoding");
583 m_aRequestHeaderList[1].Value = uno::makeAny( UNISTRING("gzip,deflate") );
585 if( aUserAgent.getLength() > 0 )
587 m_aRequestHeaderList.realloc(3);
588 m_aRequestHeaderList[2].Name = UNISTRING("User-Agent");
589 m_aRequestHeaderList[2].Value = uno::makeAny(aUserAgent);
593 //------------------------------------------------------------------------------
594 uno::Reference< uno::XInterface >
595 UpdateInformationProvider::createInstance(const uno::Reference<uno::XComponentContext>& xContext)
597 uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
598 if( !xServiceManager.is() )
599 throw uno::RuntimeException(
600 UNISTRING( "unable to obtain service manager from component context" ),
601 uno::Reference< uno::XInterface > ());
603 uno::Reference< ucb::XContentIdentifierFactory > xContentIdFactory(
604 xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.ucb.UniversalContentBroker" ), xContext ),
605 uno::UNO_QUERY_THROW);
607 uno::Reference< ucb::XContentProvider > xContentProvider(xContentIdFactory, uno::UNO_QUERY_THROW);
609 uno::Reference< xml::dom::XDocumentBuilder > xDocumentBuilder(
610 xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.xml.dom.DocumentBuilder" ), xContext ),
611 uno::UNO_QUERY_THROW);
613 uno::Reference< xml::xpath::XXPathAPI > xXPath(
614 xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.xml.xpath.XPathAPI" ), xContext ),
615 uno::UNO_QUERY_THROW);
617 xXPath->registerNS( UNISTRING("atom"), UNISTRING("http://www.w3.org/2005/Atom") );
619 return *new UpdateInformationProvider(xContext, xContentIdFactory, xContentProvider, xDocumentBuilder, xXPath);
622 //------------------------------------------------------------------------------
624 UpdateInformationProvider::~UpdateInformationProvider()
628 //------------------------------------------------------------------------------
630 uno::Any
631 UpdateInformationProvider::getConfigurationItem(uno::Reference<lang::XMultiServiceFactory> const & configurationProvider, rtl::OUString const & node, rtl::OUString const & item)
633 beans::PropertyValue aProperty;
634 aProperty.Name = UNISTRING("nodepath");
635 aProperty.Value = uno::makeAny(node);
637 uno::Sequence< uno::Any > aArgumentList( 1 );
638 aArgumentList[0] = uno::makeAny( aProperty );
640 uno::Reference< container::XNameAccess > xNameAccess(
641 configurationProvider->createInstanceWithArguments(
642 UNISTRING("com.sun.star.configuration.ConfigurationAccess"),
643 aArgumentList ),
644 uno::UNO_QUERY_THROW);
646 return xNameAccess->getByName(item);
649 //------------------------------------------------------------------------------
651 void
652 UpdateInformationProvider::storeCommandInfo(
653 sal_Int32 nCommandId,
654 uno::Reference< ucb::XCommandProcessor > const & rxCommandProcessor)
656 osl::MutexGuard aGuard(m_aMutex);
658 m_nCommandId = nCommandId;
659 m_xCommandProcessor = rxCommandProcessor;
662 //------------------------------------------------------------------------------
664 bool UpdateInformationProvider::initPasswordContainer( uno::Reference< task::XPasswordContainer > * pContainer )
666 OSL_ENSURE( pContainer, "specification violation" );
668 if ( !pContainer->is() )
670 uno::Reference<uno::XComponentContext> xContext(m_xContext);
672 if( !xContext.is() )
673 throw uno::RuntimeException( UNISTRING( "UpdateInformationProvider: empty component context" ), *this );
675 uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
677 if( !xServiceManager.is() )
678 throw uno::RuntimeException( UNISTRING( "UpdateInformationProvider: unable to obtain service manager from component context" ), *this );
680 *pContainer = uno::Reference< task::XPasswordContainer >(
681 xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.task.PasswordContainer" ), xContext ),
682 uno::UNO_QUERY);
685 OSL_ENSURE(pContainer->is(), "unexpected situation");
686 return pContainer->is();
689 //------------------------------------------------------------------------------
691 uno::Reference< io::XInputStream >
692 UpdateInformationProvider::load(const rtl::OUString& rURL)
694 uno::Reference< ucb::XContentIdentifier > xId = m_xContentIdFactory->createContentIdentifier(rURL);
696 if( !xId.is() )
697 throw uno::RuntimeException(
698 UNISTRING( "unable to obtain universal content id" ), *this);
700 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(m_xContentProvider->queryContent(xId), uno::UNO_QUERY_THROW);
701 rtl::Reference< ActiveDataSink > aSink(new ActiveDataSink());
703 ucb::OpenCommandArgument2 aOpenArgument;
704 aOpenArgument.Mode = ucb::OpenMode::DOCUMENT;
705 aOpenArgument.Priority = 32768;
706 aOpenArgument.Sink = *aSink;
708 ucb::Command aCommand;
709 aCommand.Name = UNISTRING("open");
710 aCommand.Argument = uno::makeAny(aOpenArgument);
712 sal_Int32 nCommandId = xCommandProcessor->createCommandIdentifier();
714 storeCommandInfo(nCommandId, xCommandProcessor);
717 uno::Any aResult = xCommandProcessor->execute(aCommand, nCommandId,
718 static_cast < XCommandEnvironment *> (this));
720 catch( const uno::Exception & /* e */ )
722 storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ());
724 uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY);
725 if( xCommandProcessor2.is() )
726 xCommandProcessor2->releaseCommandIdentifier(nCommandId);
728 throw;
731 uno::Sequence< beans::Property > aProps( 1 );
732 aProps[0].Name = UNISTRING( "Content-Encoding" );
734 aCommand.Name = UNISTRING("getPropertyValues");
735 aCommand.Argument = uno::makeAny( aProps );
737 sal_Bool bCompressed = sal_False;
738 rtl::OUString aContentEncoding;
742 uno::Any aResult = xCommandProcessor->execute(aCommand, 0,
743 static_cast < XCommandEnvironment *> (this));
744 uno::Reference< sdbc::XRow > xPropList( aResult, uno::UNO_QUERY );
745 if ( xPropList.is() ) {
746 aContentEncoding = xPropList->getString(1);
747 if( aContentEncoding.equalsAscii("gzip") || aContentEncoding.equalsAscii("deflate"))
748 bCompressed = sal_True;
751 catch( const uno::Exception &e )
753 OSL_TRACE( "Caught exception: %s\n",
754 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr() );
757 storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ());
759 uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY);
760 if( xCommandProcessor2.is() )
761 xCommandProcessor2->releaseCommandIdentifier(nCommandId);
763 if ( bCompressed )
764 return INPUT_STREAM( new InflateInputStream( aSink->getInputStream(), aContentEncoding ) );
765 else
766 return INPUT_STREAM(aSink->getInputStream());
769 //------------------------------------------------------------------------------
771 // TODO: docu content node
773 uno::Reference< xml::dom::XElement >
774 UpdateInformationProvider::getDocumentRoot(const uno::Reference< xml::dom::XNode >& rxNode)
776 OSL_ASSERT(m_xDocumentBuilder.is());
778 uno::Reference< xml::dom::XElement > xElement(rxNode, uno::UNO_QUERY_THROW);
780 // load the document referenced in 'src' attribute ..
781 if( xElement->hasAttribute( UNISTRING("src") ) )
783 uno::Reference< xml::dom::XDocument > xUpdateXML =
784 m_xDocumentBuilder->parse(load(xElement->getAttribute( UNISTRING("src") )));
786 OSL_ASSERT( xUpdateXML.is() );
788 if( xUpdateXML.is() )
789 return xUpdateXML->getDocumentElement();
791 // .. or return the (single) child element
792 else
794 uno::Reference< xml::dom::XNodeList> xChildNodes = rxNode->getChildNodes();
796 // ignore possible #text nodes
797 sal_Int32 nmax = xChildNodes->getLength();
798 for(sal_Int32 n=0; n < nmax; n++)
800 uno::Reference< xml::dom::XElement > xChildElement(xChildNodes->item(n), uno::UNO_QUERY);
801 if( xChildElement.is() )
803 /* Copy the content to a dedicated document since XXPathAPI->selectNodeList
804 * seems to evaluate expression always relative to the root node.
806 uno::Reference< xml::dom::XDocument > xUpdateXML = m_xDocumentBuilder->newDocument();
807 xUpdateXML->appendChild( xUpdateXML->importNode(xChildElement.get(), sal_True ) );
808 return xUpdateXML->getDocumentElement();
813 return uno::Reference< xml::dom::XElement > ();
816 //------------------------------------------------------------------------------
818 uno::Reference< xml::dom::XNode >
819 UpdateInformationProvider::getChildNode(const uno::Reference< xml::dom::XNode >& rxNode,
820 const rtl::OUString& rName)
822 OSL_ASSERT(m_xXPathAPI.is());
823 try {
824 return m_xXPathAPI->selectSingleNode(rxNode, UNISTRING( "./atom:" ) + rName);
825 } catch (xml::xpath::XPathException &) {
826 // ignore
827 return 0;
831 //------------------------------------------------------------------------------
833 uno::Reference< container::XEnumeration > SAL_CALL
834 UpdateInformationProvider::getUpdateInformationEnumeration(
835 uno::Sequence< rtl::OUString > const & repositories,
836 rtl::OUString const & extensionId
837 ) throw (uno::Exception, uno::RuntimeException)
839 OSL_ASSERT(m_xDocumentBuilder.is());
841 // reset cancelled flag
842 m_bCancelled.reset();
844 for(sal_Int32 n=0; n<repositories.getLength(); n++)
848 uno::Reference< xml::dom::XDocument > xDocument = m_xDocumentBuilder->parse(load(repositories[n]));
849 uno::Reference< xml::dom::XElement > xElement;
851 if( xDocument.is() )
852 xElement = xDocument->getDocumentElement();
854 if( xElement.is() )
856 if( xElement->getNodeName().equalsAsciiL("feed", 4) )
858 rtl::OUString aXPathExpression;
860 if( extensionId.getLength() > 0 )
861 aXPathExpression = UNISTRING("//atom:entry/atom:category[@term=\'") + extensionId + UNISTRING("\']/..");
862 else
863 aXPathExpression = UNISTRING("//atom:entry");
865 uno::Reference< xml::dom::XNodeList > xNodeList;
866 try {
867 xNodeList = m_xXPathAPI->selectNodeList(xDocument.get(),
868 aXPathExpression);
869 } catch (xml::xpath::XPathException &) {
870 // ignore
873 return new UpdateInformationEnumeration(xNodeList, this);
875 else
877 return new SingleUpdateInformationEnumeration(xElement);
881 if( m_bCancelled.check() )
882 break;
884 // rethrow runtime exceptions
885 catch( uno::RuntimeException const & ) { throw; }
887 // rethrow only if last url in the list
888 catch( uno::Exception const & )
890 if( n+1 >= repositories.getLength() )
891 throw;
895 return uno::Reference< container::XEnumeration >();
898 //------------------------------------------------------------------------------
900 uno::Sequence< uno::Reference< xml::dom::XElement > > SAL_CALL
901 UpdateInformationProvider::getUpdateInformation(
902 uno::Sequence< rtl::OUString > const & repositories,
903 rtl::OUString const & extensionId
904 ) throw (uno::Exception, uno::RuntimeException)
906 uno::Reference< container::XEnumeration > xEnumeration(
907 getUpdateInformationEnumeration(repositories, extensionId)
910 uno::Sequence< uno::Reference< xml::dom::XElement > > aRet;
912 if( xEnumeration.is() )
914 while( xEnumeration->hasMoreElements() )
918 deployment::UpdateInformationEntry aEntry;
919 if( (xEnumeration->nextElement() >>= aEntry ) && aEntry.UpdateDocument.is() )
921 sal_Int32 n = aRet.getLength();
922 aRet.realloc(n + 1);
923 aRet[n] = aEntry.UpdateDocument;
927 catch( const lang::WrappedTargetException& e )
929 // command aborted, return what we have got so far
930 if( e.TargetException.isExtractableTo( ::cppu::UnoType< ::com::sun::star::ucb::CommandAbortedException >::get() ) )
932 break;
935 // ignore files that can't be loaded
940 return aRet;
943 //------------------------------------------------------------------------------
945 void SAL_CALL
946 UpdateInformationProvider::cancel() throw (uno::RuntimeException)
948 m_bCancelled.set();
950 osl::MutexGuard aGuard(m_aMutex);
951 if( m_xCommandProcessor.is() )
952 m_xCommandProcessor->abort(m_nCommandId);
955 //------------------------------------------------------------------------------
957 void SAL_CALL
958 UpdateInformationProvider::setInteractionHandler(
959 uno::Reference< task::XInteractionHandler > const & handler )
960 throw (uno::RuntimeException)
962 osl::MutexGuard aGuard(m_aMutex);
963 m_xInteractionHandler = handler;
966 //------------------------------------------------------------------------------
968 uno::Reference< task::XInteractionHandler > SAL_CALL
969 UpdateInformationProvider::getInteractionHandler()
970 throw ( uno::RuntimeException )
972 osl::MutexGuard aGuard( m_aMutex );
974 if ( m_xInteractionHandler.is() )
975 return m_xInteractionHandler;
976 else
977 return this;
979 //------------------------------------------------------------------------------
981 uno::Sequence< rtl::OUString >
982 UpdateInformationProvider::getServiceNames()
984 uno::Sequence< rtl::OUString > aServiceList(1);
985 aServiceList[0] = UNISTRING( "com.sun.star.deployment.UpdateInformationProvider");
986 return aServiceList;
989 //------------------------------------------------------------------------------
991 rtl::OUString
992 UpdateInformationProvider::getImplName()
994 return UNISTRING( "vnd.sun.UpdateInformationProvider");
997 //------------------------------------------------------------------------------
999 rtl::OUString SAL_CALL
1000 UpdateInformationProvider::getImplementationName() throw (uno::RuntimeException)
1002 return getImplName();
1005 //------------------------------------------------------------------------------
1007 uno::Sequence< rtl::OUString > SAL_CALL
1008 UpdateInformationProvider::getSupportedServiceNames() throw (uno::RuntimeException)
1010 return getServiceNames();
1013 //------------------------------------------------------------------------------
1015 sal_Bool SAL_CALL
1016 UpdateInformationProvider::supportsService( rtl::OUString const & serviceName ) throw (uno::RuntimeException)
1018 uno::Sequence< rtl::OUString > aServiceNameList = getServiceNames();
1020 for( sal_Int32 n=0; n < aServiceNameList.getLength(); n++ )
1021 if( aServiceNameList[n].equals(serviceName) )
1022 return sal_True;
1024 return sal_False;
1027 //------------------------------------------------------------------------------
1029 void SAL_CALL UpdateInformationProvider::handle( uno::Reference< task::XInteractionRequest > const & rRequest)
1030 throw (uno::RuntimeException)
1032 uno::Any aAnyRequest( rRequest->getRequest() );
1033 ucb::AuthenticationRequest aAuthenticationRequest;
1035 if ( aAnyRequest >>= aAuthenticationRequest )
1037 uno::Sequence< uno::Reference< task::XInteractionContinuation > > xContinuations = rRequest->getContinuations();
1038 uno::Reference< task::XInteractionHandler > xIH;
1039 uno::Reference< ucb::XInteractionSupplyAuthentication > xSupplyAuthentication;
1040 uno::Reference< task::XPasswordContainer > xContainer;
1042 for ( sal_Int32 i = 0; i < xContinuations.getLength(); ++i )
1044 xSupplyAuthentication = uno::Reference< ucb::XInteractionSupplyAuthentication >(
1045 xContinuations[i], uno::UNO_QUERY );
1046 if ( xSupplyAuthentication.is() )
1047 break;
1050 // xContainer works with userName passwdSequences pairs:
1051 if ( xSupplyAuthentication.is() &&
1052 aAuthenticationRequest.HasUserName &&
1053 aAuthenticationRequest.HasPassword &&
1054 initPasswordContainer( &xContainer ) )
1056 xIH = getInteractionHandler();
1059 if ( aAuthenticationRequest.UserName.getLength() == 0 )
1061 task::UrlRecord aRec( xContainer->find( aAuthenticationRequest.ServerName, xIH ) );
1062 if ( aRec.UserList.getLength() != 0 )
1064 if ( xSupplyAuthentication->canSetUserName() )
1065 xSupplyAuthentication->setUserName( aRec.UserList[0].UserName.getStr() );
1066 if ( xSupplyAuthentication->canSetPassword() )
1068 OSL_ENSURE( aRec.UserList[0].Passwords.getLength() != 0, "empty password list" );
1069 xSupplyAuthentication->setPassword( aRec.UserList[0].Passwords[0].getStr() );
1071 if ( aRec.UserList[0].Passwords.getLength() > 1 )
1073 if ( aAuthenticationRequest.HasRealm )
1075 if ( xSupplyAuthentication->canSetRealm() )
1076 xSupplyAuthentication->setRealm( aRec.UserList[0].Passwords[1].getStr() );
1078 else if ( xSupplyAuthentication->canSetAccount() )
1079 xSupplyAuthentication->setAccount( aRec.UserList[0].Passwords[1].getStr() );
1081 xSupplyAuthentication->select();
1082 return;
1085 else
1087 task::UrlRecord aRec(xContainer->findForName( aAuthenticationRequest.ServerName,
1088 aAuthenticationRequest.UserName,
1089 xIH));
1090 if ( aRec.UserList.getLength() != 0 )
1092 OSL_ENSURE( aRec.UserList[0].Passwords.getLength() != 0, "empty password list" );
1093 if ( !aAuthenticationRequest.HasPassword ||
1094 ( aAuthenticationRequest.Password != aRec.UserList[0].Passwords[0] ) )
1096 if ( xSupplyAuthentication->canSetUserName() )
1097 xSupplyAuthentication->setUserName( aRec.UserList[0].UserName.getStr() );
1098 if ( xSupplyAuthentication->canSetPassword() )
1099 xSupplyAuthentication->setPassword(aRec.UserList[0].Passwords[0].getStr());
1100 if ( aRec.UserList[0].Passwords.getLength() > 1 )
1102 if ( aAuthenticationRequest.HasRealm )
1104 if ( xSupplyAuthentication->canSetRealm() )
1105 xSupplyAuthentication->setRealm(aRec.UserList[0].Passwords[1].getStr());
1107 else if ( xSupplyAuthentication->canSetAccount() )
1108 xSupplyAuthentication->setAccount(aRec.UserList[0].Passwords[1].getStr());
1110 xSupplyAuthentication->select();
1111 return;
1116 catch (task::NoMasterException const &)
1117 {} // user did not enter master password
1122 } // anonymous namespace
1124 //------------------------------------------------------------------------------
1126 static uno::Reference<uno::XInterface> SAL_CALL
1127 createInstance(uno::Reference<uno::XComponentContext> const & xContext)
1129 return UpdateInformationProvider::createInstance(xContext);
1132 //------------------------------------------------------------------------------
1134 static const cppu::ImplementationEntry kImplementations_entries[] =
1137 createInstance,
1138 UpdateInformationProvider::getImplName,
1139 UpdateInformationProvider::getServiceNames,
1140 cppu::createSingleComponentFactory,
1141 NULL,
1144 { NULL, NULL, NULL, NULL, NULL, 0 }
1147 //------------------------------------------------------------------------------
1149 extern "C" void SAL_CALL
1150 component_getImplementationEnvironment( const sal_Char **aEnvTypeName, uno_Environment **)
1152 *aEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME ;
1155 //------------------------------------------------------------------------------
1157 extern "C" sal_Bool SAL_CALL
1158 component_writeInfo(void *pServiceManager, void *pRegistryKey)
1160 return cppu::component_writeInfoHelper(
1161 pServiceManager,
1162 pRegistryKey,
1163 kImplementations_entries
1167 //------------------------------------------------------------------------------
1169 extern "C" void *
1170 component_getFactory(const sal_Char *pszImplementationName, void *pServiceManager, void *pRegistryKey)
1172 return cppu::component_getFactoryHelper(
1173 pszImplementationName,
1174 pServiceManager,
1175 pRegistryKey,
1176 kImplementations_entries) ;