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