//Diops.cpp
//Last updated 15.12.03

#include "dirops.h"

#include <cdio/cdio.h>
#include <cdio/iso9660.h>
#include <dirent.h>

#include <qlistview.h>

#include <kapp.h>
#include <kprocess.h>
#include <kprogress.h>
#include <kiconloader.h>
#include <ksimpleconfig.h>
#include <kdirsize.h>

QListViewItem* item;
const char *Filefilter;
bool HiddenFiles;

void createsymtree(const char *source,const char *dest)
{
	DIR *dp;
	struct dirent *entry;
	struct stat fstat;
        QString path;
        QString path2;

	mkdir(dest,7*64+5*8);
	dp = opendir(source);

	for (entry = readdir(dp);entry != NULL;entry = readdir(dp))
        if (QString(entry->d_name) != "." && QString(entry->d_name) != "..")
        {
                path = source;
                path=path + "/";
                path2 = dest;
                path2=path2 + "/";
                path=path + entry->d_name;
                path2=path2 + entry->d_name;
		stat(path,&fstat);

		if (S_ISDIR(fstat.st_mode)) {
                        path=path + "/";
                        path2=path2 + "/";
			createsymtree(path,path2);
		} else symlink(path,path2);
	};

	closedir(dp);
}

void GetDirView (QListView* Object, QDir directory, const char* filter,
bool visible)
{
 HiddenFiles=visible;
 Object->clear();

  directory.setMatchAllDirs ( true );
        directory.setNameFilter ( filter );
        if (HiddenFiles) directory.setFilter( QDir::Files | QDir::Hidden | QDir::Dirs );
        else
        directory.setFilter( QDir::Files | QDir::Dirs );

        const QFileInfoList *list = directory.entryInfoList();
        QFileInfoListIterator it( *list );
        if (directory.isRoot()) it+=1;
        it+=1;
        QFileInfo *fi;

        while ( (fi = it.current()) != 0 ) {
            QString fileSize;
            if (!fi->isDir()) fileSize = QString::number(fi->size()) + " Bytes";
            QString LastMod = fi->lastModified().toString("dd.MM.yyyy  hh:mm");
          item = new QListViewItem (Object, fi->fileName() ,fileSize, LastMod);
           QPixmap Picture = FileIcon( fi );
            item->setPixmap( 0, Picture );
              if (fi->isDir() && fi->isReadable())item->setExpandable(true); 
            ++it;
        }  
}

QPixmap FileIcon (QFileInfo* File)
{
QString ending = File->extension( FALSE ).lower();
  KIconLoader *loader = KGlobal::iconLoader();
  if (File->isDir() ){
     if ( File->fileName() == "..")
     return loader->loadIcon("up", KIcon::Small);
     if ( File->isReadable() )
     return loader->loadIcon("folder", KIcon::Small);
     else
     return loader->loadIcon("folder_locked", KIcon::Small);
    }
    if (!File->isDir() && !File->isReadable())
      return loader->loadIcon("file_locked", KIcon::Small);
    if ( ending=="exe" )
      return loader->loadIcon("exec_wine", KIcon::Small);
    if ( ending=="bat" || ending=="sh" || ending=="run" )
      return loader->loadIcon("shellscript", KIcon::Small);
    if ( ending=="doc" || ending=="kwd" )
      return loader->loadIcon("wordprocessing", KIcon::Small);
    if ( ending=="txt" || ending=="pdf" || ending=="rpm" || ending=="deb" || ending=="log" )
      return loader->loadIcon(ending, KIcon::Small);
    if ( ending=="bmp" || ending =="jpeg" || ending=="jpg" || ending=="pcx" || ending=="png" || ending=="gif" || ending=="mng" )
      return loader->loadIcon("image", KIcon::Small);
    if ( ending=="avi" || ending=="mpg" || ending=="mpeg" || ending=="wmv")
      return loader->loadIcon("video", KIcon::Small);
    if ( ending=="mp3" || ending=="au" || ending=="vob" || ending=="ogg" || ending=="mod" || ending=="wav" )
      return loader->loadIcon("sound", KIcon::Small);
    if ( ending=="mid" )
      return loader->loadIcon("midi", KIcon::Small);
    if ( ending=="cab" || ending=="tar" || ending=="gz" || ending=="bz" || ending=="zip" || ending=="lha" || ending=="bz2" || ending=="ace" || ending=="rar" || ending=="tgz" || ending==".7z")
      return loader->loadIcon("tar", KIcon::Small);
    if ( ending=="htm" || ending=="html" || ending=="xml" )
      return loader->loadIcon("html", KIcon::Small);
    if ( ending=="iso" || ending=="cue" || ending=="nrg" || ending=="img" || ending=="ccd")
      return loader->loadIcon("cdimage", KIcon::Small);
    if ( ending=="rom" )
      return loader->loadIcon("memory", KIcon::Small);
    if ( ending=="jar" || ending=="cpp" || ending=="h" || ending=="c" || ending=="pl" || ending=="php" || ending=="py" );
      return loader->loadIcon("source_" + ending, KIcon::Small);
    if ( ending=="tmp" )
      return loader->loadIcon("file_temporary", KIcon::Small);
    if ( ending=="ram" )
      return loader->loadIcon("real_doc", KIcon::Small);
    if ( ending=="ksp" || ending=="xls" )
      return loader->loadIcon("spreadsheet", KIcon::Small);
    if ( ending=="ui" )
      return loader->loadIcon("widget_doc", KIcon::Small);
    else
    return loader->loadIcon("unknown", KIcon::Small);
}

void changedirectory(QListView* Object, QString directory , QString path )
{  
  QDir Dirnew;
  Dirnew.setPath (directory + "/" + path);
 if (Dirnew.isReadable()){
 QDir::setCurrent( Dirnew.path() );
 GetDirView (Object, QDir::current(), Filefilter, HiddenFiles);
 }
}

//Find the mountpoint of a given device in the /etc/fstab.

QStringList getDeviceList()
{
   QStringList theList;

   QFile file( "/etc/fstab" );
   if ( file.open( IO_ReadOnly ) )
   {
     QTextStream theStream( &file );
     QString theLine;
     while ( !theStream.atEnd() )
     {
       theLine = theStream.readLine().stripWhiteSpace();

       if( !theLine.startsWith("#") )
       {
         uint16_t count = theLine.find(" ");
         QString _device = theLine.left(count);

         if( _device.contains("/dev/cdrom") || _device.contains("/dev/dvd") || _device.contains("/dev/cdrecorder") || _device.contains("/dev/dvdrecorder") )
         {
           theList.append(_device);
         }
       }
     }
   }
   file.close();

   return theList;
}

void Linkfiles(QDir Directory, QDir Dest, bool Createself)
{
  QString Dst = Dest.path();
  if (Createself)
  {
    Dest.mkdir( Directory.dirName() );
    Dst += "/" + Directory.dirName();
  }
  createsymtree(Directory.path(),Dst);
}

void Convert(QString Selected, KProgress* kProgress1)
{
 if (QFileInfo(Selected).extension().lower()=="bin" || QFileInfo(Selected).extension().lower()=="nrg" || QFileInfo(Selected).extension().lower()=="mdf" || QFileInfo(Selected).extension().lower()=="cdi" || QFileInfo(Selected).extension().lower()=="img" || QFileInfo(Selected).extension().lower()=="c2d")
{
 uint16_t   ecc=0, sector=0, header=0, size=2048;
 long  indx=0;
 char buffer[2448];
 int dump = 0;
Progressform *Progconvert = new Progressform(0);
if (kProgress1==0)
{
Progconvert->show();
kProgress1=Progconvert->ShellProgress;
}
QString Destinationfile = Selected.left(Selected.length()-3) + "iso";
QFile destfile (Destinationfile);
    QFile sourcefile (Selected);
    sourcefile.open( IO_ReadOnly );
    if (!destfile.open( IO_WriteOnly ))
    {
    destfile.setName (QDir::homeDirPath() + "/" + QFileInfo(Selected).baseName() + ".iso");
    destfile.open( IO_WriteOnly );
    }
    long length = sourcefile.size() / size;
    if (QFileInfo(Selected).extension().lower()=="bin"){    
//This code was inspired by the project Bin2Iso.
    const char Syn_Header[12] = { 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 };
    sourcefile.readBlock ( buffer, 16 );
    if (memcmp(Syn_Header, buffer, 12))
    {
      header = 8;
      ecc = 280;
      sector = 2336;
    }
      else
    {
    switch(buffer[15])
     {
     case 2:
    header = 24;
    ecc = 280;
    sector = 2352;
    break; 
     case 1:
    header = 16;
    ecc = 288;
    sector = 2352;
    break;
  }
 }
  length = sourcefile.size() / sector;
  sourcefile.at(0L);
  }
  
 if (QFileInfo(Selected).extension().lower()=="nrg") indx=150; 
 if (QFileInfo(Selected).extension().lower()=="mdf"){
// This code was inspired by the project mdf2iso for windows.
 const char SYNC_HEADER[12] = { 0x80, 0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, 0x80, 0x80, 0x80, 0x80 };
 sourcefile.at(sourcefile.at() + 2352);
 sourcefile.readBlock ( buffer, 16 );
 if (!memcmp(SYNC_HEADER, buffer, 12))
  {
  ecc = 384;
  }
  else
  {         
  ecc = 288;
  }
 sourcefile.at(0L);
 }     
  
   if (QFileInfo(Selected).extension().lower()=="cdi"){
// This code was inspired by the project cdi2iso for windows.
   const char SYNC_HEADER[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
   sourcefile.readBlock ( buffer, 16 );
   if (!memcmp(SYNC_HEADER, buffer, 12))
  {
   header = 16;
   sourcefile.at(0L);
   sourcefile.at(sourcefile.at() + 2352);
   sourcefile.readBlock ( buffer, 16 );
   if (!memcmp(SYNC_HEADER, buffer, 12))
  {  
   ecc = 288;
  }
   else
  {
   sourcefile.at(0L);
   sourcefile.at(sourcefile.at() + 2368);
   sourcefile.readBlock ( buffer, 16 );   
   if (!memcmp(SYNC_HEADER, buffer, 12))
   {
   ecc = 304;
   }
    else
   {
    ecc = 384;
   }
    }
   } 
    else
   {
    header = 0;
    ecc = 0;
    }
   sourcefile.at(0L);
   }
   if (QFileInfo(Selected).extension().lower()=="img"){
   const char HEADER[16] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x01};
   sourcefile.readBlock ( buffer, 16 );
   if (!memcmp(HEADER, buffer, 16))
   {
   header = 0;
   ecc = 288;
   }
   else
   {
   header = 8;
   ecc = 280;
   }
   sourcefile.at(0L);
   }
   if (QFileInfo(Selected).extension().lower()=="c2d"){
   const char HEADER[12] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
   dump = 131072;
   sourcefile.at(0L);
   sourcefile.at(sourcefile.at() + dump);
   sourcefile.readBlock ( buffer, 12 );
   if (!memcmp(HEADER, buffer, 12))
   {
   header = 24;
   ecc = 654;
   }
   else
   {
   header = 0;
   ecc = 0;
   }
   sourcefile.at(0L);
   sourcefile.at(sourcefile.at() + dump);
   }
    while(indx < length )
   {
   if (QFileInfo(Selected).extension().lower()=="cdi" || QFileInfo(Selected).extension().lower()=="bin" || QFileInfo(Selected).extension().lower()=="c2d") sourcefile.at(sourcefile.at() + header);
   if (QFileInfo(Selected).extension().lower()=="mdf") sourcefile.at(sourcefile.at() + 16);
   if (QFileInfo(Selected).extension().lower()=="nrg" && indx==150) sourcefile.at(sourcefile.at() + indx*size);
   if (QFileInfo(Selected).extension().lower()=="img") sourcefile.at(sourcefile.at() + 16 + header);
   sourcefile.readBlock ( buffer, size );
   if (indx >149 && (QFileInfo(Selected).extension().lower()=="cdi"))
   {
   if (length != indx ) destfile.writeBlock ( buffer, size );
   else
   destfile.writeBlock ( buffer, 1559 );
   }
   if (QFileInfo(Selected).extension().lower()!="cdi") destfile.writeBlock ( buffer, size );
   if (QFileInfo(Selected).extension().lower()!="nrg" || QFileInfo(Selected).extension().lower()!="img"|| QFileInfo(Selected).extension().lower()!="c2d") sourcefile.at(sourcefile.at() + ecc);
   if (kProgress1!=0)
   {
   kProgress1->setProgress( (uint8_t)((float)indx/length*100) );
   kapp->processEvents ();
   }
   indx++;
   }  
      destfile.close();
      sourcefile.close();
   if (kProgress1==Progconvert->ShellProgress) Progconvert->hide();
}
}

void openhex(QString File)
{
KSimpleConfig conf("kisorc");
conf.setGroup("Preferences");
KShellProcess *hexstart = new KShellProcess();
File = PrepforShell(File);
if ( conf.readEntry("Hexeditor", 0)=="KHexEdit" )(*hexstart)<< "khexedit" << File;
if ( conf.readEntry("Hexeditor", 0)=="GHex2" )(*hexstart)<< "ghex2" << File;
hexstart->start();
}

QString readoutheader(QString Selected, QString Type)
{
 iso9660_t           *p_iso=NULL;
 p_iso = iso9660_open (Selected);
 char *psz_str = NULL;
 if (Type == "format" && cdio_is_nrg(Selected)) return "NRG";
 if (Type == "format" && cdio_is_binfile(Selected) || cdio_is_cuefile(Selected)) return "BIN/CUE";
 if (Type == "format" && QFileInfo(Selected).extension()=="iso") return "ISO";
 if (Type == "label") iso9660_ifs_get_volume_id(p_iso, &psz_str);
 if (Type == "system") iso9660_ifs_get_system_id(p_iso, &psz_str);
 if (Type == "publish") iso9660_ifs_get_publisher_id(p_iso, &psz_str);
 if (Type == "prepar") iso9660_ifs_get_preparer_id(p_iso, &psz_str);
 if (Type == "application") iso9660_ifs_get_application_id(p_iso, &psz_str);
 return psz_str;
}

void MountISO(QString Selected, uint8_t imagenumber)
{
 QString Mountnumber=QString::number(imagenumber);
 QString SelectedSh = PrepforShell(Selected);
  if (!imagenumber) Mountnumber="";
KShellProcess *unmount = new KShellProcess();
    (*unmount)<< "sudo" << "/bin/umount" << QDir::homeDirPath() + "/.kisotmp/Mount" + Mountnumber;
    unmount->start(KShellProcess::Block, KShellProcess::Stderr);
    KShellProcess *mount = new KShellProcess();
    if (QFileInfo(Selected).extension( false ).lower()=="iso")
    (*mount)<< "sudo" << "/bin/mount" << "-o" << "loop" << "-t" << "iso9660" << SelectedSh << QDir::homeDirPath() + "/.kisotmp/Mount" + Mountnumber;
    if (QFileInfo(Selected).extension( false ).lower()=="nrg")
    (*mount)<< "sudo" << "/bin/mount" << "-o" << "loop,offset=307200" << "-t" << "iso9660" << SelectedSh << QDir::homeDirPath() + "/.kisotmp/Mount" + Mountnumber;
    mount->start(KShellProcess::Block);

if (!imagenumber)
    {
    KShellProcess *rm = new KShellProcess();
    (*rm)<< "rm" << "-R" << QDir::homeDirPath() + "/.kisotmp/ISO/*";
    rm->start(KShellProcess::Block, KShellProcess::Stderr);
    }
    QDir addi (QDir::homeDirPath() + "/.kisotmp/Mount" + Mountnumber);
    Linkfiles(addi, QDir::homeDirPath() + "/.kisotmp/ISO", false);
    QDir Iso (QDir::homeDirPath() + "/.kisotmp/ISO");
    QDir::setCurrent(Iso.path());
}

void CreateISO(QString Selected)
{
double sourcesize;
double targetsize;
QString DName = PrepforShell(QDir(Selected).dirName());
QString SelectedSH = PrepforShell(Selected);
sourcesize = KDirSize::dirSize (Selected);
Progressform *Progcreate = new Progressform(0);
Progcreate->show();
KShellProcess *createiso = new KShellProcess();
  (*createiso)<< "mkisofs" << "-joliet" << "-rock" << "-quiet" << "-f" << "-A" << "KIso" << "-J" << "-V" <<  DName << "-l" << "-o" << DName + ".iso" << Selected;
  createiso->start();
  while (createiso->isRunning()){
  QFileInfo targetfile (QDir::current().path() + "/" + QDir(Selected).dirName() + ".iso");
  targetsize = targetfile.size();
  uint8_t progress = (uint8_t)(( targetsize / sourcesize) * 100);
  if (progress>100) progress=100;
  Progcreate->ShellProgress->setProgress( (progress) );
  kapp->processEvents ();
  }
Progcreate->hide();
}

bool FindEncryption (QString Selected)
{
 QFile sourcefile (Selected);
 sourcefile.open( IO_ReadOnly );
 char buffer[17];
 sourcefile.readBlock (buffer, 16);
 buffer[17]='\n';
 QString Identify=&buffer[2];
 sourcefile.close();
 if (Identify.contains("rijndael-128",FALSE))
 return true;
 else
 return false;
}

QString PrepforShell (QString Selected)
{
 if (!Selected) Selected = " ";
 Selected.replace(" ", "\\ ");
 Selected.replace("~", "\\~");
 Selected.replace("%", "\\%");
 Selected.replace("|", "\\|");
 Selected.replace("'", "\\'");
 Selected.replace("&", "\\&");
 Selected.replace(";", "\\;");
 Selected.replace("?", "\\?");
 Selected.replace("!", "\\!");
 Selected.replace("*", "\\*");
 Selected.replace("[", "\\[");
 Selected.replace("]", "\\]");
 Selected.replace("{", "\\{");
 Selected.replace("}", "\\}");
 Selected.replace("(", "\\(");
 Selected.replace(")", "\\)");
 Selected.replace("<", "\\<");
 Selected.replace(">", "\\>");
 return Selected;
}

Progressform::Progressform(QWidget* parent, const char* name)
      :KDialog( parent, name )
{
setName( "Progressform" );
setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)5, 0, 0, sizePolicy().hasHeightForWidth() ) );
    setMinimumSize( QSize( 290, 25 ) );
    setMaximumSize( QSize( 290, 25 ) );
    setModal( TRUE );

    ShellProgress = new KProgress( this, "ShellProgress" );
    ShellProgress->setGeometry( QRect( 10, 7, 270, 22 ) );
}

Progressform::~Progressform()
{
}

#include "dirops.moc"
