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

Generated by: LCOV version 1.11