/*
    Copyright (C) 2000 - 2001 Kai Heitkamp, kai@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; either version 2 of the License, or
    (at your option) 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., 675 Mass Ave, Cambridge, MA 02139, USA.

 */

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h>

#include <qtextstream.h>

#include <klocale.h>
#include "kmessagebox.h"

#include "cddata.h"
#include "cddata.moc"

static	int CurBus;
struct DEVICES *CurDev;

CDdata::CDdata( QObject * , const char * ) {
	Devices = NULL;
	strncpy( prog, "cdrecord", sizeof( prog ) - 1);
	proc << prog << "-scanbus";
 	connect( &proc, SIGNAL(receivedStderr (KProcess *, char *, int) ),
 		this, SLOT(slotOutput (KProcess *, char *, int) ));
 	connect( &proc, SIGNAL(receivedStdout (KProcess *, char *, int) ),
 		this, SLOT(slotOutput (KProcess *, char *, int) ));
	if ( !proc.start( KProcess::Block, KProcess::AllOutput ) ){
		KMessageBox::sorry( 0, i18n( "Cannot start cdrecord!\n\nIs cdrecord installed? If it is, you need to start KOnCD as root to configure it." ) );
	}
  sprintf( dummystr,"dev=unknown" );

	struct DEVICES *d;

	for( d = Devices; d; d = d -> next ) {
		CurDev = d;
  	proc.clearArguments();
  	proc << prog << d -> devstr << "-prcap";
   	connect( &proc, SIGNAL(receivedStderr (KProcess *, char *, int) ),
   		this, SLOT(slotOutput1 (KProcess *, char *, int) ));
   	connect( &proc, SIGNAL(receivedStdout (KProcess *, char *, int) ),
   		this, SLOT(slotOutput1 (KProcess *, char *, int) ));
  	proc.start( KProcess::Block, KProcess::AllOutput );
	}
}
CDdata::~CDdata(){
	struct DEVICES *dev, *d;

	for( dev = Devices; dev; dev = d ) {
		d = dev -> next;
		free( dev );
	}
}

int CDdata::getDev( int n, const char *(*arr)[4] ) {
	int i;
	struct DEVICES *d;

	for( i = 0, d = Devices; d && i != n; d = d -> next, i++ );
	if( !d ) return -1;
	(*arr)[0] = d -> vendor;
	(*arr)[1] = d -> name;
	(*arr)[2] = d -> version;
	(*arr)[3] = d -> desc;
	return 0;
}

int CDdata::getDevParams( int n, const short *(*arr)[3] ) {
	int i;
	struct DEVICES *d;

	for( i = 0, d = Devices; d && i != n; d = d -> next, i++ );
	if( !d ) return -1;
	(*arr)[0] = &d -> bus;
	(*arr)[1] = &d -> dev;
	(*arr)[2] = &d -> speed;
	return 0;
}

const char * CDdata::getDevStr( int n ) {
	int i;
	struct DEVICES *d;

	for( i = 0, d = Devices; d && i != n; d = d -> next, i++ );
	if( !d ) return dummystr;
	return d -> devstr;
}

bool CDdata::isRW( int n ) {
	int i;
	struct DEVICES *d;

	for( i = 0, d = Devices; d && i != n; d = d -> next, i++ );
	if( !d ) return false;
	return d -> cdrw;
}

const QString CDdata::showOutput() {
	return output;
}

void CDdata::slotOutput(KProcess *, char *s, int n) {
	char *tmp, *c, *b, buf[1024], msg[1024];
	struct DEVICES *dev;
	unsigned i;

	if( !n ) {
		return;
	}
	memset( buf, 0, sizeof( buf ) );
	strncpy( buf, s, n > (int) sizeof( buf ) ? sizeof(buf) - 1 : n );
	output += buf;

	if( strstr( buf, "Cannot open SCSI driver" ) ) {
		tmp = strstr( buf, "'" );
		tmp = strtok( tmp, "'" );
		sprintf( msg, I18N_NOOP( "Cannot open SCSI driver !\n\nAccess denied to %s !\nYou need to start KOnCD as root to configure !" ), tmp );
		KMessageBox::sorry( 0, msg );
	}

	c = strtok( buf, "\n" );
	while( c ) {
  	if( (b = strstr( c, "scsibus" )) ) {
  		CurBus = c[7] - 0x30;
  	}
  	if( (b = strstr( c, ") " )) ) {
  		if( b - 1 >= c && isdigit( *(b-1) ) && b[2] != '*' ) {
    		dev = (struct DEVICES *) calloc( sizeof( struct DEVICES ), 1 );
    		dev -> next = Devices;
    		Devices = dev;
    		dev -> bus = CurBus;
    		dev -> dev = *(b-1) - 0x30;
    		sprintf( dev -> devstr, "dev=%d,%d,0",
    					(CurBus < 32) ? CurBus:0, (dev -> dev < 32) ? dev -> dev:0 );
    		for( ; *b && *b != '\''; b++ ); // point to '
    		if( *b ) b++;	// point to next character
    		for( i = 0; *b && *b != '\'' && i < sizeof(dev->vendor)-1; b++, i++ )
    			dev -> vendor[i] = *b;
    		for( i = 0; *b && i < 2; b++ ) if( *b == '\'' ) i++;
    		for( i = 0; *b && *b != '\'' && i < sizeof(dev->name)-1; b++, i++ )
    			dev -> name[i] = *b;
    		for( i = 0; *b && i < 2; b++ ) if( *b == '\'' ) i++;
    		for( i = 0; *b && *b != '\'' && i < sizeof(dev->version)-1; b++, i++ )
    			dev -> version[i] = *b;
    		for( i = 0; *b && i < 1; b++ ) if( *b == '\'' ) i++;
    		for( i = 0; *b && *b != '\'' && i < sizeof(dev->desc)-1; b++, i++ )
    			dev -> desc[i] = *b;
			}
  	}
		c = strtok( NULL, "\n" );
  }
}

void CDdata::slotOutput1(KProcess *, char *s, int n) {
	char *c, *b, buf[1024];

	if( !n ) return;

	memset( buf, 0, sizeof( buf ) );
	strncpy( buf, s, n >= (int) sizeof( buf ) ? sizeof(buf) - 1 : n );
	output += buf;

	c = strtok( buf, "\n" );
	while( c ) {
  	if( (b = strstr( c, "aximum write speed" )) ) {
  		b = strrchr( c, ' ' );
  		if( b ) CurDev -> speed = atoi( b ) / 150;
  		sprintf( buf, "speed=%d", CurDev -> speed );
  	}
  	if( (b = strstr( c, "Does write CD-RW media" )) ) {
  		CurDev -> cdrw = true;
  	}
		c = strtok( NULL, "\n" );
	}
}

int CDdata::eject( int n ) {
	int i;
	struct DEVICES *d;

	for( i = 0, d = Devices; d && i != n; d = d -> next, i++ );
	if( !d ) return -1;

	proc.clearArguments();
	proc << prog << "-eject" << d -> devstr;
	proc.start( KProcess::Block );
	return 0;
}

int CDdata::load( int n ) {
	int i;
	struct DEVICES *d;

	for( i = 0, d = Devices; d && i != n; d = d -> next, i++ );
	if( !d ) return -1;

	proc.clearArguments();
	proc << prog << "-load" << d -> devstr;
	proc.start( KProcess::Block );
	return 0;
}

int CDdata::reset( int n ) {
	int i;
	struct DEVICES *d;

	for( i = 0, d = Devices; d && i != n; d = d -> next, i++ );
	if( !d ) return -1;

	proc.clearArguments();
	proc << prog << "-reset" << d -> devstr;
	proc.start( KProcess::Block );
	return 0;
}
