Logo Search packages:      
Sourcecode: karchiver version File versions  Download package

crar.cpp

/***************************************************************************
                          crar.cpp  -  description
                             -------------------
    begin                : Sat Dec 2 2000
    copyright            : (C) 2000 by Eric Coquelle
    email                : coquelle@caramail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "crar.h"
#include <kdebug.h>
#include <kmessagebox.h>
#include <kpassdlg.h>
#include <qfile.h>
#include <qdir.h>

CRar::CRar(){
  CArchive();

  connect(&processread,SIGNAL(receivedStderr(KProcess*, char*, int)),this,SLOT(haveStdErr(KProcess*,char*,int)));
  connect(&processread,SIGNAL(receivedStdout(KProcess*, char*, int)),this,SLOT(haveSdtOut(KProcess*,char*,int)));
  connect(&processread,SIGNAL(processExited (KProcess*)),this,SLOT(endReadProcess(KProcess*)));
  connect(&processextract,SIGNAL(receivedStdout(KProcess*, char*, int)),this,SLOT(haveSdtOutExtract(KProcess*,char*,int)));
  connect(&processextract,SIGNAL(processExited (KProcess*)),this,SLOT(endProcess(KProcess*)));
  connect(&processextract, SIGNAL(receivedStderr(KProcess *, char *, int)),this, SLOT(haveSdtErrExtract(KProcess*,char*,int)));
  connect(&processadd,SIGNAL(receivedStdout(KProcess*, char*, int)),this,SLOT(haveSdtOutExtract(KProcess*,char*,int)));
  connect(&processadd,SIGNAL(processExited (KProcess*)),this,SLOT(endProcess(KProcess*)));

  list->setColumnText(4, i18n("Ratio"));
  list->setColumnText(5, i18n("Permissions"));
  passwordrequired=false;
  mustreadoncemore=false;
}

CRar::~CRar(){
archivePassword="";
}

/** this method will launch the right compressor
to list the file contents
It will then launch the right method to display
the content in the listview */
00051 void CRar::displayArchiveContent(){
  initializeReadingArchive();
  
  if(viewbydirectories)
  {
    if(!(mustreadoncemore&&passwordrequired))
    {
      //The password has been set after the 1st call to displayArchiveContent() has failed
      rarfile=new MyKRar(archiveName);
      if( !rarfile->open(IO_ReadOnly) )
        errors.append("MyKRar Process failed to open file");
    }
  }
  if(mustreadoncemore&&passwordrequired)
    mustreadoncemore=false;
  
  processread <<"rar";
  processread << "v";
  if(!passwordrequired)
    processread << "-p-";
  else
    processread << "-p"+archivePassword;
  processread << archiveName;

//  m_buffer[0]='\0';
  finished=false;
  flag=0;
  processingRarHeader=BEGIN_HEADER;
  processread.start(KProcess::NotifyOnExit, KProcess::AllOutput);
}

/** display in a listview the content of the current
rar archive. This method examines the stdout of
unarj to sort useful infos for the listview */
00085 void CRar::displayRarArchiveContent( FILE* flot ){
      CListViewItem* elementListe;
      char tampon[5000];
      char permission[30];
      QString proprietaire;
      char crc[20];
      char taille[30];
      char date[12];
      char heure[7];
      char sname[5000];
      char methode[20];
      QString path;
      QString name;
      QString message;
      int i;


      do
            fgets( tampon, 5000, flot );
      while( !feof(flot) && (strstr( tampon, "-------------------------------------------------------------------------------" )==NULL));
      fgets( tampon, 5000, flot );
      while( !feof(flot) && (strstr( tampon, "-------------------------------------------------------------------------------" )==NULL))
      {
            sscanf(tampon, " %[a-zA-Z0-9:._-] %[0-9] %[0-9] %[0-9%] %[0-9-] %[0-9:] %[a-zA-Z0-9-] %[a-zA-Z0-9] %[a-zA-Z0-9] %[^\n]",sname, taille, crc, permission, date, heure, crc, crc, crc, methode );

            name=sname;
            i=name.findRev('/');
            if(i!=-1)
            {
                  path=name.left(i+1);
                  name=name.remove(0,i+1);
            if(name=="")name="..";
            }
            else
                  path="";
   //Remove the * of the begining of the path (if password protected)
    if(path.startsWith(" *"))
    {
      path=path.remove(0,1);
      passwordrequired=true;
    }
    if(name.startsWith(" *"))
      name=name.remove(0,1);
    
    QString strdate=date;
    int dd=strdate.left(strdate.find("-")).toInt();
    int yy=strdate.right(strdate.length()-strdate.findRev("-")-1).toInt();
    int mm=strdate.mid(strdate.find("-")+1, 2).toInt();
    elementListe=new CListViewItem(list,name,taille,heure,getLocalizedDate(QDate(dd,mm,yy)),proprietaire,permission,path);
            setIcon(name, permission, elementListe);
            elementListe->widthChanged();
            fgets( tampon, 5000, flot );
      }
      fclose( flot );
}

/*Overloaded method*/
void CRar::displayRarArchiveContent( const char* line){
  CListViewItem* elementListe;
  QStringList columns;
  QString name, path;
  int i;
  
  flag++;

  if ( flag== 1)//1st line: name
  {
      m_line1 = line;
      return;
  }
  columns=QStringList::split(' ', line);//2nd line: other informations

  // if we made it here, we have all two lines.
  // Reset the line number.
  flag = 0;

  QString strdate;
  strdate=columns[3];
  int dd=strdate.left(strdate.find("-")).toInt();
  int yy=strdate.right(strdate.length()-strdate.findRev("-")-1).toInt();
  int mm=strdate.mid(strdate.find("-")+1, 2).toInt();
  name=m_line1;
      
  i=name.findRev('/');
  if(i!=-1)
  {
    path=name.left(i+1);
    name=name.remove(0,i+1);
    if(name=="")name="..";
  }
  else
    path="";
   //Remove the * of the begining of the path (if password protected)
    if(path.startsWith("*"))
    {
      path=path.remove(0,1);
      passwordrequired=true;
    }
    else if(path.startsWith(" "))
      path=path.remove(0,1);
    if(name.startsWith("*"))
      name=name.remove(0,1);
      
    elementListe=new CListViewItem(list,name,columns[0],columns[4],getLocalizedDate(QDate(dd,mm,yy)),columns[2],columns[5],path);
  if(QString(columns[5]).contains("D",false))
    setIcon( ".", columns[5], elementListe);
  else
    setIcon( name, columns[5], elementListe);
  
  elementListe->widthChanged();
}

/** we recive some informations through the standard
output of the process */
00199 void CRar::haveSdtOut(KProcess *, char *buffer, int length){
  //Has user canceled current action ?
  if(stopreadprocess)
          return;

  // This section has been taken from ark:
  //1997-1999: Rob Palmbos palm9744@kettering.edu
  //2000: Corel Corporation (author: Emily Ezust, emilye@corel.com)
  //and adapted to karchiver
  
  
  char c = buffer[length];
  buffer[length] = '\0';
  
  int lfChar, startChar = 0;
  
  while(!finished)
  {
      for(lfChar = startChar; buffer[lfChar] != '\n' && lfChar < length;
        lfChar++);
  
      if(buffer[lfChar] != '\n') break;   // We are done all the complete lines
  
      buffer[lfChar] = '\0';
      m_buffer.append(buffer + startChar);
      buffer[lfChar] = '\n';
      startChar = lfChar + 1;
  
      if(processingRarHeader==HEADER_PROCESSED)
      {
        if(m_buffer.find("--------") == -1 )
        {
          if(viewbydirectories)
            rarfile->displayRarArchiveContent(m_buffer);
          else
            displayRarArchiveContent(m_buffer);
        }
        else
            finished=true;
      }
      else if(processingRarHeader==BEGIN_HEADER)
      {
        if(m_buffer.find("for help") != -1)
            processingRarHeader=BEGIN_COMMENT;
      }
      else if(processingRarHeader==BEGIN_COMMENT)
      {
        if(m_buffer.find("Pathname/Comment") != -1)
            processingRarHeader=END_COMMENT;
        else
            archivecomments.append(m_buffer);
      }
      else if(processingRarHeader==END_COMMENT)
      {
        if( m_buffer.find("--------") != -1 )
            processingRarHeader=HEADER_PROCESSED;
      }
      
      m_buffer = "";
  }
  if(!finished)
        m_buffer.append(buffer + startChar);    // Append what's left of the buffer
  
  buffer[length] = c;
}

/** we recive some informations through the standard
      * output of the process */
00267 void CRar::haveSdtOutExtract(KProcess *, char *buffer, int length){
      QString inter;
      int i=0;

      inter=buffer;
      inter=inter.left(length);

      while((i=inter.find('\n',i+1))!=-1){
            progressbar->setProgress(progressbar->progress()+1);
      }
}

/** we recive some informations through the error
      * output of the process */
00281 void CRar::haveSdtErrExtract(KProcess *proc, char *buffer, int length){
  buffer[length]=0;

  kdDebug()<<("Error during extraction: ")<<(buffer)<<("\n");

  if (strstr(buffer,"incorrect password") || strstr(buffer,"password incorrect ?")) {
    proc->kill();
    KMessageBox::error(NULL, i18n("An error occurred during extraction: \n The archive is password protected and the given password is wrong.\nPlease choose 'Archive->Set Password', change the password and try it again."));
    return;
  }
  CArchive::haveSdtErrExtract(proc, buffer, length);
}

/** The current process ended */
00295 void CRar::endProcess(KProcess*){
 if(!mustreadoncemore)
   emit(archiveReadEnded());
}

void CRar::endReadProcess(KProcess*){
  if(!mustreadoncemore)
  {
    if(viewbydirectories)
      CArchive::displayArchiveContent(rarfile->directory(),QString::null);
    emit(archiveReadEnded());
  }
}

/** Upon the kind of archive, choose the right
      *uncompressor and extract all or some files
      *@extractall = 9: extract to karchiveur's temp directory (for viewing)
      *@extractall = 1: extract all selected files
      */
00314 void CRar::extractArchive(QString & extractpath, int extractall, QString &filetoextract){
  QString directoryOption;
  QString decompressorname="rar";

  errors.clear();
  directoryOption="";
  counter=0;
  progressbar->reset();

  processextract.clearArguments();
  processextract << decompressorname;
  processextract << "x";
  processextract << "-y";
        
  kdDebug()<<QString("Extracting Rar to %1, extractall=%2 file=%3").arg(extractpath).arg(extractall).arg(filetoextract)<<endl;
  
  if(!archivePassword.isEmpty())
    processextract << "-p"+archivePassword;
  else if(passwordrequired)
  {
    KMessageBox::error(NULL, i18n("An error occurred during extraction: \n The archive is password protected and the given password is wrong.\nPlease choose 'Archive->Set Password', change the password and try it again."));
    return;
  }
  else
    processextract << "-p-";

  //Always overwrite as we do checkFiles
  processextract << "-o+";

  processextract << archiveName;
  processextract << "-d" << extractpath;

  if((extractall!=EXTRACTONE)&&(extractall!=EXTRACTONE_AND_BLOCK)&&(!checkFiles(extractpath, extractall)))
  {
    endProcess(NULL);
    return;
  }
  else if(extractall==EXTRACTONE_AND_BLOCK)
  {
    //We want to view (and so extract) only one file. So we just add this file to the tar or unzip
    //command. For gzip and bzip2 files, in any case, we extract one and only one file, so I put
    //it apart
    processextract << filetoextract;
    if(processextract.start(KProcess::Block)==FALSE)
      kdDebug()<<("\n*PB PROCESS*\n");
  }
  else if(extractall==EXTRACTONE)
  {
    //We want to view (and so extract) only one file. So we just add this file to the tar or unzip
    //command. For gzip and bzip2 files, in any case, we extract one and only one file, so I put
    //it apart
    processextract << filetoextract;
    if(processextract.start(KProcess::NotifyOnExit)==FALSE)
      kdDebug()<<("\n*PB PROCESS*\n");
  }
  else if(extractall!=EXTRACTONE_AND_BLOCK)
  {
          //We extract through the Stdout to have a progress indicator
    if(processextract.start(KProcess::NotifyOnExit,KProcess::AllOutput)==FALSE)
      kdDebug()<<("\n*PB PROCESS*\n");
  }
  counter=0;
}

/** delete @param filestodelete from current archive */
00379 void CRar::removeFilesFromArchive (QStringList filestodelete){
  kdDebug()<<("In:removeFilesFromArchive_RAR\n");
  processadd.clearArguments();
  processadd << "rar" << "d";
  processadd << archiveName;
  for (QStringList::Iterator f = filestodelete.begin(); f!=filestodelete.end(); ++f )
  {
    kdDebug()<<QString("Will remove:%1*").arg(*f)<<endl;
    processadd << *f;
  }
  processadd.start(KProcess::Block);
  kdDebug()<<("Ok:removeFilesFromArchive_RAR\n");
}

/** Add some files to the archive
@param filestoadd : list of files to add
@param removeoriginalfiles : remove or not those files from disk
@param action : 0=mode append and replace files, 1=mode update files
@param relativepath : if !NULL, include only filenames, without their base path */
00398 void CRar::addFilesToArchive( QStringList filestoadd, bool removeoriginalfiles, int action, QString relativepath){
      QString s;

      if(relativepath!=NULL)
            QDir::setCurrent(relativepath);

      processadd.clearArguments();
      processadd << "rar";
      processadd << "a";
      
 switch(action)
 {
   case UPDATE_FILES:
   {
     processadd << "-u";
     break;
   }
 }
 if(!archivePassword.isEmpty())
   processadd << "-hp"+archivePassword;

 processadd << QString("-m%1").arg((int)(compressrate*5.0/9.0));
      if(removeoriginalfiles)
            processadd << "-df";
      
      /* rar 3.60 seems to add subdirs by default...
        if(recursivemode)
        processadd << "-r";*/

      processadd << archiveName;
      for (QStringList::Iterator f = filestoadd.begin(); f!=filestoadd.end(); ++f )
      {
        s=*f;
        if(s.endsWith("/") )
          s.truncate(s.length()-1);
        if(s.startsWith("file:"))
          s.remove(0,5);
        kdDebug()<<QString("AddRar: %1 in:%2").arg(s).arg(archiveName)<<endl;
      processadd << s;
      }
      processadd.start(KProcess::NotifyOnExit);
}

/** Create a rar archive
@param  nameofarchive: the name of the zip archive
@param param: list of files to add
@param relativepath: include only filenames, without their path */
00445 void CRar::createArchive(QString nameofarchive, QStringList filestoadd, QString relativepath) {
      QString str;

      archiveName=nameofarchive;
      kdDebug()<<QString("Create RAR archive named %1 path=%2").arg(nameofarchive).arg(relativepath)<<endl;
      addFilesToArchive(filestoadd, false, 0,relativepath);
      kdDebug()<<("\nEndCreateRar\n");
}

/** Returns true if archive type supports passwords */
00455 bool CRar::supportPassword(){
 return true;
}

void CRar::haveStdErr(KProcess *, char *buffer, int length)
{
  QString sbuffer=buffer;
  sbuffer.truncate(length-1);
  if(sbuffer.contains("password incorrect"))
  {
    QCString pass;
    mustreadoncemore=true; //A password is required, so set is and read the archive again
    int rc = KPasswordDialog::getPassword(pass,i18n("Enter Archive password"));
    if(rc==KPasswordDialog::Accepted)
    {
      setPassword(pass);
      passwordrequired=true;
      processread.kill();
      displayArchiveContent();
    }
    else
      mustreadoncemore=false;
  }
}

/**Returns true if current archive can be repaired*/
00481 bool CRar::canRepairArchive(){
  return true;
}

/**Launches the repair process*/
00486 void CRar::repairCurrentArchive()
{
  QFileInfo archive(archiveName);
  errors.clear();
  
  repairedArchiveName=archive.dirPath(true)+"/"+"rebuilt."+archive.fileName();
  QDir::setCurrent(archive.dirPath(true));
  
  processextract.clearArguments();
  processextract << "rar" << "r" << "-y" << archiveName;
  processextract.start(KProcess::NotifyOnExit,KProcess::AllOutput);
}


#include "crar.moc"

Generated by  Doxygen 1.6.0   Back to index