bump product version to 5.0.4.1
[LibreOffice.git] / desktop / source / pkgchk / unopkg / unopkg_misc.cxx
blobd86a455238cfec6c713a6164836acfb9cb1b0f49
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
22 #include "deployment.hrc"
23 #include "unopkg_shared.h"
24 #include "dp_identifier.hxx"
25 #include "../../deployment/gui/dp_gui.hrc"
26 #include "lockfile.hxx"
27 #include <vcl/svapp.hxx>
28 #include <vcl/msgbox.hxx>
29 #include <rtl/bootstrap.hxx>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <osl/process.h>
33 #include <osl/file.hxx>
34 #include <osl/thread.hxx>
35 #include <tools/getprocessworkingdir.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <unotools/configmgr.hxx>
38 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
40 #include <cppuhelper/bootstrap.hxx>
41 #include <comphelper/sequence.hxx>
42 #include <stdio.h>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::ucb;
48 namespace unopkg {
50 OUString toString( OptionInfo const * info )
52 assert(info != 0);
53 OUStringBuffer buf;
54 buf.appendAscii("--");
55 buf.appendAscii(info->m_name);
56 if (info->m_short_option != '\0')
58 buf.appendAscii(" (short -" );
59 buf.append(info->m_short_option );
60 buf.appendAscii(")");
62 if (info->m_has_argument)
63 buf.appendAscii(" <argument>" );
64 return buf.makeStringAndClear();
68 OptionInfo const * getOptionInfo(
69 OptionInfo const * list,
70 OUString const & opt, sal_Unicode copt )
72 for ( ; list->m_name != 0; ++list )
74 OptionInfo const & option_info = *list;
75 if (!opt.isEmpty())
77 if (opt.equalsAsciiL(
78 option_info.m_name, option_info.m_name_length ) &&
79 (copt == '\0' || copt == option_info.m_short_option))
81 return &option_info;
84 else
86 OSL_ASSERT( copt != '\0' );
87 if (copt == option_info.m_short_option)
89 return &option_info;
93 OSL_FAIL( OUStringToOString(
94 opt, osl_getThreadTextEncoding() ).getStr() );
95 return 0;
99 bool isOption( OptionInfo const * option_info, sal_uInt32 * pIndex )
101 assert(option_info != 0);
102 if (osl_getCommandArgCount() <= *pIndex)
103 return false;
105 OUString arg;
106 osl_getCommandArg( *pIndex, &arg.pData );
107 sal_Int32 len = arg.getLength();
109 if (len < 2 || arg[ 0 ] != '-')
110 return false;
112 if (len == 2 && arg[ 1 ] == option_info->m_short_option)
114 ++(*pIndex);
115 dp_misc::TRACE(__FILE__ ": identified option \'\'"
116 + OUString( option_info->m_short_option ) + "\n");
117 return true;
119 if (arg[ 1 ] == '-' && rtl_ustr_ascii_compare(
120 arg.pData->buffer + 2, option_info->m_name ) == 0)
122 ++(*pIndex);
123 dp_misc::TRACE(__FILE__ ": identified option \'"
124 + OUString::createFromAscii(option_info->m_name) + "\'\n");
125 return true;
127 return false;
131 bool isBootstrapVariable(sal_uInt32 * pIndex)
133 OSL_ASSERT(osl_getCommandArgCount() >= *pIndex);
135 OUString arg;
136 osl_getCommandArg(*pIndex, &arg.pData);
137 if (arg.match("-env:"))
139 ++(*pIndex);
140 return true;
142 return false;
146 bool readArgument(
147 OUString * pValue, OptionInfo const * option_info, sal_uInt32 * pIndex )
149 if (isOption( option_info, pIndex ))
151 if (*pIndex < osl_getCommandArgCount())
153 OSL_ASSERT( pValue != 0 );
154 osl_getCommandArg( *pIndex, &pValue->pData );
155 dp_misc::TRACE(__FILE__ ": argument value: "
156 + *pValue + "\n");
157 ++(*pIndex);
158 return true;
160 --(*pIndex);
162 return false;
166 namespace {
167 struct ExecutableDir : public rtl::StaticWithInit<
168 OUString, ExecutableDir> {
169 const OUString operator () () {
170 OUString path;
171 if (osl_getExecutableFile( &path.pData ) != osl_Process_E_None) {
172 throw RuntimeException("cannot locate executable directory!",0);
174 return path.copy( 0, path.lastIndexOf( '/' ) );
177 struct ProcessWorkingDir : public rtl::StaticWithInit<
178 OUString, ProcessWorkingDir> {
179 const OUString operator () () {
180 OUString workingDir;
181 tools::getProcessWorkingDir(workingDir);
182 return workingDir;
185 } // anon namespace
188 OUString const & getExecutableDir()
190 return ExecutableDir::get();
194 OUString const & getProcessWorkingDir()
196 return ProcessWorkingDir::get();
200 OUString makeAbsoluteFileUrl(
201 OUString const & sys_path, OUString const & base_url, bool throw_exc )
203 // system path to file url
204 OUString file_url;
205 oslFileError rc = osl_getFileURLFromSystemPath( sys_path.pData, &file_url.pData );
206 if ( rc != osl_File_E_None) {
207 OUString tempPath;
208 if ( osl_getSystemPathFromFileURL( sys_path.pData, &tempPath.pData) == osl_File_E_None )
210 file_url = sys_path;
212 else if (throw_exc)
214 throw RuntimeException("cannot get file url from system path: " +
215 sys_path );
219 OUString abs;
220 if (osl_getAbsoluteFileURL(
221 base_url.pData, file_url.pData, &abs.pData ) != osl_File_E_None)
223 if (throw_exc) {
224 OUStringBuffer buf;
225 buf.appendAscii( "making absolute file url failed: \"" );
226 buf.append( base_url );
227 buf.appendAscii( "\" (base-url) and \"" );
228 buf.append( file_url );
229 buf.appendAscii( "\" (file-url)!" );
230 throw RuntimeException( buf.makeStringAndClear() );
232 return OUString();
234 return abs[ abs.getLength() -1 ] == '/'
235 ? abs.copy( 0, abs.getLength() -1 ) : abs;
239 namespace {
242 inline void printf_space( sal_Int32 space )
244 while (space--)
245 dp_misc::writeConsole(" ");
249 void printf_line(
250 OUString const & name, OUString const & value, sal_Int32 level )
252 printf_space( level );
253 dp_misc::writeConsole(name + ": " + value + "\n");
257 void printf_package(
258 Reference<deployment::XPackage> const & xPackage,
259 Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level )
261 beans::Optional< OUString > id(
262 level == 0
263 ? beans::Optional< OUString >(
264 true, dp_misc::getIdentifier( xPackage ) )
265 : xPackage->getIdentifier() );
266 if (id.IsPresent)
267 printf_line( "Identifier", id.Value, level );
268 OUString version(xPackage->getVersion());
269 if (!version.isEmpty())
270 printf_line( "Version", version, level + 1 );
271 printf_line( "URL", xPackage->getURL(), level + 1 );
273 beans::Optional< beans::Ambiguous<sal_Bool> > option(
274 xPackage->isRegistered( Reference<task::XAbortChannel>(), xCmdEnv ) );
275 OUString value;
276 if (option.IsPresent) {
277 beans::Ambiguous<sal_Bool> const & reg = option.Value;
278 if (reg.IsAmbiguous)
279 value = "unknown";
280 else
281 value = reg.Value ? OUString("yes") : OUString("no");
283 else
284 value = "n/a";
285 printf_line( "is registered", value, level + 1 );
287 const Reference<deployment::XPackageTypeInfo> xPackageType(
288 xPackage->getPackageType() );
289 OSL_ASSERT( xPackageType.is() );
290 if (xPackageType.is()) {
291 printf_line( "Media-Type", xPackageType->getMediaType(), level + 1 );
293 printf_line( "Description", xPackage->getDescription(), level + 1 );
294 if (xPackage->isBundle()) {
295 Sequence< Reference<deployment::XPackage> > seq(
296 xPackage->getBundle( Reference<task::XAbortChannel>(), xCmdEnv ) );
297 printf_space( level + 1 );
298 dp_misc::writeConsole("bundled Packages: {\n");
299 ::std::vector<Reference<deployment::XPackage> >vec_bundle;
300 ::comphelper::sequenceToContainer(vec_bundle, seq);
301 printf_packages( vec_bundle, ::std::vector<bool>(vec_bundle.size()),
302 xCmdEnv, level + 2 );
303 printf_space( level + 1 );
304 dp_misc::writeConsole("}\n");
308 } // anon namespace
310 void printf_unaccepted_licenses(
311 Reference<deployment::XPackage> const & ext)
313 OUString id(
314 dp_misc::getIdentifier(ext) );
315 printf_line( "Identifier", id, 0 );
316 printf_space(1);
317 dp_misc::writeConsole("License not accepted\n\n");
321 void printf_packages(
322 ::std::vector< Reference<deployment::XPackage> > const & allExtensions,
323 ::std::vector<bool> const & vecUnaccepted,
324 Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level )
326 OSL_ASSERT(allExtensions.size() == vecUnaccepted.size());
328 if (allExtensions.empty())
330 printf_space( level );
331 dp_misc::writeConsole("<none>\n");
333 else
335 typedef ::std::vector< Reference<deployment::XPackage> >::const_iterator I_EXT;
336 int index = 0;
337 for (I_EXT i = allExtensions.begin(); i != allExtensions.end(); ++i, ++index)
339 if (vecUnaccepted[index])
340 printf_unaccepted_licenses(*i);
341 else
342 printf_package( *i, xCmdEnv, level );
343 dp_misc::writeConsole("\n");
350 namespace {
353 Reference<XComponentContext> bootstrapStandAlone()
355 Reference<XComponentContext> xContext =
356 ::cppu::defaultBootstrap_InitialComponentContext();
358 Reference<lang::XMultiServiceFactory> xServiceManager(
359 xContext->getServiceManager(), UNO_QUERY_THROW );
360 // set global process service factory used by unotools config helpers
361 ::comphelper::setProcessServiceFactory( xServiceManager );
363 // Initialize the UCB (for backwards compatibility, in case some code still
364 // uses plain createInstance w/o args directly to obtain an instance):
365 UniversalContentBroker::create( xContext );
367 return xContext;
371 Reference<XComponentContext> connectToOffice(
372 Reference<XComponentContext> const & xLocalComponentContext,
373 bool verbose )
375 Sequence<OUString> args( 3 );
376 args[ 0 ] = "--nologo";
377 args[ 1 ] = "--nodefault";
379 OUString pipeId( ::dp_misc::generateRandomPipeId() );
380 OUStringBuffer buf;
381 buf.appendAscii( "--accept=pipe,name=" );
382 buf.append( pipeId );
383 buf.appendAscii( ";urp;" );
384 args[ 2 ] = buf.makeStringAndClear();
385 OUString appURL( getExecutableDir() + "/soffice" );
387 if (verbose)
389 dp_misc::writeConsole(
390 "Raising process: " + appURL +
391 "\nArguments: --nologo --nodefault " + args[2] +
392 "\n");
395 ::dp_misc::raiseProcess( appURL, args );
397 if (verbose)
398 dp_misc::writeConsole("OK. Connecting...");
400 OSL_ASSERT( buf.isEmpty() );
401 buf.appendAscii( "uno:pipe,name=" );
402 buf.append( pipeId );
403 buf.appendAscii( ";urp;StarOffice.ComponentContext" );
404 Reference<XComponentContext> xRet(
405 ::dp_misc::resolveUnoURL(
406 buf.makeStringAndClear(), xLocalComponentContext ),
407 UNO_QUERY_THROW );
408 if (verbose)
409 dp_misc::writeConsole("OK.\n");
411 return xRet;
414 } // anon namespace
416 /** returns the path to the lock file used by unopkg.
417 @return the path. An empty string signifies an error.
419 OUString getLockFilePath()
421 OUString ret;
422 OUString sBootstrap("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}");
423 rtl::Bootstrap::expandMacros(sBootstrap);
424 OUString sAbs;
425 if (::osl::File::E_None == ::osl::File::getAbsoluteFileURL(
426 sBootstrap, ".lock", sAbs))
428 if (::osl::File::E_None ==
429 ::osl::File::getSystemPathFromFileURL(sAbs, sBootstrap))
431 ret = sBootstrap;
435 return ret;
438 Reference<XComponentContext> getUNO(
439 bool verbose, bool shared, bool bGui,
440 Reference<XComponentContext> & out_localContext)
442 // do not create any user data (for the root user) in --shared mode:
443 if (shared) {
444 rtl::Bootstrap::set(
445 OUString("CFG_CacheUrl"),
446 OUString());
449 // hold lock during process runtime:
450 static ::desktop::Lockfile s_lockfile( false /* no IPC server */ );
451 Reference<XComponentContext> xComponentContext( bootstrapStandAlone() );
452 out_localContext = xComponentContext;
453 if (::dp_misc::office_is_running()) {
454 xComponentContext.set(
455 connectToOffice( xComponentContext, verbose ) );
457 else
459 if (! s_lockfile.check( 0 ))
461 OUString sMsg(ResId(RID_STR_CONCURRENTINSTANCE, *DeploymentResMgr::get()));
462 //Create this string before we call DeInitVCL, because this will kill
463 //the ResMgr
464 OUString sError(ResId(RID_STR_UNOPKG_ERROR, *DeploymentResMgr::get()));
466 sMsg += "\n" + getLockFilePath();
468 if (bGui)
470 //We show a message box or print to the console that there
471 //is another instance already running
472 if ( ! InitVCL() )
473 throw RuntimeException( "Cannot initialize VCL!" );
475 ScopedVclPtrInstance< WarningBox > warn(nullptr, WB_OK | WB_DEF_OK, sMsg);
476 warn->SetText(utl::ConfigManager::getProductName());
477 warn->SetIcon(0);
478 warn->Execute();
480 DeInitVCL();
483 throw LockFileException(sError + sMsg);
487 return xComponentContext;
492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */