LCOV - code coverage report
Current view: top level - shell/source/unix/exec - shellexec.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 12 87 13.8 %
Date: 2014-11-03 Functions: 1 7 14.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include <config_folders.h>
      21             : 
      22             : #include <osl/diagnose.h>
      23             : #include <osl/thread.h>
      24             : #include <osl/process.h>
      25             : #include <osl/file.hxx>
      26             : #include <rtl/ustrbuf.hxx>
      27             : 
      28             : #include <rtl/uri.hxx>
      29             : #include "shellexec.hxx"
      30             : #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
      31             : 
      32             : #include <com/sun/star/util/theMacroExpander.hpp>
      33             : #include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
      34             : #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
      35             : #include <com/sun/star/uri/UriReferenceFactory.hpp>
      36             : #include <cppuhelper/supportsservice.hxx>
      37             : 
      38             : #include "uno/current_context.hxx"
      39             : 
      40             : #include <string.h>
      41             : #include <errno.h>
      42             : #include <unistd.h>
      43             : 
      44             : 
      45             : // namespace directives
      46             : 
      47             : 
      48             : using com::sun::star::system::XSystemShellExecute;
      49             : using com::sun::star::system::SystemShellExecuteException;
      50             : 
      51             : using osl::FileBase;
      52             : 
      53             : using namespace ::com::sun::star::uno;
      54             : using namespace ::com::sun::star::lang;
      55             : using namespace ::com::sun::star::system::SystemShellExecuteFlags;
      56             : using namespace cppu;
      57             : 
      58             : #define SHELLEXEC_IMPL_NAME  "com.sun.star.comp.system.SystemShellExecute2"
      59             : 
      60             : 
      61             : // helper functions
      62             : 
      63             : 
      64             : namespace // private
      65             : {
      66           0 :     Sequence< OUString > SAL_CALL ShellExec_getSupportedServiceNames()
      67             :     {
      68           0 :         Sequence< OUString > aRet(1);
      69           0 :         aRet[0] = "com.sun.star.sys.shell.SystemShellExecute";
      70           0 :         return aRet;
      71             :     }
      72             : }
      73             : 
      74           0 : void escapeForShell( OStringBuffer & rBuffer, const OString & rURL)
      75             : {
      76           0 :     sal_Int32 nmax = rURL.getLength();
      77           0 :     for(sal_Int32 n=0; n < nmax; ++n)
      78             :     {
      79             :         // escape every non alpha numeric characters (excluding a few "known good") by prepending a '\'
      80           0 :         sal_Char c = rURL[n];
      81           0 :         if( ( c < 'A' || c > 'Z' ) && ( c < 'a' || c > 'z' ) && ( c < '0' || c > '9' )  && c != '/' && c != '.' )
      82           0 :             rBuffer.append( '\\' );
      83             : 
      84           0 :         rBuffer.append( c );
      85             :     }
      86           0 : }
      87             : 
      88             : 
      89             : 
      90           2 : ShellExec::ShellExec( const Reference< XComponentContext >& xContext ) :
      91             :     WeakImplHelper2< XSystemShellExecute, XServiceInfo >(),
      92           2 :     m_xContext(xContext)
      93             : {
      94             :     try {
      95           2 :         Reference< XCurrentContext > xCurrentContext(getCurrentContext());
      96             : 
      97           2 :         if (xCurrentContext.is())
      98             :         {
      99           2 :             Any aValue = xCurrentContext->getValueByName(
     100           2 :                 OUString( "system.desktop-environment"  ) );
     101             : 
     102           4 :             OUString aDesktopEnvironment;
     103           2 :             if (aValue >>= aDesktopEnvironment)
     104             :             {
     105           2 :                 m_aDesktopEnvironment = OUStringToOString(aDesktopEnvironment, RTL_TEXTENCODING_ASCII_US);
     106           2 :             }
     107           2 :         }
     108           0 :     } catch (const RuntimeException &) {
     109             :     }
     110           2 : }
     111             : 
     112             : 
     113             : 
     114           0 : void SAL_CALL ShellExec::execute( const OUString& aCommand, const OUString& aParameter, sal_Int32 nFlags )
     115             :     throw (IllegalArgumentException, SystemShellExecuteException, RuntimeException, std::exception)
     116             : {
     117           0 :     OStringBuffer aBuffer, aLaunchBuffer;
     118             : 
     119             :     // DESKTOP_LAUNCH, see http://freedesktop.org/pipermail/xdg/2004-August/004489.html
     120           0 :     static const char *pDesktopLaunch = getenv( "DESKTOP_LAUNCH" );
     121             : 
     122             :     // Check whether aCommand contains an absolute URI reference:
     123             :     css::uno::Reference< css::uri::XUriReference > uri(
     124           0 :         css::uri::UriReferenceFactory::create(m_xContext)->parse(aCommand));
     125           0 :     if (uri.is() && uri->isAbsolute())
     126             :     {
     127             :         // It seems to be a url ..
     128             :         // We need to re-encode file urls because osl_getFileURLFromSystemPath converts
     129             :         // to UTF-8 before encoding non ascii characters, which is not what other apps
     130             :         // expect.
     131             :         OUString aURL(
     132             :             com::sun::star::uri::ExternalUriReferenceTranslator::create(
     133           0 :                 m_xContext)->translateToExternal(aCommand));
     134           0 :         if ( aURL.isEmpty() && !aCommand.isEmpty() )
     135             :         {
     136             :             throw RuntimeException(
     137             :                 OUString("Cannot translate URI reference to external format: ")
     138           0 :                  + aCommand,
     139           0 :                 static_cast< cppu::OWeakObject * >(this));
     140             :         }
     141             : 
     142             : #ifdef MACOSX
     143             :         //TODO: Using open(1) with an argument that syntactically is an absolute
     144             :         // URI reference does not necessarily give expected results:
     145             :         // 1  If the given URI reference matches a supported scheme (e.g.,
     146             :         //  "mailto:foo"):
     147             :         // 1.1  If it matches an existing pathname (relative to CWD):  Results
     148             :         //  in "mailto:foo?\n[0]\tcancel\n[1]\tOpen the file\tmailto:foo\n[2]\t
     149             :         //  Open the URL\tmailto:foo\n\nWhich did you mean? Cancelled." on
     150             :         //  stderr and SystemShellExecuteException.
     151             :         // 1.2  If it does not match an exitsting pathname (relative to CWD):
     152             :         //  Results in the corresponding application being opened with the given
     153             :         //  document (e.g., Mail with a New Message).
     154             :         // 2  If the given URI reference does not match a supported scheme
     155             :         //  (e.g., "foo:bar"):
     156             :         // 2.1  If it matches an existing pathname (relative to CWD) pointing to
     157             :         //  an executable:  Results in execution of that executable.
     158             :         // 2.2  If it matches an existing pathname (relative to CWD) pointing to
     159             :         //  a non-executable regular file:  Results in opening it in TextEdit.
     160             :         // 2.3  If it matches an existing pathname (relative to CWD) pointing to
     161             :         //  a directory:  Results in opening it in Finder.
     162             :         // 2.4  If it does not match an exitsting pathname (relative to CWD):
     163             :         //  Results in "The file /.../foo:bar does not exits." (where "/..." is
     164             :         //  the CWD) on stderr and SystemShellExecuteException.
     165             :         aBuffer.append("open --");
     166             : #else
     167             :         // The url launchers are expected to be in the $BRAND_BASE_DIR/LIBO_LIBEXEC_FOLDER
     168             :         // directory:
     169             :         com::sun::star::uno::Reference< com::sun::star::util::XMacroExpander >
     170           0 :             exp = com::sun::star::util::theMacroExpander::get(m_xContext);
     171           0 :         OUString aProgramURL;
     172             :         try {
     173           0 :             aProgramURL = exp->expandMacros(
     174           0 :                 OUString( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/"));
     175           0 :         } catch (com::sun::star::lang::IllegalArgumentException &)
     176             :         {
     177             :             throw SystemShellExecuteException(
     178             :                 "Could not expand $BRAND_BASE_DIR path",
     179           0 :                 static_cast < XSystemShellExecute * > (this), ENOENT );
     180             :         }
     181             : 
     182           0 :         OUString aProgram;
     183           0 :         if ( FileBase::E_None != FileBase::getSystemPathFromFileURL(aProgramURL, aProgram))
     184             :         {
     185             :             throw SystemShellExecuteException(
     186             :                 "Cound not convert executable path",
     187           0 :                 static_cast < XSystemShellExecute * > (this), ENOENT );
     188             :         }
     189             : 
     190           0 :         OString aTmp = OUStringToOString(aProgram, osl_getThreadTextEncoding());
     191           0 :         escapeForShell(aBuffer, aTmp);
     192             : 
     193             : #ifdef SOLARIS
     194             :         if ( m_aDesktopEnvironment.getLength() == 0 )
     195             :              m_aDesktopEnvironment = OString("GNOME");
     196             : #endif
     197             : 
     198             :         // Respect the desktop environment - if there is an executable named
     199             :         // <desktop-environement-is>-open-url, pass the url to this one instead
     200             :         // of the default "open-url" script.
     201           0 :         if ( !m_aDesktopEnvironment.isEmpty() )
     202             :         {
     203           0 :             OString aDesktopEnvironment(m_aDesktopEnvironment.toAsciiLowerCase());
     204           0 :             OStringBuffer aCopy(aTmp);
     205             : 
     206           0 :             aCopy.append(aDesktopEnvironment + "-open-url");
     207             : 
     208           0 :             if ( 0 == access( aCopy.getStr(), X_OK) )
     209             :             {
     210           0 :                 aBuffer.append(aDesktopEnvironment + "-");
     211           0 :             }
     212             :         }
     213             : 
     214           0 :         aBuffer.append("open-url");
     215             : #endif
     216           0 :         aBuffer.append(" ");
     217           0 :         escapeForShell(aBuffer, OUStringToOString(aURL, osl_getThreadTextEncoding()));
     218             : 
     219           0 :         if ( pDesktopLaunch && *pDesktopLaunch )
     220             :         {
     221           0 :             aLaunchBuffer.append( OString(pDesktopLaunch) + " ");
     222           0 :             escapeForShell(aLaunchBuffer, OUStringToOString(aURL, osl_getThreadTextEncoding()));
     223           0 :         }
     224           0 :     } else if ((nFlags & css::system::SystemShellExecuteFlags::URIS_ONLY) != 0)
     225             :     {
     226             :         throw css::lang::IllegalArgumentException(
     227             :             OUString("XSystemShellExecute.execute URIS_ONLY with non-absolute"
     228             :                      " URI reference ")
     229           0 :              + aCommand,
     230           0 :             static_cast< cppu::OWeakObject * >(this), 0);
     231             :     } else {
     232           0 :         escapeForShell(aBuffer, OUStringToOString(aCommand, osl_getThreadTextEncoding()));
     233           0 :         aBuffer.append(" ");
     234           0 :         if( nFlags != 42 )
     235           0 :             escapeForShell(aBuffer, OUStringToOString(aParameter, osl_getThreadTextEncoding()));
     236             :         else
     237           0 :             aBuffer.append(OUStringToOString(aParameter, osl_getThreadTextEncoding()));
     238             :     }
     239             : 
     240             :     // Prefer DESKTOP_LAUNCH when available
     241           0 :     if ( !aLaunchBuffer.isEmpty() )
     242             :     {
     243           0 :         FILE *pLaunch = popen( aLaunchBuffer.makeStringAndClear().getStr(), "w" );
     244           0 :         if ( pLaunch != NULL )
     245             :         {
     246           0 :             if ( 0 == pclose( pLaunch ) )
     247           0 :                 return;
     248             :         }
     249             :         // Failed, do not try DESKTOP_LAUNCH any more
     250           0 :         pDesktopLaunch = NULL;
     251             :     }
     252             : 
     253             :     OString cmd =
     254             : #ifdef LINUX
     255             :         // avoid blocking (call it in background)
     256           0 :         "( " + aBuffer.makeStringAndClear() +  " ) &";
     257             : #else
     258             :         aBuffer.makeStringAndClear();
     259             : #endif
     260           0 :     FILE *pLaunch = popen(cmd.getStr(), "w");
     261           0 :     if ( pLaunch != NULL )
     262             :     {
     263           0 :         if ( 0 == pclose( pLaunch ) )
     264           0 :             return;
     265             :     }
     266             : 
     267           0 :     int nerr = errno;
     268           0 :     throw SystemShellExecuteException(OUString::createFromAscii( strerror( nerr ) ),
     269           0 :         static_cast < XSystemShellExecute * > (this), nerr );
     270             : }
     271             : 
     272             : // XServiceInfo
     273           0 : OUString SAL_CALL ShellExec::getImplementationName(  )
     274             :     throw( RuntimeException, std::exception )
     275             : {
     276           0 :     return OUString(SHELLEXEC_IMPL_NAME );
     277             : }
     278             : 
     279             : //  XServiceInfo
     280           0 : sal_Bool SAL_CALL ShellExec::supportsService( const OUString& ServiceName )
     281             :     throw( RuntimeException, std::exception )
     282             : {
     283           0 :     return cppu::supportsService(this, ServiceName);
     284             : }
     285             : 
     286             : //  XServiceInfo
     287           0 : Sequence< OUString > SAL_CALL ShellExec::getSupportedServiceNames(   )
     288             :     throw( RuntimeException, std::exception )
     289             : {
     290           0 :     return ShellExec_getSupportedServiceNames();
     291             : }
     292             : 
     293             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10