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