/***************************************************************************
                          distroaccess.cpp  -  description
                             -------------------
    begin                : Mon Apr 29 2002
    copyright            : (C) 2002 by Argo Vessmann (ARTEC Design)
    email                : 
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>

#include "distroaccess.h"

#include "myexec.h"

#include <qdir.h>
#include <qtextstream.h>
#include <qprocess.h>

#include <iostream.h>
extern "C" {
#include <pci/pci.h>
}

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

distroaccess::distroaccess()
{
	distrotype = DISTRO_TYPE_UNKNOWN;
	IdentifyDistro();
	searchExistingSerialPorts();
	searchExistingNetmosCards();
	FindSameNetmosSerials();
	etc_serial_conf = etc_initd_serial = etc_modules_conf = FALSE;

}

distroaccess::~distroaccess(){
}

/** Return's the name of a current distro ( distro on which program is run ) */
QString distroaccess::distroname()
{
	if ( d_name.isNull() )
 		IdentifyDistro();
	return( d_name );
}

/** Return's current distros release number */
QString distroaccess::ReleaseNumber()
{
	if ( rel_number.isEmpty() )
		IdentifyDistro();
	return( rel_number );
}

/** Try's to figure out on which distribution program is run. */
void distroaccess::IdentifyDistro()
{
	QFile f;

 	QDir::setCurrent( "/etc" );
 	f.setName( "issue" );
  	if ( f.open( IO_ReadOnly ) ) {
           	IdentifyDistroByIssue( &f );
  		f.close();
   	}
    	f.setName( "redhat-release" );
     	if ( d_name.isEmpty() && f.open( IO_ReadOnly ) ) {
		IdentifyDistroByRedhatrelease( &f );
		f.close();
        }
        f.setName( "SuSE-release" );
        if ( d_name.isEmpty() && f.open( IO_ReadOnly ) ) {
		IdentifyDistroBySuserelease( &f );
  		f.close();
	}
        if ( d_name.isEmpty() )
        	d_name = "unknown";
	if ( rel_number.isEmpty() )
        	rel_number = "unknown";
	realdistrotype = distrotype;
}


/** Reads an open issue file and trys to identify Distribution. */
void distroaccess::IdentifyDistroByIssue( QFile *f )
{
	QTextStream t( f );
 	QString s = t.read();
  	if ( s.find( "Debian GNU" ) != -1 ) { // It's a debian
   		d_name = "Debian GNU";
   		if ( s.find( "3.0" ) != -1 )
     			rel_number = "3.0";
        }
}

/** Reads in a open file /etc/redhat-release and trys to identify current Distribution. */
void distroaccess::IdentifyDistroByRedhatrelease( QFile *f )
{
	QTextStream t( f );
 	QString s = t.read();
  	if ( s.find( "Red Hat Linux" ) != -1 ) { // It's a Red Hat
   		d_name = "Red Hat Linux";
     		if ( s.find( "release 7.2" ) ) {
       			rel_number = "7.2 enigma";
			distrotype = DISTRO_TYPE_REDHAT72;
		}
        } else if ( s.find( "Mandrake Linux" ) != -1 ) { // It's a Mandrake
		d_name = "Mandrake Linux";
		if ( s.find( "release 8.2" ) ) {
			rel_number = "8.2 bluebird";
			distrotype = DISTRO_TYPE_MANDRAKE82;
		}
	}
  	
}

/** Reads an open release file and trys to identify Distribution. */
void distroaccess::IdentifyDistroBySuserelease( QFile *f )
{
	QTextStream t( f );
	QString s = t.read();
	if ( s.find( "SuSE Linux" ) != -1 ) { // It's a SuSE
		d_name = "SuSE Linux";
		if ( s.find( "7.3" ) ) {
			rel_number = "7.3";
			distrotype = DISTRO_TYPE_SUSE73;
		}
	}
}
/** Returns true if this distribution is supported. */
bool distroaccess::SupportedDistribution()
{

	if ( realdistrotype <= SUPPORTED_DISTROS )
		return( TRUE );
	else
		return( FALSE );
}


/** Searches wether a program with given name exists in system or not.
Returns a full path to program. */
QString distroaccess::FindApp( QString s )
{
	QString cmnd;
	cmnd.sprintf( "which %s", (const char *)s );
	FILE *fp = popen( cmnd, "r" );
	char buf[1024];
	fgets( buf, 1024, fp );
	pclose( fp );
	QString result = buf;
	result = result.stripWhiteSpace();

	return( result );
}

/** Sets the distros type. */
void distroaccess::setDistroType( int d )
{
	distrotype = d;
}

/** Returns a list of serial ports. */
SerialPortList *distroaccess::ExistingSerialPorts()
{
	return( &serialports );
}

/** Searches existing serial ports from system */
void distroaccess::searchExistingSerialPorts()
{
	QFile f;
	f.setName( "/proc/tty/driver/serial" );
	if ( !f.open( IO_ReadOnly ) )
		return;
	QTextStream t( &f );
	t.readLine();
	for( QString line = t.readLine();!line.isNull();line=t.readLine() ) {
		SerialPort po;
		po.clean();
		int en = line.find( ":" );
		QString tmp = line.mid( 0, en );
		po.port = tmp.toInt();
		int st = line.find( "uart:" );
		en = line.find( " ", st );
		po.uart = line.mid( st+5, en-st-5 );
		st = line.find( "irq:" );
		en = line.find( " ", st );
		tmp = line.mid( st+4, en-st-4 );
		po.irq = tmp.toInt();
		st = line.find( "port:" );
		en = line.find( " ", st );
		tmp = line.mid( st+5, en-st-5 );
		po.io = tmp.toInt(0, 16);
		st = line.find( "baud:" );
		en = line.find( " ", st );
		tmp = line.mid( st+5, en-st-5 );
		po.baud = tmp.toInt();

		if( po.uart.compare( "unknown" ) == 0 )
			continue;
		if( line.find( "baud:" ) == -1 )
			po.baud = -1;
		po.setDetected( TRUE );
		po.setSystemPort( TRUE );
		serialports.append( po );
	}
	f.close();
	return;
}

/** Returns the list of Netmos cards that are on this system */
NetmosCardList *distroaccess::ExistingNetmosCards()
{
	return( &netmoscards );
}

/** Searches NetMos cards from system */
void distroaccess::searchExistingNetmosCards()
{

	struct pci_access *pacc;
	pacc = pci_alloc();

	pci_init( pacc );
	pci_scan_bus( pacc );
#ifdef DEBUG_CARDS
	int i=0;
#endif
	for( struct pci_dev *dev=pacc->devices;dev;dev=dev->next ) {
		NetmosCard card;
		pci_fill_info( dev, PCI_FILL_IDENT | PCI_FILL_BASES );
#ifdef DEBUG_CARDS
		if ( ++i == 1 ) {
			dev->device_id = 0x9835;
			dev->vendor_id = 0x9710;
		}
		if ( i == 2 ) {
			dev->device_id = 0x9805;
			dev->vendor_id = 0x9710;
		}
#endif
		card.init( dev );
		if ( card.isValid() )
			netmoscards.append( card );
	}
	pci_cleanup( pacc );
	return;
}

/** List of serials that are valid for netmos cards. */
QStringList distroaccess::ValidSerials()
{

	QStringList resp;

	QString s;
	for( int i=0;i<20;i++ ) {
		s.sprintf( "/dev/ttyS%i", i );
		resp.append( s );
	}
#if ( QT_VERSION >= 300 )
	SerialPortList::iterator it;
#else
	SerialPortList::Iterator it;
#endif
	/** Remove all system ports, that don't belong to netmos cards,
		from lists. ( We can't configure netmos as COM1, COM2, if 
		they are onboard serials. ) */
	for( it=serialports.begin(); it != serialports.end(); ++it ) {
		QStringList::Iterator sit;
		if ( !(*it).isSystemPort() )
			continue;
		sit = resp.find( (*it).DevName() );
		resp.remove( sit );
	}
#if ( QT_VERSION >= 300 )
	NetmosCardList::iterator nit;
#else
	NetmosCardList::Iterator nit;
#endif
	for( nit=netmoscards.begin(); nit !=netmoscards.end(); ++nit ) {
		QStringList::Iterator sit;
		SerialPort *tmpp;
		if ( !(*nit).fixedConf() )
			continue;
		if ( (*nit).hasSerials() ) {
			tmpp = (*nit).GetConfiguredSerialPort( 0 );
			(*nit).debug();
			if ( tmpp ) {
				sit = resp.find( tmpp->DevName() );
				if ( sit != resp.end() )
					resp.remove( sit );
			}
		}
		if ( (*nit).has2SerialPorts() ) {
			tmpp = (*nit).GetConfiguredSerialPort( 1 );
			if ( tmpp ) {
				sit = resp.find( tmpp->DevName() );
				if ( sit != resp.end() )
					resp.remove( sit );
			}
		}
	}
	return( resp );
}

/** Finds all the configured serials that belong to netmos cards. */
void distroaccess::FindSameNetmosSerials()
{
#if ( QT_VERSION >= 300 )
	SerialPortList::iterator sit;
	NetmosCardList::iterator nit;
#else
	SerialPortList::Iterator sit;
	NetmosCardList::Iterator nit;
#endif
	for( sit=serialports.begin(); sit!=serialports.end(); ++sit ) {
		for( nit=netmoscards.begin(); nit!=netmoscards.end(); ++nit ) {
			if ( (*nit).hasExistingSerial( &(*sit) ) ) {
				(*sit).setNetmosCard( TRUE );
				(*sit).setSystemPort( FALSE );
			}
		}
	}
}

/** Saves configuration. */
bool distroaccess::saveConf()
{
	QString resp;
	errormsg ="Writing configuration to disk failed\n\n"
		"Fatal error - writing configuration to disk failed.";
#if ( QT_VERSION >= 300 )
	NetmosCardList::iterator nit;
#else
	NetmosCardList::Iterator nit;
#endif
	resp.sprintf( "<h3>Checking device files</h3>\n" );
	for( nit=netmoscards.begin(); nit!=netmoscards.end(); ++nit ) {
		for( int i=0;i<2;i++ ) {
			SerialPort *po = (*nit).GetConfiguredSerialPort( i );
			if ( !po )
				continue;
			if ( !po->testDeviceFile( &resp, getDevOwner(), getDevGroup() ) )
				return( FALSE );
		}
	}
	if ( !saveSerialConf( &resp ) )
		return( FALSE );
	if ( !saveParallelConf( &resp ) )
		return( FALSE );
	bool succ = TRUE;
	if ( !restartSerial() )
		succ = FALSE;
	if ( !restartParallel() )
		succ = FALSE;
	if ( !succ ) {
		errormsg = "Modifying configuration files was successful. "
			"But restarting the serivces failed. You have to "
			"restart services by yourself or reboot the "
			"computer. After rebooting installtion is complete.";
		return( FALSE );
	}
	return( TRUE );
}

/** Find's init directory. */
bool distroaccess::FindInitDirectory( void )
{
	struct stat sbuf;
	int resp = stat( "/etc/init.d", &sbuf );
	if ( resp == 0 ) {
		initddir = "/etc/init.d";		
		return( TRUE );
	}
	resp = stat( "/etc/rc.d/init.d", &sbuf );
	if ( resp == 0 ) {
		initddir = "/etc/rc.d/init.d";		
		return( TRUE );
	}
	errormsg ="Cannot find /etc/init.d directory\n\n"
		"Solution: Handling the situation is beyond the scope of this "
		"program.";
	return( FALSE );
}

/** Test if init script exists. If not creates it. */
bool distroaccess::testInitScript( void )
{
	errormsg ="Setserial not found in /etc/init.d directory\n\n"
		"Reason: Setserial package not installed. Setserial pacakge is "
		"necessary to run this application.\n\n"
		"Solution: install setserial package. For more information "
		"consult your system documentation.\n";
	rcscript.sprintf( "%s/setserial", (const char *)initddir );
	struct stat sbuf;
	int resp = stat( rcscript, &sbuf );
	if ( resp == 0 ) 
		return TRUE;
	rcscript.sprintf( "%s/serial", (const char *)initddir );
	if ( stat( rcscript, &sbuf ) == 0 ) 
		return TRUE;

	rcscript.sprintf( "%s/setserial", (const char *)initddir );
// ### Distribution Specific
	QFile sf;
	QString src;
	src = "/usr/share/doc/setserial-2.17/rc.serial";
	sf.setName( src );
	if ( !sf.open( IO_ReadOnly ) )
		return( FALSE );
	QFile of;
	of.setName( rcscript );
	if ( !of.open( IO_WriteOnly ) ) {
		sf.close();
		return( FALSE );
	}
	QByteArray ba = sf.readAll();
	of.writeBlock( ba );
	of.close();
	sf.close();

	chmod( rcscript, (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) );

	return TRUE;
}

/** Saves serial configuration. */
bool distroaccess::saveSerialConf( QString *log )
{
	removeOldSerialConf();
	if ( distrotype == DISTRO_TYPE_REDHAT72 ||
		distrotype == DISTRO_TYPE_MANDRAKE82 ) {
		if ( log )
			log->append( "Modifying /etc/serial.conf -- " );
		if ( saveSerialConfRedHatMandrake( log ) ) {
			if ( log )
				log->append( "OK<BR>\n" );
			return TRUE;
		} else {
			if ( log )
				log->append( "Failed<BR>\n" );
			return FALSE;
		}
	} else if ( distrotype == DISTRO_TYPE_SUSE73 ) {
		log->append( "Modifying rcscript -- " );
		if ( saveSerialConfSuse73( log) ) {
			if ( log )
				log->append( "OK<BR>\n" );
			return TRUE;
		} else {
			if ( log )
				log->append( "Failed<BR>\n" );
			return FALSE;
		}
	}
	return TRUE;
}

/** Saves serial configuration. ( for suse 7.3 ) */
bool distroaccess::saveSerialConfSuse73( QString *log )
{
	QFile f( rcscript );
	if ( !f.open( IO_ReadOnly ) )
		return FALSE;
	QTextStream ts( &f );
	QString all=ts.read();
	ts.unsetDevice();
	f.close();
	QStringList splitted = QStringList::split( QChar( '\n' ), all, TRUE );

#if ( QT_VERSION >= 300 )
	NetmosCardList::iterator nit;
#else
	NetmosCardList::Iterator nit;
#endif
	for( nit=netmoscards.begin(); nit!=netmoscards.end(); ++nit ) {
		for( int i=0;i<2;i++ ) {
			SerialPort *po = (*nit).GetConfiguredSerialPort( i );
			if ( !po )
				continue;
			etc_initd_serial = TRUE;
			po->saveForSuse73( &splitted, log );
		}
	}
	if ( !f.open( IO_WriteOnly ) )
		return FALSE;
	ts.setDevice( &f );
	all = splitted.join( QString( "\n" ) );
	ts << all;
	ts.unsetDevice();
	f.close();
	return TRUE;
}

/** Save configuration into /etc/serial.conf */
bool distroaccess::saveSerialConfRedHatMandrake( QString *log )
{
	QFile f( "/etc/serial.conf" );
	QString all;
	if ( f.open( IO_ReadOnly ) ) {
		QTextStream ts( &f );
		all=ts.read();
		ts.unsetDevice();
		f.close();
	}
	QStringList splitted = QStringList::split( QChar( '\n' ), all, TRUE );

#if ( QT_VERSION >= 300 )
	NetmosCardList::iterator nit;
#else
	NetmosCardList::Iterator nit;
#endif
	for( nit=netmoscards.begin(); nit!=netmoscards.end(); ++nit ) {
		for( int i=0;i<2;i++ ) {
			SerialPort *po = (*nit).GetConfiguredSerialPort( i );
			if ( !po )
				continue;
			etc_serial_conf = TRUE;
			po->saveForMandrakeRedHat( &splitted, log );
		}
	}
	for( QStringList::Iterator it=splitted.begin();it != splitted.end();it++ ) {
		if ( (*it).stripWhiteSpace().isEmpty() )
			it = splitted.remove( it );
	}
	if ( !f.open( IO_WriteOnly ) )
		return FALSE;
	QTextStream ts( &f );
	all = splitted.join( QString( "\n" ) );
	ts << all;
	ts.unsetDevice();
	f.close();
	return TRUE;
}

/** Saves parallel configuration. */
bool distroaccess::saveParallelConf( QString *log )
{
	if ( log )
		log->append("Writing parallel configuration -- " );
	QStringList io, io_hi, irq;
	FindExistingParallelPorts( &io, &io_hi, &irq );
#if ( QT_VERSION >= 300 )
	NetmosCardList::iterator nit;
#else
	NetmosCardList::Iterator nit;
#endif
	for( nit=netmoscards.begin(); nit!=netmoscards.end(); ++nit ) {
		for( int i=0;i<2;i++ ) {
			if ( !(*nit).hasParallel( i ) )
				continue;
			if ( !(*nit).parallelenabled( i ) )
				continue;
			etc_modules_conf = TRUE;
			io.append( (*nit).getsParallelPort( i ) );
			io_hi.append( (*nit).getsParallelPortHi( i ) );
			irq.append( (*nit).getsIrq() );
		}
	}
	QString newconf;
	newconf.sprintf( "options parport_pc io=%s io_hi=%s irq=%s", \
		(const char *)io.join( "," ), (const char *)io_hi.join( "," ), (const char *)irq.join( "," ) );

	QFile f( "/etc/modules.conf" );
	if ( !f.open( IO_ReadOnly ) ) {
		if( log )
			log->append( "failed<BR>\n" );
		return FALSE;
	}
	QTextStream ts( &f );
	QString all=ts.read();
	ts.unsetDevice();
	f.close();
	QStringList splitted = QStringList::split( QChar( '\n' ), all, TRUE );
	
#if ( QT_VERSION >= 300 )
	QStringList::iterator sit;
#else
	QStringList::Iterator sit;
#endif

	for ( sit = splitted.begin(); sit != splitted.end(); ++sit ) {
		QString tmp = (*sit).stripWhiteSpace();
		if ( tmp[0] == '#' )
			continue;
		if ( tmp.find( "options parport_pc" ) != -1 ) {
			(*sit) = newconf;
			break;
		}
		
	}
	if ( sit == splitted.end() )
		splitted.append( newconf );

	if ( !f.open( IO_WriteOnly ) ) {
		if ( log )
			log->append( "failed<BR>\n" );
		return FALSE;
	}
	ts.setDevice( &f );
	all = splitted.join( QString( "\n" ) );
	ts << all;
	ts.unsetDevice();
	f.close();
	if ( log )
		log->append( "OK<BR>\n" );
	return TRUE;
}

/** Searches system for existing parallel ports. */
void distroaccess::FindExistingParallelPorts( QStringList *io, QStringList *io_hi, QStringList *irq )
{
	execsyscmnd( modprobe+" parport_pc" );
	
	QDir d( "/proc/sys/dev/parport" );
	d.setNameFilter( "parport*" );
	const QFileInfoList *list = d.entryInfoList();
	QFileInfoListIterator it( *list );
	QFileInfo *fi;
	while ( (fi = it.current()) != 0 ) {
		QString fname;
		fname = fi->absFilePath();
		fname += "/base-addr";
		QFile f( fname );
		if ( !f.open( IO_ReadOnly ) ) {
			++it;
			continue;
		}
		QTextStream ts( &f );
		QString row;
		ts >> row;
		if ( isNetmosPort( row.toInt() ) ) {
			++it;
			continue;
		}
		QString tmp;
		tmp.sprintf( "0x%x", row.toInt() );
		io->append( tmp );
		ts >> row;
		tmp.sprintf( "0x%x", row.toInt() );
		io_hi->append( tmp );
		ts.unsetDevice();
		f.close();

		fname = fi->absFilePath();
		fname += "/irq";
		f.setName( fname );
		if ( !f.open( IO_ReadOnly ) ) {
			++it;
			irq->append( "auto" );
			continue;
		}
		ts.setDevice( &f );
		ts >> row;
		if ( row.toInt() == -1 )
			irq->append( "auto" );
		else
			irq->append( row );
		ts.unsetDevice();
		f.close();
		
		++it;
	}
}

/** Returns TRUE if this given port ( p ) is port on netmos card. */
bool distroaccess::isNetmosPort( int p )
{
#if ( QT_VERSION >= 300 )
	NetmosCardList::iterator nit;
#else
	NetmosCardList::Iterator nit;
#endif
	for( nit=netmoscards.begin(); nit!=netmoscards.end(); ++nit ) {
		if ( (*nit).isNetmosPort( p ) )
			return TRUE;
	}
	return FALSE;
}

/** Activates new serial configuration. */
bool distroaccess::restartSerial( void )
{
	QString cmnd;

	cmnd.sprintf( "%s start", (const char *)rcscript );
	MyExec cm( cmnd );
	if ( cm.returnValue() == 0 )
		return TRUE;
	else
		return FALSE;
}


/** Activates new parallel configuration. */
bool distroaccess::restartParallel( void )
{
	QString cmnd;

	execsyscmnd( rmmod+" lp" );
	execsyscmnd( rmmod+" parport_pc" );
	bool parexists = FALSE;

 	QStringList lines = readFileToLines( procfs+"/modules" );
 	for( QStringList::Iterator it=lines.begin();it!=lines.end();it++ ) {
 		if ( (*it).mid( 0, 10 ) == "parport_pc" ) {
 			parexists = TRUE;
 			break;
 		}
 	}
	if ( parexists )
		return FALSE;

	MyExec cm( modprobe+" parport_pc" );
	execsyscmnd( modprobe+" lp" );
	if ( cm.returnValue() == 0 )
		return TRUE;
	else
		return FALSE;

}

/** Removes with setserial old serial configuration of netmoscard */
void distroaccess::removeOldSerialConf()
{
#if ( QT_VERSION >= 300 )
	SerialPortList::iterator it;
#else
	SerialPortList::Iterator it;
#endif
	for( it=serialports.begin(); it != serialports.end(); ++it ) {
		if ( !isNetmosPort( (*it).io ) )
			continue;
		(*it).testDeviceFile( NULL, getDevOwner(), getDevGroup() );

		QString cmnd;
		cmnd.sprintf( "%s %s uart unknown", (const char *)setserial_cmnd, (const char *)(*it).DevName() );
		execsyscmnd( (const char *)cmnd );
	}		
}

/** Return's device files owner for current distribution. */
char * distroaccess::getDevOwner()
{
	if ( distrotype == DISTRO_TYPE_REDHAT72 ) {
		return( "root" );
	} else if ( distrotype == DISTRO_TYPE_MANDRAKE82 ) {
		return( "root" );
	}
	return( "" );
}

/** Return's device files group for current distribution. */
char * distroaccess::getDevGroup()
{
	if ( distrotype == DISTRO_TYPE_REDHAT72 ) {
		return( "uucp" );
	} else if ( distrotype == DISTRO_TYPE_MANDRAKE82 ) {
		return( "tty" );
	}
	return( "" );
}

int distroaccess::execsyscmnd( QString cmnd )
{
//	cmnd += ">/dev/null 2>/dev/null";
//	iofork( cmnd, ifd, ofd, efd )
	MyExec cm( cmnd );
	return cm.returnValue();
}

bool distroaccess::testSystem()
{
	if ( !testIsRootId() )
		return FALSE;
	setserial_cmnd = FindApp( "setserial" );
	if ( setserial_cmnd.isEmpty() ) {
		errormsg = "Could not locate setserial.\n\n"
			"You need to install the setserial package.";
		return FALSE;
	}
	if ( !testProcFs() )
		return FALSE;
	if ( !testModprobe() )
		return FALSE;
	if ( !testRmmod() )
		return FALSE;
	if ( !testLPTModule() )
		return FALSE;
	if ( !testSerial() )
		return FALSE;
	if ( !FindInitDirectory() )
		return FALSE;
	if ( !testInitScript() )
		return FALSE;
	if ( !testNetmosCards() )
		return FALSE;
	return TRUE;
}

bool distroaccess::testNetmosCards()
{
	ExistingNetmosCards();

	if ( !netmoscards.isEmpty() ) 
		return TRUE;
	
	errormsg = "No NetMos cards found\n\n"
		"System cannot detect any NetMos cards. Please check the card. "
		"If the card is inserted correctly but still not responding, "
		"try inserting it into some other PCI slot.";
	return FALSE;
}
	
bool distroaccess::testLPTModule()
{
	bool resp = FALSE;

	MyExec cm( modprobe+" parport_pc" );
 	QStringList lines = readFileToLines( procfs+"/modules" );
 	for( QStringList::Iterator it=lines.begin();it!=lines.end();it++ ) {
 		if ( (*it).mid( 0, 10 ) == "parport_pc" ) {
 			resp = TRUE;
 			break;
 		}
 	}

	errormsg = "No parport_pc module found.\n\n"
		"Parallel port support has to be installed as module not built "
		"directly into the kernel.\n\n"
		"a) When building the custom kernel, enable the option "
		"'Parallel port support ---> PC style hardware' and make sure "
		"that the parallel port is installed as a module marked (M).\n"
		"b) You can use the default kernel provided by "+distributor()+
		", in most cases "
		"it is built with parallel port as module.\n\n"
		"For more information about building your kernel and kernel "
		"modules see 'The Linux Documentation Project', The Linux "
		"Kernel HOWTO (http://www.tldp.org/HOWTO/Kernel-HOWTO.html), "
		"it should have plenty of information there.";
	return resp;
}

bool distroaccess::testProcFs()
{
	MyExec cm( "mount" );
	QStringList olist = cm.stdOutput();
	QStringList::Iterator it;
	for ( it=olist.begin(); it != olist.end(); it++ ) {
		if ( (*it).find( "type proc" ) != -1 ) {
			QStringList tmp = QStringList::split( ' ', (*it) );
			procfs = tmp[2];
			return TRUE;
		}
	}
	errormsg = "Cannot find proc filesystem.\n\n"
		"The kernel has to be built with proc filesystem support and "
		"the proc file system has to be mounted.\n\n"
		"If the proc file system is not supported in your current "
		"kernel build, you have two options to troubleshoot this "
		"issue:\n"
		"a) When building the custom kernel yourself, enable the "
		"option 'File systems ---> /proc file system support'.\n"
		"b) You can use the default kernel by "+distributor()+
		", in most cases "
		"it is built with proc file system support.\n\n"
		"If you are sure that the kernel has proc file system support, "
		"check that the proc file system is mounted. Enter command "
		"'mount', the list of mounted filesystems appears on screen. "
		"To mount the proc file system enter the command 'mount proc "
		"/proc'.\n\n"
		"For more information about building your kernel see 'The "
		"Linux Documentation Project', The Linux Kernel HOWTO "
		"(http://www.tldp.org/HOWTO/Kernel-HOWTO.html), it should have "
		"plenty of information there.";
	return FALSE;
}

bool distroaccess::testIsRootId()
{
	uid_t euid = geteuid();
	if ( euid == 0 )
		return TRUE;
	errormsg = "You must log in as root to use this application.\n\n"
		"If you are not logged in as root open your favorite terminal "
		"client, enter the command 'su' and the root password. After "
		"successfully logging in as root, start the application again.";

	return FALSE;
}

bool distroaccess::testSerial()
{
	if ( QFile::exists( procfs+"/tty/driver/serial" ) )
		return TRUE;
	MyExec( modprobe+" serial" );
	if ( QFile::exists( procfs+"/tty/driver/serial" ) )
		return TRUE;
	errormsg = "No serial support detected.\n\n"
		"You have two options to solve this problem.\n"
		"a) Build the serial support directly into the kernel. When "
		"building the custom kernel, enable the options 'Character "
		"devices ---> Standard/ generic (8250/16550 and compatible "
		"UARTs) serial support'. If you have more than four serial "
		"ports, additionaly enable the 'Extended dumb serial options' "
		"and 'Support for more than 4 serial ports' in the 'Character "
		"devices' section.\n"
		"b) You can use the default kernel by "+distributor()+
		", in most cases "
		"it is built with serial port support.\n\n"
		"For more information about building your kernel see 'The "
		"Linux Documentation Project', The Linux Kernel HOWTO "
		"(http://www.tldp.org/HOWTO/Kernel-HOWTO.html), it should have "
		"plenty of information there.";
	return FALSE;
}

bool distroaccess::testModprobe()
{
	modprobe = "/sbin/modprobe";
	if ( QFile::exists( modprobe ) )
		return TRUE;
	modprobe = "/usr/sbin/modprobe";
	if ( QFile::exists( modprobe ) )
		return TRUE;
	errormsg = "Can't find modprobe.";
	return FALSE;
}

bool distroaccess::testRmmod()
{
	rmmod = "/sbin/rmmod";
	if ( QFile::exists( rmmod ) )
		return TRUE;
	rmmod = "/usr/sbin/rmmod";
	if ( QFile::exists( rmmod ) )
		return TRUE;
	errormsg = "Can't find rmmod.";
	return FALSE;
}


QString distroaccess::ErrorMsg()
{
	return errormsg;
}

QStringList distroaccess::readFileToLines( QString fname )
{
	QFile f( fname );
	f.open( IO_ReadOnly );
	QTextStream t( &f );
 	QString s = t.read();
 	t.unsetDevice();
 	f.close();

 	return( QStringList::split( "\n", s ) );
}

bool distroaccess::suitableSerials( QString *s1, QString *s2 )
{
	if ( !s1 )
		return TRUE;
	if ( !s2 )
		return TRUE;
	if ( *s1 == *s2 )
		return FALSE;

	return TRUE;
}

QString distroaccess::distributor()
{
	QString resp;
	if ( distrotype == DISTRO_TYPE_SUSE73 )
		resp = "SuSE";
	else if ( distrotype == DISTRO_TYPE_REDHAT72 )
		resp = "RedHat";
	else if ( distrotype == DISTRO_TYPE_MANDRAKE82 )
		resp = "Mandrake";
	else
		resp = "Unknown";
	return( resp );
}

QString distroaccess::README()
{
	QString resp = "This is a program to configure NetMos PCI IO-cards "
		"Nm9835 and Nm9805.\n\n"
		"This program is tested on following Linux distributions: "
		"RedHat 7.2, SuSE 7.3 and Mandrake 8.2. On other distributions "
		"this program may and may not work.\n\n"
		"To configure parallel ports, this program modifies "
		"modules.conf file. It adds necessary options to parport_pc "
		"module.\n\n"
		"To configure serial ports, this program modifies serial.conf "
		"file on RedHat and Mandrake, and setserial's init script on "
		"SuSE. It adds necessary configuration lines to configure "
		"NetMos cards serial ports.";
	return( resp );
}

QString distroaccess::saveOkMsg()
{
	QString resp = "Finished configuring NetMos cards. System updated "
		"successfully.\n\n"
		"Following system files were updated:\n";
	if ( etc_serial_conf )
		resp += "\t/etc/serial.conf\n";
	if ( etc_initd_serial )
		resp += "\t"+rcscript+"\n";
	if ( etc_modules_conf )
		resp += "\t/etc/modules.conf\n";
	resp += "\nIn case you want to reconfigure cards rerun this program.";
	return( resp );
}
