xref: /trunk/main/desktop/source/pkgchk/unopkg/unopkg_cmdenv.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 "../../deployment/gui/dp_gui.hrc"
28 #include "../../deployment/gui/dp_gui_shared.hxx"
29 #include "unopkg_shared.h"
30 #include "osl/thread.h"
31 #include "rtl/memory.h"
32 #include "tools/string.hxx"
33 #include "tools/resmgr.hxx"
34 #include "cppuhelper/implbase3.hxx"
35 #include "cppuhelper/exc_hlp.hxx"
36 #include "comphelper/anytostring.hxx"
37 #include "unotools/configmgr.hxx"
38 #include "com/sun/star/lang/WrappedTargetException.hpp"
39 #include "com/sun/star/task/XInteractionAbort.hpp"
40 #include "com/sun/star/task/XInteractionApprove.hpp"
41 #include "com/sun/star/deployment/InstallException.hpp"
42 #include "com/sun/star/container/ElementExistException.hpp"
43 #include "com/sun/star/deployment/LicenseException.hpp"
44 #include "com/sun/star/deployment/VersionException.hpp"
45 #include "com/sun/star/deployment/PlatformException.hpp"
46 #include "com/sun/star/i18n/XCollator.hpp"
47 #include "com/sun/star/i18n/CollatorOptions.hpp"
48 
49 #include <stdio.h>
50 #include "deployment.hrc"
51 #include "dp_version.hxx"
52 
53 namespace css = ::com::sun::star;
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::ucb;
56 using namespace ::com::sun::star::uno;
57 using namespace ::unopkg;
58 using ::rtl::OUString;
59 
60 
61 namespace {
62 
63 //==============================================================================
64 struct OfficeLocale :
65         public rtl::StaticWithInit<const lang::Locale, OfficeLocale> {
operator ()__anona09d055a0111::OfficeLocale66     const lang::Locale operator () () {
67         OUString slang;
68         if (! (::utl::ConfigManager::GetDirectConfigProperty(
69                    ::utl::ConfigManager::LOCALE ) >>= slang))
70             throw RuntimeException( OUSTR("Cannot determine language!"), 0 );
71         return toLocale(slang);
72     }
73 };
74 
75 //==============================================================================
76 class CommandEnvironmentImpl
77     : public ::cppu::WeakImplHelper3< XCommandEnvironment,
78                                       task::XInteractionHandler,
79                                       XProgressHandler >
80 {
81     sal_Int32 m_logLevel;
82     bool m_option_force_overwrite;
83     bool m_option_verbose;
84     Reference< XComponentContext > m_xComponentContext;
85     Reference< XProgressHandler > m_xLogFile;
86 
87     void update_( Any const & Status );
88     void printLicense(const OUString & sName,const OUString& sLicense,
89                       bool & accept, bool & decline);
90 
91 public:
92     virtual ~CommandEnvironmentImpl();
93     CommandEnvironmentImpl(
94         Reference<XComponentContext> const & xComponentContext,
95         OUString const & log_file,
96         bool option_force_overwrite,
97         bool option_verbose);
98 
99     // XCommandEnvironment
100     virtual Reference< task::XInteractionHandler > SAL_CALL
101     getInteractionHandler();
102     virtual Reference< XProgressHandler > SAL_CALL getProgressHandler();
103 
104     // XInteractionHandler
105     virtual void SAL_CALL handle(
106         Reference< task::XInteractionRequest > const & xRequest );
107 
108     // XProgressHandler
109     virtual void SAL_CALL push( Any const & Status );
110     virtual void SAL_CALL update( Any const & Status );
111     virtual void SAL_CALL pop();
112 };
113 
114 
115 //______________________________________________________________________________
CommandEnvironmentImpl(Reference<XComponentContext> const & xComponentContext,OUString const & log_file,bool option_force_overwrite,bool option_verbose)116 CommandEnvironmentImpl::CommandEnvironmentImpl(
117     Reference<XComponentContext> const & xComponentContext,
118     OUString const & log_file,
119     bool option_force_overwrite,
120     bool option_verbose)
121     : m_logLevel(0),
122       m_option_force_overwrite( option_force_overwrite ),
123       m_option_verbose( option_verbose ),
124       m_xComponentContext(xComponentContext)
125 {
126     if (log_file.getLength() > 0) {
127         const Any logfile(log_file);
128         m_xLogFile.set(
129             xComponentContext->getServiceManager()
130             ->createInstanceWithArgumentsAndContext(
131                 OUSTR("com.sun.star.comp.deployment.ProgressLog"),
132                 Sequence<Any>( &logfile, 1 ), xComponentContext ),
133             UNO_QUERY_THROW );
134     }
135 }
136 
137 //______________________________________________________________________________
~CommandEnvironmentImpl()138 CommandEnvironmentImpl::~CommandEnvironmentImpl()
139 {
140     try {
141         Reference< lang::XComponent > xComp( m_xLogFile, UNO_QUERY );
142         if (xComp.is())
143             xComp->dispose();
144     }
145     catch (RuntimeException & exc) {
146         (void) exc;
147         OSL_ENSURE( 0, ::rtl::OUStringToOString(
148                         exc.Message, osl_getThreadTextEncoding() ).getStr() );
149     }
150 }
151 
152 //May throw exceptions
printLicense(const OUString & sName,const OUString & sLicense,bool & accept,bool & decline)153 void CommandEnvironmentImpl::printLicense(
154     const OUString & sName, const OUString& sLicense, bool & accept, bool &decline)
155 {
156     ResMgr * pResMgr = DeploymentResMgr::get();
157     String s1tmp(ResId(RID_STR_UNOPKG_ACCEPT_LIC_1, *pResMgr));
158     s1tmp.SearchAndReplaceAllAscii( "$NAME", sName );
159     OUString s1(s1tmp);
160     OUString s2 = String(ResId(RID_STR_UNOPKG_ACCEPT_LIC_2, *pResMgr));
161     OUString s3 = String(ResId(RID_STR_UNOPKG_ACCEPT_LIC_3, *pResMgr));
162     OUString s4 = String(ResId(RID_STR_UNOPKG_ACCEPT_LIC_4, *pResMgr));
163     OUString sYES = String(ResId(RID_STR_UNOPKG_ACCEPT_LIC_YES, *pResMgr));
164     OUString sY = String(ResId(RID_STR_UNOPKG_ACCEPT_LIC_Y, *pResMgr));
165     OUString sNO = String(ResId(RID_STR_UNOPKG_ACCEPT_LIC_NO, *pResMgr));
166     OUString sN = String(ResId(RID_STR_UNOPKG_ACCEPT_LIC_N, *pResMgr));
167 
168     OUString sNewLine(RTL_CONSTASCII_USTRINGPARAM("\n"));
169 
170     dp_misc::writeConsole(sNewLine + sNewLine + s1 + sNewLine + sNewLine);
171     dp_misc::writeConsole(sLicense + sNewLine + sNewLine);
172     dp_misc::writeConsole(s2 + sNewLine);
173     dp_misc::writeConsole(s3);
174 
175     //the user may enter "yes" or "no", we compare in a case insensitive way
176     Reference< css::i18n::XCollator > xCollator(
177         m_xComponentContext->getServiceManager()
178             ->createInstanceWithContext(
179                 OUSTR("com.sun.star.i18n.Collator"),m_xComponentContext),
180             UNO_QUERY_THROW );
181     xCollator->loadDefaultCollator(OfficeLocale::get(),
182         css::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE);
183 
184     do
185     {
186         OUString sAnswer = dp_misc::readConsole();
187         if (xCollator->compareString(sAnswer, sYES) == 0
188             || xCollator->compareString(sAnswer, sY) == 0)
189         {
190             accept = true;
191             break;
192         }
193         else if(xCollator->compareString(sAnswer, sNO) == 0
194             || xCollator->compareString(sAnswer, sN) == 0)
195         {
196             decline = true;
197             break;
198         }
199         else
200         {
201             dp_misc::writeConsole(sNewLine + sNewLine + s4 + sNewLine);
202         }
203     }
204     while(true);
205 }
206 
207 // XCommandEnvironment
208 //______________________________________________________________________________
209 Reference< task::XInteractionHandler >
getInteractionHandler()210 CommandEnvironmentImpl::getInteractionHandler()
211 {
212     return this;
213 }
214 
215 //______________________________________________________________________________
getProgressHandler()216 Reference< XProgressHandler > CommandEnvironmentImpl::getProgressHandler()
217 {
218     return this;
219 }
220 
221 // XInteractionHandler
222 //______________________________________________________________________________
handle(Reference<task::XInteractionRequest> const & xRequest)223 void CommandEnvironmentImpl::handle(
224     Reference<task::XInteractionRequest> const & xRequest )
225 {
226     Any request( xRequest->getRequest() );
227     OSL_ASSERT( request.getValueTypeClass() == TypeClass_EXCEPTION );
228     dp_misc::TRACE(OUSTR("[unopkg_cmdenv.cxx] incoming request:\n")
229         + ::comphelper::anyToString(request) + OUSTR("\n\n"));
230 
231     // selections:
232     bool approve = false;
233     bool abort = false;
234 
235     lang::WrappedTargetException wtExc;
236     deployment::LicenseException licExc;
237     deployment::InstallException instExc;
238     deployment::PlatformException platExc;
239     deployment::VersionException verExc;
240 
241 
242     bool bLicenseException = false;
243     if (request >>= wtExc) {
244         // ignore intermediate errors of legacy packages, i.e.
245         // former pkgchk behaviour:
246         const Reference<deployment::XPackage> xPackage(
247             wtExc.Context, UNO_QUERY );
248         OSL_ASSERT( xPackage.is() );
249         if (xPackage.is()) {
250             const Reference<deployment::XPackageTypeInfo> xPackageType(
251                 xPackage->getPackageType() );
252             OSL_ASSERT( xPackageType.is() );
253             if (xPackageType.is()) {
254                 approve = (xPackage->isBundle() &&
255                            xPackageType->getMediaType().matchAsciiL(
256                                RTL_CONSTASCII_STRINGPARAM(
257                                    "application/"
258                                    "vnd.sun.star.legacy-package-bundle") ));
259             }
260         }
261         abort = !approve;
262         if (abort) {
263             // notify cause as error:
264             request = wtExc.TargetException;
265         }
266         else {
267             // handable deployment error signaled, e.g.
268             // bundle item registration failed, notify as warning:
269             update_( wtExc.TargetException );
270         }
271     }
272     else if (request >>= licExc)
273     {
274         printLicense(licExc.ExtensionName, licExc.Text, approve, abort);
275     }
276     else if (request >>= instExc)
277     {
278         //Only if the unopgk was started with gui + extension then the user is asked.
279         //In console mode there is no asking.
280         approve = true;
281     }
282     else if (request >>= platExc)
283     {
284         String sMsg(ResId(RID_STR_UNSUPPORTED_PLATFORM, *dp_gui::DeploymentGuiResMgr::get()));
285         sMsg.SearchAndReplaceAllAscii("%Name", platExc.package->getDisplayName());
286         dp_misc::writeConsole(OUSTR("\n") + sMsg + OUSTR("\n\n"));
287         approve = true;
288     }
289     else {
290         deployment::VersionException nc_exc;
291         if (request >>= nc_exc) {
292             approve = m_option_force_overwrite ||
293                 (::dp_misc::compareVersions(nc_exc.NewVersion, nc_exc.Deployed->getVersion())
294                  == ::dp_misc::GREATER);
295             abort = !approve;
296         }
297         else
298             return; // unknown request => no selection at all
299     }
300 
301     //In case of a user declining a license abort is true but this is intended,
302     //therefore no logging
303     if (abort && m_option_verbose && !bLicenseException)
304     {
305         OUString msg = ::comphelper::anyToString(request);
306         dp_misc::writeConsoleError(
307             OUSTR("\nERROR: ") + msg + OUSTR("\n"));
308     }
309 
310     // select:
311     Sequence< Reference<task::XInteractionContinuation> > conts(
312         xRequest->getContinuations() );
313     Reference<task::XInteractionContinuation> const * pConts =
314         conts.getConstArray();
315     sal_Int32 len = conts.getLength();
316     for ( sal_Int32 pos = 0; pos < len; ++pos )
317     {
318         if (approve) {
319             Reference<task::XInteractionApprove> xInteractionApprove(
320                 pConts[ pos ], UNO_QUERY );
321             if (xInteractionApprove.is()) {
322                 xInteractionApprove->select();
323                 break;
324             }
325         }
326         else if (abort) {
327             Reference<task::XInteractionAbort> xInteractionAbort(
328                 pConts[ pos ], UNO_QUERY );
329             if (xInteractionAbort.is()) {
330                 xInteractionAbort->select();
331                 break;
332             }
333         }
334     }
335 }
336 
337 // XProgressHandler
338 //______________________________________________________________________________
push(Any const & Status)339 void CommandEnvironmentImpl::push( Any const & Status )
340 {
341     update_( Status );
342     OSL_ASSERT( m_logLevel >= 0 );
343     ++m_logLevel;
344     if (m_xLogFile.is())
345         m_xLogFile->push( Status );
346 }
347 
348 //______________________________________________________________________________
update_(Any const & Status)349 void CommandEnvironmentImpl::update_( Any const & Status )
350 {
351     if (! Status.hasValue())
352         return;
353     bool bUseErr = false;
354     OUString msg;
355     if (Status >>= msg) {
356         if (! m_option_verbose)
357             return;
358     }
359     else {
360         ::rtl::OUStringBuffer buf;
361         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("WARNING: ") );
362         deployment::DeploymentException dp_exc;
363         if (Status >>= dp_exc) {
364             buf.append( dp_exc.Message );
365             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", Cause: ") );
366             buf.append( ::comphelper::anyToString(dp_exc.Cause) );
367         }
368         else {
369             buf.append( ::comphelper::anyToString(Status) );
370         }
371         msg = buf.makeStringAndClear();
372         bUseErr = true;
373     }
374     OSL_ASSERT( m_logLevel >= 0 );
375     for ( sal_Int32 n = 0; n < m_logLevel; ++n )
376     {
377         if (bUseErr)
378             dp_misc::writeConsoleError(" ");
379         else
380             dp_misc::writeConsole(" ");
381     }
382 
383     if (bUseErr)
384         dp_misc::writeConsoleError(msg + OUSTR("\n"));
385     else
386         dp_misc::writeConsole(msg + OUSTR("\n"));
387 }
388 
389 //______________________________________________________________________________
update(Any const & Status)390 void CommandEnvironmentImpl::update( Any const & Status )
391 {
392     update_( Status );
393     if (m_xLogFile.is())
394         m_xLogFile->update( Status );
395 }
396 
397 //______________________________________________________________________________
pop()398 void CommandEnvironmentImpl::pop()
399 {
400     OSL_ASSERT( m_logLevel > 0 );
401     --m_logLevel;
402     if (m_xLogFile.is())
403         m_xLogFile->pop();
404 }
405 
406 
407 } // anon namespace
408 
409 namespace unopkg {
410 
411 //==============================================================================
createCmdEnv(Reference<XComponentContext> const & xContext,OUString const & logFile,bool option_force_overwrite,bool option_verbose)412 Reference< XCommandEnvironment > createCmdEnv(
413     Reference< XComponentContext > const & xContext,
414     OUString const & logFile,
415     bool option_force_overwrite,
416     bool option_verbose)
417 {
418     return new CommandEnvironmentImpl(
419         xContext, logFile, option_force_overwrite, option_verbose);
420 }
421 } // unopkg
422