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