1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 
31 #include <cppuhelper/implbase1.hxx>
32 #include <cppuhelper/implbase4.hxx>
33 #include <cppuhelper/implementationentry.hxx>
34 #include <com/sun/star/beans/Property.hpp>
35 #include <com/sun/star/beans/XPropertySetInfo.hpp>
36 #include <com/sun/star/beans/PropertyValue.hpp>
37 #include <com/sun/star/container/XNameAccess.hpp>
38 #include <com/sun/star/deployment/UpdateInformationEntry.hpp>
39 #include <com/sun/star/deployment/UpdateInformationProvider.hpp>
40 #include <com/sun/star/io/XActiveDataSink.hpp>
41 #include <com/sun/star/io/XInputStream.hpp>
42 #include <com/sun/star/lang/XComponent.hpp>
43 #include <com/sun/star/lang/XServiceInfo.hpp>
44 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
45 #include <com/sun/star/ucb/XWebDAVCommandEnvironment.hpp>
46 #include <com/sun/star/ucb/XCommandProcessor2.hpp>
47 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
48 #include <com/sun/star/ucb/XContentProvider.hpp>
49 #include "com/sun/star/ucb/XInteractionSupplyAuthentication.hpp"
50 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
51 #include <com/sun/star/ucb/OpenMode.hpp>
52 #include <com/sun/star/sdbc/XRow.hpp>
53 #include <com/sun/star/task/PasswordContainerInteractionHandler.hpp>
54 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
55 #include <com/sun/star/xml/xpath/XXPathAPI.hpp>
56 
57 #include <rtl/ref.hxx>
58 #include <rtl/memory.h>
59 #include <rtl/bootstrap.hxx>
60 #include <rtl/ustrbuf.hxx>
61 #include <osl/process.h>
62 #include <osl/conditn.hxx>
63 
64 namespace beans = com::sun::star::beans ;
65 namespace container = com::sun::star::container ;
66 namespace deployment = com::sun::star::deployment ;
67 namespace io = com::sun::star::io ;
68 namespace lang = com::sun::star::lang ;
69 namespace task = com::sun::star::task ;
70 namespace ucb = com::sun::star::ucb ;
71 namespace uno = com::sun::star::uno ;
72 namespace xml = com::sun::star::xml ;
73 namespace sdbc = com::sun::star::sdbc ;
74 
75 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
76 
77 //------------------------------------------------------------------------------
78 
79 namespace
80 {
81 
82 #ifdef DEBUG
83 
84 class InputStreamWrapper : public ::cppu::WeakImplHelper1< io::XInputStream >
85 {
86     uno::Reference< io::XInputStream > m_xStream;
87 
88 public:
89     InputStreamWrapper(const uno::Reference< io::XInputStream >& rxStream) :
90         m_xStream(rxStream) {};
91 
92     virtual sal_Int32 SAL_CALL readBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
93         throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
94         {
95             sal_Int32 n = m_xStream->readBytes(aData, nBytesToRead);
96             if ( n )
97                 OSL_TRACE( "Read [%d] bytes: %s\n", n, aData.get()->elements );
98             return n;
99         };
100     virtual sal_Int32 SAL_CALL readSomeBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
101         throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
102         {
103             sal_Int32 n = m_xStream->readSomeBytes(aData, nMaxBytesToRead);
104             if ( n )
105                 OSL_TRACE( "Read [%d] bytes: %s\n", n, aData.get()->elements );
106             return n;
107         };
108     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
109         throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
110         { m_xStream->skipBytes(nBytesToSkip); };
111     virtual sal_Int32 SAL_CALL available()
112         throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
113         { return m_xStream->available(); };
114     virtual void SAL_CALL closeInput( )
115         throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
116         {};
117 };
118 
119 #define INPUT_STREAM(i) new InputStreamWrapper(i)
120 #else
121 #define INPUT_STREAM(i) i
122 #endif
123 
124 //------------------------------------------------------------------------------
125 
126 class ActiveDataSink : public ::cppu::WeakImplHelper1< io::XActiveDataSink >
127 {
128     uno::Reference< io::XInputStream > m_xStream;
129 
130 public:
131     ActiveDataSink() {};
132 
133     inline operator uno::Reference< io::XActiveDataSink > () { return this; };
134 
135     virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream()
136         throw (uno::RuntimeException) { return m_xStream; };
137     virtual void SAL_CALL setInputStream( uno::Reference< io::XInputStream > const & rStream )
138         throw (uno::RuntimeException) { m_xStream = rStream; };
139 };
140 
141 //------------------------------------------------------------------------------
142 
143 class UpdateInformationProvider :
144     public ::cppu::WeakImplHelper4< deployment::XUpdateInformationProvider,
145                                     ucb::XCommandEnvironment,
146                                     ucb::XWebDAVCommandEnvironment,
147                                     lang::XServiceInfo >
148 {
149 public:
150     static uno::Reference< uno::XInterface > createInstance(const uno::Reference<uno::XComponentContext>& xContext);
151 
152     static uno::Sequence< rtl::OUString > getServiceNames();
153     static rtl::OUString getImplName();
154 
155     uno::Reference< xml::dom::XElement > getDocumentRoot(const uno::Reference< xml::dom::XNode >& rxNode);
156     uno::Reference< xml::dom::XNode > getChildNode(const uno::Reference< xml::dom::XNode >& rxNode, const rtl::OUString& rName);
157 
158 
159     // XUpdateInformationService
160     virtual uno::Sequence< uno::Reference< xml::dom::XElement > > SAL_CALL
161     getUpdateInformation(
162         uno::Sequence< rtl::OUString > const & repositories,
163         rtl::OUString const & extensionId
164     ) throw (uno::Exception, uno::RuntimeException);
165 
166     virtual void SAL_CALL cancel()
167         throw (uno::RuntimeException);
168 
169     virtual void SAL_CALL setInteractionHandler(
170         uno::Reference< task::XInteractionHandler > const & handler )
171         throw (uno::RuntimeException);
172 
173     virtual uno::Reference< container::XEnumeration > SAL_CALL
174     getUpdateInformationEnumeration(
175         uno::Sequence< rtl::OUString > const & repositories,
176         rtl::OUString const & extensionId
177     ) throw (uno::Exception, uno::RuntimeException);
178 
179     // XCommandEnvironment
180     virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler()
181         throw ( uno::RuntimeException );
182 
183     virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler()
184         throw ( uno::RuntimeException ) { return  uno::Reference< ucb::XProgressHandler >(); };
185 
186     // XWebDAVCommandEnvironment
187     virtual uno::Sequence< beans::NamedValue > SAL_CALL getUserRequestHeaders(
188         const rtl::OUString&, const rtl::OUString& )
189         throw ( uno::RuntimeException ) { return m_aRequestHeaderList; };
190 
191     // XServiceInfo
192     virtual rtl::OUString SAL_CALL getImplementationName()
193         throw (uno::RuntimeException);
194     virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
195         throw (uno::RuntimeException);
196     virtual uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames()
197         throw (uno::RuntimeException);
198 
199 protected:
200 
201     virtual ~UpdateInformationProvider();
202     static uno::Any getConfigurationItem(uno::Reference<lang::XMultiServiceFactory> const & configurationProvider, rtl::OUString const & node, rtl::OUString const & item);
203 
204 private:
205     uno::Reference< io::XInputStream > load(const rtl::OUString& rURL);
206 
207     void storeCommandInfo( sal_Int32 nCommandId,
208         uno::Reference< ucb::XCommandProcessor > const & rxCommandProcessor);
209 
210     UpdateInformationProvider(const uno::Reference<uno::XComponentContext>& xContext,
211                               const uno::Reference< ucb::XContentIdentifierFactory >& xContentIdFactory,
212                               const uno::Reference< ucb::XContentProvider >& xContentProvider,
213                               const uno::Reference< xml::dom::XDocumentBuilder >& xDocumentBuilder,
214                               const uno::Reference< xml::xpath::XXPathAPI >& xXPathAPI);
215 
216     const uno::Reference< uno::XComponentContext> m_xContext;
217 
218     const uno::Reference< ucb::XContentIdentifierFactory > m_xContentIdFactory;
219     const uno::Reference< ucb::XContentProvider > m_xContentProvider;
220     const uno::Reference< xml::dom::XDocumentBuilder > m_xDocumentBuilder;
221     const uno::Reference< xml::xpath::XXPathAPI > m_xXPathAPI;
222 
223     uno::Sequence< beans::NamedValue > m_aRequestHeaderList;
224 
225     uno::Reference< ucb::XCommandProcessor > m_xCommandProcessor;
226     uno::Reference< task::XInteractionHandler > m_xInteractionHandler;
227     uno::Reference< task::XInteractionHandler > m_xPwContainerInteractionHandler;
228 
229     osl::Mutex m_aMutex;
230     osl::Condition m_bCancelled;
231 
232     sal_Int32 m_nCommandId;
233 };
234 
235 //------------------------------------------------------------------------------
236 
237 class UpdateInformationEnumeration : public ::cppu::WeakImplHelper1< container::XEnumeration >
238 {
239 public:
240     UpdateInformationEnumeration(const uno::Reference< xml::dom::XNodeList >& xNodeList,
241                                  const uno::Reference< UpdateInformationProvider > xUpdateInformationProvider) :
242         m_xUpdateInformationProvider(xUpdateInformationProvider),
243         m_xNodeList(xNodeList),
244         m_nNodes(xNodeList.is() ? xNodeList->getLength() : 0),
245         m_nCount(0)
246     {
247     };
248 
249     virtual ~UpdateInformationEnumeration() {};
250 
251     // XEnumeration
252     sal_Bool SAL_CALL hasMoreElements() throw (uno::RuntimeException) { return m_nCount < m_nNodes; };
253     uno::Any SAL_CALL nextElement() throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
254     {
255         OSL_ASSERT( m_xNodeList.is() );
256         OSL_ASSERT( m_xUpdateInformationProvider.is() );
257 
258         if( !(m_nCount < m_nNodes ) )
259             throw container::NoSuchElementException(rtl::OUString::valueOf(m_nCount), *this);
260 
261         try
262         {
263             deployment::UpdateInformationEntry aEntry;
264 
265             uno::Reference< xml::dom::XNode > xAtomEntryNode( m_xNodeList->item(m_nCount++) );
266 
267             uno::Reference< xml::dom::XNode > xSummaryNode(
268                 m_xUpdateInformationProvider->getChildNode( xAtomEntryNode, UNISTRING( "summary/text()" ) )
269             );
270 
271             if( xSummaryNode.is() )
272                 aEntry.Description = xSummaryNode->getNodeValue();
273 
274             uno::Reference< xml::dom::XNode > xContentNode(
275                 m_xUpdateInformationProvider->getChildNode( xAtomEntryNode, UNISTRING( "content" ) ) );
276 
277             if( xContentNode.is() )
278                 aEntry.UpdateDocument = m_xUpdateInformationProvider->getDocumentRoot(xContentNode);
279 
280             return uno::makeAny(aEntry);
281         }
282 
283         // action has been aborted
284         catch( ucb::CommandAbortedException const & e)
285             { throw lang::WrappedTargetException( UNISTRING( "Command aborted" ), *this, uno::makeAny(e) ); }
286 
287         // let runtime exception pass
288         catch( uno::RuntimeException const & ) { throw; }
289 
290         // document not accessible
291         catch( uno::Exception const & e)
292             { throw lang::WrappedTargetException( UNISTRING( "Document not accessible" ), *this, uno::makeAny(e) ); }
293     }
294 
295 private:
296     const uno::Reference< UpdateInformationProvider > m_xUpdateInformationProvider;
297     const uno::Reference< xml::dom::XNodeList > m_xNodeList;
298     const sal_Int32 m_nNodes;
299     sal_Int32 m_nCount;
300 };
301 
302 //------------------------------------------------------------------------------
303 
304 class SingleUpdateInformationEnumeration : public ::cppu::WeakImplHelper1< container::XEnumeration >
305 {
306 public:
307     SingleUpdateInformationEnumeration(const uno::Reference< xml::dom::XElement >& xElement)
308         : m_nCount(0) { m_aEntry.UpdateDocument = xElement; };
309     virtual ~SingleUpdateInformationEnumeration() {};
310 
311     // XEnumeration
312     sal_Bool SAL_CALL hasMoreElements() throw (uno::RuntimeException) { return 0 == m_nCount; };
313     uno::Any SAL_CALL nextElement() throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
314     {
315         if( m_nCount > 0 )
316             throw container::NoSuchElementException(rtl::OUString::valueOf(m_nCount), *this);
317 
318         ++m_nCount;
319         return uno::makeAny(m_aEntry);
320     };
321 
322 private:
323     sal_uInt8 m_nCount;
324     deployment::UpdateInformationEntry m_aEntry;
325 };
326 
327 
328 //------------------------------------------------------------------------------
329 
330 UpdateInformationProvider::UpdateInformationProvider(
331     const uno::Reference<uno::XComponentContext>& xContext,
332     const uno::Reference< ucb::XContentIdentifierFactory >& xContentIdFactory,
333     const uno::Reference< ucb::XContentProvider >& xContentProvider,
334     const uno::Reference< xml::dom::XDocumentBuilder >& xDocumentBuilder,
335     const uno::Reference< xml::xpath::XXPathAPI >& xXPathAPI
336 ) : m_xContext(xContext), m_xContentIdFactory(xContentIdFactory),
337     m_xContentProvider(xContentProvider), m_xDocumentBuilder(xDocumentBuilder),
338     m_xXPathAPI(xXPathAPI), m_aRequestHeaderList(1)
339 {
340     uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
341     if( !xServiceManager.is() )
342         throw uno::RuntimeException(
343             UNISTRING("unable to obtain service manager from component context"),
344             uno::Reference< uno::XInterface >());
345 
346     uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider(
347         xServiceManager->createInstanceWithContext(
348             UNISTRING("com.sun.star.configuration.ConfigurationProvider"),
349             xContext ),
350         uno::UNO_QUERY_THROW);
351 
352     rtl::OUStringBuffer buf;
353     rtl::OUString name;
354     getConfigurationItem(
355         xConfigurationProvider,
356         UNISTRING("org.openoffice.Setup/Product"),
357         UNISTRING("ooName")) >>= name;
358     buf.append(name);
359     buf.append(sal_Unicode(' '));
360     rtl::OUString version;
361     getConfigurationItem(
362         xConfigurationProvider,
363         UNISTRING("org.openoffice.Setup/Product"),
364         UNISTRING("ooSetupVersion")) >>= version;
365     buf.append(version);
366     rtl::OUString edition(
367         UNISTRING(
368             "${${BRAND_BASE_DIR}/program/edition/edition.ini:"
369             "EDITIONNAME}"));
370     rtl::Bootstrap::expandMacros(edition);
371     if (edition.getLength() != 0) {
372         buf.append(sal_Unicode(' '));
373         buf.append(edition);
374     }
375     rtl::OUString extension;
376     getConfigurationItem(
377         xConfigurationProvider,
378         UNISTRING("org.openoffice.Setup/Product"),
379         UNISTRING("ooSetupExtension")) >>= extension;
380     if (extension.getLength() != 0) {
381         buf.append(sal_Unicode(' '));
382         buf.append(extension);
383     }
384     rtl::OUString product(buf.makeStringAndClear());
385 
386     rtl::OUString aBaseBuildId( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
387     rtl::Bootstrap::expandMacros( aBaseBuildId );
388 
389     rtl::OUString aBrandBuildId( UNISTRING( "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
390     rtl::Bootstrap::expandMacros( aBrandBuildId );
391 
392     rtl::OUString aUserAgent( UNISTRING( "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") ":UpdateUserAgent}" ) );
393     rtl::Bootstrap::expandMacros( aUserAgent );
394 
395     if ( ! aBaseBuildId.equals( aBrandBuildId ) )
396     {
397         sal_Int32 nIndex = aUserAgent.indexOf( aBrandBuildId, 0 );
398         if ( nIndex != -1 )
399             aUserAgent = aUserAgent.replaceAt( nIndex, aBrandBuildId.getLength(), aBaseBuildId );
400     }
401 
402     for (sal_Int32 i = 0;;) {
403         i = aUserAgent.indexOfAsciiL(
404             RTL_CONSTASCII_STRINGPARAM("<PRODUCT>"), i);
405         if (i == -1) {
406             break;
407         }
408         aUserAgent = aUserAgent.replaceAt(
409             i, RTL_CONSTASCII_LENGTH("<PRODUCT>"), product);
410         i += product.getLength();
411     }
412 
413     m_aRequestHeaderList[0].Name = UNISTRING("Accept-Language");
414     m_aRequestHeaderList[0].Value = getConfigurationItem( xConfigurationProvider, UNISTRING("org.openoffice.Setup/L10N"), UNISTRING("ooLocale") );
415     if( aUserAgent.getLength() > 0 )
416     {
417         m_aRequestHeaderList.realloc(2);
418         m_aRequestHeaderList[1].Name = UNISTRING("User-Agent");
419         m_aRequestHeaderList[1].Value = uno::makeAny(aUserAgent);
420     }
421 }
422 
423 //------------------------------------------------------------------------------
424 uno::Reference< uno::XInterface >
425 UpdateInformationProvider::createInstance(const uno::Reference<uno::XComponentContext>& xContext)
426 {
427     uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
428     if( !xServiceManager.is() )
429         throw uno::RuntimeException(
430             UNISTRING( "unable to obtain service manager from component context" ),
431             uno::Reference< uno::XInterface > ());
432 
433     uno::Reference< ucb::XContentIdentifierFactory > xContentIdFactory(
434         xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.ucb.UniversalContentBroker" ), xContext ),
435         uno::UNO_QUERY_THROW);
436 
437     uno::Reference< ucb::XContentProvider > xContentProvider(xContentIdFactory, uno::UNO_QUERY_THROW);
438 
439     uno::Reference< xml::dom::XDocumentBuilder > xDocumentBuilder(
440         xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.xml.dom.DocumentBuilder" ), xContext ),
441         uno::UNO_QUERY_THROW);
442 
443     uno::Reference< xml::xpath::XXPathAPI > xXPath(
444         xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.xml.xpath.XPathAPI" ), xContext ),
445         uno::UNO_QUERY_THROW);
446 
447     xXPath->registerNS( UNISTRING("atom"), UNISTRING("http://www.w3.org/2005/Atom") );
448 
449     return *new UpdateInformationProvider(xContext, xContentIdFactory, xContentProvider, xDocumentBuilder, xXPath);
450 }
451 
452 //------------------------------------------------------------------------------
453 
454 UpdateInformationProvider::~UpdateInformationProvider()
455 {
456 }
457 
458 //------------------------------------------------------------------------------
459 
460 uno::Any
461 UpdateInformationProvider::getConfigurationItem(uno::Reference<lang::XMultiServiceFactory> const & configurationProvider, rtl::OUString const & node, rtl::OUString const & item)
462 {
463     beans::PropertyValue aProperty;
464     aProperty.Name  = UNISTRING("nodepath");
465     aProperty.Value = uno::makeAny(node);
466 
467     uno::Sequence< uno::Any > aArgumentList( 1 );
468     aArgumentList[0] = uno::makeAny( aProperty );
469 
470     uno::Reference< container::XNameAccess > xNameAccess(
471         configurationProvider->createInstanceWithArguments(
472             UNISTRING("com.sun.star.configuration.ConfigurationAccess"),
473             aArgumentList ),
474         uno::UNO_QUERY_THROW);
475 
476     return xNameAccess->getByName(item);
477 }
478 
479 //------------------------------------------------------------------------------
480 
481 void
482 UpdateInformationProvider::storeCommandInfo(
483     sal_Int32 nCommandId,
484     uno::Reference< ucb::XCommandProcessor > const & rxCommandProcessor)
485 {
486     osl::MutexGuard aGuard(m_aMutex);
487 
488     m_nCommandId = nCommandId;
489     m_xCommandProcessor = rxCommandProcessor;
490 }
491 
492 //------------------------------------------------------------------------------
493 
494 uno::Reference< io::XInputStream >
495 UpdateInformationProvider::load(const rtl::OUString& rURL)
496 {
497     uno::Reference< ucb::XContentIdentifier > xId = m_xContentIdFactory->createContentIdentifier(rURL);
498 
499     if( !xId.is() )
500         throw uno::RuntimeException(
501             UNISTRING( "unable to obtain universal content id" ), *this);
502 
503     uno::Reference< ucb::XCommandProcessor > xCommandProcessor(m_xContentProvider->queryContent(xId), uno::UNO_QUERY_THROW);
504     rtl::Reference< ActiveDataSink > aSink(new ActiveDataSink());
505 
506     ucb::OpenCommandArgument2 aOpenArgument;
507     aOpenArgument.Mode = ucb::OpenMode::DOCUMENT;
508     aOpenArgument.Priority = 32768;
509     aOpenArgument.Sink = *aSink;
510 
511     ucb::Command aCommand;
512     aCommand.Name = UNISTRING("open");
513     aCommand.Argument = uno::makeAny(aOpenArgument);
514 
515     sal_Int32 nCommandId = xCommandProcessor->createCommandIdentifier();
516 
517     storeCommandInfo(nCommandId, xCommandProcessor);
518     try
519     {
520         uno::Any aResult = xCommandProcessor->execute(aCommand, nCommandId,
521             static_cast < XCommandEnvironment *> (this));
522     }
523     catch( const uno::Exception & /* e */ )
524     {
525         storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ());
526 
527         uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY);
528         if( xCommandProcessor2.is() )
529             xCommandProcessor2->releaseCommandIdentifier(nCommandId);
530 
531         throw;
532     }
533     storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ());
534 
535     uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY);
536     if( xCommandProcessor2.is() )
537         xCommandProcessor2->releaseCommandIdentifier(nCommandId);
538 
539     return INPUT_STREAM(aSink->getInputStream());
540 }
541 
542 //------------------------------------------------------------------------------
543 
544 // TODO: docu content node
545 
546 uno::Reference< xml::dom::XElement >
547 UpdateInformationProvider::getDocumentRoot(const uno::Reference< xml::dom::XNode >& rxNode)
548 {
549     OSL_ASSERT(m_xDocumentBuilder.is());
550 
551     uno::Reference< xml::dom::XElement > xElement(rxNode, uno::UNO_QUERY_THROW);
552 
553     // load the document referenced in 'src' attribute ..
554     if( xElement->hasAttribute( UNISTRING("src") ) )
555     {
556         uno::Reference< xml::dom::XDocument > xUpdateXML =
557             m_xDocumentBuilder->parse(load(xElement->getAttribute( UNISTRING("src") )));
558 
559         OSL_ASSERT( xUpdateXML.is() );
560 
561         if( xUpdateXML.is() )
562             return xUpdateXML->getDocumentElement();
563     }
564     // .. or return the (single) child element
565     else
566     {
567         uno::Reference< xml::dom::XNodeList> xChildNodes = rxNode->getChildNodes();
568 
569         // ignore possible #text nodes
570         sal_Int32 nmax = xChildNodes->getLength();
571         for(sal_Int32 n=0; n < nmax; n++)
572         {
573             uno::Reference< xml::dom::XElement > xChildElement(xChildNodes->item(n), uno::UNO_QUERY);
574             if( xChildElement.is() )
575             {
576                 /* Copy the content to a dedicated document since XXPathAPI->selectNodeList
577                  * seems to evaluate expression always relative to the root node.
578                  */
579                 uno::Reference< xml::dom::XDocument > xUpdateXML = m_xDocumentBuilder->newDocument();
580                 xUpdateXML->appendChild( xUpdateXML->importNode(xChildElement.get(), sal_True ) );
581                 return xUpdateXML->getDocumentElement();
582             }
583         }
584     }
585 
586     return uno::Reference< xml::dom::XElement > ();
587 }
588 
589 //------------------------------------------------------------------------------
590 
591 uno::Reference< xml::dom::XNode >
592 UpdateInformationProvider::getChildNode(const uno::Reference< xml::dom::XNode >& rxNode,
593                                         const rtl::OUString& rName)
594 {
595     OSL_ASSERT(m_xXPathAPI.is());
596     try {
597         return m_xXPathAPI->selectSingleNode(rxNode, UNISTRING( "./atom:" ) + rName);
598     } catch (xml::xpath::XPathException &) {
599         // ignore
600         return 0;
601     }
602 }
603 
604 //------------------------------------------------------------------------------
605 
606 uno::Reference< container::XEnumeration > SAL_CALL
607 UpdateInformationProvider::getUpdateInformationEnumeration(
608     uno::Sequence< rtl::OUString > const & repositories,
609     rtl::OUString const & extensionId
610 ) throw (uno::Exception, uno::RuntimeException)
611 {
612     OSL_ASSERT(m_xDocumentBuilder.is());
613 
614     // reset cancelled flag
615     m_bCancelled.reset();
616 
617     for(sal_Int32 n=0; n<repositories.getLength(); n++)
618     {
619         try
620         {
621             uno::Reference< xml::dom::XDocument > xDocument = m_xDocumentBuilder->parse(load(repositories[n]));
622             uno::Reference< xml::dom::XElement > xElement;
623 
624             if( xDocument.is() )
625                 xElement = xDocument->getDocumentElement();
626 
627             if( xElement.is() )
628             {
629                 if( xElement->getNodeName().equalsAsciiL("feed", 4) )
630                 {
631                     rtl::OUString aXPathExpression;
632 
633                     if( extensionId.getLength() > 0 )
634                         aXPathExpression = UNISTRING("//atom:entry/atom:category[@term=\'") + extensionId + UNISTRING("\']/..");
635                     else
636                         aXPathExpression = UNISTRING("//atom:entry");
637 
638                     uno::Reference< xml::dom::XNodeList > xNodeList;
639                     try {
640                         xNodeList = m_xXPathAPI->selectNodeList(xDocument.get(),
641                             aXPathExpression);
642                     } catch (xml::xpath::XPathException &) {
643                         // ignore
644                     }
645 
646                     return new UpdateInformationEnumeration(xNodeList, this);
647                 }
648                 else
649                 {
650                     return new SingleUpdateInformationEnumeration(xElement);
651                 }
652             }
653 
654             if( m_bCancelled.check() )
655                 break;
656         }
657         // rethrow runtime exceptions
658         catch( uno::RuntimeException const & ) { throw; }
659 
660         // rethrow only if last url in the list
661         catch( uno::Exception const & )
662         {
663             if( n+1 >= repositories.getLength() )
664                 throw;
665         }
666     }
667 
668     return uno::Reference< container::XEnumeration >();
669 }
670 
671 //------------------------------------------------------------------------------
672 
673 uno::Sequence< uno::Reference< xml::dom::XElement > > SAL_CALL
674 UpdateInformationProvider::getUpdateInformation(
675     uno::Sequence< rtl::OUString > const & repositories,
676     rtl::OUString const & extensionId
677 ) throw (uno::Exception, uno::RuntimeException)
678 {
679     uno::Reference< container::XEnumeration > xEnumeration(
680         getUpdateInformationEnumeration(repositories, extensionId)
681     );
682 
683     uno::Sequence< uno::Reference< xml::dom::XElement > > aRet;
684 
685     if( xEnumeration.is() )
686     {
687         while( xEnumeration->hasMoreElements() )
688         {
689             try
690             {
691                 deployment::UpdateInformationEntry aEntry;
692                 if( (xEnumeration->nextElement() >>= aEntry ) && aEntry.UpdateDocument.is() )
693                 {
694                     sal_Int32 n = aRet.getLength();
695                     aRet.realloc(n + 1);
696                     aRet[n] = aEntry.UpdateDocument;
697                 }
698             }
699 
700             catch( const lang::WrappedTargetException& e )
701             {
702                 // command aborted, return what we have got so far
703                 if( e.TargetException.isExtractableTo( ::cppu::UnoType< ::com::sun::star::ucb::CommandAbortedException >::get() ) )
704                 {
705                     break;
706                 }
707 
708                 // ignore files that can't be loaded
709             }
710         }
711     }
712 
713     return aRet;
714 }
715 
716 //------------------------------------------------------------------------------
717 
718 void SAL_CALL
719 UpdateInformationProvider::cancel() throw (uno::RuntimeException)
720 {
721     m_bCancelled.set();
722 
723     osl::MutexGuard aGuard(m_aMutex);
724     if( m_xCommandProcessor.is() )
725         m_xCommandProcessor->abort(m_nCommandId);
726 }
727 
728 //------------------------------------------------------------------------------
729 
730 void SAL_CALL
731 UpdateInformationProvider::setInteractionHandler(
732         uno::Reference< task::XInteractionHandler > const & handler )
733     throw (uno::RuntimeException)
734 {
735     osl::MutexGuard aGuard(m_aMutex);
736     m_xInteractionHandler = handler;
737 }
738 
739 //------------------------------------------------------------------------------
740 
741 uno::Reference< task::XInteractionHandler > SAL_CALL
742 UpdateInformationProvider::getInteractionHandler()
743     throw ( uno::RuntimeException )
744 {
745     osl::MutexGuard aGuard( m_aMutex );
746 
747     if ( m_xInteractionHandler.is() )
748         return m_xInteractionHandler;
749     else
750     {
751         try
752         {
753             // Supply an interaction handler that uses the password container
754             // service to obtain credentials without displaying a password gui.
755 
756             if ( !m_xPwContainerInteractionHandler.is() )
757                 m_xPwContainerInteractionHandler
758                     = task::PasswordContainerInteractionHandler::create(
759                         m_xContext );
760         }
761         catch ( uno::RuntimeException const & )
762         {
763             throw;
764         }
765         catch ( uno::Exception const & )
766         {
767         }
768         return m_xPwContainerInteractionHandler;
769     }
770 }
771 //------------------------------------------------------------------------------
772 
773 uno::Sequence< rtl::OUString >
774 UpdateInformationProvider::getServiceNames()
775 {
776     uno::Sequence< rtl::OUString > aServiceList(1);
777     aServiceList[0] = UNISTRING( "com.sun.star.deployment.UpdateInformationProvider");
778     return aServiceList;
779 };
780 
781 //------------------------------------------------------------------------------
782 
783 rtl::OUString
784 UpdateInformationProvider::getImplName()
785 {
786     return UNISTRING( "vnd.sun.UpdateInformationProvider");
787 }
788 
789 //------------------------------------------------------------------------------
790 
791 rtl::OUString SAL_CALL
792 UpdateInformationProvider::getImplementationName() throw (uno::RuntimeException)
793 {
794     return getImplName();
795 }
796 
797 //------------------------------------------------------------------------------
798 
799 uno::Sequence< rtl::OUString > SAL_CALL
800 UpdateInformationProvider::getSupportedServiceNames() throw (uno::RuntimeException)
801 {
802     return getServiceNames();
803 }
804 
805 //------------------------------------------------------------------------------
806 
807 sal_Bool SAL_CALL
808 UpdateInformationProvider::supportsService( rtl::OUString const & serviceName ) throw (uno::RuntimeException)
809 {
810     uno::Sequence< rtl::OUString > aServiceNameList = getServiceNames();
811 
812     for( sal_Int32 n=0; n < aServiceNameList.getLength(); n++ )
813         if( aServiceNameList[n].equals(serviceName) )
814             return sal_True;
815 
816     return sal_False;
817 }
818 
819 } // anonymous namespace
820 
821 //------------------------------------------------------------------------------
822 
823 static uno::Reference<uno::XInterface> SAL_CALL
824 createInstance(uno::Reference<uno::XComponentContext> const & xContext)
825 {
826     return UpdateInformationProvider::createInstance(xContext);
827 }
828 
829 //------------------------------------------------------------------------------
830 
831 static const cppu::ImplementationEntry kImplementations_entries[] =
832 {
833     {
834         createInstance,
835         UpdateInformationProvider::getImplName,
836         UpdateInformationProvider::getServiceNames,
837         cppu::createSingleComponentFactory,
838         NULL,
839         0
840     },
841     { NULL, NULL, NULL, NULL, NULL, 0 }
842 } ;
843 
844 //------------------------------------------------------------------------------
845 
846 extern "C" void SAL_CALL
847 component_getImplementationEnvironment( const sal_Char **aEnvTypeName, uno_Environment **)
848 {
849     *aEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME ;
850 }
851 
852 //------------------------------------------------------------------------------
853 
854 extern "C" void *
855 component_getFactory(const sal_Char *pszImplementationName, void *pServiceManager, void *pRegistryKey)
856 {
857     return cppu::component_getFactoryHelper(
858         pszImplementationName,
859         pServiceManager,
860         pRegistryKey,
861         kImplementations_entries) ;
862 }
863 
864