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_desktop.hxx"
26 
27 #include "vcl/svapp.hxx"
28 #include "vcl/msgbox.hxx"
29 
30 #include "vos/mutex.hxx"
31 
32 #include "toolkit/helper/vclunohelper.hxx"
33 
34 #include "com/sun/star/beans/XPropertySet.hpp"
35 
36 #include "dp_gui_dialog2.hxx"
37 #include "dp_gui_extensioncmdqueue.hxx"
38 #include "dp_gui_theextmgr.hxx"
39 #include "dp_gui_theextmgr.hxx"
40 #include "dp_identifier.hxx"
41 #include "dp_update.hxx"
42 
43 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
44 
45 #define USER_PACKAGE_MANAGER    OUSTR("user")
46 #define SHARED_PACKAGE_MANAGER  OUSTR("shared")
47 #define BUNDLED_PACKAGE_MANAGER OUSTR("bundled")
48 
49 using namespace ::com::sun::star;
50 using ::rtl::OUString;
51 
52 namespace dp_gui {
53 
54 //------------------------------------------------------------------------------
55 
56 ::rtl::Reference< TheExtensionManager > TheExtensionManager::s_ExtMgr;
57 
58 //------------------------------------------------------------------------------
59 //                             TheExtensionManager
60 //------------------------------------------------------------------------------
61 
TheExtensionManager(Window * pParent,const uno::Reference<uno::XComponentContext> & xContext)62 TheExtensionManager::TheExtensionManager( Window *pParent,
63                                           const uno::Reference< uno::XComponentContext > &xContext ) :
64     m_xContext( xContext ),
65     m_pParent( pParent ),
66     m_pExtMgrDialog( NULL ),
67     m_pUpdReqDialog( NULL ),
68     m_pExecuteCmdQueue( NULL )
69 {
70     m_xExtensionManager = deployment::ExtensionManager::get( xContext );
71     m_xExtensionManager->addModifyListener( this );
72 
73     uno::Reference< lang::XMultiServiceFactory > xConfig(
74         xContext->getServiceManager()->createInstanceWithContext(
75             OUSTR("com.sun.star.configuration.ConfigurationProvider"), xContext ), uno::UNO_QUERY_THROW);
76     uno::Any args[1];
77     beans::PropertyValue aValue( OUSTR("nodepath"), 0, uno::Any( OUSTR("/org.openoffice.Office.OptionsDialog/Nodes") ),
78                                  beans::PropertyState_DIRECT_VALUE );
79     args[0] <<= aValue;
80     m_xNameAccessNodes = uno::Reference< container::XNameAccess >(
81         xConfig->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"),
82                                               uno::Sequence< uno::Any >( args, 1 )), uno::UNO_QUERY_THROW);
83 
84     // get the 'get more extensions here' url
85     uno::Reference< container::XNameAccess > xNameAccessRepositories;
86     beans::PropertyValue aValue2( OUSTR("nodepath"), 0, uno::Any( OUSTR("/org.openoffice.Office.ExtensionManager/ExtensionRepositories") ),
87                                   beans::PropertyState_DIRECT_VALUE );
88     args[0] <<= aValue2;
89     xNameAccessRepositories = uno::Reference< container::XNameAccess > (
90         xConfig->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"),
91                                               uno::Sequence< uno::Any >( args, 1 )), uno::UNO_QUERY_THROW);
92     try
93     {   //throws css::container::NoSuchElementException, css::lang::WrappedTargetException
94         uno::Any value = xNameAccessRepositories->getByName( OUSTR( "WebsiteLink" ) );
95         m_sGetExtensionsURL = value.get< OUString > ();
96      }
97     catch ( uno::Exception& )
98     {}
99 
100     if ( dp_misc::office_is_running() )
101     {
102 		// the registration should be done after the construction has been ended
103 		// otherwise an exception prevents object creation, but it is registered as a listener
104         m_xDesktop.set( xContext->getServiceManager()->createInstanceWithContext(
105                             OUSTR("com.sun.star.frame.Desktop"), xContext ), uno::UNO_QUERY );
106         if ( m_xDesktop.is() )
107             m_xDesktop->addTerminateListener( this );
108     }
109 }
110 
111 //------------------------------------------------------------------------------
~TheExtensionManager()112 TheExtensionManager::~TheExtensionManager()
113 {
114     if ( m_pUpdReqDialog )
115         delete m_pUpdReqDialog;
116     if ( m_pExtMgrDialog )
117         delete m_pExtMgrDialog;
118     if ( m_pExecuteCmdQueue )
119         delete m_pExecuteCmdQueue;
120 }
121 
122 //------------------------------------------------------------------------------
createDialog(const bool bCreateUpdDlg)123 void TheExtensionManager::createDialog( const bool bCreateUpdDlg )
124 {
125     const ::vos::OGuard guard( Application::GetSolarMutex() );
126 
127     if ( bCreateUpdDlg )
128     {
129         if ( !m_pUpdReqDialog )
130         {
131             m_pUpdReqDialog = new UpdateRequiredDialog( NULL, this );
132             delete m_pExecuteCmdQueue;
133             m_pExecuteCmdQueue = new ExtensionCmdQueue( (DialogHelper*) m_pUpdReqDialog, this, m_xContext );
134             createPackageList();
135         }
136     }
137     else if ( !m_pExtMgrDialog )
138     {
139         m_pExtMgrDialog = new ExtMgrDialog( m_pParent, this );
140         delete m_pExecuteCmdQueue;
141         m_pExecuteCmdQueue = new ExtensionCmdQueue( (DialogHelper*) m_pExtMgrDialog, this, m_xContext );
142         m_pExtMgrDialog->setGetExtensionsURL( m_sGetExtensionsURL );
143         createPackageList();
144     }
145 }
146 
147 //------------------------------------------------------------------------------
Show()148 void TheExtensionManager::Show()
149 {
150     const ::vos::OGuard guard( Application::GetSolarMutex() );
151 
152     getDialog()->Show();
153 }
154 
155 //------------------------------------------------------------------------------
SetText(const::rtl::OUString & rTitle)156 void TheExtensionManager::SetText( const ::rtl::OUString &rTitle )
157 {
158     const ::vos::OGuard guard( Application::GetSolarMutex() );
159 
160     getDialog()->SetText( rTitle );
161 }
162 
163 //------------------------------------------------------------------------------
ToTop(sal_uInt16 nFlags)164 void TheExtensionManager::ToTop( sal_uInt16 nFlags )
165 {
166     const ::vos::OGuard guard( Application::GetSolarMutex() );
167 
168     getDialog()->ToTop( nFlags );
169 }
170 
171 //------------------------------------------------------------------------------
Close()172 bool TheExtensionManager::Close()
173 {
174     if ( m_pExtMgrDialog )
175         return m_pExtMgrDialog->Close();
176     else if ( m_pUpdReqDialog )
177         return m_pUpdReqDialog->Close();
178     else
179         return true;
180 }
181 
182 //------------------------------------------------------------------------------
execute()183 sal_Int16 TheExtensionManager::execute()
184 {
185     sal_Int16 nRet = 0;
186 
187     if ( m_pUpdReqDialog )
188     {
189         nRet = m_pUpdReqDialog->Execute();
190         delete m_pUpdReqDialog;
191         m_pUpdReqDialog = NULL;
192     }
193 
194     return nRet;
195 }
196 
197 //------------------------------------------------------------------------------
isVisible()198 bool TheExtensionManager::isVisible()
199 {
200     return getDialog()->IsVisible();
201 }
202 
203 //------------------------------------------------------------------------------
checkUpdates(bool,bool)204 bool TheExtensionManager::checkUpdates( bool /* bShowUpdateOnly */, bool /*bParentVisible*/ )
205 {
206     std::vector< uno::Reference< deployment::XPackage >  > vEntries;
207     uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
208 
209     try {
210         xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
211                                                               uno::Reference< ucb::XCommandEnvironment >() );
212     } catch ( deployment::DeploymentException & ) {
213         return false;
214     } catch ( ucb::CommandFailedException & ) {
215         return false;
216     } catch ( ucb::CommandAbortedException & ) {
217         return false;
218     } catch ( lang::IllegalArgumentException & e ) {
219         throw uno::RuntimeException( e.Message, e.Context );
220     }
221 
222     for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i )
223     {
224 		uno::Reference< deployment::XPackage > xPackage = dp_misc::getExtensionWithHighestVersion(xAllPackages[i]);
225 		OSL_ASSERT(xPackage.is());
226         if ( xPackage.is() )
227         {
228 			vEntries.push_back( xPackage );
229         }
230     }
231 
232     m_pExecuteCmdQueue->checkForUpdates( vEntries );
233     return true;
234 }
235 
236 //------------------------------------------------------------------------------
installPackage(const OUString & rPackageURL,bool bWarnUser)237 bool TheExtensionManager::installPackage( const OUString &rPackageURL, bool bWarnUser )
238 {
239     if ( rPackageURL.getLength() == 0 )
240         return false;
241 
242     createDialog( false );
243 
244     bool bInstall = true;
245     bool bInstallForAll = false;
246 
247     // DV! missing function is read only repository from extension manager
248     if ( !bWarnUser && ! m_xExtensionManager->isReadOnlyRepository( SHARED_PACKAGE_MANAGER ) )
249         bInstall = getDialogHelper()->installForAllUsers( bInstallForAll );
250 
251     if ( !bInstall )
252         return false;
253 
254     if ( bInstallForAll )
255         m_pExecuteCmdQueue->addExtension( rPackageURL, SHARED_PACKAGE_MANAGER, false );
256     else
257         m_pExecuteCmdQueue->addExtension( rPackageURL, USER_PACKAGE_MANAGER, bWarnUser );
258 
259     return true;
260 }
261 
262 //------------------------------------------------------------------------------
queryTermination()263 bool TheExtensionManager::queryTermination()
264 {
265     if ( dp_misc::office_is_running() )
266         return true;
267     // the standalone application unopkg must not close ( and quit ) the dialog
268     // when there are still actions in the queue
269     return true;
270 }
271 
272 //------------------------------------------------------------------------------
terminateDialog()273 void TheExtensionManager::terminateDialog()
274 {
275     if ( ! dp_misc::office_is_running() )
276     {
277         const ::vos::OGuard guard( Application::GetSolarMutex() );
278         delete m_pExtMgrDialog;
279         m_pExtMgrDialog = NULL;
280         delete m_pUpdReqDialog;
281         m_pUpdReqDialog = NULL;
282         Application::Quit();
283     }
284 }
285 
286 //------------------------------------------------------------------------------
createPackageList()287 void TheExtensionManager::createPackageList()
288 {
289     uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
290 
291     try {
292         xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
293                                                               uno::Reference< ucb::XCommandEnvironment >() );
294     } catch ( deployment::DeploymentException & ) {
295         return;
296     } catch ( ucb::CommandFailedException & ) {
297         return;
298     } catch ( ucb::CommandAbortedException & ) {
299         return;
300     } catch ( lang::IllegalArgumentException & e ) {
301         throw uno::RuntimeException( e.Message, e.Context );
302     }
303 
304     for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i )
305     {
306         uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i];
307 
308         for ( sal_Int32 j = 0; j < xPackageList.getLength(); ++j )
309         {
310             uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
311             if ( xPackage.is() )
312             {
313                 PackageState eState = getPackageState( xPackage );
314                 getDialogHelper()->addPackageToList( xPackage );
315                 // When the package is enabled, we can stop here, otherwise we have to look for
316                 // another version of this package
317                 if ( ( eState == REGISTERED ) || ( eState == NOT_AVAILABLE ) )
318                     break;
319             }
320         }
321     }
322 
323     uno::Sequence< uno::Reference< deployment::XPackage > > xNoLicPackages;
324     xNoLicPackages = m_xExtensionManager->getExtensionsWithUnacceptedLicenses( SHARED_PACKAGE_MANAGER,
325                                                                                uno::Reference< ucb::XCommandEnvironment >() );
326     for ( sal_Int32 i = 0; i < xNoLicPackages.getLength(); ++i )
327     {
328         uno::Reference< deployment::XPackage > xPackage = xNoLicPackages[i];
329         if ( xPackage.is() )
330         {
331             getDialogHelper()->addPackageToList( xPackage, true );
332         }
333     }
334 }
335 
336 //------------------------------------------------------------------------------
getPackageState(const uno::Reference<deployment::XPackage> & xPackage) const337 PackageState TheExtensionManager::getPackageState( const uno::Reference< deployment::XPackage > &xPackage ) const
338 {
339     try {
340         beans::Optional< beans::Ambiguous< sal_Bool > > option(
341             xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
342                                     uno::Reference< ucb::XCommandEnvironment >() ) );
343         if ( option.IsPresent )
344         {
345             ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
346             if ( reg.IsAmbiguous )
347                 return AMBIGUOUS;
348             else
349                 return reg.Value ? REGISTERED : NOT_REGISTERED;
350         }
351         else
352             return NOT_AVAILABLE;
353     }
354     catch ( uno::RuntimeException & ) {
355         throw;
356     }
357     catch ( uno::Exception & exc) {
358         (void) exc;
359         OSL_ENSURE( 0, ::rtl::OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
360         return NOT_AVAILABLE;
361     }
362 }
363 
364 //------------------------------------------------------------------------------
isReadOnly(const uno::Reference<deployment::XPackage> & xPackage) const365 bool TheExtensionManager::isReadOnly( const uno::Reference< deployment::XPackage > &xPackage ) const
366 {
367     if ( m_xExtensionManager.is() && xPackage.is() )
368     {
369         return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() );
370     }
371     else
372         return true;
373 }
374 
375 //------------------------------------------------------------------------------
376 // The function investigates if the extension supports options.
supportsOptions(const uno::Reference<deployment::XPackage> & xPackage) const377 bool TheExtensionManager::supportsOptions( const uno::Reference< deployment::XPackage > &xPackage ) const
378 {
379     bool bOptions = false;
380 
381     if ( ! xPackage->isBundle() )
382         return false;
383 
384     beans::Optional< OUString > aId = xPackage->getIdentifier();
385 
386     //a bundle must always have an id
387     OSL_ASSERT( aId.IsPresent );
388 
389     //iterate over all available nodes
390     uno::Sequence< OUString > seqNames = m_xNameAccessNodes->getElementNames();
391 
392     for ( int i = 0; i < seqNames.getLength(); i++ )
393     {
394         uno::Any anyNode = m_xNameAccessNodes->getByName( seqNames[i] );
395         //If we have a node then then it must contain the set of leaves. This is part of OptionsDialog.xcs
396         uno::Reference< XInterface> xIntNode = anyNode.get< uno::Reference< XInterface > >();
397         uno::Reference< container::XNameAccess > xNode( xIntNode, uno::UNO_QUERY_THROW );
398 
399         uno::Any anyLeaves = xNode->getByName( OUSTR("Leaves") );
400         uno::Reference< XInterface > xIntLeaves = anyLeaves.get< uno::Reference< XInterface > >();
401         uno::Reference< container::XNameAccess > xLeaves( xIntLeaves, uno::UNO_QUERY_THROW );
402 
403         //iterate over all available leaves
404         uno::Sequence< OUString > seqLeafNames = xLeaves->getElementNames();
405         for ( int j = 0; j < seqLeafNames.getLength(); j++ )
406         {
407             uno::Any anyLeaf = xLeaves->getByName( seqLeafNames[j] );
408             uno::Reference< XInterface > xIntLeaf = anyLeaf.get< uno::Reference< XInterface > >();
409             uno::Reference< beans::XPropertySet > xLeaf( xIntLeaf, uno::UNO_QUERY_THROW );
410             //investigate the Id property if it matches the extension identifier which
411             //has been passed in.
412             uno::Any anyValue = xLeaf->getPropertyValue( OUSTR("Id") );
413 
414             OUString sId = anyValue.get< OUString >();
415             if ( sId == aId.Value )
416             {
417                 bOptions = true;
418                 break;
419             }
420         }
421         if ( bOptions )
422             break;
423     }
424     return bOptions;
425 }
426 
427 //------------------------------------------------------------------------------
428 // XEventListener
disposing(lang::EventObject const & rEvt)429 void TheExtensionManager::disposing( lang::EventObject const & rEvt )
430     throw ( uno::RuntimeException )
431 {
432     bool shutDown = (rEvt.Source == m_xDesktop);
433 
434     if ( shutDown && m_xDesktop.is() )
435     {
436         m_xDesktop->removeTerminateListener( this );
437         m_xDesktop.clear();
438     }
439 
440     if ( shutDown )
441     {
442         if ( dp_misc::office_is_running() )
443         {
444             const ::vos::OGuard guard( Application::GetSolarMutex() );
445             delete m_pExtMgrDialog;
446             m_pExtMgrDialog = NULL;
447             delete m_pUpdReqDialog;
448             m_pUpdReqDialog = NULL;
449         }
450         s_ExtMgr.clear();
451     }
452 }
453 
454 //------------------------------------------------------------------------------
455 // XTerminateListener
queryTermination(::lang::EventObject const &)456 void TheExtensionManager::queryTermination( ::lang::EventObject const & )
457     throw ( frame::TerminationVetoException, uno::RuntimeException )
458 {
459     DialogHelper *pDialogHelper = getDialogHelper();
460 
461     if ( m_pExecuteCmdQueue->isBusy() || ( pDialogHelper && pDialogHelper->isBusy() ) )
462     {
463         ToTop( TOTOP_RESTOREWHENMIN );
464         throw frame::TerminationVetoException(
465             OUSTR("The office cannot be closed while the Extension Manager is running"),
466             uno::Reference<XInterface>(static_cast<frame::XTerminateListener*>(this), uno::UNO_QUERY));
467     }
468     else
469     {
470         if ( m_pExtMgrDialog )
471             m_pExtMgrDialog->Close();
472         if ( m_pUpdReqDialog )
473             m_pUpdReqDialog->Close();
474     }
475 }
476 
477 //------------------------------------------------------------------------------
notifyTermination(::lang::EventObject const & rEvt)478 void TheExtensionManager::notifyTermination( ::lang::EventObject const & rEvt )
479     throw ( uno::RuntimeException )
480 {
481     disposing( rEvt );
482 }
483 
484 //------------------------------------------------------------------------------
485 // XModifyListener
modified(::lang::EventObject const &)486 void TheExtensionManager::modified( ::lang::EventObject const & /*rEvt*/ )
487     throw ( uno::RuntimeException )
488 {
489     getDialogHelper()->prepareChecking();
490     createPackageList();
491     getDialogHelper()->checkEntries();
492 }
493 
494 //------------------------------------------------------------------------------
get(const uno::Reference<uno::XComponentContext> & xContext,const uno::Reference<awt::XWindow> & xParent,const OUString & extensionURL)495 ::rtl::Reference< TheExtensionManager > TheExtensionManager::get( const uno::Reference< uno::XComponentContext > &xContext,
496                                                                   const uno::Reference< awt::XWindow > &xParent,
497                                                                   const OUString & extensionURL )
498 {
499     if ( s_ExtMgr.is() )
500     {
501         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
502         if ( extensionURL.getLength() )
503             s_ExtMgr->installPackage( extensionURL, true );
504         return s_ExtMgr;
505     }
506 
507     Window * pParent = DIALOG_NO_PARENT;
508     if ( xParent.is() )
509         pParent = VCLUnoHelper::GetWindow(xParent);
510 
511     ::rtl::Reference<TheExtensionManager> that( new TheExtensionManager( pParent, xContext ) );
512 
513     const ::vos::OGuard guard( Application::GetSolarMutex() );
514     if ( ! s_ExtMgr.is() )
515     {
516         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
517         s_ExtMgr = that;
518     }
519 
520     if ( extensionURL.getLength() )
521         s_ExtMgr->installPackage( extensionURL, true );
522 
523     return s_ExtMgr;
524 }
525 
526 } //namespace dp_gui
527 
528