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