/***************************************************************************
                                arc_vfs.cpp
                             -------------------
    copyright            : (C) 2000 by Shie Erlich & Rafi Yanai
    e-mail               : krusader@users.sourceforge.net
    web site             : http://krusader.sourceforge.net
 ---------------------------------------------------------------------------
  Description 
 ***************************************************************************

  A 

     db   dD d8888b. db    db .d8888.  .d8b.  d8888b. d88888b d8888b.
     88 ,8P' 88  `8D 88    88 88'  YP d8' `8b 88  `8D 88'     88  `8D
     88,8P   88oobY' 88    88 `8bo.   88ooo88 88   88 88ooooo 88oobY'
     88`8b   88`8b   88    88   `Y8b. 88~~~88 88   88 88~~~~~ 88`8b
     88 `88. 88 `88. 88b  d88 db   8D 88   88 88  .8D 88.     88 `88.
     YP   YD 88   YD ~Y8888P' `8888Y' YP   YP Y8888D' Y88888P 88   YD

                                                     S o u r c e    F i l e

 ***************************************************************************
 *                                                                         *
 *   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 <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
// QT includes
#include <tqregexp.h>
#include <tqdir.h>
#include <tqdatetime.h>
#include <tqfileinfo.h>
// KDE includes
#include <kmessagebox.h>
#include <klocale.h>
#include <kprocess.h>
#include <kio/jobclasses.h>
#include <tqprogressdialog.h>
#include <kglobalsettings.h>
#include <kmimetype.h>
#include <kcursor.h>
#include <klargefile.h>
// krusader includes
#include "arc_vfs.h"
#include "krpermhandler.h"
#include "krarchandler.h"
#include "../krusader.h"
#include "../defaults.h"
#include "../resources.h"
#include "../Dialogs/krdialogs.h"

#define MAX_FILES 500

//constructor
arc_vfs::arc_vfs(TQString origin,TQString type,TQObject* panel,bool write):
  vfs(panel),arcFile(origin),changed(false),prefix(""),ignoreLines(0){

	if ( type == "tarz" ) type = "-tgz";
	
	// set the cursor to busy mode
  if (!quietMode) krApp->setCursor(KCursor::waitCursor());

  // set the writable attribute
	isWritable = KRpermHandler::fileWriteable(origin);
  isWritable = ( write && isWritable ); 	

  vfs_type = vfs::ERROR;

	// create the temp dir..
  tmpDir = krApp->getTempDir();
 	if( tmpDir.isEmpty() ){
  	error = true;
		return;
	}

	TQString password = TQString();
  krConfig->setGroup("Archives");
  // fill the command options
  if( type == "gzip" ){
    cmd = KrServices::fullPathName ( "gzip" );
    listCmd = "-l";
    delCmd  = "";
    addCmd  = KrServices::fullPathName ( "gzip" ) + " -c";
    getCmd  = "-dc";
		ignoreLines = -1;
		isWritable = false;
  }
  if(type == "zip2"){
    cmd = KrServices::fullPathName( "bzip2" );
    listCmd = "";
    delCmd  = "";
    addCmd  = KrServices::fullPathName( "bzip2" )+ " -c";
    getCmd  = "-dc";
		ignoreLines = -1;
    isWritable = false;
  }
  if(type == "-tar"){
    cmd = KrServices::fullPathName( "tar" );
    listCmd = " -tvf";
    delCmd  = cmd+" --delete -vf";
    addCmd  = cmd+" -uvf";
    getCmd  = " -xvf";
  }
	if(type == "-tgz"){
    cmd = KrServices::fullPathName( "tar" );
    listCmd = " -tzvf";
    delCmd  = "";
    addCmd  = cmd+" -uvzf";
    getCmd  = " -xzvf";
    isWritable = false;
  }
  if(type == "-tbz"){
    cmd = KrServices::fullPathName( "tar" );
    listCmd = " -tjvf";
    delCmd  = "";
    addCmd  = cmd+" -uvjf";
    getCmd  = " -xjvf";
    isWritable = false;
  }
	if(type == "-zip"){
    password = KRarcHandler::getPassword(arcFile,type);
		cmd = KrServices::fullPathName( "unzip" );
    listCmd = "-ZTs ";
    TQString zipcmd = KrServices::fullPathName( "zip" );
    delCmd  = zipcmd+" -d";
    addCmd  = zipcmd+" -ry";
    getCmd  = " -o";
		if( !password.isEmpty() ){
    	//listCmd = listCmd + " -P "+password;
			delCmd = delCmd + " -P "+password;
			addCmd = addCmd + " -P "+password;
			getCmd = getCmd + " -P "+password;
		}
    ignoreLines = 1;
  }
  // "-rpm" is used only to list the rpm - to extract files use "+rpm"
  if(type == "-rpm"){
    //rpm can't handle files with " " in them so replace " " with "\ "
    arcFile.replace(TQRegExp(" "),"\\ ");

    cmd = KrServices::fullPathName( "rpm" );
    listCmd = " --dump -lpq ";
    delCmd  = "";
    addCmd  = "";
    getCmd  = "";
    isWritable    = false;
  }
  if( type == "+rpm" ){
		// extract the cpio archive from the rpm
		KShellProcess rpm;
  	rpm << "rpm2cpio"<<"\""+arcFile+"\""+" > "+tmpDir+"/contents.cpio";
  	rpm.start(KProcess::Block);
		arcFile = tmpDir+"/contents.cpio";
	}
	if(type == "cpio" || type == "+rpm" ){
    cmd = KrServices::fullPathName( "cpio" );
    listCmd = "-tvF ";
    delCmd  = "";
    addCmd  = "";
    getCmd  = " --force-local --no-absolute-filenames -ivdF";
    isWritable    = false;
  }
  if(type == "-rar"){
    bool doRar = krConfig->readBoolEntry("Do Rar",_DoRar);
    cmd = KrServices::fullPathName( "unrar" );
    listCmd = " -c- v ";
    delCmd  = "";
    addCmd  = (doRar ? TQString(KrServices::fullPathName( "rar" ) + " -r a ") : TQString("")) ;
    getCmd  = " x -y ";
    ignoreLines = 8;
    isWritable    = (doRar && isWritable );
  }

	getDirs();
	// set the cursor to normal mode
  if (!quietMode) krApp->setCursor(KCursor::arrowCursor());
}

// return the working dir
TQString arc_vfs::vfs_workingDir(){
  // get the path inside the archive
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  if(path.left(1) != "/") path = "/"+path;
  TQDir().mkdir(tmpDir+path);
  return tmpDir+path;
}

arc_vfs::~arc_vfs(){
  // set the cursor to busy mode
  if (!quietMode) krApp->setCursor(KCursor::waitCursor());
	// don't touch messed-up archives
	if(!error) repack();
  // delete the temp dir
  KShellProcess proc;
  proc<<"rm"<<"-rf"<<tmpDir;
  proc.start(KProcess::Block);

	// set the cursor to normal mode
  if (!quietMode) krApp->setCursor(KCursor::arrowCursor());
}	

bool arc_vfs::getDirs(){
  if( !listCmd.isEmpty() ){
    // write the temp file
    KShellProcess proc;
    proc << cmd << listCmd << "\""+arcFile+"\"" <<" > " << tmpDir+"/tempfilelist";
    proc.start(KProcess::Block);
    if( !proc.normalExit() || !proc.exitStatus() == 0 ){
      if (!quietMode) KMessageBox::error(krApp, i18n("<qt>Can't read <b>%1</b>. Archive "
                      "might be corrupted!</qt>").arg(arcFile.mid(arcFile.findRev('/')+1)));
     error = true;
		 return false;
    }
		
		// clear the dir list
  	dirList.clear();

  	// prepare the first dir entry - the "" entry
  	arc_dir *tempdir = new arc_dir("");
  	vfs_filesP = &(tempdir->entries);
  	dirList.append(tempdir);

    // parse the temp file
    TQFile temp(tmpDir+"/tempfilelist");
    temp.open(IO_ReadOnly);
    char buf[1000];
    TQString line;
    if(vfs_type == "gzip" || vfs_type == "-zip" )
      temp.readLine(line,10000);  // skip the first line - it's garbage
    if( vfs_type == "-rar" ){
      while(temp.readLine(line,10000) != -1)
        if ( line.contains("----------") ) break;
    }
    while(temp.readLine(buf,1000) != -1){
      line = TQString::fromLocal8Bit(buf);
      if ( line.contains("----------") ) break;
      parseLine(line.stripWhiteSpace(),&temp);

    }
    temp.close();
    TQDir().remove(tmpDir+"/tempfilelist");
  }
  else { // bzip2
		// clear the dir list
  	dirList.clear();

  	// prepare the first dir entry - the "" entry
  	arc_dir *tempdir = new arc_dir("");
  	vfs_filesP = &(tempdir->entries);
  	dirList.append(tempdir);

	 	parseLine("",0);
	}
	return true;
}


// copy a file to the vfs (physical)
void arc_vfs::vfs_addFiles(KURL::List *fileUrls,KIO::CopyJob::CopyMode mode,TQObject* toNotify,TQString dir, PreserveMode /*pmode*/ ){
  if ( addCmd.isEmpty() ) return;

  // get the path inside the archive
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  path = path+"/";
  if(dir != "" ) dir = "/"+dir;
  if(path.left(1) != "/") path = "/"+path;

  // make sure the destination exist
  for( int i=0; i >= 0 ; i= TQString(tmpDir+path+dir).find('/',i+1) ){
    TQDir().mkdir(TQString(tmpDir+path+dir).left(i));
  }

  changed = true; //rescan the archive
	
	KURL dest;
	dest.setPath(tmpDir+path+dir);

  KIO::Job* job = new KIO::CopyJob(*fileUrls,dest,mode,false,true);
  connect(job,TQT_SIGNAL(result(KIO::Job*)),this,TQT_SLOT(vfs_refresh(KIO::Job*)) );
  if(mode == KIO::CopyJob::Move) // notify the other panel
   connect(job,TQT_SIGNAL(result(KIO::Job*)),toNotify,TQT_SLOT(vfs_refresh(KIO::Job*)) );
}
	

// remove a file from the vfs (physical)
void arc_vfs::vfs_delFiles(TQStringList *fileNames){
  if ( delCmd.isEmpty() ) return;
	// if we move to trash - just extract files and move them to trash -
  // the repack() will delete them for us
  krConfig->setGroup("General");
	if( krConfig->readBoolEntry("Move To Trash",_MoveToTrash) ) {
	  KURL::List* filesUrls = vfs_getFiles(fileNames); // extract
	  changed = true;
	
	  KIO::Job *job = new KIO::CopyJob(*filesUrls,KGlobalSettings::trashPath(),KIO::CopyJob::Move,false,true );
	  connect(job,TQT_SIGNAL(result(KIO::Job*)),this,TQT_SLOT(vfs_refresh(KIO::Job*)));
	}
	// else we have to delete the files from both the archive and the temp dir
	else {
	  // change dir to the temp dir
    TQString save = getcwd(0,0);
    chdir(tmpDir.local8Bit());

    TQStringList files;
    KIO::filesize_t totalSizeVal = 0;
    unsigned long totalFilesVal =  0;
    	
	  // names -> urls
    for(TQStringList::Iterator name = fileNames->begin(); name != fileNames->end(); ++name )
      processName(*name,&files,&totalSizeVal,&totalFilesVal);


		KShellProcess proc1 , proc2;
		krApp->startWaiting(i18n("Deleting Files..."),files.count()+ignoreLines);
	  connect(&proc1,TQT_SIGNAL(receivedStdout(KProcess*,char*,int)),
            krApp, TQT_SLOT(incProgress(KProcess*,char*,int)) );

    proc1 <<  delCmd << "\""+arcFile+"\"";
    proc2 << "rm -rf";
    for(unsigned int i =0; i < files.count(); ){
      proc1 << (prefix+*files.at(i));
      proc2 << tmpDir+"/"+(*files.at(i));
			extFiles.remove(*files.at(i++));
			if ( i%MAX_FILES==0 || i==files.count() ){
				proc1.start(KProcess::NotifyOnExit,KProcess::AllOutput);
    		proc2.start();
        while( proc1.isRunning() || proc2.isRunning() ) tqApp->processEvents(); // busy wait - need to find something better...
        proc1.clearArguments() ; proc2.clearArguments();
				proc1 <<  delCmd << "\""+arcFile+"\"";
    		proc2 << "rm -rf";
			}
    }
	  krApp->stopWait();

	  changed = true;
	  chdir (save.local8Bit());
	  vfs_refresh(vfs_origin);
  }
}	

// return a path to the file
TQString arc_vfs::vfs_getFile(TQString name){
  // get the current file path
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  if(path.left(1)=="/") path.remove(0,1);
  if(path != "") path = path+"/";

  TQStringList temp(name);
  vfs_getFiles(&temp);

  return tmpDir+"/"+path+name;
}

KURL::List* arc_vfs::vfs_getFiles(TQStringList* names){
  KURL url;
  KURL::List* urls = new KURL::List();

  // get the current file path
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  if(path.left(1)=="/") path.remove(0,1);
  if(path != "") path = path+"/";

  // change dir to the temp dir
  TQString save = getcwd(0,0);
	chdir(tmpDir.local8Bit());
	// names -> urls
  TQStringList files;
  KIO::filesize_t totalSize = 0;
  unsigned long totalFiles = 0;
  for(TQStringList::Iterator name = names->begin(); name != names->end(); ++name ){
    processName(*name,&files,&totalSize,&totalFiles);
    url.setPath(tmpDir+"/"+path+(*name));
    urls->append(url);
  }
  // check the urls for unpacked files and directories
	for(TQStringList::Iterator file = files.begin(); file != files.end(); ++file ){
  	if ( (*file).right(1)=="/" ){
			TQDir(tmpDir).mkdir(*file);
      if( vfs_type == "-rar" ) file = files.remove(file--);
		}
		// don't unpack the same file twice
		else if( extFiles.contains(*file) ){
      file = files.remove(file--);
		}
  }
  // unpack ( if needed )
	if ( files.count() > 0 ){
		krApp->startWaiting(i18n("Unpacking Files"),files.count()+ignoreLines);
    KShellProcess proc;
	  connect(&proc,TQT_SIGNAL(receivedStdout(KProcess*,char*,int)),
            krApp, TQT_SLOT(incProgress(KProcess*,char*,int)) );
		
		proc << cmd << getCmd << "\""+arcFile+"\"";
  	if( vfs_type == "gzip" || vfs_type == "zip2" ) proc << ">";
		for(unsigned int i=0 ; i < files.count() ; ){
  		proc << (prefix+*files.at(i++));
			if ( i%MAX_FILES==0 || i==files.count() ){
				proc.start(KProcess::NotifyOnExit,KProcess::AllOutput);
        while( proc.isRunning() ) tqApp->processEvents();
				proc.clearArguments();
				proc << cmd << getCmd << "\""+arcFile+"\"";
  		}
		}
    getExtFiles(); // this will update the extFiles list.
		krApp->stopWait();
	}
  // restore dir
	chdir(save.local8Bit());
	
  return urls;
}

// make dir
void arc_vfs::vfs_mkdir(TQString name){
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  if(path.left(1)=="/") path.remove(0,1);
  if(path != "") path = path+"/";

  TQDir(tmpDir).mkdir(path+name);
  changed = true; //rescan the archive
  vfs_refresh(vfs_origin);
}
	
// rename file
void arc_vfs::vfs_rename(TQString fileName,TQString newName){
	KURL::List temp;
	temp.append(vfs_getFile(fileName));
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  if(path.left(1)=="/") path.remove(0,1);
  if(path != "") path = path+"/";

  TQDir(tmpDir).mkdir(path);
  changed = true; //rescan the archive

	KURL dest;
	dest.setPath(tmpDir+path+"/"+newName);

  KIO::Job* job = new KIO::CopyJob(temp,dest,KIO::CopyJob::Move,false,false);
  connect(job,TQT_SIGNAL(result(KIO::Job*)),this,TQT_SLOT(vfs_refresh(KIO::Job*)) );
}

bool arc_vfs::vfs_refresh(TQString origin){
	if ( error ) return false;
	
  if ( changed || origin == vfs_origin ){
		repack(); // repack dirs only if needed
		if ( !getDirs() ){
			if (!quietMode) emit startUpdate();
    	return true;
		}
		changed = false;
	}

  vfs_origin = origin;
  // get the directory...
  TQString path = origin.right((origin.length()-origin.findRev('\\'))-1);
  if(path.left(1) =="/") path.remove(0,1);

  vfs_filesP = findDir(path);

  if (!quietMode) emit startUpdate();
  return true;
}

// service functions
TQString arc_vfs::nextWord(TQString &s,char d) {
  s=s.stripWhiteSpace();
  int j=s.find(d,0);
  TQString temp=s.left(j); // find the leftmost word.
  s.remove(0,j);
  return temp;
}

void arc_vfs::getFilesToPack(TQStringList* filesToPack,TQString dir_name){
  bool newDir = false;
  vfileDict *vfs_filesP_backup = vfs_filesP; // save vfs_filesP

  // init all the diffrent lists (and list pointers);
  vfs_filesP=findDir(dir_name);
  if ( vfs_filesP == 0) newDir = true;
  if(dir_name != "") dir_name = dir_name+"/";

 	register DIR* dir = opendir(tmpDir.local8Bit()+"/"+dir_name.local8Bit());
  if(!dir) return ;

	register struct dirent* dirEnt;
  TQString name;
	KDE_struct_stat stat_p;
	while( (dirEnt=readdir(dir)) != NULL ){
    name = dirEnt->d_name;
		if ( name == ".." || name == "." ) continue;
	  if( KDE_lstat(tmpDir.local8Bit()+"/"+dir_name.local8Bit()+name.local8Bit(),&stat_p) ) continue;
	  extFile temp(dir_name+name,stat_p.st_mtime,stat_p.st_size);
		// add to the list file that are diffrent than the ones packed
    if( S_ISDIR(stat_p.st_mode) ){ // recurse on all sub dirs
      if( !findDir(dir_name+name) ){
      	// add to the list only new && empty dirs
				if( newDir && TQDir(dir_name+name).entryList(TQDir::All | TQDir::AccessMask).count() <= 2 )
					filesToPack->append( dir_name+name);
      }
			getFilesToPack(filesToPack,dir_name+name);
			continue;
		}

		// if the file don't exist add it to the archive and to the extFiles
    if( newDir || !extFiles.contains( dir_name+name ) ){
    	filesToPack->append( dir_name+name );
			extFiles.append( temp );
    } // else if the file exist but was modified - repack it;
    else if( !extFiles.contains( temp ) ){
			filesToPack->append( dir_name+name );
			extFiles.remove( dir_name+name );
			extFiles.append( temp );
    }
  }
  vfs_filesP = vfs_filesP_backup; // restore  vfs_filesP
}

void arc_vfs::getFilesToDelete(TQStringList* filesToDelete,TQString){
	// sync the extFiles - and find out which files were deleted
	TQString file;
	for(unsigned int i=0 ; i<extFiles.count(); ){
		file = tmpDir+"/"+(*extFiles.at(i)).url;
		if( !KRpermHandler::fileExist(file) ){
  		filesToDelete->append( (*extFiles.at(i)).url );
    	extFiles.remove(extFiles.at(i));
   	}
		else ++i;
  }
}

void arc_vfs::getExtFiles(TQString dir_name){
	register DIR* dir = opendir(tmpDir.local8Bit()+"/"+dir_name.local8Bit());
  if(!dir){
    kdWarning() << "faild to opendir(): " << tmpDir.local8Bit()+"/"+dir_name.local8Bit() << endl;
		return ;
	}

	if( dir_name != "") dir_name = dir_name+"/";
	
	register struct dirent* dirEnt;
  TQString name;
	KDE_struct_stat stat_p;
	while( (dirEnt=readdir(dir)) != NULL ){
    name = dirEnt->d_name;
		if ( name == ".." || name == "." ) continue;
	  if( KDE_lstat(tmpDir.local8Bit()+"/"+dir_name.local8Bit()+name.local8Bit(),&stat_p) ) continue;
	  extFile temp(dir_name+name,stat_p.st_mtime,stat_p.st_size);
		// recurse on all sub dirs
    if( S_ISDIR(stat_p.st_mode) ){
      getExtFiles(dir_name+name);
		}
    // if the file is not in extFiles - it is newly extracted.
    // note: getFilesToPack() updates time + size !
		else if( !extFiles.contains( dir_name+name ) ){
			extFiles.append( temp );
    }
  }	
}

void arc_vfs::repack(){
  TQString save = getcwd(0,0);
  chdir(tmpDir.local8Bit());
	
  // delete from the archive files that were unpacked and deleted
	if( vfs_isWritable() ){
		TQStringList filesToDelete;
		getFilesToDelete(&filesToDelete);
		if( !filesToDelete.isEmpty() ){
			KShellProcess delProc;
  		krApp->startWaiting(i18n("Deleting Files..."),filesToDelete.count()+ignoreLines);
	 		connect(&delProc,TQT_SIGNAL(receivedStdout(KProcess*,char*,int)),
               krApp, TQT_SLOT(incProgress(KProcess*,char*,int)) );

			delProc << delCmd << "\""+arcFile+"\"";
			for( unsigned int i=0 ; i < filesToDelete.count() ;){
				delProc << (*filesToDelete.at(i++));
				if( i%MAX_FILES==0 || i==filesToDelete.count() ){
  	  		delProc.start(KProcess::NotifyOnExit,KProcess::AllOutput);
    			while( delProc.isRunning() )  tqApp->processEvents();
					delProc.clearArguments();
		    	delProc << delCmd << "\""+arcFile+"\"";
  			}
			}
  		krApp->stopWait();
		}
	}

  // finaly repack tmpDir
  if( vfs_isWritable() || vfs_type=="gzip" || vfs_type=="zip2" ){
    TQStringList filesToPack;
		getFilesToPack(&filesToPack);
		if( !filesToPack.isEmpty() ){
			KShellProcess addProc;
			krApp->startWaiting(i18n("Repacking..."),filesToPack.count()+ignoreLines);
    	connect(&addProc,TQT_SIGNAL(receivedStdout(KProcess*,char*,int)),
            krApp, TQT_SLOT(incProgress(KProcess*,char*,int)) );

			if( vfs_type=="gzip" || vfs_type=="zip2" ){
      	addProc << addCmd << *filesToPack.at(0)<< ">" << "\""+arcFile+"\"";
				addProc.start(KProcess::NotifyOnExit);
      	while( addProc.isRunning() ) tqApp->processEvents();
     	}
    	else {
				addProc << addCmd << "\""+arcFile+"\"";
    		for( unsigned int i=0 ; i<filesToPack.count(); ){
      		addProc << "\""+prefix+(*filesToPack.at(i++))+"\"";
					if( i%MAX_FILES==0 || i==filesToPack.count() ){
      			addProc.start(KProcess::NotifyOnExit,KProcess::AllOutput);
      			while( addProc.isRunning() ) tqApp->processEvents(); // busy wait - need to find something better...
        		addProc.clearArguments();
		    		addProc << addCmd << "\""+arcFile+"\"";
					}
    		}
			}
			krApp->stopWait();
		}
 	}
  chdir(save.local8Bit());
}

vfileDict* arc_vfs::findDir(TQString name){
  for(arc_dir* temp = dirList.first();temp != 0 ; temp = dirList.next()){
    if(temp->name == name) return &(temp->entries);
  }
  return 0;
}

arc_vfs::arc_dir* arc_vfs::findArcDir(TQString name){
for(arc_dir* temp = dirList.first();temp != 0 ; temp = dirList.next()){
    if(temp->name == name) return temp;
  }
  return 0;
}

TQString arc_vfs::changeDir(TQString name){
  if(name.left(2) == "./") {
    prefix = "./";
    name.remove(0,2);
  }

  if(!name.contains('/')){
    vfs_filesP = findDir("");
    return name;
  }
  // seperate the path from the name
  TQString path = name.left(name.findRev('/'));
  name = name.mid(name.findRev('/')+1);
  // see if the path exists
  if ((vfs_filesP=findDir(path)) == 0){
   //create a new dir entry
   TQString Pname = path.mid(path.findRev('/')+1);
   if(Pname.isEmpty()) return name;
   TQString tempName = arcFile;
   TQFileInfo qfi(tempName.replace(TQRegExp("\\"),""));
   vfile* vf=new vfile(Pname,0,"drwxr-xr-x",qfi.lastModified().toTime_t(),false,
                 qfi.owner(),qfi.group(),"inode/directory","",0 );
   // add  dirs if needed
   changeDir(path);

   vfile* vf2 = vfs_search(Pname);
   if(vf2 != 0) vfs_removeFromList(vf2);
   vfs_addToList(vf);

   // add a new arc_dir
   dirList.append(new arc_dir(path));
   vfs_filesP = findDir(path);
  }
  return name;
}

// calculate space
void arc_vfs::vfs_calcSpace(TQString name ,KIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs,bool* stop){
  if ( *stop ) return;
  vfile* vf = vfs_search(name);

  // get the path inside the archive
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  path = path+"/";
  if(path.left(1) == "/") path.remove(0,1);

  if( !vf->vfile_isDir() ){ // single files are simple :)
    ++(*totalFiles);
    (*totalSize) += vf->vfile_getSize();
  }
  else { // handle directories : (
    ++(*totalDirs);

    TQString origin_backup = vfs_origin; // backup the vfs origin
    vfs_origin = vfs_origin+"/"+name;
    vfileDict* vfs_filesP_backup = vfs_filesP; // backup the vfs_filesP
    vfs_filesP = findDir(path+name);

    // process all the files in the directory.
    for( vf = vfs_getFirstFile(); vf != 0; vf = vfs_getNextFile() ){
      if (*stop) return;
      vfs_calcSpace(vf->vfile_getName(),totalSize,totalFiles,totalDirs,stop);
    }

    vfs_origin = origin_backup;     // restore origin
    vfs_filesP = vfs_filesP_backup; // restore vfs_filesP
  }
}

void arc_vfs::processName(const TQString& name, TQStringList *urls,KIO::filesize_t *totalSize,unsigned long *totalFiles ){
  vfile* vf = vfs_search(name);
	if ( vf == 0 ) return;

  // get the path inside the archive
  TQString path = vfs_origin.right((vfs_origin.length()-vfs_origin.findRev('\\'))-1);
  path = path+"/";
  if(path.left(1) == "/") path.remove(0,1);

  if( !vf->vfile_isDir() || vf->vfile_isSymLink() ){ // single files are simple :)
    ++(*totalFiles);
    (*totalSize) += vf->vfile_getSize();
    urls->append(path+name);
  } else { // handle directories : (
    urls->append(path+name+"/");
    TQString origin_backup = vfs_origin; // backup the vfs origin
    vfs_origin = vfs_origin+"/"+name;
    vfileDict* vfs_filesP_backup = vfs_filesP; // backup the vfs_filesP
    vfs_filesP = findDir(path+name);

    // process all the files in the directory.
    for( vf = vfs_getFirstFile(); vf != 0; vf = vfs_getNextFile() )
      processName(vf->vfile_getName(),urls,totalSize,totalFiles);

    vfs_origin = origin_backup;     // restore origin
    vfs_filesP = vfs_filesP_backup; // restore vfs_filesP
  }
}

void arc_vfs::parseLine(TQString line, TQFile* temp){
  TQString name;
  KIO::filesize_t size = 0;
  TQString perm;
  TQFileInfo qfi(arcFile);
  time_t mtime = qfi.lastModified().toTime_t();
  bool link = false;
  uid_t owner = getuid();
  gid_t group = getgid();
  TQString dest = "";
  mode_t mode = 0;


  // parse gziped files
  if(vfs_type == "gzip"){
    KDE_struct_stat stat_p;
    KDE_stat(arcFile.local8Bit(),&stat_p);

    nextWord(line);
    size = nextWord(line).toLong();
    nextWord(line);
    name = nextWord(line,'\n');
    if(name.contains('/')) name = name.mid(name.findRev('/')+1,name.length());
    perm  = KRpermHandler::mode2TQString(stat_p.st_mode) ;
    owner = KRpermHandler::user2uid(qfi.owner());
    group = KRpermHandler::group2gid(qfi.group());
    mode  = stat_p.st_mode;
  }

  // parse bzip2ed files
  if( vfs_type == "zip2" ){
    KDE_struct_stat stat_p;
    KDE_stat(arcFile.local8Bit(),&stat_p);

    name = qfi.fileName();
    name = name.left(name.findRev('.'));
    //long size = qfi.size();
    perm  = KRpermHandler::mode2TQString(stat_p.st_mode) ;
    owner = KRpermHandler::user2uid(qfi.owner());
    group = KRpermHandler::group2gid(qfi.group());
    mode  = stat_p.st_mode;
  }

  // parse tar files
  if(vfs_type == "-tar" || vfs_type == "-tbz" || vfs_type == "-tgz" ){
    perm = nextWord(line);
    TQString temp = nextWord(line);
    owner = temp.left(temp.findRev('/')).toInt();
    group = temp.mid(temp.find('/')+1,temp.length()).toInt();
    size = nextWord(line).toLong();
    temp = nextWord(line);
    name = nextWord(line,'\n');
    if (name.startsWith("/"))  // fix full-paths problem in tar (thanks to Heiner!)
      name.remove(0, 1);
    if( name.contains(" -> ") ){
      link = true;
			dest = name.mid(name.find(" -> ")+4);
			name = name.left(name.find(" -> "));
    }
  }

  // parse zipped files
  if(vfs_type == "-zip"){
    perm = nextWord(line);
    if(perm.length() != 10)
      perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ;
    if (nextWord(line).contains("file")) return;
    nextWord(line);
    size = nextWord(line).toLong();
    nextWord(line);nextWord(line);
    TQString temp = nextWord(line);
    name = nextWord(line,'\n');
  }

  // parse cpio packages
  if(vfs_type == "cpio" || vfs_type == "+rpm"){
		perm = nextWord(line);
    nextWord(line);nextWord(line);nextWord(line);
		size = nextWord(line).toLong();
		nextWord(line);nextWord(line);nextWord(line);
		TQString tempName = arcFile;
    TQFileInfo qfi(tempName.replace(TQRegExp("\\"),""));
		name = nextWord(line,'\n');
    if ( name.left(1) == "/" ) name.remove(0,1);
    if( name.contains(" -> ") ){
      link = true;
      dest = name.mid(name.find(" -> ")+4);
			name = name.left(name.find(" -> "));
    }
  }
  // parse rared files
  if(vfs_type == "-rar"){
    name = nextWord(line,'\n');
    temp->readLine(line,10000);
    size = nextWord(line).toLong();
    nextWord(line);
    nextWord(line);
    perm = nextWord(line);
    if(perm.length() != 10)
      perm = (perm.at(1)=='D')? "drwxr-xr-x" : "-rw-r--r--" ;
  }
  // parse rpm packages
  if(vfs_type == "-rpm"){
		name = nextWord(line);
    if ( name.left(1) == "/" ) name.remove(0,1);
    size = nextWord(line).toLong();
    mtime = nextWord(line).toLong();
    nextWord(line);
    perm = KRpermHandler::mode2TQString(nextWord(line).toLong());
    perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ;
  }

  if ( perm[0]=='d'  && name.right(1) != "/" )  name = name+"/";
  name = changeDir(name);
  if(name.length() < 1) return;


  TQString mime = KMimeType::findByURL( "/"+name,0,true,true)->name();
  vfile* vf=new vfile(name,size,perm,mtime,link,owner,group,mime,dest,mode);
  vfile* vf2 = vfs_search(name);
  if(vf2 != 0) vfs_removeFromList(vf2);
  vfs_addToList(vf);
}

#include "arc_vfs.moc"
