1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: shellexec.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_shell.hxx"
33 #include <osl/diagnose.h>
34 #include <osl/thread.h>
35 #include <osl/process.h>
36 #include <osl/file.hxx>
37 #include <rtl/ustrbuf.hxx>
40 #include <rtl/uri.hxx>
42 #include "shellexec.hxx"
43 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
45 #include <com/sun/star/util/XMacroExpander.hpp>
46 #include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
47 #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
49 #include "uno/current_context.hxx"
55 //------------------------------------------------------------------------
56 // namespace directives
57 //------------------------------------------------------------------------
59 using com::sun::star::system::XSystemShellExecute
;
60 using com::sun::star::system::SystemShellExecuteException
;
64 using rtl::OStringBuffer
;
65 using rtl::OUStringBuffer
;
68 using namespace ::com::sun::star::uno
;
69 using namespace ::com::sun::star::lang
;
70 using namespace ::com::sun::star::system::SystemShellExecuteFlags
;
73 //------------------------------------------------------------------------
75 //------------------------------------------------------------------------
77 #define SHELLEXEC_IMPL_NAME "com.sun.star.comp.system.SystemShellExecute2"
79 //------------------------------------------------------------------------
81 //------------------------------------------------------------------------
85 Sequence
< OUString
> SAL_CALL
ShellExec_getSupportedServiceNames()
87 Sequence
< OUString
> aRet(1);
88 aRet
[0] = OUString::createFromAscii("com.sun.star.sys.shell.SystemShellExecute");
93 void escapeForShell( rtl::OStringBuffer
& rBuffer
, const rtl::OString
& rURL
)
95 sal_Int32 nmax
= rURL
.getLength();
96 for(sal_Int32 n
=0; n
< nmax
; ++n
)
98 // escape every non alpha numeric characters (excluding a few "known good") by prepending a '\'
100 #ifndef OS2 // YD shell does not support escaped chars
101 if( ( c
< 'A' || c
> 'Z' ) && ( c
< 'a' || c
> 'z' ) && ( c
< '0' || c
> '9' ) && c
!= '/' && c
!= '.' )
102 rBuffer
.append( '\\' );
109 //-----------------------------------------------------------------------------------------
111 //-----------------------------------------------------------------------------------------
113 ShellExec::ShellExec( const Reference
< XComponentContext
>& xContext
) :
114 WeakImplHelper2
< XSystemShellExecute
, XServiceInfo
>(),
118 Reference
< XCurrentContext
> xCurrentContext(getCurrentContext());
120 if (xCurrentContext
.is())
122 Any aValue
= xCurrentContext
->getValueByName(
123 OUString( RTL_CONSTASCII_USTRINGPARAM( "system.desktop-environment" ) ) );
125 OUString aDesktopEnvironment
;
126 if (aValue
>>= aDesktopEnvironment
)
128 m_aDesktopEnvironment
= OUStringToOString(aDesktopEnvironment
, RTL_TEXTENCODING_ASCII_US
);
131 } catch (RuntimeException e
) {
135 //-------------------------------------------------
137 //-------------------------------------------------
139 void SAL_CALL
ShellExec::execute( const OUString
& aCommand
, const OUString
& aParameter
, sal_Int32 nFlags
)
140 throw (IllegalArgumentException
, SystemShellExecuteException
, RuntimeException
)
142 OStringBuffer aBuffer
, aLaunchBuffer
;
144 // DESKTOP_LAUNCH, see http://freedesktop.org/pipermail/xdg/2004-August/004489.html
145 static const char *pDesktopLaunch
= getenv( "DESKTOP_LAUNCH" );
147 // Check wether aCommand contains a document url or not
148 sal_Int32 nIndex
= aCommand
.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM(":/") ) );
150 if( nIndex
> 0 || 0 == aCommand
.compareToAscii("mailto:", 7) )
152 // It seems to be a url ..
153 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts
154 // to UTF-8 before encoding non ascii characters, which is not what other apps
157 com::sun::star::uri::ExternalUriReferenceTranslator::create(
158 m_xContext
)->translateToExternal(aCommand
));
159 if ( aURL
.getLength() == 0 && aCommand
.getLength() != 0 )
161 throw RuntimeException(
163 RTL_CONSTASCII_USTRINGPARAM(
164 "Cannot translate URI reference to external format: "))
166 static_cast< cppu::OWeakObject
* >(this));
170 aBuffer
.append("open");
172 // The url launchers are expected to be in the $OOO_BASE_DIR/program
174 com::sun::star::uno::Reference
< com::sun::star::util::XMacroExpander
>
176 if (!(m_xContext
->getValueByName(
178 RTL_CONSTASCII_USTRINGPARAM(
179 "/singletons/com.sun.star.util.theMacroExpander")))
183 throw SystemShellExecuteException(
185 RTL_CONSTASCII_USTRINGPARAM(
186 "component context fails to supply singleton"
187 " com.sun.star.util.theMacroExpander of type"
188 " com.sun.star.util.XMacroExpander")),
189 static_cast< XSystemShellExecute
* >(this), ENOENT
);
191 OUString aProgramURL
;
193 aProgramURL
= exp
->expandMacros(
195 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program/")));
196 } catch (com::sun::star::lang::IllegalArgumentException
&)
198 throw SystemShellExecuteException(
199 OUString(RTL_CONSTASCII_USTRINGPARAM("Could not expand $OOO_BASE_DIR path")),
200 static_cast < XSystemShellExecute
* > (this), ENOENT
);
204 if ( FileBase::E_None
!= FileBase::getSystemPathFromFileURL(aProgramURL
, aProgram
))
206 throw SystemShellExecuteException(
207 OUString(RTL_CONSTASCII_USTRINGPARAM("Cound not convert executable path")),
208 static_cast < XSystemShellExecute
* > (this), ENOENT
);
212 OStringBuffer aProg
= OUStringToOString(aProgram
, osl_getThreadTextEncoding());
213 aProg
.append("open-url.exe");
214 OString aUrl
= OUStringToOString(aURL
, osl_getThreadTextEncoding());
215 if ( -1 == spawnl(P_NOWAIT
, aProg
.getStr(), aProg
.getStr(), aUrl
.getStr() , NULL
) )
218 throw SystemShellExecuteException(OUString::createFromAscii( strerror( nerr
) ),
219 static_cast < XSystemShellExecute
* > (this), nerr
);
224 OString aTmp
= OUStringToOString(aProgram
, osl_getThreadTextEncoding());
225 escapeForShell(aBuffer
, aTmp
);
228 if ( m_aDesktopEnvironment
.getLength() == 0 )
229 m_aDesktopEnvironment
= OString("GNOME");
232 // Respect the desktop environment - if there is an executable named
233 // <desktop-environement-is>-open-url, pass the url to this one instead
234 // of the default "open-url" script.
235 if ( m_aDesktopEnvironment
.getLength() > 0 )
237 OString
aDesktopEnvironment(m_aDesktopEnvironment
.toAsciiLowerCase());
238 OStringBuffer
aCopy(aTmp
);
240 aCopy
.append(aDesktopEnvironment
);
241 aCopy
.append("-open-url");
243 if ( 0 == access( aCopy
.getStr(), X_OK
) )
245 aBuffer
.append(aDesktopEnvironment
);
248 /* CDE requires file urls to be decoded */
249 if ( m_aDesktopEnvironment
.equals("CDE") && 0 == aURL
.compareToAscii("file://", 7) )
251 aURL
= rtl::Uri::decode(aURL
, rtl_UriDecodeWithCharset
, osl_getThreadTextEncoding());
256 aBuffer
.append("open-url");
259 escapeForShell(aBuffer
, OUStringToOString(aURL
, osl_getThreadTextEncoding()));
261 if ( pDesktopLaunch
&& *pDesktopLaunch
)
263 aLaunchBuffer
.append( pDesktopLaunch
);
264 aLaunchBuffer
.append(" ");
265 escapeForShell(aLaunchBuffer
, OUStringToOString(aURL
, osl_getThreadTextEncoding()));
268 escapeForShell(aBuffer
, OUStringToOString(aCommand
, osl_getThreadTextEncoding()));
271 escapeForShell(aBuffer
, OUStringToOString(aParameter
, osl_getThreadTextEncoding()));
273 aBuffer
.append(OUStringToOString(aParameter
, osl_getThreadTextEncoding()));
276 // Prefer DESKTOP_LAUNCH when available
277 if ( aLaunchBuffer
.getLength() > 0 )
279 FILE *pLaunch
= popen( aLaunchBuffer
.makeStringAndClear().getStr(), "w" );
280 if ( pLaunch
!= NULL
)
282 if ( 0 == pclose( pLaunch
) )
285 // Failed, do not try DESKTOP_LAUNCH any more
286 pDesktopLaunch
= NULL
;
289 OString cmd
= aBuffer
.makeStringAndClear();
290 if ( 0 != pclose(popen(cmd
.getStr(), "w")) )
293 throw SystemShellExecuteException(OUString::createFromAscii( strerror( nerr
) ),
294 static_cast < XSystemShellExecute
* > (this), nerr
);
299 // -------------------------------------------------
301 // -------------------------------------------------
303 OUString SAL_CALL
ShellExec::getImplementationName( )
304 throw( RuntimeException
)
306 return OUString::createFromAscii( SHELLEXEC_IMPL_NAME
);
309 // -------------------------------------------------
311 // -------------------------------------------------
313 sal_Bool SAL_CALL
ShellExec::supportsService( const OUString
& ServiceName
)
314 throw( RuntimeException
)
316 Sequence
< OUString
> SupportedServicesNames
= ShellExec_getSupportedServiceNames();
318 for ( sal_Int32 n
= SupportedServicesNames
.getLength(); n
--; )
319 if (SupportedServicesNames
[n
].compareTo(ServiceName
) == 0)
325 // -------------------------------------------------
327 // -------------------------------------------------
329 Sequence
< OUString
> SAL_CALL
ShellExec::getSupportedServiceNames( )
330 throw( RuntimeException
)
332 return ShellExec_getSupportedServiceNames();