1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <osl/diagnose.h>
23 #include <osl/thread.h>
24 #include <osl/process.h>
25 #include <osl/file.hxx>
26 #include <rtl/ustrbuf.hxx>
28 #include <rtl/uri.hxx>
29 #include "shellexec.hxx"
30 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
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>
38 #include "uno/current_context.hxx"
45 // namespace directives
48 using com::sun::star::system::XSystemShellExecute
;
49 using com::sun::star::system::SystemShellExecuteException
;
53 using namespace ::com::sun::star::uno
;
54 using namespace ::com::sun::star::lang
;
55 using namespace ::com::sun::star::system::SystemShellExecuteFlags
;
60 Sequence
< OUString
> SAL_CALL
ShellExec_getSupportedServiceNames()
62 Sequence
< OUString
> aRet(1);
63 aRet
[0] = "com.sun.star.system.SystemShellExecute";
68 void escapeForShell( OStringBuffer
& rBuffer
, const OString
& rURL
)
70 sal_Int32 nmax
= rURL
.getLength();
71 for(sal_Int32 n
=0; n
< nmax
; ++n
)
73 // escape every non alpha numeric characters (excluding a few "known good") by prepending a '\'
75 if( ( c
< 'A' || c
> 'Z' ) && ( c
< 'a' || c
> 'z' ) && ( c
< '0' || c
> '9' ) && c
!= '/' && c
!= '.' )
76 rBuffer
.append( '\\' );
84 ShellExec::ShellExec( const Reference
< XComponentContext
>& xContext
) :
85 WeakImplHelper2
< XSystemShellExecute
, XServiceInfo
>(),
89 Reference
< XCurrentContext
> xCurrentContext(getCurrentContext());
91 if (xCurrentContext
.is())
93 Any aValue
= xCurrentContext
->getValueByName(
94 OUString( "system.desktop-environment" ) );
96 OUString aDesktopEnvironment
;
97 if (aValue
>>= aDesktopEnvironment
)
99 m_aDesktopEnvironment
= OUStringToOString(aDesktopEnvironment
, RTL_TEXTENCODING_ASCII_US
);
102 } catch (const RuntimeException
&) {
108 void SAL_CALL
ShellExec::execute( const OUString
& aCommand
, const OUString
& aParameter
, sal_Int32 nFlags
)
109 throw (IllegalArgumentException
, SystemShellExecuteException
, RuntimeException
, std::exception
)
111 OStringBuffer aBuffer
, aLaunchBuffer
;
113 // DESKTOP_LAUNCH, see http://freedesktop.org/pipermail/xdg/2004-August/004489.html
114 static const char *pDesktopLaunch
= getenv( "DESKTOP_LAUNCH" );
116 // Check whether aCommand contains an absolute URI reference:
117 css::uno::Reference
< css::uri::XUriReference
> uri(
118 css::uri::UriReferenceFactory::create(m_xContext
)->parse(aCommand
));
119 if (uri
.is() && uri
->isAbsolute())
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
126 com::sun::star::uri::ExternalUriReferenceTranslator::create(
127 m_xContext
)->translateToExternal(aCommand
));
128 if ( aURL
.isEmpty() && !aCommand
.isEmpty() )
130 throw RuntimeException(
131 "Cannot translate URI reference to external format: "
133 static_cast< cppu::OWeakObject
* >(this));
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.,
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 --");
161 // The url launchers are expected to be in the $BRAND_BASE_DIR/LIBO_LIBEXEC_FOLDER
163 com::sun::star::uno::Reference
< com::sun::star::util::XMacroExpander
>
164 exp
= com::sun::star::util::theMacroExpander::get(m_xContext
);
165 OUString aProgramURL
;
167 aProgramURL
= exp
->expandMacros(
168 OUString( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER
"/"));
169 } catch (com::sun::star::lang::IllegalArgumentException
&)
171 throw SystemShellExecuteException(
172 "Could not expand $BRAND_BASE_DIR path",
173 static_cast < XSystemShellExecute
* > (this), ENOENT
);
177 if ( FileBase::E_None
!= FileBase::getSystemPathFromFileURL(aProgramURL
, aProgram
))
179 throw SystemShellExecuteException(
180 "Cound not convert executable path",
181 static_cast < XSystemShellExecute
* > (this), ENOENT
);
184 OString aTmp
= OUStringToOString(aProgram
, osl_getThreadTextEncoding());
185 escapeForShell(aBuffer
, aTmp
);
188 if ( m_aDesktopEnvironment
.getLength() == 0 )
189 m_aDesktopEnvironment
= OString("GNOME");
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 if ( !m_aDesktopEnvironment
.isEmpty() )
197 OString
aDesktopEnvironment(m_aDesktopEnvironment
.toAsciiLowerCase());
198 OStringBuffer
aCopy(aTmp
);
200 aCopy
.append(aDesktopEnvironment
+ "-open-url");
202 if ( 0 == access( aCopy
.getStr(), X_OK
) )
204 aBuffer
.append(aDesktopEnvironment
+ "-");
208 aBuffer
.append("open-url");
211 escapeForShell(aBuffer
, OUStringToOString(aURL
, osl_getThreadTextEncoding()));
213 if ( pDesktopLaunch
&& *pDesktopLaunch
)
215 aLaunchBuffer
.append( OString(pDesktopLaunch
) + " ");
216 escapeForShell(aLaunchBuffer
, OUStringToOString(aURL
, osl_getThreadTextEncoding()));
218 } else if ((nFlags
& css::system::SystemShellExecuteFlags::URIS_ONLY
) != 0)
220 throw css::lang::IllegalArgumentException(
221 "XSystemShellExecute.execute URIS_ONLY with non-absolute"
224 static_cast< cppu::OWeakObject
* >(this), 0);
226 escapeForShell(aBuffer
, OUStringToOString(aCommand
, osl_getThreadTextEncoding()));
229 escapeForShell(aBuffer
, OUStringToOString(aParameter
, osl_getThreadTextEncoding()));
231 aBuffer
.append(OUStringToOString(aParameter
, osl_getThreadTextEncoding()));
234 // Prefer DESKTOP_LAUNCH when available
235 if ( !aLaunchBuffer
.isEmpty() )
237 FILE *pLaunch
= popen( aLaunchBuffer
.makeStringAndClear().getStr(), "w" );
238 if ( pLaunch
!= NULL
)
240 if ( 0 == pclose( pLaunch
) )
243 // Failed, do not try DESKTOP_LAUNCH any more
244 pDesktopLaunch
= NULL
;
249 // avoid blocking (call it in background)
250 "( " + aBuffer
.makeStringAndClear() + " ) &";
252 aBuffer
.makeStringAndClear();
254 FILE *pLaunch
= popen(cmd
.getStr(), "w");
255 if ( pLaunch
!= NULL
)
257 if ( 0 == pclose( pLaunch
) )
262 throw SystemShellExecuteException(OUString::createFromAscii( strerror( nerr
) ),
263 static_cast < XSystemShellExecute
* > (this), nerr
);
267 OUString SAL_CALL
ShellExec::getImplementationName( )
268 throw( RuntimeException
, std::exception
)
270 return OUString("com.sun.star.comp.system.SystemShellExecute");
274 sal_Bool SAL_CALL
ShellExec::supportsService( const OUString
& ServiceName
)
275 throw( RuntimeException
, std::exception
)
277 return cppu::supportsService(this, ServiceName
);
281 Sequence
< OUString
> SAL_CALL
ShellExec::getSupportedServiceNames( )
282 throw( RuntimeException
, std::exception
)
284 return ShellExec_getSupportedServiceNames();
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */