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         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         };
readSomeBytes(uno::Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)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         };
skipBytes(sal_Int32 nBytesToSkip)103     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
104         throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
105         { m_xStream->skipBytes(nBytesToSkip); };
available()106     virtual sal_Int32 SAL_CALL available()
107         throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
108         { return m_xStream->available(); };
closeInput()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:
ActiveDataSink()126     ActiveDataSink() {};
127 
operator uno::Reference<io::XActiveDataSink>()128     inline operator uno::Reference< io::XActiveDataSink > () { return this; };
129 
getInputStream()130     virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream()
131         throw (uno::RuntimeException) { return m_xStream; };
setInputStream(uno::Reference<io::XInputStream> const & rStream)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 
getProgressHandler()177     virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler()
178         throw ( uno::RuntimeException ) { return  uno::Reference< ucb::XProgressHandler >(); };
179 
180     // XWebDAVCommandEnvironment
getUserRequestHeaders(const rtl::OUString &,ucb::WebDAVHTTPMethod)181     virtual uno::Sequence< beans::StringPair > SAL_CALL getUserRequestHeaders(
182         const rtl::OUString&,  ucb::WebDAVHTTPMethod )
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:
UpdateInformationEnumeration(const uno::Reference<xml::dom::XNodeList> & xNodeList,const uno::Reference<UpdateInformationProvider> xUpdateInformationProvider)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 
~UpdateInformationEnumeration()243     virtual ~UpdateInformationEnumeration() {};
244 
245     // XEnumeration
hasMoreElements()246     sal_Bool SAL_CALL hasMoreElements() throw (uno::RuntimeException) { return m_nCount < m_nNodes; };
nextElement()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:
SingleUpdateInformationEnumeration(const uno::Reference<xml::dom::XElement> & xElement)301     SingleUpdateInformationEnumeration(const uno::Reference< xml::dom::XElement >& xElement)
302         : m_nCount(0) { m_aEntry.UpdateDocument = xElement; };
~SingleUpdateInformationEnumeration()303     virtual ~SingleUpdateInformationEnumeration() {};
304 
305     // XEnumeration
hasMoreElements()306     sal_Bool SAL_CALL hasMoreElements() throw (uno::RuntimeException) { return 0 == m_nCount; };
nextElement()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 
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)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             "${${OOO_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(aBaseBuildId);
382     // rtl::OUString aBrandBuildId( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
383     // rtl::Bootstrap::expandMacros( aBrandBuildId );
384 
385     rtl::OUString aUserAgent( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":UpdateUserAgent}" ) );
386     rtl::Bootstrap::expandMacros( aUserAgent );
387 
388     if ( ! aBaseBuildId.equals( aBrandBuildId ) )
389     {
390         sal_Int32 nIndex = aUserAgent.indexOf( aBrandBuildId, 0 );
391         if ( nIndex != -1 )
392             aUserAgent = aUserAgent.replaceAt( nIndex, aBrandBuildId.getLength(), aBaseBuildId );
393     }
394 
395     for (sal_Int32 i = 0;;) {
396         i = aUserAgent.indexOfAsciiL(
397             RTL_CONSTASCII_STRINGPARAM("<PRODUCT>"), i);
398         if (i == -1) {
399             break;
400         }
401         aUserAgent = aUserAgent.replaceAt(
402             i, RTL_CONSTASCII_LENGTH("<PRODUCT>"), product);
403         i += product.getLength();
404     }
405 
406     m_aRequestHeaderList[0].First = UNISTRING("Accept-Language");
407     m_aRequestHeaderList[0].Second = getConfigurationItem( xConfigurationProvider, UNISTRING("org.openoffice.Setup/L10N"), UNISTRING("ooLocale") );
408     if( aUserAgent.getLength() > 0 )
409     {
410         m_aRequestHeaderList.realloc(2);
411         m_aRequestHeaderList[1].First = UNISTRING("User-Agent");
412         m_aRequestHeaderList[1].Second = aUserAgent;
413     }
414 }
415 
416 //------------------------------------------------------------------------------
417 uno::Reference< uno::XInterface >
createInstance(const uno::Reference<uno::XComponentContext> & xContext)418 UpdateInformationProvider::createInstance(const uno::Reference<uno::XComponentContext>& xContext)
419 {
420     uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
421     if( !xServiceManager.is() )
422         throw uno::RuntimeException(
423             UNISTRING( "unable to obtain service manager from component context" ),
424             uno::Reference< uno::XInterface > ());
425 
426     uno::Reference< ucb::XContentIdentifierFactory > xContentIdFactory(
427         xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.ucb.UniversalContentBroker" ), xContext ),
428         uno::UNO_QUERY_THROW);
429 
430     uno::Reference< ucb::XContentProvider > xContentProvider(xContentIdFactory, uno::UNO_QUERY_THROW);
431 
432     uno::Reference< xml::dom::XDocumentBuilder > xDocumentBuilder(
433         xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.xml.dom.DocumentBuilder" ), xContext ),
434         uno::UNO_QUERY_THROW);
435 
436     uno::Reference< xml::xpath::XXPathAPI > xXPath(
437         xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.xml.xpath.XPathAPI" ), xContext ),
438         uno::UNO_QUERY_THROW);
439 
440     xXPath->registerNS( UNISTRING("atom"), UNISTRING("http://www.w3.org/2005/Atom") );
441 
442     return *new UpdateInformationProvider(xContext, xContentIdFactory, xContentProvider, xDocumentBuilder, xXPath);
443 }
444 
445 //------------------------------------------------------------------------------
446 
~UpdateInformationProvider()447 UpdateInformationProvider::~UpdateInformationProvider()
448 {
449 }
450 
451 //------------------------------------------------------------------------------
452 
453 rtl::OUString
getConfigurationItem(uno::Reference<lang::XMultiServiceFactory> const & configurationProvider,rtl::OUString const & node,rtl::OUString const & item)454 UpdateInformationProvider::getConfigurationItem(uno::Reference<lang::XMultiServiceFactory> const & configurationProvider, rtl::OUString const & node, rtl::OUString const & item)
455 {
456     rtl::OUString sRet;
457     beans::PropertyValue aProperty;
458     aProperty.Name  = UNISTRING("nodepath");
459     aProperty.Value = uno::makeAny(node);
460 
461     uno::Sequence< uno::Any > aArgumentList( 1 );
462     aArgumentList[0] = uno::makeAny( aProperty );
463 
464     uno::Reference< container::XNameAccess > xNameAccess(
465         configurationProvider->createInstanceWithArguments(
466             UNISTRING("com.sun.star.configuration.ConfigurationAccess"),
467             aArgumentList ),
468         uno::UNO_QUERY_THROW);
469 
470     xNameAccess->getByName(item) >>= sRet;
471     return sRet;
472 }
473 
474 //------------------------------------------------------------------------------
475 
476 void
storeCommandInfo(sal_Int32 nCommandId,uno::Reference<ucb::XCommandProcessor> const & rxCommandProcessor)477 UpdateInformationProvider::storeCommandInfo(
478     sal_Int32 nCommandId,
479     uno::Reference< ucb::XCommandProcessor > const & rxCommandProcessor)
480 {
481     osl::MutexGuard aGuard(m_aMutex);
482 
483     m_nCommandId = nCommandId;
484     m_xCommandProcessor = rxCommandProcessor;
485 }
486 
487 //------------------------------------------------------------------------------
488 
489 uno::Reference< io::XInputStream >
load(const rtl::OUString & rURL)490 UpdateInformationProvider::load(const rtl::OUString& rURL)
491 {
492     uno::Reference< ucb::XContentIdentifier > xId = m_xContentIdFactory->createContentIdentifier(rURL);
493 
494     if( !xId.is() )
495         throw uno::RuntimeException(
496             UNISTRING( "unable to obtain universal content id" ), *this);
497 
498     uno::Reference< ucb::XCommandProcessor > xCommandProcessor(m_xContentProvider->queryContent(xId), uno::UNO_QUERY_THROW);
499     rtl::Reference< ActiveDataSink > aSink(new ActiveDataSink());
500 
501     ucb::OpenCommandArgument2 aOpenArgument;
502     aOpenArgument.Mode = ucb::OpenMode::DOCUMENT;
503     aOpenArgument.Priority = 32768;
504     aOpenArgument.Sink = *aSink;
505 
506     ucb::Command aCommand;
507     aCommand.Name = UNISTRING("open");
508     aCommand.Argument = uno::makeAny(aOpenArgument);
509 
510     sal_Int32 nCommandId = xCommandProcessor->createCommandIdentifier();
511 
512     storeCommandInfo(nCommandId, xCommandProcessor);
513     try
514     {
515         uno::Any aResult = xCommandProcessor->execute(aCommand, nCommandId,
516             static_cast < XCommandEnvironment *> (this));
517     }
518     catch( const uno::Exception & /* e */ )
519     {
520         storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ());
521 
522         uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY);
523         if( xCommandProcessor2.is() )
524             xCommandProcessor2->releaseCommandIdentifier(nCommandId);
525 
526         throw;
527     }
528     storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ());
529 
530     uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY);
531     if( xCommandProcessor2.is() )
532         xCommandProcessor2->releaseCommandIdentifier(nCommandId);
533 
534     return INPUT_STREAM(aSink->getInputStream());
535 }
536 
537 //------------------------------------------------------------------------------
538 
539 // TODO: docu content node
540 
541 uno::Reference< xml::dom::XElement >
getDocumentRoot(const uno::Reference<xml::dom::XNode> & rxNode)542 UpdateInformationProvider::getDocumentRoot(const uno::Reference< xml::dom::XNode >& rxNode)
543 {
544     OSL_ASSERT(m_xDocumentBuilder.is());
545 
546     uno::Reference< xml::dom::XElement > xElement(rxNode, uno::UNO_QUERY_THROW);
547 
548     // load the document referenced in 'src' attribute ..
549     if( xElement->hasAttribute( UNISTRING("src") ) )
550     {
551         uno::Reference< xml::dom::XDocument > xUpdateXML =
552             m_xDocumentBuilder->parse(load(xElement->getAttribute( UNISTRING("src") )));
553 
554         OSL_ASSERT( xUpdateXML.is() );
555 
556         if( xUpdateXML.is() )
557             return xUpdateXML->getDocumentElement();
558     }
559     // .. or return the (single) child element
560     else
561     {
562         uno::Reference< xml::dom::XNodeList> xChildNodes = rxNode->getChildNodes();
563 
564         // ignore possible #text nodes
565         sal_Int32 nmax = xChildNodes->getLength();
566         for(sal_Int32 n=0; n < nmax; n++)
567         {
568             uno::Reference< xml::dom::XElement > xChildElement(xChildNodes->item(n), uno::UNO_QUERY);
569             if( xChildElement.is() )
570             {
571                 /* Copy the content to a dedicated document since XXPathAPI->selectNodeList
572                  * seems to evaluate expression always relative to the root node.
573                  */
574                 uno::Reference< xml::dom::XDocument > xUpdateXML = m_xDocumentBuilder->newDocument();
575                 xUpdateXML->appendChild( xUpdateXML->importNode(xChildElement.get(), sal_True ) );
576                 return xUpdateXML->getDocumentElement();
577             }
578         }
579     }
580 
581     return uno::Reference< xml::dom::XElement > ();
582 }
583 
584 //------------------------------------------------------------------------------
585 
586 uno::Reference< xml::dom::XNode >
getChildNode(const uno::Reference<xml::dom::XNode> & rxNode,const rtl::OUString & rName)587 UpdateInformationProvider::getChildNode(const uno::Reference< xml::dom::XNode >& rxNode,
588                                         const rtl::OUString& rName)
589 {
590     OSL_ASSERT(m_xXPathAPI.is());
591     try {
592         return m_xXPathAPI->selectSingleNode(rxNode, UNISTRING( "./atom:" ) + rName);
593     } catch (xml::xpath::XPathException &) {
594         // ignore
595         return 0;
596     }
597 }
598 
599 //------------------------------------------------------------------------------
600 
601 uno::Reference< container::XEnumeration > SAL_CALL
getUpdateInformationEnumeration(uno::Sequence<rtl::OUString> const & repositories,rtl::OUString const & extensionId)602 UpdateInformationProvider::getUpdateInformationEnumeration(
603     uno::Sequence< rtl::OUString > const & repositories,
604     rtl::OUString const & extensionId
605 ) throw (uno::Exception, uno::RuntimeException)
606 {
607     OSL_ASSERT(m_xDocumentBuilder.is());
608 
609     // reset cancelled flag
610     m_bCancelled.reset();
611 
612     for(sal_Int32 n=0; n<repositories.getLength(); n++)
613     {
614         try
615         {
616             uno::Reference< xml::dom::XDocument > xDocument = m_xDocumentBuilder->parse(load(repositories[n]));
617             uno::Reference< xml::dom::XElement > xElement;
618 
619             if( xDocument.is() )
620                 xElement = xDocument->getDocumentElement();
621 
622             if( xElement.is() )
623             {
624                 if( xElement->getNodeName().equalsAsciiL("feed", 4) )
625                 {
626                     rtl::OUString aXPathExpression;
627 
628                     if( extensionId.getLength() > 0 )
629                         aXPathExpression = UNISTRING("//atom:entry/atom:category[@term=\'") + extensionId + UNISTRING("\']/..");
630                     else
631                         aXPathExpression = UNISTRING("//atom:entry");
632 
633                     uno::Reference< xml::dom::XNodeList > xNodeList;
634                     try {
635                         xNodeList = m_xXPathAPI->selectNodeList(xDocument.get(),
636                             aXPathExpression);
637                     } catch (xml::xpath::XPathException &) {
638                         // ignore
639                     }
640 
641                     return new UpdateInformationEnumeration(xNodeList, this);
642                 }
643                 else
644                 {
645                     return new SingleUpdateInformationEnumeration(xElement);
646                 }
647             }
648 
649             if( m_bCancelled.check() )
650                 break;
651         }
652         catch( uno::RuntimeException const& /*e*/)
653         {
654             // #i118675# ignore runtime exceptions for now
655             // especially the "unsatisfied query for interface of type com.sun.star.ucb.XCommandProcessor!" exception
656         }
657 
658         // rethrow only if last url in the list
659         catch( uno::Exception const & )
660         {
661             if( n+1 >= repositories.getLength() )
662                 throw;
663         }
664     }
665 
666     return uno::Reference< container::XEnumeration >();
667 }
668 
669 //------------------------------------------------------------------------------
670 
671 uno::Sequence< uno::Reference< xml::dom::XElement > > SAL_CALL
getUpdateInformation(uno::Sequence<rtl::OUString> const & repositories,rtl::OUString const & extensionId)672 UpdateInformationProvider::getUpdateInformation(
673     uno::Sequence< rtl::OUString > const & repositories,
674     rtl::OUString const & extensionId
675 ) throw (uno::Exception, uno::RuntimeException)
676 {
677     uno::Reference< container::XEnumeration > xEnumeration(
678         getUpdateInformationEnumeration(repositories, extensionId)
679     );
680 
681     uno::Sequence< uno::Reference< xml::dom::XElement > > aRet;
682 
683     if( xEnumeration.is() )
684     {
685         while( xEnumeration->hasMoreElements() )
686         {
687             try
688             {
689                 deployment::UpdateInformationEntry aEntry;
690                 if( (xEnumeration->nextElement() >>= aEntry ) && aEntry.UpdateDocument.is() )
691                 {
692                     sal_Int32 n = aRet.getLength();
693                     aRet.realloc(n + 1);
694                     aRet[n] = aEntry.UpdateDocument;
695                 }
696             }
697 
698             catch( const lang::WrappedTargetException& e )
699             {
700                 // command aborted, return what we have got so far
701                 if( e.TargetException.isExtractableTo( ::cppu::UnoType< ::com::sun::star::ucb::CommandAbortedException >::get() ) )
702                 {
703                     break;
704                 }
705 
706                 // ignore files that can't be loaded
707             }
708         }
709     }
710 
711     return aRet;
712 }
713 
714 //------------------------------------------------------------------------------
715 
716 void SAL_CALL
cancel()717 UpdateInformationProvider::cancel() throw (uno::RuntimeException)
718 {
719     m_bCancelled.set();
720 
721     osl::MutexGuard aGuard(m_aMutex);
722     if( m_xCommandProcessor.is() )
723         m_xCommandProcessor->abort(m_nCommandId);
724 }
725 
726 //------------------------------------------------------------------------------
727 
728 void SAL_CALL
setInteractionHandler(uno::Reference<task::XInteractionHandler> const & handler)729 UpdateInformationProvider::setInteractionHandler(
730         uno::Reference< task::XInteractionHandler > const & handler )
731     throw (uno::RuntimeException)
732 {
733     osl::MutexGuard aGuard(m_aMutex);
734     m_xInteractionHandler = handler;
735 }
736 
737 //------------------------------------------------------------------------------
738 
739 uno::Reference< task::XInteractionHandler > SAL_CALL
getInteractionHandler()740 UpdateInformationProvider::getInteractionHandler()
741     throw ( uno::RuntimeException )
742 {
743     osl::MutexGuard aGuard( m_aMutex );
744 
745     if ( m_xInteractionHandler.is() )
746         return m_xInteractionHandler;
747     else
748     {
749         try
750         {
751             // Supply an interaction handler that uses the password container
752             // service to obtain credentials without displaying a password gui.
753 
754             if ( !m_xPwContainerInteractionHandler.is() )
755                 m_xPwContainerInteractionHandler
756                     = task::PasswordContainerInteractionHandler::create(
757                         m_xContext );
758         }
759         catch ( uno::RuntimeException const & )
760         {
761             throw;
762         }
763         catch ( uno::Exception const & )
764         {
765         }
766         return m_xPwContainerInteractionHandler;
767     }
768 }
769 //------------------------------------------------------------------------------
770 
771 uno::Sequence< rtl::OUString >
getServiceNames()772 UpdateInformationProvider::getServiceNames()
773 {
774     uno::Sequence< rtl::OUString > aServiceList(1);
775     aServiceList[0] = UNISTRING( "com.sun.star.deployment.UpdateInformationProvider");
776     return aServiceList;
777 };
778 
779 //------------------------------------------------------------------------------
780 
781 rtl::OUString
getImplName()782 UpdateInformationProvider::getImplName()
783 {
784     return UNISTRING( "vnd.sun.UpdateInformationProvider");
785 }
786 
787 //------------------------------------------------------------------------------
788 
789 rtl::OUString SAL_CALL
getImplementationName()790 UpdateInformationProvider::getImplementationName() throw (uno::RuntimeException)
791 {
792     return getImplName();
793 }
794 
795 //------------------------------------------------------------------------------
796 
797 uno::Sequence< rtl::OUString > SAL_CALL
getSupportedServiceNames()798 UpdateInformationProvider::getSupportedServiceNames() throw (uno::RuntimeException)
799 {
800     return getServiceNames();
801 }
802 
803 //------------------------------------------------------------------------------
804 
805 sal_Bool SAL_CALL
supportsService(rtl::OUString const & serviceName)806 UpdateInformationProvider::supportsService( rtl::OUString const & serviceName ) throw (uno::RuntimeException)
807 {
808     uno::Sequence< rtl::OUString > aServiceNameList = getServiceNames();
809 
810     for( sal_Int32 n=0; n < aServiceNameList.getLength(); n++ )
811         if( aServiceNameList[n].equals(serviceName) )
812             return sal_True;
813 
814     return sal_False;
815 }
816 
817 } // anonymous namespace
818 
819 //------------------------------------------------------------------------------
820 
821 static uno::Reference<uno::XInterface> SAL_CALL
createInstance(uno::Reference<uno::XComponentContext> const & xContext)822 createInstance(uno::Reference<uno::XComponentContext> const & xContext)
823 {
824     return UpdateInformationProvider::createInstance(xContext);
825 }
826 
827 //------------------------------------------------------------------------------
828 
829 static const cppu::ImplementationEntry kImplementations_entries[] =
830 {
831     {
832         createInstance,
833         UpdateInformationProvider::getImplName,
834         UpdateInformationProvider::getServiceNames,
835         cppu::createSingleComponentFactory,
836         NULL,
837         0
838     },
839     { NULL, NULL, NULL, NULL, NULL, 0 }
840 } ;
841 
842 //------------------------------------------------------------------------------
843 
844 extern "C" void SAL_CALL
component_getImplementationEnvironment(const sal_Char ** aEnvTypeName,uno_Environment **)845 component_getImplementationEnvironment( const sal_Char **aEnvTypeName, uno_Environment **)
846 {
847     *aEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME ;
848 }
849 
850 //------------------------------------------------------------------------------
851 
852 extern "C" void *
component_getFactory(const sal_Char * pszImplementationName,void * pServiceManager,void * pRegistryKey)853 component_getFactory(const sal_Char *pszImplementationName, void *pServiceManager, void *pRegistryKey)
854 {
855     return cppu::component_getFactoryHelper(
856         pszImplementationName,
857         pServiceManager,
858         pRegistryKey,
859         kImplementations_entries) ;
860 }
861 
862