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