1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_framework.hxx" 30 31 //_______________________________________________ 32 // include own header 33 34 #include <jobs/shelljob.hxx> 35 #include <jobs/jobconst.hxx> 36 #include <threadhelp/readguard.hxx> 37 #include <services.h> 38 39 //_______________________________________________ 40 // include others 41 42 #include <osl/file.hxx> 43 #include <osl/process.h> 44 #include <vcl/svapp.hxx> 45 #include <rtl/ustrbuf.hxx> 46 #include <comphelper/sequenceashashmap.hxx> 47 48 //_______________________________________________ 49 // include interfaces 50 51 #include <com/sun/star/system/XSystemShellExecute.hpp> 52 #include <com/sun/star/system/SystemShellExecuteFlags.hpp> 53 #include <com/sun/star/util/XStringSubstitution.hpp> 54 55 //_______________________________________________ 56 // namespace 57 58 namespace framework{ 59 60 //_______________________________________________ 61 // definitions 62 63 /** adress job configuration inside argument set provided on method execute(). */ 64 static const ::rtl::OUString PROP_JOBCONFIG = ::rtl::OUString::createFromAscii("JobConfig"); 65 66 /** adress job configuration property "Command". */ 67 static const ::rtl::OUString PROP_COMMAND = ::rtl::OUString::createFromAscii("Command"); 68 69 /** adress job configuration property "Arguments". */ 70 static const ::rtl::OUString PROP_ARGUMENTS = ::rtl::OUString::createFromAscii("Arguments"); 71 72 /** adress job configuration property "DeactivateJobIfDone". */ 73 static const ::rtl::OUString PROP_DEACTIVATEJOBIFDONE = ::rtl::OUString::createFromAscii("DeactivateJobIfDone"); 74 75 /** adress job configuration property "CheckExitCode". */ 76 static const ::rtl::OUString PROP_CHECKEXITCODE = ::rtl::OUString::createFromAscii("CheckExitCode"); 77 78 //----------------------------------------------- 79 80 DEFINE_XSERVICEINFO_MULTISERVICE(ShellJob , 81 ::cppu::OWeakObject , 82 SERVICENAME_JOB , 83 IMPLEMENTATIONNAME_SHELLJOB) 84 85 DEFINE_INIT_SERVICE(ShellJob, 86 { 87 /* Attention 88 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() 89 to create a new instance of this class by our own supported service factory. 90 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! 91 */ 92 } 93 ) 94 95 //----------------------------------------------- 96 ShellJob::ShellJob(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) 97 : ThreadHelpBase( ) 98 , m_xSMGR (xSMGR) 99 { 100 } 101 102 //----------------------------------------------- 103 ShellJob::~ShellJob() 104 { 105 } 106 107 //----------------------------------------------- 108 css::uno::Any SAL_CALL ShellJob::execute(const css::uno::Sequence< css::beans::NamedValue >& lJobArguments) 109 throw(css::lang::IllegalArgumentException, 110 css::uno::Exception , 111 css::uno::RuntimeException ) 112 { 113 ::comphelper::SequenceAsHashMap lArgs (lJobArguments); 114 ::comphelper::SequenceAsHashMap lOwnCfg(lArgs.getUnpackedValueOrDefault(PROP_JOBCONFIG, css::uno::Sequence< css::beans::NamedValue >())); 115 116 const ::rtl::OUString sCommand = lOwnCfg.getUnpackedValueOrDefault(PROP_COMMAND , ::rtl::OUString()); 117 const css::uno::Sequence< ::rtl::OUString > lCommandArguments = lOwnCfg.getUnpackedValueOrDefault(PROP_ARGUMENTS , css::uno::Sequence< ::rtl::OUString >()); 118 const ::sal_Bool bDeactivateJobIfDone = lOwnCfg.getUnpackedValueOrDefault(PROP_DEACTIVATEJOBIFDONE , sal_True ); 119 const ::sal_Bool bCheckExitCode = lOwnCfg.getUnpackedValueOrDefault(PROP_CHECKEXITCODE , sal_True ); 120 121 // replace all might existing place holder. 122 ::rtl::OUString sRealCommand = impl_substituteCommandVariables(sCommand); 123 124 // Command is required as minimum. 125 // If it does not exists ... we cant do our job. 126 // Deactivate such miss configured job silently .-) 127 if (sRealCommand.getLength() < 1) 128 return ShellJob::impl_generateAnswer4Deactivation(); 129 130 // do it 131 ::sal_Bool bDone = impl_execute(sRealCommand, lCommandArguments, bCheckExitCode); 132 if (! bDone) 133 return css::uno::Any(); 134 135 // Job was done ... user configured deactivation of this job 136 // in such case. 137 if (bDeactivateJobIfDone) 138 return ShellJob::impl_generateAnswer4Deactivation(); 139 140 // There was no decision about deactivation of this job. 141 // So we have to return nothing here ! 142 return css::uno::Any(); 143 } 144 145 //----------------------------------------------- 146 css::uno::Any ShellJob::impl_generateAnswer4Deactivation() 147 { 148 css::uno::Sequence< css::beans::NamedValue > aAnswer(1); 149 aAnswer[0].Name = JobConst::ANSWER_DEACTIVATE_JOB(); 150 aAnswer[0].Value = css::uno::makeAny(sal_True); 151 152 return css::uno::makeAny(aAnswer); 153 } 154 155 //----------------------------------------------- 156 ::rtl::OUString ShellJob::impl_substituteCommandVariables(const ::rtl::OUString& sCommand) 157 { 158 // SYNCHRONIZED -> 159 ReadGuard aReadLock(m_aLock); 160 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; 161 aReadLock.unlock(); 162 // <- SYNCHRONIZED 163 164 try 165 { 166 css::uno::Reference< css::util::XStringSubstitution > xSubst ( xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES), css::uno::UNO_QUERY_THROW); 167 const ::sal_Bool bSubstRequired = sal_True; 168 const ::rtl::OUString sCompleteCommand = xSubst->substituteVariables(sCommand, bSubstRequired); 169 170 return sCompleteCommand; 171 } 172 catch(const css::uno::Exception&) 173 {} 174 175 return ::rtl::OUString(); 176 } 177 178 //----------------------------------------------- 179 ::sal_Bool ShellJob::impl_execute(const ::rtl::OUString& sCommand , 180 const css::uno::Sequence< ::rtl::OUString >& lArguments , 181 ::sal_Bool bCheckExitCode) 182 { 183 ::rtl_uString** pArgs = NULL; 184 const ::sal_Int32 nArgs = lArguments.getLength (); 185 oslProcessOption nOptions = osl_Process_WAIT; 186 oslProcess hProcess(0); 187 188 if (nArgs > 0) 189 pArgs = reinterpret_cast< ::rtl_uString** >(const_cast< ::rtl::OUString* >(lArguments.getConstArray())); 190 191 oslProcessError eError = osl_executeProcess(sCommand.pData, pArgs, nArgs, nOptions, NULL, NULL, NULL, 0, &hProcess); 192 193 // executable not found or couldnt be started 194 if (eError != osl_Process_E_None) 195 return sal_False; 196 197 ::sal_Bool bRet = sal_True; 198 if (bCheckExitCode) 199 { 200 // check its return codes ... 201 oslProcessInfo aInfo; 202 aInfo.Size = sizeof (oslProcessInfo); 203 eError = osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo); 204 205 if (eError != osl_Process_E_None) 206 bRet = sal_False; 207 else 208 bRet = (aInfo.Code == 0); 209 } 210 osl_freeProcessHandle(hProcess); 211 return bRet; 212 } 213 214 } // namespace framework 215