/*
    smpppdsearcher.h
 
    Copyright (c) 2004-2006 by Heiko Schaefer        <heiko@rangun.de>
 
    Kopete    (c) 2002-2006 by the Kopete developers <kopete-devel@kde.org>
 
    *************************************************************************
    *                                                                       *
    * 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; version 2 of the License.               *
    *                                                                       *
    *************************************************************************
*/

#include <tqregexp.h>
#include <tqfile.h>

#include <tdeprocess.h>
#include <kdebug.h>

#include "smpppdclient.h"
#include "smpppdsearcher.h"

SMPPPDSearcher::SMPPPDSearcher()
        : m_cancelSearchNow(false),
        m_procIfconfig(NULL),
m_procNetstat(NULL) {}

SMPPPDSearcher::~SMPPPDSearcher() {
    delete m_procIfconfig;
    delete m_procNetstat;
}

/*!
    \fn SMPPPDSearcher::searchNetwork() const
 */
void SMPPPDSearcher::searchNetwork() {
    kdDebug(14312) << k_funcinfo << endl;

    // the first point to search is localhost
    if(!scan("127.0.0.1", "255.0.0.0")) {

        m_procNetstat  = new TDEProcess;
        m_procNetstat->setEnvironment("LANG", "C"); // we want to force english output

        *m_procNetstat << "/bin/netstat" << "-rn";
        connect(m_procNetstat, TQ_SIGNAL(receivedStdout(TDEProcess *,char *,int)), this, TQ_SLOT(slotStdoutReceivedNetstat(TDEProcess *,char *,int)));
        if(!m_procNetstat->start(TDEProcess::Block, TDEProcess::Stdout)) {
            kdDebug(14312) << k_funcinfo << "Couldn't execute /sbin/netstat -rn" << endl << "Perhaps the package net-tools isn't installed." << endl;

            emit smpppdNotFound();
        }

        delete m_procNetstat;
        m_procNetstat = NULL;
    }
}

/*!
    \fn SMPPPDSearcher::slotStdoutReceived(TDEProcess * proc, char * buf, int len)
 */
void SMPPPDSearcher::slotStdoutReceivedIfconfig(TDEProcess * /* proc */, char * buf, int len) {
    kdDebug(14312) << k_funcinfo << endl;

    TQString myBuf = TQString::fromLatin1(buf,len);
    TQRegExp rex("^[ ]{10}.*inet addr:([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}).*Mask:([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})");
    // tokenize the string into lines
    TQStringList toks = TQStringList::split("\n", myBuf);
    for(TQStringList::size_type i = 0; i < toks.count(); i++) {
        if(rex.exactMatch(toks[i])) {
            if(scan(rex.cap(1), rex.cap(2))) {
                return;
            }
        }
    }

    emit smpppdNotFound();
}
void SMPPPDSearcher::slotStdoutReceivedNetstat(TDEProcess * /* proc */, char * buf, int len) {
    kdDebug(14312) << k_funcinfo << endl;

    TQRegExp rexGW(".*\\n0.0.0.0[ ]*([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}).*");
    TQString myBuf = TQString::fromLatin1(buf,len);

    if(!(rexGW.exactMatch(myBuf) && scan(rexGW.cap(1), "255.255.255.255"))) {
        // if netstat -r found no gateway we search the network
        m_procIfconfig = new TDEProcess;
        m_procIfconfig->setEnvironment("LANG", "C"); // we want to force english output

        *m_procIfconfig << "/sbin/ifconfig";
        connect(m_procIfconfig, TQ_SIGNAL(receivedStdout(TDEProcess *,char *,int)), this, TQ_SLOT(slotStdoutReceivedIfconfig(TDEProcess *,char *,int)));
        if(!m_procIfconfig->start(TDEProcess::Block, TDEProcess::Stdout)) {
            kdDebug(14312) << k_funcinfo << "Couldn't execute /sbin/ifconfig" << endl << "Perhaps the package net-tools isn't installed." << endl;

            emit smpppdNotFound();
        }

        delete m_procIfconfig;
        m_procIfconfig = NULL;
    }
}

/*!
    \fn SMPPPDSearcher::scan() const
 */
bool SMPPPDSearcher::scan(const TQString& ip, const TQString& mask) {
    kdDebug(14312) << k_funcinfo << "Scanning " << ip << "/" << mask << "..." << endl;
	
	SMPPPD::Client client;
	
	if(ip == "127.0.0.1") { // if localhost, we only scan this one host
		if(client.connect(ip, 3185)) {
			client.disconnect();
			emit smpppdFound(ip);
			return true;
		}
		
		return false;
	}

    uint min_range = 0;
    uint max_range = 255;

    // calculate ip range (only last mask entry)
    TQRegExp lastRex("([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})");
    if(lastRex.exactMatch(ip)) {

        uint lastWordIP = lastRex.cap(4).toUInt();

        TQStringList ipToks;
        for(int i = 1; i < 5; i++) {
            ipToks.push_back(lastRex.cap(i));
        }

        if(lastRex.exactMatch(mask)) {
            uint lastWordMask = lastRex.cap(4).toUInt();

            if(lastWordMask == 0) {
                kdDebug(14312) << k_funcinfo << "IP-Range: " << ipToks[0] << "." << ipToks[1] << "." <<  ipToks[2] << ".0 - " << ipToks[0] << "." << ipToks[1] << "." << ipToks[2] << ".255" << endl;
                max_range = 255;
            } else if(lastWordMask == 255) {
                min_range = max_range = lastWordIP;
            } else {
                kdDebug(14312) << k_funcinfo << "IP-Range: " << ipToks[0] << "." << ipToks[1] << "." <<  ipToks[2] << ".0 - " << ipToks[0] << "." << ipToks[1] << "." << ipToks[2] << "." << lastWordMask << endl;
                max_range = lastWordMask;
            }
        }

        uint range = max_range - min_range;
        m_cancelSearchNow = false;
        if(range > 1) {
            emit scanStarted(max_range);
        }
        for(uint i = min_range; i <= max_range; i++) {
            if(m_cancelSearchNow) {
                if(range > 1) {
                    emit scanFinished();
                }
                break;
            }
            if(range > 1) {
                emit scanProgress(i);
            }
			
			if(client.connect(TQString(ipToks[0] + "." + ipToks[1] + "." + ipToks[2] + "." + TQString::number(i)), 3185)) {
				client.disconnect();
				emit smpppdFound(ip);
                if(range > 1) {
                    emit scanFinished();
                }
                return true;
			} 
#ifndef NDEBUG
			else {
				kdDebug(14312) << k_funcinfo << "No smpppd found at " << TQString(ipToks[0] + "." + ipToks[1] + "." + ipToks[2] + "." + TQString::number(i)) << endl;
			}
#endif
        }
        if(range > 1) {
            emit scanFinished();
        }
    }

    return false;
}

#include "smpppdsearcher.moc"
