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