You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeutils/ark/arch.cpp

494 lines
13 KiB

/*
ark -- archiver for the KDE project
Copyright (C)
2002: Helio Chissini de Castro <helio@conectiva.com.br>
2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com)
1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com)
1999: Francois-Xavier Duranceau duranceau@kde.org
1997-1999: Rob Palmbos palm9744@kettering.edu
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// C includes
#include <stdlib.h>
#include <time.h>
// QT includes
#include <tqapplication.h>
#include <tqfile.h>
#include <tqtextcodec.h>
// KDE includes
#include <kdebug.h>
#include <kmessagebox.h>
#include <kmimetype.h>
#include <klocale.h>
#include <kpassdlg.h>
#include <kprocess.h>
#include <kstandarddirs.h>
// ark includes
#include "arch.h"
#include "arkwidget.h"
#include "arkutils.h"
#include "filelistview.h"
// the archive types
#include "tar.h"
#include "zip.h"
#include "lha.h"
#include "compressedfile.h"
#include "zoo.h"
#include "rar.h"
#include "ar.h"
#include "sevenzip.h"
#include "ace.h"
#include "arj.h"
Arch::ArchColumns::ArchColumns( int col, TQRegExp reg, int length, bool opt )
: colRef( col ), pattern( reg ), maxLength( length ), optional( opt )
{
}
Arch::Arch( ArkWidget *gui, const TQString &filename )
: m_filename( filename ), m_buffer( "" ), m_gui( gui ),
m_bReadOnly( false ), m_bNotifyWhenDeleteFails( true ),
m_header_removed( false ), m_finished( false ),
m_numCols( 0 ), m_dateCol( -1 ), m_fixYear( -1 ), m_fixMonth( -1 ),
m_fixDay( -1 ), m_fixTime( -1 ), m_repairYear( -1 ), m_repairMonth( -1 ),
m_repairTime( -1 ), m_currentProcess( 0 )
{
m_archCols.setAutoDelete( true ); // To check: it still leaky here???
}
Arch::~Arch()
{
if ( m_currentProcess )
m_currentProcess->kill();
}
//Check if a compress utility exists
void Arch::verifyCompressUtilityIsAvailable( const TQString &utility )
{
// see if the utility is in the PATH of the user.
TQString cmd = KGlobal::dirs()->findExe( utility );
m_bArchUtilityIsAvailable = !cmd.isEmpty();
}
//Check if a utility can uncompress files
void Arch::verifyUncompressUtilityIsAvailable( const TQString &utility )
{
// see if the utility is in the PATH of the user.
TQString cmd = KGlobal::dirs()->findExe( utility );
m_bUnarchUtilityIsAvailable = !cmd.isEmpty();
}
void Arch::slotOpenExited( KProcess* _kp )
{
bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
if( !success )
{
if ( passwordRequired() )
{
TQString msg;
if ( !m_password.isEmpty() )
msg = i18n("The password was incorrect. ");
if (KPasswordDialog::getPassword( m_password, msg+i18n("You must enter a password to open the file:") ) == KPasswordDialog::Accepted )
{
delete _kp;
_kp = m_currentProcess = 0;
clearShellOutput();
open(); // try to open the file again with a password
return;
}
m_password = "";
emit sigOpen( this, false, TQString(), 0 );
delete _kp;
_kp = m_currentProcess = 0;
return;
}
}
int exitStatus = 100; // arbitrary bad exit status
if ( _kp->normalExit() )
exitStatus = _kp->exitStatus();
if ( exitStatus == 1 )
{
exitStatus = 0; // because 1 means empty archive - not an error.
// Is this a safe assumption?
}
if ( !exitStatus )
emit sigOpen( this, true, m_filename,
Arch::Extract | Arch::Delete | Arch::Add | Arch::View );
else
emit sigOpen( this, false, TQString(), 0 );
delete _kp;
_kp = m_currentProcess = 0;
}
void Arch::slotDeleteExited( KProcess *_kp )
{
bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
if ( !success )
{
TQApplication::restoreOverrideCursor();
TQString msg = i18n( "The deletion operation failed." );
if ( !getLastShellOutput().isNull() )
{
TQStringList list = TQStringList::split( "\n", getLastShellOutput() );
KMessageBox::errorList( m_gui, msg, list );
clearShellOutput();
}
else
{
KMessageBox::error( m_gui, msg );
}
}
emit sigDelete( success );
delete _kp;
_kp = m_currentProcess = 0;
}
void Arch::slotExtractExited( KProcess *_kp )
{
bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
if( !success )
{
if ( passwordRequired() )
{
TQString msg;
if ( !m_password.isEmpty() )
msg = i18n("The password was incorrect. ");
if (KPasswordDialog::getPassword( m_password, msg+i18n("You must enter a password to extract the file:") ) == KPasswordDialog::Accepted )
{
delete _kp;
_kp = m_currentProcess = 0;
clearShellOutput();
unarchFileInternal(); // try to extract the file again with a password
return;
}
m_password = "";
emit sigExtract( false );
delete _kp;
_kp = m_currentProcess = 0;
return;
}
else if ( m_password.isEmpty() || _kp->exitStatus() > 1 )
{
TQApplication::restoreOverrideCursor();
TQString msg = i18n( "The extraction operation failed." );
if ( !getLastShellOutput().isNull() )
{
//getLastShellOutput() is a TQString. errorList is expecting TQStringLists to show in multiple lines
TQStringList list = TQStringList::split( "\n", getLastShellOutput() );
KMessageBox::errorList( m_gui, msg, list );
clearShellOutput();
}
else
{
KMessageBox::error( m_gui, msg );
}
}
}
m_password = "";
delete _kp;
_kp = m_currentProcess = 0;
emit sigExtract( success );
}
void Arch::unarchFile( TQStringList *fileList, const TQString & destDir,
bool viewFriendly )
{
m_fileList = fileList;
m_destDir = destDir;
m_viewFriendly = viewFriendly;
unarchFileInternal();
}
void Arch::slotAddExited( KProcess *_kp )
{
bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
if( !success )
{
TQApplication::restoreOverrideCursor();
TQString msg = i18n( "The addition operation failed." );
if ( !getLastShellOutput().isNull() )
{
TQStringList list = TQStringList::split( "\n", getLastShellOutput() );
KMessageBox::errorList( m_gui, msg, list );
clearShellOutput();
}
else
{
KMessageBox::error( m_gui, msg );
}
}
emit sigAdd( success );
delete _kp;
_kp = m_currentProcess = 0;
}
void Arch::slotReceivedOutput( KProcess*, char* data, int length )
{
char c = data[ length ];
data[ length ] = '\0';
appendShellOutputData( data );
data[ length ] = c;
}
void Arch::slotReceivedTOC( KProcess*, char* data, int length )
{
char c = data[ length ];
data[ length ] = '\0';
appendShellOutputData( data );
int lfChar, startChar = 0;
while ( !m_finished )
{
for ( lfChar = startChar; data[ lfChar ] != '\n' && lfChar < length;
lfChar++ );
if ( data[ lfChar ] != '\n')
break; // We are done all the complete lines
data[ lfChar ] = '\0';
m_buffer.append( data + startChar );
data[ lfChar ] = '\n';
startChar = lfChar + 1;
if ( m_headerString.isEmpty() )
{
processLine( m_buffer );
}
else if ( m_buffer.find( m_headerString.data() ) == -1 )
{
if ( m_header_removed && !m_finished )
{
if ( !processLine( m_buffer ) )
{
// Have faith - maybe it wasn't a header?
m_header_removed = false;
m_error = true;
}
}
}
else if ( !m_header_removed )
{
m_header_removed = true;
}
else
{
m_finished = true;
}
m_buffer = "";
}
if ( !m_finished )
m_buffer.append( data + startChar); // Append what's left of the buffer
data[ length ] = c;
}
bool Arch::processLine( const TQCString &line )
{
TQString columns[ 11 ];
unsigned int pos = 0;
int strpos, len;
TQTextCodec::setCodecForCStrings(TQTextCodec::codecForLocale());
TQTextCodec *codec = TQTextCodec::codecForLocale();
TQString tqunicode_line = codec->toUnicode( line );
// Go through our columns, try to pick out data, return silently on failure
for ( TQPtrListIterator <ArchColumns>col( m_archCols ); col.current(); ++col )
{
ArchColumns *curCol = *col;
strpos = curCol->pattern.search( tqunicode_line, pos );
len = curCol->pattern.matchedLength();
if ( ( strpos == -1 ) || ( len > curCol->maxLength ) )
{
if ( curCol->optional )
continue; // More?
else
{
kdDebug(1601) << "processLine failed to match critical column" << endl;
return false;
}
}
pos = strpos + len;
columns[curCol->colRef] = tqunicode_line.mid(strpos, len).utf8();
}
if ( m_dateCol >= 0 )
{
TQString year = ( m_repairYear >= 0 ) ?
ArkUtils::fixYear( columns[ m_repairYear ].ascii())
: columns[ m_fixYear ];
TQString month = ( m_repairMonth >= 0 ) ?
TQString( "%1" )
.arg( ArkUtils::getMonth( columns[ m_repairMonth ].ascii() ) )
: columns[ m_fixMonth ];
TQString timestamp = TQString::fromLatin1( "%1-%2-%3 %4" )
.arg( year )
.arg( month )
.arg( columns[ m_fixDay ] )
.arg( columns[ m_fixTime ] );
columns[ m_dateCol ] = timestamp;
}
TQStringList list;
for ( int i = 0; i < m_numCols; ++i )
{
list.append( columns[ i ] );
}
m_gui->fileList()->addItem( list ); // send the entry to the GUI
return true;
}
void Arch::test()
{
emit sigTest(false);
KMessageBox::information(0, i18n("Not implemented."));
}
void Arch::slotTestExited( KProcess *_kp )
{
bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
if( !success )
{
if ( passwordRequired() )
{
TQString msg;
if ( !m_password.isEmpty() )
msg = i18n("The password was incorrect. ");
if (KPasswordDialog::getPassword( m_password, msg+i18n("You must enter a password to extract the file:") ) == KPasswordDialog::Accepted )
{
delete _kp;
_kp = m_currentProcess = 0;
clearShellOutput();
test(); // try to test the archive again with a password
return;
}
m_password = "";
emit sigTest( false );
delete _kp;
_kp = m_currentProcess = 0;
return;
}
else if ( m_password.isEmpty() || _kp->exitStatus() > 1 )
{
TQApplication::restoreOverrideCursor();
TQString msg = i18n( "The test operation failed." );
if ( !getLastShellOutput().isNull() )
{
//getLastShellOutput() is a TQString. errorList is expecting TQStringLists to show in multiple lines
TQStringList list = TQStringList::split( "\n", getLastShellOutput() );
KMessageBox::errorList( m_gui, msg, list );
clearShellOutput();
}
else
{
KMessageBox::error( m_gui, msg );
}
}
}
delete _kp;
_kp = m_currentProcess = 0;
emit sigTest( success );
}
Arch *Arch::archFactory( ArchType aType,
ArkWidget *parent, const TQString &filename,
const TQString &openAsMimeType )
{
switch( aType )
{
case TAR_FORMAT:
return new TarArch( parent, filename, openAsMimeType );
case ZIP_FORMAT:
return new ZipArch( parent, filename );
case LHA_FORMAT:
return new LhaArch( parent, filename );
case COMPRESSED_FORMAT:
return new CompressedFile( parent, filename, openAsMimeType );
case ZOO_FORMAT:
return new ZooArch( parent, filename );
case RAR_FORMAT:
return new RarArch( parent, filename );
case AA_FORMAT:
return new ArArch( parent, filename );
case SEVENZIP_FORMAT:
return new SevenZipArch( parent, filename );
case ACE_FORMAT:
return new AceArch( parent, filename );
case ARJ_FORMAT:
return new ArjArch( parent, filename );
case UNKNOWN_FORMAT:
default:
return 0;
}
}
#include "arch.moc"