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
28
29 #include <dp_gui_handleversionexception.hxx>
30
31 #include "sal/config.h"
32
33 #include <cstddef>
34
35 #include "com/sun/star/beans/PropertyValue.hpp"
36 #include "com/sun/star/beans/NamedValue.hpp"
37
38 #include "com/sun/star/deployment/DependencyException.hpp"
39 #include "com/sun/star/deployment/LicenseException.hpp"
40 #include "com/sun/star/deployment/VersionException.hpp"
41 #include "com/sun/star/deployment/InstallException.hpp"
42 #include "com/sun/star/deployment/PlatformException.hpp"
43
44 #include "com/sun/star/deployment/ui/LicenseDialog.hpp"
45 #include "com/sun/star/deployment/DeploymentException.hpp"
46 #include "com/sun/star/deployment/UpdateInformationProvider.hpp"
47 #include "com/sun/star/deployment/XPackage.hpp"
48
49 #include "com/sun/star/task/XAbortChannel.hpp"
50 #include "com/sun/star/task/XInteractionAbort.hpp"
51 #include "com/sun/star/task/XInteractionApprove.hpp"
52
53 #include "com/sun/star/ucb/CommandAbortedException.hpp"
54 #include "com/sun/star/ucb/CommandFailedException.hpp"
55 #include "com/sun/star/ucb/XCommandEnvironment.hpp"
56
57 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
58
59 #include "com/sun/star/uno/Reference.hxx"
60 #include "com/sun/star/uno/RuntimeException.hpp"
61 #include "com/sun/star/uno/Sequence.hxx"
62 #include "com/sun/star/uno/XInterface.hpp"
63 #include "com/sun/star/uno/TypeClass.hpp"
64 #include "osl/diagnose.h"
65 #include "osl/mutex.hxx"
66 #include "rtl/ref.hxx"
67 #include "rtl/ustring.h"
68 #include "rtl/ustring.hxx"
69 #include "sal/types.h"
70 #include "ucbhelper/content.hxx"
71 #include "cppuhelper/exc_hlp.hxx"
72 #include "cppuhelper/implbase3.hxx"
73 #include "comphelper/anytostring.hxx"
74 #include "vcl/msgbox.hxx"
75 #include "toolkit/helper/vclunohelper.hxx"
76 #include "comphelper/processfactory.hxx"
77
78 #include "dp_gui.h"
79 #include "dp_gui_thread.hxx"
80 #include "dp_gui_extensioncmdqueue.hxx"
81 #include "dp_gui_dependencydialog.hxx"
82 #include "dp_gui_dialog2.hxx"
83 #include "dp_gui_shared.hxx"
84 #include "dp_gui_theextmgr.hxx"
85 #include "dp_gui_updatedialog.hxx"
86 #include "dp_gui_updateinstalldialog.hxx"
87 #include "dp_dependencies.hxx"
88 #include "dp_identifier.hxx"
89 #include "dp_version.hxx"
90 #include <dp_gui_handleversionexception.hxx>
91
92 #include <queue>
93 #include <boost/shared_ptr.hpp>
94
95 #if (defined(_MSC_VER) && (_MSC_VER < 1400))
96 #define _WIN32_WINNT 0x0400
97 #endif
98
99 #ifdef WNT
100 #include "tools/prewin.h"
101 #include <objbase.h>
102 #include "tools/postwin.h"
103 #endif
104
105
106 using namespace ::com::sun::star;
107 using ::rtl::OUString;
108
109 namespace dp_gui {
110
111 //==============================================================================
112
113 class ProgressCmdEnv
114 : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment,
115 task::XInteractionHandler,
116 ucb::XProgressHandler >
117 {
118 uno::Reference< task::XInteractionHandler> m_xHandler;
119 uno::Reference< uno::XComponentContext > m_xContext;
120 uno::Reference< task::XAbortChannel> m_xAbortChannel;
121
122 DialogHelper *m_pDialogHelper;
123 OUString m_sTitle;
124 bool m_bAborted;
125 bool m_bWarnUser;
126 sal_Int32 m_nCurrentProgress;
127
128 void updateProgress();
129
130 void update_( uno::Any const & Status ) throw ( uno::RuntimeException );
131
132 public:
133 virtual ~ProgressCmdEnv();
134
135 /** When param bAskWhenInstalling = true, then the user is asked if he
136 agrees to install this extension. In case this extension is already installed
137 then the user is also notified and asked if he wants to replace that existing
138 extension. In first case an interaction request with an InstallException
139 will be handled and in the second case a VersionException will be handled.
140 */
141
ProgressCmdEnv(const uno::Reference<uno::XComponentContext> rContext,DialogHelper * pDialogHelper,const OUString & rTitle)142 ProgressCmdEnv( const uno::Reference< uno::XComponentContext > rContext,
143 DialogHelper *pDialogHelper,
144 const OUString &rTitle )
145 : m_xContext( rContext ),
146 m_pDialogHelper( pDialogHelper ),
147 m_sTitle( rTitle ),
148 m_bAborted( false ),
149 m_bWarnUser( false )
150 {}
151
activeDialog()152 Dialog * activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getWindow() : NULL; }
153
setTitle(const OUString & rNewTitle)154 void setTitle( const OUString& rNewTitle ) { m_sTitle = rNewTitle; }
155 void startProgress();
156 void stopProgress();
157 void progressSection( const OUString &rText,
158 const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 );
isAborted() const159 inline bool isAborted() const { return m_bAborted; }
setWarnUser(bool bNewVal)160 inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; }
161
162 // XCommandEnvironment
163 virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler()
164 throw ( uno::RuntimeException );
165 virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler()
166 throw ( uno::RuntimeException );
167
168 // XInteractionHandler
169 virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest )
170 throw ( uno::RuntimeException );
171
172 // XProgressHandler
173 virtual void SAL_CALL push( uno::Any const & Status )
174 throw ( uno::RuntimeException );
175 virtual void SAL_CALL update( uno::Any const & Status )
176 throw ( uno::RuntimeException );
177 virtual void SAL_CALL pop() throw ( uno::RuntimeException );
178 };
179
180 //------------------------------------------------------------------------------
181 struct ExtensionCmd
182 {
183 enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE };
184
185 E_CMD_TYPE m_eCmdType;
186 bool m_bWarnUser;
187 OUString m_sExtensionURL;
188 OUString m_sRepository;
189 uno::Reference< deployment::XPackage > m_xPackage;
190 std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList;
191
ExtensionCmddp_gui::ExtensionCmd192 ExtensionCmd( const E_CMD_TYPE eCommand,
193 const OUString &rExtensionURL,
194 const OUString &rRepository,
195 const bool bWarnUser )
196 : m_eCmdType( eCommand ),
197 m_bWarnUser( bWarnUser ),
198 m_sExtensionURL( rExtensionURL ),
199 m_sRepository( rRepository ) {};
ExtensionCmddp_gui::ExtensionCmd200 ExtensionCmd( const E_CMD_TYPE eCommand,
201 const uno::Reference< deployment::XPackage > &rPackage )
202 : m_eCmdType( eCommand ),
203 m_bWarnUser( false ),
204 m_xPackage( rPackage ) {};
ExtensionCmddp_gui::ExtensionCmd205 ExtensionCmd( const E_CMD_TYPE eCommand,
206 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
207 : m_eCmdType( eCommand ),
208 m_bWarnUser( false ),
209 m_vExtensionList( vExtensionList ) {};
210 };
211
212 typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd;
213
214 //------------------------------------------------------------------------------
215 class ExtensionCmdQueue::Thread: public dp_gui::Thread
216 {
217 public:
218 Thread( DialogHelper *pDialogHelper,
219 TheExtensionManager *pManager,
220 const uno::Reference< uno::XComponentContext > & rContext );
221
222 void addExtension( const OUString &rExtensionURL,
223 const OUString &rRepository,
224 const bool bWarnUser );
225 void removeExtension( const uno::Reference< deployment::XPackage > &rPackage );
226 void enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
227 const bool bEnable );
228 void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
229 void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage );
230 void stop();
231 bool isBusy();
232
233 static OUString searchAndReplaceAll( const OUString &rSource,
234 const OUString &rWhat,
235 const OUString &rWith );
236 private:
237 Thread( Thread & ); // not defined
238 void operator =( Thread & ); // not defined
239
240 virtual ~Thread();
241
242 virtual void execute();
243 virtual void SAL_CALL onTerminated();
244
245 void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
246 const OUString &rPackageURL,
247 const OUString &rRepository,
248 const bool bWarnUser );
249 void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
250 const uno::Reference< deployment::XPackage > &xPackage );
251 void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
252 const uno::Reference< deployment::XPackage > &xPackage );
253 void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
254 const uno::Reference< deployment::XPackage > &xPackage );
255 void _checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
256 void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
257 const uno::Reference< deployment::XPackage > &xPackage );
258
259 enum Input { NONE, START, STOP };
260
261 uno::Reference< uno::XComponentContext > m_xContext;
262 std::queue< TExtensionCmd > m_queue;
263
264 DialogHelper *m_pDialogHelper;
265 TheExtensionManager *m_pManager;
266
267 const OUString m_sEnablingPackages;
268 const OUString m_sDisablingPackages;
269 const OUString m_sAddingPackages;
270 const OUString m_sRemovingPackages;
271 const OUString m_sDefaultCmd;
272 const OUString m_sAcceptLicense;
273 osl::Condition m_wakeup;
274 osl::Mutex m_mutex;
275 Input m_eInput;
276 bool m_bTerminated;
277 bool m_bStopped;
278 bool m_bWorking;
279 };
280
281 //------------------------------------------------------------------------------
startProgress()282 void ProgressCmdEnv::startProgress()
283 {
284 m_nCurrentProgress = 0;
285
286 if ( m_pDialogHelper )
287 m_pDialogHelper->showProgress( true );
288 }
289
290 //------------------------------------------------------------------------------
stopProgress()291 void ProgressCmdEnv::stopProgress()
292 {
293 if ( m_pDialogHelper )
294 m_pDialogHelper->showProgress( false );
295 }
296
297 //------------------------------------------------------------------------------
progressSection(const OUString & rText,const uno::Reference<task::XAbortChannel> & xAbortChannel)298 void ProgressCmdEnv::progressSection( const OUString &rText,
299 const uno::Reference< task::XAbortChannel > &xAbortChannel )
300 {
301 m_xAbortChannel = xAbortChannel;
302 if (! m_bAborted)
303 {
304 m_nCurrentProgress = 0;
305 if ( m_pDialogHelper )
306 {
307 m_pDialogHelper->updateProgress( rText, xAbortChannel );
308 m_pDialogHelper->updateProgress( 5 );
309 }
310 }
311 }
312
313 //------------------------------------------------------------------------------
updateProgress()314 void ProgressCmdEnv::updateProgress()
315 {
316 if ( ! m_bAborted )
317 {
318 long nProgress = ((m_nCurrentProgress*5) % 100) + 5;
319 if ( m_pDialogHelper )
320 m_pDialogHelper->updateProgress( nProgress );
321 }
322 }
323
324 //------------------------------------------------------------------------------
~ProgressCmdEnv()325 ProgressCmdEnv::~ProgressCmdEnv()
326 {
327 // TODO: stop all threads and wait
328 }
329
330
331 //------------------------------------------------------------------------------
332 // XCommandEnvironment
333 //------------------------------------------------------------------------------
getInteractionHandler()334 uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler()
335 throw ( uno::RuntimeException )
336 {
337 return this;
338 }
339
340 //------------------------------------------------------------------------------
getProgressHandler()341 uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler()
342 throw ( uno::RuntimeException )
343 {
344 return this;
345 }
346
347 //------------------------------------------------------------------------------
348 // XInteractionHandler
349 //------------------------------------------------------------------------------
350
handle(uno::Reference<task::XInteractionRequest> const & xRequest)351 void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest )
352 throw ( uno::RuntimeException )
353 {
354 uno::Any request( xRequest->getRequest() );
355 OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION );
356 dp_misc::TRACE( OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n")
357 + ::comphelper::anyToString(request) + OUSTR("\n"));
358
359 lang::WrappedTargetException wtExc;
360 deployment::DependencyException depExc;
361 deployment::LicenseException licExc;
362 deployment::VersionException verExc;
363 deployment::InstallException instExc;
364 deployment::PlatformException platExc;
365
366 // selections:
367 bool approve = false;
368 bool abort = false;
369
370 if (request >>= wtExc) {
371 // handable deployment error signalled, e.g.
372 // bundle item registration failed, notify cause only:
373 uno::Any cause;
374 deployment::DeploymentException dpExc;
375 if (wtExc.TargetException >>= dpExc)
376 cause = dpExc.Cause;
377 else {
378 ucb::CommandFailedException cfExc;
379 if (wtExc.TargetException >>= cfExc)
380 cause = cfExc.Reason;
381 else
382 cause = wtExc.TargetException;
383 }
384 update_( cause );
385
386 // ignore intermediate errors of legacy packages, i.e.
387 // former pkgchk behaviour:
388 const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY );
389 OSL_ASSERT( xPackage.is() );
390 if ( xPackage.is() )
391 {
392 const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() );
393 OSL_ASSERT( xPackageType.is() );
394 if (xPackageType.is())
395 {
396 approve = ( xPackage->isBundle() &&
397 xPackageType->getMediaType().matchAsciiL(
398 RTL_CONSTASCII_STRINGPARAM(
399 "application/"
400 "vnd.sun.star.legacy-package-bundle") ));
401 }
402 }
403 abort = !approve;
404 }
405 else if (request >>= depExc)
406 {
407 std::vector< rtl::OUString > deps;
408 for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength();
409 ++i)
410 {
411 deps.push_back(
412 dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) );
413 }
414 {
415 vos::OGuard guard(Application::GetSolarMutex());
416 short n = DependencyDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, deps ).Execute();
417 // Distinguish between closing the dialog and programatically
418 // canceling the dialog (headless VCL):
419 approve = n == RET_OK
420 || (n == RET_CANCEL && !Application::IsDialogCancelEnabled());
421 }
422 }
423 else if (request >>= licExc)
424 {
425 uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
426 deployment::ui::LicenseDialog::create(
427 m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ),
428 licExc.ExtensionName, licExc.Text ) );
429 sal_Int16 res = xDialog->execute();
430 if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
431 abort = true;
432 else if ( res == ui::dialogs::ExecutableDialogResults::OK )
433 approve = true;
434 else
435 {
436 OSL_ASSERT(0);
437 }
438 }
439 else if (request >>= verExc)
440 {
441 approve = handleVersionException( verExc, m_pDialogHelper );
442 abort = !approve;
443 }
444 else if (request >>= instExc)
445 {
446 if ( ! m_bWarnUser )
447 {
448 approve = true;
449 }
450 else
451 {
452 if ( m_pDialogHelper )
453 {
454 vos::OGuard guard(Application::GetSolarMutex());
455
456 approve = m_pDialogHelper->installExtensionWarn( instExc.displayName );
457 }
458 else
459 approve = false;
460 abort = !approve;
461 }
462 }
463 else if (request >>= platExc)
464 {
465 vos::OGuard guard( Application::GetSolarMutex() );
466 String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) );
467 sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() );
468 ErrorBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, sMsg );
469 box.Execute();
470 approve = true;
471 }
472
473 if (approve == false && abort == false)
474 {
475 // forward to UUI handler:
476 if (! m_xHandler.is()) {
477 // late init:
478 uno::Sequence< uno::Any > handlerArgs( 1 );
479 handlerArgs[ 0 ] <<= beans::PropertyValue(
480 OUSTR("Context"), -1, uno::Any( m_sTitle ),
481 beans::PropertyState_DIRECT_VALUE );
482 m_xHandler.set( m_xContext->getServiceManager()
483 ->createInstanceWithArgumentsAndContext(
484 OUSTR("com.sun.star.uui.InteractionHandler"),
485 handlerArgs, m_xContext ), uno::UNO_QUERY_THROW );
486 }
487 m_xHandler->handle( xRequest );
488 }
489 else
490 {
491 // select:
492 uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts(
493 xRequest->getContinuations() );
494 uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
495 sal_Int32 len = conts.getLength();
496 for ( sal_Int32 pos = 0; pos < len; ++pos )
497 {
498 if (approve) {
499 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
500 if (xInteractionApprove.is()) {
501 xInteractionApprove->select();
502 // don't query again for ongoing continuations:
503 approve = false;
504 }
505 }
506 else if (abort) {
507 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
508 if (xInteractionAbort.is()) {
509 xInteractionAbort->select();
510 // don't query again for ongoing continuations:
511 abort = false;
512 }
513 }
514 }
515 }
516 }
517
518 //------------------------------------------------------------------------------
519 // XProgressHandler
520 //------------------------------------------------------------------------------
push(uno::Any const & rStatus)521 void ProgressCmdEnv::push( uno::Any const & rStatus )
522 throw( uno::RuntimeException )
523 {
524 update_( rStatus );
525 }
526
527 //------------------------------------------------------------------------------
update_(uno::Any const & rStatus)528 void ProgressCmdEnv::update_( uno::Any const & rStatus )
529 throw( uno::RuntimeException )
530 {
531 OUString text;
532 if ( rStatus.hasValue() && !( rStatus >>= text) )
533 {
534 if ( rStatus.getValueTypeClass() == uno::TypeClass_EXCEPTION )
535 text = static_cast< uno::Exception const *>( rStatus.getValue() )->Message;
536 if ( text.getLength() == 0 )
537 text = ::comphelper::anyToString( rStatus ); // fallback
538
539 const ::vos::OGuard aGuard( Application::GetSolarMutex() );
540 const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, text ) );
541 aBox->Execute();
542 }
543 ++m_nCurrentProgress;
544 updateProgress();
545 }
546
547 //------------------------------------------------------------------------------
update(uno::Any const & rStatus)548 void ProgressCmdEnv::update( uno::Any const & rStatus )
549 throw( uno::RuntimeException )
550 {
551 update_( rStatus );
552 }
553
554 //------------------------------------------------------------------------------
pop()555 void ProgressCmdEnv::pop()
556 throw( uno::RuntimeException )
557 {
558 update_( uno::Any() ); // no message
559 }
560
561 //------------------------------------------------------------------------------
Thread(DialogHelper * pDialogHelper,TheExtensionManager * pManager,const uno::Reference<uno::XComponentContext> & rContext)562 ExtensionCmdQueue::Thread::Thread( DialogHelper *pDialogHelper,
563 TheExtensionManager *pManager,
564 const uno::Reference< uno::XComponentContext > & rContext ) :
565 m_xContext( rContext ),
566 m_pDialogHelper( pDialogHelper ),
567 m_pManager( pManager ),
568 m_sEnablingPackages( DialogHelper::getResourceString( RID_STR_ENABLING_PACKAGES ) ),
569 m_sDisablingPackages( DialogHelper::getResourceString( RID_STR_DISABLING_PACKAGES ) ),
570 m_sAddingPackages( DialogHelper::getResourceString( RID_STR_ADDING_PACKAGES ) ),
571 m_sRemovingPackages( DialogHelper::getResourceString( RID_STR_REMOVING_PACKAGES ) ),
572 m_sDefaultCmd( DialogHelper::getResourceString( RID_STR_ADD_PACKAGES ) ),
573 m_sAcceptLicense( DialogHelper::getResourceString( RID_STR_ACCEPT_LICENSE ) ),
574 m_eInput( NONE ),
575 m_bTerminated( false ),
576 m_bStopped( false ),
577 m_bWorking( false )
578 {
579 OSL_ASSERT( pDialogHelper );
580 }
581
582 //------------------------------------------------------------------------------
addExtension(const::rtl::OUString & rExtensionURL,const::rtl::OUString & rRepository,const bool bWarnUser)583 void ExtensionCmdQueue::Thread::addExtension( const ::rtl::OUString &rExtensionURL,
584 const ::rtl::OUString &rRepository,
585 const bool bWarnUser )
586 {
587 ::osl::MutexGuard aGuard( m_mutex );
588
589 //If someone called stop then we do not add the extension -> game over!
590 if ( m_bStopped )
591 return;
592
593 if ( rExtensionURL.getLength() )
594 {
595 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser ) );
596
597 m_queue.push( pEntry );
598 m_eInput = START;
599 m_wakeup.set();
600 }
601 }
602
603 //------------------------------------------------------------------------------
removeExtension(const uno::Reference<deployment::XPackage> & rPackage)604 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
605 {
606 ::osl::MutexGuard aGuard( m_mutex );
607
608 //If someone called stop then we do not remove the extension -> game over!
609 if ( m_bStopped )
610 return;
611
612 if ( rPackage.is() )
613 {
614 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackage ) );
615
616 m_queue.push( pEntry );
617 m_eInput = START;
618 m_wakeup.set();
619 }
620 }
621
622 //------------------------------------------------------------------------------
acceptLicense(const uno::Reference<deployment::XPackage> & rPackage)623 void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
624 {
625 ::osl::MutexGuard aGuard( m_mutex );
626
627 //If someone called stop then we do not remove the extension -> game over!
628 if ( m_bStopped )
629 return;
630
631 if ( rPackage.is() )
632 {
633 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ACCEPT_LICENSE, rPackage ) );
634
635 m_queue.push( pEntry );
636 m_eInput = START;
637 m_wakeup.set();
638 }
639 }
640
641 //------------------------------------------------------------------------------
enableExtension(const uno::Reference<deployment::XPackage> & rPackage,const bool bEnable)642 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
643 const bool bEnable )
644 {
645 ::osl::MutexGuard aGuard( m_mutex );
646
647 //If someone called stop then we do not remove the extension -> game over!
648 if ( m_bStopped )
649 return;
650
651 if ( rPackage.is() )
652 {
653 TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE :
654 ExtensionCmd::DISABLE,
655 rPackage ) );
656 m_queue.push( pEntry );
657 m_eInput = START;
658 m_wakeup.set();
659 }
660 }
661
662 //------------------------------------------------------------------------------
checkForUpdates(const std::vector<uno::Reference<deployment::XPackage>> & vExtensionList)663 void ExtensionCmdQueue::Thread::checkForUpdates(
664 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
665 {
666 ::osl::MutexGuard aGuard( m_mutex );
667
668 //If someone called stop then we do not update the extension -> game over!
669 if ( m_bStopped )
670 return;
671
672 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) );
673 m_queue.push( pEntry );
674 m_eInput = START;
675 m_wakeup.set();
676 }
677
678 //------------------------------------------------------------------------------
679 //Stopping this thread will not abort the installation of extensions.
stop()680 void ExtensionCmdQueue::Thread::stop()
681 {
682 osl::MutexGuard aGuard( m_mutex );
683 m_bStopped = true;
684 m_eInput = STOP;
685 m_wakeup.set();
686 }
687
688 //------------------------------------------------------------------------------
isBusy()689 bool ExtensionCmdQueue::Thread::isBusy()
690 {
691 osl::MutexGuard aGuard( m_mutex );
692 return m_bWorking;
693 }
694
695 //------------------------------------------------------------------------------
~Thread()696 ExtensionCmdQueue::Thread::~Thread() {}
697
698 //------------------------------------------------------------------------------
execute()699 void ExtensionCmdQueue::Thread::execute()
700 {
701 #ifdef WNT
702 //Needed for use of the service "com.sun.star.system.SystemShellExecute" in
703 //DialogHelper::openWebBrowser
704 CoUninitialize();
705 HRESULT r = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
706 #endif
707 for (;;)
708 {
709 if ( m_wakeup.wait() != osl::Condition::result_ok )
710 {
711 dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored "
712 "osl::Condition::wait failure\n" );
713 }
714 m_wakeup.reset();
715
716 int nSize;
717 Input eInput;
718 {
719 osl::MutexGuard aGuard( m_mutex );
720 eInput = m_eInput;
721 m_eInput = NONE;
722 nSize = m_queue.size();
723 m_bWorking = false;
724 }
725
726 // If this thread has been woken up by anything else except start, stop
727 // then input is NONE and we wait again.
728 // We only install the extension which are currently in the queue.
729 // The progressbar will be set to show the progress of the current number
730 // of extensions. If we allowed to add extensions now then the progressbar may
731 // have reached the end while we still install newly added extensions.
732 if ( ( eInput == NONE ) || ( nSize == 0 ) )
733 continue;
734 if ( eInput == STOP )
735 break;
736
737 ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) );
738
739 // Do not lock the following part with addExtension. addExtension may be called in the main thread.
740 // If the message box "Do you want to install the extension (or similar)" is shown and then
741 // addExtension is called, which then blocks the main thread, then we deadlock.
742 bool bStartProgress = true;
743
744 while ( !currentCmdEnv->isAborted() && --nSize >= 0 )
745 {
746 {
747 osl::MutexGuard aGuard( m_mutex );
748 m_bWorking = true;
749 }
750
751 try
752 {
753 TExtensionCmd pEntry;
754 {
755 ::osl::MutexGuard queueGuard( m_mutex );
756 pEntry = m_queue.front();
757 m_queue.pop();
758 }
759
760 if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) )
761 {
762 currentCmdEnv->startProgress();
763 bStartProgress = false;
764 }
765
766 switch ( pEntry->m_eCmdType ) {
767 case ExtensionCmd::ADD :
768 _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser );
769 break;
770 case ExtensionCmd::REMOVE :
771 _removeExtension( currentCmdEnv, pEntry->m_xPackage );
772 break;
773 case ExtensionCmd::ENABLE :
774 _enableExtension( currentCmdEnv, pEntry->m_xPackage );
775 break;
776 case ExtensionCmd::DISABLE :
777 _disableExtension( currentCmdEnv, pEntry->m_xPackage );
778 break;
779 case ExtensionCmd::CHECK_FOR_UPDATES :
780 _checkForUpdates( pEntry->m_vExtensionList );
781 break;
782 case ExtensionCmd::ACCEPT_LICENSE :
783 _acceptLicense( currentCmdEnv, pEntry->m_xPackage );
784 break;
785 }
786 }
787 //catch ( deployment::DeploymentException &)
788 //{
789 //}
790 //catch ( lang::IllegalArgumentException &)
791 //{
792 //}
793 catch ( ucb::CommandAbortedException & )
794 {
795 //This exception is thrown when the user clicks cancel on the progressbar.
796 //Then we cancel the installation of all extensions and remove them from
797 //the queue.
798 {
799 ::osl::MutexGuard queueGuard2(m_mutex);
800 while ( --nSize >= 0 )
801 m_queue.pop();
802 }
803 break;
804 }
805 catch ( ucb::CommandFailedException & )
806 {
807 //This exception is thrown when a user clicked cancel in the messagebox which was
808 //startet by the interaction handler. For example the user will be asked if he/she
809 //really wants to install the extension.
810 //These interaction are run for exectly one extension at a time. Therefore we continue
811 //with installing the remaining extensions.
812 continue;
813 }
814 catch ( uno::Exception & )
815 {
816 //Todo display the user an error
817 //see also DialogImpl::SyncPushButton::Click()
818 uno::Any exc( ::cppu::getCaughtException() );
819 OUString msg;
820 deployment::DeploymentException dpExc;
821 if ((exc >>= dpExc) &&
822 dpExc.Cause.getValueTypeClass() == uno::TypeClass_EXCEPTION)
823 {
824 // notify error cause only:
825 msg = reinterpret_cast< uno::Exception const * >( dpExc.Cause.getValue() )->Message;
826 }
827 if (msg.getLength() == 0) // fallback for debugging purposes
828 msg = ::comphelper::anyToString(exc);
829
830 const ::vos::OGuard guard( Application::GetSolarMutex() );
831 ::std::auto_ptr<ErrorBox> box(
832 new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) );
833 if ( m_pDialogHelper )
834 box->SetText( m_pDialogHelper->getWindow()->GetText() );
835 box->Execute();
836 //Continue with installation of the remaining extensions
837 }
838 {
839 osl::MutexGuard aGuard( m_mutex );
840 m_bWorking = false;
841 }
842 }
843
844 {
845 // when leaving the while loop with break, we should set working to false, too
846 osl::MutexGuard aGuard( m_mutex );
847 m_bWorking = false;
848 }
849
850 if ( !bStartProgress )
851 currentCmdEnv->stopProgress();
852 }
853 //end for
854 //enable all buttons
855 // m_pDialog->m_bAddingExtensions = false;
856 // m_pDialog->updateButtonStates();
857 #ifdef WNT
858 CoUninitialize();
859 #endif
860 }
861
862 //------------------------------------------------------------------------------
_addExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const OUString & rPackageURL,const OUString & rRepository,const bool bWarnUser)863 void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
864 const OUString &rPackageURL,
865 const OUString &rRepository,
866 const bool bWarnUser )
867 {
868 //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void
869 //and anyTitle.get<OUString> throws as RuntimeException.
870 uno::Any anyTitle;
871 try
872 {
873 anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") );
874 }
875 catch ( uno::Exception & )
876 {
877 return;
878 }
879
880 OUString sName;
881 if ( ! (anyTitle >>= sName) )
882 {
883 OSL_ENSURE(0, "Could not get file name for extension.");
884 return;
885 }
886
887 rCmdEnv->setWarnUser( bWarnUser );
888 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
889 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
890 OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName );
891 rCmdEnv->progressSection( sTitle, xAbortChannel );
892
893 try
894 {
895 xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(),
896 rRepository, xAbortChannel, rCmdEnv.get() );
897 }
898 catch ( ucb::CommandFailedException & )
899 {
900 // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press
901 // cancel this exception is thrown.
902 }
903 catch ( ucb::CommandAbortedException & )
904 {
905 // User clicked the cancel button
906 // TODO: handle cancel
907 }
908 rCmdEnv->setWarnUser( false );
909 }
910
911 //------------------------------------------------------------------------------
_removeExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)912 void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
913 const uno::Reference< deployment::XPackage > &xPackage )
914 {
915 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
916 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
917 OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
918 rCmdEnv->progressSection( sTitle, xAbortChannel );
919
920 OUString id( dp_misc::getIdentifier( xPackage ) );
921 try
922 {
923 xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv.get() );
924 }
925 catch ( deployment::DeploymentException & )
926 {}
927 catch ( ucb::CommandFailedException & )
928 {}
929 catch ( ucb::CommandAbortedException & )
930 {}
931
932 // Check, if there are still updates to be notified via menu bar icon
933 uno::Sequence< uno::Sequence< rtl::OUString > > aItemList;
934 UpdateDialog::createNotifyJob( false, aItemList );
935 }
936
937 //------------------------------------------------------------------------------
_checkForUpdates(const std::vector<uno::Reference<deployment::XPackage>> & vExtensionList)938 void ExtensionCmdQueue::Thread::_checkForUpdates(
939 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
940 {
941 UpdateDialog* pUpdateDialog;
942 std::vector< UpdateData > vData;
943
944 const ::vos::OGuard guard( Application::GetSolarMutex() );
945
946 pUpdateDialog = new UpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, vExtensionList, &vData );
947
948 pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
949
950 if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() )
951 {
952 // If there is at least one directly downloadable dialog then we
953 // open the install dialog.
954 ::std::vector< UpdateData > dataDownload;
955 int countWebsiteDownload = 0;
956 typedef std::vector< dp_gui::UpdateData >::const_iterator cit;
957
958 for ( cit i = vData.begin(); i < vData.end(); i++ )
959 {
960 if ( i->sWebsiteURL.getLength() > 0 )
961 countWebsiteDownload ++;
962 else
963 dataDownload.push_back( *i );
964 }
965
966 short nDialogResult = RET_OK;
967 if ( !dataDownload.empty() )
968 {
969 nDialogResult = UpdateInstallDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, dataDownload, m_xContext ).Execute();
970 pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
971 }
972 else
973 pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
974
975 //Now start the webbrowser and navigate to the websites where we get the updates
976 if ( RET_OK == nDialogResult )
977 {
978 for ( cit i = vData.begin(); i < vData.end(); i++ )
979 {
980 if ( m_pDialogHelper && ( i->sWebsiteURL.getLength() > 0 ) )
981 m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() );
982 }
983 }
984 }
985 else
986 pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
987
988 delete pUpdateDialog;
989 }
990
991 //------------------------------------------------------------------------------
_enableExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)992 void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
993 const uno::Reference< deployment::XPackage > &xPackage )
994 {
995 if ( !xPackage.is() )
996 return;
997
998 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
999 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1000 OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1001 rCmdEnv->progressSection( sTitle, xAbortChannel );
1002
1003 try
1004 {
1005 xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
1006 if ( m_pDialogHelper )
1007 m_pDialogHelper->updatePackageInfo( xPackage );
1008 }
1009 catch ( ::ucb::CommandAbortedException & )
1010 {}
1011 }
1012
1013 //------------------------------------------------------------------------------
_disableExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)1014 void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1015 const uno::Reference< deployment::XPackage > &xPackage )
1016 {
1017 if ( !xPackage.is() )
1018 return;
1019
1020 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1021 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1022 OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1023 rCmdEnv->progressSection( sTitle, xAbortChannel );
1024
1025 try
1026 {
1027 xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
1028 if ( m_pDialogHelper )
1029 m_pDialogHelper->updatePackageInfo( xPackage );
1030 }
1031 catch ( ::ucb::CommandAbortedException & )
1032 {}
1033 }
1034
1035 //------------------------------------------------------------------------------
_acceptLicense(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)1036 void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1037 const uno::Reference< deployment::XPackage > &xPackage )
1038 {
1039 if ( !xPackage.is() )
1040 return;
1041
1042 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1043 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1044 OUString sTitle = searchAndReplaceAll( m_sAcceptLicense, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1045 rCmdEnv->progressSection( sTitle, xAbortChannel );
1046
1047 try
1048 {
1049 xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() );
1050 if ( m_pDialogHelper )
1051 m_pDialogHelper->updatePackageInfo( xPackage );
1052 }
1053 catch ( ::ucb::CommandAbortedException & )
1054 {}
1055 }
1056
1057 //------------------------------------------------------------------------------
onTerminated()1058 void ExtensionCmdQueue::Thread::onTerminated()
1059 {
1060 ::osl::MutexGuard g(m_mutex);
1061 m_bTerminated = true;
1062 }
1063
1064 //------------------------------------------------------------------------------
searchAndReplaceAll(const OUString & rSource,const OUString & rWhat,const OUString & rWith)1065 OUString ExtensionCmdQueue::Thread::searchAndReplaceAll( const OUString &rSource,
1066 const OUString &rWhat,
1067 const OUString &rWith )
1068 {
1069 OUString aRet( rSource );
1070 sal_Int32 nLen = rWhat.getLength();
1071
1072 if ( !nLen )
1073 return aRet;
1074
1075 sal_Int32 nIndex = rSource.indexOf( rWhat );
1076 while ( nIndex != -1 )
1077 {
1078 aRet = aRet.replaceAt( nIndex, nLen, rWith );
1079 nIndex = aRet.indexOf( rWhat, nIndex + rWith.getLength() );
1080 }
1081 return aRet;
1082 }
1083
1084
1085 //------------------------------------------------------------------------------
1086 //------------------------------------------------------------------------------
1087 //------------------------------------------------------------------------------
ExtensionCmdQueue(DialogHelper * pDialogHelper,TheExtensionManager * pManager,const uno::Reference<uno::XComponentContext> & rContext)1088 ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper * pDialogHelper,
1089 TheExtensionManager *pManager,
1090 const uno::Reference< uno::XComponentContext > &rContext )
1091 : m_thread( new Thread( pDialogHelper, pManager, rContext ) )
1092 {
1093 m_thread->launch();
1094 }
1095
~ExtensionCmdQueue()1096 ExtensionCmdQueue::~ExtensionCmdQueue() {
1097 stop();
1098 }
1099
addExtension(const::rtl::OUString & extensionURL,const::rtl::OUString & repository,const bool bWarnUser)1100 void ExtensionCmdQueue::addExtension( const ::rtl::OUString & extensionURL,
1101 const ::rtl::OUString & repository,
1102 const bool bWarnUser )
1103 {
1104 m_thread->addExtension( extensionURL, repository, bWarnUser );
1105 }
1106
removeExtension(const uno::Reference<deployment::XPackage> & rPackage)1107 void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
1108 {
1109 m_thread->removeExtension( rPackage );
1110 }
1111
enableExtension(const uno::Reference<deployment::XPackage> & rPackage,const bool bEnable)1112 void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
1113 const bool bEnable )
1114 {
1115 m_thread->enableExtension( rPackage, bEnable );
1116 }
1117
checkForUpdates(const std::vector<uno::Reference<deployment::XPackage>> & vExtensionList)1118 void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
1119 {
1120 m_thread->checkForUpdates( vExtensionList );
1121 }
1122
acceptLicense(const uno::Reference<deployment::XPackage> & rPackage)1123 void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
1124 {
1125 m_thread->acceptLicense( rPackage );
1126 }
1127
syncRepositories(const uno::Reference<uno::XComponentContext> & xContext)1128 void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext )
1129 {
1130 dp_misc::syncRepositories( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) );
1131 }
1132
stop()1133 void ExtensionCmdQueue::stop()
1134 {
1135 m_thread->stop();
1136 }
1137
isBusy()1138 bool ExtensionCmdQueue::isBusy()
1139 {
1140 return m_thread->isBusy();
1141 }
1142
handleInteractionRequest(const uno::Reference<uno::XComponentContext> & xContext,const uno::Reference<task::XInteractionRequest> & xRequest)1143 void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext,
1144 const uno::Reference< task::XInteractionRequest > & xRequest )
1145 {
1146 ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) );
1147 xCmdEnv->handle( xRequest );
1148 }
1149
1150 } //namespace dp_gui
1151
1152