xref: /trunk/main/desktop/source/app/check_ext_deps.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 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_desktop.hxx"
25 
26 #include "osl/file.hxx"
27 #include "osl/mutex.hxx"
28 
29 #include <rtl/bootstrap.hxx>
30 #include <rtl/ustring.hxx>
31 #include <rtl/logfile.hxx>
32 #include "cppuhelper/compbase3.hxx"
33 
34 #include "vcl/wrkwin.hxx"
35 #include "vcl/timer.hxx"
36 
37 #include <unotools/configmgr.hxx>
38 #include "toolkit/helper/vclunohelper.hxx"
39 
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/sequence.hxx>
42 #include <cppuhelper/bootstrap.hxx>
43 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/beans/NamedValue.hpp>
46 #include "com/sun/star/deployment/XPackage.hpp"
47 #include "com/sun/star/deployment/ExtensionManager.hpp"
48 #include "com/sun/star/deployment/LicenseException.hpp"
49 #include "com/sun/star/deployment/ui/LicenseDialog.hpp"
50 #include <com/sun/star/task/XJob.hpp>
51 #include <com/sun/star/task/XJobExecutor.hpp>
52 #include <com/sun/star/task/XInteractionApprove.hpp>
53 #include <com/sun/star/task/XInteractionAbort.hpp>
54 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
55 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
56 #include <com/sun/star/util/XChangesBatch.hpp>
57 
58 #include "app.hxx"
59 
60 #include "../deployment/inc/dp_misc.h"
61 
62 using rtl::OUString;
63 using namespace desktop;
64 using namespace com::sun::star;
65 
66 #define UNISTRING(s) OUString(RTL_CONSTASCII_USTRINGPARAM(s))
67 
68 namespace
69 {
70 //For use with XExtensionManager.synchronize
71 class SilentCommandEnv
72     : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment,
73                                       task::XInteractionHandler,
74                                       ucb::XProgressHandler >
75 {
76     Desktop    *mpDesktop;
77     sal_Int32   mnLevel;
78     sal_Int32   mnProgress;
79 
80 public:
81              SilentCommandEnv( Desktop* pDesktop );
82     virtual ~SilentCommandEnv();
83 
84     // XCommandEnvironment
85     virtual uno::Reference<task::XInteractionHandler > SAL_CALL
86     getInteractionHandler();
87     virtual uno::Reference<ucb::XProgressHandler >
88     SAL_CALL getProgressHandler();
89 
90     // XInteractionHandler
91     virtual void SAL_CALL handle(
92         uno::Reference<task::XInteractionRequest > const & xRequest );
93 
94     // XProgressHandler
95     virtual void SAL_CALL push( uno::Any const & Status );
96     virtual void SAL_CALL update( uno::Any const & Status );
97     virtual void SAL_CALL pop();
98 };
99 
100 //-----------------------------------------------------------------------------
SilentCommandEnv(Desktop * pDesktop)101 SilentCommandEnv::SilentCommandEnv( Desktop* pDesktop )
102 {
103     mpDesktop = pDesktop;
104     mnLevel = 0;
105     mnProgress = 25;
106 }
107 
108 //-----------------------------------------------------------------------------
~SilentCommandEnv()109 SilentCommandEnv::~SilentCommandEnv()
110 {
111     mpDesktop->SetSplashScreenText( OUString() );
112 }
113 
114 //-----------------------------------------------------------------------------
getInteractionHandler()115 Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
116 {
117     return this;
118 }
119 
120 //-----------------------------------------------------------------------------
getProgressHandler()121 Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
122 {
123     return this;
124 }
125 
126 //-----------------------------------------------------------------------------
127 // XInteractionHandler
handle(Reference<task::XInteractionRequest> const & xRequest)128 void SilentCommandEnv::handle( Reference< task::XInteractionRequest> const & xRequest )
129 {
130     deployment::LicenseException licExc;
131 
132     uno::Any request( xRequest->getRequest() );
133     bool bApprove = true;
134 
135     if ( request >>= licExc )
136     {
137         uno::Reference< uno::XComponentContext > xContext = comphelper_getProcessComponentContext();
138         uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
139             deployment::ui::LicenseDialog::create(
140             xContext, VCLUnoHelper::GetInterface( NULL ),
141             licExc.ExtensionName, licExc.Text ) );
142         sal_Int16 res = xDialog->execute();
143         if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
144             bApprove = false;
145         else if ( res == ui::dialogs::ExecutableDialogResults::OK )
146             bApprove = true;
147         else
148         {
149             OSL_ASSERT(0);
150         }
151     }
152 
153     // We approve everything here
154     uno::Sequence< Reference< task::XInteractionContinuation > > conts( xRequest->getContinuations() );
155     Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
156     sal_Int32 len = conts.getLength();
157 
158     for ( sal_Int32 pos = 0; pos < len; ++pos )
159     {
160         if ( bApprove )
161         {
162             uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
163             if ( xInteractionApprove.is() )
164                 xInteractionApprove->select();
165         }
166         else
167         {
168             uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
169             if ( xInteractionAbort.is() )
170                 xInteractionAbort->select();
171         }
172     }
173 }
174 
175 //-----------------------------------------------------------------------------
176 // XProgressHandler
push(uno::Any const & rStatus)177 void SilentCommandEnv::push( uno::Any const & rStatus )
178 {
179     OUString sText;
180     mnLevel += 1;
181 
182     if ( rStatus.hasValue() && ( rStatus >>= sText) )
183     {
184         if ( mnLevel <= 3 )
185             mpDesktop->SetSplashScreenText( sText );
186         else
187             mpDesktop->SetSplashScreenProgress( ++mnProgress );
188     }
189 }
190 
191 //-----------------------------------------------------------------------------
update(uno::Any const & rStatus)192 void SilentCommandEnv::update( uno::Any const & rStatus )
193 {
194     OUString sText;
195     if ( rStatus.hasValue() && ( rStatus >>= sText) )
196     {
197         mpDesktop->SetSplashScreenText( sText );
198     }
199 }
200 
201 //-----------------------------------------------------------------------------
pop()202 void SilentCommandEnv::pop()
203 {
204     mnLevel -= 1;
205 }
206 
207 } // end namespace
208 
209 //-----------------------------------------------------------------------------
210 //-----------------------------------------------------------------------------
211 //-----------------------------------------------------------------------------
212 static const OUString sConfigSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) );
213 static const OUString sAccessSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) );
214 //------------------------------------------------------------------------------
impl_showExtensionDialog(uno::Reference<uno::XComponentContext> & xContext)215 static sal_Int16 impl_showExtensionDialog( uno::Reference< uno::XComponentContext > &xContext )
216 {
217     rtl::OUString sServiceName = UNISTRING("com.sun.star.deployment.ui.UpdateRequiredDialog");
218     uno::Reference< uno::XInterface > xService;
219     sal_Int16 nRet = 0;
220 
221     uno::Reference< lang::XMultiComponentFactory > xServiceManager( xContext->getServiceManager() );
222     if( !xServiceManager.is() )
223         throw uno::RuntimeException(
224             UNISTRING( "impl_showExtensionDialog(): unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () );
225 
226     xService = xServiceManager->createInstanceWithContext( sServiceName, xContext );
227     uno::Reference< ui::dialogs::XExecutableDialog > xExecuteable( xService, uno::UNO_QUERY );
228     if ( xExecuteable.is() )
229         nRet = xExecuteable->execute();
230 
231     return nRet;
232 }
233 
234 //------------------------------------------------------------------------------
235 // Check dependencies of all packages
236 //------------------------------------------------------------------------------
impl_checkDependencies(const uno::Reference<uno::XComponentContext> & xContext)237 static bool impl_checkDependencies( const uno::Reference< uno::XComponentContext > &xContext )
238 {
239     uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
240     uno::Reference< deployment::XExtensionManager > xExtensionManager = deployment::ExtensionManager::get( xContext );
241 
242     if ( !xExtensionManager.is() )
243     {
244         OSL_ENSURE( 0, "Could not get the Extension Manager!" );
245         return true;
246     }
247 
248     try {
249         xAllPackages = xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
250                                                             uno::Reference< ucb::XCommandEnvironment >() );
251     }
252     catch ( deployment::DeploymentException & ) { return true; }
253     catch ( ucb::CommandFailedException & ) { return true; }
254     catch ( ucb::CommandAbortedException & ) { return true; }
255     catch ( lang::IllegalArgumentException & e ) {
256         throw uno::RuntimeException( e.Message, e.Context );
257     }
258 
259     sal_Int32 nMax = 2;
260 #ifdef DEBUG
261     nMax = 3;
262 #endif
263 
264     for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i )
265     {
266         uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i];
267 
268         for ( sal_Int32 j = 0; (j<nMax) && (j < xPackageList.getLength()); ++j )
269         {
270             uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
271             if ( xPackage.is() )
272             {
273                 bool bRegistered = false;
274                 try {
275                     beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
276                                                                                                     uno::Reference< ucb::XCommandEnvironment >() ) );
277                     if ( option.IsPresent )
278                     {
279                         ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
280                         if ( reg.IsAmbiguous )
281                             bRegistered = false;
282                         else
283                             bRegistered = reg.Value ? true : false;
284                     }
285                     else
286                         bRegistered = false;
287                 }
288                 catch ( uno::RuntimeException & ) { throw; }
289                 catch ( uno::Exception & exc) {
290                     (void) exc;
291                     OSL_ENSURE( 0, ::rtl::OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
292                 }
293 
294                 if ( bRegistered )
295                 {
296                     bool bDependenciesValid = false;
297                     try {
298                         bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
299                     }
300                     catch ( deployment::DeploymentException & ) {}
301                     if ( ! bDependenciesValid )
302                     {
303                         return false;
304                     }
305                 }
306             }
307         }
308     }
309     return true;
310 }
311 
312 //------------------------------------------------------------------------------
313 // resets the 'check needed' flag (needed, if aborted)
314 //------------------------------------------------------------------------------
impl_setNeedsCompatCheck()315 static void impl_setNeedsCompatCheck()
316 {
317     try {
318         Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
319         // get configuration provider
320         Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >(
321                 xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW);
322 
323         Sequence< Any > theArgs(1);
324         beans::NamedValue v( OUString::createFromAscii("NodePath"),
325                       makeAny( OUString::createFromAscii("org.openoffice.Setup/Office") ) );
326         theArgs[0] <<= v;
327         Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
328             theConfigProvider->createInstanceWithArguments( sAccessSrvc, theArgs ), UNO_QUERY_THROW );
329 
330         Any value = makeAny( OUString::createFromAscii("never") );
331 
332         pset->setPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID"), value );
333         Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
334     }
335     catch (const Exception&) {}
336 }
337 
338 //------------------------------------------------------------------------------
impl_check()339 static bool impl_check()
340 {
341     uno::Reference< uno::XComponentContext > xContext = comphelper_getProcessComponentContext();
342 
343     bool bDependenciesValid = impl_checkDependencies( xContext );
344 
345     short nRet = 0;
346 
347     if ( !bDependenciesValid )
348         nRet = impl_showExtensionDialog( xContext );
349 
350     if ( nRet == -1 )
351     {
352         impl_setNeedsCompatCheck();
353         return true;
354     }
355     else
356         return false;
357 }
358 
359 //------------------------------------------------------------------------------
360 // to check if we need checking the dependencies of the extensions again, we compare
361 // the build id of the office with the one of the last check
362 //------------------------------------------------------------------------------
impl_needsCompatCheck()363 static bool impl_needsCompatCheck()
364 {
365     bool bNeedsCheck = false;
366     rtl::OUString aLastCheckBuildID;
367     rtl::OUString aCurrentBuildID( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
368     rtl::Bootstrap::expandMacros( aCurrentBuildID );
369 
370     try {
371         Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
372         // get configuration provider
373         Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >(
374                 xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW);
375 
376         Sequence< Any > theArgs(1);
377         beans::NamedValue v( OUString::createFromAscii("NodePath"),
378                       makeAny( OUString::createFromAscii("org.openoffice.Setup/Office") ) );
379         theArgs[0] <<= v;
380         Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
381             theConfigProvider->createInstanceWithArguments( sAccessSrvc, theArgs ), UNO_QUERY_THROW );
382 
383         Any result = pset->getPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID") );
384 
385         result >>= aLastCheckBuildID;
386         if ( aLastCheckBuildID != aCurrentBuildID )
387         {
388             bNeedsCheck = true;
389             result <<= aCurrentBuildID;
390             pset->setPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID"), result );
391             Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
392         }
393 #ifdef DEBUG
394         bNeedsCheck = true;
395 #endif
396     }
397     catch (const Exception&) {}
398 
399     return bNeedsCheck;
400 }
401 
402 //------------------------------------------------------------------------------
403 // Do we need to check the dependencies of the extensions?
404 // When there are unresolved issues, we can't continue with startup
CheckExtensionDependencies()405 sal_Bool Desktop::CheckExtensionDependencies()
406 {
407     sal_Bool bAbort = false;
408 
409     if ( impl_needsCompatCheck() )
410         bAbort = impl_check();
411 
412     return bAbort;
413 }
414 
SynchronizeExtensionRepositories()415 void Desktop::SynchronizeExtensionRepositories()
416 {
417     RTL_LOGFILE_CONTEXT(aLog,"desktop (jl) ::Desktop::SynchronizeExtensionRepositories");
418     dp_misc::syncRepositories( new SilentCommandEnv( this ) );
419 }
420