//============================================================================= // // File : kvi_kvs_processmanager.cpp // Created on Wed 07 Apr 2004 03:03:52 by Szymon Stefanek // // This file is part of the KVIrc IRC client distribution // Copyright (C) 2004-2007 Szymon Stefanek // // This program is FREE software. You can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your opinion) any later version. // // This program is distributed in the HOPE that it will be USEFUL, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, write to the Free Software Foundation, // Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #define __KVIRC__ #include "kvi_kvs_processmanager.h" #include "kvi_window.h" #include "kvi_out.h" #include "kvi_locale.h" #include "kvi_parameterlist.h" #include "kvi_app.h" #include "kvi_console.h" #include "kvi_kvs_script.h" //#include KviKvsProcessAsyncOperation::KviKvsProcessAsyncOperation(KviKvsProcessDescriptorData * d) : KviKvsAsyncOperation(d->pWnd) { m_pData = d; m_pProcess = 0; m_pExtendedRunTimeData = new KviKvsExtendedRunTimeData(new KviKvsHash(),TRUE); m_pPingTimer = 0; m_pRunTimeTimer = 0; m_bDeletePending = false; } KviKvsProcessAsyncOperation::~KviKvsProcessAsyncOperation() { if(m_pPingTimer)delete m_pPingTimer; if(m_pRunTimeTimer)delete m_pRunTimeTimer; if(m_pProcess) { TQObject::disconnect(m_pProcess,0,this,0); m_pProcess->kill(); delete m_pProcess; } delete m_pExtendedRunTimeData; if(m_pData->pCallback)delete m_pData->pCallback; if(m_pData->pMagic)delete m_pData->pMagic; delete m_pData; } bool KviKvsProcessAsyncOperation::start() { TQStringList args; if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_NOSHELL) { args = TQStringList::split(" ",m_pData->szCommandline); } else { TQString szShell = m_pData->szShell; if(szShell.isEmpty()) { #ifdef COMPILE_ON_WINDOWS // [01:26:00] btw, what is qt_winunicode ? // [01:26:12] TQt export specific to win32 // [01:26:27] bool which indicates whether system is Unicode (NT) or not // [01:26:58] not sure if that's documented, but it is a public export // // [02:50:21] if ( TQApplication::winVersion() & TQt::WV_NT_based ) // [02:50:41] I see another implementation using that, maybe it is the official way of detecting that :[ szShell = "command.com /c"; // Thnx kode54 :) #else szShell = "sh -c"; #endif } args = TQStringList::split(" ",szShell); args.append(m_pData->szCommandline); } m_pProcess = new KviProcess(args); int c = KviProcess::Stdin; if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTDOUT) { connect(m_pProcess,TQ_SIGNAL(readyReadStdout()),this,TQ_SLOT(readStdout())); c |= KviProcess::Stdout; } if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTDERR) { connect(m_pProcess,TQ_SIGNAL(readyReadStderr()),this,TQ_SLOT(readStderr())); c |= KviProcess::Stderr; } m_pProcess->setCommunication(c); connect(m_pProcess,TQ_SIGNAL(processExited()),this,TQ_SLOT(processExited())); if(!m_pProcess->start()) { return false; } if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTARTED) { TQString szPid; szPid.setNum((int)(m_pProcess->processIdentifier())); if(trigger(EventStarted,szPid)) { triggerSelfDelete(); return true; } } if(m_pData->iMaxRunTime > 0) { m_pRunTimeTimer = new TQTimer(this); connect(m_pRunTimeTimer,TQ_SIGNAL(timeout()),this,TQ_SLOT(maxRunTimeExpired())); m_pRunTimeTimer->start(m_pData->iMaxRunTime); } if(m_pData->iPingTimeout > 0) { m_pPingTimer = new TQTimer(this); connect(m_pPingTimer,TQ_SIGNAL(timeout()),this,TQ_SLOT(ping())); m_pPingTimer->start(m_pData->iPingTimeout); } return true; } void KviKvsProcessAsyncOperation::ping() { if(trigger(EventPing,TQString())) { triggerSelfDelete(); } } void KviKvsProcessAsyncOperation::triggerSelfDelete() { if(m_bDeletePending)return; m_bDeletePending = true; TQTimer::singleShot(m_pData->iMaxRunTime,this,TQ_SLOT(selfDelete())); } void KviKvsProcessAsyncOperation::selfDelete() { delete this; } void KviKvsProcessAsyncOperation::maxRunTimeExpired() { trigger(EventTerminated,"0"); triggerSelfDelete(); } bool KviKvsProcessAsyncOperation::trigger(CallbackEvent e,const TQString &szData) { if(m_bDeletePending)return false; if(!g_pApp->windowExists(m_pData->pWnd)) { if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_KILLIFNOWINDOW) { return true; } m_pData->pWnd = g_pApp->activeConsole(); } if(m_pData->pCallback) { KviKvsVariantList params; params.setAutoDelete(true); switch(e) { case EventStdout: params.append(new KviKvsVariant(TQString("stdout"))); break; case EventStderr: params.append(new KviKvsVariant(TQString("stderr"))); break; case EventTerminated: params.append(new KviKvsVariant(TQString("terminated"))); break; case EventStarted: params.append(new KviKvsVariant(TQString("started"))); break; case EventPing: params.append(new KviKvsVariant(TQString("ping"))); break; default: tqDebug("Ops... unknown trigger() CallbackEvent parameter in KviProcessDescriptor::trigger()"); return false; break; } params.append(new KviKvsVariant(szData)); if (m_pData->pMagic) params.append(m_pData->pMagic); KviKvsVariant retVal; int iRet = m_pData->pCallback->run(m_pData->pWnd,¶ms,&retVal,KviKvsScript::PreserveParams,m_pExtendedRunTimeData); if(!iRet) { m_pData->pWnd->output(KVI_OUT_PARSERERROR, __tr2qs("Error triggered from process callback handler: killing process")); return true; } if(!retVal.isNothing()) { TQString sz; retVal.asString(sz); m_pProcess->writeToStdin(sz); } if(iRet & KviKvsScript::HaltEncountered) { // halt encountered: kill the process return true; } } return false; } void KviKvsProcessAsyncOperation::readStdout() { if(m_bDeletePending)return; if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_OUTPUTBYBLOCKS) { TQByteArray a = m_pProcess->readStdout(); if(a.size() > 0) m_szStdoutBuffer += TQString(a); } else { TQString l = m_pProcess->readLineStdout(); bool bBreak = false; while((!l.isNull()) && (!bBreak)) { if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTDOUT) { if(trigger(EventStdout,l)) { bBreak = true; triggerSelfDelete(); } } l = m_pProcess->readLineStdout(); } } } void KviKvsProcessAsyncOperation::readStderr() { if(m_bDeletePending)return; if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_OUTPUTBYBLOCKS) { TQByteArray a = m_pProcess->readStderr(); if(a.size() > 0) m_szStderrBuffer += TQString(a); } else { TQString l = m_pProcess->readLineStderr(); bool bBreak = false; while((!l.isNull()) && (!bBreak)) { if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTDERR) { if(trigger(EventStderr,l)) { bBreak = true; triggerSelfDelete(); } } l = m_pProcess->readLineStderr(); } } } void KviKvsProcessAsyncOperation::processExited() { if(m_bDeletePending)return; readStdout(); // just to make sure readStderr(); // just to make sure if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_OUTPUTBYBLOCKS) { // trigger Stdout and Stderr once if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTDOUT) { if(trigger(EventStdout,m_szStdoutBuffer)) { triggerSelfDelete(); return; } } if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTDERR) { if(trigger(EventStdout,m_szStderrBuffer)) { triggerSelfDelete(); return; } } } if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERTERMINATED) { TQString szRetVal; szRetVal.setNum(m_pProcess->exitStatus()); trigger(EventTerminated,szRetVal); } triggerSelfDelete(); } /* KviKvsProcessManager::KviKvsProcessManager() : TQObject() { } KviKvsProcessManager::~KviKvsProcessManager() { } void KviKvsProcessManager::init() { if(m_pInstance)return; m_pInstance = new KviProcessManager(); } void KviKvsProcessManager::done() { if(!m_pInstance)return; delete m_pInstance; m_pInstance = 0; } bool KviKvsProcessManager::execute(KviKvsProcessAsyncOperationData * d) { KviKvsProcessAsyncOperation * pd = new KviKvsProcessAsyncOperation(d,this); if(!pd->start()) { //delete d; <-- delete by KviKvsProcessAsyncOperation delete pd; return false; } return true; } */