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