summaryrefslogtreecommitdiff
path: root/desktop/source/deployment/misc/dp_misc.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/source/deployment/misc/dp_misc.cxx')
-rw-r--r--desktop/source/deployment/misc/dp_misc.cxx632
1 files changed, 632 insertions, 0 deletions
diff --git a/desktop/source/deployment/misc/dp_misc.cxx b/desktop/source/deployment/misc/dp_misc.cxx
new file mode 100644
index 000000000000..1a46cdda3d5a
--- /dev/null
+++ b/desktop/source/deployment/misc/dp_misc.cxx
@@ -0,0 +1,632 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_desktop.hxx"
+
+
+#include "dp_misc.h"
+#include "dp_version.hxx"
+#include "dp_interact.h"
+#include "rtl/uri.hxx"
+#include "rtl/digest.h"
+#include "rtl/random.h"
+#include "rtl/bootstrap.hxx"
+#include "unotools/bootstrap.hxx"
+#include "osl/file.hxx"
+#include "osl/pipe.hxx"
+#include "osl/security.hxx"
+#include "osl/thread.hxx"
+#include "osl/mutex.hxx"
+#include "com/sun/star/ucb/CommandAbortedException.hpp"
+#include "com/sun/star/task/XInteractionHandler.hpp"
+#include "com/sun/star/bridge/UnoUrlResolver.hpp"
+#include "com/sun/star/bridge/XUnoUrlResolver.hpp"
+#include "com/sun/star/deployment/ExtensionManager.hpp"
+#include "com/sun/star/task/XRestartManager.hpp"
+#include "boost/scoped_array.hpp"
+#include "boost/shared_ptr.hpp"
+#include <comphelper/processfactory.hxx>
+
+#ifdef WNT
+#define UNICODE
+#define _UNICODE
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#endif
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using ::rtl::OUString;
+using ::rtl::OString;
+
+
+#define SOFFICE1 "soffice.exe"
+#define SOFFICE2 "soffice.bin"
+#define SBASE "sbase.exe"
+#define SCALC "scalc.exe"
+#define SDRAW "sdraw.exe"
+#define SIMPRESS "simpress.exe"
+#define SWRITER "swriter.exe"
+
+namespace dp_misc {
+namespace {
+
+struct UnoRc : public rtl::StaticWithInit<
+ const boost::shared_ptr<rtl::Bootstrap>, UnoRc> {
+ const boost::shared_ptr<rtl::Bootstrap> operator () () {
+ OUString unorc( RTL_CONSTASCII_USTRINGPARAM(
+ "$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno")) );
+ ::rtl::Bootstrap::expandMacros( unorc );
+ ::boost::shared_ptr< ::rtl::Bootstrap > ret(
+ new ::rtl::Bootstrap( unorc ) );
+ OSL_ASSERT( ret->getHandle() != 0 );
+ return ret;
+ }
+};
+
+struct OfficePipeId : public rtl::StaticWithInit<const OUString, OfficePipeId> {
+ const OUString operator () ();
+};
+
+const OUString OfficePipeId::operator () ()
+{
+ OUString userPath;
+ ::utl::Bootstrap::PathStatus aLocateResult =
+ ::utl::Bootstrap::locateUserInstallation( userPath );
+ if (!(aLocateResult == ::utl::Bootstrap::PATH_EXISTS ||
+ aLocateResult == ::utl::Bootstrap::PATH_VALID))
+ {
+ throw Exception(OUSTR("Extension Manager: Could not obtain path for UserInstallation."), 0);
+ }
+
+ rtlDigest digest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
+ if (digest <= 0) {
+ throw RuntimeException(
+ OUSTR("cannot get digest rtl_Digest_AlgorithmMD5!"), 0 );
+ }
+
+ sal_uInt8 const * data =
+ reinterpret_cast<sal_uInt8 const *>(userPath.getStr());
+ sal_Size size = (userPath.getLength() * sizeof (sal_Unicode));
+ sal_uInt32 md5_key_len = rtl_digest_queryLength( digest );
+ ::boost::scoped_array<sal_uInt8> md5_buf( new sal_uInt8 [ md5_key_len ] );
+
+ rtl_digest_init( digest, data, static_cast<sal_uInt32>(size) );
+ rtl_digest_update( digest, data, static_cast<sal_uInt32>(size) );
+ rtl_digest_get( digest, md5_buf.get(), md5_key_len );
+ rtl_digest_destroy( digest );
+
+ // create hex-value string from the MD5 value to keep
+ // the string size minimal
+ ::rtl::OUStringBuffer buf;
+ buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("SingleOfficeIPC_") );
+ for ( sal_uInt32 i = 0; i < md5_key_len; ++i ) {
+ buf.append( static_cast<sal_Int32>(md5_buf[ i ]), 0x10 );
+ }
+ return buf.makeStringAndClear();
+}
+
+bool existsOfficePipe()
+{
+ OUString const & pipeId = OfficePipeId::get();
+ if (pipeId.getLength() == 0)
+ return false;
+ ::osl::Security sec;
+ ::osl::Pipe pipe( pipeId, osl_Pipe_OPEN, sec );
+ return pipe.is();
+}
+
+
+//Returns true if the Folder was more recently modified then
+//the lastsynchronized file. That is the repository needs to
+//be synchronized.
+bool compareExtensionFolderWithLastSynchronizedFile(
+ OUString const & folderURL, OUString const & fileURL)
+{
+ bool bNeedsSync = false;
+ ::osl::DirectoryItem itemExtFolder;
+ ::osl::File::RC err1 =
+ ::osl::DirectoryItem::get(folderURL, itemExtFolder);
+ //If it does not exist, then there is nothing to be done
+ if (err1 == ::osl::File::E_NOENT)
+ {
+ return false;
+ }
+ else if (err1 != ::osl::File::E_None)
+ {
+ OSL_FAIL("Cannot access extension folder");
+ return true; //sync just in case
+ }
+
+ //If last synchronized does not exist, then OOo is started for the first time
+ ::osl::DirectoryItem itemFile;
+ ::osl::File::RC err2 = ::osl::DirectoryItem::get(fileURL, itemFile);
+ if (err2 == ::osl::File::E_NOENT)
+ {
+ return true;
+
+ }
+ else if (err2 != ::osl::File::E_None)
+ {
+ OSL_FAIL("Cannot access file lastsynchronized");
+ return true; //sync just in case
+ }
+
+ //compare the modification time of the extension folder and the last
+ //modified file
+ ::osl::FileStatus statFolder(FileStatusMask_ModifyTime);
+ ::osl::FileStatus statFile(FileStatusMask_ModifyTime);
+ if (itemExtFolder.getFileStatus(statFolder) == ::osl::File::E_None)
+ {
+ if (itemFile.getFileStatus(statFile) == ::osl::File::E_None)
+ {
+ TimeValue timeFolder = statFolder.getModifyTime();
+ TimeValue timeFile = statFile.getModifyTime();
+
+ if (timeFile.Seconds < timeFolder.Seconds)
+ bNeedsSync = true;
+ }
+ else
+ {
+ OSL_ASSERT(0);
+ bNeedsSync = true;
+ }
+ }
+ else
+ {
+ OSL_ASSERT(0);
+ bNeedsSync = true;
+ }
+ return bNeedsSync;
+}
+
+bool needToSyncRepostitory(OUString const & name)
+{
+ OUString folder;
+ OUString file;
+ if (name.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("bundled"))))
+ {
+ folder = OUString(
+ RTL_CONSTASCII_USTRINGPARAM("$BUNDLED_EXTENSIONS"));
+ file = OUString (
+ RTL_CONSTASCII_USTRINGPARAM(
+ "$BUNDLED_EXTENSIONS_USER/lastsynchronized"));
+ }
+ else if (name.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("shared"))))
+ {
+ folder = OUString(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "$UNO_SHARED_PACKAGES_CACHE/uno_packages"));
+ file = OUString (
+ RTL_CONSTASCII_USTRINGPARAM(
+ "$SHARED_EXTENSIONS_USER/lastsynchronized"));
+ }
+ else
+ {
+ OSL_ASSERT(0);
+ return true;
+ }
+ ::rtl::Bootstrap::expandMacros(folder);
+ ::rtl::Bootstrap::expandMacros(file);
+ return compareExtensionFolderWithLastSynchronizedFile(
+ folder, file);
+}
+
+
+} // anon namespace
+
+//==============================================================================
+
+namespace {
+inline OUString encodeForRcFile( OUString const & str )
+{
+ // escape $\{} (=> rtl bootstrap files)
+ ::rtl::OUStringBuffer buf;
+ sal_Int32 pos = 0;
+ const sal_Int32 len = str.getLength();
+ for ( ; pos < len; ++pos ) {
+ sal_Unicode c = str[ pos ];
+ switch (c) {
+ case '$':
+ case '\\':
+ case '{':
+ case '}':
+ buf.append( static_cast<sal_Unicode>('\\') );
+ break;
+ }
+ buf.append( c );
+ }
+ return buf.makeStringAndClear();
+}
+}
+
+//==============================================================================
+OUString makeURL( OUString const & baseURL, OUString const & relPath_ )
+{
+ ::rtl::OUStringBuffer buf;
+ if (baseURL.getLength() > 1 && baseURL[ baseURL.getLength() - 1 ] == '/')
+ buf.append( baseURL.copy( 0, baseURL.getLength() - 1 ) );
+ else
+ buf.append( baseURL );
+ OUString relPath(relPath_);
+ if (relPath.getLength() > 0 && relPath[ 0 ] == '/')
+ relPath = relPath.copy( 1 );
+ if (relPath.getLength() > 0)
+ {
+ buf.append( static_cast<sal_Unicode>('/') );
+ if (baseURL.matchAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:") )) {
+ // encode for macro expansion: relPath is supposed to have no
+ // macros, so encode $, {} \ (bootstrap mimic)
+ relPath = encodeForRcFile(relPath);
+
+ // encode once more for vnd.sun.star.expand schema:
+ // vnd.sun.star.expand:$UNO_...
+ // will expand to file-url
+ relPath = ::rtl::Uri::encode( relPath, rtl_UriCharClassUric,
+ rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8 );
+ }
+ buf.append( relPath );
+ }
+ return buf.makeStringAndClear();
+}
+
+OUString makeURLAppendSysPathSegment( OUString const & baseURL, OUString const & relPath_ )
+{
+ OUString segment = relPath_;
+ OSL_ASSERT(segment.indexOf(static_cast<sal_Unicode>('/')) == -1);
+
+ ::rtl::Uri::encode(
+ segment, rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8);
+ return makeURL(baseURL, segment);
+}
+
+
+
+//==============================================================================
+OUString expandUnoRcTerm( OUString const & term_ )
+{
+ OUString term(term_);
+ UnoRc::get()->expandMacrosFrom( term );
+ return term;
+}
+
+OUString makeRcTerm( OUString const & url )
+{
+ OSL_ASSERT( url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM(
+ "vnd.sun.star.expand:") ) );
+ if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:") )) {
+ // cut protocol:
+ OUString rcterm( url.copy( sizeof ("vnd.sun.star.expand:") - 1 ) );
+ // decode uric class chars:
+ rcterm = ::rtl::Uri::decode(
+ rcterm, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
+ return rcterm;
+ }
+ else
+ return url;
+}
+
+//==============================================================================
+OUString expandUnoRcUrl( OUString const & url )
+{
+ if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:") )) {
+ // cut protocol:
+ OUString rcurl( url.copy( sizeof ("vnd.sun.star.expand:") - 1 ) );
+ // decode uric class chars:
+ rcurl = ::rtl::Uri::decode(
+ rcurl, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
+ // expand macro string:
+ UnoRc::get()->expandMacrosFrom( rcurl );
+ return rcurl;
+ }
+ else {
+ return url;
+ }
+}
+
+//==============================================================================
+bool office_is_running()
+{
+ //We need to check if we run within the office process. Then we must not use the pipe, because
+ //this could cause a deadlock. This is actually a workaround for i82778
+ OUString sFile;
+ oslProcessError err = osl_getExecutableFile(& sFile.pData);
+ bool ret = false;
+ if (osl_Process_E_None == err)
+ {
+ sFile = sFile.copy(sFile.lastIndexOf('/') + 1);
+ if (
+#if defined UNIX
+ sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SOFFICE2)))
+#elif defined WNT || defined OS2
+ //osl_getExecutableFile should deliver "soffice.bin" on windows
+ //even if swriter.exe, scalc.exe etc. was started. This is a bug
+ //in osl_getExecutableFile
+ sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SOFFICE1)))
+ || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SOFFICE2)))
+ || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SBASE)))
+ || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SCALC)))
+ || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SDRAW)))
+ || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SIMPRESS)))
+ || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SWRITER)))
+#else
+#error "Unsupported platform"
+#endif
+
+ )
+ ret = true;
+ else
+ ret = existsOfficePipe();
+ }
+ else
+ {
+ OSL_FAIL("NOT osl_Process_E_None ");
+ //if osl_getExecutable file than we take the risk of creating a pipe
+ ret = existsOfficePipe();
+ }
+ return ret;
+}
+
+//==============================================================================
+oslProcess raiseProcess(
+ OUString const & appURL, Sequence<OUString> const & args )
+{
+ ::osl::Security sec;
+ oslProcess hProcess = 0;
+ oslProcessError rc = osl_executeProcess(
+ appURL.pData,
+ reinterpret_cast<rtl_uString **>(
+ const_cast<OUString *>(args.getConstArray()) ),
+ args.getLength(),
+ osl_Process_DETACHED,
+ sec.getHandle(),
+ 0, // => current working dir
+ 0, 0, // => no env vars
+ &hProcess );
+
+ switch (rc) {
+ case osl_Process_E_None:
+ break;
+ case osl_Process_E_NotFound:
+ throw RuntimeException( OUSTR("image not found!"), 0 );
+ case osl_Process_E_TimedOut:
+ throw RuntimeException( OUSTR("timout occurred!"), 0 );
+ case osl_Process_E_NoPermission:
+ throw RuntimeException( OUSTR("permission denied!"), 0 );
+ case osl_Process_E_Unknown:
+ throw RuntimeException( OUSTR("unknown error!"), 0 );
+ case osl_Process_E_InvalidError:
+ default:
+ throw RuntimeException( OUSTR("unmapped error!"), 0 );
+ }
+
+ return hProcess;
+}
+
+//==============================================================================
+OUString generateRandomPipeId()
+{
+ // compute some good pipe id:
+ static rtlRandomPool s_hPool = rtl_random_createPool();
+ if (s_hPool == 0)
+ throw RuntimeException( OUSTR("cannot create random pool!?"), 0 );
+ sal_uInt8 bytes[ 32 ];
+ if (rtl_random_getBytes(
+ s_hPool, bytes, ARLEN(bytes) ) != rtl_Random_E_None) {
+ throw RuntimeException( OUSTR("random pool error!?"), 0 );
+ }
+ ::rtl::OUStringBuffer buf;
+ for ( sal_uInt32 i = 0; i < ARLEN(bytes); ++i ) {
+ buf.append( static_cast<sal_Int32>(bytes[ i ]), 0x10 );
+ }
+ return buf.makeStringAndClear();
+}
+
+//==============================================================================
+Reference<XInterface> resolveUnoURL(
+ OUString const & connectString,
+ Reference<XComponentContext> const & xLocalContext,
+ AbortChannel * abortChannel )
+{
+ Reference<bridge::XUnoUrlResolver> xUnoUrlResolver(
+ bridge::UnoUrlResolver::create( xLocalContext ) );
+
+ for (;;)
+ {
+ if (abortChannel != 0 && abortChannel->isAborted()) {
+ throw ucb::CommandAbortedException(
+ OUSTR("abort!"), Reference<XInterface>() );
+ }
+ try {
+ return xUnoUrlResolver->resolve( connectString );
+ }
+ catch (connection::NoConnectException &) {
+ TimeValue tv = { 0 /* secs */, 500000000 /* nanosecs */ };
+ ::osl::Thread::wait( tv );
+ }
+ }
+}
+
+#ifdef WNT
+void writeConsoleWithStream(::rtl::OUString const & sText, HANDLE stream)
+{
+ DWORD nWrittenChars = 0;
+ WriteFile(stream, sText.getStr(),
+ sText.getLength() * 2, &nWrittenChars, NULL);
+}
+#else
+void writeConsoleWithStream(::rtl::OUString const & sText, FILE * stream)
+{
+ OString s = OUStringToOString(sText, osl_getThreadTextEncoding());
+ fprintf(stream, "%s", s.getStr());
+ fflush(stream);
+}
+#endif
+
+#ifdef WNT
+void writeConsoleWithStream(::rtl::OString const & sText, HANDLE stream)
+{
+ writeConsoleWithStream(OStringToOUString(
+ sText, RTL_TEXTENCODING_UTF8), stream);
+}
+#else
+void writeConsoleWithStream(::rtl::OString const & sText, FILE * stream)
+{
+ fprintf(stream, "%s", sText.getStr());
+ fflush(stream);
+}
+#endif
+
+void writeConsole(::rtl::OUString const & sText)
+{
+#ifdef WNT
+ writeConsoleWithStream(sText, GetStdHandle(STD_OUTPUT_HANDLE));
+#else
+ writeConsoleWithStream(sText, stdout);
+#endif
+}
+
+void writeConsole(::rtl::OString const & sText)
+{
+#ifdef WNT
+ writeConsoleWithStream(sText, GetStdHandle(STD_OUTPUT_HANDLE));
+#else
+ writeConsoleWithStream(sText, stdout);
+#endif
+}
+
+void writeConsoleError(::rtl::OUString const & sText)
+{
+#ifdef WNT
+ writeConsoleWithStream(sText, GetStdHandle(STD_ERROR_HANDLE));
+#else
+ writeConsoleWithStream(sText, stderr);
+#endif
+}
+
+
+void writeConsoleError(::rtl::OString const & sText)
+{
+#ifdef WNT
+ writeConsoleWithStream(sText, GetStdHandle(STD_ERROR_HANDLE));
+#else
+ writeConsoleWithStream(sText, stderr);
+#endif
+}
+
+
+
+OUString readConsole()
+{
+#ifdef WNT
+ sal_Unicode aBuffer[1024];
+ DWORD dwRead = 0;
+ //unopkg.com feeds unopkg.exe with wchar_t|s
+ if (ReadFile( GetStdHandle(STD_INPUT_HANDLE), &aBuffer, sizeof(aBuffer), &dwRead, NULL ) )
+ {
+ OSL_ASSERT((dwRead % 2) == 0);
+ OUString value( aBuffer, dwRead / 2);
+ return value.trim();
+ }
+#else
+ char buf[1024];
+ rtl_zeroMemory(buf, 1024);
+ // read one char less so that the last char in buf is always zero
+ if (fgets(buf, 1024, stdin) != NULL)
+ {
+ OUString value = ::rtl::OStringToOUString(::rtl::OString(buf), osl_getThreadTextEncoding());
+ return value.trim();
+ }
+#endif
+ return OUString();
+}
+
+void TRACE(::rtl::OUString const & sText)
+{
+ (void) sText;
+#if OSL_DEBUG_LEVEL > 1
+ writeConsole(sText);
+#endif
+}
+
+void TRACE(::rtl::OString const & sText)
+{
+ (void) sText;
+#if OSL_DEBUG_LEVEL > 1
+ writeConsole(sText);
+#endif
+}
+
+void syncRepositories(Reference<ucb::XCommandEnvironment> const & xCmdEnv)
+{
+ OUString sDisable;
+ ::rtl::Bootstrap::get( OUSTR( "DISABLE_EXTENSION_SYNCHRONIZATION" ), sDisable, OUString() );
+ if (sDisable.getLength() > 0)
+ return;
+
+ Reference<deployment::XExtensionManager> xExtensionManager;
+ //synchronize shared before bundled otherewise there are
+ //more revoke and registration calls.
+ sal_Bool bModified = false;
+ if (needToSyncRepostitory(OUString(RTL_CONSTASCII_USTRINGPARAM("shared")))
+ || needToSyncRepostitory(OUString(RTL_CONSTASCII_USTRINGPARAM("bundled"))))
+ {
+ xExtensionManager =
+ deployment::ExtensionManager::get(
+ comphelper_getProcessComponentContext());
+
+ if (xExtensionManager.is())
+ {
+ bModified = xExtensionManager->synchronize(
+ Reference<task::XAbortChannel>(), xCmdEnv);
+ }
+ }
+
+ if (bModified)
+ {
+ Reference<task::XRestartManager> restarter(
+ comphelper_getProcessComponentContext()->getValueByName(
+ OUSTR( "/singletons/com.sun.star.task.OfficeRestartManager") ), UNO_QUERY );
+ if (restarter.is())
+ {
+ OSL_TRACE( "Request restart for modified extensions manager" );
+ restarter->requestRestart(xCmdEnv.is() == sal_True ? xCmdEnv->getInteractionHandler() :
+ Reference<task::XInteractionHandler>());
+ }
+ }
+}
+
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */