diff options
author | Michele Calgaro <michele.calgaro@yahoo.it> | 2025-08-28 22:44:34 +0900 |
---|---|---|
committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2025-08-31 23:30:34 +0900 |
commit | f9abd9d505434c9244c03eac708e29a0ca042f6b (patch) | |
tree | 30a197ab4c413849188bc131ff859212e636c821 /src/krArc | |
parent | 14d42d284de233f9937becf3fc9ee0dabede3b21 (diff) | |
download | krusader-r14.1.x.tar.gz krusader-r14.1.x.zip |
Restructure source foldersr14.1.x
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
(cherry picked from commit 086012dcad8a976a0dabbb7cbc20c9cb612cdfa9)
Diffstat (limited to 'src/krArc')
-rw-r--r-- | src/krArc/CMakeL10n.txt | 3 | ||||
-rw-r--r-- | src/krArc/Makefile.am | 59 | ||||
-rw-r--r-- | src/krArc/krarc.cpp | 1692 | ||||
-rw-r--r-- | src/krArc/krarc.h | 144 | ||||
-rw-r--r-- | src/krArc/krarc.protocol | 18 |
5 files changed, 1916 insertions, 0 deletions
diff --git a/src/krArc/CMakeL10n.txt b/src/krArc/CMakeL10n.txt new file mode 100644 index 0000000..30959a5 --- /dev/null +++ b/src/krArc/CMakeL10n.txt @@ -0,0 +1,3 @@ +##### create translation templates ############## + +tde_l10n_create_template( "messages/tdeio_krarc/" ) diff --git a/src/krArc/Makefile.am b/src/krArc/Makefile.am new file mode 100644 index 0000000..5d7eeb6 --- /dev/null +++ b/src/krArc/Makefile.am @@ -0,0 +1,59 @@ +####### tdevelop will overwrite this part!!! (begin)########## +kde_module_LTLIBRARIES = tdeio_krarc.la + + +INCLUDES = $(all_includes) + + +#LDFLAGS = + +tdeio_krarc_la_METASOURCES=AUTO + +tdeio_krarc_la_SOURCES = krarc.cpp +tdeio_krarc_la_LIBADD = $(LIB_TQT) $(LIB_TDECORE) $(LIB_TDEIO) +# $(LIB_TDEUI) $(LIB_TDECORE) $(LIB_TQT) + +tdeio_krarc_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +noinst_HEADERS = krarc.h + +EXTRA_DIST = krarc.protocol + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(kde_servicesdir) + $(INSTALL_DATA) $(srcdir)/krarc.protocol $(DESTDIR)$(kde_servicesdir)/krarc.protocol + +uninstall-local: + rm -f $(DESTDIR)$(kde_servicesdir)/krarc.protocol + +####### tdevelop will overwrite this part!!! (end)############ +# These paths are KDE specific. Use them: +# kde_appsdir Where your application's menu entry (.desktop) should go to. +# kde_icondir Where your icon should go to - better use KDE_ICON. +# kde_sounddir Where your sounds should go to. +# kde_htmldir Where your docs should go to. (contains lang subdirs) +# kde_datadir Where you install application data. (Use a subdir) +# kde_locale Where translation files should go to. (contains lang subdirs) +# kde_cgidir Where cgi-bin executables should go to. +# kde_confdir Where config files should go to (system-wide ones with default values). +# kde_mimedir Where mimetypes .desktop files should go to. +# kde_servicesdir Where services .desktop files should go to. +# kde_servicetypesdir Where servicetypes .desktop files should go to. +# kde_toolbardir Where general toolbar icons should go to (deprecated, use KDE_ICON). +# kde_wallpaperdir Where general wallpapers should go to. +# kde_templatesdir Where templates for the "New" menu (Konqueror/KDesktop) should go to. +# kde_bindir Where executables should go to. Use bin_PROGRAMS or bin_SCRIPTS. +# kde_libdir Where shared libraries should go to. Use lib_LTLIBRARIES. +# kde_moduledir Where modules (e.g. parts) should go to. Use kde_module_LTLIBRARIES. +# kde_styledir Where TQt/TDE widget styles should go to. +# kde_designerdir Where TQt Designer plugins should go to. + + +# make messages.po. Move this one to ../po/ and "make merge" in po +# the -x is for skipping messages already translated in tdelibs +messages: + LIST=`find . -name \*.h -o -name \*.cpp`; \ + if test -n "$$LIST"; then \ + $(XGETTEXT) -C -ki18n -x $(kde_includes)/kde.pot $$LIST -o ../po/krarc.pot; \ + fi + diff --git a/src/krArc/krarc.cpp b/src/krArc/krarc.cpp new file mode 100644 index 0000000..a77eaea --- /dev/null +++ b/src/krArc/krarc.cpp @@ -0,0 +1,1692 @@ +/*************************************************************************** + krarc.cpp + ------------------- + begin : Sat Jun 14 14:42:49 IDT 2003 + copyright : (C) 2003 by Rafi Yanai & Shie Erlich + email : krusader@users.sf.net + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <stdlib.h> + +#include <tqdir.h> +#include <tqfile.h> +#include <tqfileinfo.h> +#include <tqregexp.h> +#include <tqdir.h> + +#include <tdefileitem.h> +#include <kdebug.h> +#include <tdemessagebox.h> +#include <tdeinstance.h> +#include <tdelocale.h> +#include <kurl.h> +#include <tdetempfile.h> +#include <klargefile.h> +#include <kstandarddirs.h> +#include <tdeio/job.h> +#include <ktar.h> + +#include <iostream> +#include "krarc.h" + +#define MAX_IPC_SIZE (1024*32) +#define TRIES_WITH_PASSWORDS 3 + +#if 0 +#define KRDEBUG(X...) do{ \ + TQFile f("/tmp/debug"); \ + f.open(IO_WriteOnly | IO_Append); \ + TQTextStream stream( &f ); \ + stream << "Pid:" << (int)getpid() << " " <<__FUNCTION__<<"(" <<__LINE__<<"): "; \ + stream << X << endl; \ + f.close(); \ +} while(0); +#else +#define KRDEBUG(X...) +#endif + +using namespace TDEIO; +extern "C" { + +int kdemain( int argc, char **argv ){ + TDEInstance instance( "tdeio_krarc" ); + + if (argc != 4) { + kdWarning() << "Usage: tdeio_krarc protocol domain-socket1 domain-socket2" << endl; + exit(-1); + } + + tdeio_krarcProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + return 0; +} + +} // extern "C" + +tdeio_krarcProtocol::tdeio_krarcProtocol(const TQCString &pool_socket, const TQCString &app_socket) + : SlaveBase("tdeio_krarc", pool_socket, app_socket), archiveChanged(true), arcFile(0L),extArcReady(false), + password(TQString()) { + + krConfig = new TDEConfig( "krusaderrc" ); + krConfig->setGroup( "Dependencies" ); + + dirDict.setAutoDelete(true); + + arcTempDir = locateLocal("tmp",TQString()); + TQString dirName = "krArc"+TQDateTime::currentDateTime().toString(TQt::ISODate); + dirName.replace(TQRegExp(":"),"_"); + TQDir(arcTempDir).mkdir(dirName); + arcTempDir = arcTempDir+dirName+"/"; +} + +/* ---------------------------------------------------------------------------------- */ +tdeio_krarcProtocol::~tdeio_krarcProtocol(){ + // delete the temp directory + KrShellProcess proc; + proc << "rm -rf "<< arcTempDir; + proc.start(TDEProcess::Block); +} + +/* ---------------------------------------------------------------------------------- */ +void tdeio_krarcProtocol::receivedData(TDEProcess*,char* buf,int len){ + TQByteArray d(len); + d.setRawData(buf,len); + data(d); + d.resetRawData(buf,len); + processedSize(len); + decompressedLen += len; +} + +void tdeio_krarcProtocol::mkdir(const KURL& url,int permissions){ + KRDEBUG(url.path()); + + if( !setArcFile( url ) ) { + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + if( newArchiveURL && !initDirDict(url) ){ + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + + if( putCmd.isEmpty() ){ + error(ERR_UNSUPPORTED_ACTION, + i18n("Creating directories is not supported with %1 archives").arg(arcType) ); + return; + } + + if( arcType == "arj" || arcType == "lha" ) { + TQString arcDir = url.path().mid(arcFile->url().path().length()); + if( arcDir.right(1) != "/") arcDir = arcDir+"/"; + + if( dirDict.find( arcDir ) == 0 ) + addNewDir( arcDir ); + finished(); + return; + } + + //TQString tmpDir = arcTempDir+url.path(); + TQString arcDir = findArcDirectory(url); + TQString tmpDir = arcTempDir + arcDir.mid(1) + url.path().mid(url.path().findRev("/")+1); + if( tmpDir.right(1) != "/" ) tmpDir = tmpDir+"/"; + + if( permissions == -1 ) permissions = 0777; //set default permissions + for( unsigned int i=arcTempDir.length();i<tmpDir.length(); i=tmpDir.find("/",i+1)){ + ::mkdir(tmpDir.left(i).local8Bit(),permissions); + } + + if( tmpDir.endsWith( "/" ) ) + tmpDir.truncate( tmpDir.length() - 1 ); + + // pack the directory + KrShellProcess proc; + proc << putCmd << convertName( arcFile->url().path() ) + " " << convertFileName( tmpDir.mid(arcTempDir.length()) ); + infoMessage(i18n("Creating %1 ...").arg( url.fileName() ) ); + TQDir::setCurrent(arcTempDir); + proc.start(TDEProcess::Block,TDEProcess::AllOutput); + + // delete the temp directory + TQDir().rmdir(arcTempDir); + + if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) { + error(ERR_COULD_NOT_WRITE,url.path() + "\n\n" + proc.getErrorMsg() ); + return; + } + + // force a refresh of archive information + initDirDict(url,true); + finished(); +} + +void tdeio_krarcProtocol::put(const KURL& url,int permissions,bool overwrite,bool resume){ + KRDEBUG(url.path()); + if( !setArcFile( url ) ) { + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + if( newArchiveURL && !initDirDict(url) ){ + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + + if( putCmd.isEmpty() ){ + error(ERR_UNSUPPORTED_ACTION, + i18n("Writing to %1 archives is not supported").arg(arcType) ); + return; + } + if( !overwrite && findFileEntry(url) ){ + error( ERR_FILE_ALREADY_EXIST,url.path() ); + return; + } + + TQString arcDir = findArcDirectory(url); + TQString tmpFile = arcTempDir + arcDir.mid(1) + url.path().mid(url.path().findRev("/")+1); + + TQString tmpDir = arcTempDir+arcDir.mid(1)+"/"; + for( unsigned int i=arcTempDir.length();i<tmpDir.length(); i=tmpDir.find("/",i+1)){ + TQDir("/").mkdir(tmpDir.left(i)); + } + int fd; + if ( resume ) { + fd = KDE_open( tmpFile.local8Bit(), O_RDWR ); // append if resuming + KDE_lseek(fd, 0, SEEK_END); // Seek to end + } else { + // WABA: Make sure that we keep writing permissions ourselves, + // otherwise we can be in for a surprise on NFS. + mode_t initialMode; + if ( permissions != -1) + initialMode = permissions | S_IWUSR | S_IRUSR; + else + initialMode = 0666; + + fd = KDE_open(tmpFile.local8Bit(), O_CREAT | O_TRUNC | O_WRONLY, initialMode); + } + TQByteArray buffer; + int readResult; + do{ + dataReq(); + readResult = readData(buffer); + write(fd,buffer.data(),buffer.size()); + } while( readResult > 0 ); + close(fd); + // pack the file + KrShellProcess proc; + proc << putCmd << convertName( arcFile->url().path() )+ " " <<convertFileName( tmpFile.mid(arcTempDir.length()) ); + infoMessage(i18n("Packing %1 ...").arg( url.fileName() ) ); + TQDir::setCurrent(arcTempDir); + proc.start(TDEProcess::Block,TDEProcess::AllOutput); + // remove the file + TQFile::remove(tmpFile); + + if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) { + error(ERR_COULD_NOT_WRITE,url.path() + "\n\n" + proc.getErrorMsg() ); + return; + } + // force a refresh of archive information + initDirDict(url,true); + finished(); +} + +void tdeio_krarcProtocol::get(const KURL& url ){ + get( url, TRIES_WITH_PASSWORDS ); +} + +void tdeio_krarcProtocol::get(const KURL& url, int tries ){ + bool decompressToFile = false; + KRDEBUG(url.path()); + + if( !setArcFile( url ) ) { + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + if( newArchiveURL && !initDirDict(url) ){ + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + + if( getCmd.isEmpty() ){ + error(ERR_UNSUPPORTED_ACTION, + i18n("Retrieving data from %1 archives is not supported").arg(arcType) ); + return; + } + UDSEntry* entry = findFileEntry(url); + if( !entry ){ + error(TDEIO::ERR_DOES_NOT_EXIST,url.path()); + return; + } + if(KFileItem(*entry,url).isDir()){ + error(TDEIO::ERR_IS_DIRECTORY,url.path()); + return; + } + TDEIO::filesize_t expectedSize = KFileItem(*entry,url).size(); + // for RPM files extract the cpio file first + if( !extArcReady && arcType == "rpm"){ + KrShellProcess cpio; + cpio << "rpm2cpio" << convertName( arcFile->url().path(-1) ) << " > " << arcTempDir+"contents.cpio"; + cpio.start(TDEProcess::Block,TDEProcess::AllOutput); + if( !cpio.normalExit() || cpio.exitStatus() != 0 ) { + error(ERR_COULD_NOT_READ,url.path() + "\n\n" + cpio.getErrorMsg() ); + return; + } + extArcReady = true; + } + // for DEB files extract the tar file first + if ( !extArcReady && arcType == "deb" ) { + KrShellProcess dpkg; + dpkg << cmd + " --fsys-tarfile" << convertName( arcFile->url().path( -1 ) ) << " > " << arcTempDir + "contents.cpio"; + dpkg.start( TDEProcess::Block, TDEProcess::AllOutput ); + if( !dpkg.normalExit() || dpkg.exitStatus() != 0 ) { + error(ERR_COULD_NOT_READ,url.path() + "\n\n" + dpkg.getErrorMsg() ); + return; + } + extArcReady = true; + } + + // Use the external unpacker to unpack the file + TQString file = url.path().mid(arcFile->url().path().length()+1); + KrShellProcess proc; + if( extArcReady ){ + proc << getCmd << arcTempDir+"contents.cpio " << convertName( "*"+file ); + } else if( arcType == "arj" || arcType == "ace" || arcType == "7z" ) { + proc << getCmd << convertName( arcFile->url().path(-1) )+ " " << convertFileName( file ); + if( arcType == "ace" && TQFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!! + proc << "<" << "/dev/ptmx"; + file = url.fileName(); + decompressToFile = true; + } else { + decompressedLen = 0; + // Determine the mimetype of the file to be retrieved, and emit it. + // This is mandatory in all slaves (for KRun/BrowserRun to work). + KMimeType::Ptr mt = KMimeType::findByURL( arcTempDir+file, 0, false /* NOT local URL */ ); + emit mimeType( mt->name() ); + proc << getCmd << convertName( arcFile->url().path() )+" "; + if( arcType != "gzip" && arcType != "bzip2" && arcType != "xz") proc << convertFileName( file ); + connect(&proc,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + this,TQ_SLOT(receivedData(TDEProcess*,char*,int)) ); + } + infoMessage(i18n("Unpacking %1 ...").arg( url.fileName() ) ); + // change the working directory to our arcTempDir + TQDir::setCurrent(arcTempDir); + proc.start(TDEProcess::Block,TDEProcess::AllOutput); + + if( !extArcReady && !decompressToFile ) { + if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) || + ( arcType != "bzip2" && arcType != "xz" && expectedSize != decompressedLen ) ) { + if( encrypted && tries ) { + invalidatePassword(); + get( url, tries - 1 ); + return; + } + error( TDEIO::ERR_ACCESS_DENIED, url.path() + "\n\n" + proc.getErrorMsg() ); + return; + } + } + else{ + if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) || !TQFileInfo( arcTempDir+file ).exists() ) { + if( decompressToFile ) + TQFile(arcTempDir+file).remove(); + if( encrypted && tries ) { + invalidatePassword(); + get( url, tries - 1 ); + return; + } + error( TDEIO::ERR_ACCESS_DENIED, url.path() ); + return; + } + // the follwing block is ripped from KDE file TDEIO::Slave + // $Id: krarc.cpp,v 1.43 2007/01/13 13:39:51 ckarai Exp $ + TQCString _path( TQFile::encodeName(arcTempDir+file) ); + KDE_struct_stat buff; + if( KDE_lstat( _path.data(), &buff ) == -1 ) { + if ( errno == EACCES ) + error( TDEIO::ERR_ACCESS_DENIED, url.path() ); + else + error( TDEIO::ERR_DOES_NOT_EXIST, url.path() ); + return; + } + if ( S_ISDIR( buff.st_mode ) ) { + error( TDEIO::ERR_IS_DIRECTORY, url.path() ); + return; + } + if ( !S_ISREG(buff.st_mode) ) { + error( TDEIO::ERR_CANNOT_OPEN_FOR_READING, url.path() ); + return; + } + int fd = KDE_open( _path.data(), O_RDONLY ); + if ( fd < 0 ) { + error( TDEIO::ERR_CANNOT_OPEN_FOR_READING, url.path() ); + return; + } + // Determine the mimetype of the file to be retrieved, and emit it. + // This is mandatory in all slaves (for KRun/BrowserRun to work). + KMimeType::Ptr mt = KMimeType::findByURL( arcTempDir+file, buff.st_mode, true /* local URL */ ); + emit mimeType( mt->name() ); + + TDEIO::filesize_t processed_size = 0; + + TQString resumeOffset = metaData("resume"); + if ( !resumeOffset.isEmpty() ){ + bool ok; + TDEIO::fileoffset_t offset = resumeOffset.toLongLong(&ok); + if (ok && (offset > 0) && (offset < buff.st_size)){ + if (KDE_lseek(fd, offset, SEEK_SET) == offset){ + canResume (); + processed_size = offset; + } + } + } + + totalSize( buff.st_size ); + + char buffer[ MAX_IPC_SIZE ]; + TQByteArray array; + while( 1 ){ + int n = ::read( fd, buffer, MAX_IPC_SIZE ); + if (n == -1){ + if (errno == EINTR) + continue; + error( TDEIO::ERR_COULD_NOT_READ, url.path()); + close(fd); + return; + } + if (n == 0) + break; // Finished + + array.setRawData(buffer, n); + data( array ); + array.resetRawData(buffer, n); + + processed_size += n; + } + + data( TQByteArray() ); + close( fd ); + processedSize( buff.st_size ); + finished(); + + if( decompressToFile ) + TQFile(arcTempDir+file).remove(); + return; + } + // send empty buffer to mark EOF + data(TQByteArray()); + finished(); +} + +void tdeio_krarcProtocol::del(KURL const & url, bool isFile){ + KRDEBUG(url.path()); + + if( !setArcFile( url ) ) { + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + if( newArchiveURL && !initDirDict(url) ){ + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + + if( delCmd.isEmpty() ){ + error(ERR_UNSUPPORTED_ACTION, + i18n("Deleting files from %1 archives is not supported").arg(arcType) ); + return; + } + if( !findFileEntry(url) ){ + if( ( arcType != "arj" && arcType != "lha" ) || isFile ) { + error(TDEIO::ERR_DOES_NOT_EXIST,url.path()); + return; + } + } + + TQString file = url.path().mid(arcFile->url().path().length()+1); + if( !isFile && file.right(1) != "/" ) { + if(arcType == "zip") file = file + "/"; + } + KrShellProcess proc; + proc << delCmd << convertName( arcFile->url().path() )+" " << convertFileName( file ); + infoMessage(i18n("Deleting %1 ...").arg( url.fileName() ) ); + proc.start(TDEProcess::Block, TDEProcess::AllOutput); + if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) { + error(ERR_COULD_NOT_WRITE,url.path() + "\n\n" + proc.getErrorMsg() ); + return; + } + // force a refresh of archive information + initDirDict(url,true); + finished(); +} + +void tdeio_krarcProtocol::stat( const KURL & url ){ + KRDEBUG(url.path()); + if( !setArcFile( url ) ) { + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + if( newArchiveURL && !initDirDict(url) ){ + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + + if( listCmd.isEmpty() ){ + error(ERR_UNSUPPORTED_ACTION, + i18n("Accessing files is not supported with the %1 archives").arg(arcType) ); + return; + } + TQString path = url.path(-1); + KURL newUrl = url; + + // but treat the archive itself as the archive root + if( path == arcFile->url().path(-1) ){ + newUrl.setPath(path+"/"); + path = newUrl.path(); + } + // we might be stating a real file + if( TQFileInfo(path).exists() ){ + KDE_struct_stat buff; + KDE_stat( path.local8Bit(), &buff ); + TQString mime = KMimeType::findByPath(path,buff.st_mode)->name(); + statEntry(KFileItem(path,mime,buff.st_mode).entry()); + finished(); + return; + } + UDSEntry* entry = findFileEntry(newUrl); + if( entry ){ + statEntry( *entry ); + finished(); + } else error( TDEIO::ERR_DOES_NOT_EXIST, path ); +} + +void tdeio_krarcProtocol::copy (const KURL &url, const KURL &dest, int, bool overwrite) { + KRDEBUG(url.path()); + + // KDE HACK: opening the password dlg in copy causes error for the COPY, and further problems + // that's why encrypted files are not allowed to copy + if( !encrypted && dest.isLocalFile() ) + do { + if( url.fileName() != dest.fileName() ) + break; + + //the file exists and we don't want to overwrite + if ((!overwrite) && ( TQFile( dest.path() ).exists() ) ) { + error(ERR_FILE_ALREADY_EXIST, TQFile::encodeName(dest.path()) ); + return; + }; + + if( !setArcFile( url ) ) { + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + if( newArchiveURL && !initDirDict(url) ){ + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + + UDSEntry* entry = findFileEntry(url); + if( copyCmd.isEmpty() || !entry ) + break; + + TQString file = url.path().mid(arcFile->url().path().length()+1); + + TQString destDir = dest.path( -1 ); + if( !TQDir( destDir ).exists() ) { + int ndx = destDir.findRev( '/' ); + if( ndx != -1 ) + destDir.truncate( ndx+1 ); + } + + TQDir::setCurrent( destDir.local8Bit() ); + + KrShellProcess proc; + proc << copyCmd << convertName( arcFile->url().path(-1) )+" " << convertFileName( file ); + if( arcType == "ace" && TQFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!! + proc << "<" << "/dev/ptmx"; + + infoMessage(i18n("Unpacking %1 ...").arg( url.fileName() ) ); + proc.start(TDEProcess::Block, TDEProcess::AllOutput); + if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) { + error(TDEIO::ERR_COULD_NOT_WRITE, dest.path(-1) + "\n\n" + proc.getErrorMsg() ); + return; + } + if( !TQFileInfo( dest.path(-1) ).exists() ) { + error( TDEIO::ERR_COULD_NOT_WRITE, dest.path(-1) ); + return; + } + + processedSize( KFileItem(*entry,url).size() ); + finished(); + TQDir::setCurrent( "/" ); /* for being able to umount devices after copying*/ + return; + }while( 0 ); + + error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); +} + +void tdeio_krarcProtocol::listDir(const KURL& url){ + KRDEBUG(url.path()); + if( !setArcFile( url ) ) { + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + if( listCmd.isEmpty() ){ + error(ERR_UNSUPPORTED_ACTION, + i18n("Listing directories is not supported for %1 archives").arg(arcType) ); + return; + } + TQString path = url.path(); + if( path.right(1) != "/" ) path = path+"/"; + + // it might be a real dir ! + if( TQFileInfo(path).exists() ){ + if( TQFileInfo(path).isDir() ){ + KURL redir; + redir.setPath( url.path() ); + redirection(redir); + finished(); + } else { // maybe it's an archive ! + error(ERR_IS_FILE,path); + } + return; + } + if( !initDirDict(url) ){ + error( ERR_CANNOT_ENTER_DIRECTORY, url.path()); + return; + } + TQString arcDir = path.mid(arcFile->url().path().length()); + arcDir.truncate(arcDir.findRev("/")); + if(arcDir.right(1) != "/") arcDir = arcDir+"/"; + + UDSEntryList* dirList = dirDict.find(arcDir); + if( dirList == 0 ){ + error(ERR_CANNOT_ENTER_DIRECTORY,url.path()); + return; + } + totalSize(dirList->size()); + listEntries(*dirList); + finished(); +} + +bool tdeio_krarcProtocol::setArcFile(const KURL& url){ + TQString path = url.path(); + time_t currTime = time( 0 ); + archiveChanged = true; + newArchiveURL = true; + // is the file already set ? + if( arcFile && arcFile->url().path(-1) == path.left(arcFile->url().path(-1).length()) ){ + newArchiveURL = false; + // Has it changed ? + KFileItem* newArcFile = new KFileItem(arcFile->url(),TQString(),arcFile->mode()); + if( !newArcFile->cmp( *arcFile ) ){ + delete arcFile; + password = TQString(); + extArcReady = false; + arcFile = newArcFile; + } else { // same old file + delete newArcFile; + archiveChanged = false; + if( encrypted && password.isNull() ) + initArcParameters(); + } + } else { // it's a new file... + extArcReady = false; + if( arcFile ){ + delete arcFile; + password = TQString(); + arcFile = 0L; + } + TQString newPath = path; + if(newPath.right(1) != "/") newPath = newPath+"/"; + for(int pos=0; pos >= 0; pos = newPath.find("/",pos+1)){ + TQFileInfo qfi(newPath.left(pos)); + if( qfi.exists() && !qfi.isDir() ){ + KDE_struct_stat stat_p; + KDE_lstat(newPath.left(pos).local8Bit(),&stat_p); + arcFile = new KFileItem(KURL::fromPathOrURL( newPath.left(pos) ),TQString(),stat_p.st_mode); + break; + } + } + if( !arcFile ){ + error( ERR_DOES_NOT_EXIST,path ); + return false; // file not found + } + } + + /* FIX: file change can only be detected if the timestamp between the two consequent + changes is more than 1s. If the archive is continuously changing (check: move files + inside the archive), krarc may erronously think, that the archive file is unchanged, + because the timestamp is the same as the previous one. This situation can only occur + if the modification time equals with the current time. While this condition is true, + we can say, that the archive is changing, so content reread is always necessary + during that period. */ + if( archiveChanging ) + archiveChanged = true; + archiveChanging = ( currTime == arcFile->time( UDS_MODIFICATION_TIME ) ); + + arcPath = arcFile->url().path(-1); + arcType = detectArchive( encrypted, arcPath ); + + if( arcType == "tbz" ) + arcType = "bzip2"; + else if( arcType == "tgz" ) + arcType = "gzip"; + else if( arcType == "txz" ) + arcType = "xz"; + + if( arcType.isEmpty() ) { + arcType = arcFile->mimetype(); + arcType = arcType.mid(arcType.findRev("-")+1); + + if( arcType == "jar" ) + arcType = "zip"; + } + + return initArcParameters(); +} + +bool tdeio_krarcProtocol::initDirDict(const KURL&url, bool forced){ + // set the archive location + //if( !setArcFile(url.path()) ) return false; + // no need to rescan the archive if it's not changed + if( !archiveChanged && !forced ) return true; + extArcReady = false; + + if( !setArcFile( url ) ) + return false; /* if the archive was changed refresh the file information */ + + // write the temp file + KrShellProcess proc; + KTempFile temp( TQString(), "tmp" ); + temp.setAutoDelete(true); + if (arcType != "bzip2" && arcType != "xz") { + if( arcType == "rpm" ) + proc << listCmd << convertName( arcPath ) <<" > " << temp.name(); + else + proc << listCmd << convertName( arcFile->url().path(-1) ) <<" > " << temp.name(); + if( arcType == "ace" && TQFile( "/dev/ptmx" ).exists() ) // Don't remove, unace crashes if missing!!! + proc << "<" << "/dev/ptmx"; + proc.start(TDEProcess::Block,TDEProcess::AllOutput); + if( !proc.normalExit() || !checkStatus( proc.exitStatus() ) ) return false; + } + // clear the dir dictionary + dirDict.clear(); + + // add the "/" directory + UDSEntryList* root = new UDSEntryList(); + dirDict.insert("/",root); + // and the "/" UDSEntry + UDSEntry entry; + UDSAtom atom; + atom.m_uds = UDS_NAME; + atom.m_str = "."; + entry.append(atom); + mode_t mode = parsePermString("drwxr-xr-x"); + atom.m_uds = UDS_FILE_TYPE; + atom.m_long = mode & S_IFMT; // keep file type only + entry.append( atom ); + atom.m_uds = UDS_ACCESS; + atom.m_long = mode & 07777; // keep permissions only + entry.append( atom ); + + root->append(entry); + + if (arcType == "bzip2" || arcType == "xz"){ + KRDEBUG("Got me here..."); + parseLine(0,"",temp.file()); + return true; + } + + // parse the temp file + temp.file()->open(IO_ReadOnly); + char buf[1000]; + TQString line; + + int lineNo = 0; + bool invalidLine = false; + // the rar list is started with a ------ line. + if(arcType == "rar" || arcType == "arj" || arcType == "lha" || arcType == "7z" ){ + while(temp.file()->readLine(buf,1000) != -1){ + line = TQString::fromLocal8Bit(buf); + if( line.startsWith("----------") ) break; + } + } + while(temp.file()->readLine(buf,1000) != -1) { + line = TQString::fromLocal8Bit(buf); + if( arcType == "rar" ) { + // the rar list is ended with a ------ line. + if( line.startsWith("----------") ) { + invalidLine = !invalidLine; + continue; + } + if( invalidLine ) + continue; + else{ + temp.file()->readLine(buf,1000); + line = line+TQString::fromLocal8Bit(buf); + if( line[0]=='*' ) // encrypted archives starts with '*' + line[0]=' '; + } + } + if( arcType == "ace" ) { + // the ace list begins with a number. + if( !line[0].isDigit() ) continue; + } + if( arcType == "arj" ) { + // the arj list is ended with a ------ line. + if( line.startsWith("----------") ) { + invalidLine = !invalidLine; + continue; + } + if( invalidLine ) + continue; + else { + temp.file()->readLine(buf,1000); + line = line+TQString::fromLocal8Bit(buf); + temp.file()->readLine(buf,1000); + line = line+TQString::fromLocal8Bit(buf); + temp.file()->readLine(buf,1000); + line = line+TQString::fromLocal8Bit(buf); + } + } + if( arcType == "lha" || arcType == "7z" ) { + // the arj list is ended with a ------ line. + if( line.startsWith("----------") ) break; + } + parseLine(lineNo++,line.stripWhiteSpace(),temp.file()); + } + // close and delete our file + temp.file()->close(); + + archiveChanged = false; + return true; +} + +TQString tdeio_krarcProtocol::findArcDirectory(const KURL& url){ + TQString path = url.path(); + if( path.right(1) == "/" ) path.truncate(path.length()-1); + + if( !initDirDict(url) ){ + return TQString(); + } + TQString arcDir = path.mid(arcFile->url().path().length()); + arcDir.truncate(arcDir.findRev("/")); + if(arcDir.right(1) != "/") arcDir = arcDir+"/"; + + return arcDir; +} + +UDSEntry* tdeio_krarcProtocol::findFileEntry(const KURL& url){ + TQString arcDir = findArcDirectory(url); + if( arcDir.isEmpty() ) return 0; + + UDSEntryList* dirList = dirDict.find(arcDir); + if( !dirList ){ + return 0; + } + TQString name = url.path(); + if( arcFile->url().path(-1) == url.path(-1) ) name = "."; // the "/" case + else{ + if( name.right(1) == "/" ) name.truncate(name.length()-1); + name = name.mid(name.findRev("/")+1); + } + + UDSEntryList::iterator entry; + UDSEntry::iterator atom; + + for ( entry = dirList->begin(); entry != dirList->end(); ++entry ){ + for( atom = (*entry).begin(); atom != (*entry).end(); ++atom ){ + if( (*atom).m_uds == UDS_NAME ){ + if((*atom).m_str == name){ + return &(*entry); + } else break; + } + } + } + return 0; +} + +TQString tdeio_krarcProtocol::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; +} + +mode_t tdeio_krarcProtocol::parsePermString(TQString perm){ + mode_t mode=0; + // file type + if(perm[0] == 'd') mode |= S_IFDIR; + if(perm[0] == 'l') mode |= S_IFLNK; + if(perm[0] == '-') mode |= S_IFREG; + // owner permissions + if(perm[1] != '-') mode |= S_IRUSR; + if(perm[2] != '-') mode |= S_IWUSR; + if(perm[3] != '-') mode |= S_IXUSR; + // group permissions + if(perm[4] != '-') mode |= S_IRGRP; + if(perm[5] != '-') mode |= S_IWGRP; + if(perm[6] != '-') mode |= S_IXGRP; + // other permissions + if(perm[7] != '-') mode |= S_IROTH; + if(perm[8] != '-') mode |= S_IWOTH; + if(perm[9] != '-') mode |= S_IXOTH; + + return mode; +} + +UDSEntryList* tdeio_krarcProtocol::addNewDir(TQString path){ + UDSEntryList* dir; + + // check if the current dir exists + dir = dirDict.find(path); + if(dir != 0) return dir; // dir exists- return it ! + + // set dir to the parent dir + dir = addNewDir(path.left(path.findRev("/",-2)+1)); + + // add a new entry in the parent dir + TQString name = path.mid(path.findRev("/",-2)+1); + name = name.left(name.length()-1); + + UDSEntry entry; + UDSAtom atom; + atom.m_uds = UDS_NAME; + atom.m_str = name; + entry.append(atom); + + mode_t mode = parsePermString("drwxr-xr-x"); + + atom.m_uds = UDS_FILE_TYPE; + atom.m_long = mode & S_IFMT; // keep file type only + entry.append( atom ); + + atom.m_uds = UDS_ACCESS; + atom.m_long = mode & 07777; // keep permissions only + entry.append( atom ); + + atom.m_uds = UDS_SIZE; + atom.m_long = 0; + entry.append( atom ); + + atom.m_uds = UDS_MODIFICATION_TIME; + atom.m_long = arcFile->time(UDS_MODIFICATION_TIME); + entry.append( atom ); + + dir->append(entry); + + // create a new directory entry and add it.. + dir = new UDSEntryList(); + dirDict.insert(path,dir); + + return dir; +} + +void tdeio_krarcProtocol::parseLine(int lineNo, TQString line, TQFile*) { + UDSEntryList* dir; + UDSEntry entry; + UDSAtom atom; + + TQString owner = TQString(); + TQString group = TQString(); + TQString symlinkDest = TQString(); + TQString perm = TQString(); + mode_t mode = 0666; + size_t size = 0; + time_t time = ::time(0); + TQString fullName = TQString(); + + if(arcType == "zip"){ + // permissions + perm = nextWord(line); + // ignore the next 2 fields + nextWord(line); nextWord(line); + // size + size = nextWord(line).toLong(); + // ignore the next 2 fields + nextWord(line);nextWord(line); + // date & time + TQString d = nextWord(line); + TQDate qdate(d.mid(0,4).toInt(),d.mid(4,2).toInt(),d.mid(6,2).toInt()); + TQTime qtime(d.mid(9,2).toInt(),d.mid(11,2).toInt(),d.mid(13,2).toInt()); + time = TQDateTime(qdate,qtime).toTime_t(); + // full name + fullName = nextWord(line,'\n'); + + if(perm.length() != 10) + perm = (perm.at(0)=='d' || fullName.endsWith( "/" )) ? "drwxr-xr-x" : "-rw-r--r--" ; + mode = parsePermString(perm); + } + if(arcType == "rar") { + // full name + fullName = nextWord(line,'\n'); + // size + size = nextWord(line).toLong(); + // ignore the next 2 fields + nextWord(line); nextWord(line); + // date & time + TQString d = nextWord(line); + int year = 1900 + d.mid(6,2).toInt(); + if( year < 1930 ) year+=100; + TQDate qdate( year, d.mid(3,2).toInt(), d.mid(0,2).toInt() ); + TQString t = nextWord(line); + TQTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),0); + time = TQDateTime(qdate,qtime).toTime_t(); + // permissions + perm = nextWord(line); + + if( perm.length() == 7 ) // windows rar permission format + { + bool isDir = ( perm.at(1).lower() == 'd' ); + bool isReadOnly = ( perm.at(2).lower() == 'r' ); + + perm = isDir ? "drwxr-xr-x" : "-rw-r--r--"; + + if( isReadOnly ) + perm.at( 2 ) = '-'; + } + + if(perm.length() != 10) perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ; + mode = parsePermString(perm); + } + if(arcType == "arj"){ + nextWord(line); + // full name + fullName = nextWord(line,'\n'); + // ignore the next 2 fields + nextWord(line); nextWord(line); + // size + size = nextWord(line).toLong(); + // ignore the next 2 fields + nextWord(line); nextWord(line); + // date & time + TQString d = nextWord(line); + int year = 1900 + d.mid(0,2).toInt(); + if( year < 1930 ) year+=100; + TQDate qdate( year, d.mid(3,2).toInt(), d.mid(6,2).toInt() ); + TQString t = nextWord(line); + TQTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),0); + time = TQDateTime(qdate,qtime).toTime_t(); + // permissions + perm = nextWord(line); + if(perm.length() != 10) perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ; + mode = parsePermString(perm); + } + if(arcType == "rpm"){ + // full name + fullName = nextWord(line); + // size + size = nextWord(line).toULong(); + // date & time + time = nextWord(line).toULong(); + // next field is md5sum, ignore it + nextWord(line); + // permissions + mode = nextWord(line).toULong(0,8); + // Owner & Group + owner = nextWord(line); + group = nextWord(line); + // symlink destination + if( S_ISLNK(mode) ){ + // ignore the next 3 fields + nextWord(line); nextWord(line); nextWord(line); + symlinkDest = nextWord(line); + } + } + if( arcType == "gzip" ){ + if( !lineNo ) return; //ignore the first line + // first field is uncompressed size - ignore it + nextWord(line); + // size + size = nextWord(line).toULong(); + // ignore the next field + nextWord(line); + // full name + fullName = nextWord(line); + fullName = fullName.mid(fullName.findRev("/")+1); + } + if( arcType == "bzip2" ){ + // There is no way to list bzip2 files, so we take our information from + // the archive itself... + fullName = arcFile->name(); + if( fullName.endsWith("bz2") ) fullName.truncate(fullName.length()-4); + mode = arcFile->mode(); + size = arcFile->size(); + } + if(arcType == "lha"){ + // permissions + perm = nextWord(line); + if(perm.length() != 10) perm = (perm.at(0)=='d')? "drwxr-xr-x" : "-rw-r--r--" ; + mode = parsePermString(perm); + // ignore the next field + nextWord(line); + // size + size = nextWord(line).toLong(); + // ignore the next field + nextWord(line); + // date & time + int month = (TQStringList::split(',', "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec")).findIndex( nextWord(line) ) + 1; + int day = nextWord(line).toInt(); + int year = TQDate::currentDate().year(); + TQString third = nextWord(line); + TQTime qtime; + + if( third.contains(":" ) ) + qtime = TQTime::fromString( third ); + else + year = third.toInt(); + + TQDate qdate(year, month, day ); + + time = TQDateTime(qdate, qtime).toTime_t(); + // full name + fullName = nextWord(line,'\n'); + } + if(arcType == "ace"){ + // date & time + TQString d = nextWord(line); + int year = 1900 + d.mid(6,2).toInt(); + if( year < 1930 ) year+=100; + TQDate qdate( year, d.mid(3,2).toInt(), d.mid(0,2).toInt() ); + TQString t = nextWord(line); + TQTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),0); + time = TQDateTime(qdate,qtime).toTime_t(); + // ignore the next field + nextWord(line); + // size + size = nextWord(line).toLong(); + // ignore the next field + nextWord(line); + // full name + fullName = nextWord(line,'\n'); + if( fullName[ 0 ] == '*' ) // encrypted archives starts with '*' + fullName = fullName.mid( 1 ); + } + if( arcType == "deb" ){ + // permissions + perm = nextWord( line ); + mode = parsePermString( perm ); + // Owner & Group + owner = nextWord( line,'/' ); + group = nextWord( line ).mid(1); + // size + size = nextWord( line ).toLong(); + // date & time + TQString d = nextWord( line ); + TQDate qdate( d.mid( 0, 4 ).toInt(), d.mid( 5, 2 ).toInt(), d.mid( 8, 2 ).toInt() ); + TQString t = nextWord( line ); + TQTime qtime( t.mid( 0, 2 ).toInt(), t.mid( 3, 2 ).toInt(), 0 ); + time = TQDateTime( qdate, qtime ).toTime_t(); + // full name + fullName = nextWord( line, '\n' ).mid( 1 ); + //if ( fullName.right( 1 ) == "/" ) return; + if( fullName.contains("->") ){ + symlinkDest = fullName.mid(fullName.find("->")+2); + fullName = fullName.left(fullName.find("->")-1); + } + } + if(arcType == "7z"){ + // date & time + TQString d = nextWord(line); + TQDate qdate( d.mid(0,4).toInt(), d.mid(5,2).toInt(), d.mid(8,2).toInt() ); + TQString t = nextWord(line); + TQTime qtime(t.mid(0,2).toInt(),t.mid(3,2).toInt(),t.mid(6,2).toInt() ); + time = TQDateTime(qdate,qtime).toTime_t(); + + // permissions + perm = nextWord(line); + bool isDir = ( perm.at(0).lower() == 'd' ); + bool isReadOnly = ( perm.at(1).lower() == 'r' ); + perm = isDir ? "drwxr-xr-x" : "-rw-r--r--"; + if( isReadOnly ) + perm.at( 2 ) = '-'; + + mode = parsePermString(perm); + + // size + size = nextWord(line).toLong(); + + // ignore the next 15 characters + line = line.mid( 15 ); + + // full name + fullName = nextWord(line,'\n'); + } + if (arcType == "xz") { + fullName = arcFile->name(); + if (fullName.endsWith("xz")) { + fullName.truncate(fullName.length() - 3); + } + mode = arcFile->mode(); + size = arcFile->size(); + } + + if( fullName.right(1) == "/" ) fullName = fullName.left(fullName.length()-1); + if( !fullName.startsWith("/") ) fullName = "/"+fullName; + TQString path = fullName.left(fullName.findRev("/")+1); + // set/create the directory UDSEntryList + dir = dirDict.find(path); + if(dir == 0) dir = addNewDir(path); + TQString name = fullName.mid(fullName.findRev("/")+1); + // file name + atom.m_uds = UDS_NAME; + atom.m_str = name; + entry.append(atom); + // file type + atom.m_uds = UDS_FILE_TYPE; + atom.m_long = mode & S_IFMT; // keep file type only + entry.append( atom ); + // file permissions + atom.m_uds = UDS_ACCESS; + atom.m_long = mode & 07777; // keep permissions only + entry.append( atom ); + // file size + atom.m_uds = UDS_SIZE; + atom.m_long = size; + entry.append( atom ); + // modification time + atom.m_uds = UDS_MODIFICATION_TIME; + atom.m_long = time; + entry.append( atom ); + // link destination + if( !symlinkDest.isEmpty() ){ + atom.m_uds = UDS_LINK_DEST; + atom.m_str = symlinkDest; + entry.append( atom ); + } + if( S_ISDIR(mode) ){ + fullName=fullName+"/"; + if(dirDict.find(fullName) == 0) + dirDict.insert(fullName,new UDSEntryList()); + else { + // try to overwrite an existing entry + UDSEntryList::iterator entryIt; + UDSEntry::iterator atomIt; + + for ( entryIt = dir->begin(); entryIt != dir->end(); ++entryIt ) + for( atomIt = (*entryIt).begin(); atomIt != (*entryIt).end(); ++atomIt ) + if( (*atomIt).m_uds == UDS_NAME ) + if((*atomIt).m_str == name) { + for( atomIt = (*entryIt).begin(); atomIt != (*entryIt).end(); ++atomIt ) { + switch( (*atomIt).m_uds ) { + case UDS_MODIFICATION_TIME: + (*atomIt).m_long = time; + break; + case UDS_ACCESS: + (*atomIt).m_long = mode & 07777; + break; + } + } + return; + } + return; // there is alreay an entry for this directory + } + } + + // multi volume archives can add a file twice, use only one + UDSEntryList::iterator dirEntryIt; + UDSEntry::iterator dirAtomIt; + for ( dirEntryIt = dir->begin(); dirEntryIt != dir->end(); ++dirEntryIt ) + for( dirAtomIt = (*dirEntryIt).begin(); dirAtomIt != (*dirEntryIt).end(); ++dirAtomIt ) + if( (*dirAtomIt).m_uds == UDS_NAME && (*dirAtomIt).m_str == name ) + return; + + dir->append(entry); +} + +bool tdeio_krarcProtocol::initArcParameters() { + KRDEBUG("arcType: "<<arcType); + + if(arcType == "zip"){ + cmd = fullPathName( "unzip" ); + listCmd = fullPathName( "unzip" ) + " -ZTs-z-t-h "; + getCmd = fullPathName( "unzip" ) + " -p "; + copyCmd = fullPathName( "unzip" ) + " -jo "; + + if( TDEStandardDirs::findExe( "zip" ).isEmpty() ) { + delCmd = TQString(); + putCmd = TQString(); + } else { + delCmd = fullPathName( "zip" ) + " -d "; + putCmd = fullPathName( "zip" ) + " -ry "; + } + + if( !getPassword().isEmpty() ) { + getCmd += "-P '"+password+"' "; + copyCmd += "-P '"+password+"' "; + putCmd += "-P '"+password+"' "; + } + } else if (arcType == "rar") { + if( TDEStandardDirs::findExe( "rar" ).isEmpty() ) { + cmd = fullPathName( "unrar" ); + listCmd = fullPathName( "unrar" ) + " -c- -v v "; + getCmd = fullPathName( "unrar" ) + " p -ierr -idp -c- -y "; + copyCmd = fullPathName( "unrar" ) + " e -y "; + delCmd = TQString(); + putCmd = TQString(); + } else { + cmd = fullPathName( "rar" ); + listCmd = fullPathName( "rar" ) + " -c- -v v "; + getCmd = fullPathName( "rar" ) + " p -ierr -idp -c- -y "; + copyCmd = fullPathName( "rar" ) + " e -y "; + delCmd = fullPathName( "rar" ) + " d "; + putCmd = fullPathName( "rar" ) + " -r a "; + } + if( !getPassword().isEmpty() ) { + getCmd += "-p'"+password+"' "; + listCmd += "-p'"+password+"' "; + copyCmd += "-p'"+password+"' "; + if( !putCmd.isEmpty() ) { + putCmd += "-p'"+password+"' "; + delCmd += "-p'"+password+"' "; + } + } + } else if(arcType == "rpm") { + cmd = fullPathName( "rpm" ); + listCmd = fullPathName( "rpm" ) + " --dump -lpq "; + getCmd = fullPathName( "cpio" ) + " --force-local --no-absolute-filenames -iuvdF"; + delCmd = TQString(); + putCmd = TQString(); + copyCmd = TQString(); + } else if(arcType == "gzip") { + cmd = fullPathName( "gzip" ); + listCmd = fullPathName( "gzip" ) + " -l"; + getCmd = fullPathName( "gzip" ) + " -dc"; + copyCmd = TQString(); + delCmd = TQString(); + putCmd = TQString(); + } else if(arcType == "bzip2") { + cmd = fullPathName( "bzip2" ); + listCmd = fullPathName( "bzip2" ); + getCmd = fullPathName( "bzip2" ) + " -dc"; + copyCmd = TQString(); + delCmd = TQString(); + putCmd = TQString(); + } else if(arcType == "arj"){ + cmd = fullPathName( "arj" ); + listCmd = fullPathName( "arj" ) + " v -y -v "; + getCmd = fullPathName( "arj" ) + " -jyov -v e "; + copyCmd = fullPathName( "arj" ) + " -jyov -v e "; + delCmd = fullPathName( "arj" ) + " d "; + putCmd = fullPathName( "arj" ) + " -r a "; + if( !getPassword().isEmpty() ) { + getCmd += "-g'"+password+"' "; + copyCmd += "-g'"+password+"' "; + putCmd += "-g'"+password+"' "; + } + } else if(arcType == "lha") { + cmd = fullPathName( "lha" ); + listCmd = fullPathName( "lha" ) + " l "; + getCmd = fullPathName( "lha" ) + " pq "; + copyCmd = fullPathName( "lha" ) + " eif "; + delCmd = fullPathName( "lha" ) + " d "; + putCmd = fullPathName( "lha" ) + " a "; + } else if(arcType == "ace") { + cmd = fullPathName( "unace" ); + listCmd = fullPathName( "unace" ) + " v"; + getCmd = fullPathName( "unace" ) + " e -o "; + copyCmd = fullPathName( "unace" ) + " e -o "; + delCmd = TQString(); + putCmd = TQString(); + if( !getPassword().isEmpty() ) { + getCmd += "-p'"+password+"' "; + copyCmd += "-p'"+password+"' "; + } + } else if ( arcType == "deb" ) { + cmd = fullPathName("dpkg"); + listCmd = fullPathName("dpkg")+" -c"; + getCmd = fullPathName("tar")+" xvf "; + copyCmd = TQString(); + delCmd = TQString(); + putCmd = TQString(); + } else if (arcType == "7z") { + cmd = fullPathName( "7z" ); + if( TDEStandardDirs::findExe(cmd).isEmpty() ) + cmd = fullPathName( "7za" ); + + listCmd = cmd + " l -y "; + getCmd = cmd + " e -y "; + copyCmd = cmd + " e -y "; + delCmd = cmd + " d -y "; + putCmd = cmd + " a -y "; + if( !getPassword().isEmpty() ) { + getCmd += "-p'"+password+"' "; + listCmd += "-p'"+password+"' "; + copyCmd += "-p'"+password+"' "; + if( !putCmd.isEmpty() ) { + putCmd += "-p'"+password+"' "; + delCmd += "-p'"+password+"' "; + } + } + } else if (arcType == "xz") { + cmd = fullPathName("xz"); + listCmd = fullPathName("xz"); + getCmd = fullPathName("xz") + "-dc"; + copyCmd = TQString(); + delCmd = TQString(); + putCmd = TQString(); + } else { + cmd = TQString(); + listCmd = TQString(); + getCmd = TQString(); + copyCmd = TQString(); + delCmd = TQString(); + putCmd = TQString(); + } + + if( TDEStandardDirs::findExe(cmd).isEmpty() ){ + error( TDEIO::ERR_CANNOT_LAUNCH_PROCESS, + cmd+ + i18n("\nMake sure that the %1 binary are installed properly on your system.").arg(cmd)); + KRDEBUG("Failed to find cmd: " << cmd); + return false; + } + return true; +} + +bool tdeio_krarcProtocol::checkStatus( int exitCode ) { + KRDEBUG( exitCode ); + + if( arcType == "zip" || arcType == "rar" || arcType == "7z" ) + return exitCode == 0 || exitCode == 1; + else if( arcType == "ace" || arcType == "bzip2" || arcType == "lha" || arcType == "rpm" || arcType == "arj" ) + return exitCode == 0; + else if( arcType == "gzip"|| arcType == "xz" ) + return exitCode == 0 || exitCode == 2; + else + return exitCode == 0; +} + +struct AutoDetectParams { + TQString type; + int location; + TQString detectionString; +}; + +TQString tdeio_krarcProtocol::detectArchive( bool &encrypted, TQString fileName ) { + static AutoDetectParams autoDetectParams[] = {{"zip", 0, "PK\x03\x04"}, + {"rar", 0, "Rar!\x1a" }, + {"arj", 0, "\x60\xea" }, + {"rpm", 0, "\xed\xab\xee\xdb"}, + {"ace", 7, "**ACE**" }, + {"bzip2",0, "\x42\x5a\x68\x39\x31" }, + {"gzip", 0, "\x1f\x8b"}, + {"deb", 0, "!<arch>\ndebian-binary " }, + {"7z", 0, "7z\xbc\xaf\x27\x1c" }, + {"xz", 0, "\xfd" "7zXZ\x00"} }; + static int autoDetectElems = sizeof( autoDetectParams ) / sizeof( AutoDetectParams ); + + encrypted = false; + + TQFile arcFile( fileName ); + if ( arcFile.open( IO_ReadOnly ) ) { + char buffer[ 1024 ]; + long sizeMax = arcFile.readBlock( buffer, sizeof( buffer ) ); + arcFile.close(); + + for( int i=0; i < autoDetectElems; i++ ) { + TQString detectionString = autoDetectParams[ i ].detectionString; + int location = autoDetectParams[ i ].location; + + int endPtr = detectionString.length() + location; + if( endPtr > sizeMax ) + continue; + + unsigned int j=0; + for(; j != detectionString.length(); j++ ) { + if( detectionString[ j ] == '?' ) + continue; + if( buffer[ location + j ] != detectionString[ j ] ) + break; + } + + if( j == detectionString.length() ) { + TQString type = autoDetectParams[ i ].type; + if( type == "bzip2" || type == "gzip" ) { + KTar tapeArchive( fileName ); + if( tapeArchive.open( IO_ReadOnly ) ) { + tapeArchive.close(); + if( type == "bzip2" ) + type = "tbz"; + else + type = "tgz"; + } + } + else if( type == "zip" ) + encrypted = (buffer[6] & 1); + else if( type == "arj" ) { + if( sizeMax > 4 ) { + long headerSize = ((unsigned char *)buffer)[ 2 ] + 256*((unsigned char *)buffer)[ 3 ]; + long fileHeader = headerSize + 10; + if( fileHeader + 9 < sizeMax && buffer[ fileHeader ] == (char)0x60 && buffer[ fileHeader + 1 ] == (char)0xea ) + encrypted = (buffer[ fileHeader + 8 ] & 1 ); + } + } + else if( type == "rar" ) { + if( sizeMax > 13 && buffer[ 9 ] == (char)0x73 ) { + if( buffer[ 10 ] & 0x80 ) { // the header is encrypted? + encrypted = true; + } else { + long offset = 7; + long mainHeaderSize = ((unsigned char *)buffer)[ offset+5 ] + 256*((unsigned char *)buffer)[ offset+6 ]; + offset += mainHeaderSize; + while( offset + 10 < sizeMax ) { + long headerSize = ((unsigned char *)buffer)[ offset+5 ] + 256*((unsigned char *)buffer)[ offset+6 ]; + bool isDir = (buffer[ offset+7 ] == '\0' ) && (buffer[ offset+8 ] == '\0' ) && + (buffer[ offset+9 ] == '\0' ) && (buffer[ offset+10 ] == '\0' ); + + if( buffer[ offset + 2 ] != (char)0x74 ) + break; + if( !isDir ) { + encrypted = ( buffer[ offset + 3 ] & 4 ) != 0; + break; + } + offset += headerSize; + } + } + } + } + else if( type == "ace" ) { + long offset = 0; + long mainHeaderSize = ((unsigned char *)buffer)[ offset+2 ] + 256*((unsigned char *)buffer)[ offset+3 ] + 4; + offset += mainHeaderSize; + while( offset + 10 < sizeMax ) { + long headerSize = ((unsigned char *)buffer)[ offset+2 ] + 256*((unsigned char *)buffer)[ offset+3 ] + 4; + bool isDir = (buffer[ offset+11 ] == '\0' ) && (buffer[ offset+12 ] == '\0' ) && + (buffer[ offset+13 ] == '\0' ) && (buffer[ offset+14 ] == '\0' ); + + if( buffer[ offset + 4 ] != (char)0x01 ) + break; + if( !isDir ) { + encrypted = ( buffer[ offset + 6 ] & 64 ) != 0; + break; + } + offset += headerSize; + } + } + else if( type == "7z" ) { + if( encryptedArchPath == fileName ) + encrypted = true; + else { // we try to find whether the 7z archive is encrypted + // this is hard as the headers are also compresseds + TQString tester = fullPathName( "7z" ); + if( TDEStandardDirs::findExe( tester ).isEmpty() ) { + tester = fullPathName( "7za" ); + if( TDEStandardDirs::findExe( tester ).isEmpty() ) { + return type; + } + } + + TQString testCmd = tester + " t -y "; + lastData = encryptedArchPath = ""; + + KrShellProcess proc; + proc << testCmd << convertName( fileName ); + connect( &proc, TQ_SIGNAL( receivedStdout(TDEProcess*,char*,int) ), + this, TQ_SLOT( checkOutputForPassword( TDEProcess*,char*,int ) ) ); + proc.start(TDEProcess::Block,TDEProcess::AllOutput); + encrypted = this->encrypted; + + if( encrypted ) + encryptedArchPath = fileName; + } + } + return type; + } + } + + if( sizeMax >= 512 ) { + /* checking if it's a tar file */ + unsigned checksum = 32*8; + char chksum[ 9 ]; + for( int i=0; i != 512; i++ ) + checksum += ((unsigned char *)buffer)[ i ]; + for( int i=148; i != 156; i++ ) + checksum -= ((unsigned char *)buffer)[ i ]; + sprintf( chksum, "0%o", checksum ); + if( !memcmp( buffer + 148, chksum, strlen( chksum ) ) ) { + int k = strlen( chksum ); + for(; k < 8; k++ ) + if( buffer[148+k] != 0 && buffer[148+k] != 32 ) + break; + if( k==8 ) + return "tar"; + } + } + } + + if (fileName.endsWith(".tar.xz")) + { + return "txz"; + } + else if (fileName.endsWith(".xz")) + { + return "xz"; + } + + return TQString(); +} + +void tdeio_krarcProtocol::checkOutputForPassword( TDEProcess *proc,char *buf,int len ) { + TQByteArray d(len); + d.setRawData(buf,len); + TQString data = TQString( d ); + d.resetRawData(buf,len); + + TQString checkable = lastData + data; + + TQStringList lines = TQStringList::split( '\n', checkable ); + lastData = lines[ lines.count() - 1 ]; + for( unsigned i=0; i != lines.count(); i++ ) { + TQString line = lines[ i ].stripWhiteSpace().lower(); + int ndx = line.find( "testing" ); + if( ndx >=0 ) + line.truncate( ndx ); + if( line.isEmpty() ) + continue; + + if( line.contains( "password" ) && line.contains( "enter" ) ) { + KRDEBUG( "Encrypted 7z archive found!" ); + encrypted = true; + proc->kill(); + } + } +} + +void tdeio_krarcProtocol::invalidatePassword() { + KRDEBUG( arcFile->url().path(-1) + "/" ); + + if( !encrypted ) + return; + + TDEIO::AuthInfo authInfo; + authInfo.caption= i18n( "Krarc Password Dialog" ); + authInfo.username= "archive"; + authInfo.readOnly = true; + authInfo.keepPassword = true; + authInfo.verifyPath = true; + TQString fileName = arcFile->url().path(-1); + authInfo.url = KURL::fromPathOrURL( "/" ); + authInfo.url.setHost( fileName /*.replace('/','_')*/ ); + authInfo.url.setProtocol( "krarc" ); + + password = TQString(); + + cacheAuthentication( authInfo ); +} + +TQString tdeio_krarcProtocol::getPassword() { + KRDEBUG( encrypted ); + + if( !password.isNull() ) + return password; + if( !encrypted ) + return (password = "" ); + + TDEIO::AuthInfo authInfo; + authInfo.caption= i18n( "Krarc Password Dialog" ); + authInfo.username= "archive"; + authInfo.readOnly = true; + authInfo.keepPassword = true; + authInfo.verifyPath = true; + TQString fileName = arcFile->url().path(-1); + authInfo.url = KURL::fromPathOrURL( "/" ); + authInfo.url.setHost( fileName /*.replace('/','_')*/ ); + authInfo.url.setProtocol( "krarc" ); + + if( checkCachedAuthentication( authInfo ) && !authInfo.password.isNull() ) { + KRDEBUG( authInfo.password ); + return ( password = authInfo.password ); + } + + authInfo.password = TQString(); + + if ( openPassDlg( authInfo, i18n("Accessing the file requires password.") ) && !authInfo.password.isNull() ) { + KRDEBUG( authInfo.password ); + return ( password = authInfo.password ); + } + + KRDEBUG( password ); + return password; +} + +TQString tdeio_krarcProtocol::fullPathName( TQString name ) { + TQString supposedName = krConfig->readEntry( name, name ); + if( supposedName.isEmpty() ) + supposedName = name; + return escape( supposedName ); +} + +TQString tdeio_krarcProtocol::convertFileName( TQString name ) { + if( arcType == "zip" ) + name = name.replace( "[", "[[]" ); + return convertName( name ); +} + +TQString tdeio_krarcProtocol::convertName( TQString name ) { + if( !name.contains( '\'' ) ) + return "'" + name + "'"; + if( !name.contains( '"' ) && !name.contains( '$' ) ) + return "\"" + name + "\""; + return escape( name ); +} + +TQString tdeio_krarcProtocol::escape( TQString name ) { + const TQString evilstuff = "\\\"'`()[]{}!?;$&<>| "; // stuff that should get escaped + + for ( unsigned int i = 0; i < evilstuff.length(); ++i ) + name.replace( evilstuff[ i ], (TQString("\\") + evilstuff[ i ]) ); + + return name; +} + +#include "krarc.moc" diff --git a/src/krArc/krarc.h b/src/krArc/krarc.h new file mode 100644 index 0000000..6b9ca6c --- /dev/null +++ b/src/krArc/krarc.h @@ -0,0 +1,144 @@ +/*************************************************************************** + krarc.h + ------------------- + begin : Sat Jun 14 14:42:49 IDT 2003 + copyright : (C) 2003 by Rafi Yanai & Shie Erlich + email : yanai@users.sf.net + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef __krarc_h__ +#define __krarc_h__ + +#include <tqstring.h> +#include <tqcstring.h> +#include <tqdict.h> +#include <tqfile.h> +#include <sys/types.h> + +#include <kurl.h> +#include <tdeio/global.h> +#include <tdeio/slavebase.h> +#include <kprocess.h> + +class TDEProcess; +class KFileItem; +class TQCString; + +class tdeio_krarcProtocol : public TQObject, public TDEIO::SlaveBase { +TQ_OBJECT + +public: + tdeio_krarcProtocol(const TQCString &pool_socket, const TQCString &app_socket); + virtual ~tdeio_krarcProtocol(); + virtual void stat( const KURL & url ); + virtual void get(const KURL& url); + virtual void put(const KURL& url,int permissions,bool overwrite,bool resume); + virtual void mkdir(const KURL& url,int permissions); + virtual void listDir(const KURL& url); + virtual void del(KURL const & url, bool isFile); + virtual void copy (const KURL &src, const KURL &dest, int permissions, bool overwrite); + +public slots: + void receivedData(TDEProcess* proc,char* buf,int len); + void checkOutputForPassword( TDEProcess*,char*,int ); + +protected: + virtual bool initDirDict(const KURL& url,bool forced = false); + virtual bool initArcParameters(); + TQString detectArchive( bool &encrypted, TQString fileName ); + virtual void parseLine(int lineNo, TQString line, TQFile* temp); + virtual bool setArcFile(const KURL& url); + virtual TQString getPassword(); + virtual void invalidatePassword(); + + // archive specific commands + TQString cmd; ///< the archiver name. + TQString listCmd; ///< list files. + TQString getCmd; ///< unpack files command. + TQString delCmd; ///< delete files command. + TQString putCmd; ///< add file command. + TQString copyCmd; ///< copy to file command. + +private: + void get(const KURL& url, int tries); + /** checks if the exit code is OK. */ + bool checkStatus( int exitCode ); + /** service function for parseLine. */ + TQString nextWord(TQString &s,char d=' '); + /** translate permittion string to mode_t. */ + mode_t parsePermString(TQString perm); + /** return the name of the directory inside the archive. */ + TQString findArcDirectory(const KURL& url); + /** find the UDSEntry of a file in a directory. */ + TDEIO::UDSEntry* findFileEntry(const KURL& url); + /** add a new directory (file list container). */ + TDEIO::UDSEntryList* addNewDir(TQString path); + TQString fullPathName( TQString name ); + TQString convertFileName( TQString name ); + static TQString convertName( TQString name ); + static TQString escape( TQString name ); + + TQDict<TDEIO::UDSEntryList> dirDict; //< the directoris data structure. + bool encrypted; //< tells whether the archive is encrypted + bool archiveChanged; //< true if the archive was changed. + bool archiveChanging; //< true if the archive is currently changing. + bool newArchiveURL; //< true if new archive was entered for the protocol + TDEIO::filesize_t decompressedLen; //< the number of the decompressed bytes + KFileItem* arcFile; //< the archive file item. + TQString arcPath; //< the archive location + TQString arcTempDir; //< the currently used temp directory. + TQString arcType; //< the archive type. + bool extArcReady; //< Used for RPM & DEB files. + TQString password; //< Password for the archives + TDEConfig *krConfig; //< The configuration file for krusader + + TQString lastData; + TQString encryptedArchPath; +}; + +class KrShellProcess : public KShellProcess { + TQ_OBJECT + +public: + KrShellProcess() : KShellProcess(), errorMsg( TQString() ), outputMsg( TQString() ) { + connect(this,TQ_SIGNAL(receivedStderr(TDEProcess*,char*,int)), + this,TQ_SLOT(receivedErrorMsg(TDEProcess*,char*,int)) ); + connect(this,TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), + this,TQ_SLOT(receivedOutputMsg(TDEProcess*,char*,int)) ); + } + + TQString getErrorMsg() { + if( errorMsg.stripWhiteSpace().isEmpty() ) + return outputMsg.right( 500 ); + else + return errorMsg.right( 500 ); + } + +public slots: + void receivedErrorMsg(TDEProcess*, char *buf, int len) { + errorMsg += TQString::fromLocal8Bit( buf, len ); + if( errorMsg.length() > 500 ) + errorMsg = errorMsg.right( 500 ); + receivedOutputMsg( 0, buf, len ); + } + + void receivedOutputMsg(TDEProcess*, char *buf, int len) { + outputMsg += TQString::fromLocal8Bit( buf, len ); + if( outputMsg.length() > 500 ) + outputMsg = outputMsg.right( 500 ); + } + +private: + TQString errorMsg; + TQString outputMsg; +}; + +#endif diff --git a/src/krArc/krarc.protocol b/src/krArc/krarc.protocol new file mode 100644 index 0000000..ba363be --- /dev/null +++ b/src/krArc/krarc.protocol @@ -0,0 +1,18 @@ +[Protocol] +exec=tdeio_krarc +protocol=krarc +mimetype=application/x-archive +input=filesystem +output=filesystem +listing=Name,Type,Size,Date,Access,Owner,Group,Link +reading=true +writing=true +makedir=true +deleting=true +source=true +linking=false +moving=false +copyToFile=true +Icon=ark +Description=Mutiple archive handler that currently supports: zip,rar. +X-DocPath=tdeioslave/krarc/index.html |