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 "dp_gui_updatedata.hxx"
28
29 #include "sal/config.h"
30 #include "osl/file.hxx"
31 #include "osl/conditn.hxx"
32 #include "cppuhelper/exc_hlp.hxx"
33 #include "tools/resid.hxx"
34 #include "tools/resmgr.hxx"
35 #include "tools/solar.h"
36 #include "tools/string.hxx"
37 #include "vcl/dialog.hxx"
38 #include "vcl/msgbox.hxx"
39 #include "vcl/svapp.hxx"
40 #include "vos/mutex.hxx"
41 #include "vcl/dialog.hxx"
42 #include "cppuhelper/implbase3.hxx"
43
44 #include "com/sun/star/beans/PropertyValue.hpp"
45 #include "com/sun/star/beans/NamedValue.hpp"
46 #include "com/sun/star/xml/dom/XElement.hpp"
47 #include "com/sun/star/xml/dom/XNode.hpp"
48 #include "com/sun/star/xml/dom/XNodeList.hpp"
49 #include "com/sun/star/ucb/NameClash.hpp"
50 #include "com/sun/star/ucb/InteractiveAugmentedIOException.hpp"
51 #include "com/sun/star/ucb/XCommandEnvironment.hpp"
52 #include "com/sun/star/ucb/XProgressHandler.hpp"
53 #include "com/sun/star/deployment/XExtensionManager.hpp"
54 #include "com/sun/star/deployment/ExtensionManager.hpp"
55 #include "com/sun/star/deployment/XUpdateInformationProvider.hpp"
56 #include "com/sun/star/deployment/DependencyException.hpp"
57 #include "com/sun/star/deployment/LicenseException.hpp"
58 #include "com/sun/star/deployment/VersionException.hpp"
59 #include "com/sun/star/deployment/ui/LicenseDialog.hpp"
60 #include "com/sun/star/task/XInteractionHandler.hpp"
61 #include "com/sun/star/ui/dialogs/XExecutableDialog.hpp"
62 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
63 #include "com/sun/star/task/XInteractionAbort.hpp"
64 #include "com/sun/star/task/XInteractionApprove.hpp"
65
66 #include "dp_descriptioninfoset.hxx"
67 #include "dp_gui.hrc"
68 #include "dp_gui_updateinstalldialog.hxx"
69 #include "dp_gui_shared.hxx"
70 #include "dp_gui_updatedata.hxx"
71 #include "dp_ucb.h"
72 #include "dp_misc.h"
73 #include "dp_version.hxx"
74 #include "dp_gui_thread.hxx"
75 #include "dp_gui_extensioncmdqueue.hxx"
76 #include "ucbhelper/content.hxx"
77 #include "osl/mutex.hxx"
78 #include "vos/mutex.hxx"
79 #include "rtl/ref.hxx"
80 #include "com/sun/star/uno/Sequence.h"
81 #include "comphelper/anytostring.hxx"
82 #include "toolkit/helper/vclunohelper.hxx"
83
84 #include <vector>
85
86 class Window;
87
88 namespace cssu = ::com::sun::star::uno;
89 namespace css = ::com::sun::star;
90
91 using ::rtl::OUString;
92
93
94 namespace dp_gui {
95
96 class UpdateInstallDialog::Thread: public dp_gui::Thread {
97 friend class UpdateCommandEnv;
98 public:
99 Thread(cssu::Reference< cssu::XComponentContext > ctx,
100 UpdateInstallDialog & dialog, std::vector< dp_gui::UpdateData > & aVecUpdateData);
101
102 void stop();
103
104
105
106 private:
107 Thread(Thread &); // not defined
108 void operator =(Thread &); // not defined
109
110 virtual ~Thread();
111
112 virtual void execute();
113 void downloadExtensions();
114 void download(::rtl::OUString const & aUrls, UpdateData & aUpdatData);
115 void installExtensions();
116 void removeTempDownloads();
117
118 UpdateInstallDialog & m_dialog;
119 cssu::Reference< css::deployment::XUpdateInformationProvider >
120 m_updateInformation;
121
122 // guarded by Application::GetSolarMutex():
123 cssu::Reference< css::task::XAbortChannel > m_abort;
124 cssu::Reference< cssu::XComponentContext > m_xComponentContext;
125 std::vector< dp_gui::UpdateData > & m_aVecUpdateData;
126 ::rtl::Reference<UpdateCommandEnv> m_updateCmdEnv;
127
128 //A folder which is created in the temp directory in which then the updates are downloaded
129 ::rtl::OUString m_sDownloadFolder;
130
131 bool m_stop;
132
133 };
134
135 class UpdateCommandEnv
136 : public ::cppu::WeakImplHelper3< css::ucb::XCommandEnvironment,
137 css::task::XInteractionHandler,
138 css::ucb::XProgressHandler >
139 {
140 friend class UpdateInstallDialog::Thread;
141
142 UpdateInstallDialog & m_updateDialog;
143 ::rtl::Reference<UpdateInstallDialog::Thread> m_installThread;
144 cssu::Reference< cssu::XComponentContext > m_xContext;
145
146 public:
147 virtual ~UpdateCommandEnv();
148 UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx,
149 UpdateInstallDialog & updateDialog,
150 ::rtl::Reference<UpdateInstallDialog::Thread>const & thread);
151
152 // XCommandEnvironment
153 virtual cssu::Reference<css::task::XInteractionHandler > SAL_CALL
154 getInteractionHandler() throw (cssu::RuntimeException);
155 virtual cssu::Reference<css::ucb::XProgressHandler >
156 SAL_CALL getProgressHandler() throw (cssu::RuntimeException);
157
158 // XInteractionHandler
159 virtual void SAL_CALL handle(
160 cssu::Reference<css::task::XInteractionRequest > const & xRequest )
161 throw (cssu::RuntimeException);
162
163 // XProgressHandler
164 virtual void SAL_CALL push( cssu::Any const & Status )
165 throw (cssu::RuntimeException);
166 virtual void SAL_CALL update( cssu::Any const & Status )
167 throw (cssu::RuntimeException);
168 virtual void SAL_CALL pop() throw (cssu::RuntimeException);
169 };
170
171
Thread(cssu::Reference<cssu::XComponentContext> xCtx,UpdateInstallDialog & dialog,std::vector<dp_gui::UpdateData> & aVecUpdateData)172 UpdateInstallDialog::Thread::Thread(
173 cssu::Reference< cssu::XComponentContext> xCtx,
174 UpdateInstallDialog & dialog,
175 std::vector< dp_gui::UpdateData > & aVecUpdateData):
176 m_dialog(dialog),
177 m_xComponentContext(xCtx),
178 m_aVecUpdateData(aVecUpdateData),
179 m_updateCmdEnv(new UpdateCommandEnv(xCtx, m_dialog, this)),
180 m_stop(false)
181 {}
182
stop()183 void UpdateInstallDialog::Thread::stop() {
184 cssu::Reference< css::task::XAbortChannel > abort;
185 {
186 vos::OGuard g(Application::GetSolarMutex());
187 abort = m_abort;
188 m_stop = true;
189 }
190 if (abort.is()) {
191 abort->sendAbort();
192 }
193 }
194
~Thread()195 UpdateInstallDialog::Thread::~Thread() {}
196
execute()197 void UpdateInstallDialog::Thread::execute()
198 {
199 try {
200 downloadExtensions();
201 installExtensions();
202 }
203 catch (...)
204 {
205 }
206
207 //clean up the temp directories
208 try {
209 removeTempDownloads();
210 } catch( ... ) {
211 }
212
213 {
214 //make sure m_dialog is still alive
215 ::vos::OGuard g(Application::GetSolarMutex());
216 if (! m_stop)
217 m_dialog.updateDone();
218 }
219 //UpdateCommandEnv keeps a reference to Thread and prevents destruction. Therefore remove it.
220 m_updateCmdEnv->m_installThread.clear();
221 }
222
223
UpdateInstallDialog(Window * parent,std::vector<dp_gui::UpdateData> & aVecUpdateData,cssu::Reference<cssu::XComponentContext> const & xCtx)224 UpdateInstallDialog::UpdateInstallDialog(
225 Window * parent,
226 std::vector<dp_gui::UpdateData> & aVecUpdateData,
227 cssu::Reference< cssu::XComponentContext > const & xCtx):
228 ModalDialog(
229 parent,
230 DpGuiResId(RID_DLG_UPDATEINSTALL)),
231
232 m_thread(new Thread(xCtx, *this, aVecUpdateData)),
233 m_xComponentContext(xCtx),
234 m_bError(false),
235 m_bNoEntry(true),
236 m_bActivated(false),
237 m_sInstalling(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_INSTALLING))),
238 m_sFinished(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_FINISHED))),
239 m_sNoErrors(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_NO_ERRORS))),
240 m_sErrorDownload(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_ERROR_DOWNLOAD))),
241 m_sErrorInstallation(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_ERROR_INSTALLATION))),
242 m_sErrorLicenseDeclined(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_ERROR_LIC_DECLINED))),
243 m_sNoInstall(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_EXTENSION_NOINSTALL))),
244 m_sThisErrorOccurred(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_THIS_ERROR_OCCURRED))),
245 m_ft_action(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_DOWNLOADING)),
246 m_statusbar(this,DpGuiResId(RID_DLG_UPDATE_INSTALL_STATUSBAR)),
247 m_ft_extension_name(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_EXTENSION_NAME)),
248 m_ft_results(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_RESULTS)),
249 m_mle_info(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_INFO)),
250 m_line(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_LINE)),
251 m_help(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_HELP)),
252 m_ok(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_OK)),
253 m_cancel(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_ABORT))
254 {
255 FreeResource();
256
257 m_xExtensionManager = css::deployment::ExtensionManager::get( xCtx );
258
259 m_cancel.SetClickHdl(LINK(this, UpdateInstallDialog, cancelHandler));
260 m_mle_info.EnableCursor(sal_False);
261 if ( ! dp_misc::office_is_running())
262 m_help.Disable();
263 }
264
~UpdateInstallDialog()265 UpdateInstallDialog::~UpdateInstallDialog() {}
266
Close()267 sal_Bool UpdateInstallDialog::Close()
268 {
269 m_thread->stop();
270 return ModalDialog::Close();
271 }
272
Execute()273 short UpdateInstallDialog::Execute()
274 {
275 m_thread->launch();
276 return ModalDialog::Execute();
277 }
278
279
280 // make sure the solar mutex is locked before calling
updateDone()281 void UpdateInstallDialog::updateDone()
282 {
283 if (!m_bError)
284 m_mle_info.InsertText(m_sNoErrors);
285 m_ok.Enable();
286 m_ok.GrabFocus();
287 m_cancel.Disable();
288 }
289 // make sure the solar mutex is locked before calling
290 //sets an error message in the text area
setError(INSTALL_ERROR err,::rtl::OUString const & sExtension,OUString const & exceptionMessage)291 void UpdateInstallDialog::setError(INSTALL_ERROR err, ::rtl::OUString const & sExtension,
292 OUString const & exceptionMessage)
293 {
294 String sError;
295 m_bError = true;
296
297 switch (err)
298 {
299 case ERROR_DOWNLOAD:
300 sError = m_sErrorDownload;
301 break;
302 case ERROR_INSTALLATION:
303 sError = m_sErrorInstallation;
304 break;
305 case ERROR_LICENSE_DECLINED:
306 sError = m_sErrorLicenseDeclined;
307 break;
308
309 default:
310 OSL_ASSERT(0);
311 }
312
313 sError.SearchAndReplace(String(OUSTR("%NAME")), String(sExtension), 0);
314 //We want to have an empty line between the error messages. However,
315 //there shall be no empty line after the last entry.
316 if (m_bNoEntry)
317 m_bNoEntry = false;
318 else
319 m_mle_info.InsertText(OUSTR("\n"));
320 m_mle_info.InsertText(sError);
321 //Insert more information about the error
322 if (exceptionMessage.getLength())
323 m_mle_info.InsertText(m_sThisErrorOccurred + exceptionMessage + OUSTR("\n"));
324
325 m_mle_info.InsertText(m_sNoInstall);
326 m_mle_info.InsertText(OUSTR("\n"));
327 }
328
setError(OUString const & exceptionMessage)329 void UpdateInstallDialog::setError(OUString const & exceptionMessage)
330 {
331 m_bError = true;
332 m_mle_info.InsertText(exceptionMessage + OUSTR("\n"));
333 }
334
IMPL_LINK(UpdateInstallDialog,cancelHandler,void *,EMPTYARG)335 IMPL_LINK(UpdateInstallDialog, cancelHandler, void *, EMPTYARG)
336 {
337 m_thread->stop();
338 EndDialog(RET_CANCEL);
339 return 0;
340 }
341
342 //------------------------------------------------------------------------------------------------
343
downloadExtensions()344 void UpdateInstallDialog::Thread::downloadExtensions()
345 {
346 try
347 {
348 //create the download directory in the temp folder
349 OUString sTempDir;
350 if (::osl::FileBase::getTempDirURL(sTempDir) != ::osl::FileBase::E_None)
351 throw cssu::Exception(OUSTR("Could not get URL for the temp directory. No extensions will be installed."), 0);
352
353 //create a unique name for the directory
354 OUString tempEntry, destFolder;
355 if (::osl::File::createTempFile(&sTempDir, 0, &tempEntry ) != ::osl::File::E_None)
356 throw cssu::Exception(OUSTR("Could not create a temporary file in ") + sTempDir +
357 OUSTR(". No extensions will be installed"), 0 );
358
359 tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 );
360
361 destFolder = dp_misc::makeURL( sTempDir, tempEntry );
362 destFolder += OUSTR("_");
363 m_sDownloadFolder = destFolder;
364 try
365 {
366 dp_misc::create_folder(0, destFolder, m_updateCmdEnv.get(), true );
367 } catch (cssu::Exception & e)
368 {
369 throw cssu::Exception(e.Message + OUSTR(" No extensions will be installed."), 0);
370 }
371
372
373 sal_uInt16 count = 0;
374 typedef std::vector<UpdateData>::iterator It;
375 for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); i++)
376 {
377 UpdateData & curData = *i;
378
379 if (!curData.aUpdateInfo.is() || curData.aUpdateSource.is())
380 continue;
381 //We assume that m_aVecUpdateData contains only information about extensions which
382 //can be downloaded directly.
383 OSL_ASSERT(curData.sWebsiteURL.getLength() == 0);
384
385 //update the name of the extension which is to be downloaded
386 {
387 ::vos::OGuard g(Application::GetSolarMutex());
388 if (m_stop) {
389 return;
390 }
391 m_dialog.m_ft_extension_name.SetText(curData.aInstalledPackage->getDisplayName());
392 sal_uInt16 prog = (sal::static_int_cast<sal_uInt16>(100) * ++count) /
393 sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size());
394 m_dialog.m_statusbar.SetValue(prog);
395 }
396 dp_misc::DescriptionInfoset info(m_xComponentContext, curData.aUpdateInfo);
397 //remember occurring exceptions in case we need to print out error information
398 ::std::vector< ::std::pair<OUString, cssu::Exception> > vecExceptions;
399 cssu::Sequence<OUString> seqDownloadURLs = info.getUpdateDownloadUrls();
400 OSL_ENSURE(seqDownloadURLs.getLength() > 0, "No download URL provided!");
401 for (sal_Int32 j = 0; j < seqDownloadURLs.getLength(); j++)
402 {
403 try
404 {
405 OSL_ENSURE(seqDownloadURLs[j].getLength() > 0, "Download URL is empty!");
406 download(seqDownloadURLs[j], curData);
407 if (curData.sLocalURL.getLength() > 0)
408 break;
409 }
410 catch ( cssu::Exception & e )
411 {
412 vecExceptions.push_back( ::std::make_pair(seqDownloadURLs[j], e));
413 //There can be several different errors, for example, the URL is wrong, webserver cannot be reached,
414 //name cannot be resolved. The UCB helper API does not specify different special exceptions for these
415 //cases. Therefore ignore and continue.
416 continue;
417 }
418 }
419 //update the progress and display download error
420 {
421 ::vos::OGuard g(Application::GetSolarMutex());
422 if (m_stop) {
423 return;
424 }
425 if (curData.sLocalURL.getLength() == 0)
426 {
427 //Construct a string of all messages contained in the exceptions plus the respective download URLs
428 ::rtl::OUStringBuffer buf(256);
429 typedef ::std::vector< ::std::pair<OUString, cssu::Exception > >::const_iterator CIT;
430 for (CIT j = vecExceptions.begin(); j != vecExceptions.end(); j++)
431 {
432 if (j != vecExceptions.begin())
433 buf.appendAscii("\n");
434 buf.append(OUSTR("Could not download "));
435 buf.append(j->first);
436 buf.appendAscii(". ");
437 buf.append(j->second.Message);
438 }
439 m_dialog.setError(UpdateInstallDialog::ERROR_DOWNLOAD, curData.aInstalledPackage->getDisplayName(),
440 buf.makeStringAndClear());
441 }
442 }
443
444 }
445 }
446 catch (cssu::Exception & e)
447 {
448 ::vos::OGuard g(Application::GetSolarMutex());
449 if (m_stop) {
450 return;
451 }
452 m_dialog.setError(e.Message);
453 }
454 }
installExtensions()455 void UpdateInstallDialog::Thread::installExtensions()
456 {
457 //Update the fix text in the dialog to "Installing extensions..."
458 {
459 vos::OGuard g(Application::GetSolarMutex());
460 if (m_stop) {
461 return;
462 }
463 m_dialog.m_ft_action.SetText(m_dialog.m_sInstalling);
464 m_dialog.m_statusbar.SetValue(0);
465 }
466
467 sal_uInt16 count = 0;
468 typedef std::vector<UpdateData>::iterator It;
469 for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); i++, count++)
470 {
471 //update the name of the extension which is to be installed
472 {
473 ::vos::OGuard g(Application::GetSolarMutex());
474 if (m_stop) {
475 return;
476 }
477 //we only show progress after an extension has been installed.
478 if (count > 0) {
479 m_dialog.m_statusbar.SetValue(
480 (sal::static_int_cast<sal_uInt16>(100) * count) /
481 sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size()));
482 }
483 m_dialog.m_ft_extension_name.SetText(i->aInstalledPackage->getDisplayName());
484 }
485 // TimeValue v = {1, 0};
486 // osl::Thread::wait(v);
487 bool bError = false;
488 bool bLicenseDeclined = false;
489 cssu::Reference<css::deployment::XPackage> xExtension;
490 UpdateData & curData = *i;
491 cssu::Exception exc;
492 try
493 {
494 cssu::Reference< css::task::XAbortChannel > xAbortChannel(
495 curData.aInstalledPackage->createAbortChannel() );
496 {
497 vos::OGuard g(Application::GetSolarMutex());
498 if (m_stop) {
499 return;
500 }
501 m_abort = xAbortChannel;
502 }
503 if (!curData.aUpdateSource.is() && curData.sLocalURL.getLength())
504 {
505 css::beans::NamedValue prop(OUSTR("EXTENSION_UPDATE"), css::uno::makeAny(OUSTR("1")));
506 if (!curData.bIsShared)
507 xExtension = m_dialog.getExtensionManager()->addExtension(
508 curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
509 OUSTR("user"), xAbortChannel, m_updateCmdEnv.get());
510 else
511 xExtension = m_dialog.getExtensionManager()->addExtension(
512 curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
513 OUSTR("shared"), xAbortChannel, m_updateCmdEnv.get());
514 }
515 else if (curData.aUpdateSource.is())
516 {
517 OSL_ASSERT(curData.aUpdateSource.is());
518 //I am not sure if we should obtain the install properties and pass them into
519 //add extension. Currently it contains only "SUPPRESS_LICENSE". So it it could happen
520 //that a license is displayed when updating from the shared repository, although the
521 //shared extension was installed using "SUPPRESS_LICENSE".
522 css::beans::NamedValue prop(OUSTR("EXTENSION_UPDATE"), css::uno::makeAny(OUSTR("1")));
523 if (!curData.bIsShared)
524 xExtension = m_dialog.getExtensionManager()->addExtension(
525 curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
526 OUSTR("user"), xAbortChannel, m_updateCmdEnv.get());
527 else
528 xExtension = m_dialog.getExtensionManager()->addExtension(
529 curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
530 OUSTR("shared"), xAbortChannel, m_updateCmdEnv.get());
531 }
532 }
533 catch (css::deployment::DeploymentException & de)
534 {
535 if (de.Cause.has<css::deployment::LicenseException>())
536 {
537 bLicenseDeclined = true;
538 }
539 else
540 {
541 exc = de.Cause.get<cssu::Exception>();
542 bError = true;
543 }
544 }
545 catch (cssu::Exception& e)
546 {
547 exc = e;
548 bError = true;
549 }
550
551 if (bLicenseDeclined)
552 {
553 ::vos::OGuard g(Application::GetSolarMutex());
554 if (m_stop) {
555 return;
556 }
557 m_dialog.setError(UpdateInstallDialog::ERROR_LICENSE_DECLINED,
558 curData.aInstalledPackage->getDisplayName(), OUString());
559 }
560 else if (!xExtension.is() || bError)
561 {
562 ::vos::OGuard g(Application::GetSolarMutex());
563 if (m_stop) {
564 return;
565 }
566 m_dialog.setError(UpdateInstallDialog::ERROR_INSTALLATION,
567 curData.aInstalledPackage->getDisplayName(), exc.Message);
568 }
569 }
570 {
571 vos::OGuard g(Application::GetSolarMutex());
572 if (m_stop) {
573 return;
574 }
575 m_dialog.m_statusbar.SetValue(100);
576 m_dialog.m_ft_extension_name.SetText(OUString());
577 m_dialog.m_ft_action.SetText(m_dialog.m_sFinished);
578 }
579 }
580
removeTempDownloads()581 void UpdateInstallDialog::Thread::removeTempDownloads()
582 {
583 if (m_sDownloadFolder.getLength())
584 {
585 dp_misc::erase_path(m_sDownloadFolder,
586 cssu::Reference<css::ucb::XCommandEnvironment>(),false /* no throw: ignore errors */ );
587 //remove also the temp file which we have used to create the unique name
588 OUString tempFile = m_sDownloadFolder.copy(0, m_sDownloadFolder.getLength() - 1);
589 dp_misc::erase_path(tempFile, cssu::Reference<css::ucb::XCommandEnvironment>(),false);
590 m_sDownloadFolder = OUString();
591 }
592 }
593
594
download(OUString const & sDownloadURL,UpdateData & aUpdateData)595 void UpdateInstallDialog::Thread::download(OUString const & sDownloadURL, UpdateData & aUpdateData)
596 {
597 {
598 ::vos::OGuard g(Application::GetSolarMutex());
599 if (m_stop) {
600 return;
601 }
602 }
603
604 OSL_ASSERT(m_sDownloadFolder.getLength());
605 OUString destFolder, tempEntry;
606 if (::osl::File::createTempFile(
607 &m_sDownloadFolder,
608 0, &tempEntry ) != ::osl::File::E_None)
609 {
610 //ToDo feedback in window that download of this component failed
611 throw cssu::Exception(OUSTR("Could not create temporary file in folder ") + destFolder + OUSTR("."), 0);
612 }
613 tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 );
614
615 destFolder = dp_misc::makeURL( m_sDownloadFolder, tempEntry );
616 destFolder += OUSTR("_");
617
618 ::ucbhelper::Content destFolderContent;
619 dp_misc::create_folder( &destFolderContent, destFolder, m_updateCmdEnv.get() );
620
621 ::ucbhelper::Content sourceContent;
622 dp_misc::create_ucb_content( &sourceContent, sDownloadURL, m_updateCmdEnv.get() );
623
624 const OUString sTitle(sourceContent.getPropertyValue(
625 dp_misc::StrTitle::get() ).get<OUString>() );
626
627 if (destFolderContent.transferContent(
628 sourceContent, ::ucbhelper::InsertOperation_COPY,
629 sTitle, css::ucb::NameClash::OVERWRITE ))
630 {
631 //the user may have cancelled the dialog because downloading took to long
632 {
633 ::vos::OGuard g(Application::GetSolarMutex());
634 if (m_stop) {
635 return;
636 }
637 //all errors should be handeld by the command environment.
638 aUpdateData.sLocalURL = destFolder + OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + sTitle;
639 }
640 }
641 }
642
643
644 // -------------------------------------------------------------------------------------------------------
645
UpdateCommandEnv(cssu::Reference<cssu::XComponentContext> const & xCtx,UpdateInstallDialog & updateDialog,::rtl::Reference<UpdateInstallDialog::Thread> const & thread)646 UpdateCommandEnv::UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx,
647 UpdateInstallDialog & updateDialog,
648 ::rtl::Reference<UpdateInstallDialog::Thread>const & thread)
649 : m_updateDialog( updateDialog ),
650 m_installThread(thread),
651 m_xContext(xCtx)
652 {
653 }
654
~UpdateCommandEnv()655 UpdateCommandEnv::~UpdateCommandEnv()
656 {
657 }
658
659
660 // XCommandEnvironment
661 //______________________________________________________________________________
getInteractionHandler()662 cssu::Reference<css::task::XInteractionHandler> UpdateCommandEnv::getInteractionHandler()
663 throw (cssu::RuntimeException)
664 {
665 return this;
666 }
667
668 //______________________________________________________________________________
getProgressHandler()669 cssu::Reference<css::ucb::XProgressHandler> UpdateCommandEnv::getProgressHandler()
670 throw (cssu::RuntimeException)
671 {
672 return this;
673 }
674
675 // XInteractionHandler
handle(cssu::Reference<css::task::XInteractionRequest> const & xRequest)676 void UpdateCommandEnv::handle(
677 cssu::Reference< css::task::XInteractionRequest> const & xRequest )
678 throw (cssu::RuntimeException)
679 {
680 cssu::Any request( xRequest->getRequest() );
681 OSL_ASSERT( request.getValueTypeClass() == cssu::TypeClass_EXCEPTION );
682 dp_misc::TRACE(OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n")
683 + ::comphelper::anyToString(request) + OUSTR("\n\n"));
684
685 css::deployment::VersionException verExc;
686 bool approve = false;
687 bool abort = false;
688
689 if (request >>= verExc)
690 { //We must catch the version exception during the update,
691 //because otherwise the user would be confronted with the dialogs, asking
692 //them if they want to replace an already installed version of the same extension.
693 //During an update we assume that we always want to replace the old version with the
694 //new version.
695 approve = true;
696 }
697
698 if (approve == false && abort == false)
699 {
700 //forward to interaction handler for main dialog.
701 handleInteractionRequest( m_xContext, xRequest );
702 }
703 else
704 {
705 // select:
706 cssu::Sequence< cssu::Reference< css::task::XInteractionContinuation > > conts(
707 xRequest->getContinuations() );
708 cssu::Reference< css::task::XInteractionContinuation > const * pConts =
709 conts.getConstArray();
710 sal_Int32 len = conts.getLength();
711 for ( sal_Int32 pos = 0; pos < len; ++pos )
712 {
713 if (approve) {
714 cssu::Reference< css::task::XInteractionApprove > xInteractionApprove(
715 pConts[ pos ], cssu::UNO_QUERY );
716 if (xInteractionApprove.is()) {
717 xInteractionApprove->select();
718 // don't query again for ongoing continuations:
719 approve = false;
720 }
721 }
722 else if (abort) {
723 cssu::Reference< css::task::XInteractionAbort > xInteractionAbort(
724 pConts[ pos ], cssu::UNO_QUERY );
725 if (xInteractionAbort.is()) {
726 xInteractionAbort->select();
727 // don't query again for ongoing continuations:
728 abort = false;
729 }
730 }
731 }
732 }
733 }
734
735 // XProgressHandler
push(cssu::Any const &)736 void UpdateCommandEnv::push( cssu::Any const & /*Status*/ )
737 throw (cssu::RuntimeException)
738 {
739 }
740
741
update(cssu::Any const &)742 void UpdateCommandEnv::update( cssu::Any const & /*Status */)
743 throw (cssu::RuntimeException)
744 {
745 }
746
pop()747 void UpdateCommandEnv::pop() throw (cssu::RuntimeException)
748 {
749 }
750
751
752 } //end namespace dp_gui
753