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