You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kvirc/src/kvirc/kvs/kvi_kvs_processmanager.cpp

377 lines
8.9 KiB

//=============================================================================
//
// 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 <pragma at kvirc dot net>
//
// 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 <TQSysInfo>
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] <PragmaOff> btw, what is qt_wintqunicode ?
// [01:26:12] <kode54> TQt export specific to win32
// [01:26:27] <kode54> bool which indicates whether system is Unicode (NT) or not
// [01:26:58] <kode54> not sure if that's documented, but it is a public export
//
// [02:50:21] <kode54> if ( TQApplication::winVersion() & TQt::WV_NT_based )
// [02:50:41] <kode54> I see another implementation using that, maybe it is the official way of detecting that :[
#ifdef COMPILE_USE_QT4
szShell = !(TQSysInfo::WindowsVersion & TQSysInfo::WV_DOS_based) ? "cmd.exe /c" : "command.com /c";
#else
szShell = "command.com /c";
#endif
// 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,TQT_SIGNAL(readyReadStdout()),this,TQT_SLOT(readStdout()));
c |= KviProcess::Stdout;
}
if(m_pData->iFlags & KVI_KVS_PROCESSDESCRIPTOR_TRIGGERSTDERR)
{
connect(m_pProcess,TQT_SIGNAL(readyReadStderr()),this,TQT_SLOT(readStderr()));
c |= KviProcess::Stderr;
}
m_pProcess->setCommunication(c);
connect(m_pProcess,TQT_SIGNAL(processExited()),this,TQT_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,TQT_SIGNAL(timeout()),this,TQT_SLOT(maxRunTimeExpired()));
m_pRunTimeTimer->start(m_pData->iMaxRunTime);
}
if(m_pData->iPingTimeout > 0)
{
m_pPingTimer = new TQTimer(this);
connect(m_pPingTimer,TQT_SIGNAL(timeout()),this,TQT_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,TQT_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:
debug("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,&params,&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->exiStatus());
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;
}
*/