void KviKvsAsyncDnsOperation::lookupTerminated(KviDnsResolver *)
{
	KviWindow * pWnd = window();
	if(!g_pApp->windowExists(pWnd))
		pWnd = g_pActiveWindow;

	if(m_pCallback)
	{
		KviKvsVariantList params;
		params.setAutoDelete(true);
		if(m_pDns->state() == KviDnsResolver::Failure)
		{
			params.append(new KviKvsVariant(m_szQuery));
			params.append(new KviKvsVariant((kvs_int_t)0));
			params.append(new KviKvsVariant(m_pDns->errorString()));
			params.append(new KviKvsVariant());
			params.append(new KviKvsVariant(*m_pMagic));
		}
		else
		{
			QString szHostName = m_pDns->hostName();
			const auto & strL = m_pDns->ipAddressList();
			const QString & fi = strL.empty() ? QString("?.?.?.?") : strL.front();

			params.append(new KviKvsVariant(m_szQuery));
			params.append(new KviKvsVariant((kvs_int_t)1));
			params.append(new KviKvsVariant(fi));
			params.append(new KviKvsVariant(szHostName.isEmpty() ? QString("?.?") : szHostName));
			params.append(new KviKvsVariant(*m_pMagic));
		}

		m_pCallback->run(pWnd, &params, nullptr, KviKvsScript::PreserveParams);

		delete this;
		return;
	}

	// we have no callback : output the results
	QString szQuery = m_pDns->query();
	pWnd->output(KVI_OUT_HOSTLOOKUP, __tr2qs_ctx("DNS lookup result for query \"%Q\"", "kvs"), &szQuery);

	if(m_pDns->state() == KviDnsResolver::Failure)
	{
		QString strDescription(m_pDns->errorString());
		pWnd->output(KVI_OUT_HOSTLOOKUP, __tr2qs_ctx("Error: %Q", "kvs"), &strDescription);
	}
	else
	{
		QString szHostName = m_pDns->hostName();
		pWnd->output(KVI_OUT_HOSTLOOKUP, __tr2qs_ctx("Hostname: %Q", "kvs"), &szHostName);
		int idx = 1;
		for(const auto & a : m_pDns->ipAddressList())
		{
			pWnd->output(KVI_OUT_HOSTLOOKUP, __tr2qs_ctx("IP address %d: %Q", "kvs"), idx, &a);
			idx++;
		}
	}

	delete this;
}
	bool characters(const QString & szChars) override
	{
		KviKvsVariant ret;
		KviKvsVariantList par;
		par.setAutoDelete(true);
		par.append(new KviKvsVariant(szChars));
		if(!m_pReader->callFunction(m_pReader, "onText", &ret, &par))
			return kvsCodeFailure();
		return handleKvsCallReturnValue(&ret);
	}
	bool endElement(const QString & szNamespaceUri, const QString & szLocalName, const QString & szQualifiedName) override
	{
		KviKvsVariant ret;
		KviKvsVariantList par;
		par.setAutoDelete(true);
		par.append(new KviKvsVariant(szQualifiedName));
		par.append(new KviKvsVariant(szNamespaceUri));
		par.append(new KviKvsVariant(szLocalName));
		if(!m_pReader->callFunction(m_pReader, "onElementEnd", &ret, &par))
			return kvsCodeFailure();
		return handleKvsCallReturnValue(&ret);
	}
	bool error(const QXmlParseException & exception) override
	{
		// recoverable
		QString szMsg;
		decodeException(szMsg, false, exception);

		KviKvsVariant ret;
		KviKvsVariantList par;
		par.setAutoDelete(true);
		par.append(new KviKvsVariant(szMsg));
		if(!m_pReader->callFunction(m_pReader, "onWarning", &ret, &par))
			return kvsCodeFailure();
		return handleKvsCallReturnValue(&ret);
	}
bool KviKvsTreeNodeCoreSimpleCommand::execute(KviKvsRunTimeContext * c)
{
	KviKvsVariantList l;
	l.setAutoDelete(true);
	if(!(m_pParams->evaluate(c,&l)))return false;

	KviKvsSwitchList swl;
	if(m_pSwitches)
	{
		if(!(m_pSwitches->evaluate(c,&swl)))return false;
	}

	c->setDefaultReportLocation(this);

	return m_pExecRoutine->proc(c,&l,&swl);
}
	bool startElement(const QString & szNamespaceUri, const QString & szLocalName, const QString & szQualifiedName, const QXmlAttributes & attrs) override
	{
		KviKvsVariant ret;
		KviKvsVariantList par;
		par.setAutoDelete(true);
		par.append(new KviKvsVariant(szQualifiedName));
		KviKvsHash * pHash = new KviKvsHash();
		par.append(new KviKvsVariant(pHash));
		par.append(new KviKvsVariant(szNamespaceUri));
		par.append(new KviKvsVariant(szLocalName));
		int c = attrs.count();
		for(int i = 0; i < c; i++)
			pHash->set(attrs.qName(i), new KviKvsVariant(attrs.value(i)));
		if(!m_pReader->callFunction(m_pReader, "onElementStart", &ret, &par))
			return kvsCodeFailure();
		return handleKvsCallReturnValue(&ret);
	}
KviKvsObject * KviKvsObjectClass::allocateInstance(KviKvsObject * pParent,const QString &szName,KviKvsRunTimeContext * pContext,KviKvsVariantList * pParams)
{
	if(!m_allocProc)
		return 0;

	KviKvsObject * pObject = m_allocProc(this,pParent,szName);
	if(!pObject)
		return 0;

	if(!pObject->init(pContext,pParams))
	{
		// internal init failure : abort
		pObject->dieNow();
		return 0;
	}

	// copy params
	KviKvsVariantList copy;
	copy.setAutoDelete(false);

	KviKvsVariant * v = pParams->first();

	while(v)
	{
		copy.append(v);
		v = pParams->next();
	}
	KviKvsVariant ret;

	if(!pObject->callFunction(pObject,"constructor",QString(),pContext,&ret,&copy))
	{
		// ops...constructor failed (script error!)
		pObject->dieNow();
		return 0;
	}
	
	if(!ret.isEmpty())
		pContext->warning(__tr2qs_ctx("It's not allowed to return values in the constructor","kvs"));

	return pObject;
}
bool KviKvsTreeNodeSpecialCommandForeach::execute(KviKvsRunTimeContext * c)
{
    KviKvsVariantList l;
    l.setAutoDelete(true);
    if(!m_pIterationData->evaluate(c,&l))
        return false;

    KviKvsSwitchList swl;
    if(m_pSwitches)
    {
        if(!(m_pSwitches->evaluate(c,&swl)))
            return false;
    }

    bool bIncludeEmptyScalars = swl.find('a',"all") != 0;

    for(KviKvsVariant * pArg = l.first(); pArg; pArg = l.next())
    {
        switch(pArg->type())
        {
        case KviKvsVariantData::Array:
        {
            unsigned int uCnt = pArg->array()->size();
            unsigned int idx = 0;
            while(idx < uCnt)
            {
                // we evaluate this each time (as it may actually be killed at each iteration)
                // FIXME: maybe some kind of reference counting or a observer pattern might be a bit more efficient here
                //        (but might be far less efficient everywhere else...)
                KviKvsRWEvaluationResult * v = m_pIterationVariable->evaluateReadWrite(c);
                if(!v)
                    return false;
                KviKvsVariant * pOne = pArg->array()->at(idx);
                if(pOne)
                {
                    if(bIncludeEmptyScalars || (!pOne->isEmpty()))
                    {
                        v->result()->copyFrom(*pOne);
                    } else {
                        delete v; // we're done with it for this iteration
                        idx++;
                        continue;
                    }
                } else {
                    if(bIncludeEmptyScalars)
                    {
                        v->result()->setNothing();
                    } else {
                        delete v; // we're done with it for this iteration
                        idx++;
                        continue;
                    }

                }
                delete v; // we're done with it for this iteration

                if(!m_pLoop->execute(c))
                {
                    if(c->error())
                        return false;

                    // break allowed!
                    if(c->breakPending())
                    {
                        c->handleBreak();
                        return true;
                    }

                    if(c->continuePending())
                    {
                        c->handleContinue();
                        idx++;
                        continue;
                    }

                    return false; // propagate the false return value
                }

                idx++;
            }
        }
        break;
        case KviKvsVariantData::Hash:
        {
            KviKvsHashIterator it(*(pArg->hash()->dict()));
            while(KviKvsVariant * pOne = it.current())
            {
                // we evaluate this each time (as it may actually be killed at each iteration)
                // FIXME: maybe some kind of reference counting or a observer pattern might be a bit more efficient here
                //        (but might be far less efficient everywhere else...)
                KviKvsRWEvaluationResult * v = m_pIterationVariable->evaluateReadWrite(c);
                if(!v)
                    return false;

                if(bIncludeEmptyScalars || (!pOne->isEmpty()))
                {
                    v->result()->copyFrom(*pOne);
                } else {
                    delete v; // we're done with it for this iteration
                    ++it;
                    continue;
                }
                delete v; // we're done with it for this iteration

                if(!m_pLoop->execute(c))
                {
                    if(c->error())
                        return false;

                    // break allowed!
                    if(c->breakPending())
                    {
                        c->handleBreak();
                        return true;
                    }

                    if(c->continuePending())
                    {
                        c->handleContinue();
                        ++it;
                        continue;
                    }

                    return false; // propagate the false return value
                }

                ++it;
            }
        }
        break;
        default:
            if(bIncludeEmptyScalars || (!pArg->isEqualToNothing()))
            {
                // we evaluate this each time (as it may actually be killed at each iteration)
                // FIXME: maybe some kind of reference counting or a observer pattern might be a bit more efficient here
                //        (but might be far less efficient everywhere else...)
                KviKvsRWEvaluationResult * v = m_pIterationVariable->evaluateReadWrite(c);
                if(!v)
                    return false;
                v->result()->copyFrom(*pArg);
                delete v; // we're done with it for this iteration

                if(!m_pLoop->execute(c))
                {
                    if(c->error())
                        return false;

                    // break allowed!
                    if(c->breakPending())
                    {
                        c->handleBreak();
                        return true;
                    }

                    if(c->continuePending())
                    {
                        c->handleContinue();
                        continue;
                    }

                    return false; // propagate the false return value
                }
            }
            break;
        }
    }

    return true;
}
bool KviKvsProcessAsyncOperation::trigger(CallbackEvent e, const QString & 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(QString("stdout")));
				break;
			case EventStderr:
				params.append(new KviKvsVariant(QString("stderr")));
				break;
			case EventTerminated:
				params.append(new KviKvsVariant(QString("terminated")));
				break;
			case EventStarted:
				params.append(new KviKvsVariant(QString("started")));
				break;
			case EventPing:
				params.append(new KviKvsVariant(QString("ping")));
				break;
			default:
				qDebug("Oops! Unknown trigger() CallbackEvent parameter in QProcessDescriptor::trigger()");
				return false;
				break;
		}

		params.append(new KviKvsVariant(szData));
		if(m_pData->pMagic)
		{
			KviKvsVariant * pTmp = new KviKvsVariant();
			pTmp->copyFrom(m_pData->pMagic);
			params.append(pTmp);
		}

		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_ctx("Error triggered from process callback handler: killing process", "kvs"));
			return true;
		}

		if(!retVal.isNothing())
		{
			QString sz;
			retVal.asString(sz);
			m_pProcess->write(sz.toUtf8().data());
		}

		if(iRet & KviKvsScript::HaltEncountered)
		{
			// halt encountered: kill the process
			return true;
		}
	}

	return false;
}