diff options
Diffstat (limited to 'ark')
83 files changed, 12244 insertions, 0 deletions
diff --git a/ark/AUTHORS b/ark/AUTHORS new file mode 100644 index 0000000..0de587e --- /dev/null +++ b/ark/AUTHORS @@ -0,0 +1,5 @@ +Rob Palmbos palm9744@kettering.edu +Francois-Xavier Duranceau duranceau@kde.org +Emily Ezust emilye@corel.com +Roberto Selbach Teixeira maragato@kde.org +Helio Chissini de Castro helio@kde.org diff --git a/ark/ChangeLog b/ark/ChangeLog new file mode 100644 index 0000000..cd5b4de --- /dev/null +++ b/ark/ChangeLog @@ -0,0 +1,277 @@ + $Id$ + +2001-10-24: Roberto Selbach Teixeira <maragato@kde.org> + * Renamed all .cc files to .cpp to make things more logic. + +2001-06-23: Roberto Selbach Teixeira <maragato@kde.org> + * Fixed a bug in tar addition with non-compressed tar archives + +2001-06-10: Roberto Selbach Teixeira <maragato@conectiva.com> + * Made extraction use KURL instead of QString. + * Made extractDlg use a KHistoryCombo. + +2001-05-31 Roberto Selbach Teixeira <maragato@conectiva.com> + * Fixed a bug that made the file list freeze. + * Fixed extractDlg size to use QLayout + +2001-05-30 Roberto Selbach Teixeira <maragato@conectiva.com> + * Began using KMimeMagic to figure file types + * Began cleaning up Ark's code a bit. + +2001-05-29 Roberto Selbach Teixeira <maragato@conectiva.com> + + * compressedfile.cc (unarchFile): move to fromLocal8Bit() to allow + non-Latin1 characters in filenames. + + * ar.cc (unarchFile): .latin1() to .local8Bit() + + * zip.cc (unarchFile): .latin1() to .local8Bit() + +2000-07-10: Emily Ezust <emilye@corel.com> + * Added checks for available disk space + +2000-07-05: Emily Ezust <emilye@corel.com> + * Added some more mimetype magic. + +2000-06-28: Emily Ezust <emilye@corel.com> + * Made Extract dialog prettier + +2000-06-27: Emily Ezust <emilye@corel.com> + * Added code to let users load rar, lha, ar and tar archives that + do not have the standard extensions. You can also "Save As" into + a file with no extension provided the original is rar, lha or ar. + Zip and zoo don't like having no extension. Tar doesn't mind but + I haven't explored that tangle yet. It's complicated with all the + compressors! + * Made shell output dialog a tiny bit prettier. + +2000-06-22: Emily Ezust <emilye@corel.com> + * Overhaul of Directories Preferences dialog + * For Save As, ark will add proper extension if user does not have one. + +2000-06-13: Emily Ezust <emilye@corel.com> + * Fixed "Save As" code so that it prevents the user from saving a + zip as a tar + * Fixed bug preventing you from opening a network file after having + opened one before in the same session. + * Added a check for utilities (it will notify you e.g. that + "The utility zip is not in your PATH. Please + install it or contact your system administrator."). + * Added support for drag/adding files or drag/opening network archives + from konqy. + +2000-06-12: Emily Ezust <emilye@corel.com> + * Began adding network transparency + * Added a Save As option so that people can rename arks that are + temporary files + +2000-05-23: Emily Ezust <emilye@corel.com> + * Odds and ends: fixed problem with selecting multiple files in Add + File; added some better option enabling in the extract dialog. + +2000-05-16: Emily Ezust <emilye@corel.com> + * Fixed a bug in ArArch - wasn't reading TOCs properly + +2000-05-12: Emily Ezust <emilye@corel.com> + * Added some code to notify the user about file(s) that were not + extracted. This happens when the user disallows overwrites and + then extracts file(s) that already exist in the destination + directory. The notification happens before the extract, so that + the user can decide whether to continue or not. + * Fixed a possible memory corruption having to do with the lists passed + via the stack to unarchFile which cease to exist because unarchFile + returns before the job is done. + +2000-05-04: Emily Ezust <emilye@corel.com> + * Added control/shift LMB selection rules + * Added code to allow drag/extract but it doesn't work yet. Commented + it out. Not too sure about when to start the drag anyhow... have to + extract first! + * Added an "Edit With" option to let you edit files in the archive. + It would be too complicated to let the user edit more than one + file at a time, so like view, this freezes the app until the user + quits the editor. + + It even works with files that have paths! (I think - haven't + tested thoroughly) + +2000-04-27: Emily Ezust <emilye@corel.com> + * Got rid of a segfault that occured whenever you closed an archive + (I was deleting something that the statusbar needed (but had not + needed before KStatusBar was adopted by QStatusBar!)) + * Added code to let users drag files to extract them. Not working + yet: when I drag to konqy, it requests a filename for + clipboard content. + +2000-04-18: Emily Ezust <emilye@corel.com> + * Added some code to prevent tar from adding duplicate filenames + (having duplicates really screws up deletion and particular extracts) + * More archive-specific options (for all types: update only with + newer files; tar: keep absolute paths; zip, rar: store file as + symlinks (although my version of rar doesn't seem to know how + to extract a symlink??) + +2000-04-06: Emily Ezust <emilye@corel.com> + * Switched to KListView + * Some work on settings and archive-specific actions + * Couldn't load LHA archives with files that were symlinks; fixed + * Added more entries to the Settings and RMB menu. Toggle menu bar will + display help in the titlebar for getting the menubar back (just as + konsole does) + * Seems I need a KFileOpenWithHandler for OpenWith now... + * Moved archive column header strings from archive classes to the base + class header file on Francois-Xavier Duranceau's suggestion. + +2000-04-03: Emily Ezust <emilye@corel.com> + * Struggling with the Recent Files popup (fixed next day with help of + Kurt Granroth) + * Ar had a problem with some of my files; fixed + * ArkWidget destructor was never being called; fixed + +2000-03-29: Emily Ezust <emilye@corel.com> + * Extra GUI tweaks + * Fixed faulty drop/add into compressed file (if you chose to create a + real archive, it didn't actually add the files, just the compressed + file). + +2000-03-23: Emily Ezust <emilye@corel.com> + * Began migration to the XML-GUI framework. RMB menus disabled for + the moment... + +2000-03-20: Emily Ezust <emilye@corel.com> + * Fixed up Ar format. + +2000-03-20: Emily Ezust <emilye@corel.com> + * Added Rar format. Added disabling of buttons and menu entries during + operations + +2000-03-16: Emily Ezust <emilye@corel.com> + * Added Zoo format + +2000-03-15: Emily Ezust <emilye@corel.com> + * Added the class CompressedFile to the hierarchy. This + allows ark to be used to view, create, and extract compressed files. + The user will be asked if he/she wants to create a real archive if + she/he tries to add a file to the thing when there's already + a file in there. + * Added an Open With option (RMB and Action menu) + * Made use of statusbar improvements + * Made the time and date stamp in LHA sortable + +2000-03-09: Emily Ezust <emilye@corel.com> + * Fixed TarArch so that it warns the user before deleting the + contents of a directory. (Delete a directory entry in tar and + tar deletes everything in it, unlike zip & lha!!) + * Finished TarArch so that extract and view work. + * Added LHA format + * Simplified the Arch API a little (got rid of useless return values) + +2000-03-06: Emily Ezust <emilye@corel.com> + * Fixed TarArch so that the other compressors work + * Dealt with readonly archives (if the user views an archive from + within an archive, it is extracted to the /tmp directory, so all + changes will be lost.) + +2000-03-06: Emily Ezust <emilye@corel.com> + * Got rid of KProcess data member in Arch - no need for it with the + new way that KProcess does its work: we are always passing it + around to the functions that need it. This way we won't get + confused when there are more than one processes happening. + * Made tar more asynchronous, redid the temp file creation & updating. + +2000-03-03: Emily Ezust <emilye@corel.com> + * Made zip fully asynchronous. + +2000-03-02: Emily Ezust <emilye@corel.com> + * add and delete now work for tar files, although I'll probably + change how temp files are created from compressed tars and + how they are used to update the original archive... + Note: ark uses KTar for display and shell process for everything + else. + * Reduced the number of calls of slotSelectionChanged + * OK, _now_ I'm done with the enable/disable stuff - I swear! + * Other miscellaneous abstractions with zip->arch code + +2000-02-24: Emily Ezust <emilye@corel.com> + * Got showFile interface working (see zip) + * Started using KTar in tar. Seems to display OK. + No other functionality yet for tar. + +2000-02-22: Emily Ezust <emilye@corel.com> + * More work on the abstract base class for archives - moved lots of + slots dealing with the KProcess from zip.cpp to arch.cpp + * Some work on tar. Doesn't work yet. + +2000-02-16: Emily Ezust <emilye@corel.com> + * More consistent disabling/enabling of menu items and toolbar buttons. + * Added "add directory" - might need some more tweaking in zip so it + doesn't flatten the files out. + +2000-02-15: Emily Ezust <emilye@corel.com> + * Added drop support. Doesn't seem to work with directories though. + * Toolbar icons stopped working briefly - renamed them to ensure no + ambiguity. + +2000-02-14: Emily Ezust <emilye@corel.com> + * Separated GUI and backend in zip, which will be the model + for the other formats once it's just-right. Next I'll make sure + drag and drop works. + +2000-02-09: Emily Ezust <emilye@corel.com> + * Finally have Add and Extract working for zip + +2000-02-07: Emily Ezust <emilye@corel.com> + * new locking scheme to prevent users from opening the same archive + in two different windows. Handles symlinks. But I can't figure out + why raise() alone doesn't do it - I hide and show the window + instead - blech! + * made classes more const correct + * add dialog still doesn't work. Problem with KFileView? + +2000-01-18: Emily Ezust <emilye@corel.com> + * KUniqueApplication stuff was enabled by waba, with KCmdLineArgs + code. Modified it to work according to Cooperating-SDI model. + * Moved windowList to ArkApplication (accessed through a static + function). ArkApplication is now modelled on the singleton pattern. + +2000-01-10: Emily Ezust <emilye@corel.com> + * Finished renaming ArkData to ArkSettings. + * Tried using KDialogBase for Add dialog - not working too well. + +2000-01-6: Emily Ezust <emilye@corel.com> + * Disabled KUniqueApplication stuff for now... was interfering with + development with crashes. Will add later. + * Asks "Are you sure?" when you try to "New" over an existing zip + * Began work on new extract dialog - old one doesn't work any longer + due to kdelibs changes. Doesn't do anything yet - just trying out + for look&feel with error-checking. + Idea of extract: highlight the ones to be extracted and then + let the right archiver grab all the highlighted files (or current). + + +1999-12-16 Emily Ezust <emilye@corel.com> + * created ArkApplication : public KUniqueApplication + * Code now to follow the Co-operating SDI model. + * Some problems with dcop still... exiting the last window doesn't + get you back the prompt! + +1999-12-13 Emily Ezust <emilye@corel.com> + * fixed up icons, continued with merge: enabling toolbar buttons + and menu items. Close enables don't work yet... + * Fixed status bar totals for selection, number and size. + +1999-12-09 Emily Ezust <emilye@corel.com> + * started merge with Corel Linux code. + * added toolbar icons (with two more on the way), lock files, + and fixed the sorting for numeric column data. + * added preliminary code to count number of files and total sizes + in the status bar, but it does nothing so far. + * created a new problem: action_add in zip now segfaults. + +1999-07-05 Francois-Xavier Duranceau <duranceau@kde.org> + * added selection with regular expressions + +1999-04-11 Francois-Xavier Duranceau <duranceau@kde.org> + + * created this file + diff --git a/ark/Makefile.am b/ark/Makefile.am new file mode 100644 index 0000000..b97b034 --- /dev/null +++ b/ark/Makefile.am @@ -0,0 +1,54 @@ +# set the include path for X, qt and KDE +AM_CPPFLAGS = -D_LARGEFILE64_SOURCE $(all_includes) + +SUBDIRS = pics + +# The binary name. Changed from kzip to ark +bin_PROGRAMS = +kdeinit_LTLIBRARIES = ark.la +lib_LTLIBRARIES = + +ark_la_SOURCES = main.cpp arkapp.cpp mainwindow.cpp +ark_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +ark_la_LIBADD = libark_common.la $(LIB_KPARTS) +ark_la_COMPILE_FIRST = settings.h + +noinst_LTLIBRARIES = libark_common.la + +libark_common_la_SOURCES = settings.kcfgc archiveformatinfo.cpp +libark_common_la_LDFLAGS = $(all_libraries) -no-undefined +libark_common_la_LIBADD = $(LIB_KFILE) + +kde_module_LTLIBRARIES = libarkpart.la +libarkpart_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries) +libarkpart_la_LIBADD = libark_common.la $(LIB_KPARTS) +libarkpart_la_COMPILE_FIRST = settings.h + +libarkpart_la_SOURCES = ark_part.cpp arkfactory.cpp zip.cpp tar.cpp \ + filelistview.cpp arch.cpp lha.cpp \ + compressedfile.cpp zoo.cpp rar.cpp \ + ar.cpp arkutils.cpp archiveformatdlg.cpp \ + arkwidget.cpp searchbar.cpp \ + addition.ui extraction.ui general.ui \ + arkviewer.cpp sevenzip.cpp extractiondialog.cpp \ + ace.cpp tarlistingthread.cpp + +METASOURCES = AUTO + +rcdir = $(kde_datadir)/ark +rc_DATA = arkui.rc ark_part.rc ark_part_readonly.rc + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/ark.pot + +KDE_ICON = ark + +xdg_apps_DATA = ark.desktop +kde_kcfg_DATA = ark.kcfg + +parts_DATA = ark_part.desktop +partsdir = $(kde_servicesdir) + +#konqservice_DATA = arkservicemenu.desktop ark_directory_service.desktop +#konqservicedir = $(kde_datadir)/konqueror/servicemenus + diff --git a/ark/README b/ark/README new file mode 100644 index 0000000..156c2bb --- /dev/null +++ b/ark/README @@ -0,0 +1,4 @@ +This is Ark version 2.3.x. + +Ark is KDE archive handling tool, part of the kdeutils package. + diff --git a/ark/TODO b/ark/TODO new file mode 100644 index 0000000..cc3d455 --- /dev/null +++ b/ark/TODO @@ -0,0 +1,11 @@ +TODO +----- + +Feature-wise: +- Rename option +- Behavior-compatibility with the Konqueror filemanager + +For KDE 4.0: +- Use KArchive to handle archives +- Add support for split files +- Add support for more archive formats (ace, iso, rpm) diff --git a/ark/ace.cpp b/ark/ace.cpp new file mode 100644 index 0000000..d9cce52 --- /dev/null +++ b/ark/ace.cpp @@ -0,0 +1,181 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2005: Henrique Pinto <henrique.pinto@kdemail.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. + + 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. + +*/ + +#include <qdir.h> + +#include <kglobal.h> +#include <klocale.h> +#include <kdebug.h> +#include <kurl.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kstandarddirs.h> + +#include "ace.h" +#include "arkwidget.h" +#include "settings.h" + +AceArch::AceArch( ArkWidget *gui, const QString &filename ) + : Arch( gui, filename ) +{ + //m_archiver_program = m_unarchiver_program = "/usr/local/bin/unace"; + m_archiver_program = m_unarchiver_program = "/home/henrique/ArkTest/teste.sh"; + verifyCompressUtilityIsAvailable( m_archiver_program ); + + m_headerString = "Date Time Packed Size RatioFile"; + + m_repairYear = 5; m_fixMonth = 6; m_fixDay = 7; m_fixTime = 8; + m_dateCol = 3; + m_numCols = 5; + + m_archCols.append( new ArchColumns( 7, QRegExp( "[0-3][0-9]" ), 2 ) ); // Day + m_archCols.append( new ArchColumns( 6, QRegExp( "[01][0-9]" ), 2 ) ); // Month + m_archCols.append( new ArchColumns( 5, QRegExp( "[0-9][0-9]" ), 4 ) ); // Year + m_archCols.append( new ArchColumns( 8, QRegExp( "[0-9:]+" ), 8 ) ); // Time + m_archCols.append( new ArchColumns( 2, QRegExp( "[0-9]+" ) ) ); // Compressed Size + m_archCols.append( new ArchColumns( 1, QRegExp( "[0-9]+" ) ) ); // Size + m_archCols.append( new ArchColumns( 9, QRegExp( "[0-9][0-9]%" ) ) ); // Ratio + m_archCols.append( new ArchColumns( 0, QRegExp( "[^\\n]+" ), 4096 ) ); // Name +} + +AceArch::~AceArch() +{ +} + +void AceArch::setHeaders() +{ + ColumnList list; + list.append( FILENAME_COLUMN ); + list.append( SIZE_COLUMN ); + list.append( PACKED_COLUMN ); + list.append( TIMESTAMP_COLUMN ); + + emit headers( list ); +} + +void AceArch::open() +{ + kdDebug(1601) << "+AceArch::open()" << endl; + setHeaders(); + + m_buffer = ""; + m_header_removed = false; + m_finished = false; + + KProcess *kp = m_currentProcess = new KProcess; + *kp << m_archiver_program << "v" << m_filename; + //kp->setUseShell( true ); + + kdDebug() << "AceArch::open(): kp->args(): " << kp->args() << endl; + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedTOC(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotOpenExited(KProcess*) ) ); + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + this, SLOT( catchMeIfYouCan(KProcess*, char*, int) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigOpen( this, false, QString::null, 0 ); + } +} + +void AceArch::create() +{ + emit sigCreate( this, true, m_filename, + Arch::Extract | Arch::View ); +} + +void AceArch::addFile( const QStringList & urls ) +{ +} + +void AceArch::addDir( const QString & dirName ) +{ +} + +void AceArch::remove( QStringList *list ) +{ +} + +void AceArch::unarchFileInternal( ) +{ + if ( m_destDir.isEmpty() || m_destDir.isNull() ) + { + kdError( 1601 ) << "There was no extract directory given." << endl; + return; + } + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + // extract (and maybe overwrite) + *kp << m_unarchiver_program << "x" << "-y"; + + if ( ArkSettings::extractOverwrite() ) + { + *kp << "-o"; + } + + *kp << m_filename; + + *kp << m_destDir ; + + // if the file list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if ( m_fileList ) + { + QStringList::Iterator it; + for ( it = m_fileList->begin(); it != m_fileList->end(); ++it ) + { + *kp << (*it); + } + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotExtractExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigExtract( false ); + } +} + +void AceArch::catchMeIfYouCan( KProcess*, char *buffer, int buflen ) +{ + QString myBuf = QString::fromLatin1( buffer, buflen ); + kdDebug(1601) << " Wololo!: " << myBuf << endl; +} + +#include "ace.moc" diff --git a/ark/ace.h b/ark/ace.h new file mode 100644 index 0000000..7aed56c --- /dev/null +++ b/ark/ace.h @@ -0,0 +1,55 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2005: Henrique Pinto <henrique.pinto@kdemail.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. + + 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. + +*/ + +#ifndef ARK_ACE_H +#define ARK_ACE_H + +#include "arch.h" + +class KProcess; // TODO: Remove me! + +class AceArch : public Arch +{ + Q_OBJECT + public: + AceArch( ArkWidget *, const QString & ); + virtual ~AceArch(); + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir( const QString & ); + + virtual void remove( QStringList * ); + virtual void unarchFileInternal( ); + + private slots: + void catchMeIfYouCan( KProcess*, char*, int ); + + private: + void setHeaders(); +}; + +#endif // ARK_ACE_H diff --git a/ark/addition.ui b/ark/addition.ui new file mode 100644 index 0000000..a8f51d8 --- /dev/null +++ b/ark/addition.ui @@ -0,0 +1,79 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>Addition</class> +<widget class="QWidget"> + <property name="name"> + <cstring>Addition</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>365</width> + <height>268</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_replaceOnlyWithNewer</cstring> + </property> + <property name="text"> + <string>Replace old files only &with newer files</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_forceMSDOS</cstring> + </property> + <property name="text"> + <string>Force &MS-DOS short filenames (Zip)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_convertLF2CRLF</cstring> + </property> + <property name="text"> + <string>Translate &LF to DOS CRLF (Zip)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_rarStoreSymlinks</cstring> + </property> + <property name="text"> + <string>&Store symlinks as links (Zip, Rar)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_rarRecurseSubdirs</cstring> + </property> + <property name="text"> + <string>&Recursively add subfolders (Zip, Rar)</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>51</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/ark/ar.cpp b/ark/ar.cpp new file mode 100644 index 0000000..71f44e0 --- /dev/null +++ b/ark/ar.cpp @@ -0,0 +1,263 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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 <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +// QT includes +#include <qdir.h> + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +// ark includes +#include "arkwidget.h" +#include "settings.h" +#include "ar.h" + +ArArch::ArArch( ArkWidget *_gui, const QString & _fileName ) + : Arch(_gui, _fileName ) +{ + m_archiver_program = m_unarchiver_program = "ar"; + verifyCompressUtilityIsAvailable( m_archiver_program ); + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + + // Do not set headerString - there is none for Ar + m_numCols = 5; + m_dateCol = 4; m_fixYear = 8; m_repairMonth = 5; m_fixDay = 6; m_fixTime = 7; + + m_archCols.append(new ArchColumns(1, QRegExp("[a-zA-Z-]+"), 12)); // Perms + m_archCols.append(new ArchColumns(2, QRegExp("[^\\s]+"), 128)); //User/grp + m_archCols.append(new ArchColumns(3, QRegExp("[0-9]+"))); // Size + m_archCols.append(new ArchColumns(5, QRegExp("[a-zA-Z]+"), 4)); // Month + m_archCols.append(new ArchColumns(6, QRegExp("[0-9]+"), 2)); // Day + m_archCols.append(new ArchColumns(7, QRegExp("[0-9:]+"), 6)); // Time + m_archCols.append(new ArchColumns(8, QRegExp("[0-9]+"), 5)); // Year + m_archCols.append(new ArchColumns(0, QRegExp("[^\\s][^\\n]+"), 4096));// File + + kdDebug(1601) << "ArArch constructor" << endl; +} + +void ArArch::setHeaders() +{ + ColumnList list; + list.append( FILENAME_COLUMN ); + list.append( PERMISSION_COLUMN ); + list.append( OWNER_GROUP_COLUMN ); + list.append( SIZE_COLUMN ); + list.append( TIMESTAMP_COLUMN ); + + emit headers( list ); +} + +void ArArch::open() +{ + kdDebug(1601) << "+ArArch::open" << endl; + setHeaders(); + + m_buffer = ""; + + KProcess *kp = m_currentProcess = new KProcess; + *kp << m_archiver_program << "vt" << m_filename; + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedTOC(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotOpenExited(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigOpen(this, false, QString::null, 0 ); + } + kdDebug(1601) << "-ArArch::open" << endl; +} + +void ArArch::create() +{ + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + *kp << m_archiver_program << "c" << m_filename; + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + if (kp->start(KProcess::Block) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigCreate(this, false, m_filename, + Arch::Extract | Arch::Delete | Arch::Add + | Arch::View); + } + else + emit sigCreate(this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add + | Arch::View); +} + +void ArArch::addFile( const QStringList &urls ) +{ + kdDebug(1601) << "+ArArch::addFile" << endl; + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + *kp << m_archiver_program; + + if (ArkSettings::replaceOnlyWithNewer()) + *kp << "ru"; + else + *kp << "r"; + + *kp << m_filename; + + QStringList::ConstIterator iter; + KURL url( urls.first() ); + QDir::setCurrent( url.directory() ); + for (iter = urls.begin(); iter != urls.end(); ++iter ) + { + KURL fileURL( *iter ); + *kp << fileURL.fileName(); + } + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotAddExited(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigAdd(false); + } + + kdDebug(1601) << "-ArArch::addFile" << endl; +} + +void ArArch::unarchFileInternal() +{ + // if m_fileList is empty, we extract all. + // if m_destDir is empty, abort with error. + + kdDebug(1601) << "+ArArch::unarchFile" << endl; + QString dest; + + if (m_destDir.isEmpty() || m_destDir.isNull()) + { + kdError(1601) << "There was no extract directory given." << endl; + return; + } + else dest = m_destDir; + + // ar has no option to specify the destination directory + // so I have to change to it. + + bool ret = QDir::setCurrent(dest); + // I already checked the validity of the dir before coming here + Q_ASSERT(ret); + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program; + *kp << "vx"; + *kp << m_filename; + + // if the list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if (m_fileList) + { + for ( QStringList::Iterator it = m_fileList->begin(); + it != m_fileList->end(); ++it ) + { + *kp << (*it); + } + } + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotExtractExited(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigExtract(false); + } +} + +void ArArch::remove(QStringList *list) +{ + kdDebug(1601) << "+ArArch::remove" << endl; + + if (!list) + return; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program << "d" << m_filename; + for ( QStringList::Iterator it = list->begin(); + it != list->end(); ++it ) + { + QString str = *it; + *kp << str; + } + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotDeleteExited(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigDelete(false); + } + + kdDebug(1601) << "-ArArch::remove" << endl; +} + + +#include "ar.moc" diff --git a/ark/ar.h b/ark/ar.h new file mode 100644 index 0000000..1a5f00f --- /dev/null +++ b/ark/ar.h @@ -0,0 +1,61 @@ +// -*-C++-*- emacs magic for .h files +/* + + $Id$ + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ + +#ifndef ARARCH_H +#define ARARCH_H + +class QString; +class QCString; +class QStringList; + +class Arch; +class ArkWidget; + +class ArArch : public Arch +{ + Q_OBJECT +public: + ArArch( ArkWidget *_gui, + const QString & _fileName ); + virtual ~ArArch() {} + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir(const QString &) {} // never gets called + + virtual void remove(QStringList *); + virtual void unarchFileInternal(); + +private: + void setHeaders(); +}; + +#endif /* ARARCH_H */ diff --git a/ark/arch.cpp b/ark/arch.cpp new file mode 100644 index 0000000..8ff6a2b --- /dev/null +++ b/ark/arch.cpp @@ -0,0 +1,403 @@ +/* + + 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 <qapplication.h> +#include <qfile.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" + +Arch::ArchColumns::ArchColumns( int col, QRegExp reg, int length, bool opt ) + : colRef( col ), pattern( reg ), maxLength( length ), optional( opt ) +{ +} + +Arch::Arch( ArkWidget *gui, const QString &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 QString &utility ) +{ + // see if the utility is in the PATH of the user. + QString cmd = KGlobal::dirs()->findExe( utility ); + m_bArchUtilityIsAvailable = !cmd.isEmpty(); +} + +//Check if a utility can uncompress files +void Arch::verifyUncompressUtilityIsAvailable( const QString &utility ) +{ + // see if the utility is in the PATH of the user. + QString cmd = KGlobal::dirs()->findExe( utility ); + m_bUnarchUtilityIsAvailable = !cmd.isEmpty(); +} + +void Arch::slotOpenExited( KProcess* _kp ) +{ + 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, QString::null, 0 ); + + delete _kp; + _kp = m_currentProcess = 0; +} + +void Arch::slotDeleteExited( KProcess *_kp ) +{ + bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) ); + + if ( !success ) + { + QApplication::restoreOverrideCursor(); + + QString msg = i18n( "The deletion operation failed." ); + + if ( !getLastShellOutput().isNull() ) + { + QStringList list = QStringList::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() ) + { + QString 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 ) + { + QApplication::restoreOverrideCursor(); + + QString msg = i18n( "The extraction operation failed." ); + + if ( !getLastShellOutput().isNull() ) + { + //getLastShellOutput() is a QString. errorList is expecting QStringLists to show in multiple lines + QStringList list = QStringList::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( QStringList *fileList, const QString & 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 ) + { + QApplication::restoreOverrideCursor(); + + QString msg = i18n( "The addition operation failed." ); + + if ( !getLastShellOutput().isNull() ) + { + QStringList list = QStringList::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 ) == -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 QCString &line ) +{ + QString columns[ 11 ]; + unsigned int pos = 0; + int strpos, len; + + // Go through our columns, try to pick out data, return silently on failure + for ( QPtrListIterator <ArchColumns>col( m_archCols ); col.current(); ++col ) + { + ArchColumns *curCol = *col; + + strpos = curCol->pattern.search( 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] = QString::fromLocal8Bit( line.mid(strpos, len) ); + } + + + if ( m_dateCol >= 0 ) + { + QString year = ( m_repairYear >= 0 ) ? + ArkUtils::fixYear( columns[ m_repairYear ].ascii()) + : columns[ m_fixYear ]; + QString month = ( m_repairMonth >= 0 ) ? + QString( "%1" ) + .arg( ArkUtils::getMonth( columns[ m_repairMonth ].ascii() ) ) + : columns[ m_fixMonth ]; + QString timestamp = QString::fromLatin1( "%1-%2-%3 %4" ) + .arg( year ) + .arg( month ) + .arg( columns[ m_fixDay ] ) + .arg( columns[ m_fixTime ] ); + + columns[ m_dateCol ] = timestamp; + } + + QStringList 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; +} + + +Arch *Arch::archFactory( ArchType aType, + ArkWidget *parent, const QString &filename, + const QString &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 UNKNOWN_FORMAT: + default: + return 0; + } +} +#include "arch.moc" diff --git a/ark/arch.h b/ark/arch.h new file mode 100644 index 0000000..1a38a2c --- /dev/null +++ b/ark/arch.h @@ -0,0 +1,221 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ + +/* The following class is the base class for all of the archive types. + * In order for it to work properly with the KProcess, you have to + * connect the ProcessExited signal appropriately before spawning + * the core operations. Then the signal that the process exited can + * be intercepted by the viewer (in ark, ArkWidget) and dealt with + * appropriately. See LhaArch or ZipArch for a good model. Don't use + * TarArch or CompressedFile as models - they're too complicated! + * + * Don't forget to set m_archiver_program and m_unarchiver_program + * and add a call to + * verifyUtilityIsAvailable(m_archiver_program, m_unarchiver_program); + * in the constructor of your class. It's OK to leave out the second argument. + * + * To add a new archive type: + * 1. Create a new header file and a source code module + * 2. Add an entry to the ArchType enum in arch.h. + * 3. Add appropriate types to buildFormatInfo() in archiveformatinfo.cpp + * and archFactory() in arch.cpp + */ + + +#ifndef ARCH_H +#define ARCH_H + +#include <qobject.h> +#include <qptrlist.h> // Some very annoying hackery in arkwidgetpart +#include <qregexp.h> +#include <qstring.h> +#include <kurl.h> +#include <qpair.h> + +class QCString; +class QStringList; +class KProcess; + +class FileListView; +class ArkWidget; + +enum ArchType { UNKNOWN_FORMAT, ZIP_FORMAT, TAR_FORMAT, AA_FORMAT, + LHA_FORMAT, RAR_FORMAT, ZOO_FORMAT, COMPRESSED_FORMAT, + SEVENZIP_FORMAT, ACE_FORMAT }; + +typedef QValueList< QPair< QString, Qt::AlignmentFlags > > ColumnList; + +/** + * Pure virtual base class for archives - provides a framework as well as + * useful common functionality. + */ +class Arch : public QObject +{ + Q_OBJECT + + protected: + /** + * A struct representing column data. This makes it possible to abstract + * archive output, and save writing the same function for every archive + * type. It is also much more robust than sscanf (which was breaking). + */ + struct ArchColumns + { + int colRef; // Which column to load to in processLine + QRegExp pattern; + int maxLength; + bool optional; + + ArchColumns( int col, QRegExp reg, int length = 64, bool opt = false ); + }; + + public: + Arch( ArkWidget *_viewer, const QString & _fileName ); + virtual ~Arch(); + + virtual void open() = 0; + virtual void create() = 0; + virtual void remove( QStringList * ) = 0; + + virtual void addFile( const QStringList & ) = 0; + virtual void addDir( const QString & ) = 0; + + // unarch the files in m_fileList or all files if m_fileList is empty. + // if m_destDir is empty, abort with error. + // m_viewFriendly forces certain options like directory junking required by view/edit + virtual void unarchFileInternal() = 0; + // returns true if a password is required + virtual bool passwordRequired() { return false; } + + void unarchFile( QStringList *, const QString & _destDir, + bool viewFriendly = false ); + + QString fileName() const { return m_filename; } + + enum EditProperties{ Add = 1, Delete = 2, Extract = 4, + View = 8, Integrity = 16 }; + + // is the archive readonly? + bool isReadOnly() { return m_bReadOnly; } + void setReadOnly( bool bVal ) { m_bReadOnly = bVal; } + + bool isError() { return m_error; } + void resetError() { m_error = false; } + + // check to see if the utility exists in the PATH of the user + void verifyUtilityIsAvailable( const QString &, + const QString & = QString::null ); + + void verifyCompressUtilityIsAvailable( const QString &utility ); + + void verifyUncompressUtilityIsAvailable( const QString &utility ); + + bool archUtilityIsAvailable() { return m_bArchUtilityIsAvailable; } + + bool unarchUtilityIsAvailable() { return m_bUnarchUtilityIsAvailable; } + + QString getArchUtility() { return m_archiver_program; } + + QString getUnarchUtility() { return m_unarchiver_program; } + + void appendShellOutputData( const char * data ) { m_lastShellOutput.append( QString::fromLocal8Bit( data ) ); } + void clearShellOutput() { m_lastShellOutput.truncate( 0 ); } + const QString& getLastShellOutput() const { return m_lastShellOutput; } + + static Arch *archFactory( ArchType aType, ArkWidget *parent, + const QString &filename, + const QString &openAsMimeType = QString::null ); + + protected slots: + void slotOpenExited( KProcess* ); + void slotExtractExited( KProcess* ); + void slotDeleteExited( KProcess* ); + void slotAddExited( KProcess* ); + + void slotReceivedOutput( KProcess *, char*, int ); + + virtual bool processLine( const QCString &line ); + virtual void slotReceivedTOC( KProcess *, char *, int ); + + signals: + void sigOpen( Arch * archive, bool success, const QString &filename, int ); + void sigCreate( Arch *, bool, const QString &, int ); + void sigDelete( bool ); + void sigExtract( bool ); + void sigAdd( bool ); + void headers( const ColumnList& columns ); + + protected: // data + QString m_filename; + QString m_lastShellOutput; + QCString m_buffer; + ArkWidget *m_gui; + bool m_bReadOnly; // for readonly archives + bool m_error; + + // lets tar delete unsuccessfully before adding without confusing the user + bool m_bNotifyWhenDeleteFails; + + // set to whether if the compressing utility is in the user's PATH + bool m_bArchUtilityIsAvailable; + + // set to whether if the uncompressing utility is in the user's PATH + bool m_bUnarchUtilityIsAvailable; + + QString m_archiver_program; + QString m_unarchiver_program; + + // Archive parsing information + QCString m_headerString; + bool m_header_removed, m_finished; + QPtrList<ArchColumns> m_archCols; + int m_numCols, m_dateCol, m_fixYear, m_fixMonth, m_fixDay, m_fixTime; + int m_repairYear, m_repairMonth, m_repairTime; + KProcess *m_currentProcess; + QStringList *m_fileList; + QString m_destDir; + bool m_viewFriendly; + QCString m_password; +}; + +// Columns +// don't forget to change common_texts.cpp if you change something here +#define FILENAME_COLUMN qMakePair( i18n(" Filename "), Qt::AlignLeft ) +#define PERMISSION_COLUMN qMakePair( i18n(" Permissions "), Qt::AlignLeft ) +#define OWNER_GROUP_COLUMN qMakePair( i18n(" Owner/Group "), Qt::AlignLeft ) +#define SIZE_COLUMN qMakePair( i18n(" Size "), Qt::AlignRight ) +#define TIMESTAMP_COLUMN qMakePair( i18n(" Timestamp "), Qt::AlignRight ) +#define LINK_COLUMN qMakePair( i18n(" Link "), Qt::AlignLeft ) +#define PACKED_COLUMN qMakePair( i18n(" Size Now "), Qt::AlignRight ) +#define RATIO_COLUMN qMakePair( i18n(" Ratio "), Qt::AlignRight ) +#define CRC_COLUMN qMakePair( i18n("Cyclic Redundancy Check"," CRC "), Qt::AlignLeft ) +#define METHOD_COLUMN qMakePair( i18n(" Method "), Qt::AlignLeft ) +#define VERSION_COLUMN qMakePair( i18n(" Version "), Qt::AlignLeft ) +#define OWNER_COLUMN qMakePair( i18n(" Owner "), Qt::AlignLeft ) +#define GROUP_COLUMN qMakePair( i18n(" Group "), Qt::AlignLeft ) + +#endif /* ARCH_H */ diff --git a/ark/archiveformatdlg.cpp b/ark/archiveformatdlg.cpp new file mode 100644 index 0000000..be046fb --- /dev/null +++ b/ark/archiveformatdlg.cpp @@ -0,0 +1,71 @@ +/* + ark -- archiver for the KDE project + + Copyright (C) 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + + 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. + +*/ + +#include "archiveformatdlg.h" +#include "archiveformatinfo.h" +#include "arch.h" + +#include <klocale.h> + +#include <qlabel.h> +#include <qvbox.h> + +ArchiveFormatDlg::ArchiveFormatDlg( QWidget * parent, const QString & defaultType ) + :KDialogBase( parent, "archiveformatdialog", true, + i18n( "Choose Archive Format" ), + KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok), + m_combo( 0 ) +{ + QString defaultDescription = ArchiveFormatInfo::self()->descriptionForMimeType( defaultType ); + QString text; + if ( defaultDescription.isNull() ) + text = i18n( "This file appears to be of type %1,\n" + "which is not a supported archive format.\n" + "In order to proceed, please choose the format\n" + "of the file." ).arg( defaultType ); + else + text = i18n( "You are about to open a file that has a non-standard extension.\n" + "Ark has detected the format: %1\n" + "If this is not correct, please choose " + "the appropriate format." ).arg( defaultDescription ); + + QVBox * page = makeVBoxMainWidget(); + + QLabel * label; + label = new QLabel( text, page ); + + m_combo = new KComboBox( page ); + QStringList list = ArchiveFormatInfo::self()->allDescriptions(); + list.sort(); + m_combo->insertStringList( list ); + m_combo->setCurrentItem( list.findIndex( defaultDescription ) ); +} + +QString ArchiveFormatDlg::mimeType() +{ + if (m_combo && !m_combo->currentText().isEmpty()) + return ArchiveFormatInfo::self()->mimeTypeForDescription( m_combo->currentText() ); + else + return QString(); +} + +#include "archiveformatdlg.moc" + diff --git a/ark/archiveformatdlg.h b/ark/archiveformatdlg.h new file mode 100644 index 0000000..c8a2e46 --- /dev/null +++ b/ark/archiveformatdlg.h @@ -0,0 +1,39 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + + 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. + +*/ +#ifndef ARCHIVEFORMATDLG_H +#define ARCHIVEFORMATDLG_H + +#include <kdialogbase.h> +#include <kcombobox.h> + +class ArchiveFormatDlg: public KDialogBase +{ + Q_OBJECT +public: + ArchiveFormatDlg( QWidget * parent, const QString & defaultType ); + QString mimeType(); + +private: + KComboBox * m_combo; +}; +#endif // ARCHIVEFORMATDLG_H + diff --git a/ark/archiveformatinfo.cpp b/ark/archiveformatinfo.cpp new file mode 100644 index 0000000..f2ac14d --- /dev/null +++ b/ark/archiveformatinfo.cpp @@ -0,0 +1,278 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) 2003 Georg Robbers <Georg.Robbers@urz.uni-hd.de> + + 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. + +*/ + +#include "arch.h" +#include "archiveformatinfo.h" +#include "settings.h" + +#include <klocale.h> +#include <kdebug.h> +#include <kdesktopfile.h> +#include <kfilterdev.h> + +#include <qfile.h> + +ArchiveFormatInfo * ArchiveFormatInfo::m_pSelf = 0; + +ArchiveFormatInfo::ArchiveFormatInfo() + :m_lastExtensionUnknown( false ) +{ + buildFormatInfos(); +} + +ArchiveFormatInfo * ArchiveFormatInfo::self() +{ + if ( !m_pSelf ) + m_pSelf = new ArchiveFormatInfo(); + return m_pSelf; +} + +void ArchiveFormatInfo::buildFormatInfos() +{ + addFormatInfo( TAR_FORMAT, "application/x-tgz", ".tar.gz" ); + addFormatInfo( TAR_FORMAT, "application/x-tzo", ".tar.lzo" ); + addFormatInfo( TAR_FORMAT, "application/x-tarz", ".tar.z" ); + addFormatInfo( TAR_FORMAT, "application/x-tbz", ".tar.bz2" ); + addFormatInfo( TAR_FORMAT, "application/x-tbz2", ".tar.bz2" ); + // x-tar as the last one to get its comment for all the others, too + addFormatInfo( TAR_FORMAT, "application/x-tar", ".tar" ); + + addFormatInfo( LHA_FORMAT, "application/x-lha", ".lha" ); + + addFormatInfo( ZIP_FORMAT, "application/x-jar", ".jar" ); + addFormatInfo( ZIP_FORMAT, "application/x-zip", ".zip" ); + addFormatInfo( ZIP_FORMAT, "application/x-zip-compressed", ".zip" ); + + addFormatInfo( COMPRESSED_FORMAT, "application/x-gzip", ".gz" ); + addFormatInfo( COMPRESSED_FORMAT, "application/x-bzip", ".bz" ); + addFormatInfo( COMPRESSED_FORMAT, "application/x-bzip2", ".bz2" ); + addFormatInfo( COMPRESSED_FORMAT, "application/x-lzop", ".lzo" ); + addFormatInfo( COMPRESSED_FORMAT, "application/x-compress", ".Z" ); + find( COMPRESSED_FORMAT ).description = i18n( "Compressed File" ); + + addFormatInfo( ZOO_FORMAT, "application/x-zoo", ".zoo" ); + + addFormatInfo( RAR_FORMAT, "application/x-rar", ".rar" ); + addFormatInfo( RAR_FORMAT, "application/x-rar-compressed", ".rar" ); + + addFormatInfo( AA_FORMAT, "application/x-deb", ".deb" ); + addFormatInfo( AA_FORMAT, "application/x-archive",".a" ); + + addFormatInfo( SEVENZIP_FORMAT, "application/x-7z", ".7z" ); + + if ( ArkSettings::aceSupport() ) + addFormatInfo( ACE_FORMAT, "application/x-ace", ".ace" ); +} + +void ArchiveFormatInfo::addFormatInfo( ArchType type, QString mime, QString stdExt ) +{ + FormatInfo & info = find( type ); + + KDesktopFile * desktopFile = new KDesktopFile( mime + ".desktop", true, "mime" ); + if( !desktopFile ) + kdWarning( 1601 ) << "MimeType " << mime << " seems to be missing." << endl; + KMimeType mimeType( desktopFile ); + info.mimeTypes.append( mimeType.name() ); + info.extensions += mimeType.patterns(); + info.defaultExtensions += stdExt; + info.allDescriptions.append( mimeType.comment() ); + info.description = mimeType.comment(); + + delete desktopFile; +} + + +QString ArchiveFormatInfo::filter() +{ + QStringList allExtensions; + QString filter; + InfoList::Iterator it; + for ( it = m_formatInfos.begin(); it != m_formatInfos.end(); ++it ) + { + allExtensions += (*it).extensions; + filter += "\n" + (*it).extensions.join( " " ) + '|' + (*it).description; + } + return allExtensions.join( " " ) + '|' + i18n( "All Valid Archives\n" ) + + "*|" + i18n( "All Files" ) + + filter; +} + +const QStringList ArchiveFormatInfo::supportedMimeTypes( bool includeCompressed ) +{ + QStringList list; + + InfoList::Iterator end = m_formatInfos.end(); + for ( InfoList::Iterator it = m_formatInfos.begin(); it != end; ++it ) + { + if ( includeCompressed || ( *it ).type != COMPRESSED_FORMAT ) + { + list += ( *it ).mimeTypes; + } + } + + return list; +} + +QStringList ArchiveFormatInfo::allDescriptions() +{ + QStringList descriptions; + InfoList::Iterator it; + for ( it = m_formatInfos.begin(); it != m_formatInfos.end(); ++it ) + descriptions += (*it).allDescriptions; + return descriptions; +} + +ArchiveFormatInfo::FormatInfo & ArchiveFormatInfo::find( ArchType type ) +{ + InfoList::Iterator it = m_formatInfos.begin(); + for( ; it != m_formatInfos.end(); ++it ) + if( (*it).type == type ) + return (*it); + + FormatInfo info; + info.type = type; + return ( *m_formatInfos.append( info ) ); +} + +ArchType ArchiveFormatInfo::archTypeByExtension( const QString & archname ) +{ + InfoList::Iterator it = m_formatInfos.begin(); + QStringList::Iterator ext; + for( ; it != m_formatInfos.end(); ++it ) + { + ext = (*it).extensions.begin(); + for( ; ext != (*it).extensions.end(); ++ext ) + if( archname.endsWith( (*ext).remove( '*' ) ) ) + return (*it).type; + } + return UNKNOWN_FORMAT; +} + +ArchType ArchiveFormatInfo::archTypeForMimeType( const QString & mimeType ) +{ + InfoList::Iterator it = m_formatInfos.begin(); + for( ; it != m_formatInfos.end(); ++it ) + { + int index = (*it).mimeTypes.findIndex( mimeType ); + if( index != -1 ) + return (*it).type; + } + return UNKNOWN_FORMAT; +} + +ArchType ArchiveFormatInfo::archTypeForURL( const KURL & url ) +{ + m_lastExtensionUnknown = false; + + if( url.isEmpty() ) + return UNKNOWN_FORMAT; + + if( !QFile::exists( url.path() ) ) + return archTypeByExtension( url.path() ); + + QString mimeType = KMimeType::findByURL( url, 0, true, true )->name(); + kdDebug( 1601 ) << "find by url: " << mimeType << endl; + if( mimeType == KMimeType::defaultMimeType() ) + { + m_lastExtensionUnknown = true; + mimeType = KMimeType::findByFileContent( url.path() )->name(); + } + + ArchType archType = archTypeForMimeType( mimeType ); + if ( archType == UNKNOWN_FORMAT ) + m_lastExtensionUnknown = true; + + return archType; +} + + +QString ArchiveFormatInfo::findMimeType( const KURL & url ) +{ + QString mimeType = KMimeType::findByURL( url )->name(); + if ( mimeType != "application/x-bzip2" && mimeType != "application/x-gzip" ) + return mimeType; + + QIODevice * dev = KFilterDev::deviceForFile( url.path(), mimeType ); + if ( !dev ) + return mimeType; + + char buffer[ 0x200 ]; + + dev->open( IO_ReadOnly ); + Q_LONG n = dev->readBlock( buffer, 0x200 ); + delete dev; + + if ( n == 0x200 && buffer[0] != 0 && !strncmp(buffer + 257, "ustar", 5) ) + { + if (mimeType == "application/x-bzip2") + return "application/x-tbz"; + else + return "application/x-tgz"; + } + + return mimeType; +} + +QString ArchiveFormatInfo::mimeTypeForDescription( const QString & description ) +{ + InfoList::Iterator it = m_formatInfos.begin(); + int index; + for( ; it != m_formatInfos.end(); ++it ) + { + index = (*it).allDescriptions.findIndex( description ); + if ( index != -1 ) + return (* (*it).mimeTypes.at( index ) ); + } + return QString::null; +} + +QString ArchiveFormatInfo::descriptionForMimeType( const QString & mimeType ) +{ + InfoList::Iterator it = m_formatInfos.begin(); + int index; + for( ; it != m_formatInfos.end(); ++it ) + { + index = (*it).mimeTypes.findIndex( mimeType ); + if ( index != -1 ) + return (* (*it).allDescriptions.at( index ) ); + } + return QString::null; +} + +QString ArchiveFormatInfo::defaultExtension( const QString & mimeType ) +{ + InfoList::Iterator it = m_formatInfos.begin(); + int index; + for( ; it != m_formatInfos.end(); ++it ) + { + index = (*it).mimeTypes.findIndex( mimeType ); + if ( index != -1 ) + return (* (*it).defaultExtensions.at( index ) ); + } + return QString::null; +} + +bool ArchiveFormatInfo::wasUnknownExtension() +{ + return m_lastExtensionUnknown; +} + diff --git a/ark/archiveformatinfo.h b/ark/archiveformatinfo.h new file mode 100644 index 0000000..5682a11 --- /dev/null +++ b/ark/archiveformatinfo.h @@ -0,0 +1,73 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) 2003 Georg Robbers <Georg.Robbers@urz.uni-hd.de> + + 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. + +*/ + +#ifndef ARCHIVEFORMATINFO_H +#define ARCHIVEFORMATINFO_H + +#include "arch.h" +#include <kmimetype.h> + +class ArchiveFormatInfo +{ +private: + ArchiveFormatInfo(); + +public: + static ArchiveFormatInfo * self(); + QString filter(); + const QStringList supportedMimeTypes( bool includeCompressed = true ); + QStringList allDescriptions(); + ArchType archTypeForMimeType( const QString & mimeType ); + ArchType archTypeByExtension( const QString & archname ); + ArchType archTypeForURL( const KURL & url ); + QString mimeTypeForDescription( const QString & description ); + QString findMimeType( const KURL & url ); + QString descriptionForMimeType( const QString & mimeType ); + QString defaultExtension( const QString & mimeType ); + bool wasUnknownExtension(); + +private: + void buildFormatInfos(); + void addFormatInfo( ArchType type, QString mime, QString stdExt ); + + struct FormatInfo + { + QStringList extensions; + QStringList mimeTypes; + QStringList allDescriptions; + QStringList defaultExtensions; + QString description; + enum ArchType type; + }; + + FormatInfo & find ( ArchType type ); + + typedef QValueList<FormatInfo> InfoList; + InfoList m_formatInfos; + + bool m_lastExtensionUnknown; + + static ArchiveFormatInfo * m_pSelf; +}; + +#endif // ARCHIVEFORMATINFO_H + diff --git a/ark/ark.desktop b/ark/ark.desktop new file mode 100644 index 0000000..d3615fe --- /dev/null +++ b/ark/ark.desktop @@ -0,0 +1,87 @@ +[Desktop Entry] +MimeType=application/x-gzip;application/x-lha;application/x-tar;application/x-tgz;application/x-tbz;application/x-tbz2;application/x-zip;application/zip;application/x-bzip;application/x-tzo;application/x-lzop;application/x-rar;application/x-zoo;application/x-tarz;application/x-archive;application/x-bzip2;application/x-jar;application/x-deb;application/x-ace;application/x-7z;application/x-arc;application/x-arj;application/x-compress;application/x-cpio;application/x-pak;application/x-zip-compressed +GenericName=Archiving Tool +GenericName[af]=Argiveer Program +GenericName[ar]=أداة أرشفة +GenericName[bg]=Работа с архиви +GenericName[br]=Ostilh merañ an Dielloù +GenericName[bs]=Alat za arhiviranje +GenericName[ca]=Eina d'arxivament +GenericName[cs]=Archivační nástroj +GenericName[cy]=Erfyn Archifo +GenericName[da]=Arkiveringsværktøj +GenericName[de]=Archivprogramm +GenericName[el]=Εργαλείο αρχειοθέτησης +GenericName[eo]=Arĥivilo +GenericName[es]=Archivador +GenericName[et]=Arhiivide haldamise rakendus +GenericName[eu]=Artxibaketa Tresna +GenericName[fa]=ابزار بایگانی +GenericName[fi]=Pakettienhallintatyökalu +GenericName[fr]=Outil de manipulation d'archives +GenericName[ga]=Uirlis Chartlannaithe +GenericName[he]=כלי לניהול ארכיונים +GenericName[hi]=अभिलेख औज़ार +GenericName[hr]=Uslužni program za arhiviranje +GenericName[hu]=Fájltömörítő +GenericName[is]=Vinna með safnskrár +GenericName[it]=Strumento di archiviazione +GenericName[ja]=アーカイバツール +GenericName[ka]=არქივებთან სამუშაო უტილიტა +GenericName[kk]=Архивтеу құралы +GenericName[km]=ឧបករណ៍ប័ណ្ណសារ +GenericName[lt]=Archyvavimo priemonė +GenericName[lv]=Arhivēšanas Rīks +GenericName[mk]=Алатка за архивирање +GenericName[ms]=Alatan Pengarkiban +GenericName[mt]=Għodda tal-arkivji +GenericName[nb]=Arkiveringsverktøy +GenericName[nds]=Archivwarktüüch +GenericName[ne]=उपकरण सङ्ग्रह गर्दै +GenericName[nl]=Archiefgereedschap +GenericName[nn]=Arkiveringsverktøy +GenericName[pa]=ਪੁਰਾਲੇਖ ਸੰਦ +GenericName[pl]=Narzędzie do archiwizacji +GenericName[pt]=Ferramenta de Armazenamento +GenericName[pt_BR]=Ferramenta de Arquivamento +GenericName[ro]=Utilitar de arhivare +GenericName[ru]=Архиватор +GenericName[sk]=Archivačný nástroj +GenericName[sl]=Orodje za ravnanje z arhivi +GenericName[sr]=Алат за архивирање +GenericName[sr@Latn]=Alat za arhiviranje +GenericName[sv]=Arkiveringsverktyg +GenericName[ta]=காப்பக கருவி +GenericName[tg]=Асбобҳои Бойгонӣ +GenericName[th]=เครื่องมือจัดการแฟ้มบีบอัด +GenericName[tr]=Arşivleme Aracı +GenericName[uk]=Засіб роботи з архівами +GenericName[uz]=Arxivlash vositasi +GenericName[uz@cyrillic]=Архивлаш воситаси +GenericName[ven]=Tshishumiswa tsha fhethu huno vhulungelwa hone zwithu zwa kale +GenericName[vi]=Công cụ nén +GenericName[wa]=Usteye d' årtchivaedje +GenericName[xh]=Isixhobo Sokuphatha i Archive +GenericName[zh_CN]=文件压缩归档工具 +GenericName[zh_TW]=壓縮工具 +GenericName[zu]=Ithuluzi Lomqulu +Name=Ark +Name[ar]=أرك +Name[eo]=Arĥivilo +Name[hi]=आर्क +Name[ne]=आर्क +Name[nso]=Areka +Name[pa]=ਆਕ +Name[ta]=ஆர்க் +Name[th]=อาร์ค +Exec=ark -caption "%c" %i %m %U +Icon=ark +Path= +DocPath=ark/index.html +Type=Application +Terminal=false +SwallowExec= +SwallowTitle= +X-DCOP-ServiceType=Unique +X-KDE-HasTempFileOption=true +Categories=Qt;KDE;Utility;X-KDE-Utilities-File; diff --git a/ark/ark.kcfg b/ark/ark.kcfg new file mode 100644 index 0000000..1c134a4 --- /dev/null +++ b/ark/ark.kcfg @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="arkrc"/> + <group name="generic"> + <entry name="extractionHistory" type="PathList"> + <label>Last folders used for extraction</label> + </entry> + <entry name="replaceOnlyWithNewer" type="Bool"> + <label>Replace old files only with newer files</label> + <whatsthis>If this option is enabled and you add filenames that already exist in an archive, only replace the old files if the added files are newer than them</whatsthis> + <default>false</default> + </entry> + <entry name="extractOverwrite" type="Bool"> + <label>Overwrite files (Zip, Tar, Zoo, Rar)</label> + <whatsthis>Overwrite any files that have matching names on disk with the one from the archive</whatsthis> + <default>false</default> + </entry> + </group> + <group name="Tar"> + <entry name="preservePerms" type="Bool"> + <label>Preserve permissions</label> + <whatsthis>Save the user, group, and permission settings on files. Use with care, as this may result in files being extracted that do not belong to any valid user on your computer</whatsthis> + <default>false</default> + </entry> + </group> + <group name="Zip"> + <entry name="forceMSDOS" type="Bool"> + <label>Force MS-DOS short filenames (Zip)</label> + <whatsthis>Force names of files in Zip archives to the DOS 8.3 format</whatsthis> + <default>false</default> + </entry> + <entry name="convertLF2CRLF" type="Bool"> + <label>Translate LF to DOS CRLF</label> + <default>false</default> + </entry> + <entry name="extractJunkPaths" type="Bool"> + <label>Ignore folder names (Zip)</label> + <whatsthis>Extract all the files into the extraction folder, ignoring any folder structure in the archive.</whatsthis> + <default>false</default> + </entry> + </group> + <group name="Rar"> + <entry name="rarStoreSymlinks" type="Bool"> + <label>Store symlinks as links (Zip, Rar)</label> + <default>true</default> + </entry> + <entry name="rarRecurseSubdirs" type="Bool"> + <label>Recursively add subfolders (Zip, Rar)</label> + <default>true</default> + </entry> + <entry name="rarToLower" type="Bool"> + <label>Convert filenames to lowercase (Zip, Rar)</label> + <default>false</default> + </entry> + <entry name="rarToUpper" type="Bool"> + <label>Convert filenames to uppercase</label> + <default>false</default> + </entry> + </group> + <group name="ark"> + <entry name="showSearchBar" type="Bool"> + <label>Show search bar</label> + <default>true</default> + </entry> + <entry name="KonquerorIntegration" type="Bool"> + <label>Enable Konqueror integration</label> + <whatsthis>Enables integration with Konqueror's context menus, letting you easily archive or unarchive files. This option will only work if you have the kdeaddons package installed.</whatsthis> + <default>true</default> + </entry> + <entry name="UseIntegratedViewer" type="Bool"> + <label>Use integrated viewer</label> + <default>true</default> + </entry> + <entry name="TarExe" type="String"> + <label>Tar Command</label> + <default>tar</default> + </entry> + <entry name="OpenDestinationFolder" type="Bool"> + <label>Open destination folder after extraction</label> + <default>false</default> + </entry> + <entry name="aceSupport" type="Bool"> + <label>Enable experimental support for loading ACE files</label> + <default>false</default> + </entry> + </group> +</kcfg> diff --git a/ark/ark_part.cpp b/ark/ark_part.cpp new file mode 100644 index 0000000..a574217 --- /dev/null +++ b/ark/ark_part.cpp @@ -0,0 +1,533 @@ +/* + Copyright (C) + + 2001: Macadamian Technologies Inc (author: Jian Huang, jian@macadamian.com) + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + 2005: Henrique Pinto <henrique.pinto@kdemail.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. + + 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. + +*/ + +#include "ark_part.h" +#include "arkfactory.h" +#include "arkwidget.h" +#include "settings.h" +#include "filelistview.h" +#include "searchbar.h" + +#include <kdebug.h> +#include <kpopupmenu.h> +#include <kmessagebox.h> +#include <kaboutdata.h> +#include <kxmlguifactory.h> +#include <kstatusbar.h> +#include <kiconloader.h> +#include <kio/netaccess.h> +#include <kpushbutton.h> +#include <ksqueezedtextlabel.h> + +#include <qfile.h> +#include <qtimer.h> + +KAboutData *ArkPart::createAboutData() +{ + KAboutData *about = new KAboutData("ark", I18N_NOOP("ark"), + "1.0", + I18N_NOOP("Ark KParts Component"), + KAboutData::License_GPL, + I18N_NOOP( "(c) 1997-2003, The Various Ark Developers" )); + about->addAuthor("Robert Palmbos",0, "palm9744@kettering.edu"); + about->addAuthor("Francois-Xavier Duranceau",0, "duranceau@kde.org"); + about->addAuthor("Corel Corporation (author: Emily Ezust)",0, + "emilye@corel.com"); + about->addAuthor("Corel Corporation (author: Michael Jarrett)", 0, + "michaelj@corel.com"); + about->addAuthor("Jian Huang"); + about->addAuthor( "Roberto Teixeira", 0, "maragato@kde.org" ); + + return about; +} + + + +ArkPart::ArkPart( QWidget *parentWidget, const char * /*widgetName*/, QObject *parent, + const char *name, const QStringList &, bool readWrite ) + : KParts::ReadWritePart(parent, name) +{ + kdDebug(1601)<<"ArkPart::ArkPart"<<endl; + setInstance(ArkFactory::instance()); + awidget = new ArkWidget( parentWidget, "ArkWidget" ); + + setWidget(awidget); + connect( awidget, SIGNAL( fixActions() ), this, SLOT( fixEnables() ) ); + connect( awidget, SIGNAL( disableAllActions() ), this, SLOT( disableActions() ) ); + connect( awidget, SIGNAL( signalFilePopup( const QPoint& ) ), this, SLOT( slotFilePopup( const QPoint& ) ) ); + connect( awidget, SIGNAL( setWindowCaption( const QString & ) ), this, SIGNAL( setWindowCaption( const QString & ) ) ); + connect( awidget, SIGNAL( removeRecentURL( const KURL & ) ), this, SIGNAL( removeRecentURL( const KURL & ) ) ); + connect( awidget, SIGNAL( addRecentURL( const KURL & ) ), this, SIGNAL( addRecentURL( const KURL & ) ) ); + + if( readWrite ) + setXMLFile( "ark_part.rc" ); + else + { + setXMLFile( "ark_part_readonly.rc" ); + } + setReadWrite( readWrite ); + + setupActions(); + + m_ext = new ArkBrowserExtension( this, "ArkBrowserExtension" ); + connect( awidget, SIGNAL( openURLRequest( const KURL & ) ), + m_ext, SLOT( slotOpenURLRequested( const KURL & ) ) ); + + m_bar = new ArkStatusBarExtension( this ); + connect( awidget, SIGNAL( setStatusBarText( const QString & ) ), m_bar, + SLOT( slotSetStatusBarText( const QString & ) ) ); + connect( awidget, SIGNAL( setStatusBarSelectedFiles( const QString & ) ), m_bar, + SLOT( slotSetStatusBarSelectedFiles( const QString & ) ) ); + connect( awidget, SIGNAL( setBusy( const QString & ) ), m_bar, + SLOT( slotSetBusy( const QString & ) ) ); + connect( awidget, SIGNAL( setReady() ), m_bar, + SLOT( slotSetReady() ) ); + connect( this, SIGNAL( started(KIO::Job*) ), SLOT( transferStarted(KIO::Job*) ) ); + connect( this, SIGNAL( completed() ), SLOT( transferCompleted() ) ); + connect( this, SIGNAL( canceled(const QString&) ), + SLOT( transferCanceled(const QString&) ) ); + + setProgressInfoEnabled( false ); +} + +ArkPart::~ArkPart() +{} + +void +ArkPart::setupActions() +{ + addFileAction = new KAction(i18n("Add &File..."), "ark_addfile", 0, awidget, + SLOT(action_add()), actionCollection(), "addfile"); + + addDirAction = new KAction(i18n("Add Folde&r..."), "ark_adddir", 0, awidget, + SLOT(action_add_dir()), actionCollection(), "adddir"); + + extractAction = new KAction(i18n("E&xtract..."), "ark_extract", 0, awidget, + SLOT(action_extract()), actionCollection(), "extract"); + + deleteAction = new KAction(i18n("De&lete"), "ark_delete", KShortcut(Qt::Key_Delete), awidget, + SLOT(action_delete()), actionCollection(), "delete"); + + viewAction = new KAction(i18n("to view something","&View"), "ark_view", 0, awidget, + SLOT(action_view()), actionCollection(), "view"); + + + openWithAction = new KAction(i18n("&Open With..."), 0, awidget, + SLOT(slotOpenWith()), actionCollection(), "open_with"); + + + editAction = new KAction(i18n("Edit &With..."), 0, awidget, + SLOT(action_edit()), actionCollection(), "edit"); + + selectAllAction = KStdAction::selectAll(awidget->fileList(), SLOT(selectAll()), actionCollection(), "select_all"); + + deselectAllAction = new KAction(i18n("&Unselect All"), 0, awidget->fileList(), SLOT(unselectAll()), actionCollection(), "deselect_all"); + + invertSelectionAction = new KAction(i18n("&Invert Selection"), 0, awidget->fileList(), SLOT(invertSelection()), actionCollection(), "invert_selection"); + + saveAsAction = KStdAction::saveAs(this, SLOT(file_save_as()), actionCollection()); + + //KStdAction::preferences(awidget, SLOT(showSettings()), actionCollection()); + + ( void ) new KAction( i18n( "Configure &Ark..." ), "configure" , 0, awidget, + SLOT( showSettings() ), actionCollection(), "options_configure_ark" ); + + + showSearchBar = new KToggleAction( i18n( "Show Search Bar" ), KShortcut(), actionCollection(), "options_show_search_bar" ); + showSearchBar->setCheckedState(i18n("Hide Search Bar")); + + showSearchBar->setChecked( ArkSettings::showSearchBar() ); + + connect( showSearchBar, SIGNAL( toggled( bool ) ), awidget, SLOT( slotShowSearchBarToggled( bool ) ) ); + + initialEnables(); +} + + +void ArkPart::fixEnables() +{ + bool bHaveFiles = ( awidget->getNumFilesInArchive() > 0 ); + bool bReadOnly = false; + bool bAddDirSupported = true; + QString extension; + if ( awidget->archiveType() == ZOO_FORMAT || awidget->archiveType() == AA_FORMAT + || awidget->archiveType() == COMPRESSED_FORMAT) + bAddDirSupported = false; + + if (awidget->archive()) + bReadOnly = awidget->archive()->isReadOnly(); + + saveAsAction->setEnabled(bHaveFiles); + selectAllAction->setEnabled(bHaveFiles); + deselectAllAction->setEnabled(bHaveFiles); + invertSelectionAction->setEnabled(bHaveFiles); + + deleteAction->setEnabled(bHaveFiles && awidget->numSelectedFiles() > 0 + && awidget->archive() && !bReadOnly); + addFileAction->setEnabled(awidget->isArchiveOpen() && + !bReadOnly); + addDirAction->setEnabled(awidget->isArchiveOpen() && + !bReadOnly && bAddDirSupported); + extractAction->setEnabled(bHaveFiles); + awidget->searchBar()->setEnabled(bHaveFiles); + + bool b = ( bHaveFiles + && (awidget->numSelectedFiles() == 1) + && (awidget->fileList()->currentItem()->childCount() == 0) + ); + viewAction->setEnabled( b ); + openWithAction->setEnabled( b ); + editAction->setEnabled( b && !bReadOnly ); // You can't edit files in read-only archives + emit fixActionState( bHaveFiles ); +} + +void ArkPart::initialEnables() +{ + saveAsAction->setEnabled( false ); + selectAllAction->setEnabled(false); + deselectAllAction->setEnabled(false); + invertSelectionAction->setEnabled(false); + + viewAction->setEnabled(false); + + deleteAction->setEnabled(false); + extractAction->setEnabled(false); + addFileAction->setEnabled(false); + addDirAction->setEnabled(false); + openWithAction->setEnabled(false); + editAction->setEnabled(false); + + awidget->searchBar()->setEnabled(false); +} + +void ArkPart::disableActions() +{ + saveAsAction->setEnabled(false); + selectAllAction->setEnabled(false); + deselectAllAction->setEnabled(false); + invertSelectionAction->setEnabled(false); + + viewAction->setEnabled(false); + deleteAction->setEnabled(false); + extractAction->setEnabled(false); + addFileAction->setEnabled(false); + addDirAction->setEnabled(false); + openWithAction->setEnabled(false); + editAction->setEnabled(false); + awidget->searchBar()->setEnabled(false); +} + +bool ArkPart::openURL( const KURL & url ) +{ + awidget->setRealURL( url ); + return KParts::ReadWritePart::openURL( KIO::NetAccess::mostLocalURL( url, awidget ) ); +} + +bool ArkPart::openFile() +{ + KURL url; + url.setPath( m_file ); + if( !QFile::exists( m_file ) ) + { + emit setWindowCaption( QString::null ); + emit removeRecentURL( awidget->realURL() ); + return false; + } + emit addRecentURL( awidget->realURL() ); + awidget->setModified( false ); + awidget->file_open( url ); + return true; +} + +void ArkPart::file_save_as() +{ + KURL u = awidget->getSaveAsFileName(); + if ( u.isEmpty() ) // user canceled + return; + + if ( !awidget->allowedArchiveName( u ) ) + awidget->convertTo( u ); + else if ( awidget->file_save_as( u ) ) + m_ext->slotOpenURLRequested( u ); + else + kdWarning( 1601 ) << "Save As failed." << endl; +} + +bool ArkPart::saveFile() +{ + return true; +} + +bool ArkPart::closeArchive() +{ + awidget->file_close(); + awidget->setModified( false ); + return ReadWritePart::closeURL(); +} + +bool ArkPart::closeURL() +{ + if ( !isReadWrite() || !awidget->isModified() || awidget->realURL().isLocalFile() ) + return closeArchive(); + + QString docName = awidget->realURL().prettyURL(); + + int res = KMessageBox::warningYesNoCancel( widget(), + i18n( "The archive \"%1\" has been modified.\n" + "Do you want to save it?" ).arg( docName ), + i18n( "Save Archive?" ), KStdGuiItem::save(), KStdGuiItem::discard() ); + + switch ( res ) + { + case KMessageBox::Yes : + return awidget->file_save_as( awidget->realURL() ) && closeArchive(); + + case KMessageBox::No : + return closeArchive(); + + default : // case KMessageBox::Cancel + return false; + } +} + +void ArkPart::slotFilePopup( const QPoint &pPoint ) +{ + if ( factory() ) + static_cast<KPopupMenu *>(factory()->container("file_popup", this))->popup(pPoint); +} + +void ArkPart::transferStarted( KIO::Job *job ) +{ + m_job = job; + + m_bar->slotSetBusy( i18n( "Downloading %1..." ).arg( m_url.prettyURL() ), + (job != 0), (job != 0) ); + + if ( job ) + { + disableActions(); + connect( job, SIGNAL( percent(KIO::Job*, unsigned long) ), + SLOT( progressInformation(KIO::Job*, unsigned long) ) ); + connect( m_bar->cancelButton(), SIGNAL( clicked() ), + SLOT( cancelTransfer() ) ); + } +} + +void ArkPart::transferCompleted() +{ + if ( m_job ) + { + disconnect( m_job, SIGNAL( percent(KIO::Job*, unsigned long) ), + this, SLOT( progressInformation(KIO::Job*, unsigned long) ) ); + m_job = 0; + } + + m_bar->slotSetReady(); +} + +void ArkPart::transferCanceled( const QString& errMsg ) +{ + m_job = 0; + if ( !errMsg.isEmpty() ) + { + KMessageBox::error( awidget, errMsg ); + } + initialEnables(); + m_bar->slotSetReady(); +} + +void ArkPart::progressInformation( KIO::Job *, unsigned long progress ) +{ + m_bar->setProgress( progress ); +} + +void ArkPart::cancelTransfer() +{ + disconnect( m_bar->cancelButton(), SIGNAL( clicked() ), + this, SLOT( cancelTransfer() ) ); + if ( m_job ) + { + m_job->kill( false ); + transferCanceled( QString() ); + } +} + +ArkBrowserExtension::ArkBrowserExtension( KParts::ReadOnlyPart * parent, const char * name ) + : KParts::BrowserExtension( parent, name ) +{ +} + +void ArkBrowserExtension::slotOpenURLRequested( const KURL & url ) +{ + emit openURLRequest( url, KParts::URLArgs() ); +} + +ArkStatusBarExtension::ArkStatusBarExtension( KParts::ReadWritePart * parent ) + : KParts::StatusBarExtension( parent ), + m_bBusy( false ), + m_pStatusLabelSelect( 0 ), + m_pStatusLabelTotal( 0 ), + m_pBusyText( 0 ), + m_cancelButton( 0 ), + m_pProgressBar( 0 ), + m_pTimer( 0 ) +{ +} + +ArkStatusBarExtension::~ArkStatusBarExtension() +{ +} + +void ArkStatusBarExtension::setupStatusBar() +{ + if ( m_pTimer // setup already done + || !statusBar() ) + { + return; + } + + m_pTimer = new QTimer( this ); + connect( m_pTimer, SIGNAL( timeout() ), this, SLOT( slotProgress() ) ); + + m_pStatusLabelTotal = new KSqueezedTextLabel( statusBar(), "StatusLabelTotal" ); + m_pStatusLabelTotal->setFrameStyle( QFrame::NoFrame ); + m_pStatusLabelTotal->setAlignment( AlignRight ); + m_pStatusLabelTotal->setText( i18n( "Total: 0 files" ) ); + + m_pStatusLabelSelect = new QLabel( statusBar(), "StatusLabelSelect" ); + m_pStatusLabelSelect->setFrameStyle( QFrame::NoFrame ); + m_pStatusLabelSelect->setAlignment( AlignLeft ); + m_pStatusLabelSelect->setText(i18n( "0 files selected" ) ); + + m_cancelButton = new KPushButton( SmallIcon( "cancel" ), QString(), statusBar(), "CancelButton" ); + + addStatusBarItem( m_pStatusLabelSelect, 3000, false ); + addStatusBarItem( m_pStatusLabelTotal, 3000, false ); +} + +void ArkStatusBarExtension::slotSetStatusBarText( const QString & text ) +{ + if ( !statusBar() ) + return; + + setupStatusBar(); + m_pStatusLabelTotal->setText( text ); +} + +void ArkStatusBarExtension::slotSetStatusBarSelectedFiles( const QString & text ) +{ + + if ( !statusBar() ) + return; + + setupStatusBar(); + m_pStatusLabelSelect->setText( text ); +} + +void ArkStatusBarExtension::slotSetBusy( const QString & text, bool showCancelButton, bool detailedProgress ) +{ + if ( m_bBusy || !statusBar() ) + return; + + setupStatusBar(); + if ( !m_pBusyText ) + { + m_pBusyText = new QLabel( statusBar() ); + + m_pBusyText->setAlignment( AlignLeft ); + m_pBusyText->setFrameStyle( QFrame::Panel | QFrame::Raised ); + } + + if ( !m_pProgressBar ) + { + m_pProgressBar = new KProgress( statusBar() ); + m_pProgressBar->setFixedHeight( m_pBusyText->fontMetrics().height() ); + } + + if ( !detailedProgress ) + { + m_pProgressBar->setTotalSteps( 0 ); + m_pProgressBar->setPercentageVisible( false ); + } + else + { + m_pProgressBar->setTotalSteps(100); + m_pProgressBar->setPercentageVisible( true ); + } + + m_pBusyText->setText( text ); + + removeStatusBarItem( m_pStatusLabelSelect ); + removeStatusBarItem( m_pStatusLabelTotal ); + + addStatusBarItem( m_pBusyText, 5, true ); + addStatusBarItem( m_pProgressBar, 1, true ); + if ( showCancelButton ) + { + addStatusBarItem( m_cancelButton, 0, true ); + } + + if ( !detailedProgress ) + { + m_pTimer->start( 200, false ); + } + m_bBusy = true; +} + +void ArkStatusBarExtension::slotSetReady() +{ + if ( !m_bBusy || !statusBar() ) + return; + + setupStatusBar(); + m_pTimer->stop(); + m_pProgressBar->setProgress( 0 ); + + removeStatusBarItem( m_pBusyText ); + removeStatusBarItem( m_pProgressBar ); + removeStatusBarItem( m_cancelButton ); + + addStatusBarItem( m_pStatusLabelSelect, 3000, false ); + addStatusBarItem( m_pStatusLabelTotal, 3000, false ); + + m_bBusy = false; +} + +void ArkStatusBarExtension::slotProgress() +{ + if ( !statusBar() ) + return; + + setupStatusBar(); + m_pProgressBar->setProgress( m_pProgressBar->progress() + 4 ); +} + +void ArkStatusBarExtension::setProgress( unsigned long progress ) +{ + if ( m_pProgressBar && ( m_pProgressBar->totalSteps() != 0 ) ) + { + m_pProgressBar->setProgress( progress ); + } +} + +#include "ark_part.moc" diff --git a/ark/ark_part.desktop b/ark/ark_part.desktop new file mode 100644 index 0000000..e167f26 --- /dev/null +++ b/ark/ark_part.desktop @@ -0,0 +1,135 @@ +[Desktop Entry] +MimeType=application/x-gzip;application/x-lha;application/x-tar;application/x-tgz;application/x-tbz;application/x-tbz2;application/x-zip;application/x-bzip;application/x-tzo;application/x-lzop;application/x-rar;application/x-zoo;application/x-tarz;application/x-archive;application/x-bzip2;application/x-jar;application/x-deb;application/x-ace;application/x-7z;application/x-arc;application/x-arj;application/x-compress;application/x-cpio;application/x-pak +Comment=Archive Handling Tool +Comment[af]=Argief Handtering Program +Comment[ar]=أداة التعامل مع الملفات المضغوطة +Comment[az]=Arxiv İşləmə Vasitəsi +Comment[bg]=Работа с архиви +Comment[br]=Ostilh merañ an dielloù +Comment[bs]=Uslužni program za arhiviranje +Comment[ca]=Eina per a treballar amb arxius +Comment[cs]=Program pro práci s archívy +Comment[cy]=Erfyn Triniaeth Archif +Comment[da]=Arkivbehandlingsværktøj +Comment[de]=Archiv-Verwaltung +Comment[el]=Εργαλείο χειρισμού αρχειοθηκών +Comment[eo]=Administrilo por arĥivoj +Comment[es]=Herramienta para archivos comprimidos +Comment[et]=Arhiivide haldamise rakendus +Comment[eu]=Artxiboak Kudeatzeko tresna +Comment[fa]=ابزار گرداندن بایگانی +Comment[fi]=Pakettienhallintatyökalu +Comment[fr]=Outil de manipulation d'archives +Comment[ga]=Uirlis Láimhseála Cartlainne +Comment[gl]=Ferramenta de Manexo de Arquivos +Comment[he]=כלי לניהול ארכיונים +Comment[hi]=अभिलेख संभाल औज़ार +Comment[hr]=Uslužni program za arhiviranje +Comment[hu]=Tömörítóprogram +Comment[id]=Program bantu menangani archive +Comment[is]=Vinna með safnskrár +Comment[it]=Gestione degli archivi +Comment[ja]=アーカイバツール +Comment[ka]=არქივებთან სამუშაო ხელსაწყო +Comment[kk]=Архивпен айналысу құралы +Comment[km]=ឧបករណ៍គ្រប់គ្រងប័ណ្ណសារ +Comment[lt]=Archyvo valdymo priemonė +Comment[lv]=Arhīvu Apstrādes Rīks +Comment[mk]=Алатка за справување со архивирани датотеки +Comment[ms]=Alatan Pengendalian Arkib +Comment[mt]=Għodda biex tuża l-arkivji +Comment[nb]=Arkivbehandlingsverktøy +Comment[nds]=En Warktüüch för de Archivpleeg +Comment[ne]=ह्यान्डलिङ उपकरण सङ्ग्रह गर्नुहोस् +Comment[nl]=Hulpprogramma voor het beheer van archieven +Comment[nn]=Verktøy for arkivhandsaming +Comment[pa]=ਪੁਰਾਲੇਖ ਬਣਾਉਣ ਸੰਦ +Comment[pl]=Program obsługi archiwów +Comment[pt]=Programa de gestão de arquivos +Comment[pt_BR]=Gerenciador de arquivos empacotados +Comment[ro]=Utilitar de manipulare arhive +Comment[ru]=Программа работы с архивами +Comment[sk]=Program na prácu s archívmi +Comment[sl]=Orodje za ravnanje z arhivi +Comment[sr]=Алат за руковање архивама +Comment[sr@Latn]=Alat za rukovanje arhivama +Comment[sv]=Verktyg för att hantera filarkiv +Comment[ta]= காப்பகத்தை கையாளும் கருவி +Comment[tg]=Асбобҳои Дасткории Бойгонӣ +Comment[th]=เครื่องมือจัดการแฟ้มบีบอัดทั้งหลาย +Comment[tr]=Arşiv İşleme Aracı +Comment[uk]=Засіб роботи з архівами +Comment[uz]=Arxiv uchun vosita +Comment[uz@cyrillic]=Архив учун восита +Comment[ven]=Tshishumiswa tshau fara tsha fhethu huno vhulungwa zwa kale +Comment[vi]=Công cụ xử lí các file nén +Comment[wa]=Usteye po-z apougnî les årtchives +Comment[xh]=Isixhobo sokuphatha i Archive +Comment[zh_CN]=文件压缩归档处理工具 +Comment[zh_TW]=壓縮檔案處理工具 +Comment[zu]=Ithuluzi Lokuphatha Umqulu +Name=Archiver +Name[af]=Argifeerder +Name[ar]=الضاغط +Name[az]=Arxivci +Name[br]=Dieller +Name[bs]=Arhiver +Name[ca]=Arxivador +Name[cs]=Archivátor +Name[cy]=Archifydd +Name[da]=Arkivbehandler +Name[de]=Archivprogramm +Name[el]=Πρόγραμμα αρχειοθέτησης +Name[eo]=Arĥivilo +Name[es]=Archivador +Name[et]=Arhiveerija +Name[eu]=Artxibalaria +Name[fa]=بایگانیکننده +Name[fr]=Archiveur +Name[gl]=Arquivador +Name[he]=מנהל הארכיונים +Name[hi]=अभिलेखक +Name[hr]=Arhiver +Name[hu]=Ark fájltömörítő +Name[is]=Skráasafnari +Name[it]=Utilità di archiviazione +Name[ja]=アーカイバ +Name[ka]=არქივარიუსი +Name[kk]=Архивтегіш +Name[km]=កម្មវិធីប័ណ្ណសារ +Name[lt]=Archyvatorius +Name[lv]=Arhivators +Name[mk]=Архивер +Name[ms]=Pengarkib +Name[nb]=Arkivbehandler +Name[ne]=पुरालेखक +Name[nl]=Archiefgereedschap +Name[nn]=Arkiverar +Name[pa]=ਆਕੀਵਰ +Name[pl]=Ark +Name[pt]=Ark +Name[pt_BR]=Arquivador +Name[ro]=Arhivator +Name[ru]=Архиватор +Name[sk]=Archivátor +Name[sl]=Arhivar +Name[sr]=Архивер +Name[sr@Latn]=Arhiver +Name[sv]=Arkiverare +Name[ta]= காப்பகம் +Name[tg]=Бойгонигар +Name[th]=อาร์ไคว์ฟเออร์ +Name[tr]=Arşivci +Name[uk]=Архіватор +Name[uz]=Arxivlagich +Name[uz@cyrillic]=Архивлагич +Name[ven]=Muvhulungi nwa zwithu zwa kale +Name[vi]=Luư trữ +Name[wa]=Årtchiveu +Name[xh]=Umenzi woshicilelo lukawonke-wonke noxwebhu lweMbali +Name[zh_CN]=压缩存档工具 +Name[zu]=Umqulu +Icon=ark +Type=Service +ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=libarkpart diff --git a/ark/ark_part.h b/ark/ark_part.h new file mode 100644 index 0000000..b5b7f6f --- /dev/null +++ b/ark/ark_part.h @@ -0,0 +1,148 @@ +/* + Copyright (C) + + 2001: Macadamian Technologies Inc (author: Jian Huang, jian@macadamian.com) + 2005: Henrique Pinto <henrique.pinto@kdemail.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. + + 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. + +*/ + +#ifndef ARK_PART_H +#define ARK_PART_H + +#include <kparts/part.h> +#include <kparts/browserextension.h> +#include <kparts/statusbarextension.h> +#include <kparts/factory.h> +#include <kaction.h> +#include <kprogress.h> + +#include <qlabel.h> + +class KAboutData; +class KPushButton; + +class ArkWidget; + +namespace KIO +{ + class Job; +} + + +class ArkBrowserExtension: public KParts::BrowserExtension +{ + Q_OBJECT +public: + ArkBrowserExtension( KParts::ReadOnlyPart * parent, const char * name = 0L ); +public slots: + void slotOpenURLRequested( const KURL & url ); +}; + +class ArkStatusBarExtension: public KParts::StatusBarExtension +{ + Q_OBJECT +public: + ArkStatusBarExtension( KParts::ReadWritePart * parent ); + ~ArkStatusBarExtension(); + + void setProgress( unsigned long progress ); + KPushButton* cancelButton() const { return m_cancelButton; } + +public slots: + void slotSetStatusBarSelectedFiles( const QString & text ); + void slotSetStatusBarText( const QString & text ); + void slotSetBusy( const QString & text, bool showCancelButton = false, bool detailedProgress = false ); + void slotSetReady(); + void slotProgress(); + +protected: + void setupStatusBar(); + +private: + bool m_bBusy; + QLabel *m_pStatusLabelSelect; // How many files are selected + QLabel *m_pStatusLabelTotal; // How many files in archive + QLabel *m_pBusyText; + KPushButton *m_cancelButton; // Cancel an operation + KProgress *m_pProgressBar; + QTimer *m_pTimer; +}; + + +class ArkPart: public KParts::ReadWritePart +{ + Q_OBJECT +public: + ArkPart( QWidget *parentWidget, const char *widgetName, QObject *parent, + const char *name, const QStringList &, bool readWrite ); + virtual ~ArkPart(); + + static KAboutData* createAboutData(); + +public slots: + void fixEnables();//rename to slotFixEnables()... + void disableActions(); + void slotFilePopup( const QPoint & pPoint ); + void file_save_as(); + bool saveFile(); + bool openURL( const KURL & url ); + bool closeURL(); + void transferStarted( KIO::Job * ); + void transferCompleted(); + void transferCanceled( const QString& errMsg ); + void progressInformation( KIO::Job *, unsigned long ); + void cancelTransfer(); + +signals: + void fixActionState( const bool & bHaveFiles ); + void removeRecentURL( const KURL & url ); + void addRecentURL( const KURL & url ); + +protected: + virtual bool openFile(); //Opening an archive file + bool closeArchive(); + void setupActions(); + void initialEnables(); + void init(); + +private: + ArkWidget *awidget; + ArkBrowserExtension *m_ext; + ArkStatusBarExtension *m_bar; + + KAction *saveAsAction; + KAction *addFileAction; + KAction *addDirAction; + KAction *extractAction; + KAction *deleteAction; + KAction *selectAllAction; + KAction *viewAction; + KAction *helpAction; + KAction *openWithAction; + KAction *deselectAllAction; + KAction *invertSelectionAction; + KAction *editAction; + + // the following have different enable rules from the above KActions + KAction *popupViewAction; + KAction *popupOpenWithAction; + KToggleAction *showSearchBar; + + KIO::Job *m_job; +}; + +#endif // ARK_PART_H diff --git a/ark/ark_part.rc b/ark/ark_part.rc new file mode 100644 index 0000000..ff0a894 --- /dev/null +++ b/ark/ark_part.rc @@ -0,0 +1,57 @@ +<!DOCTYPE kpartgui> +<kpartgui name="ark_kparts" version="8"> +<ActionProperties> + <Action name="select_all" icon="ark_selectall"/> +</ActionProperties> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="file_save_as"/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Action name="select"/> + <Action name="select_all"/> + <Action name="deselect_all"/> + <Action name="invert_selection"/> + </Menu> + <Menu name="action"><text>&Action</text> + <Action name="addfile"/> + <Action name="adddir"/> + <Action name="delete"/> + <Action name="extract"/> + <Action name="view"/> + <Action name="open_with"/> + <Action name="edit"/> + </Menu> + <Menu noMerge="1" name="settings"> + <text>&Settings</text> + <Merge name="StandardToolBarMenuHandler"/> + <Action name="options_show_search_bar" group="settings_show"/> + <Separator/> + <Action name="options_configure_keybinding" group="settings_configure"/> + <Action name="options_configure_toolbars" group="settings_configure"/> + <Action name="options_configure_ark" group="settings_configure"/> + </Menu> +</MenuBar> +<ToolBar name="mainToolBar"> + <Action name="addfile"/> + <Action name="adddir"/> + <Separator lineSeparator="true"/> + <Action name="extract"/> + <Action name="delete"/> + <Action name="view"/> + <Merge/> +</ToolBar> +<Menu name="file_popup"> + <Action name="extract"/> + <Action name="delete"/> + <Action name="view"/> + <Action name="open_with"/> + <Action name="edit"/> +</Menu> +<Menu name="archive_popup"> + <Action name="addfile"/> + <Action name="adddir"/> + <Separator lineSeparator="true"/> + <Action name="select_all"/> +</Menu> +</kpartgui> diff --git a/ark/ark_part_readonly.rc b/ark/ark_part_readonly.rc new file mode 100644 index 0000000..c124aae --- /dev/null +++ b/ark/ark_part_readonly.rc @@ -0,0 +1,42 @@ +<!DOCTYPE kpartgui> +<kpartgui name="ark_kparts" version="7"> +<ActionProperties> + <Action name="select_all" icon="ark_selectall"/> +</ActionProperties> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="file_save_as"/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Action name="select"/> + <Action name="select_all"/> + <Action name="deselect_all"/> + <Action name="invert_selection"/> + </Menu> + <Menu name="action"><text>&Action</text> + <Action name="extract"/> + <Action name="view"/> + <Action name="open_with"/> + </Menu> + <Menu noMerge="1" name="settings"> + <text>&Settings</text> + <Merge name="StandardToolBarMenuHandler"/> + <Action name="options_show_search_bar" group="settings_show"/> + <Separator/> + <Action name="options_configure_keybinding" group="settings_configure"/> + <Action name="options_configure_toolbars" group="settings_configure"/> + <Action name="options_configure_ark" group="settings_configure"/> + </Menu> +</MenuBar> +<ToolBar name="mainToolBar"> + <Action name="extract"/> + <Action name="view"/> +</ToolBar> +<Menu name="file_popup"> + <Action name="extract"/> + <Action name="view"/> + <Action name="open_with"/> + <Separator lineSeparator="true"/> + <Action name="select_all"/> +</Menu> +</kpartgui> diff --git a/ark/arkapp.cpp b/ark/arkapp.cpp new file mode 100644 index 0000000..c117d0b --- /dev/null +++ b/ark/arkapp.cpp @@ -0,0 +1,294 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2002-2003: Helio Chissini de Castro <helio@conectiva.com.br> + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + 1999-2000: Corel Corporation (author: Emily Ezust emilye@corel.com) + 1999: Francois-Xavier Duranceau duranceau@kde.org + + 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. + +*/ + +#include <dcopclient.h> +#include <kdebug.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <unistd.h> +#include <qfile.h> +#include <errno.h> + + +#include "arkapp.h" + +ArkApplication *ArkApplication::mInstance = NULL; + +// a helper function to follow a symlink and obtain the real filename +// Used in the ArkApplication functions that use the archive filename +// to make sure an archive isn't opened twice in different windows +// Now, readlink only gives one level so this function recurses. + +static QString resolveFilename(const QString & _arkname) +{ + char *buff; + int nread; + int iter = 1; + + while ( true ) + { + buff = new char[BUFSIZ*iter]; + nread = readlink( QFile::encodeName(_arkname), buff, BUFSIZ); + if (-1 == nread) + { + if ( EINVAL == errno ) // not a symbolic link. Stopping condition. + { + delete [] buff; + return _arkname; + } + else if ( ENAMETOOLONG == errno ) + { + kdDebug(1601) << "resolveFilename: have to reallocate - name too long!" << endl; + iter++; + delete [] buff; + continue; + } + else + { + delete [] buff; + // the other errors will be taken care of already in simply + // // opening the archive (i.e., the user will be notified) + return ""; + } + } + else + { + buff[nread] = '\0'; // readlink doesn't null terminate + QString name = QFile::decodeName( buff ); + delete [] buff; + + // watch out for relative pathnames + if (name.at(0) != '/') + { + // copy the path from _arkname + int index = _arkname.findRev('/'); + name = _arkname.left(index + 1) + name; + } + kdDebug(1601) << "Now resolve " << name << endl; + + return resolveFilename( name ); + } + } +} + + +ArkApplication * ArkApplication::getInstance() +{ + if (mInstance == NULL) + { + mInstance = new ArkApplication(); + } + return mInstance; +} + +ArkApplication::ArkApplication() + : KUniqueApplication(), m_windowCount(0) +{ + m_mainwidget = new QWidget; + setMainWidget(m_mainwidget); +} + +int +ArkApplication::newInstance() +{ + + // If we are restored by session management, we don't need to open + // another window on startup. + if (restoringSession()) return 0; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if ( args->isSet( "extract-to" ) ) + { + if ( args->count() == 2 ) + { + MainWindow *arkWin = new MainWindow(); + + arkWin->extractTo( args->url( 0 ), args->url( 1 ), args->isSet( "guess-name" ) ); + return 0; + } + else + { + KCmdLineArgs::usage( i18n( "Wrong number of arguments specified" ) ); + return 0; + } + } + + if ( args->isSet( "add-to" ) && ( !args->isSet( "add" ) ) ) + { + if ( args->count() < 2 ) + { + KCmdLineArgs::usage( i18n( "You need to specify at least one file to be added to the archive." ) ); + return 0; + } + else + { + KURL::List URLList; + for ( int c = 0; c < args->count()-1 ; c++ ) + URLList.append( args->url( c ) ); + + MainWindow *arkWin = new MainWindow(); + + arkWin->addToArchive( URLList, args->cwd(), args->url( args->count()-1 ) ); + return 0; + } + } + + if ( args->isSet( "add" ) && args->isSet( "add-to" ) ) // HACK + { + bool oneFile = (args->count() == 2 ) ; + + QString extension = args->arg( 0 ); + KURL archiveName = args->url( 1 ); // the filename + + // if more than one file -> use directory name + if ( !oneFile ) + archiveName.setPath( archiveName.directory() ); + + archiveName.setFileName( archiveName.fileName() + extension ); + KURL::List URLList; + for ( int c = 1; c < args->count(); c++ ) + URLList.append( args->url( c ) ); + + MainWindow *arkWin = new MainWindow(); + + arkWin->addToArchive( URLList, args->cwd(), archiveName, !oneFile ); + return 0; + } + + + if ( args->isSet( "add" ) && ( !args->isSet( "add-to" ) ) ) + { + if ( args->count() < 1 ) + { + KCmdLineArgs::usage( i18n( "You need to specify at least one file to be added to the archive." ) ); + return 0; + } + else + { + KURL::List URLList; + for ( int c = 0; c < args->count() ; c++ ) + URLList.append( args->url( c ) ); + + MainWindow *arkWin = new MainWindow(); + + arkWin->addToArchive( URLList, args->cwd() ); + return 0; + } + } + + + int i = 0; + KURL url; + bool doAutoExtract = args->isSet("extract"); + bool tempFile = KCmdLineArgs::isTempFileSet(); + do + { + if (args->count() > 0) + { + url = args->url(i); + } + MainWindow *arkWin = new MainWindow(); + arkWin->show(); + if(doAutoExtract) + { + arkWin->setExtractOnly(true); + } + if (!url.isEmpty()) + { + arkWin->openURL(url, tempFile); + } + + ++i; + } while (i < args->count()); + + args->clear(); + return 0; +} + + +void +ArkApplication::addOpenArk(const KURL & _arkname, MainWindow *_ptr) +{ + QString realName; + if( _arkname.isLocalFile() ) + { + realName = resolveFilename( _arkname.path() ); // follow symlink + kdDebug(1601) << " Real name of " << _arkname.prettyURL() << " is " << realName << endl; + } + else + realName = _arkname.prettyURL(); + openArksList.append(realName); + m_windowsHash.replace(realName, _ptr); + kdDebug(1601) << "Saved ptr " << _ptr << " added open ark: " << realName << endl; +} + +void +ArkApplication::removeOpenArk(const KURL & _arkname) +{ + QString realName; + if ( _arkname.isLocalFile() ) + realName = resolveFilename( _arkname.path() ); // follow symlink + else + realName = _arkname.prettyURL(); + kdDebug(1601) << "Removing name " << _arkname.prettyURL() << endl; + openArksList.remove(realName); + m_windowsHash.remove(realName); +} + +void +ArkApplication::raiseArk(const KURL & _arkname) +{ + kdDebug( 1601 ) << "ArkApplication::raiseArk " << endl; + MainWindow *window; + QString realName; + if( _arkname.isLocalFile() ) + realName = resolveFilename(_arkname.path()); // follow symlink + else + realName = _arkname.prettyURL(); + window = m_windowsHash[realName]; + kdDebug(1601) << "ArkApplication::raiseArk " << window << endl; + // raise didn't seem to be enough. Not sure why! + // This might be annoying though. + //window->hide(); + //window->show(); + window->raise(); +} + +bool +ArkApplication::isArkOpenAlready(const KURL & _arkname) +{ + QString realName; + if ( _arkname.isLocalFile() ) + realName = resolveFilename(_arkname.path()); // follow symlink + else + realName = _arkname.prettyURL(); + return ( openArksList.findIndex(realName) != -1 ); +} + +#include "arkapp.moc" + diff --git a/ark/arkapp.h b/ark/arkapp.h new file mode 100644 index 0000000..1d1b474 --- /dev/null +++ b/ark/arkapp.h @@ -0,0 +1,93 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2002: Helio Chissini de Castro <helio@conectiva.com.br> + 1999-2000: Corel Corporation (author: Emily Ezust emilye@corel.com) + 1999: Francois-Xavier Duranceau duranceau@kde.org + + 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. + +*/ + +#ifndef ARKAPP_H +#define ARKAPP_H + +#include "mainwindow.h" + +// QT includes +#include <qdict.h> + +// KDE includes +#include <kuniqueapplication.h> + +class QString; +class QStringList; + +class EqualKey +{ + public: + bool operator()(const QString & str1, const QString & str2) const + { + return (str1 == str2); + } +}; + + +// This class follows the singleton pattern. +class ArkApplication : public KUniqueApplication +{ + Q_OBJECT + public: + virtual int newInstance(); + virtual ~ArkApplication() {} + + // keep track of windows so we know when to quit + int windowCount() { return m_windowCount; } + int addWindow() { ++m_windowCount; return m_windowCount; } + void removeWindow() { --m_windowCount;} + + // keep track of open archive names so we don't open one twice + // note that ArkWidget is not a pointer to const because raise() + // requires later a pointer to nonconst. + void addOpenArk(const KURL & _arkname, MainWindow * _ptr); + void removeOpenArk(const KURL & _arkname); + + bool isArkOpenAlready(const KURL & _arkname); + + void raiseArk(const KURL & _arkname); + + // use this function to access data from other modules. + static ArkApplication *getInstance(); + + protected: + ArkApplication(); + + private: + QWidget *m_mainwidget; // to be the parent of all ArkWidgets + int m_windowCount; + + QStringList openArksList; + + // a hash to obtain the window associated with a filename. + // given a QString key, you get an ArkWidget * pointer. + QDict<MainWindow> m_windowsHash; + + static ArkApplication *mInstance; +}; + +#endif // ARKAPP_H diff --git a/ark/arkfactory.cpp b/ark/arkfactory.cpp new file mode 100644 index 0000000..8fcd262 --- /dev/null +++ b/ark/arkfactory.cpp @@ -0,0 +1,68 @@ +/* + ark -- archiver for the KDE project + + Copyright (C) 2003: Georg Robbers <georg.robbers@urz.uni-hd.de> + + 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. + +*/ + +#include <kaboutdata.h> +#include <kinstance.h> + +#include "ark_part.h" +#include "arkfactory.h" + +KInstance* ArkFactory::s_instance = 0L; +KAboutData* ArkFactory::s_about = 0L; +int ArkFactory::instanceNumber = 0; + +K_EXPORT_COMPONENT_FACTORY( libarkpart, ArkFactory ) + +ArkFactory::~ArkFactory() +{ + delete s_instance; + delete s_about; + s_instance = 0L; +} + +KParts::Part * ArkFactory::createPartObject( QWidget *parentWidget, + const char *widgetName, QObject *parent, + const char *name, const char *classname, + const QStringList &args ) +{ + bool readWrite = false; // for e.g. Browser/View or KParts::ReadOnlyPart + if ( QCString( classname ) == "KParts::ReadWritePart" + || QCString( classname ) == "ArkPart" ) + { + readWrite = true; + } + ArkPart* obj = new ArkPart( parentWidget, widgetName, parent, name, + args, readWrite ); + //kdDebug( 1601 ) << "classname is: " << QCString( classname ) << endl; + return obj; +} + +KInstance* ArkFactory::instance() +{ + instanceNumber++; + if( !s_instance ) + { + s_about = ArkPart::createAboutData(); + s_instance = new KInstance( s_about ); + } + return s_instance; +} + diff --git a/ark/arkfactory.h b/ark/arkfactory.h new file mode 100644 index 0000000..ec3534a --- /dev/null +++ b/ark/arkfactory.h @@ -0,0 +1,43 @@ +/* + ark -- archiver for the KDE project + + Copyright (C) 2003: Georg Robbers <georg.robbers@urz.uni-hd.de> + + 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. + +*/ + +#ifndef ARKFACTORY_H +#define ARKFACTORY_H +#include <kparts/factory.h> + +class ArkFactory : public KParts::Factory +{ +public: + ArkFactory() : KParts::Factory() {} + virtual ~ArkFactory(); + virtual KParts::Part *createPartObject( + QWidget *parentWidget = 0,const char *widgetName = 0, + QObject *parent = 0, const char *name = 0, + const char *classname = "KParts::Part", + const QStringList &args = QStringList() ); + static KInstance* instance(); + private: + static KInstance* s_instance; + static KAboutData* s_about; + static int instanceNumber; +}; + +#endif diff --git a/ark/arkui.rc b/ark/arkui.rc new file mode 100644 index 0000000..335abc8 --- /dev/null +++ b/ark/arkui.rc @@ -0,0 +1,22 @@ +<!DOCTYPE kpartgui> +<kpartgui name="ark" version="9"> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="new_window"/> + <Action name="reload_arch"/> + <Merge/> + </Menu> + <Menu name="settings"> + <DefineGroup name="settings_show" append="show_merge"/> + <DefineGroup name="settings_configure" append="configure_merge"/> + </Menu> + <Merge/> +</MenuBar> +<Menu name="archive_popup"> + <Action name="file_new"/> + <Action name="file_open"/> + <Action name="file_close"/> + <Separator lineSeparator="true"/> + <Merge/> +</Menu> +</kpartgui> diff --git a/ark/arkutils.cpp b/ark/arkutils.cpp new file mode 100644 index 0000000..1b4ed0a --- /dev/null +++ b/ark/arkutils.cpp @@ -0,0 +1,230 @@ +/* + + $Id$ + + 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 + 2003: Hans Petter Bieker <bieker@kde.org> + + 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. + +*/ + +#include <config.h> + +// C includes +#include <stdlib.h> +#include <time.h> + +#include <errno.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <unistd.h> +#include <config.h> + +#ifdef _HPUX_SOURCE +#include <sys/vfs.h> +#endif + +// for statfs: +#ifdef BSD4_4 +#include <sys/mount.h> +#elif defined(__linux__) +#include <sys/vfs.h> +#elif defined(__sun) +#include <sys/statvfs.h> +#define STATFS statvfs +#elif defined(_AIX) +#include <sys/statfs.h> +#endif + +#ifndef STATFS +#define STATFS statfs +#endif + +// KDE includes +#include <kdebug.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <klargefile.h> + +// Qt includes +#include <qfile.h> + +#include "arkutils.h" + +QString ArkUtils::getTimeStamp(const QString &_month, + const QString &_day, + const QString &_yearOrTime) +{ + // Make the date format sortable. + // Month is in _month, day is in _day. + // In _yearOrTime is either a year or a time. + // If it's March, we'll see the year for all dates up to October 1999. + // (five months' difference - e.g., if it's Apr, then get years up to Nov) + + char month[4]; + strncpy(month, _month.ascii(), 3); + month[3] = '\0'; + int nMonth = getMonth(month); + int nDay = _day.toInt(); + + kdDebug(1601) << "Month is " << nMonth << ", Day is " << nDay << endl; + + time_t t = time(0); + if (t == -1) + exit(1); + struct tm *now = localtime(&t); + int thisYear = now->tm_year + 1900; + int thisMonth = now->tm_mon + 1; + + QString year, timestamp; + + if (_yearOrTime.contains(":")) + // it has a timestamp so we have to figure out the year + { + year.sprintf("%d", ArkUtils::getYear(nMonth, thisYear, thisMonth)); + timestamp = _yearOrTime; + } + else + { + year = _yearOrTime; + if (year.right(1) == " ") + year = year.left(4); + if (year.left(1) == " ") + year = year.right(4); + + timestamp = "??:??"; + } + + QString retval; + retval.sprintf("%s-%.2d-%.2d %s", + year.utf8().data(), nMonth, nDay, + timestamp.utf8().data()); + return retval; +} + +int ArkUtils::getMonth(const char *strMonth) + // returns numeric value for three-char month string +{ + static char months[13][4] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + int nIndex; + for (nIndex = 1; nIndex < 13; ++nIndex) + { + if (0 == strcmp(strMonth, months[nIndex])) + return nIndex; + } + return 0; +} + +// This function gets the year from an LHA or ls -l timestamp. +// Note: LHA doesn't seem to display the year if the file is more +// than 6 months into the future, so this will fail to give the correct +// year (of course it is hoped that there are not too many files lying +// around from the future). + +int ArkUtils::getYear(int theMonth, int thisYear, int thisMonth) +{ + int monthDiff = QABS(thisMonth - theMonth); + if (monthDiff > 6) + return (thisYear - 1); + else + return thisYear; +} + +QString ArkUtils::fixYear(const QString& strYear) +{ + // returns 4-digit year by guessing from two-char year string. + // Remember: this is used for file timestamps. There probably aren't any + // files that were created before 1970, so that's our cutoff. Of course, + // in 2070 we'll have some problems.... + + if ( strYear.length() != 2 ) return strYear; + + bool ok; + int y = strYear.toInt( &ok ); + + if ( ok ) + { + if ( y > 70 ) + y += 1900; + else + y += 2000; + + return QString::number( y ); + } + else + return QString::null; +} + +bool +ArkUtils::haveDirPermissions( const QString &strFile ) +{ + return ( access( QFile::encodeName( strFile ), W_OK ) == 0 ); +} + +bool +ArkUtils::diskHasSpace(const QString &dir, KIO::filesize_t size) + // check if disk has enough space to accommodate (a) new file(s) of + // the given size in the partition containing the given directory +{ + kdDebug( 1601 ) << "diskHasSpace() " << "dir: " << dir << " Size: " << size << endl; + + struct STATFS buf; + if (STATFS(QFile::encodeName(dir), &buf) == 0) + { + double nAvailable = (double)buf.f_bavail * buf.f_bsize; + if ( nAvailable < (double)size ) + { + KMessageBox::error(0, i18n("You have run out of disk space.")); + return false; + } + } + else + { + // something bad happened + kdWarning( 1601 ) << "diskHasSpace() failed" << endl; + // Q_ASSERT(0); + } + return true; +} + +KIO::filesize_t +ArkUtils::getSizes(QStringList *list) +{ + KIO::filesize_t sum = 0; + QString str; + KDE_struct_stat st; + + for ( QStringList::Iterator it = list->begin(); it != list->end(); ++it) + { + str = *it; + str = str.right(str.length()-5); + if (KDE_stat(QFile::encodeName(str), &st ) < 0) + continue; + sum += st.st_size; + } + return sum; +} diff --git a/ark/arkutils.h b/ark/arkutils.h new file mode 100644 index 0000000..4ddea65 --- /dev/null +++ b/ark/arkutils.h @@ -0,0 +1,56 @@ +// -*-C++-*- emacs magic for .h files +/* + + $Id$ + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com) + 2003: Hans Petter Bieker <bieker@kde.org> + + 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. + +*/ + +#ifndef ARKUTILS_H +#define ARKUTILS_H + +#include <qstring.h> + +#include <kio/global.h> + +class QStringList; + +// various functions for massaging timestamps +namespace ArkUtils +{ + int getYear(int theMonth, int thisYear, int thisMonth); + int getMonth(const char *strMonth); + QString fixYear(const QString& strYear); + + QString getTimeStamp(const QString &month, + const QString &day, + const QString &year); + bool haveDirPermissions(const QString &strFile); + bool diskHasSpace(const QString &dir, KIO::filesize_t size); + KIO::filesize_t getSizes(QStringList *list); +} + +#endif diff --git a/ark/arkviewer.cpp b/ark/arkviewer.cpp new file mode 100644 index 0000000..1ea76ac --- /dev/null +++ b/ark/arkviewer.cpp @@ -0,0 +1,103 @@ +/* + * ark: A program for modifying archives via a GUI. + * + * Copyright (C) 2004, Henrique Pinto <henrique.pinto@kdemail.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. + * + * 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. + * + */ + +#include "arkviewer.h" + +#include <klocale.h> +#include <kparts/componentfactory.h> +#include <kmimetype.h> +#include <kdebug.h> +#include <kurl.h> +#include <kglobal.h> +#include <kiconloader.h> + +#include <qvbox.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qframe.h> +#include <qurl.h> + + +ArkViewer::ArkViewer( QWidget * parent, const char * name ) + : KDialogBase( parent, name, false, QString::null, Close ), m_part( 0 ) +{ + m_widget = new QVBox( this ); + m_widget->layout()->setSpacing( 10 ); + + connect( this, SIGNAL( finished() ), this, SLOT( slotFinished() ) ); + + setMainWidget( m_widget ); +} + +ArkViewer::~ArkViewer() +{ + saveDialogSize( "ArkViewer" ); +} + +void ArkViewer::slotFinished() +{ + delete m_part; + m_part = 0; + delayedDestruct(); +} + +bool ArkViewer::view( const KURL& filename ) +{ + KMimeType::Ptr mimetype = KMimeType::findByURL( filename, 0, true ); + + setCaption( filename.fileName() ); + + QSize size = configDialogSize( "ArkViewer" ); + if (size.width() < 200) + size = QSize(560, 400); + setInitialSize( size ); + + QFrame *header = new QFrame( m_widget ); + QHBoxLayout *headerLayout = new QHBoxLayout( header ); + headerLayout->setAutoAdd( true ); + + QLabel *iconLabel = new QLabel( header ); + iconLabel->setPixmap( mimetype->pixmap( KIcon::Desktop ) ); + iconLabel->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ); + + QVBox *headerRight = new QVBox( header ); + new QLabel( QString( "<qt><b>%1</b></qt>" ) + .arg( filename.fileName() ), headerRight + ); + new QLabel( mimetype->comment(), headerRight ); + + header->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Maximum ); + + m_part = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadOnlyPart>( mimetype->name(), QString::null, m_widget, 0, this ); + + if ( m_part ) + { + m_part->openURL( filename ); + show(); + return true; + } + else + { + return false; + } +} + +#include "arkviewer.moc" diff --git a/ark/arkviewer.h b/ark/arkviewer.h new file mode 100644 index 0000000..e0fda83 --- /dev/null +++ b/ark/arkviewer.h @@ -0,0 +1,47 @@ +#ifndef ARKVIEWER_H +#define ARKVIEWER_H + +/* + * ark: A program for modifying archives via a GUI. + * + * Copyright (C) 2004, Henrique Pinto <henrique.pinto@kdemail.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. + * + * 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. + * + */ + +#include <kdialogbase.h> +#include <kparts/part.h> + +class ArkViewer : public KDialogBase +{ + Q_OBJECT + + public: + ArkViewer( QWidget* parent = 0, const char * name = 0 ); + ~ArkViewer(); + + bool view( const KURL& filename ); + + protected slots: + void slotFinished(); + + private: + KParts::ReadOnlyPart *m_part; + QWidget *m_widget; +}; + +#endif // ARKVIEWER_H + diff --git a/ark/arkwidget.cpp b/ark/arkwidget.cpp new file mode 100644 index 0000000..d0fa3d4 --- /dev/null +++ b/ark/arkwidget.cpp @@ -0,0 +1,2262 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2004-2005: Henrique Pinto <henrique.pinto@kdemail.net> + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + 2002-2003: Helio Chissini de Castro <helio@conectiva.com.br> + 2001-2002: Roberto Teixeira <maragato@kde.org> + 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. + +*/ + +#include <sys/types.h> +#include <sys/stat.h> + +// Qt includes +#include <qlayout.h> +#include <qstringlist.h> +#include <qlabel.h> +#include <qcheckbox.h> +#include <qdir.h> + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kio/netaccess.h> +#include <kio/job.h> +#include <kopenwith.h> +#include <ktempfile.h> +#include <kmimemagic.h> +#include <kmimetype.h> +#include <kstandarddirs.h> +#include <ktempdir.h> +#include <kprocess.h> +#include <kfiledialog.h> +#include <kdirselectdialog.h> +#include <kurldrag.h> +#include <klistviewsearchline.h> +#include <ktoolbar.h> +#include <kconfigdialog.h> +#include <ktrader.h> +#include <kurl.h> + +// settings +#include "settings.h" +#include "general.h" +#include "addition.h" +#include "extraction.h" +#include <kpopupmenu.h> +#include <kdialog.h> + +// ark includes +#include "arkapp.h" +#include "archiveformatdlg.h" +#include "extractiondialog.h" +#include "arkwidget.h" +#include "filelistview.h" +#include "arkutils.h" +#include "archiveformatinfo.h" +#include "compressedfile.h" +#include "searchbar.h" +#include "arkviewer.h" + +static void viewInExternalViewer( ArkWidget* parent, const KURL& filename ) +{ + QString mimetype = KMimeType::findByURL( filename )->name(); + bool view = true; + + if ( KRun::isExecutable( mimetype ) ) + { + QString text = i18n( "The file you're trying to view may be an executable. Running untrusted executables may compromise your system's security.\nAre you sure you want to run that file?" ); + view = ( KMessageBox::warningContinueCancel( parent, text, QString::null, i18n("Run Nevertheless") ) == KMessageBox::Continue ); + } + + if ( view ) + KRun::runURL( filename, mimetype ); + +} + +//---------------------------------------------------------------------- +// +// Class ArkWidget starts here +// +//---------------------------------------------------------------------- + +ArkWidget::ArkWidget( QWidget *parent, const char *name ) + : QVBox(parent, name), m_bBusy( false ), m_bBusyHold( false ), + m_extractOnly( false ), m_extractRemote(false), + m_openAsMimeType(QString::null), m_pTempAddList(NULL), + m_bArchivePopupEnabled( false ), + m_convert_tmpDir( NULL ), m_convertSuccess( false ), + m_createRealArchTmpDir( NULL ), m_extractRemoteTmpDir( NULL ), + m_modified( false ), m_searchToolBar( 0 ), m_searchBar( 0 ), + arch( 0 ), m_archType( UNKNOWN_FORMAT ), m_fileListView( 0 ), + m_nSizeOfFiles( 0 ), m_nSizeOfSelectedFiles( 0 ), m_nNumFiles( 0 ), + m_nNumSelectedFiles( 0 ), m_bIsArchiveOpen( false ), + m_bIsSimpleCompressedFile( false ), + m_bDropSourceIsSelf( false ), m_extractList( 0 ) +{ + m_tmpDir = new KTempDir( locateLocal( "tmp", "ark" ) ); + + if ( m_tmpDir->status() != 0 ) + { + kdWarning( 1601 ) << "Could not create a temporary directory. status() returned " + << m_tmpDir->status() << "." << endl; + m_tmpDir = NULL; + } + + m_searchToolBar = new KToolBar( this, "searchBar" ); + m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() ); + + QLabel * l1 = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" ); + m_searchBar = new SearchBar( m_searchToolBar, 0 ); + l1->setBuddy( m_searchBar ); + + m_searchToolBar->setStretchableWidget( m_searchBar ); + + if ( !ArkSettings::showSearchBar() ) + m_searchToolBar->hide(); + + createFileListView(); + + m_searchBar->setListView( m_fileListView ); + + // enable DnD + setAcceptDrops(true); + setFocusProxy(m_searchBar); +} + +ArkWidget::~ArkWidget() +{ + cleanArkTmpDir(); + ready(); + delete m_pTempAddList; + delete m_fileListView; + m_fileListView = 0; + delete arch; + ArkSettings::writeConfig(); +} + +void ArkWidget::cleanArkTmpDir() +{ + removeDownloadedFiles(); + if ( m_tmpDir ) + { + m_tmpDir->unlink(); + delete m_tmpDir; + m_tmpDir = NULL; + } +} + +void ArkWidget::closeArch() +{ + if ( isArchiveOpen() ) + { + delete arch; + arch = 0; + m_bIsArchiveOpen = false; + } + + if ( m_fileListView ) + { + m_fileListView->clear(); + m_fileListView->clearHeaders(); + } +} + +//////////////////////////////////////////////////////////////////// +///////////////////////// updateStatusTotals /////////////////////// +//////////////////////////////////////////////////////////////////// + +void +ArkWidget::updateStatusTotals() +{ + m_nNumFiles = m_fileListView->totalFiles(); + m_nSizeOfFiles = m_fileListView->totalSize(); + + QString strInfo = i18n( "%n file %1", "%n files %1", m_nNumFiles ) + .arg( KIO::convertSize( m_nSizeOfFiles ) ); + emit setStatusBarText(strInfo); +} + +void +ArkWidget::busy( const QString & text ) +{ + emit setBusy( text ); + + if ( m_bBusy ) + return; + + m_fileListView->setEnabled( false ); + + QApplication::setOverrideCursor( waitCursor ); + m_bBusy = true; +} + +void +ArkWidget::holdBusy() +{ + if ( !m_bBusy || m_bBusyHold ) + return; + + m_bBusyHold = true; + QApplication::restoreOverrideCursor(); +} + +void +ArkWidget::resumeBusy() +{ + if ( !m_bBusyHold ) + return; + + m_bBusyHold = false; + QApplication::setOverrideCursor( waitCursor ); +} + +void +ArkWidget::ready() +{ + if ( !m_bBusy ) + return; + + m_fileListView->setEnabled( true ); + + QApplication::restoreOverrideCursor(); + emit setReady(); + m_bBusyHold = false; + m_bBusy = false; +} + +////////////////////////////////////////////////////////////////////// +////////////////////// file_save_as ////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +KURL +ArkWidget::getSaveAsFileName() +{ + QString defaultMimeType; + if ( m_openAsMimeType.isNull() ) + defaultMimeType = KMimeType::findByPath( m_strArchName )->name(); + else + defaultMimeType = m_openAsMimeType; + + KURL u; + QString suggestedName; + if ( m_realURL.isLocalFile() ) + suggestedName = m_realURL.url(); + else + suggestedName = m_realURL.fileName( false ); + + do + { + u = getCreateFilename( i18n( "Save Archive As" ), defaultMimeType, true, suggestedName ); + if ( u.isEmpty() ) + return u; + if( allowedArchiveName( u ) || ( ArchiveFormatInfo::self()->archTypeByExtension( u.path() ) != UNKNOWN_FORMAT ) ) + break; + KMessageBox::error( this, i18n( "Please save your archive in the same format as the original.\nHint: Use one of the suggested extensions." ) ); + } + while ( true ); + return u; +} + +bool +ArkWidget::file_save_as( const KURL & u ) +{ + bool success = KIO::NetAccess::upload( m_strArchName, u, this ); + if ( m_modified && success ) + m_modified = false; + return success; +} + +void +ArkWidget::convertTo( const KURL & u ) +{ + busy( i18n( "Saving..." ) ); + m_convert_tmpDir = new KTempDir( tmpDir() + "convtmp" ); + m_convert_tmpDir->setAutoDelete( true ); + connect( arch, SIGNAL( sigExtract( bool ) ), this, SLOT( convertSlotExtractDone( bool ) ) ); + m_convert_saveAsURL = u; + arch->unarchFile( 0, m_convert_tmpDir->name() ); +} + +void +ArkWidget::convertSlotExtractDone( bool ) +{ + kdDebug( 1601 ) << k_funcinfo << endl; + disconnect( arch, SIGNAL( sigExtract( bool ) ), this, SLOT( convertSlotExtractDone( bool ) ) ); + QTimer::singleShot( 0, this, SLOT( convertSlotCreate() ) ); +} + +void +ArkWidget::convertSlotCreate() +{ + file_close(); + connect( this, SIGNAL( createDone( bool ) ), this, SLOT( convertSlotCreateDone( bool ) ) ); + QString archToCreate; + if ( m_convert_saveAsURL.isLocalFile() ) + archToCreate = m_convert_saveAsURL.path(); + else + archToCreate = tmpDir() + m_convert_saveAsURL.fileName(); + + createArchive( archToCreate ); +} + + +void +ArkWidget::convertSlotCreateDone( bool success ) +{ + disconnect( this, SIGNAL( createDone( bool ) ), this, SLOT( convertSlotCreateDone( bool ) ) ); + kdDebug( 1601 ) << k_funcinfo << endl; + if ( !success ) + { + kdWarning( 1601 ) << "Error while converting. (convertSlotCreateDone)" << endl; + return; + } + QDir dir( m_convert_tmpDir->name() ); + QStringList entries = dir.entryList(); + entries.remove( ".." ); + entries.remove( "." ); + QStringList::Iterator it = entries.begin(); + for ( ; it != entries.end(); ++it ) + { + /////////////////////////////////////////////////////// + // BIG TODO: get rid of 'the assume // + // 'file:/', do some black magic // + // to find the basedir, chdir there, // + // and break the rest of the world' // + // hack. See also action_edit ... // + // addFile should be: // + // addFile( const QString & baseDir, // + // const QStringList & filesToAdd ) // + ////////////////////////////////////////////////////// + *it = QString::fromLatin1( "file:" )+ m_convert_tmpDir->name() + *it; + } + bool bOldRecVal = ArkSettings::rarRecurseSubdirs(); + connect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( convertSlotAddDone( bool ) ) ); + arch->addFile( entries ); + ArkSettings::setRarRecurseSubdirs( bOldRecVal ); +} + +void +ArkWidget::convertSlotAddDone( bool success ) +{ + disconnect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( convertSlotAddDone( bool ) ) ); + kdDebug( 1601 ) << k_funcinfo << endl; + m_convertSuccess = success; + // needed ? (TarArch, lzo) + QTimer::singleShot( 0, this, SLOT( convertFinish() ) ); +} + +void +ArkWidget::convertFinish() +{ + kdDebug( 1601 ) << k_funcinfo << endl; + delete m_convert_tmpDir; + m_convert_tmpDir = NULL; + + ready(); + if ( m_convertSuccess ) + { + if ( m_convert_saveAsURL.isLocalFile() ) + { + emit openURLRequest( m_convert_saveAsURL ); + } + else + { + KIO::NetAccess::upload( tmpDir() + + m_convert_saveAsURL.fileName(), m_convert_saveAsURL, this ); + // TODO: save bandwidth - we already have a local tmp file ... + emit openURLRequest( m_convert_saveAsURL ); + } + } + else + { + kdWarning( 1601 ) << "Error while converting (convertSlotAddDone)" << endl; + } +} + +bool +ArkWidget::allowedArchiveName( const KURL & u ) +{ + if (u.isEmpty()) + return false; + + QString archMimeType = KMimeType::findByURL( m_url )->name(); + if ( !m_openAsMimeType.isNull() ) + archMimeType = m_openAsMimeType; + QString newArchMimeType = KMimeType::findByPath( u.path() )->name(); + if ( archMimeType == newArchMimeType ) + return true; + + return false; +} + +void +ArkWidget::extractTo( const KURL & targetDirectory, const KURL & archive, bool bGuessName ) +{ + m_extractTo_targetDirectory = targetDirectory; + + if ( bGuessName ) // suggest an extract directory based on archive name + { + const QString fileName = guessName( archive ); + m_extractTo_targetDirectory.setPath( targetDirectory.path( 1 ) + fileName + '/' ); + } + + if ( !KIO::NetAccess::exists( m_extractTo_targetDirectory, false, this ) ) + { + if ( !KIO::NetAccess::mkdir( m_extractTo_targetDirectory, this ) ) + { + KMessageBox::error( 0, i18n( "Could not create the folder %1" ).arg( + targetDirectory.prettyURL() ) ); + emit request_file_quit(); + return; + } + } + + connect( this, SIGNAL( openDone( bool ) ), this, SLOT( extractToSlotOpenDone( bool ) ) ); +} + +const QString +ArkWidget::guessName( const KURL &archive ) +{ + QString fileName = archive.fileName(); + QStringList list = KMimeType::findByPath( fileName )->patterns(); + QStringList::Iterator it = list.begin(); + QString ext; + for ( ; it != list.end(); ++it ) + { + ext = (*it).remove( '*' ); + if ( fileName.endsWith( ext ) ) + { + fileName = fileName.left( fileName.findRev( ext ) ); + break; + } + } + + return fileName; +} + +void +ArkWidget::extractToSlotOpenDone( bool success ) +{ + disconnect( this, SIGNAL( openDone( bool ) ), this, SLOT( extractToSlotOpenDone( bool ) ) ); + if ( !success ) + { + KMessageBox::error( this, i18n( "An error occurred while opening the archive %1." ).arg( m_url.prettyURL() ) ); + emit request_file_quit(); + return; + } + + QString extractDir = m_extractTo_targetDirectory.path(); + // little code duplication from action_extract(): + if ( !m_extractTo_targetDirectory.isLocalFile() ) + { + m_extractRemoteTmpDir = new KTempDir( tmpDir() + "extremote" ); + m_extractRemoteTmpDir->setAutoDelete( true ); + + extractDir = m_extractRemoteTmpDir->name(); + m_extractRemote = true; + + if ( m_extractRemoteTmpDir->status() != 0 ) + { + kdWarning(1601) << "Unable to create " << extractDir << endl; + m_extractRemote = false; + emit request_file_quit(); + return; + } + } + + QStringList empty; + QStringList alreadyExisting = existingFiles( extractDir, empty ); + kdDebug( 1601 ) << "Already existing files count: " << existingFiles( extractDir, empty ).count() << endl; + bool keepGoing = true; + if ( !ArkSettings::extractOverwrite() && !alreadyExisting.isEmpty() ) + { + keepGoing = ( KMessageBox::Continue == KMessageBox::warningContinueCancelList( this, + i18n( "The following files will not be extracted\nbecause they " + "already exist:" ), alreadyExisting ) ); + } + + if ( keepGoing ) // if the user's OK with those failures, go ahead + { + // unless we have no space! + if ( ArkUtils::diskHasSpace( extractDir, m_nSizeOfFiles ) ) + { + disableAll(); + connect( arch, SIGNAL( sigExtract( bool ) ), this, SLOT( extractToSlotExtractDone( bool ) ) ); + arch->unarchFile( 0, extractDir ); + } + else + { + KMessageBox::error( this, i18n( "Not enough free disc space to extract the archive." ) ); + emit request_file_quit(); + return; + } + } + else + emit request_file_quit(); +} + +void +ArkWidget::extractToSlotExtractDone( bool success ) +{ + disconnect( arch, SIGNAL( sigExtract( bool ) ), this, SLOT( extractToSlotExtractDone( bool ) ) ); + if ( !success ) + { + kdDebug( 1601 ) << "Last Shell Output" << arch->getLastShellOutput() << endl; + KMessageBox::error( this, i18n( "An error occurred while extracting the archive." ) ); + emit request_file_quit(); + return; + } + + if ( m_extractRemote ) + { + connect( this, SIGNAL( extractRemoteMovingDone() ), this, SIGNAL( request_file_quit() ) ); + extractRemoteInitiateMoving( m_extractTo_targetDirectory ); + } + else + emit request_file_quit(); +} + +bool +ArkWidget::addToArchive( const KURL::List & filesToAdd, const KURL & archive) +{ + m_addToArchive_filesToAdd = filesToAdd; + m_addToArchive_archive = archive; + if ( !KIO::NetAccess::exists( archive, false, this ) ) + { + if ( !m_openAsMimeType.isEmpty() ) + { + QStringList extensions = KMimeType::mimeType( m_openAsMimeType )->patterns(); + QStringList::Iterator it = extensions.begin(); + QString file = archive.path(); + for ( ; it != extensions.end() && !file.endsWith( ( *it ).remove( '*' ) ); ++it ) + ; + + if ( it == extensions.end() ) + { + file += ArchiveFormatInfo::self()->defaultExtension( m_openAsMimeType ); + const_cast< KURL & >( archive ).setPath( file ); + } + } + + connect( this, SIGNAL( createDone( bool ) ), this, SLOT( addToArchiveSlotCreateDone( bool ) ) ); + + // TODO: remote Archives should be handled by createArchive + if ( archive.isLocalFile() ) + { + if ( !createArchive( archive.path() ) ) + return false; + } + else + { + if ( !createArchive( tmpDir() + archive.fileName() ) ) + return false; + } + return true; + + } + connect( this, SIGNAL( openDone( bool ) ), this, SLOT( addToArchiveSlotOpenDone( bool ) ) ); + return true; +} + +void +ArkWidget::addToArchiveSlotCreateDone( bool success ) +{ + disconnect( this, SIGNAL( createDone( bool ) ), this, SLOT( addToArchiveSlotCreateDone( bool ) ) ); + if ( !success ) + { + kdDebug( 1601 ) << "Could not create the archive" << endl; + emit request_file_quit(); + return; + } + addToArchiveSlotOpenDone( true ); +} + +void +ArkWidget::addToArchiveSlotOpenDone( bool success ) +{ + kdDebug( 1601 ) << k_funcinfo << endl; + disconnect( this, SIGNAL( openDone( bool ) ), this, SLOT( addToArchiveSlotOpenDone( bool ) ) ); + // TODO: handle dirs with addDir ( or better+easier: get rid of the need to do that entirely ) + if ( !success ) + { + emit request_file_quit(); + return; + } + + if ( m_bIsSimpleCompressedFile && (m_nNumFiles == 1)) + { + QString strFilename; + KURL url = askToCreateRealArchive(); + strFilename = url.path(); + if (!strFilename.isEmpty()) + { + connect( this, SIGNAL( createRealArchiveDone( bool ) ), this, SLOT( addToArchiveSlotAddDone( bool ) ) ); + createRealArchive( strFilename, m_addToArchive_filesToAdd.toStringList() ); + return; + } + else + { + emit request_file_quit(); + return; + } + } + +/* QStringList list = m_addToArchive_filesToAdd.toStringList(); + if ( !ArkUtils::diskHasSpace( tmpDir(), ArkUtils::getSizes( &list ) ) ) + { + KMessageBox::error( this, i18n( "Not enough free disc space to extract the archive." ) ); + emit request_file_quit(); + return; + }*/ + + disableAll(); + // if they are URLs, we have to download them, replace the URLs + // with filenames, and remember to delete the temporaries later. +/* for ( QStringList::Iterator it = list.begin(); + it != list.end(); ++it) + { + QString str = *it; + KURL url( toLocalFile( str ) ); + *it = url.prettyURL(); + } +*/ + KURL::List list = m_addToArchive_filesToAdd; + + + // Remote URLs need to be downloaded. + KURL::List::Iterator end( list.end() ); + for ( KURL::List::Iterator it = list.begin(); it != end; ++it ) + { + if (!(*it).isLocalFile()) + { + *it = toLocalFile( *it ); + } + } + + kdDebug( 1601 ) << "Adding: " << list << endl; + + connect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( addToArchiveSlotAddDone( bool ) ) ); + arch->addFile( list.toStringList() ); +} + +void +ArkWidget::addToArchiveSlotAddDone( bool success ) +{ + kdDebug( 1601 ) << k_funcinfo << endl; + disconnect( this, SLOT( addToArchiveSlotAddDone( bool ) ) ); + if ( !success ) + { + KMessageBox::error( this, i18n( "An error occurred while adding the files to the archive." ) ); + } + if ( !m_addToArchive_archive.isLocalFile() ) + KIO::NetAccess::upload( m_strArchName, m_addToArchive_archive, this ); + emit request_file_quit(); + return; +} + +void ArkWidget::setOpenAsMimeType( const QString & mimeType ) +{ + m_openAsMimeType = mimeType; +} + +void +ArkWidget::file_open(const KURL& url) +{ + if ( url.isEmpty() ) + { + kdDebug( 1601 ) << "file_open: url empty" << endl; + return; + } + + if ( isArchiveOpen() ) + file_close(); // close old arch. If we don't, our temp file is wrong! + + if ( !url.isLocalFile() ) + { + kdWarning ( 1601 ) << url.prettyURL() << " is not a local URL in ArkWidget::file_open( KURL). Aborting. " << endl; + return; + } + + + QString strFile = url.path(); + + kdDebug( 1601 ) << "File to open: " << strFile << endl; + + QFileInfo fileInfo( strFile ); + if ( !fileInfo.exists() ) + { + KMessageBox::error(this, i18n("The archive %1 does not exist.").arg(strFile)); + emit removeRecentURL( m_realURL ); + return; + } + else if ( !fileInfo.isReadable() ) + { + KMessageBox::error(this, i18n("You do not have permission to access that archive.") ); + emit removeRecentURL( m_realURL ); + return; + } + + // see if the user is just opening the same file that's already + // open (erm...) + + if (strFile == m_strArchName && m_bIsArchiveOpen) + { + kdDebug( 1601 ) << "file_open: strFile == m_strArchName" << endl; + return; + } + + // no errors if we made it this far. + + // Set the current archive filename to the filename + m_strArchName = strFile; + m_url = url; + //arch->clearShellOutput(); + + openArchive( strFile ); +} + + +// File menu ///////////////////////////////////////////////////////// + +KURL +ArkWidget::getCreateFilename(const QString & _caption, + const QString & _defaultMimeType, + bool allowCompressed, + const QString & _suggestedName ) +{ + int choice=0; + bool fileExists = true; + QString strFile; + KURL url; + + KFileDialog dlg( ":ArkSaveAsDialog", QString::null, this, "SaveAsDialog", true ); + dlg.setCaption( _caption ); + dlg.setOperationMode( KFileDialog::Saving ); + dlg.setMimeFilter( ArchiveFormatInfo::self()->supportedMimeTypes( allowCompressed ), + _defaultMimeType.isNull() ? "application/x-tgz" : _defaultMimeType ); + if ( !_suggestedName.isEmpty() ) + dlg.setSelection( _suggestedName ); + + while ( fileExists ) + // keep asking for filenames as long as the user doesn't want to + // overwrite existing ones; break if they agree to overwrite + // or if the file doesn't already exist. Return if they cancel. + // Also check for proper extensions. + { + dlg.exec(); + url = dlg.selectedURL(); + strFile = url.path(); + + if (strFile.isEmpty()) + return QString::null; + + //the user chose to save as the current archive + //or wanted to create a new one with the same name + //no need to do anything + if (strFile == m_strArchName && m_bIsArchiveOpen) + return QString::null; + + QStringList extensions = dlg.currentFilterMimeType()->patterns(); + QStringList::Iterator it = extensions.begin(); + for ( ; it != extensions.end() && !strFile.endsWith( ( *it ).remove( '*' ) ); ++it ) + ; + + if ( it == extensions.end() ) + { + strFile += ArchiveFormatInfo::self()->defaultExtension( dlg.currentFilterMimeType()->name() ); + url.setPath( strFile ); + } + + kdDebug(1601) << "Trying to create an archive named " << strFile << endl; + fileExists = QFile::exists( strFile ); + if( fileExists ) + { + choice = KMessageBox::warningYesNoCancel(0, + i18n("Archive already exists. Do you wish to overwrite it?"), + i18n("Archive Already Exists"), i18n("Overwrite"), i18n("Do Not Overwrite")); + + if ( choice == KMessageBox::Yes ) + { + QFile::remove( strFile ); + break; + } + else if ( choice == KMessageBox::Cancel ) + { + return QString::null; + } + else + { + continue; + } + } + // if we got here, the file does not already exist. + if ( !ArkUtils::haveDirPermissions( url.directory() ) ) + { + KMessageBox::error( this, + i18n( "You do not have permission" + " to write to the directory %1" ).arg(url.directory() ) ); + return QString::null; + } + } // end of while loop + + return url; +} + +void +ArkWidget::file_new() +{ + QString strFile; + KURL url = getCreateFilename(i18n("Create New Archive") ); + strFile = url.path(); + if (!strFile.isEmpty()) + { + file_close(); + createArchive( strFile ); + } +} + +void +ArkWidget::extractOnlyOpenDone() +{ + bool done = action_extract(); + + // last extract dir is still set, but this is not a problem + if( !done ) + { + emit request_file_quit(); + } + +} + +void +ArkWidget::slotExtractDone(bool success) +{ + disconnect( arch, SIGNAL( sigExtract( bool ) ), + this, SLOT( slotExtractDone(bool) ) ); + ready(); + + if(m_extractList != 0) + delete m_extractList; + m_extractList = 0; + + if( m_fileListView ) // avoid race condition, don't do updates if application is exiting + { + m_fileListView->setUpdatesEnabled(true); + fixEnables(); + } + + if ( m_extractRemote ) + { + extractRemoteInitiateMoving( m_extractURL ); + } + else if( m_extractOnly ) + { + emit request_file_quit(); + } + + if ( success && ArkSettings::openDestinationFolder() ) + { + KRun::runURL( m_extractURL, "inode/directory" ); + } + + kdDebug(1601) << "-ArkWidget::slotExtractDone" << endl; +} + +void +ArkWidget::extractRemoteInitiateMoving( const KURL & target ) +{ + KURL srcDirURL; + KURL src; + QString srcDir; + + srcDir = m_extractRemoteTmpDir->name(); + srcDirURL.setPath( srcDir ); + + QDir dir( srcDir ); + dir.setFilter( QDir::All | QDir::Hidden ); + QStringList lst( dir.entryList() ); + lst.remove( "." ); + lst.remove( ".." ); + + KURL::List srcList; + for( QStringList::ConstIterator it = lst.begin(); it != lst.end() ; ++it) + { + src = srcDirURL; + src.addPath( *it ); + srcList.append( src ); + } + + m_extractURL.adjustPath( 1 ); + + KIO::CopyJob *job = KIO::copy( srcList, target, this ); + connect( job, SIGNAL(result(KIO::Job*)), + this, SLOT(slotExtractRemoteDone(KIO::Job*)) ); + + m_extractRemote = false; +} + +void +ArkWidget::slotExtractRemoteDone(KIO::Job *job) +{ + delete m_extractRemoteTmpDir; + m_extractRemoteTmpDir = NULL; + + if ( job->error() ) + job->showErrorDialog(); + + emit extractRemoteMovingDone(); + + if ( m_extractOnly ) + emit request_file_quit(); +} + + +void +ArkWidget::disableAll() // private +{ + emit disableAllActions(); + m_fileListView->setUpdatesEnabled(true); +} + +void +ArkWidget::fixEnables() // private +{ + emit fixActions(); //connected to the part +} + +void +ArkWidget::file_close() +{ + if ( isArchiveOpen() ) + { + closeArch(); + emit setWindowCaption( QString::null ); + emit removeOpenArk( m_strArchName ); + updateStatusTotals(); + updateStatusSelection(); + fixEnables(); + } + else + { + closeArch(); + } + + m_strArchName = QString::null; + m_url = KURL(); +} + + +KURL +ArkWidget::askToCreateRealArchive() +{ + // ask user whether to create a real archive from a compressed file + // returns filename if so + KURL url; + int choice = + KMessageBox::warningYesNo(0, i18n("You are currently working with a simple compressed file.\nWould you like to make it into an archive so that it can contain multiple files?\nIf so, you must choose a name for your new archive."), i18n("Warning"),i18n("Make Into Archive"),i18n("Do Not Make")); + if (choice == KMessageBox::Yes) + { + url = getCreateFilename( i18n("Create New Archive"), + QString::null, false ); + } + else + url.setPath( QString::null ); + return url; +} + +void +ArkWidget::createRealArchive( const QString & strFilename, const QStringList & filesToAdd ) +{ + Arch * newArch = getNewArchive( strFilename ); + busy( i18n( "Creating archive..." ) ); + if ( !newArch ) + return; + if ( !filesToAdd.isEmpty() ) + m_pTempAddList = new QStringList( filesToAdd ); + m_compressedFile = static_cast< CompressedFile * >( arch )->tempFileName(); + KURL u1, u2; + u1.setPath( m_compressedFile ); + m_createRealArchTmpDir = new KTempDir( tmpDir() + "create_real_arch" ); + u2.setPath( m_createRealArchTmpDir->name() + u1.fileName() ); + KIO::NetAccess::copy( u1, u2, this ); + m_compressedFile = "file:" + u2.path(); // AGAIN THE 5 SPACES Hack :-( + connect( newArch, SIGNAL( sigCreate( Arch *, bool, const QString &, int ) ), + this, SLOT( createRealArchiveSlotCreate( Arch *, bool, + const QString &, int ) ) ); + file_close(); + newArch->create(); +} + +void +ArkWidget::createRealArchiveSlotCreate( Arch * newArch, bool success, + const QString & fileName, int nbr ) +{ + slotCreate( newArch, success, fileName, nbr ); + + if ( !success ) + return; + + QStringList listForCompressedFile; + listForCompressedFile.append(m_compressedFile); + disableAll(); + + connect( newArch, SIGNAL( sigAdd( bool ) ), this, + SLOT( createRealArchiveSlotAddDone( bool ) ) ); + + newArch->addFile(listForCompressedFile); +} + +void +ArkWidget::createRealArchiveSlotAddDone( bool success ) +{ + kdDebug( 1601 ) << "createRealArchiveSlotAddDone+, success:" << success << endl; + disconnect( arch, SIGNAL( sigAdd( bool ) ), this, + SLOT( createRealArchiveSlotAddDone( bool ) ) ); + + m_createRealArchTmpDir->unlink(); + delete m_createRealArchTmpDir; + m_createRealArchTmpDir = NULL; + + + if ( !success ) + return; + + ready(); + + if ( m_pTempAddList == NULL ) + { + // now get the files to be added + // we don't know which files to add yet + action_add(); + } + else + { + connect( arch, SIGNAL( sigAdd( bool ) ), this, + SLOT( createRealArchiveSlotAddFilesDone( bool ) ) ); + // files were dropped in + addFile( m_pTempAddList ); + } +} + +void +ArkWidget::createRealArchiveSlotAddFilesDone( bool success ) +{ + //kdDebug( 1601 ) << "createRealArchiveSlotAddFilesDone+, success:" << success << endl; + disconnect( arch, SIGNAL( sigAdd( bool ) ), this, + SLOT( createRealArchiveSlotAddFilesDone( bool ) ) ); + delete m_pTempAddList; + m_pTempAddList = NULL; + emit createRealArchiveDone( success ); +} + + + + +// Action menu ///////////////////////////////////////////////////////// + +void +ArkWidget::action_add() +{ + if (m_bIsSimpleCompressedFile && (m_nNumFiles == 1)) + { + QString strFilename; + KURL url = askToCreateRealArchive(); + strFilename = url.path(); + if (!strFilename.isEmpty()) + { + createRealArchive(strFilename); + } + return; + } + + KFileDialog fileDlg( ":ArkAddDir", QString::null, this, "adddlg", true ); + fileDlg.setMode( KFile::Mode( KFile::Files | KFile::ExistingOnly ) ); + fileDlg.setCaption(i18n("Select Files to Add")); + + if(fileDlg.exec()) + { + KURL::List addList; + addList = fileDlg.selectedURLs(); + QStringList * list = new QStringList(); + //Here we pre-calculate the end of the list + KURL::List::ConstIterator endList = addList.end(); + for (KURL::List::ConstIterator it = addList.begin(); it != endList; ++it) + list->append( KURL::decode_string( (*it).url() ) ); + + if ( list->count() > 0 ) + { + if ( m_bIsSimpleCompressedFile && list->count() > 1 ) + { + QString strFilename; + KURL url = askToCreateRealArchive(); + strFilename = url.path(); + if (!strFilename.isEmpty()) + { + createRealArchive(strFilename); + } + delete list; + return; + } + addFile( list ); + } + delete list; + } +} + +void +ArkWidget::addFile(QStringList *list) +{ + if ( !ArkUtils::diskHasSpace( tmpDir(), ArkUtils::getSizes( list ) ) ) + return; + + disableAll(); + busy( i18n( "Adding files..." ) ); + // if they are URLs, we have to download them, replace the URLs + // with filenames, and remember to delete the temporaries later. + for (QStringList::Iterator it = list->begin(); it != list->end(); ++it) + { + QString str = *it; + *it = toLocalFile(KURL(str)).prettyURL(); + + } + + connect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( slotAddDone( bool ) ) ); + arch->addFile( ( *list ) ); +} + +void +ArkWidget::action_add_dir() +{ + KURL u = KDirSelectDialog::selectDirectory( ":ArkAddDir", + false, this, + i18n("Select Folder to Add")); + + QString dir = KURL::decode_string( u.url(-1) ); + if ( !dir.isEmpty() ) + { + busy( i18n( "Adding folder..." ) ); + disableAll(); + u = toLocalFile(u); + connect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( slotAddDone( bool ) ) ); + arch->addDir( u.prettyURL() ); + } + +} + +void +ArkWidget::slotAddDone(bool _bSuccess) +{ + disconnect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( slotAddDone( bool ) ) ); + m_fileListView->setUpdatesEnabled(true); + m_fileListView->triggerUpdate(); + ready(); + + if (_bSuccess) + { + m_modified = true; + //simulate reload + KURL u; + u.setPath( arch->fileName() ); + file_close(); + file_open( u ); + emit setWindowCaption( u.path() ); + } + removeDownloadedFiles(); + fixEnables(); +} + + + +KURL +ArkWidget::toLocalFile( const KURL& url ) +{ + KURL localURL = url; + + if(!url.isLocalFile()) + { + QString strURL = url.prettyURL(); + + QString tempfile = tmpDir(); + tempfile += strURL.right(strURL.length() - strURL.findRev("/") - 1); + deleteAfterUse(tempfile); // remember for deletion + KURL tempurl; tempurl.setPath( tempfile ); + if( !KIO::NetAccess::dircopy(url, tempurl, this) ) + return KURL(); + localURL = tempfile; + } + return localURL; +} + +void +ArkWidget::deleteAfterUse( const QString& path ) +{ + mpDownloadedList.append( path ); +} + +void +ArkWidget::removeDownloadedFiles() +{ + if (!mpDownloadedList.isEmpty()) + { + // It is necessary to remove those files even if tmpDir() is getting deleted: + // not all files in mpDownloadedList are from tmpDir() - e.g. when using --tempfile + // But of course we could decide to not add files from tmpDir() into mpDownloadedList. + QStringList::ConstIterator it = mpDownloadedList.begin(); + QStringList::ConstIterator end = mpDownloadedList.end(); + for ( ; it != end ; ++it ) + QFile::remove( *it ); + mpDownloadedList.clear(); + } +} + +void +ArkWidget::action_delete() +{ + // remove selected files and create a list to send to the archive + // Warn the user if he/she/it tries to delete a directory entry in + // a tar file - it actually deletes the contents of the directory + // as well. + + if (m_fileListView->isSelectionEmpty()) + { + return; // shouldn't happen - delete should have been disabled! + } + + QStringList list = m_fileListView->selectedFilenames(); + + // ask for confirmation + if ( KMessageBox::warningContinueCancelList( this, + i18n( "Do you really want to delete the selected items?" ), + list, + QString::null, + KStdGuiItem::del(), + "confirmDelete" ) + != KMessageBox::Continue) + { + return; + } + + // Remove the entries from the list view + QListViewItemIterator it( m_fileListView ); + while ( it.current() ) + { + if ( it.current()->isSelected() ) + delete *it; + else + ++it; + } + + disableAll(); + busy( i18n( "Removing..." ) ); + connect( arch, SIGNAL( sigDelete( bool ) ), this, SLOT( slotDeleteDone( bool ) ) ); + arch->remove(&list); + kdDebug(1601) << "-ArkWidget::action_delete" << endl; +} + +void +ArkWidget::slotDeleteDone(bool _bSuccess) +{ + disconnect( arch, SIGNAL( sigDelete( bool ) ), this, SLOT( slotDeleteDone( bool ) ) ); + kdDebug(1601) << "+ArkWidget::slotDeleteDone" << endl; + m_fileListView->setUpdatesEnabled(true); + m_fileListView->triggerUpdate(); + if (_bSuccess) + { + m_modified = true; + updateStatusTotals(); + updateStatusSelection(); + } + // disable the select all and extract options if there are no files left + fixEnables(); + ready(); + kdDebug(1601) << "-ArkWidget::slotDeleteDone" << endl; + +} + + + +void +ArkWidget::slotOpenWith() +{ + connect( arch, SIGNAL( sigExtract( bool ) ), this, + SLOT( openWithSlotExtractDone( bool ) ) ); + + showCurrentFile(); +} + +void +ArkWidget::openWithSlotExtractDone( bool success ) +{ + disconnect( arch, SIGNAL( sigExtract( bool ) ), this, + SLOT( openWithSlotExtractDone( bool ) ) ); + + if ( success ) + { + KURL::List list; + list.append(m_viewURL); + KOpenWithDlg l( list, i18n("Open with:"), QString::null, (QWidget*)0L); + if ( l.exec() ) + { + KService::Ptr service = l.service(); + if ( !!service ) + { + KRun::run( *service, list ); + } + else + { + QString exec = l.text(); + exec += " %f"; + KRun::run( exec, list ); + } + } + } + + if( m_fileListView ) + { + m_fileListView->setUpdatesEnabled(true); + fixEnables(); + } +} + + +void +ArkWidget::prepareViewFiles( const QStringList & fileList ) +{ + QString destTmpDirectory; + destTmpDirectory = tmpDir(); + + // Make sure to delete previous file already there... + for(QStringList::ConstIterator it = fileList.begin(); + it != fileList.end(); ++it) + QFile::remove(destTmpDirectory + *it); + + m_viewList = new QStringList( fileList ); + arch->unarchFile( m_viewList, destTmpDirectory, true); +} + +bool +ArkWidget::reportExtractFailures( const QString & _dest, QStringList *_list ) +{ + // reports extract failures when Overwrite = False and the file + // exists already in the destination directory. + // If list is null, it means we are extracting all files. + // Otherwise the list contains the files we are to extract. + + bool redoExtraction = false; + QString strFilename; + + QStringList list = *_list; + QStringList filesExisting = existingFiles( _dest, list ); + + int numFilesToReport = filesExisting.count(); + + // now report on the contents + holdBusy(); + if (numFilesToReport != 0) + { + redoExtraction = ( KMessageBox::Cancel == KMessageBox::warningContinueCancelList( this, + i18n( "The following files will not be extracted\nbecause they " + "already exist:" ), filesExisting ) ); + } + resumeBusy(); + return redoExtraction; +} + +QStringList +ArkWidget::existingFiles( const QString & _dest, QStringList & _list ) +{ + QString strFilename, tmp; + + QString strDestDir = _dest; + + // make sure the destination directory has a / at the end. + if ( !strDestDir.endsWith( "/" ) ) + { + strDestDir += '/'; + } + + if (_list.isEmpty()) + { + _list = m_fileListView->fileNames(); + } + + QStringList existingFiles; + // now the list contains all the names we must verify. + for (QStringList::Iterator it = _list.begin(); it != _list.end(); ++it) + { + strFilename = *it; + QString strFullName = strDestDir + strFilename; + + // if the filename ends with an "/", it means it is a directory + if ( QFile::exists( strFullName ) && !strFilename.endsWith("/") ) + { + existingFiles.append( strFilename ); + } + } + return existingFiles; +} + + + + + +bool +ArkWidget::action_extract() +{ + KURL fileToExtract; + fileToExtract.setPath( arch->fileName() ); + + //before we start, make sure the archive is still there + if (!KIO::NetAccess::exists( fileToExtract.prettyURL(), true, this ) ) + { + KMessageBox::error(0, i18n("The archive to extract from no longer exists.")); + return false; + } + + //if more than one entry in the archive is root level, suggest a path prefix + QString prefix = m_fileListView->childCount() > 1 ? + QChar( '/' ) + guessName( realURL() ) + : QString(); + + // Should the extraction dialog show an option for extracting only selected files? + bool enableSelected = ( m_nNumSelectedFiles > 0 ) && + ( m_fileListView->totalFiles() > 1); + + QString base = ArkSettings::extractionHistory().isEmpty()? + QString() : ArkSettings::extractionHistory().first(); + if ( base.isEmpty() ) + { + // Perhaps the KDE Documents folder is a better choice? + base = QDir::homeDirPath(); + } + + // Default URL shown in the extraction dialog; + KURL defaultDir( base ); + + if ( m_extractOnly ) + { + defaultDir = KURL::fromPathOrURL( QDir::currentDirPath() ); + } + + ExtractionDialog *dlg = new ExtractionDialog( this, 0, enableSelected, defaultDir, prefix, m_url.fileName() ); + + bool bRedoExtract = false; + + // list of files to be extracted + m_extractList = new QStringList; + if ( dlg->exec() ) + { + //m_extractURL will always be the location the user chose to + //m_extract to, whether local or remote + m_extractURL = dlg->extractionDirectory(); + + //extractDir will either be the real, local extract dir, + //or in case of a extract to remote location, a local tmp dir + QString extractDir; + + if ( !m_extractURL.isLocalFile() ) + { + m_extractRemoteTmpDir = new KTempDir( tmpDir() + "extremote" ); + m_extractRemoteTmpDir->setAutoDelete( true ); + + extractDir = m_extractRemoteTmpDir->name(); + m_extractRemote = true; + if ( m_extractRemoteTmpDir->status() != 0 ) + { + kdWarning( 1601 ) << "Unable to create temporary directory" << extractDir << endl; + m_extractRemote = false; + delete dlg; + return false; + } + } + else + { + extractDir = m_extractURL.path(); + } + + // if overwrite is false, then we need to check for failure of + // extractions. + bool bOvwrt = ArkSettings::extractOverwrite(); + + if ( dlg->selectedOnly() == false ) + { + if (!bOvwrt) // send empty list to indicate we're extracting all + { + bRedoExtract = reportExtractFailures(extractDir, m_extractList); + } + + if (!bRedoExtract) // if the user's OK with those failures, go ahead + { + // unless we have no space! + if ( ArkUtils::diskHasSpace( extractDir, m_nSizeOfFiles ) ) + { + disableAll(); + busy( i18n( "Extracting..." ) ); + connect( arch, SIGNAL( sigExtract( bool ) ), this, SLOT( slotExtractDone(bool) ) ); + arch->unarchFile(0, extractDir); + } + } + } + else + { + KIO::filesize_t nTotalSize = 0; + // make a list to send to unarchFile + QStringList selectedFiles = m_fileListView->selectedFilenames(); + for ( QStringList::const_iterator it = selectedFiles.constBegin(); + it != selectedFiles.constEnd(); + ++it ) + { + m_extractList->append( QFile::encodeName( *it ) ); + } + + if (!bOvwrt) + { + bRedoExtract = reportExtractFailures(extractDir, m_extractList); + } + if (!bRedoExtract) + { + if (ArkUtils::diskHasSpace(extractDir, nTotalSize)) + { + disableAll(); + busy( i18n( "Extracting..." ) ); + connect( arch, SIGNAL( sigExtract( bool ) ), + this, SLOT( slotExtractDone(bool) ) ); + arch->unarchFile(m_extractList, extractDir); // extract selected files + } + } + } + + delete dlg; + } + else + { + delete dlg; + return false; + } + + // user might want to change some options or the selection... + if (bRedoExtract) + { + return action_extract(); + } + + return true; +} + +void +ArkWidget::action_edit() +{ + // begin an edit. This is like a view, but once the process exits, + // the file is put back into the archive. If the user tries to quit or + // close the archive, there will be a warning that any changes to the + // files open under "Edit" will be lost unless the archive remains open. + // [hmm, does that really make sense? I'll leave it for now.] + + busy( i18n( "Extracting..." ) ); + connect( arch, SIGNAL( sigExtract( bool ) ), this, + SLOT( editSlotExtractDone() ) ); + showCurrentFile(); +} + +void +ArkWidget::editSlotExtractDone() +{ + disconnect( arch, SIGNAL( sigExtract( bool ) ), + this, SLOT( editSlotExtractDone() ) ); + ready(); + editStart(); + + // avoid race condition, don't do updates if application is exiting + if( m_fileListView ) + { + m_fileListView->setUpdatesEnabled(true); + fixEnables(); + } +} + +void +ArkWidget::editStart() +{ + kdDebug(1601) << "Edit in progress..." << endl; + KURL::List list; + // edit will be in progress until the KProcess terminates. + KOpenWithDlg l( list, i18n("Edit with:"), + QString::null, (QWidget*)0L ); + if ( l.exec() ) + { + KProcess *kp = new KProcess; + + *kp << l.text() << m_strFileToView; + connect( kp, SIGNAL(processExited(KProcess *)), + this, SLOT(slotEditFinished(KProcess *)) ); + if ( kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false ) + { + KMessageBox::error(0, i18n("Trouble editing the file...")); + } + } +} + +void +ArkWidget::slotEditFinished(KProcess *kp) +{ + kdDebug(1601) << "+ArkWidget::slotEditFinished" << endl; + connect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( editSlotAddDone( bool ) ) ); + delete kp; + QStringList list; + // now put the file back into the archive. + list.append(m_strFileToView); + disableAll(); + + + // BUG: this puts any edited file back at the archive toplevel... + // there's only one file, and it's in the temp directory. + // If the filename has more than three /'s then we should + // change to the first level directory so that the paths + // come out right. + QStringList::Iterator it = list.begin(); + QString filename = *it; + QString path; + if (filename.contains('/') > 3) + { + kdDebug(1601) << "Filename is originally: " << filename << endl; + int i = filename.find('/', 5); + path = filename.left(1+i); + kdDebug(1601) << "Changing to dir: " << path << endl; + QDir::setCurrent(path); + filename = filename.right(filename.length()-i-1); + // HACK!! We need a relative path. If I have "file:", it + // will look like an absolute path. So five spaces here to get + // chopped off later.... + filename = " " + filename; + *it = filename; + } + + busy( i18n( "Readding edited file..." ) ); + arch->addFile( list ); + + kdDebug(1601) << "-ArkWidget::slotEditFinished" << endl; +} + +void +ArkWidget::editSlotAddDone( bool success ) +{ + ready(); + disconnect( arch, SIGNAL( sigAdd( bool ) ), this, SLOT( editSlotAddDone( bool ) ) ); + slotAddDone( success ); +} + +void +ArkWidget::action_view() +{ + connect( arch, SIGNAL( sigExtract( bool ) ), this, + SLOT( viewSlotExtractDone( bool ) ) ); + busy( i18n( "Extracting file to view" ) ); + showCurrentFile(); +} + +void +ArkWidget::viewSlotExtractDone( bool success ) +{ + if ( success ) + { + chmod( QFile::encodeName( m_strFileToView ), 0400 ); + bool view = true; + + if ( ArkSettings::useIntegratedViewer() ) + { + ArkViewer * viewer = new ArkViewer( this, "viewer" ); + + if ( !viewer->view( m_viewURL ) ) + { + QString text = i18n( "The internal viewer is not able to display this file. Would you like to view it using an external program?" ); + view = ( KMessageBox::warningYesNo( this, text, QString::null, i18n("View Externally"), i18n("Do Not View") ) == KMessageBox::Yes ); + + if ( view ) + viewInExternalViewer( this, m_viewURL ); + } + } + else + { + viewInExternalViewer( this, m_viewURL ); + } + } + + disconnect( arch, SIGNAL( sigExtract( bool ) ), this, + SLOT( viewSlotExtractDone( bool ) ) ); + + delete m_viewList; + + // avoid race condition, don't do updates if application is exiting + if( m_fileListView ) + { + m_fileListView->setUpdatesEnabled(true); + fixEnables(); + } + ready(); +} + + +void +ArkWidget::showCurrentFile() +{ + if ( !m_fileListView->currentItem() ) + return; + + QString name = m_fileListView->currentItem()->fileName(); + + QString fullname = tmpDir(); + fullname += name; + + if(fullname.contains("../")) + fullname.remove("../"); + + //Convert the QString filename to KURL to escape the bad characters + m_viewURL.setPath(fullname); + + m_strFileToView = fullname; + kdDebug(1601) << "File to be extracted: " << m_viewURL << endl; + + QStringList extractList; + extractList.append(name); + + if (ArkUtils::diskHasSpace( tmpDir(), m_fileListView->currentItem()->fileSize() ) ) + { + disableAll(); + prepareViewFiles( extractList ); + } +} + +// Popup ///////////////////////////////////////////////////////////// + +void +ArkWidget::setArchivePopupEnabled( bool b ) +{ + m_bArchivePopupEnabled = b; +} + +void +ArkWidget::doPopup( QListViewItem *pItem, const QPoint &pPoint, int nCol ) // slot +// do the right-click popup menus +{ + if ( nCol == 0 || !m_bArchivePopupEnabled ) + { + m_fileListView->setCurrentItem(pItem); + m_fileListView->setSelected(pItem, true); + emit signalFilePopup( pPoint ); + } + else // clicked anywhere else but the name column + { + emit signalArchivePopup( pPoint ); + } +} + + +void +ArkWidget::viewFile( QListViewItem* item ) // slot +// show contents when double click +{ + // Preview, if it is a file + if ( item->childCount() == 0) + emit action_view(); + else // Change opened state if it is a dir + item->setOpen( !item->isOpen() ); +} + + +// Service functions ///////////////////////////////////////////////// + +void +ArkWidget::slotSelectionChanged() +{ + updateStatusSelection(); +} + + +//////////////////////////////////////////////////////////////////// +//////////////////// updateStatusSelection ///////////////////////// +//////////////////////////////////////////////////////////////////// + +void +ArkWidget::updateStatusSelection() +{ + m_nNumSelectedFiles = m_fileListView->selectedFilesCount(); + m_nSizeOfSelectedFiles = m_fileListView->selectedSize(); + + QString strInfo; + if (m_nNumSelectedFiles == 0) + { + strInfo = i18n("0 files selected"); + } + else if (m_nNumSelectedFiles != 1) + { + strInfo = i18n("%1 files selected %2") + .arg(KGlobal::locale()->formatNumber(m_nNumSelectedFiles, 0)) + .arg(KIO::convertSize(m_nSizeOfSelectedFiles)); + } + else + { + strInfo = i18n("1 file selected %2") + .arg(KIO::convertSize(m_nSizeOfSelectedFiles)); + } + + emit setStatusBarSelectedFiles(strInfo); + fixEnables(); +} + + +// Drag & Drop //////////////////////////////////////////////////////// + +void +ArkWidget::dragMoveEvent(QDragMoveEvent *e) +{ + if (KURLDrag::canDecode(e) && !m_bDropSourceIsSelf) + { + e->accept(); + } +} + + +void +ArkWidget::dropEvent(QDropEvent* e) +{ + kdDebug( 1601 ) << "+ArkWidget::dropEvent" << endl; + + KURL::List list; + + if ( KURLDrag::decode( e, list ) ) + { + QStringList urlList = list.toStringList(); + dropAction( urlList ); + } + + kdDebug(1601) << "-dropEvent" << endl; +} + +////////////////////////////////////////////////////////////////////// +///////////////////////// dropAction ///////////////////////////////// +////////////////////////////////////////////////////////////////////// + +void +ArkWidget::dropAction( QStringList & list ) +{ + // Called by dropEvent + + // The possibilities treated are as follows: + // drop a regular file into a window with + // * an open archive - add it. + // * no open archive - ask user to open an archive for adding file or cancel + // drop an archive into a window with + // * an open archive - ask user to add to open archive or to open it freshly + // * no open archive - open it + // drop many files (can be a mix of archives and regular) into a window with + // * an open archive - add them. + // * no open archive - ask user to open an archive for adding files or cancel + + // and don't forget about gzip files. + + QString str; + QStringList urls; // to be sent to addFile + + str = list.first(); + + if ( 1 == list.count() && + ( UNKNOWN_FORMAT != ArchiveFormatInfo::self()->archTypeByExtension( str ) ) ) + { + // if there's one thing being dropped and it's an archive + if (isArchiveOpen()) + { + // ask them if they want to add the dragged archive to the current + // one or open it as the new current archive + int nRet = KMessageBox::warningYesNoCancel(this, + i18n("Do you wish to add this to the current archive or open it as a new archive?"), + QString::null, + i18n("&Add"), i18n("&Open")); + if (KMessageBox::Yes == nRet) // add it + { + if (m_bIsSimpleCompressedFile && (m_nNumFiles == 1)) + { + QString strFilename; + KURL url = askToCreateRealArchive(); + strFilename = url.path(); + if (!strFilename.isEmpty()) + { + createRealArchive( strFilename, list ); + } + return; + } + + addFile( &list ); + return; + } + else if (KMessageBox::Cancel == nRet) // cancel + { + return; + } + } + + // if I made it here, there's either no archive currently open + // or they selected "Open". + KURL url = str; + + emit openURLRequest( url ); + } + else + { + if (isArchiveOpen()) + { + if (m_bIsSimpleCompressedFile && (m_nNumFiles == 1)) + { + QString strFilename; + KURL url = askToCreateRealArchive(); + strFilename = url.path(); + if (!strFilename.isEmpty()) + { + createRealArchive( strFilename, list ); + } + return; + } + // add the files to the open archive + addFile( &list ); + } + else + { + // no archive is open, so we ask if the user wants to open one + // for this/these file/files. + + QString str; + str = (list.count() > 1) + ? i18n("There is no archive currently open. Do you wish to create one now for these files?") + : i18n("There is no archive currently open. Do you wish to create one now for this file?"); + int nRet = KMessageBox::warningYesNo(this, str, QString::null, i18n("Create Archive"), i18n("Do Not Create")); + if (nRet == KMessageBox::Yes) // yes + { + file_new(); + if (isArchiveOpen()) // they still could have canceled! + { + addFile( &list ); + } + } + // else // basically a cancel on the drop. + } + } +} + +void +ArkWidget::startDrag( const QStringList & fileList ) +{ + mDragFiles = fileList; + connect( arch, SIGNAL( sigExtract( bool ) ), this, SLOT( startDragSlotExtractDone( bool ) ) ); + prepareViewFiles( fileList ); +} + +void +ArkWidget::startDragSlotExtractDone( bool ) +{ + disconnect( arch, SIGNAL( sigExtract( bool ) ), + this, SLOT( startDragSlotExtractDone( bool ) ) ); + + KURL::List list; + + for (QStringList::Iterator it = mDragFiles.begin(); it != mDragFiles.end(); ++it) + { + KURL url; + url.setPath( tmpDir() + *it ); + list.append( url ); + } + + KURLDrag *drg = new KURLDrag(list, m_fileListView->viewport(), "Ark Archive Drag" ); + m_bDropSourceIsSelf = true; + drg->dragCopy(); + m_bDropSourceIsSelf = false; +} + + +void +ArkWidget::arkWarning(const QString& msg) +{ + KMessageBox::information(this, msg); +} + +void +ArkWidget::createFileListView() +{ + kdDebug(1601) << "ArkWidget::createFileListView" << endl; + if ( !m_fileListView ) + { + m_fileListView = new FileListView(this); + + connect( m_fileListView, SIGNAL( selectionChanged() ), + this, SLOT( slotSelectionChanged() ) ); + connect( m_fileListView, SIGNAL( rightButtonPressed(QListViewItem *, const QPoint &, int) ), + this, SLOT(doPopup(QListViewItem *, const QPoint &, int))); + connect( m_fileListView, SIGNAL( startDragRequest( const QStringList & ) ), + this, SLOT( startDrag( const QStringList & ) ) ); + connect( m_fileListView, SIGNAL( executed(QListViewItem *, const QPoint &, int ) ), + this, SLOT( viewFile(QListViewItem*) ) ); + connect( m_fileListView, SIGNAL( returnPressed(QListViewItem * ) ), + this, SLOT( viewFile(QListViewItem*) ) ); + } + m_fileListView->clear(); +} + + +Arch * ArkWidget::getNewArchive( const QString & _fileName, const QString& _mimetype ) +{ + Arch * newArch = 0; + + QString type = _mimetype.isNull()? KMimeType::findByURL( KURL::fromPathOrURL(_fileName) )->name() : _mimetype; + ArchType archtype = ArchiveFormatInfo::self()->archTypeForMimeType(type); + kdDebug( 1601 ) << "archtype is recognised as: " << archtype << endl; + if(0 == (newArch = Arch::archFactory(archtype, this, + _fileName, _mimetype))) + { + KMessageBox::error(this, i18n("Unknown archive format or corrupted archive") ); + emit request_file_quit(); + return NULL; + } + + if (!newArch->archUtilityIsAvailable()) + { + KMessageBox::error(this, i18n("The utility %1 is not in your PATH.\nPlease install it or contact your system administrator.").arg(newArch->getArchUtility())); + return NULL; + } + + connect( newArch, SIGNAL(headers(const ColumnList&)), + m_fileListView, SLOT(setHeaders(const ColumnList&))); + + m_archType = archtype; + m_fileListView->setUpdatesEnabled(true); + return newArch; +} + +////////////////////////////////////////////////////////////////////// +////////////////////// createArchive ///////////////////////////////// +////////////////////////////////////////////////////////////////////// + + +bool +ArkWidget::createArchive( const QString & _filename ) +{ + Arch * newArch = getNewArchive( _filename ); + if ( !newArch ) + return false; + + busy( i18n( "Creating archive..." ) ); + connect( newArch, SIGNAL(sigCreate(Arch *, bool, const QString &, int) ), + this, SLOT(slotCreate(Arch *, bool, const QString &, int) ) ); + + newArch->create(); + return true; +} + +void +ArkWidget::slotCreate(Arch * _newarch, bool _success, const QString & _filename, int) +{ + kdDebug( 1601 ) << k_funcinfo << endl; + disconnect( _newarch, SIGNAL( sigCreate( Arch *, bool, const QString &, int ) ), + this, SLOT(slotCreate(Arch *, bool, const QString &, int) ) ); + ready(); + if ( _success ) + { + //file_close(); already called in ArkWidget::file_new() + m_strArchName = _filename; + // for the hack in compressedfile; needed when creating a compressedfile + // then directly adding a file + KURL u; + u.setPath( _filename ); + setRealURL( u ); + + emit setWindowCaption( _filename ); + emit addRecentURL( u ); + createFileListView(); + m_fileListView->show(); + m_bIsArchiveOpen = true; + arch = _newarch; + m_bIsSimpleCompressedFile = + (m_archType == COMPRESSED_FORMAT); + fixEnables(); + } + else + { + KMessageBox::error(this, i18n("An error occurred while trying to create the archive.") ); + } + emit createDone( _success ); +} + +////////////////////////////////////////////////////////////////////// +//////////////////////// openArchive ///////////////////////////////// +////////////////////////////////////////////////////////////////////// + +void +ArkWidget::openArchive( const QString & _filename ) +{ + Arch *newArch = 0; + ArchType archtype; + ArchiveFormatInfo * info = ArchiveFormatInfo::self(); + if ( m_openAsMimeType.isNull() ) + { + archtype = info->archTypeForURL( m_url ); + if ( info->wasUnknownExtension() ) + { + ArchiveFormatDlg * dlg = new ArchiveFormatDlg( this, info->findMimeType( m_url ) ); + if ( !dlg->exec() == QDialog::Accepted ) + { + emit setWindowCaption( QString::null ); + emit removeRecentURL( m_realURL ); + delete dlg; + file_close(); + return; + } + m_openAsMimeType = dlg->mimeType(); + archtype = info->archTypeForMimeType( m_openAsMimeType ); + delete dlg; + } + } + else + { + archtype = info->archTypeForMimeType( m_openAsMimeType ); + } + + kdDebug( 1601 ) << "m_openAsMimeType is: " << m_openAsMimeType << endl; + if( 0 == ( newArch = Arch::archFactory( archtype, this, + _filename, m_openAsMimeType) ) ) + { + emit setWindowCaption( QString::null ); + emit removeRecentURL( m_realURL ); + KMessageBox::error( this, i18n("Unknown archive format or corrupted archive") ); + return; + } + + if (!newArch->unarchUtilityIsAvailable()) + { + KMessageBox::error(this, i18n("The utility %1 is not in your PATH.\nPlease install it or contact your system administrator.").arg(newArch->getUnarchUtility())); + return; + } + + m_archType = archtype; + + connect( newArch, SIGNAL(sigOpen(Arch *, bool, const QString &, int)), + this, SLOT(slotOpen(Arch *, bool, const QString &,int)) ); + connect( newArch, SIGNAL(headers(const ColumnList&)), + m_fileListView, SLOT(setHeaders(const ColumnList&))); + + disableAll(); + + busy( i18n( "Opening the archive..." ) ); + m_fileListView->setUpdatesEnabled( false ); + arch = newArch; + newArch->open(); + emit addRecentURL( m_url ); +} + +void +ArkWidget::slotOpen( Arch * /* _newarch */, bool _success, const QString & _filename, int ) +{ + ready(); + m_fileListView->setUpdatesEnabled(true); + m_fileListView->triggerUpdate(); + + m_fileListView->show(); + + if ( _success ) + { + QFileInfo fi( _filename ); + QString path = fi.dirPath( true ); + + if ( !fi.isWritable() ) + { + arch->setReadOnly(true); + KMessageBox::information(this, i18n("This archive is read-only. If you want to save it under a new name, go to the File menu and select Save As."), i18n("Information"), "ReadOnlyArchive"); + } + updateStatusTotals(); + m_bIsArchiveOpen = true; + m_bIsSimpleCompressedFile = ( m_archType == COMPRESSED_FORMAT ); + + if ( m_extractOnly ) + { + extractOnlyOpenDone(); + return; + } + m_fileListView->adjustColumns(); + emit addOpenArk( _filename ); + } + else + { + emit removeRecentURL( m_realURL ); + emit setWindowCaption( QString::null ); + KMessageBox::error( this, i18n( "An error occurred while trying to open the archive %1" ).arg( _filename ) ); + + if ( m_extractOnly ) + emit request_file_quit(); + } + + fixEnables(); + emit openDone( _success ); +} + + +void ArkWidget::slotShowSearchBarToggled( bool b ) +{ + if ( b ) + { + m_searchToolBar->show(); + ArkSettings::setShowSearchBar( true ); + } + else + { + m_searchToolBar->hide(); + ArkSettings::setShowSearchBar( false ); + } +} + +/** + * Show Settings dialog. + */ +void ArkWidget::showSettings(){ + if(KConfigDialog::showDialog("settings")) + return; + + KConfigDialog *dialog = new KConfigDialog(this, "settings", ArkSettings::self()); + + General* genPage = new General(0, "General"); + dialog->addPage(genPage, i18n("General"), "ark", i18n("General Settings")); + dialog->addPage(new Addition(0, "Addition"), i18n("Addition"), "ark_addfile", i18n("File Addition Settings")); + dialog->addPage(new Extraction(0, "Extraction"), i18n("Extraction"), "ark_extract", i18n("Extraction Settings")); + + KTrader::OfferList offers; + + offers = KTrader::self()->query( "KonqPopupMenu/Plugin", "Library == 'libarkplugin'" ); + + if ( offers.isEmpty() ) + genPage->kcfg_KonquerorIntegration->setEnabled( false ); + else + genPage->konqIntegrationLabel->setText( QString::null ); + + dialog->show(); +} + +#include "arkwidget.moc" diff --git a/ark/arkwidget.h b/ark/arkwidget.h new file mode 100644 index 0000000..d64bbd0 --- /dev/null +++ b/ark/arkwidget.h @@ -0,0 +1,318 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + 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. + +*/ + +#ifndef ARKWIDGET_H +#define ARKWIDGET_H + +#include <kio/job.h> +#include <ktempdir.h> + +#include <qvbox.h> +#include "arch.h" + +class QPoint; +class QString; +class QStringList; +class QLabel; +class QListViewItem; +class QDragMoveEvent; +class QDropEvent; + +class KPopupMenu; +class KProcess; +class KURL; +class KRun; +class KTempFile; +class KTempDir; +class KToolBar; + +class FileListView; +class SearchBar; + + +class ArkWidget : public QVBox +{ + Q_OBJECT +public: + ArkWidget( QWidget *parent=0, const char *name=0 ); + virtual ~ArkWidget(); + + bool isArchiveOpen() const { return m_bIsArchiveOpen; } + int getNumFilesInArchive() const { return m_nNumFiles; } + + int getArkInstanceId() const { return m_arkInstanceId; } + void setArkInstanceId( int aid ) { m_arkInstanceId = aid; } + + void cleanArkTmpDir(); + virtual QString getArchName() const { return m_strArchName; } + + const KURL& realURL() const { return m_realURL; } + void setRealURL( const KURL& url ) { m_realURL = url; } + + QString tmpDir() const { return m_tmpDir ? m_tmpDir->name() : QString::null; } + + FileListView * fileList() const { return m_fileListView; } + SearchBar * searchBar() const { return m_searchBar; } + Arch * archive() const { return arch; } + ArchType archiveType() const { return m_archType; } + int numSelectedFiles() const { return m_nNumSelectedFiles; } + + /** + * Miscellaneous tasks involved in closing an archive. + */ + void closeArch(); + + virtual void setExtractOnly(bool extOnly) { m_extractOnly = extOnly; } + virtual void deleteAfterUse( const QString& path ); + bool allowedArchiveName( const KURL & u ); + bool file_save_as( const KURL & u ); + virtual KURL getSaveAsFileName(); + virtual void setOpenAsMimeType( const QString & mimeType ); + QString & openAsMimeType(){ return m_openAsMimeType; } + void prepareViewFiles( const QStringList & fileList ); + virtual void setArchivePopupEnabled( bool b ); + + virtual void extractTo( const KURL & targetDirectory, const KURL & archive, bool bGuessName ); + virtual bool addToArchive( const KURL::List & filesToAdd, const KURL & archive = KURL() ); + void convertTo( const KURL & u ); + + bool isModified() { return m_modified; } + void setModified( bool b ) { m_modified = b; } + +public slots: + void file_open( const KURL& url); + virtual void file_close(); + virtual void file_new(); + void slotShowSearchBarToggled( bool b ); + void showSettings(); + +protected slots: + void action_add(); + void action_add_dir(); + void action_view(); + void action_delete(); + bool action_extract(); + void slotOpenWith(); + void action_edit(); + + void doPopup(QListViewItem *, const QPoint &, int); // right-click menus + void viewFile(QListViewItem*); // doubleClick view files + + void slotSelectionChanged(); + void slotOpen(Arch *, bool, const QString &, int); + void slotCreate(Arch *, bool, const QString &, int); + void slotDeleteDone(bool); + void slotExtractDone(bool); + void slotExtractRemoteDone(KIO::Job *job); + void slotAddDone(bool); + void slotEditFinished(KProcess *); +signals: + void openURLRequest( const KURL & url ); + void request_file_quit(); + void setBusy( const QString & ); + void setReady(); + void fixActions(); + void disableAllActions(); + void signalFilePopup( const QPoint & pPoint ); + void signalArchivePopup( const QPoint & pPoint ); + void setStatusBarText( const QString & text ); + void setStatusBarSelectedFiles( const QString & text ); + void removeRecentURL( const KURL & url ); + void addRecentURL( const KURL & url ); + void setWindowCaption( const QString &caption ); + void removeOpenArk( const KURL & ); + void addOpenArk( const KURL & ); + void createDone( bool ); + void openDone( bool ); + void createRealArchiveDone( bool ); + void extractRemoteMovingDone(); + +protected: + + // DND + void dragMoveEvent(QDragMoveEvent *e); + void dropEvent(QDropEvent* event); + void dropAction(QStringList & list); + +private: // methods + // disabling/enabling of buttons and menu items + void fixEnables(); + + // disable all (temporarily, during operations) + void disableAll(); + void updateStatusSelection(); + void updateStatusTotals(); + void addFile(QStringList *list); + void removeDownloadedFiles(); + + // make sure that str is a local file/dir + KURL toLocalFile(const KURL& url); + + // ask user whether to create a real archive from a compressed file + // returns filename if so. Otherwise, empty. + KURL askToCreateRealArchive(); + Arch * getNewArchive( const QString & _fileName, const QString& _mimetype = QString() ); + void createRealArchive( const QString &strFilename, + const QStringList & filesToAdd = QStringList() ); + KURL getCreateFilename( const QString & _caption, + const QString & _defaultMimeType = QString::null, + bool allowCompressed = true, + const QString & _suggestedName = QString::null ); + + bool reportExtractFailures(const QString & _dest, QStringList *_list); + QStringList existingFiles( const QString & _dest, QStringList & _list ); + + void extractOnlyOpenDone(); + void extractRemoteInitiateMoving( const KURL & target ); + void editStart(); + + void busy( const QString & text ); + void holdBusy(); + void resumeBusy(); + void ready(); + + //suggests an extract directory based on archive name + const QString guessName( const KURL & archive ); + +private slots: + void startDrag( const QStringList & fileList ); + void startDragSlotExtractDone( bool ); + void editSlotExtractDone(); + void editSlotAddDone( bool success ); + void viewSlotExtractDone( bool success ); + void openWithSlotExtractDone( bool success ); + + void createRealArchiveSlotCreate( Arch * newArch, bool success, + const QString & fileName, int nbr ); + void createRealArchiveSlotAddDone( bool success ); + void createRealArchiveSlotAddFilesDone( bool success ); + + void convertSlotExtractDone( bool success ); + void convertSlotCreate(); + void convertSlotCreateDone( bool success ); + void convertSlotAddDone( bool success ); + void convertFinish(); + + void extractToSlotOpenDone( bool success ); + void extractToSlotExtractDone( bool success ); + + void addToArchiveSlotOpenDone( bool success ); + void addToArchiveSlotCreateDone( bool success ); + void addToArchiveSlotAddDone( bool success ); + +protected: + void arkWarning(const QString& msg); + void arkError(const QString& msg); + + void newCaption(const QString& filename); + void createFileListView(); + + bool createArchive(const QString & name); + void openArchive(const QString & name); + + void showCurrentFile(); + +private: // data + + bool m_bBusy; + bool m_bBusyHold; + + // for use in the edit methods: the url. + QString m_strFileToView; + + // the compressed file to be added into the new archive + QString m_compressedFile; + + // Set to true if we are doing an "Extract to Folder" + bool m_extractOnly; + + // Set to true if we are extracting to a remote location + bool m_extractRemote; + + // URL to extract to. + KURL m_extractURL; + + // URL to view + KURL m_viewURL; + + // the mimetype the user wants to open this archive as + QString m_openAsMimeType; + + // if they're dragging in files, this is the temporary list for when + // we have to create an archive: + QStringList *m_pTempAddList; + + KRun *m_pKRunPtr; + + QStringList mpDownloadedList; + + bool m_bArchivePopupEnabled; + + KTempDir * m_convert_tmpDir; + KURL m_convert_saveAsURL; + bool m_convertSuccess; + + KURL m_extractTo_targetDirectory; + + KURL::List m_addToArchive_filesToAdd; + KURL m_addToArchive_archive; + + KTempDir * m_createRealArchTmpDir; + KTempDir * m_extractRemoteTmpDir; + + bool m_modified; + + KToolBar * m_searchToolBar; + SearchBar * m_searchBar; + + Arch * arch; + QString m_strArchName; + KURL m_realURL; + KURL m_url; + ArchType m_archType; + FileListView * m_fileListView; + + KIO::filesize_t m_nSizeOfFiles; + KIO::filesize_t m_nSizeOfSelectedFiles; + unsigned int m_nNumFiles; + int m_nNumSelectedFiles; + int m_arkInstanceId; + + bool m_bIsArchiveOpen; + bool m_bIsSimpleCompressedFile; + bool m_bDropSourceIsSelf; + + QStringList mDragFiles; + QStringList *m_extractList; + QStringList *m_viewList; + KTempDir *m_tmpDir; +}; + +#endif /* ARKWIDGET_H*/ + diff --git a/ark/common_texts.cpp b/ark/common_texts.cpp new file mode 100644 index 0000000..cc64b82 --- /dev/null +++ b/ark/common_texts.cpp @@ -0,0 +1,35 @@ +i18n(" Filename ") +i18n(" Permissions ") +i18n(" Owner/Group ") +i18n(" Size ") +i18n(" Timestamp ") +i18n(" Link ") +i18n(" Size Now ") +i18n(" Ratio ") +i18n("acronym for Cyclic Redundancy Check"," CRC ") +i18n(" Method ") +i18n(" Version ") +i18n(" Owner ") +i18n(" Group ") +i18n("(used as part of a sentence)","start-up folder") +i18n("folder for opening files (used as part of a sentence)","open folder") +i18n("folder for extracting files (used as part of a sentence)","extract folder") +i18n("folder for adding files (used as part of a sentence)","add folder") + +i18n("Settings") +i18n("&Adding") +i18n("&Extracting") +i18n("&Folders") +i18n("Add Settings") +i18n("Extract Settings") +i18n("Replace &old files only with newer files") +i18n("Keep entries &generic (Lha)") +i18n("Force &MS-DOS short filenames (Zip)") +i18n("Translate LF to DOS &CRLF (Zip)") +i18n("&Recursively add subfolders (Zip, Rar)") +i18n("&Store symlinks as links (Zip, Rar)") +i18n("O&verwrite files (Zip, Tar, Zoo, Rar)") +i18n("&Preserve permissions (Tar)") +i18n("&Ignore folder names (Zip)") +i18n("Convert filenames to &lowercase (Zip, Rar)") +i18n("Convert filenames to &uppercase (Rar)") diff --git a/ark/compressedfile.cpp b/ark/compressedfile.cpp new file mode 100644 index 0000000..9ebe283 --- /dev/null +++ b/ark/compressedfile.cpp @@ -0,0 +1,376 @@ +/* + ark: A program for modifying archives via a GUI. + + Copyright (C) + + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com) + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + + 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 <unistd.h> +#include <stdlib.h> +#include <fcntl.h> + +// Qt includes +#include <qdir.h> + +// KDE includes +#include <kdebug.h> +#include <klargefile.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ktempdir.h> +#include <kprocess.h> +#include <kmimetype.h> +#include <kio/netaccess.h> +#include <kio/global.h> +#include <kfileitem.h> +#include <kapplication.h> +#include <kglobal.h> + +// ark includes +#include "arkwidget.h" +#include "filelistview.h" +#include "compressedfile.h" + +// encapsulates the idea of a compressed file + +CompressedFile::CompressedFile( ArkWidget *_gui, const QString & _fileName, const QString & _openAsMimeType ) + : Arch( _gui, _fileName ) +{ + m_tempDirectory = NULL; + m_openAsMimeType = _openAsMimeType; + kdDebug(1601) << "CompressedFile constructor" << endl; + m_tempDirectory = new KTempDir( _gui->tmpDir() + + QString::fromLatin1( "compressed_file_temp" ) ); + m_tempDirectory->setAutoDelete( true ); + m_tmpdir = m_tempDirectory->name(); + initData(); + verifyCompressUtilityIsAvailable( m_archiver_program ); + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + + if (!QFile::exists(_fileName)) + { + KMessageBox::information(0, + i18n("You are creating a simple compressed archive which contains only one input file.\n" + "When uncompressed, the file name will be based on the name of the archive file.\n" + "If you add more files you will be prompted to convert it to a real archive."), + i18n("Simple Compressed Archive"), "CreatingCompressedArchive"); + } +} + +CompressedFile::~CompressedFile() +{ + if ( m_tempDirectory ) + delete m_tempDirectory; +} + +void CompressedFile::setHeaders() +{ + ColumnList list; + list.append(FILENAME_COLUMN); + list.append(PERMISSION_COLUMN); + list.append(OWNER_COLUMN); + list.append(GROUP_COLUMN); + list.append(SIZE_COLUMN); + + emit headers(list); +} + +void CompressedFile::initData() +{ + m_unarchiver_program = QString::null; + m_archiver_program = QString::null; + + QString mimeType; + if ( !m_openAsMimeType.isNull() ) + mimeType = m_openAsMimeType; + else + mimeType = KMimeType::findByPath( m_filename )->name(); + + if ( mimeType == "application/x-gzip" ) + { + m_unarchiver_program = "gunzip"; + m_archiver_program = "gzip"; + m_defaultExtensions << ".gz" << "-gz" << ".z" << "-z" << "_z" << ".Z"; + } + if ( mimeType == "application/x-bzip" ) + { + m_unarchiver_program = "bunzip"; + m_archiver_program = "bzip"; + m_defaultExtensions << ".bz"; + } + if ( mimeType == "application/x-bzip2" ) + { + m_unarchiver_program = "bunzip2"; + m_archiver_program = "bzip2"; + m_defaultExtensions << ".bz2" << ".bz"; + } + if ( mimeType == "application/x-lzop" ) + { m_unarchiver_program = "lzop"; + m_archiver_program = "lzop"; + m_defaultExtensions << ".lzo"; + } + if ( mimeType == "application/x-compress" ) + { + m_unarchiver_program = KGlobal::dirs()->findExe( "uncompress" ).isNull()? "gunzip" : "uncompress"; + m_archiver_program = "compress"; + m_defaultExtensions = ".Z"; + } + +} + +QString CompressedFile::extension() +{ + QStringList::Iterator it = m_defaultExtensions.begin(); + for( ; it != m_defaultExtensions.end(); ++it ) + if( m_filename.endsWith( *it ) ) + return QString::null; + return m_defaultExtensions.first(); +} + +void CompressedFile::open() +{ + kdDebug(1601) << "+CompressedFile::open" << endl; + setHeaders(); + + // We copy the file into the temporary directory, uncompress it, + // and when the uncompression is done, list it + // (that code is in the slot slotOpenDone) + + m_tmpfile = m_gui->realURL().fileName(); + if ( m_tmpfile.isEmpty() ) + m_tmpfile = m_filename; + m_tmpfile += extension(); + m_tmpfile = m_tmpdir + m_tmpfile; + + KURL src, target; + src.setPath( m_filename ); + target.setPath( m_tmpfile ); + + KIO::NetAccess::copy( src, target, m_gui ); + kdDebug(1601) << "Temp file name is " << target << endl; + + if ( !KIO::NetAccess::exists( target, true, NULL ) ) + return; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + *kp << m_unarchiver_program << "-f" ; + if ( m_unarchiver_program == "lzop") + { + *kp << "-d"; + // lzop hack, see comment in tar.cpp createTmp() + kp->setUsePty( KProcess::Stdin, false ); + } + // gunzip 1.3 seems not to like original names with directories in them + // testcase: https://listman.redhat.com/pipermail/valhalla-list/2006-October.txt.gz + /*if ( m_unarchiver_program == "gunzip" ) + *kp << "-N"; + */ + *kp << m_tmpfile; + + kdDebug(1601) << "Command is " << m_unarchiver_program << " " << m_tmpfile<< endl; + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotUncompressDone(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigOpen(this, false, QString::null, 0 ); + } + + kdDebug(1601) << "-CompressedFile::open" << endl; +} + +void CompressedFile::slotUncompressDone(KProcess *_kp) +{ + bool bSuccess = false; + kdDebug(1601) << "normalExit = " << _kp->normalExit() << endl; + if( _kp->normalExit() ) + kdDebug(1601) << "exitStatus = " << _kp->exitStatus() << endl; + + if( _kp->normalExit() && (_kp->exitStatus()==0) ) + { + bSuccess = true; + } + + delete _kp; + _kp = m_currentProcess = 0; + + if ( !bSuccess ) + { + emit sigOpen( this, false, QString::null, 0 ); + return; + } + + QDir dir( m_tmpdir ); + QStringList lst( dir.entryList() ); + lst.remove( ".." ); + lst.remove( "." ); + KURL url; + url.setPath( m_tmpdir + lst.first() ); + m_tmpfile = url.path(); + KIO::UDSEntry udsInfo; + KIO::NetAccess::stat( url, udsInfo, m_gui ); + KFileItem fileItem( udsInfo, url ); + QStringList list; + list << fileItem.name(); + list << fileItem.permissionsString(); + list << fileItem.user(); + list << fileItem.group(); + list << KIO::number( fileItem.size() ); + m_gui->fileList()->addItem(list); // send to GUI + + emit sigOpen( this, bSuccess, m_filename, + Arch::Extract | Arch::Delete | Arch::Add | Arch::View ); +} + +void CompressedFile::create() +{ + emit sigCreate(this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add + | Arch::View); +} + +void CompressedFile::addFile( const QStringList &urls ) +{ + // only used for adding ONE file to an EMPTY gzip file, i.e., one that + // has just been created + + kdDebug(1601) << "+CompressedFile::addFile" << endl; + + Q_ASSERT(m_gui->getNumFilesInArchive() == 0); + Q_ASSERT(urls.count() == 1); + + KURL url = KURL::fromPathOrURL(urls.first()); + Q_ASSERT(url.isLocalFile()); + + QString file; + file = url.path(); + + KProcess proc; + proc << "cp" << file << m_tmpdir; + proc.start(KProcess::Block); + + m_tmpfile = file.right(file.length() + - file.findRev("/")-1); + m_tmpfile = m_tmpdir + '/' + m_tmpfile; + + kdDebug(1601) << "Temp file name is " << m_tmpfile << endl; + + kdDebug(1601) << "File is " << file << endl; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + // lzop hack, see comment in tar.cpp createTmp() + if ( m_archiver_program == "lzop") + kp->setUsePty( KProcess::Stdin, false ); + + QString compressor = m_archiver_program; + + *kp << compressor << "-c" << file; + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotAddInProgress(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotAddDone(KProcess*))); + + int f_desc = KDE_open(QFile::encodeName(m_filename), O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (f_desc != -1) + fd = fdopen( f_desc, "w" ); + else + fd = NULL; + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + } + + kdDebug(1601) << "-CompressedFile::addFile" << endl; +} + +void CompressedFile::slotAddInProgress(KProcess*, char* _buffer, int _bufflen) +{ + // we're trying to capture the output of a command like this + // gzip -c myfile + // and feed the output to the compressed file + int size; + size = fwrite(_buffer, 1, _bufflen, fd); + if (size != _bufflen) + { + KMessageBox::error(0, i18n("Trouble writing to the archive...")); + exit(99); + } +} + +void CompressedFile::slotAddDone(KProcess *_kp) +{ + fclose(fd); + slotAddExited(_kp); +} + +void CompressedFile::unarchFileInternal() +{ + if (m_destDir != m_tmpdir) + { + QString dest; + if (m_destDir.isEmpty() || m_destDir.isNull()) + { + kdError(1601) << "There was no extract directory given." << endl; + return; + } + else + dest=m_destDir; + + KProcess proc; + proc << "cp" << m_tmpfile << dest; + proc.start(KProcess::Block); + } + emit sigExtract(true); +} + +void CompressedFile::remove(QStringList *) +{ + kdDebug(1601) << "+CompressedFile::remove" << endl; + QFile::remove(m_tmpfile); + + // do not delete but truncate the compressed file in case someone + // does a reload and finds it no longer exists! + truncate(QFile::encodeName(m_filename), 0); + + m_tmpfile = ""; + emit sigDelete(true); + kdDebug(1601) << "-CompressedFile::remove" << endl; +} + + + +#include "compressedfile.moc" + diff --git a/ark/compressedfile.h b/ark/compressedfile.h new file mode 100644 index 0000000..ceaee6c --- /dev/null +++ b/ark/compressedfile.h @@ -0,0 +1,86 @@ +/* + + ark: A program for modifying archives via a GUI. + + Copyright (C) + + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ +#ifndef COMPRESSED_FILE_H +#define COMPRESSED_FILE_H + +class QString; +class QCString; +class QStringList; +class KProcess; +class KTempDir; + +class Arch; +class ArkWidget; + +// This isn't *really* an archive, but having this class in the program +// allows people to manage gzipped files if they want. If someone tries to +// add a file, the gz-file must be empty (hozat? it could be empty by having +// just been created). Otherwise, the user will be asked to create a REAL +// archive, and then the added file(s) and the original file will be +// transferred to the new archive. +// +class CompressedFile : public Arch +{ + Q_OBJECT +public: + CompressedFile( ArkWidget *_gui, const QString & _fileName, const QString &_openAsMimeType ); + virtual ~CompressedFile(); + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList& ); + virtual void addDir(const QString &) { } + + virtual void remove(QStringList *); + virtual void unarchFileInternal(); + + QString tempFileName(){ return m_tmpfile; } + +private slots: + void slotUncompressDone(KProcess *); + void slotAddInProgress(KProcess*, char*, int); + void slotAddDone(KProcess*); + +private: + void initExtract( bool, bool, bool ); + void setHeaders(); + void initData(); + QString extension(); + + QString m_openAsMimeType; + KTempDir * m_tempDirectory; + QString m_tmpdir; + QString m_tmpfile; + QStringList m_defaultExtensions; + + // for use with addFile + FILE *fd; + +}; + + + +#endif // COMPRESSED_FILE_H diff --git a/ark/configure.in.in b/ark/configure.in.in new file mode 100644 index 0000000..e0e280a --- /dev/null +++ b/ark/configure.in.in @@ -0,0 +1,11 @@ +AC_CHECK_KDEMAXPATHLEN + +KDE_CHECK_FUNC_EXT(statfs, [ +#include <sys/mount.h> +], [ + char buffer[200]; + struct statfs b; + statfs(buffer, &b); +], [ + int statfs(const char *path, struct statfs *buffer) +], [STATFS]) diff --git a/ark/extraction.ui b/ark/extraction.ui new file mode 100644 index 0000000..692692f --- /dev/null +++ b/ark/extraction.ui @@ -0,0 +1,79 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>Extraction</class> +<widget class="QWidget"> + <property name="name"> + <cstring>Extraction</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>436</width> + <height>289</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_extractOverwrite</cstring> + </property> + <property name="text"> + <string>O&verwrite files (Zip, Tar, Zoo, Rar)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_preservePerms</cstring> + </property> + <property name="text"> + <string>&Preserve permissions (Tar)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_extractJunkPaths</cstring> + </property> + <property name="text"> + <string>&Ignore folder names (Zip)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_rarToLower</cstring> + </property> + <property name="text"> + <string>Convert file names to &lowercase (Zip, Rar)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_rarToUpper</cstring> + </property> + <property name="text"> + <string>Convert file names to &uppercase (Rar)</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/ark/extractiondialog.cpp b/ark/extractiondialog.cpp new file mode 100644 index 0000000..7892efb --- /dev/null +++ b/ark/extractiondialog.cpp @@ -0,0 +1,195 @@ +/* + * ark -- archiver for the KDE project + * + * Copyright (C) + * + * 2005: Henrique Pinto <henrique.pinto@kdemail.net> + * 2002: Helio Chissini de Castro <helio@conectiva.com.br> + * 2001: Roberto Selbach Teixeira <maragato@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. + * + */ + +#include "extractiondialog.h" + +#include <qvbox.h> +#include <qhbox.h> +#include <qhbuttongroup.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <qlayout.h> + +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kurlrequester.h> +#include <kurlcompletion.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kcombobox.h> +#include <klineedit.h> +#include <kurlpixmapprovider.h> +#include <kdebug.h> + +#include "arkutils.h" +#include "settings.h" + +ExtractionDialog::ExtractionDialog( QWidget *parent, const char *name, + bool enableSelected, + const KURL& defaultExtractionDir, + const QString &prefix, + const QString &archiveName ) + : KDialogBase( parent, name, true, i18n( "Extract" ), Ok | Cancel, Ok ), + m_selectedButton( 0 ), m_allButton( 0 ), + m_selectedOnly( enableSelected ), m_extractionDirectory( defaultExtractionDir ), + m_defaultExtractionDir( defaultExtractionDir.prettyURL() ), m_prefix( prefix ) +{ + if ( !archiveName.isNull() ) + { + setCaption( i18n( "Extract Files From %1" ).arg( archiveName ) ); + } + + QVBox *vbox = makeVBoxMainWidget(); + + QHBox *header = new QHBox( vbox ); + header->layout()->setSpacing( 10 ); + + QLabel *icon = new QLabel( header ); + icon->setPixmap( DesktopIcon( "ark_extract" ) ); + icon->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ); + + if ( enableSelected ) + { + QVBox *whichFiles = new QVBox( header ); + whichFiles->layout()->setSpacing( 6 ); + new QLabel( QString( "<qt><b><font size=\"+1\">%1</font></b></qt>" ) + .arg( i18n( "Extract:" ) ), whichFiles ); + QHButtonGroup *filesGroup = new QHButtonGroup( whichFiles ); + m_selectedButton = new QRadioButton( i18n( "Selected files only" ), filesGroup ); + m_allButton = new QRadioButton( i18n( "All files" ), filesGroup ); + + m_selectedButton->setChecked( true ); + } + else + { + new QLabel( QString( "<qt><b><font size=\"+2\">%1</font></b></qt>" ) + .arg( i18n( "Extract all files" ) ), header ); + } + + QHBox *destDirBox = new QHBox( vbox ); + + QLabel *destFolderLabel = new QLabel( i18n( "Destination folder: " ), destDirBox ); + destFolderLabel->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ); + + KHistoryCombo *combobox = new KHistoryCombo( true, destDirBox ); + combobox->setPixmapProvider( new KURLPixmapProvider ); + combobox->setHistoryItems( ArkSettings::extractionHistory() ); + destFolderLabel->setBuddy( combobox ); + + KURLCompletion *comp = new KURLCompletion(); + comp->setReplaceHome( true ); + comp->setCompletionMode( KGlobalSettings::CompletionAuto ); + combobox->setCompletionObject( comp ); + combobox->setMaxCount( 20 ); + combobox->setInsertionPolicy( QComboBox::AtTop ); + + m_urlRequester = new KURLRequester( combobox, destDirBox ); + m_urlRequester->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + m_urlRequester->setMode( KFile::Directory ); + + if (!defaultExtractionDir.prettyURL().isEmpty() ) + { + m_urlRequester->setKURL( defaultExtractionDir.prettyURL() + prefix ); + } + + m_viewFolderAfterExtraction = new QCheckBox( i18n( "Open destination folder after extraction" ), vbox ); + m_viewFolderAfterExtraction->setChecked( ArkSettings::openDestinationFolder() ); + + connect( combobox, SIGNAL( returnPressed( const QString& ) ), combobox, SLOT( addToHistory( const QString& ) ) ); + connect( combobox->lineEdit(), SIGNAL( textChanged( const QString& ) ), + this, SLOT( extractDirChanged( const QString & ) ) ); +} + +ExtractionDialog::~ExtractionDialog() +{ + ArkSettings::setExtractionHistory( ( static_cast<KHistoryCombo*>( m_urlRequester->comboBox() ) )->historyItems() ); +} + +void ExtractionDialog::accept() +{ + + KURLCompletion uc; + uc.setReplaceHome( true ); + KURL p( uc.replacedPath( m_urlRequester->comboBox()->currentText() ) ); + + //if p isn't local KIO and friends will complain later on + if ( p.isLocalFile() ) + { + QFileInfo fi( p.path() ); + if ( !fi.isDir() && !fi.exists() ) + { + QString ltext = i18n( "Create folder %1?").arg(p.path()); + int createDir = KMessageBox::questionYesNo( this, ltext, i18n( "Missing Folder" ) , i18n("Create Folder"), i18n("Do Not Create")); + if( createDir == 4 ) + { + return; + } + // create directory using filename, make sure it has trailing slash + p.adjustPath(1); + if( !KStandardDirs::makeDir( p.path() ) ) + { + KMessageBox::error( this, i18n( "The folder could not be created. Please check permissions." ) ); + return; + } + } + if ( !ArkUtils::haveDirPermissions( p.path() ) ) + { + KMessageBox::error( this, i18n( "You do not have write permission to this folder. Please provide another folder." ) ); + return; + } + } + + m_extractionDirectory = p; + m_selectedOnly = m_selectedButton == 0? false : m_selectedButton->isChecked(); + + // Determine what exactly should be added to the extraction combo list + QString historyURL = p.prettyURL(); + if ( historyURL == KURL( m_defaultExtractionDir + m_prefix ).prettyURL() ) + { + historyURL = m_defaultExtractionDir; + } + + KHistoryCombo *combo = static_cast<KHistoryCombo*>( m_urlRequester->comboBox() ); + // If the item was already in the list, delete it from the list and readd it at the top + combo->removeFromHistory( historyURL ); + combo->addToHistory( historyURL ); + + ArkSettings::setOpenDestinationFolder( m_viewFolderAfterExtraction->isChecked() ); + + KDialogBase::accept(); +} + +void ExtractionDialog::extractDirChanged(const QString &text ) +{ + enableButtonOK(!text.isEmpty()); +} + +#include "extractiondialog.moc" +// kate: space-indent off; tab-width 4; diff --git a/ark/extractiondialog.h b/ark/extractiondialog.h new file mode 100644 index 0000000..822c085 --- /dev/null +++ b/ark/extractiondialog.h @@ -0,0 +1,97 @@ +/* + * ark -- archiver for the KDE project + * + * Copyright (C) + * + * 1997-1999: Rob Palmbos palm9744@kettering.edu + * 1999: Francois-Xavier Duranceau duranceau@kde.org + * 1999-2000: Corel Corporation (author: Emily Ezust emilye@corel.com) + * 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com) + * 2001: Roberto Selbach Teixeira (maragato@conectiva.com) + * 2005: Henrique Pinto ( henrique.pinto@kdemail.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. + * + * 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. + * + */ + +#ifndef EXTRACTIONDIALOG_H +#define EXTRACTIONDIALOG_H + +#include <qcheckbox.h> + +#include <kurl.h> +#include <kdialogbase.h> + +class QRadioButton; + +class KURLRequester; + +class ExtractionDialog : public KDialogBase +{ + Q_OBJECT + public: + /** + * Constructor. + */ + ExtractionDialog( QWidget *parent = 0, const char *name = 0, + bool enableSelected = true, + const KURL &defaultExtractionDir = KURL(), + const QString &prefix = QString(), + const QString &archiveName = QString::null ); + + /** + * Destructor. + */ + ~ExtractionDialog(); + + + + /** + * Returns true if the user wants to extract only the selected files + */ + bool selectedOnly() const { return m_selectedOnly; } + + /** + * Returns the directory the files should be extracted to. + */ + KURL extractionDirectory() const { return m_extractionDirectory; } + + /** + * Returns true if the user wants the extraction folder to be opened after extraction + */ + bool viewFolderAfterExtraction() const { return m_viewFolderAfterExtraction->isChecked(); } + + + + public slots: + void accept(); + void extractDirChanged( const QString & ); + + + + private: + QRadioButton *m_selectedButton; + QRadioButton *m_allButton; + QCheckBox *m_viewFolderAfterExtraction; + bool m_selectedOnly; + KURL m_extractionDirectory; + KURLRequester *m_urlRequester; + QString m_defaultExtractionDir; + QString m_prefix; +}; + +#endif // EXTRACTIONDIALOG_H +// kate: space-indent off; tab-width 4; + diff --git a/ark/filelistview.cpp b/ark/filelistview.cpp new file mode 100644 index 0000000..3668d11 --- /dev/null +++ b/ark/filelistview.cpp @@ -0,0 +1,587 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2005: Henrique Pinto <henrique.pinto@kdemail.net> + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + 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 + + 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. + +*/ + +// Qt includes +#include <qpainter.h> +#include <qwhatsthis.h> +#include <qheader.h> + +// KDE includes +#include <klocale.h> +#include <kglobal.h> +#include <kdebug.h> +#include <kglobalsettings.h> +#include <kmimetype.h> + +#include "filelistview.h" +#include "arch.h" + +///////////////////////////////////////////////////////////////////// +// FileLVI implementation +///////////////////////////////////////////////////////////////////// + +FileLVI::FileLVI( KListView* lv ) + : KListViewItem( lv ), m_fileSize( 0 ), m_packedFileSize( 0 ), + m_ratio( 0 ), m_timeStamp( QDateTime() ), m_entryName( QString() ) +{ + +} + +FileLVI::FileLVI( KListViewItem* lvi ) + : KListViewItem( lvi ), m_fileSize( 0 ), m_packedFileSize( 0 ), + m_ratio( 0 ), m_timeStamp( QDateTime() ), m_entryName( QString() ) +{ +} + +QString FileLVI::key( int column, bool ascending ) const +{ + if ( column == 0 ) + return fileName(); + else + return QListViewItem::key( column, ascending ); +} + +int FileLVI::compare( QListViewItem * i, int column, bool ascending ) const +{ + FileLVI * item = static_cast< FileLVI * >( i ); + + if ( ( this->childCount() > 0 ) && ( item->childCount() == 0 ) ) + return -1; + + if ( ( this->childCount() == 0 ) && ( item->childCount() > 0 ) ) + return 1; + + if ( column == 0 ) + return KListViewItem::compare( i, column, ascending ); + + columnName colName = ( static_cast< FileListView * > ( listView() ) )->nameOfColumn( column ); + switch ( colName ) + { + case sizeCol: + { + return ( m_fileSize < item->fileSize() ? -1 : + ( m_fileSize > item->fileSize() ? 1 : 0 ) + ); + break; + } + + case ratioStrCol: + { + return ( m_ratio < item->ratio() ? -1 : + ( m_ratio > item->ratio() ? 1 : 0 ) + ); + break; + } + + case packedStrCol: + { + return ( m_packedFileSize < item->packedFileSize() ? -1 : + ( m_packedFileSize > item->packedFileSize() ? 1 : 0 ) + ); + break; + } + + case timeStampStrCol: + { + return ( m_timeStamp < item->timeStamp() ? -1 : + ( m_timeStamp > item->timeStamp() ? 1 : 0 ) + ); + break; + } + + default: + return KListViewItem::compare( i, column, ascending ); + } +} + +void FileLVI::setText( int column, const QString &text ) +{ + columnName colName = ( static_cast< FileListView * > ( listView() ) )->nameOfColumn( column ); + if ( column == 0 ) + { + QString name = text; + if ( name.endsWith( "/" ) ) + name = name.left( name.length() - 1 ); + if ( name.startsWith( "/" ) ) + name = name.mid( 1 ); + int pos = name.findRev( '/' ); + if ( pos != -1 ) + name = name.right( name.length() - pos - 1 ); + QListViewItem::setText( column, name ); + m_entryName = text; + } + else if ( colName == sizeCol ) + { + m_fileSize = text.toULongLong(); + QListViewItem::setText( column, KIO::convertSize( m_fileSize ) ); + } + else if ( colName == packedStrCol ) + { + m_packedFileSize = text.toULongLong(); + QListViewItem::setText( column, KIO::convertSize( m_packedFileSize ) ); + } + else if ( colName == ratioStrCol ) + { + int l = text.length() - 1; + if ( l>0 && text[l] == '%' ) + m_ratio = text.left(l).toDouble(); + else + m_ratio = text.toDouble(); + QListViewItem::setText( column, i18n( "Packed Ratio", "%1 %" ) + .arg(KGlobal::locale()->formatNumber( m_ratio, 1 ) ) + ); + } + else if ( colName == timeStampStrCol ) + { + if ( text.isEmpty() ) + QListViewItem::setText(column, text); + else + { + m_timeStamp = QDateTime::fromString( text, ISODate ); + QListViewItem::setText( column, KGlobal::locale()->formatDateTime( m_timeStamp ) ); + } + } + else + QListViewItem::setText(column, text); +} + +static FileLVI* folderLVI( KListViewItem *parent, const QString& name ) +{ + FileLVI *folder = new FileLVI( parent ); + + folder->setText( 0, name ); + + folder->setPixmap( 0, KMimeType::mimeType( "inode/directory" )->pixmap( KIcon::Small ) ); + + return folder; +} + +static FileLVI* folderLVI( KListView *parent, const QString& name ) +{ + FileLVI *folder = new FileLVI( parent ); + folder->setText( 0, name ); + folder->setPixmap( 0, KMimeType::mimeType( "inode/directory" )->pixmap( KIcon::Small ) ); + return folder; +} + +///////////////////////////////////////////////////////////////////// +// FileListView implementation +///////////////////////////////////////////////////////////////////// + + +FileListView::FileListView(QWidget *parent, const char* name) + : KListView(parent, name) +{ + QWhatsThis::add( this, + i18n( "This area is for displaying information about the files contained within an archive." ) + ); + + setMultiSelection( true ); + setSelectionModeExt( FileManager ); + setItemsMovable( false ); + setRootIsDecorated( true ); + setShowSortIndicator( true ); + setItemMargin( 3 ); + header()->hide(); // Don't show the header until there is something to be shown in it + + m_pressed = false; +} + +int FileListView::addColumn ( const QString & label, int width ) +{ + int index = KListView::addColumn( label, width ); + if ( label == SIZE_COLUMN.first ) + { + m_columnMap[ index ] = sizeCol; + } + else if ( label == PACKED_COLUMN.first ) + { + m_columnMap[ index ] = packedStrCol; + } + else if ( label == RATIO_COLUMN.first ) + { + m_columnMap[ index ] = ratioStrCol; + } + else if ( label == TIMESTAMP_COLUMN.first ) + { + m_columnMap[ index ] = timeStampStrCol; + } + else + { + m_columnMap[ index ] = otherCol; + } + return index; +} + +void FileListView::removeColumn( int index ) +{ + for ( unsigned int i = index; i < m_columnMap.count() - 2; i++ ) + { + m_columnMap.replace( i, m_columnMap[ i + 1 ] ); + } + + m_columnMap.remove( m_columnMap[ m_columnMap.count() - 1 ] ); + KListView::removeColumn( index ); +} + +columnName FileListView::nameOfColumn( int index ) +{ + return m_columnMap[ index ]; +} + +QStringList FileListView::selectedFilenames() +{ + QStringList files; + + FileLVI *item = static_cast<FileLVI*>( firstChild() ); + + while ( item ) + { + if ( item->isSelected() ) + { + // If the item has children, add each child and the item + if ( item->childCount() > 0 ) + { + files += item->fileName(); + files += childrenOf( item ); + + /* If we got here, then the logic for "going to the next item" + * is a bit different: as we already dealt with all the children, + * the "next item" is the next sibling of the current item, not + * its first child. If the current item has no siblings, then + * the next item is the next sibling of its parent, and so on. + */ + FileLVI *nitem = static_cast<FileLVI*>( item->nextSibling() ); + while ( !nitem && item->parent() ) + { + item = static_cast<FileLVI*>( item->parent() ); + if ( item->parent() ) + nitem = static_cast<FileLVI*>( item->parent()->nextSibling() ); + } + item = nitem; + continue; + } + else + { + // If the item has no children, just add it to the list + files += item->fileName(); + } + } + // Go to the next item + item = static_cast<FileLVI*>( item->itemBelow() ); + } + + return files; +} + +QStringList FileListView::fileNames() +{ + QStringList files; + + QListViewItemIterator it( this ); + while ( it.current() ) + { + FileLVI *item = static_cast<FileLVI*>( it.current() ); + files += item->fileName(); + ++it; + } + + return files; +} + +bool FileListView::isSelectionEmpty() +{ + FileLVI * flvi = (FileLVI*)firstChild(); + + while (flvi) + { + if( flvi->isSelected() ) + return false; + else + flvi = (FileLVI*)flvi->itemBelow(); + } + return true; +} + +void +FileListView::contentsMousePressEvent(QMouseEvent *e) +{ + if( e->button()==QMouseEvent::LeftButton ) + { + m_pressed = true; + m_presspos = e->pos(); + } + + KListView::contentsMousePressEvent(e); +} + +void +FileListView::contentsMouseReleaseEvent(QMouseEvent *e) +{ + m_pressed = false; + KListView::contentsMouseReleaseEvent(e); +} + +void +FileListView::contentsMouseMoveEvent(QMouseEvent *e) +{ + if(!m_pressed) + { + KListView::contentsMouseMoveEvent(e); + } + else if( ( m_presspos - e->pos() ).manhattanLength() > KGlobalSettings::dndEventDelay() ) + { + m_pressed = false; // Prevent triggering again + if(isSelectionEmpty()) + { + return; + } + QStringList dragFiles = selectedFilenames(); + emit startDragRequest( dragFiles ); + KListView::contentsMouseMoveEvent(e); + } +} + +FileLVI* +FileListView::item(const QString& filename) const +{ + FileLVI * flvi = (FileLVI*) firstChild(); + + while (flvi) + { + QString curFilename = flvi->fileName(); + if (curFilename == filename) + return flvi; + flvi = (FileLVI*) flvi->nextSibling(); + } + + return 0; +} + +void FileListView::addItem( const QStringList & entries ) +{ + FileLVI *flvi, *parent = findParent( entries[0] ); + if ( parent ) + flvi = new FileLVI( parent ); + else + flvi = new FileLVI( this ); + + + int i = 0; + + for (QStringList::ConstIterator it = entries.begin(); it != entries.end(); ++it) + { + flvi->setText(i, *it); + ++i; + } + + KMimeType::Ptr mimeType = KMimeType::findByPath( entries.first(), 0, true ); + flvi->setPixmap( 0, mimeType->pixmap( KIcon::Small ) ); +} + +void FileListView::selectAll() +{ + QListView::selectAll( true ); +} + +void FileListView::unselectAll() +{ + QListView::selectAll( false ); +} + +void FileListView::setHeaders( const ColumnList& columns ) +{ + clearHeaders(); + + for ( ColumnList::const_iterator it = columns.constBegin(); + it != columns.constEnd(); + ++it ) + { + QPair< QString, Qt::AlignmentFlags > pair = *it; + int colnum = addColumn( pair.first ); + setColumnAlignment( colnum, pair.second ); + } + + setResizeMode( QListView::LastColumn ); + + header()->show(); +} + +void FileListView::clearHeaders() +{ + header()->hide(); + while ( columns() > 0 ) + { + removeColumn( 0 ); + } +} + +int FileListView::totalFiles() +{ + int numFiles = 0; + + QListViewItemIterator it( this ); + while ( it.current() ) + { + if ( it.current()->childCount() == 0 ) + ++numFiles; + ++it; + } + + return numFiles; +} + +int FileListView::selectedFilesCount() +{ + int numFiles = 0; + + QListViewItemIterator it( this, QListViewItemIterator::Selected ); + while ( it.current() ) + { + ++numFiles; + ++it; + } + + return numFiles; +} + +KIO::filesize_t FileListView::totalSize() +{ + KIO::filesize_t size = 0; + + QListViewItemIterator it(this); + while ( it.current() ) + { + FileLVI *item = static_cast<FileLVI*>( it.current() ); + size += item->fileSize(); + ++it; + } + + return size; +} + +KIO::filesize_t FileListView::selectedSize() +{ + KIO::filesize_t size = 0; + + QListViewItemIterator it( this, QListViewItemIterator::Selected ); + while ( it.current() ) + { + FileLVI *item = static_cast<FileLVI*>( it.current() ); + size += item->fileSize(); + ++it; + } + + return size; +} + +FileLVI* FileListView::findParent( const QString& fullname ) +{ + QString name = fullname; + + if ( name.endsWith( "/" ) ) + name = name.left( name.length() -1 ); + if ( name.startsWith( "/" ) ) + name = name.mid( 1 ); + // Checks if this entry needs a parent + if ( !name.contains( '/' ) ) + return static_cast< FileLVI* >( 0 ); + + // Get a list of ancestors + QString parentFullname = name.left( name.findRev( '/' ) ); + QStringList ancestorList = QStringList::split( '/', parentFullname ); + + // Checks if the listview contains the first item in the list of ancestors + QListViewItem *item = firstChild(); + while ( item ) + { + if ( item->text( 0 ) == ancestorList[0] ) + break; + item = item->nextSibling(); + } + + // If the list view does not contain the item, create it + if ( !item ) + { + item = folderLVI( this, ancestorList[0] ); + } + + // We've already dealt with the first item, remove it + ancestorList.pop_front(); + + while ( ancestorList.count() > 0 ) + { + QString name = ancestorList[0]; + + FileLVI *parent = static_cast< FileLVI*>( item ); + item = parent->firstChild(); + while ( item ) + { + if ( item->text(0) == name ) + break; + item = item->nextSibling(); + } + + if ( !item ) + { + item = folderLVI( parent, name ); + } + + ancestorList.pop_front(); + } + + item->setOpen( true ); + return static_cast< FileLVI* >( item ); +} + +QStringList FileListView::childrenOf( FileLVI* parent ) +{ + Q_ASSERT( parent ); + QStringList children; + + FileLVI *item = static_cast<FileLVI*>( parent->firstChild() ); + + while ( item ) + { + if ( item->childCount() == 0 ) + { + children += item->fileName(); + } + else + { + children += item->fileName(); + children += childrenOf( item ); + } + item = static_cast<FileLVI*>( item->nextSibling() ); + } + + return children; +} + +#include "filelistview.moc" +// kate: space-indent off; tab-width 4; diff --git a/ark/filelistview.h b/ark/filelistview.h new file mode 100644 index 0000000..8ea0d48 --- /dev/null +++ b/ark/filelistview.h @@ -0,0 +1,163 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com) + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + 2005: Henrique Pinto <henrique.pinto@kdemail.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. + + 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. + +*/ +#ifndef FILELISTVIEW_H +#define FILELISTVIEW_H + +#include <qdatetime.h> +#include <qpair.h> +#include <qvaluelist.h> + +#include <klistview.h> +#include <kio/global.h> + +class QString; +class QStringList; +class QRect; +class QPainter; +class QColorGroup; +class QMouseEvent; +class QPoint; + +enum columnName { sizeCol = 1 , packedStrCol, ratioStrCol, timeStampStrCol, otherCol }; + +class FileLVI : public KListViewItem +{ + public: + FileLVI( KListView* lv ); + FileLVI( KListViewItem* lvi ); + + QString fileName() const { return m_entryName; } + KIO::filesize_t fileSize() const { return m_fileSize; } + KIO::filesize_t packedFileSize() const { return m_packedFileSize; } + double ratio() const { return m_ratio; } + QDateTime timeStamp() const { return m_timeStamp; } + + int compare ( QListViewItem * i, int col, bool ascending ) const; + virtual QString key( int column, bool ) const; + virtual void setText( int column, const QString &text ); + + private: + KIO::filesize_t m_fileSize; + KIO::filesize_t m_packedFileSize; + double m_ratio; + QDateTime m_timeStamp; + QString m_entryName; +}; + +typedef QValueList< QPair< QString, Qt::AlignmentFlags > > ColumnList; + +class FileListView: public KListView +{ + Q_OBJECT + public: + FileListView( QWidget *parent = 0, const char* name = 0 ); + + FileLVI *currentItem() {return ((FileLVI *) KListView::currentItem());} + + /** + * Returns the full names of the selected files. + */ + QStringList selectedFilenames(); + + /** + * Return the full names of all files. + */ + QStringList fileNames(); + + /** + * Returns true if no file is selected + */ + bool isSelectionEmpty(); + + virtual int addColumn( const QString & label, int width = -1 ); + virtual void removeColumn( int index ); + columnName nameOfColumn( int index ); + + /** + * Returns the file item, or 0 if not found. + * @param filename The filename in question to reference in the archive + * @return The requested file's FileLVI + */ + FileLVI* item(const QString& filename) const; + + /** + * Adds a file and stats to the file listing + * @param entries A stringlist of the entries for each column of the list. + */ + void addItem( const QStringList & entries ); + + /** + * Returns the number of files in the archive. + */ + int totalFiles(); + + /** + * Returns the number of selected files. + */ + int selectedFilesCount(); + + /** + * Return the sum of the sizes of all files in the archive. + */ + KIO::filesize_t totalSize(); + + /** + * Return the sum of the sizes of the selected files. + */ + KIO::filesize_t selectedSize(); + + /** + * Adjust the size of all columns to fit their content. + */ + void adjustColumns() { for ( int i = 0; i < columns(); ++i ) adjustColumn( i ); } + + public slots: + void selectAll(); + void unselectAll(); + void setHeaders( const ColumnList& columns ); + void clearHeaders(); + + signals: + void startDragRequest( const QStringList & fileList ); + + protected: + virtual void contentsMouseReleaseEvent( QMouseEvent *e ); + virtual void contentsMousePressEvent( QMouseEvent *e ); + virtual void contentsMouseMoveEvent( QMouseEvent *e ); + + private: + FileLVI* findParent( const QString& fullname ); + QStringList childrenOf( FileLVI* parent ); + + QMap<int, columnName> m_columnMap; + bool m_pressed; + QPoint m_presspos; // this will save the click pos to correctly recognize drag events +}; + +#endif +// kate: space-indent off; tab-width 4; diff --git a/ark/general.ui b/ark/general.ui new file mode 100644 index 0000000..d822b4c --- /dev/null +++ b/ark/general.ui @@ -0,0 +1,93 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>General</class> +<widget class="QWidget"> + <property name="name"> + <cstring>General</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>323</width> + <height>251</height> + </rect> + </property> + <property name="caption"> + <string>General</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_UseIntegratedViewer</cstring> + </property> + <property name="text"> + <string>&Use integrated viewer</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_KonquerorIntegration</cstring> + </property> + <property name="text"> + <string>&Enable Konqueror integration</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>konqIntegrationLabel</cstring> + </property> + <property name="text"> + <string><font size="-1"><i>Konqueror integration is only available if you install the Konqueror integration plugin from the kdeaddons package.</i></font></string> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>90</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/ark/hi128-app-ark.png b/ark/hi128-app-ark.png Binary files differnew file mode 100644 index 0000000..874d332 --- /dev/null +++ b/ark/hi128-app-ark.png diff --git a/ark/hi16-app-ark.png b/ark/hi16-app-ark.png Binary files differnew file mode 100644 index 0000000..07391b6 --- /dev/null +++ b/ark/hi16-app-ark.png diff --git a/ark/hi22-app-ark.png b/ark/hi22-app-ark.png Binary files differnew file mode 100644 index 0000000..859b325 --- /dev/null +++ b/ark/hi22-app-ark.png diff --git a/ark/hi32-app-ark.png b/ark/hi32-app-ark.png Binary files differnew file mode 100644 index 0000000..2b00cc4 --- /dev/null +++ b/ark/hi32-app-ark.png diff --git a/ark/hi48-app-ark.png b/ark/hi48-app-ark.png Binary files differnew file mode 100644 index 0000000..89f9723 --- /dev/null +++ b/ark/hi48-app-ark.png diff --git a/ark/hi64-app-ark.png b/ark/hi64-app-ark.png Binary files differnew file mode 100644 index 0000000..7f3809b --- /dev/null +++ b/ark/hi64-app-ark.png diff --git a/ark/hisc-app-ark.svgz b/ark/hisc-app-ark.svgz Binary files differnew file mode 100644 index 0000000..ec03594 --- /dev/null +++ b/ark/hisc-app-ark.svgz diff --git a/ark/lha.cpp b/ark/lha.cpp new file mode 100644 index 0000000..f890139 --- /dev/null +++ b/ark/lha.cpp @@ -0,0 +1,302 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ + +#include <config.h> + +// C includes +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/errno.h> +#include <string.h> + +// QT includes +#include <qfile.h> +#include <qdir.h> + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +// ark includes +#include "arkwidget.h" +#include "settings.h" +#include "arch.h" +#include "lha.h" +#include "arkutils.h" +#include "filelistview.h" + +LhaArch::LhaArch( ArkWidget *_gui, const QString & _fileName ) + : Arch( _gui, _fileName ) +{ + m_archiver_program = "lha"; + verifyCompressUtilityIsAvailable( m_archiver_program ); + + m_headerString = "----"; +} + +bool LhaArch::processLine( const QCString &line ) +{ + const char *_line = ( const char * ) line; + char columns[13][80]; + char filename[4096]; + + if ( line.contains( "[generic]" ) ) + { + sscanf( _line, + " %79[]\\[generic] %79[0-9] %79[0-9] %79[0-9.%*] %10[-a-z0-9 ] %3[A-Za-z]%1[ ]%2[0-9 ]%1[ ]%5[ 0-9:]%1[ ]%4095[^\n]", + columns[0], columns[2], columns[3], columns[4], columns[5], + columns[6], columns[10], columns[7], columns[11], columns[8], + columns[9], filename ); + strcpy( columns[1], " " ); + } + else if ( line.contains( "[MS-DOS]" ) ) + { + sscanf( _line, + " %79[]\\[MS-DOS] %79[0-9] %79[0-9] %79[0-9.%*] %10[-a-z0-9 ] %3[A-Za-z]%1[ ]%2[0-9 ]%1[ ]%5[ 0-9:]%1[ ]%4095[^\n]", + columns[0], columns[2], columns[3], columns[4], columns[5], + columns[6], columns[10], columns[7], columns[11], columns[8], + columns[9], filename ); + strcpy( columns[1], " " ); + } + else + { + sscanf( _line, + " %79[-drlwxst] %79[0-9/] %79[0-9] %79[0-9] %79[0-9.%*] %10[-a-z0-9 ] %3[A-Za-z]%1[ ]%2[0-9 ]%1[ ]%5[ 0-9:]%1[ ]%4095[^\n]", + columns[0], columns[1], columns[2], columns[3], + columns[4], columns[5], columns[6], columns[10], columns[7], + columns[11], columns[8], columns[9], filename ); + } + + // make the time stamp sortable + QString massagedTimeStamp = ArkUtils::getTimeStamp( columns[6], columns[7], + columns[8] ); + strlcpy( columns[6], massagedTimeStamp.ascii(), sizeof( columns[6] ) ); + + // see if there was a link in filename + QString file = filename; + QString name, link; + bool bLink = false; + int pos = file.find( " -> " ); + if ( pos != -1 ) + { + bLink = true; + name = file.left(pos); + link = file.right(file.length()-pos-4); + } + else + { + name = file; + } + + QStringList list; + list.append( name ); + + for ( int i = 0; i < 7; i++ ) + { + list.append( QString::fromLocal8Bit( columns[i] ) ); + } + + if ( bLink ) + list.append( link ); + else + list.append( "" ); + + m_gui->fileList()->addItem( list ); // send to GUI + + return true; +} + +void LhaArch::open() +{ + setHeaders(); + + m_buffer = ""; + m_header_removed = false; + m_finished = false; + + + KProcess *kp = m_currentProcess = new KProcess; + *kp << m_archiver_program << "v" << m_filename; + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedTOC(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotOpenExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigOpen( this, false, QString::null, 0 ); + } +} + +void LhaArch::setHeaders() +{ + ColumnList list; + list.append( FILENAME_COLUMN); + list.append( PERMISSION_COLUMN); + list.append( OWNER_GROUP_COLUMN); + list.append( PACKED_COLUMN); + list.append( SIZE_COLUMN); + list.append( RATIO_COLUMN); + list.append( CRC_COLUMN); + list.append( TIMESTAMP_COLUMN); + list.append( LINK_COLUMN); + emit headers( list ); +} + + +void LhaArch::create() +{ + emit sigCreate( this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add | Arch::View ); +} + +void LhaArch::addDir( const QString & dirName ) +{ + if ( !dirName.isEmpty() ) + { + QStringList list; + list.append( dirName ); + addFile( list ); + } +} + +void LhaArch::addFile( const QStringList &urls ) +{ + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + *kp << m_archiver_program; + + QString strOptions; + if ( ArkSettings::replaceOnlyWithNewer() ) + strOptions = "u"; + else + strOptions = "a"; + + *kp << strOptions << m_filename; + + KURL url( urls.first() ); + QDir::setCurrent( url.directory() ); + + QStringList::ConstIterator iter; + for ( iter = urls.begin(); iter != urls.end(); ++iter ) + { + KURL fileURL( *iter ); + *kp << fileURL.fileName(); + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotAddExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigAdd( false ); + } +} + +void LhaArch::unarchFileInternal() +{ + // if _fileList is empty, we extract all. + // if _destDir is empty, abort with error. + + if ( m_destDir.isEmpty() || m_destDir.isNull() ) + { + kdError( 1601 ) << "There was no extract directory given." << endl; + return; + } + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program << "xfw=" + m_destDir << m_filename; + + // if the list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if ( m_fileList ) + { + QStringList::Iterator it; + for ( it = m_fileList->begin(); it != m_fileList->end(); ++it ) + { + *kp << ( *it ); + } + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotExtractExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigExtract( false ); + } +} + +void LhaArch::remove( QStringList *list ) +{ + if ( !list ) + return; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program << "df" << m_filename; + + QStringList::Iterator it; + for ( it = list->begin(); it != list->end(); ++it ) + { + *kp << ( *it ); + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotDeleteExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigDelete( false ); + } +} + +#include "lha.moc" diff --git a/ark/lha.h b/ark/lha.h new file mode 100644 index 0000000..98041fb --- /dev/null +++ b/ark/lha.h @@ -0,0 +1,61 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ +#ifndef LHA_H +#define LHA_H + +#include "arch.h" + +class QString; +class QCString; +class QStringList; + +class ArkWidget; + +class LhaArch : public Arch +{ + Q_OBJECT + public: + LhaArch( ArkWidget *, const QString & ); + virtual ~LhaArch() { } + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir( const QString & ); + + virtual void remove( QStringList * ); + virtual void unarchFileInternal(); + + protected slots: + virtual bool processLine( const QCString &line ); + + private: + void setHeaders(); +}; + +#endif // LHA_H diff --git a/ark/main.cpp b/ark/main.cpp new file mode 100644 index 0000000..a2156b4 --- /dev/null +++ b/ark/main.cpp @@ -0,0 +1,128 @@ +/* + +ark: A program for modifying archives via a GUI. + +Copyright (C) +2002-2003: Helio Chissini de Castro <helio@conectiva.com.br> +2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> +2001: Roberto Selbach Teixeira <maragato@kde.org> +1999-2000: Corel Corporation (author: Emily Ezust emilye@corel.com) +1999 Francois-Xavier Duranceau <duranceau@kde.org> +1997-1999 Robert 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. + +*/ + +// +// Note: This is a KUniqueApplication. +// To debug add --nofork to the command line. +// Be aware that newInstance() will not be called in this case, but you +// can run ark from a console, and that will invoke it in the debugger. +// + +// C includes +#include <stdlib.h> + +// KDE includes +#include <kdebug.h> +#include <dcopclient.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kdelibs_export.h> +// ark includes +#include "arkapp.h" + +static KCmdLineOptions option[] = +{ + { "extract", I18N_NOOP( "Open extract dialog, quit when finished" ), 0 }, + { "extract-to", I18N_NOOP( "Extract 'archive' to 'folder'. Quit when finished.\n" + "'folder' will be created if it does not exist."), 0 }, + { "add", I18N_NOOP( "Ask for the name of the archive to add 'files' to. Quit when finished." ), 0 }, + { "add-to", I18N_NOOP( "Add 'files' to 'archive'. Quit when finished.\n'archive' " + "will be created if it does not exist." ), 0 }, + { "guess-name", I18N_NOOP( "Used with '--extract-to'. When specified, 'archive'\n" + "will be extracted to a subfolder of 'folder'\n" + "whose name will be the name of 'archive' without the filename extension."), 0 }, + { "+[folder]", I18N_NOOP( "Folder to extract to" ), 0 }, + { "+[files]", I18N_NOOP( "Files to be added" ), 0 }, + { "+[archive]", I18N_NOOP( "Open 'archive'" ), 0 }, + KCmdLineLastOption +}; + +extern "C" KDE_EXPORT int kdemain( int argc, char *argv[] ) +{ + KAboutData aboutData( "ark", I18N_NOOP( "Ark" ), + "2.6.4", I18N_NOOP( "KDE Archiving tool" ), + KAboutData::License_GPL, + I18N_NOOP( "(c) 1997-2006, The Various Ark Developers" ) + ); + + aboutData.addAuthor( "Henrique Pinto", + I18N_NOOP( "Maintainer" ), + "henrique.pinto@kdemail.net" ); + aboutData.addAuthor( "Charis Kouzinopoulos", + 0, + "kouzinopoulos@gmail.com" ); + aboutData.addAuthor( "Helio Chissini de Castro", + I18N_NOOP( "Former maintainer" ), + "helio@kde.org" ); + aboutData.addAuthor( "Georg Robbers", + 0, + "Georg.Robbers@urz.uni-hd.de" ); + aboutData.addAuthor( "Roberto Selbach Teixeira", + 0, + "maragato@kde.org" ); + aboutData.addAuthor( "Francois-Xavier Duranceau", + 0, + "duranceau@kde.org" ); + aboutData.addAuthor( "Emily Ezust (Corel Corporation)", + 0, + "emilye@corel.com" ); + aboutData.addAuthor( "Michael Jarrett (Corel Corporation)", + 0, + "michaelj@corel.com" ); + aboutData.addAuthor( "Robert Palmbos", + 0, + "palm9744@kettering.edu" ); + + aboutData.addCredit( "Bryce Corkins", + I18N_NOOP( "Icons" ), + "dbryce@attglobal.net" ); + aboutData.addCredit( "Liam Smit", + I18N_NOOP( "Ideas, help with the icons" ), + "smitty@absamail.co.za" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( option ); + KCmdLineArgs::addTempFileOption(); + + if ( !ArkApplication::start() ) + { + // Already running! + kdDebug( 1601 ) << "Already running" << endl; + exit( 0 ); + } + + if ( ArkApplication::getInstance()->isRestored() ) + { + kdDebug( 1601 ) << "In main: Restore..." << endl; + RESTORE( MainWindow ); + } + + return ArkApplication::getInstance()->exec(); +} + +// kate: space-indent off; tab-width 4; diff --git a/ark/mainwindow.cpp b/ark/mainwindow.cpp new file mode 100644 index 0000000..b62422c --- /dev/null +++ b/ark/mainwindow.cpp @@ -0,0 +1,481 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) 2002-2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + Copyright (C) 2003: Helio Chissini de Castro <helio@conectiva.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. + + 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. + +*/ + +// QT includes +#include <qlayout.h> + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kedittoolbar.h> +#include <kstatusbar.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> +#include <kparts/componentfactory.h> +#include <kparts/browserextension.h> +#include <kkeydialog.h> +#include <kcombobox.h> +#include <kio/netaccess.h> +#include <kaccel.h> + +// ark includes +#include "arkapp.h" +#include "settings.h" +#include "archiveformatinfo.h" +#include "arkwidget.h" + +MainWindow::MainWindow( QWidget * /*parent*/, const char *name ) + : KParts::MainWindow(), progressDialog( 0 ) +{ + setXMLFile( "arkui.rc" ); + m_part = KParts::ComponentFactory::createPartInstanceFromLibrary<KParts::ReadWritePart>( "libarkpart", this, name, this, "ArkPart"); + if (m_part ) + { + //Since most of the functionality is still in ArkWidget: + m_widget = static_cast< ArkWidget* >( m_part->widget() ); + + setStandardToolBarMenuEnabled( true ); + setupActions(); + + connect( m_part->widget(), SIGNAL( request_file_quit() ), this, SLOT( file_quit() ) ); + connect( KParts::BrowserExtension::childObject( m_part ), SIGNAL( openURLRequestDelayed + ( const KURL &, const KParts::URLArgs & ) ), + m_part, SLOT( openURL( const KURL & ) ) ); + + m_widget->setArchivePopupEnabled( true ); + connect( m_part->widget(), SIGNAL( signalArchivePopup( const QPoint & ) ), this, + SLOT( slotArchivePopup( const QPoint & ) ) ); + + connect( m_part, SIGNAL( removeRecentURL( const KURL & ) ), this, + SLOT( slotRemoveRecentURL( const KURL & ) ) ); + connect( m_part, SIGNAL( addRecentURL( const KURL & ) ), this, + SLOT( slotAddRecentURL( const KURL & ) ) ); + connect( m_part, SIGNAL( fixActionState( const bool & ) ), this, + SLOT( slotFixActionState( const bool & ) ) ); + connect( m_widget, SIGNAL( disableAllActions() ), this, + SLOT( slotDisableActions() ) ); + + ArkApplication::getInstance()->addWindow(); + connect( m_widget, SIGNAL( removeOpenArk( const KURL &) ), this, + SLOT( slotRemoveOpenArk( const KURL & ) ) ); + connect( m_widget, SIGNAL( addOpenArk( const KURL & ) ), this, + SLOT( slotAddOpenArk( const KURL & ) ) ); + + setCentralWidget( m_part->widget() ); + createGUI( m_part ); + + if ( !initialGeometrySet() ) + { + resize( 640, 300 ); + } + setAutoSaveSettings( "MainWindow" ); + } + else + kdFatal( 1601 ) << "libark could not found. Aborting. " << endl; + +} + + + +MainWindow::~MainWindow() +{ + ArkApplication::getInstance()->removeWindow(); + delete m_part; + delete progressDialog; + progressDialog = 0; +} + +void +MainWindow::setupActions() +{ + newWindowAction = new KAction(i18n("New &Window"), "window_new", KShortcut(), this, + SLOT(file_newWindow()), actionCollection(), "new_window"); + + newArchAction = KStdAction::openNew(this, SLOT(file_new()), actionCollection()); + openAction = KStdAction::open(this, SLOT(file_open()), actionCollection()); + + reloadAction = new KAction(i18n("Re&load"), "reload", KStdAccel::shortcut( KStdAccel::Reload ), this, + SLOT(file_reload()), actionCollection(), "reload_arch"); + closeAction = KStdAction::close(this, SLOT(file_close()), actionCollection(), "file_close"); + + recent = KStdAction::openRecent(this, SLOT(openURL(const KURL&)), actionCollection()); + recent->loadEntries(kapp->config()); + + createStandardStatusBarAction(); + + KStdAction::quit(this, SLOT(window_close()), actionCollection()); + KStdAction::configureToolbars(this, SLOT(editToolbars()), actionCollection()); + KStdAction::keyBindings(this, SLOT( slotConfigureKeyBindings()), actionCollection()); + + openAction->setEnabled( true ); + recent->setEnabled( true ); + closeAction->setEnabled( false ); + reloadAction->setEnabled( false ); +} + +void +MainWindow::slotDisableActions() +{ + openAction->setEnabled(false); + newArchAction->setEnabled(false); + closeAction->setEnabled(false); + reloadAction->setEnabled(false); +} + +void +MainWindow::slotFixActionState( const bool & bHaveFiles ) +{ + openAction->setEnabled(true); + newArchAction->setEnabled(true); + closeAction->setEnabled(bHaveFiles); + reloadAction->setEnabled(bHaveFiles); +} + +void +MainWindow::file_newWindow() +{ + MainWindow *kw = new MainWindow; + kw->resize( 640, 300 ); + kw->show(); +} + +void +MainWindow::file_new() +{ + m_widget->file_new(); +} + +void +MainWindow::file_reload() +{ + KURL url( m_part->url() ); + file_close(); + m_part->openURL( url ); +} + +void +MainWindow::editToolbars() +{ + saveMainWindowSettings( KGlobal::config(), QString::fromLatin1("MainWindow") ); + KEditToolbar dlg( factory(), this ); + connect(&dlg, SIGNAL( newToolbarConfig() ), this, SLOT( slotNewToolbarConfig() )); + dlg.exec(); +} + +void +MainWindow::slotNewToolbarConfig() +{ + createGUI( m_part ); + applyMainWindowSettings( KGlobal::config(), QString::fromLatin1("MainWindow") ); +} + +void +MainWindow::slotConfigureKeyBindings() +{ + KKeyDialog dlg( true, this ); + + dlg.insert( actionCollection() ); + dlg.insert( m_part->actionCollection() ); + + dlg.configure(); +} + +void +MainWindow::slotArchivePopup( const QPoint &pPoint) +{ + static_cast<KPopupMenu *>(factory()->container("archive_popup", this))->popup(pPoint); +} + +// see if the ark is already open in another window +bool +MainWindow::arkAlreadyOpen( const KURL & url ) +{ + if (ArkApplication::getInstance()->isArkOpenAlready(url)) + { + if ( m_part->url() == url ) return true; + // raise the window containing the already open archive + ArkApplication::getInstance()->raiseArk(url); + + // close this window + window_close(); + + // notify the user what's going on + KMessageBox::information(0, i18n("The archive %1 is already open and has been raised.\nNote: if the filename does not match, it only means that one of the two is a symbolic link.").arg(url.prettyURL())); + return true; + } + return false; +} + + +void +MainWindow::openURL( const KURL & url, bool tempFile ) +{ + if( !arkAlreadyOpen( url ) ) + { + if ( tempFile && url.isLocalFile() ) + m_widget->deleteAfterUse( url.path() ); + m_part->openURL( url ); + } +} + +KURL +MainWindow::getOpenURL( bool addOnly, const QString & caption, + const QString & startDir, const QString & suggestedName ) +{ + kdDebug( 1601 ) << "startDir is: " << startDir << endl; + QWidget * forceFormatWidget = new QWidget( this ); + QHBoxLayout * l = new QHBoxLayout( forceFormatWidget ); + + QLabel * label = new QLabel( forceFormatWidget ); + label->setText( i18n( "Open &as:" ) ); + label->adjustSize(); + + KComboBox * combo = new KComboBox( forceFormatWidget ); + + QStringList list; + list = ArchiveFormatInfo::self()->allDescriptions(); + list.sort(); + list.prepend( i18n( "Autodetect (default)" ) ); + combo->insertStringList( list ); + + QString filter = ArchiveFormatInfo::self()->filter(); + if ( !suggestedName.isEmpty() ) + { + filter = QString::null; + combo->setCurrentItem( list.findIndex( ArchiveFormatInfo::self()->descriptionForMimeType( + KMimeType::findByPath( suggestedName, 0, true )->name() ) ) ); + } + + label->setBuddy( combo ); + + l->addWidget( label ); + l->addWidget( combo, 1 ); + + QString dir; + if ( addOnly ) + dir = startDir; + else + dir = ":ArkOpenDir"; + + KFileDialog dlg( dir, filter, this, "filedialog", true, forceFormatWidget ); + dlg.setOperationMode( addOnly ? KFileDialog::Saving + : KFileDialog::Opening ); + + dlg.setCaption( addOnly ? caption : i18n("Open") ); + dlg.setMode( addOnly ? ( KFile::File | KFile::ExistingOnly ) + : KFile::File ); + dlg.setSelection( suggestedName ); + + dlg.exec(); + + KURL url; + url = dlg.selectedURL(); + + if ( combo->currentItem() !=0 ) // i.e. != "Autodetect" + m_widget->setOpenAsMimeType( + ArchiveFormatInfo::self()->mimeTypeForDescription( combo->currentText() ) ); + else + m_widget->setOpenAsMimeType( QString::null ); + + return url; +} + +void +MainWindow::file_open() +{ + KURL url = getOpenURL(); + if( !arkAlreadyOpen( url ) ) + m_part->openURL( url ); +} + +void +MainWindow::file_close() +{ + m_part->closeURL(); +} + +void +MainWindow::window_close() +{ + file_close(); + slotSaveProperties(); + //kdDebug(1601) << "-ArkWidget::window_close" << endl; + close(); +} + +bool +MainWindow::queryClose() +{ + window_close(); + return true; +} + +void +MainWindow::file_quit() +{ + window_close(); +} + +void +MainWindow::slotSaveProperties() +{ + recent->saveEntries(kapp->config()); +} + +void +MainWindow::saveProperties( KConfig* config ) +{ + //TODO: make it work for URLS + config->writePathEntry( "SMOpenedFile",m_widget->getArchName() ); + config->sync(); +} + + +void +MainWindow::readProperties( KConfig* config ) +{ + QString file = config->readPathEntry("SMOpenedFile"); + kdDebug(1601) << "ArkWidget::readProperties( KConfig* config ) file=" << file << endl; + if ( !file.isEmpty() ) + openURL( KURL::fromPathOrURL( file ) ); +} + +void +MainWindow::slotAddRecentURL( const KURL & url ) +{ + recent->addURL( url ); + recent->saveEntries(kapp->config()); +} + +void +MainWindow::slotRemoveRecentURL( const KURL & url ) +{ + recent->removeURL( url ); + recent->saveEntries(kapp->config()); +} + +void +MainWindow::slotAddOpenArk( const KURL & _arkname ) +{ + ArkApplication::getInstance()->addOpenArk( _arkname, this ); +} + +void +MainWindow::slotRemoveOpenArk( const KURL & _arkname ) +{ + ArkApplication::getInstance()->removeOpenArk( _arkname ); +} + +void +MainWindow::setExtractOnly ( bool b ) +{ + m_widget->setExtractOnly( b ); +} + +void +MainWindow::extractTo( const KURL & targetDirectory, const KURL & archive, bool guessName ) +{ + startProgressDialog( i18n( "Extracting..." ) ); + m_widget->extractTo( targetDirectory, archive, guessName ); + m_part->openURL( archive ); +} + +void +MainWindow::addToArchive( const KURL::List & filesToAdd, const QString & /*cwd*/, + const KURL & archive, bool askForName ) +{ + KURL archiveFile; + if ( askForName || archive.isEmpty() ) + { + // user definded actions in servicemus are being started by konq + // from konqis working directory, not from the one being shown when + // the popupmenu was requested; work around that so the user + // sees a list of the archives in the diretory he is looking at. + // makes it show the 'wrong' dir when being called from the commandline + // like: /dira> ark -add /dirb/file, but well... + KURL cwdURL; + cwdURL.setPath( filesToAdd.first().path() ); + QString dir = cwdURL.directory( false ); + + archiveFile = getOpenURL( true, i18n( "Select Archive to Add Files To" ), + dir /*cwd*/, archive.fileName() ); + } + else + archiveFile = archive; + + if ( archiveFile.isEmpty() ) + { + kdDebug( 1601 ) << "no archive selected." << endl; + file_quit(); + return; + } + + startProgressDialog( i18n( "Compressing..." ) ); + + bool exists = KIO::NetAccess::exists( archiveFile, false, m_widget ); + kdDebug( 1601 ) << archiveFile << endl; + + if ( !m_widget->addToArchive( filesToAdd, archiveFile ) ) + file_quit(); + if ( exists ) + m_part->openURL( archiveFile ); +} + +void +MainWindow::startProgressDialog( const QString & text ) +{ + if ( !progressDialog ) + progressDialog = new KProgressDialog( this, "progress_dialog", QString::null, text, false ); + else + progressDialog->setLabel( text ); + +// progressDialog->setWFlags( Qt::WType_TopLevel ); + + progressDialog->setAllowCancel( true ); + progressDialog->setPlainCaption( i18n( "Please Wait" ) ); + + progressDialog->progressBar()->setTotalSteps( 0 ); + progressDialog->progressBar()->setPercentageVisible( false ); + +// progressDialog->setInitialSize( QSize(200,100), true ); + progressDialog->setMinimumDuration( 500 ); + progressDialog->show(); + KDialog::centerOnScreen( progressDialog ); + connect( progressDialog, SIGNAL( cancelClicked() ), this, SLOT( window_close() ) ); + + timer = new QTimer( this ); + connect( timer, SIGNAL( timeout() ), this, SLOT( slotProgress() ) ); + + timer->start( 200, false ); +} + +void +MainWindow::slotProgress() +{ + progressDialog->progressBar()->setProgress( progressDialog->progressBar()->progress() + 4 ); +} + + +#include "mainwindow.moc" + diff --git a/ark/mainwindow.h b/ark/mainwindow.h new file mode 100644 index 0000000..2d25ed0 --- /dev/null +++ b/ark/mainwindow.h @@ -0,0 +1,112 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) 2002-2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + Copyright (C) 2003: Helio Chissini de Castro <helio@conectiva.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. + + 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. + +*/ + +#ifndef ARKMAINWINDOW_H +#define ARKMAINWINDOW_H + +// QT includes +#include <qstring.h> +#include <qpopupmenu.h> +#include <qtimer.h> + +// KDE includes +#include <kmainwindow.h> +#include <kparts/mainwindow.h> +#include <kparts/part.h> +#include <kprogress.h> + +class ArkWidget; + +class +MainWindow: public KParts::MainWindow +{ + Q_OBJECT +public: + MainWindow( QWidget *parent=0, const char *name=0 ); + virtual ~MainWindow(); + + void setExtractOnly ( bool b ); + void extractTo( const KURL & targetDirectory, const KURL & archive, bool guessName ); + void addToArchive( const KURL::List & filesToAdd, const QString & cwd = QString::null, + const KURL & archive = KURL(), bool askForName = false ); + +public slots: + void file_newWindow(); + void file_new(); + void openURL( const KURL & url, bool tempFile = false ); + void file_open(); + void file_reload(); + void editToolbars(); + void window_close(); + void file_quit(); + void file_close(); + void slotNewToolbarConfig(); + void slotConfigureKeyBindings(); + virtual void saveProperties( KConfig* config ); + virtual void readProperties( KConfig* config ); + void slotSaveProperties(); + void slotArchivePopup( const QPoint &pPoint); + void slotRemoveRecentURL( const KURL &url ); + void slotAddRecentURL( const KURL &url ); + void slotFixActionState( const bool & bHaveFiles ); + void slotDisableActions(); + void slotAddOpenArk( const KURL & _arkname ); + void slotRemoveOpenArk( const KURL & _arkname ); + +protected: + virtual bool queryClose(); // SM + +private: // methods + // disabling/enabling of buttons and menu items + void setupActions(); + void setupMenuBar(); + + void newCaption(const QString & filename); + bool arkAlreadyOpen( const KURL & url ); + + KURL getOpenURL( bool addOnly = false , const QString & caption = QString::null, + const QString & startDir = QString::null, + const QString & suggestedName = QString::null ); + + void startProgressDialog( const QString & text ); + +private slots: + void slotProgress(); + +private: // data + KParts::ReadWritePart *m_part; + ArkWidget *m_widget; //the parts widget + + KAction *newWindowAction; + KAction *newArchAction; + KAction *openAction; + KAction *closeAction; + KAction *reloadAction; + KRecentFilesAction *recent; + + //progress dialog for konqs service menus / commmand line + KProgressDialog *progressDialog; + QTimer *timer; +}; + +#endif /* ARKMAINWINDOW_H*/ diff --git a/ark/pics/Makefile.am b/ark/pics/Makefile.am new file mode 100644 index 0000000..fc447c5 --- /dev/null +++ b/ark/pics/Makefile.am @@ -0,0 +1,2 @@ +icondir = $(kde_datadir)/ark/icons +icon_ICON = AUTO diff --git a/ark/pics/cr22-action-ark_adddir.png b/ark/pics/cr22-action-ark_adddir.png Binary files differnew file mode 100644 index 0000000..e92bd63 --- /dev/null +++ b/ark/pics/cr22-action-ark_adddir.png diff --git a/ark/pics/cr22-action-ark_addfile.png b/ark/pics/cr22-action-ark_addfile.png Binary files differnew file mode 100644 index 0000000..8108fff --- /dev/null +++ b/ark/pics/cr22-action-ark_addfile.png diff --git a/ark/pics/cr22-action-ark_delete.png b/ark/pics/cr22-action-ark_delete.png Binary files differnew file mode 100644 index 0000000..4d60b28 --- /dev/null +++ b/ark/pics/cr22-action-ark_delete.png diff --git a/ark/pics/cr22-action-ark_extract.png b/ark/pics/cr22-action-ark_extract.png Binary files differnew file mode 100644 index 0000000..d82746d --- /dev/null +++ b/ark/pics/cr22-action-ark_extract.png diff --git a/ark/pics/cr22-action-ark_selectall.png b/ark/pics/cr22-action-ark_selectall.png Binary files differnew file mode 100644 index 0000000..677b116 --- /dev/null +++ b/ark/pics/cr22-action-ark_selectall.png diff --git a/ark/pics/cr22-action-ark_view.png b/ark/pics/cr22-action-ark_view.png Binary files differnew file mode 100644 index 0000000..77d8470 --- /dev/null +++ b/ark/pics/cr22-action-ark_view.png diff --git a/ark/pics/cr32-action-ark_adddir.png b/ark/pics/cr32-action-ark_adddir.png Binary files differnew file mode 100644 index 0000000..022438d --- /dev/null +++ b/ark/pics/cr32-action-ark_adddir.png diff --git a/ark/pics/cr32-action-ark_addfile.png b/ark/pics/cr32-action-ark_addfile.png Binary files differnew file mode 100644 index 0000000..a447f8c --- /dev/null +++ b/ark/pics/cr32-action-ark_addfile.png diff --git a/ark/pics/cr32-action-ark_delete.png b/ark/pics/cr32-action-ark_delete.png Binary files differnew file mode 100644 index 0000000..7b9e6fe --- /dev/null +++ b/ark/pics/cr32-action-ark_delete.png diff --git a/ark/pics/cr32-action-ark_extract.png b/ark/pics/cr32-action-ark_extract.png Binary files differnew file mode 100644 index 0000000..38913ec --- /dev/null +++ b/ark/pics/cr32-action-ark_extract.png diff --git a/ark/pics/cr32-action-ark_view.png b/ark/pics/cr32-action-ark_view.png Binary files differnew file mode 100644 index 0000000..f1bd613 --- /dev/null +++ b/ark/pics/cr32-action-ark_view.png diff --git a/ark/rar.cpp b/ark/rar.cpp new file mode 100644 index 0000000..592ffe2 --- /dev/null +++ b/ark/rar.cpp @@ -0,0 +1,306 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2003: Helio Chissini de Castro <helio@conectiva.com> + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.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. + + 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. + +*/ + +// Std includes +#include <sys/errno.h> +#include <unistd.h> +#include <iostream> +#include <string> + +// QT includes +#include <qfile.h> +#include <qdir.h> + +// KDE includes +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kstandarddirs.h> + +// ark includes +#include <config.h> +#include "arkwidget.h" +#include "arch.h" +#include "settings.h" +#include "rar.h" +#include "arkutils.h" +#include "filelistview.h" + +RarArch::RarArch( ArkWidget *_gui, const QString & _fileName ) + : Arch( _gui, _fileName ) +{ + // Check if rar is available + bool have_rar = !KGlobal::dirs()->findExe( "rar" ).isNull(); + + if ( have_rar ) + { + // If it is, then use it as archiver and unarchiver + m_archiver_program = m_unarchiver_program = "rar"; + verifyCompressUtilityIsAvailable( m_archiver_program ); + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + } + else + { + // If rar is not available, try to use unrar to open the archive read-only + m_unarchiver_program = "unrar"; + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + setReadOnly( true ); + } + + + + m_headerString = "-------------------------------------------------------------------------------"; + + m_isFirstLine = true; +} + +bool RarArch::processLine( const QCString &line ) +{ + if ( m_isFirstLine ) + { + m_entryFilename = QString::fromLocal8Bit( line ); + m_entryFilename.remove( 0, 1 ); + m_isFirstLine = false; + return true; + } + + QStringList list; + + QStringList l2 = QStringList::split( ' ', line ); + + list << m_entryFilename; // filename + list << l2[ 0 ]; // size + list << l2[ 1 ]; // packed + list << l2[ 2 ]; // ratio + + QStringList date = QStringList::split( '-', l2[ 3 ] ); + list << ArkUtils::fixYear( date[ 2 ].latin1() ) + '-' + date[ 1 ] + '-' + date [ 0 ] + ' ' + l2[4]; // date + list << l2[ 5 ]; // attributes + list << l2[ 6 ]; // crc + list << l2[ 7 ]; // method + list << l2[ 8 ]; // Version + + m_gui->fileList()->addItem( list ); // send to GUI + + m_isFirstLine = true; + return true; +} + +void RarArch::open() +{ + setHeaders(); + + m_buffer = ""; + m_header_removed = false; + m_finished = false; + + KProcess *kp = m_currentProcess = new KProcess; + *kp << m_unarchiver_program << "v" << "-c-" << m_filename; + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedTOC(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotOpenExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigOpen( this, false, QString::null, 0 ); + } +} + +void RarArch::setHeaders() +{ + ColumnList list; + list.append( FILENAME_COLUMN ); + list.append( SIZE_COLUMN ); + list.append( PACKED_COLUMN ); + list.append( RATIO_COLUMN ); + list.append( TIMESTAMP_COLUMN ); + list.append( PERMISSION_COLUMN ); + list.append( CRC_COLUMN ); + list.append( METHOD_COLUMN ); + list.append( VERSION_COLUMN ); + + emit headers( list ); +} + +void RarArch::create() +{ + emit sigCreate( this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add | Arch::View ); +} + +void RarArch::addDir( const QString & _dirName ) +{ + if ( !_dirName.isEmpty() ) + { + QStringList list; + list.append( _dirName ); + addFile( list ); + } +} + +void RarArch::addFile( const QStringList & urls ) +{ + KProcess *kp = m_currentProcess = new KProcess; + + kp->clearArguments(); + *kp << m_archiver_program; + + if ( ArkSettings::replaceOnlyWithNewer() ) + *kp << "u"; + else + *kp << "a"; + + if ( ArkSettings::rarStoreSymlinks() ) + *kp << "-ol"; + if ( ArkSettings::rarRecurseSubdirs() ) + *kp << "-r"; + + *kp << m_filename; + + KURL dir( urls.first() ); + QDir::setCurrent( dir.directory() ); + + QStringList::ConstIterator iter; + for ( iter = urls.begin(); iter != urls.end(); ++iter ) + { + KURL url( *iter ); + *kp << url.fileName(); + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotAddExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigAdd( false ); + } +} + +void RarArch::unarchFileInternal() +{ + if ( m_destDir.isEmpty() || m_destDir.isNull() ) + { + kdError( 1601 ) << "There was no extract directory given." << endl; + return; + } + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + // extract (and maybe overwrite) + *kp << m_unarchiver_program << "x"; + + if ( !m_password.isEmpty() ) + *kp << "-p" + m_password; + else + *kp << "-p-"; + + if ( !ArkSettings::extractOverwrite() ) + { + *kp << "-o+"; + } + else + { + *kp << "-o-"; + } + + *kp << m_filename; + + // if the file list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if ( m_fileList ) + { + QStringList::Iterator it; + for ( it = m_fileList->begin(); it != m_fileList->end(); ++it ) + { + *kp << (*it); + } + } + + *kp << m_destDir ; + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotExtractExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigExtract( false ); + } +} + +bool RarArch::passwordRequired() +{ + return m_lastShellOutput.findRev("password incorrect ?)")+1; +} + +void RarArch::remove( QStringList *list ) +{ + if ( !list ) + return; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program << "d" << m_filename; + + QStringList::Iterator it; + for ( it = list->begin(); it != list->end(); ++it ) + { + QString str = *it; + *kp << str; + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotDeleteExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigDelete( false ); + } +} + +#include "rar.moc" diff --git a/ark/rar.h b/ark/rar.h new file mode 100644 index 0000000..d8a4ab4 --- /dev/null +++ b/ark/rar.h @@ -0,0 +1,68 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.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. + + 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. + +*/ +#ifndef RAR_H +#define RAR_H + +#include "arch.h" + +class QString; +class QCString; +class QStringList; + +class ArkWidget; + +class RarArch : public Arch +{ + Q_OBJECT + public: + RarArch( ArkWidget *_gui, const QString & _fileName ); + virtual ~RarArch() {} + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir( const QString & ); + + virtual void remove( QStringList * ); + virtual void unarchFileInternal(); + virtual bool passwordRequired(); + + protected slots: + virtual bool processLine( const QCString & ); + + private: + void setHeaders(); + + /* + * The output of the rar command uses more than one + * line for each entry, the first containing the filename + * for the entry, the second containing additional information. + * Therefore, the variables below are needed. + */ + bool m_isFirstLine; + QString m_entryFilename; +}; + +#endif // RAR_H diff --git a/ark/searchbar.cpp b/ark/searchbar.cpp new file mode 100644 index 0000000..015a3bf --- /dev/null +++ b/ark/searchbar.cpp @@ -0,0 +1,49 @@ +/* + * ark: A program for modifying archives via a GUI. + * + * Copyright (C) 2004, Henrique Pinto <henrique.pinto@kdemail.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. + * + * 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. + * + */ + +#include "searchbar.h" + +#include <klistviewsearchline.h> +#include <klistview.h> +#include <kcombobox.h> +#include <klocale.h> +#include <kaction.h> +#include <kactioncollection.h> + +#include <qlabel.h> +#include <qapplication.h> +#include <qvaluelist.h> + +SearchBar::SearchBar( QWidget* parent, KActionCollection* aC, const char * name ) + : KListViewSearchLine( parent, 0, name ) +{ + KAction *resetSearch = new KAction( i18n( "Reset Search" ), QApplication::reverseLayout() ? "clear_left" : "locationbar_erase", 0, this, SLOT( clear() ), aC, "reset_search" ); + + resetSearch->plug( parent ); + resetSearch->setWhatsThis( i18n( "Reset Search\n" + "Resets the search bar, so that all archive entries are shown again." ) ); +} + +SearchBar::~SearchBar() +{ +} + +#include "searchbar.moc" diff --git a/ark/searchbar.h b/ark/searchbar.h new file mode 100644 index 0000000..95857ae --- /dev/null +++ b/ark/searchbar.h @@ -0,0 +1,40 @@ +#ifndef SEARCHBAR_H +#define SEARCHBAR_H +/* + * ark: A program for modifying archives via a GUI. + * + * Copyright (C) 2004, Henrique Pinto <henrique.pinto@kdemail.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. + * + * 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. + * + */ + +#include <klistviewsearchline.h> + +#include <qwidget.h> + +class KListView; +class KComboBox; +class KActionCollection; + +class SearchBar: public KListViewSearchLine +{ + Q_OBJECT + public: + SearchBar( QWidget* parent, KActionCollection* aC, const char * name = 0 ); + ~SearchBar(); +}; + +#endif // SEARCHBAR_H diff --git a/ark/settings.kcfgc b/ark/settings.kcfgc new file mode 100644 index 0000000..a8bc919 --- /dev/null +++ b/ark/settings.kcfgc @@ -0,0 +1,5 @@ +File=ark.kcfg +ClassName=ArkSettings +Singleton=true +Mutators=true +SetUserTexts=true diff --git a/ark/sevenzip.cpp b/ark/sevenzip.cpp new file mode 100644 index 0000000..30747a3 --- /dev/null +++ b/ark/sevenzip.cpp @@ -0,0 +1,367 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2004: Henrique Pinto <henrique.pinto@kdemail.net> + 2003: Helio Chissini de Castro <helio@conectiva.com> + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.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. + + 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. + +*/ + +#include <qdir.h> + +#include <kglobal.h> +#include <klocale.h> +#include <kdebug.h> +#include <kurl.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kstandarddirs.h> + +#include "sevenzip.h" +#include "arkwidget.h" +#include "settings.h" +#include "arkutils.h" +#include "filelistview.h" + +SevenZipArch::SevenZipArch( ArkWidget *gui, const QString &filename ) + : Arch( gui, filename ), m_nameColumnPos( -1 ) +{ + // Check if 7z is available + bool have_7z = !KGlobal::dirs()->findExe( "7z" ).isNull(); + // Check if 7za is available + bool have_7za = !KGlobal::dirs()->findExe( "7za" ).isNull(); + + if ( have_7z ) + m_archiver_program = m_unarchiver_program = "7z"; // Use 7z + else if ( have_7za ) + m_archiver_program = m_unarchiver_program = "7za"; // Try 7za + else + m_archiver_program = m_unarchiver_program = "7zr"; + + verifyCompressUtilityIsAvailable( m_archiver_program ); + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + + m_headerString = "------------------"; + + m_repairYear = 5; m_fixMonth = 6; m_fixDay = 7; m_fixTime = 8; + m_dateCol = 3; + m_numCols = 5; + + m_archCols.append( new ArchColumns( 5, QRegExp( "[0-2][0-9][0-9][0-9]" ), 4 ) ); // Year + m_archCols.append( new ArchColumns( 6, QRegExp( "[01][0-9]" ), 2 ) ); // Month + m_archCols.append( new ArchColumns( 7, QRegExp( "[0-3][0-9]" ), 2 ) ); // Day + m_archCols.append( new ArchColumns( 8, QRegExp( "[0-9:]+" ), 8 ) ); // Time + m_archCols.append( new ArchColumns( 4, QRegExp( "[^\\s]+" ) ) ); // Attributes + m_archCols.append( new ArchColumns( 1, QRegExp( "[0-9]+" ) ) ); // Size + m_archCols.append( new ArchColumns( 2, QRegExp( "[0-9]+" ), 64, true ) ); // Compressed Size +} + +SevenZipArch::~SevenZipArch() +{ +} + +void SevenZipArch::setHeaders() +{ + ColumnList columns; + columns.append( FILENAME_COLUMN ); + columns.append( SIZE_COLUMN ); + columns.append( PACKED_COLUMN ); + columns.append( TIMESTAMP_COLUMN ); + columns.append( PERMISSION_COLUMN ); + + emit headers( columns ); +} + +void SevenZipArch::open() +{ + setHeaders(); + + m_buffer = ""; + m_header_removed = false; + m_finished = false; + + KProcess *kp = m_currentProcess = new KProcess; + *kp << m_archiver_program << "l" << m_filename; + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedTOC(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotOpenExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigOpen( this, false, QString::null, 0 ); + } +} + +void SevenZipArch::create() +{ + emit sigCreate( this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add | Arch::View ); +} + +void SevenZipArch::addFile( const QStringList & urls ) +{ + KProcess *kp = m_currentProcess = new KProcess; + + kp->clearArguments(); + *kp << m_archiver_program << "a" ; + + KURL url( urls.first() ); + QDir::setCurrent( url.directory() ); + + *kp << m_filename; + + QStringList::ConstIterator iter; + for ( iter = urls.begin(); iter != urls.end(); ++iter ) + { + KURL url( *iter ); + *kp << url.fileName(); + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotAddExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigAdd( false ); + } +} + +void SevenZipArch::addDir( const QString & dirName ) +{ + if ( !dirName.isEmpty() ) + { + QStringList list; + list.append( dirName ); + addFile( list ); + } +} + +void SevenZipArch::remove( QStringList *list ) +{ + if ( !list ) + return; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program << "d" << m_filename; + + QStringList::Iterator it; + for ( it = list->begin(); it != list->end(); ++it ) + { + *kp << *it; + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotDeleteExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigDelete( false ); + } +} + +void SevenZipArch::unarchFileInternal( ) +{ + if ( m_destDir.isEmpty() || m_destDir.isNull() ) + { + kdError( 1601 ) << "There was no extract directory given." << endl; + return; + } + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + // extract (and maybe overwrite) + *kp << m_unarchiver_program << "x"; + + if ( ArkSettings::extractOverwrite() ) + { + //*kp << "-ao"; + } + + *kp << m_filename; + + // if the file list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if ( m_fileList ) + { + QStringList::Iterator it; + for ( it = m_fileList->begin(); it != m_fileList->end(); ++it ) + { + *kp << (*it); + } + } + + *kp << "-o" + m_destDir ; + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotExtractExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigExtract( false ); + } +} + +bool SevenZipArch::processLine( const QCString& _line ) +{ + QCString line( _line ); + QString columns[ 11 ]; + unsigned int pos = 0; + int strpos, len; + + columns[ 0 ] = line.right( line.length() - m_nameColumnPos +1); + line.truncate( m_nameColumnPos ); + + // Go through our columns, try to pick out data, return silently on failure + for ( QPtrListIterator <ArchColumns>col( m_archCols ); col.current(); ++col ) + { + ArchColumns *curCol = *col; + + strpos = curCol->pattern.search( 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 ] = line.mid( strpos, len ); + } + + + if ( m_dateCol >= 0 ) + { + QString year = ( m_repairYear >= 0 ) ? + ArkUtils::fixYear( columns[ m_repairYear ].ascii()) + : columns[ m_fixYear ]; + QString month = ( m_repairMonth >= 0 ) ? + QString( "%1" ) + .arg( ArkUtils::getMonth( columns[ m_repairMonth ].ascii() ) ) + : columns[ m_fixMonth ]; + QString timestamp = QString::fromLatin1( "%1-%2-%3 %4" ) + .arg( year ) + .arg( month ) + .arg( columns[ m_fixDay ] ) + .arg( columns[ m_fixTime ] ); + + columns[ m_dateCol ] = timestamp; + } + + QStringList 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 SevenZipArch::slotReceivedTOC( KProcess*, char* data, int length ) +{ + char endchar = data[ length ]; + data[ length ] = '\0'; + + appendShellOutputData( data ); + + int startChar = 0; + + while ( !m_finished ) + { + int lfChar; + 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; + + // Check if the header was found + if ( m_buffer.find( m_headerString ) != -1 ) + { + if ( !m_header_removed ) + { + m_nameColumnPos = m_buffer.findRev( ' ' ) + 1; + m_header_removed = true; + } + else + { + m_finished = true; + } + } + else + { + // If the header was not found, process the line + if ( m_header_removed && !m_finished ) + { + if ( !processLine( m_buffer ) ) + { + m_header_removed = false; + m_error = true; + } + } + } + + m_buffer.resize( 0 ); + } + + if ( !m_finished ) + m_buffer.append( data + startChar); // Append what's left of the buffer + + data[ length ] = endchar; +} + +#include "sevenzip.moc" diff --git a/ark/sevenzip.h b/ark/sevenzip.h new file mode 100644 index 0000000..4a34c48 --- /dev/null +++ b/ark/sevenzip.h @@ -0,0 +1,54 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2004: Henrique Pinto <henrique.pinto@kdemail.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. + + 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. + +*/ +#ifndef SEVENZIP_H +#define SEVENZIP_H + +#include "arch.h" + +class SevenZipArch : public Arch +{ + Q_OBJECT + public: + SevenZipArch( ArkWidget *, const QString & ); + virtual ~SevenZipArch(); + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir( const QString & ); + + virtual void remove( QStringList * ); + virtual void unarchFileInternal( ); + + protected slots: + virtual bool processLine( const QCString& line ); + virtual void slotReceivedTOC( KProcess*, char*, int ); + + private: + void setHeaders(); + int m_nameColumnPos; +}; + +#endif // SEVENZIP_H diff --git a/ark/tar.cpp b/ark/tar.cpp new file mode 100644 index 0000000..5f104ef --- /dev/null +++ b/ark/tar.cpp @@ -0,0 +1,774 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com) + 2001: Roberto Selbach Teixeira <maragato@conectiva.com> + 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> + 2006: Henrique Pinto <henrique.pinto@kdemail.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. + + 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. + +*/ + +// Note: When maintaining tar files with ark, the user should be +// aware that these options have been improved (IMHO). When you append a file +// to a tarchive, tar does not check if the file exists already, and just +// tacks the new one on the end. ark deletes the old one. +// When you update a file that exists in a tarchive, it does check if +// it exists, but once again, it creates a duplicate at the end (only if +// the file is newer though). ark deletes the old one in this case as well. +// +// Basically, tar files are great for creating and extracting, but +// not especially for maintaining. The original purpose of a tar was of +// course, for tape backups, so this is not so surprising! -Emily +// + +// C includes +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +// Qt includes +#include <qdir.h> +#include <qregexp.h> +#include <qeventloop.h> + +// KDE includes +#include <kapplication.h> +#include <kdebug.h> +#include <klargefile.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ktempfile.h> +#include <kmimetype.h> +#include <kstandarddirs.h> +#include <ktempdir.h> +#include <kprocess.h> +#include <ktar.h> + +// ark includes +#include "arkwidget.h" +#include "settings.h" +#include "tar.h" +#include "filelistview.h" +#include "tarlistingthread.h" + +TarArch::TarArch( ArkWidget *_gui, + const QString & _filename, const QString & _openAsMimeType) + : Arch( _gui, _filename), m_tmpDir( 0 ), createTmpInProgress(false), + updateInProgress(false), deleteInProgress(false), fd(0), + m_pTmpProc( 0 ), m_pTmpProc2( 0 ), failed( false ), + m_dotslash( false ), m_listingThread( 0 ) +{ + m_filesToAdd = m_filesToRemove = QStringList(); + m_archiver_program = m_unarchiver_program = ArkSettings::tarExe(); + verifyCompressUtilityIsAvailable( m_archiver_program ); + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + + m_fileMimeType = _openAsMimeType; + if ( m_fileMimeType.isNull() ) + m_fileMimeType = KMimeType::findByPath( _filename )->name(); + + kdDebug(1601) << "TarArch::TarArch: mimetype is " << m_fileMimeType << endl; + + if ( m_fileMimeType == "application/x-tbz2" ) + { + // ark treats .tar.bz2 as x-tbz, instead of duplicating the mimetype + // let's just alias it to the one we already handle. + m_fileMimeType = "application/x-tbz"; + } + + if ( m_fileMimeType == "application/x-tar" ) + { + compressed = false; + } + else + { + compressed = true; + m_tmpDir = new KTempDir( _gui->tmpDir() + + QString::fromLatin1( "temp_tar" ) ); + m_tmpDir->setAutoDelete( true ); + m_tmpDir->qDir()->cd( m_tmpDir->name() ); + // build the temp file name + KTempFile *pTempFile = new KTempFile( m_tmpDir->name(), + QString::fromLatin1(".tar") ); + + tmpfile = pTempFile->name(); + delete pTempFile; + + kdDebug(1601) << "Tmpfile will be " << tmpfile << "\n" << endl; + } +} + +TarArch::~TarArch() +{ + delete m_tmpDir; + m_tmpDir = 0; + + if ( m_listingThread && m_listingThread->finished() != true ) + { + m_listingThread->wait(); + delete m_listingThread; + m_listingThread = 0; + } +} + +int TarArch::getEditFlag() +{ + return Arch::Extract; +} + +void TarArch::updateArch() +{ + if (compressed) + { + updateInProgress = true; + int f_desc = KDE_open(QFile::encodeName(m_filename), O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (f_desc != -1) + fd = fdopen( f_desc, "w" ); + else + fd = NULL; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + KProcess::Communication flag = KProcess::AllOutput; + if ( getCompressor() == "lzop" ) + { + kp->setUsePty( KProcess::Stdin, false ); + flag = KProcess::Stdout; + } + if ( !getCompressor().isNull() ) + *kp << getCompressor() << "-c" << tmpfile; + else + *kp << "cat" << tmpfile; + + + connect(kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(updateProgress( KProcess *, char *, int ))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + (Arch *)this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect(kp, SIGNAL(processExited(KProcess *)), + this, SLOT(updateFinished(KProcess *)) ); + + if ( !fd || kp->start(KProcess::NotifyOnExit, flag) == false) + { + KMessageBox::error(0, i18n("Trouble writing to the archive...")); + emit updateDone(); + } + } +} + +void TarArch::updateProgress( KProcess * _proc, char *_buffer, int _bufflen ) +{ + // we're trying to capture the output of a command like this + // gzip -c myarch.tar + // and feed the output to the archive + int size; + size = fwrite(_buffer, 1, _bufflen, fd); + if (size != _bufflen) + { + _proc->kill(); + KMessageBox::error(0, i18n("Trouble writing to the archive...")); + kdWarning( 1601 ) << "trouble updating tar archive" << endl; + //kdFatal( 1601 ) << "trouble updating tar archive" << endl; + } +} + + + +QString TarArch::getCompressor() +{ + if ( m_fileMimeType == "application/x-tarz" ) + return QString( "compress" ); + + if ( m_fileMimeType == "application/x-tgz" ) + return QString( "gzip" ); + + if ( m_fileMimeType == "application/x-tbz" ) + return QString( "bzip2" ); + + if( m_fileMimeType == "application/x-tzo" ) + return QString( "lzop" ); + + return QString::null; +} + + +QString TarArch::getUnCompressor() +{ + if ( m_fileMimeType == "application/x-tarz" ) + return QString( "uncompress" ); + + if ( m_fileMimeType == "application/x-tgz" ) + return QString( "gunzip" ); + + if ( m_fileMimeType == "application/x-tbz" ) + return QString( "bunzip2" ); + + if( m_fileMimeType == "application/x-tzo" ) + return QString( "lzop" ); + + return QString::null; +} + +void +TarArch::open() +{ + if ( compressed ) + QFile::remove(tmpfile); // just to make sure + setHeaders(); + + clearShellOutput(); + + // might as well plunk the output of tar -tvf in the shell output window... + // + // Now it's essential - used later to decide whether pathnames in the + // tar archive are plain or start with "./" + KProcess *kp = m_currentProcess = new KProcess; + + *kp << m_archiver_program; + + if ( compressed ) + { + *kp << "--use-compress-program=" + getUnCompressor(); + } + + *kp << "-tvf" << m_filename; + + m_buffer = ""; + m_header_removed = false; + m_finished = false; + + connect(kp, SIGNAL(processExited(KProcess *)), + this, SLOT(slotListingDone(KProcess *))); + connect(kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput( KProcess *, char *, int ))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + } + + // We list afterwards because we want the signals at the end + // This unconfuses Extract Here somewhat + + if ( m_fileMimeType == "application/x-tgz" + || m_fileMimeType == "application/x-tbz" || !compressed ) + { + openFirstCreateTempDone(); + } + else + { + connect( this, SIGNAL( createTempDone() ), this, SLOT( openFirstCreateTempDone() ) ); + createTmp(); + } +} + +void TarArch::openFirstCreateTempDone() +{ + if ( compressed && ( m_fileMimeType != "application/x-tgz" ) + && ( m_fileMimeType != "application/x-tbz" ) ) + { + disconnect( this, SIGNAL( createTempDone() ), this, SLOT( openFirstCreateTempDone() ) ); + } + + Q_ASSERT( !m_listingThread ); + m_listingThread = new TarListingThread( this, m_filename ); + m_listingThread->start(); +} + +void TarArch::slotListingDone(KProcess *_kp) +{ + const QString list = getLastShellOutput(); + FileListView *flv = m_gui->fileList(); + if (flv!=NULL && flv->totalFiles()>0) + { + const QString firstfile = ((FileLVI *) flv->firstChild())->fileName(); + if (list.find(QRegExp(QString("\\s\\./%1[/\\n]").arg(firstfile)))>=0) + { + m_dotslash = true; + kdDebug(1601) << k_funcinfo << "archive has dot-slash" << endl; + } + else + { + if (list.find(QRegExp(QString("\\s%1[/\\n]").arg(firstfile)))>=0) + { + // archive doesn't have dot-slash + m_dotslash = false; + } + else + { + kdDebug(1601) << k_funcinfo << "cannot match '" << firstfile << "' in listing!" << endl; + } + } + } + + delete _kp; + _kp = m_currentProcess = NULL; +} + +void TarArch::create() +{ + emit sigCreate(this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add + | Arch::View); +} + +void TarArch::setHeaders() +{ + ColumnList list; + + list.append(FILENAME_COLUMN); + list.append(PERMISSION_COLUMN); + list.append(OWNER_COLUMN); + list.append(GROUP_COLUMN); + list.append(SIZE_COLUMN); + list.append(TIMESTAMP_COLUMN); + list.append(LINK_COLUMN); + + emit headers( list ); +} + +void TarArch::createTmp() +{ + if ( compressed ) + { + if ( !QFile::exists(tmpfile) ) + { + QString strUncompressor = getUnCompressor(); + // at least lzop doesn't want to pipe zerosize/nonexistent files + QFile originalFile( m_filename ); + if ( strUncompressor != "gunzip" && strUncompressor !="bunzip2" && + ( !originalFile.exists() || originalFile.size() == 0 ) ) + { + QFile temp( tmpfile ); + temp.open( IO_ReadWrite ); + temp.close(); + emit createTempDone(); + return; + } + // the tmpfile does not yet exist, so we create it. + createTmpInProgress = true; + int f_desc = KDE_open(QFile::encodeName(tmpfile), O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (f_desc != -1) + fd = fdopen( f_desc, "w" ); + else + fd = NULL; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + kdDebug(1601) << "Uncompressor is " << strUncompressor << endl; + *kp << strUncompressor; + KProcess::Communication flag = KProcess::AllOutput; + if (strUncompressor == "lzop") + { + // setting up a pty for lzop, since it doesn't like stdin to + // be /dev/null ( "no filename allowed when reading from stdin" ) + // - but it used to work without this ? ( Feb 13, 2003 ) + kp->setUsePty( KProcess::Stdin, false ); + flag = KProcess::Stdout; + *kp << "-d"; + } + *kp << "-c" << m_filename; + + connect(kp, SIGNAL(processExited(KProcess *)), + this, SLOT(createTmpFinished(KProcess *))); + connect(kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(createTmpProgress( KProcess *, char *, int ))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + if (kp->start(KProcess::NotifyOnExit, flag ) == false) + { + KMessageBox::error(0, i18n("Unable to fork a decompressor")); + emit sigOpen( this, false, QString::null, 0 ); + } + } + else + { + emit createTempDone(); + kdDebug(1601) << "Temp tar already there..." << endl; + } + } + else + { + emit createTempDone(); + } +} + +void TarArch::createTmpProgress( KProcess * _proc, char *_buffer, int _bufflen ) +{ + // we're trying to capture the output of a command like this + // gunzip -c myarch.tar.gz + // and put the output into tmpfile. + + int size; + size = fwrite(_buffer, 1, _bufflen, fd); + if (size != _bufflen) + { + _proc->kill(); + KMessageBox::error(0, i18n("Trouble writing to the tempfile...")); + //kdFatal( 1601 ) << "Trouble writing to archive(createTmpProgress)" << endl; + kdWarning( 1601 ) << "Trouble writing to archive(createTmpProgress)" << endl; + //exit(99); + } +} + +void TarArch::deleteOldFiles(const QStringList &urls, bool bAddOnlyNew) + // because tar is broken. Used when appending: see addFile. +{ + QStringList list; + QString str; + + QStringList::ConstIterator iter; + for (iter = urls.begin(); iter != urls.end(); ++iter ) + { + KURL url( *iter ); + // find the file entry in the archive listing + const FileLVI * lv = m_gui->fileList()->item( url.fileName() ); + if ( !lv ) // it isn't in there, so skip it. + continue; + + if (bAddOnlyNew) + { + // compare timestamps. If the file to be added is newer, delete the + // old. Otherwise we aren't adding it anyway, so we can go on to the next + // file with a "continue". + + QFileInfo fileInfo( url.path() ); + QDateTime addFileMTime = fileInfo.lastModified(); + QDateTime oldFileMTime = lv->timeStamp(); + + kdDebug(1601) << "Old file: " << oldFileMTime.date().year() << '-' << + oldFileMTime.date().month() << '-' << oldFileMTime.date().day() << + ' ' << oldFileMTime.time().hour() << ':' << + oldFileMTime.time().minute() << ':' << oldFileMTime.time().second() << + endl; + kdDebug(1601) << "New file: " << addFileMTime.date().year() << '-' << + addFileMTime.date().month() << '-' << addFileMTime.date().day() << + ' ' << addFileMTime.time().hour() << ':' << + addFileMTime.time().minute() << ':' << addFileMTime.time().second() << + endl; + + if (oldFileMTime >= addFileMTime) + { + kdDebug(1601) << "Old time is newer or same" << endl; + continue; // don't add this file to the list to be deleted. + } + } + list.append(str); + + kdDebug(1601) << "To delete: " << str << endl; + } + if(!list.isEmpty()) + remove(&list); + else + emit removeDone(); +} + + +void TarArch::addFile( const QStringList& urls ) +{ + m_filesToAdd = urls; + // tar is broken. If you add a file that's already there, it gives you + // two entries for that name, whether you --append or --update. If you + // extract by name, it will give you + // the first one. If you extract all, the second one will overwrite the + // first. So we'll first delete all the old files matching the names of + // those in urls. + m_bNotifyWhenDeleteFails = false; + connect( this, SIGNAL( removeDone() ), this, SLOT( deleteOldFilesDone() ) ); + deleteOldFiles(urls, ArkSettings::replaceOnlyWithNewer()); +} + +void TarArch::deleteOldFilesDone() +{ + disconnect( this, SIGNAL( removeDone() ), this, SLOT( deleteOldFilesDone() ) ); + m_bNotifyWhenDeleteFails = true; + + connect( this, SIGNAL( createTempDone() ), this, SLOT( addFileCreateTempDone() ) ); + createTmp(); +} + +void TarArch::addFileCreateTempDone() +{ + disconnect( this, SIGNAL( createTempDone() ), this, SLOT( addFileCreateTempDone() ) ); + QStringList * urls = &m_filesToAdd; + + KProcess *kp = m_currentProcess = new KProcess; + *kp << m_archiver_program; + + if( ArkSettings::replaceOnlyWithNewer()) + *kp << "uvf"; + else + *kp << "rvf"; + + if (compressed) + *kp << tmpfile; + else + *kp << m_filename; + + QStringList::ConstIterator iter; + KURL url( urls->first() ); + QDir::setCurrent( url.directory() ); + for (iter = urls->begin(); iter != urls->end(); ++iter ) + { + KURL fileURL( *iter ); + *kp << fileURL.fileName(); + } + + // debugging info + QValueList<QCString> list = kp->args(); + QValueList<QCString>::Iterator strTemp; + for ( strTemp=list.begin(); strTemp != list.end(); ++strTemp ) + { + kdDebug(1601) << *strTemp << " " << endl; + } + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotAddFinished(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigAdd(false); + } +} + +void TarArch::slotAddFinished(KProcess *_kp) +{ + disconnect( _kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotAddFinished(KProcess*))); + m_pTmpProc = _kp; + m_filesToAdd = QStringList(); + if ( compressed ) + { + connect( this, SIGNAL( updateDone() ), this, SLOT( addFinishedUpdateDone() ) ); + updateArch(); + } + else + addFinishedUpdateDone(); +} + +void TarArch::addFinishedUpdateDone() +{ + if ( compressed ) + disconnect( this, SIGNAL( updateDone() ), this, SLOT( addFinishedUpdateDone() ) ); + Arch::slotAddExited( m_pTmpProc ); // this will delete _kp + m_pTmpProc = NULL; +} + +void TarArch::unarchFileInternal() +{ + QString dest; + + if (m_destDir.isEmpty() || m_destDir.isNull()) + { + kdError(1601) << "There was no extract directory given." << endl; + return; + } + else dest = m_destDir; + + QString tmp; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program; + if (compressed) + *kp << "--use-compress-program="+getUnCompressor(); + + QString options = "-x"; + if (!ArkSettings::extractOverwrite()) + options += "k"; + if (ArkSettings::preservePerms()) + options += "p"; + options += "f"; + + kdDebug(1601) << "Options were: " << options << endl; + *kp << options << m_filename << "-C" << dest; + + // if the list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if (m_fileList) + { + for ( QStringList::Iterator it = m_fileList->begin(); + it != m_fileList->end(); ++it ) + { + *kp << QString(m_dotslash ? "./" : "")+(*it); + } + } + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotExtractExited(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigExtract(false); + } + +} + +void TarArch::remove(QStringList *list) +{ + deleteInProgress = true; + m_filesToRemove = *list; + connect( this, SIGNAL( createTempDone() ), this, SLOT( removeCreateTempDone() ) ); + createTmp(); +} + +void TarArch::removeCreateTempDone() +{ + disconnect( this, SIGNAL( createTempDone() ), this, SLOT( removeCreateTempDone() ) ); + + QString name, tmp; + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + *kp << m_archiver_program << "--delete" << "-f" ; + if (compressed) + *kp << tmpfile; + else + *kp << m_filename; + + QStringList::Iterator it = m_filesToRemove.begin(); + for ( ; it != m_filesToRemove.end(); ++it ) + { + *kp << QString(m_dotslash ? "./" : "")+(*it); + } + m_filesToRemove = QStringList(); + + connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + connect( kp, SIGNAL(processExited(KProcess*)), this, + SLOT(slotDeleteExited(KProcess*))); + + if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) + { + KMessageBox::error( 0, i18n("Could not start a subprocess.") ); + emit sigDelete(false); + } +} + +void TarArch::slotDeleteExited(KProcess *_kp) +{ + m_pTmpProc2 = _kp; + if ( compressed ) + { + connect( this, SIGNAL( updateDone() ), this, SLOT( removeUpdateDone() ) ); + updateArch(); + } + else + removeUpdateDone(); +} + +void TarArch::removeUpdateDone() +{ + if ( compressed ) + disconnect( this, SIGNAL( updateDone() ), this, SLOT( removeUpdateDone() ) ); + + deleteInProgress = false; + emit removeDone(); + Arch::slotDeleteExited( m_pTmpProc2 ); + m_pTmpProc = NULL; +} + +void TarArch::addDir(const QString & _dirName) +{ + QStringList list; + list.append(_dirName); + addFile(list); +} + +void TarArch::openFinished( KProcess * ) +{ + // do nothing + // turn off busy light (when someone makes one) + kdDebug(1601) << "Open finshed" << endl; +} + +void TarArch::createTmpFinished( KProcess *_kp ) +{ + createTmpInProgress = false; + fclose(fd); + delete _kp; + _kp = m_currentProcess = NULL; + + emit createTempDone(); +} + +void TarArch::updateFinished( KProcess *_kp ) +{ + fclose(fd); + updateInProgress = false; + delete _kp; + _kp = m_currentProcess = NULL; + + emit updateDone(); +} + +void TarArch::customEvent( QCustomEvent *ev ) +{ + if ( ev->type() == 65442 ) + { + ListingEvent *event = static_cast<ListingEvent*>( ev ); + switch ( event->status() ) + { + case ListingEvent::Normal: + m_gui->fileList()->addItem( event->columns() ); + break; + + case ListingEvent::Error: + m_listingThread->wait(); + delete m_listingThread; + m_listingThread = 0; + emit sigOpen( this, false, QString::null, 0 ); + break; + + case ListingEvent::ListingFinished: + m_listingThread->wait(); + delete m_listingThread; + m_listingThread = 0; + emit sigOpen( this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add | Arch::View ); + } + } +} + +#include "tar.moc" +// kate: space-indent on; diff --git a/ark/tar.h b/ark/tar.h new file mode 100644 index 0000000..544949a --- /dev/null +++ b/ark/tar.h @@ -0,0 +1,135 @@ +/* + +ark -- archiver for the KDE project + +Copyright (C) + +1997-1999: Rob Palmbos palm9744@kettering.edu +1999: Francois-Xavier Duranceau duranceau@kde.org +1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) +2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com) +2001: Roberto Selbach Teixeira <maragato@conectiva.com> +2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> +2006: Henrique Pinto <henrique.pinto@kdemail.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. + +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. + +*/ + +#ifndef TAR_H +#define TAR_H + +#include <unistd.h> + + +class QString; +class QStrList; + +class KProcess; +class KTempDir; +class KTarDirectory; +class KTar; + +class ArkWidget; +class Arch; +class TarListingThread; + +// TarArch can read Tar files and Tar files compressed with gzip. +// It doesn't yet know how to list Tar files compressed with other +// compressors because the listing part is done through KTar. +// If it could be listed though, the rest would work. +// The reason we use KTar for listing is that the output tar -tvf is +// of unreliable format. + +class TarArch : public Arch +{ + Q_OBJECT + public: + TarArch( ArkWidget *_gui, const QString & _filename, + const QString & _openAsMimeType ); + virtual ~TarArch(); + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir( const QString & ); + virtual void remove( QStringList* ); + virtual void unarchFileInternal(); + + virtual int getEditFlag(); + + QString getCompressor(); + QString getUnCompressor(); + + public slots: + void updateProgress( KProcess *_kp, char *_buffer, int _bufflen ); + void openFinished( KProcess * ); + void updateFinished( KProcess * ); + void createTmpFinished( KProcess * ); + void createTmpProgress( KProcess *_kp, char *_buffer, int _bufflen ); + void slotAddFinished( KProcess * ); + void slotListingDone( KProcess * ); + void slotDeleteExited( KProcess * ); + + signals: + void removeDone(); + void createTempDone(); + void updateDone(); + + private slots: + void openFirstCreateTempDone(); + void deleteOldFilesDone(); + void addFileCreateTempDone(); + void addFinishedUpdateDone(); + void removeCreateTempDone(); + void removeUpdateDone(); + + protected: + void customEvent( QCustomEvent * ); + + private: // methods + void updateArch(); + void createTmp(); + void setHeaders(); + void processDir( const KTarDirectory *tardir, const QString & root ); + void deleteOldFiles( const QStringList &list, bool bAddOnlyNew ); + QString getEntry( const QString & filename ); + + private: // data + // if the tar is compressed, this is the temporary uncompressed tar. + KTempDir * m_tmpDir; + QString tmpfile; + QString m_fileMimeType; + bool compressed; + + // for use with createTmp and updateArch + bool createTmpInProgress; + bool updateInProgress; + + // for use with deleteOldFiles + bool deleteInProgress; + FILE *fd; + QStringList m_filesToAdd; + QStringList m_filesToRemove; + KProcess * m_pTmpProc; + KProcess * m_pTmpProc2; + bool failed; + bool m_dotslash; + TarListingThread *m_listingThread; +}; + +#endif /* TAR_H */ + diff --git a/ark/tarlistingthread.cpp b/ark/tarlistingthread.cpp new file mode 100644 index 0000000..2a98375 --- /dev/null +++ b/ark/tarlistingthread.cpp @@ -0,0 +1,161 @@ +/* + This file is part of KDE. + + Copyright (c) 2006 Henrique Pinto <henrique.pinto@kdemail.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. + + 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. +*/ + + +#include <qstring.h> +#include <qapplication.h> + +#include <karchive.h> +#include <ktar.h> +#include <kdebug.h> + +#include "tarlistingthread.h" + +// Helper function +// copied from KonqTreeViewItem::makeAccessString() +static char *makeAccessString(mode_t mode) +{ + static char buffer[10]; + + char uxbit,gxbit,oxbit; + + if ( (mode & (S_IXUSR|S_ISUID)) == (S_IXUSR|S_ISUID) ) + uxbit = 's'; + else if ( (mode & (S_IXUSR|S_ISUID)) == S_ISUID ) + uxbit = 'S'; + else if ( (mode & (S_IXUSR|S_ISUID)) == S_IXUSR ) + uxbit = 'x'; + else + uxbit = '-'; + + if ( (mode & (S_IXGRP|S_ISGID)) == (S_IXGRP|S_ISGID) ) + gxbit = 's'; + else if ( (mode & (S_IXGRP|S_ISGID)) == S_ISGID ) + gxbit = 'S'; + else if ( (mode & (S_IXGRP|S_ISGID)) == S_IXGRP ) + gxbit = 'x'; + else + gxbit = '-'; + + if ( (mode & (S_IXOTH|S_ISVTX)) == (S_IXOTH|S_ISVTX) ) + oxbit = 't'; + else if ( (mode & (S_IXOTH|S_ISVTX)) == S_ISVTX ) + oxbit = 'T'; + else if ( (mode & (S_IXOTH|S_ISVTX)) == S_IXOTH ) + oxbit = 'x'; + else + oxbit = '-'; + + buffer[0] = ((( mode & S_IRUSR ) == S_IRUSR ) ? 'r' : '-' ); + buffer[1] = ((( mode & S_IWUSR ) == S_IWUSR ) ? 'w' : '-' ); + buffer[2] = uxbit; + buffer[3] = ((( mode & S_IRGRP ) == S_IRGRP ) ? 'r' : '-' ); + buffer[4] = ((( mode & S_IWGRP ) == S_IWGRP ) ? 'w' : '-' ); + buffer[5] = gxbit; + buffer[6] = ((( mode & S_IROTH ) == S_IROTH ) ? 'r' : '-' ); + buffer[7] = ((( mode & S_IWOTH ) == S_IWOTH ) ? 'w' : '-' ); + buffer[8] = oxbit; + buffer[9] = 0; + + return buffer; +} + +TarListingThread::TarListingThread( QObject *parent, const QString& filename ) + : QThread(), m_parent( parent ) +{ + Q_ASSERT( m_parent ); + m_archive = new KTar( filename ); +} + +TarListingThread::~TarListingThread() +{ + delete m_archive; + m_archive = 0; +} + +void TarListingThread::run() +{ + if (!m_archive->open( IO_ReadOnly )) + { + ListingEvent *ev = new ListingEvent( QStringList(), ListingEvent::Error ); + qApp->postEvent( m_parent, ev ); + return; + } + + processDir( m_archive->directory(), QString() ); + + // Send an empty QStringList in an Event to signal the listing end. + ListingEvent *ev = new ListingEvent( QStringList(), ListingEvent::ListingFinished ); + qApp->postEvent( m_parent, ev ); +} + +void TarListingThread::processDir( const KTarDirectory *tardir, const QString & root ) +{ + QStringList list = tardir->entries(); + + QStringList::const_iterator itEnd = list.constEnd(); + + for ( QStringList::const_iterator it = list.constBegin(); it != itEnd; ++it ) + { + const KTarEntry* tarEntry = tardir->entry((*it)); + if (!tarEntry) + continue; + + QStringList col_list; + QString name; + if (root.isEmpty() || root.isNull()) + name = tarEntry->name(); + else + name = root + tarEntry->name(); + if ( !tarEntry->isFile() ) + name += '/'; + col_list.append( name ); + QString perms = makeAccessString(tarEntry->permissions()); + if (!tarEntry->isFile()) + perms = "d" + perms; + else if (!tarEntry->symlink().isEmpty()) + perms = "l" + perms; + else + perms = "-" + perms; + col_list.append(perms); + col_list.append( tarEntry->user() ); + col_list.append( tarEntry->group() ); + QString strSize = "0"; + if (tarEntry->isFile()) + { + strSize.sprintf("%d", ((KTarFile *)tarEntry)->size()); + } + col_list.append(strSize); + QString timestamp = tarEntry->datetime().toString(ISODate); + col_list.append(timestamp); + col_list.append(tarEntry->symlink()); + + ListingEvent *ev = new ListingEvent( col_list ); + qApp->postEvent( m_parent, ev ); + + // if it's a directory, process it. + // remember that name is root + / + the name of the directory + if ( tarEntry->isDirectory() ) + { + processDir( static_cast<const KTarDirectory *>( tarEntry ), name ); + } + } +} diff --git a/ark/tarlistingthread.h b/ark/tarlistingthread.h new file mode 100644 index 0000000..f9de02b --- /dev/null +++ b/ark/tarlistingthread.h @@ -0,0 +1,63 @@ +/* + This file is part of KDE. + + Copyright (c) 2006 Henrique Pinto <henrique.pinto@kdemail.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. + + 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. +*/ + +#ifndef TARLISTINGTHREAD_H +#define TARLISTINGTHREAD_H + +#include <qthread.h> +#include <qstringlist.h> +#include <qevent.h> + +class QString; +class KArchive; + +class ListingEvent: public QCustomEvent +{ + public: + enum Status { Normal, Error, ListingFinished }; + ListingEvent( const QStringList& data, Status st = Normal ) + : QCustomEvent( 65442 ), m_data( data ), m_status( st ) {} + + const QStringList& columns() const { return m_data; } + Status status() const { return m_status; } + + private: + QStringList m_data; + Status m_status; +}; + +class TarListingThread: public QThread +{ + public: + TarListingThread( QObject *parent, const QString& filename ); + ~TarListingThread(); + + protected: + void run(); + + private: + void processDir( const KTarDirectory *tardir, const QString & root ); + + KArchive *m_archive; + QObject *m_parent; +}; + +#endif // TARLISTINGTHREAD_H diff --git a/ark/zip.cpp b/ark/zip.cpp new file mode 100644 index 0000000..3538d11 --- /dev/null +++ b/ark/zip.cpp @@ -0,0 +1,277 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ + + +// Qt includes +#include <qdir.h> + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +// ark includes +#include "zip.h" +#include "arkwidget.h" +#include "settings.h" + + +ZipArch::ZipArch( ArkWidget *_gui, const QString & _fileName ) + : Arch( _gui, _fileName ) +{ + m_archiver_program = "zip"; + m_unarchiver_program = "unzip"; + verifyCompressUtilityIsAvailable( m_archiver_program ); + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + + m_headerString = "----"; + m_repairYear = 9; m_fixMonth = 7; m_fixDay = 8; m_fixTime = 10; + m_dateCol = 5; + m_numCols = 7; + + m_archCols.append( new ArchColumns( 1, QRegExp( "[0-9]+" ) ) ); + m_archCols.append( new ArchColumns( 2, QRegExp( "[^\\s]+" ) ) ); + m_archCols.append( new ArchColumns( 3, QRegExp( "[0-9]+" ) ) ); + m_archCols.append( new ArchColumns( 4, QRegExp( "[0-9.]+%" ) ) ); + m_archCols.append( new ArchColumns( 7, QRegExp( "[01][0-9]" ), 2 ) ); + m_archCols.append( new ArchColumns( 8, QRegExp( "[0-3][0-9]" ), 2 ) ); + m_archCols.append( new ArchColumns( 9, QRegExp( "[0-9][0-9]" ), 2 ) ); + m_archCols.append( new ArchColumns( 10, QRegExp( "[0-9:]+" ), 6 ) ); + m_archCols.append( new ArchColumns( 6, QRegExp( "[a-fA-F0-9]+ {2}" ) ) ); + m_archCols.append( new ArchColumns( 0, QRegExp( "[^\\n]+" ), 4096 ) ); + +} + +void ZipArch::setHeaders() +{ + ColumnList list; + list.append( FILENAME_COLUMN ); + list.append( SIZE_COLUMN ); + list.append( METHOD_COLUMN ); + list.append( PACKED_COLUMN ); + list.append( RATIO_COLUMN ); + list.append( TIMESTAMP_COLUMN ); + list.append( CRC_COLUMN ); + + emit headers( list ); +} + +void ZipArch::open() +{ + setHeaders(); + + m_buffer = ""; + m_header_removed = false; + m_finished = false; + + KProcess *kp = m_currentProcess = new KProcess; + + *kp << m_unarchiver_program << "-v" << m_filename; + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedTOC(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotOpenExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigOpen( this, false, QString::null, 0 ); + } +} + + +void ZipArch::create() +{ + emit sigCreate( this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add | Arch::View ); +} + +void ZipArch::addDir( const QString & _dirName ) +{ + if ( !_dirName.isEmpty() ) + { + bool bOldRecVal = ArkSettings::rarRecurseSubdirs(); + // must be true for add directory - otherwise why would user try? + ArkSettings::setRarRecurseSubdirs( true ); + + QStringList list; + list.append( _dirName ); + addFile( list ); + ArkSettings::setRarRecurseSubdirs( bOldRecVal ); // reset to old val + } +} + +void ZipArch::addFile( const QStringList &urls ) +{ + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program; + + if ( !m_password.isEmpty() ) + *kp << "-P" << m_password; + + if ( ArkSettings::rarRecurseSubdirs() ) + *kp << "-r"; + + if ( ArkSettings::rarStoreSymlinks() ) + *kp << "-y"; + + if ( ArkSettings::forceMSDOS() ) + *kp << "-k"; + if ( ArkSettings::convertLF2CRLF() ) + *kp << "-l"; + + if ( ArkSettings::replaceOnlyWithNewer() ) + *kp << "-u"; + + + *kp << m_filename; + + QStringList::ConstIterator iter; + KURL url( urls.first() ); + QDir::setCurrent( url.directory() ); + for ( iter = urls.begin(); iter != urls.end(); ++iter ) + { + KURL fileURL( *iter ); + *kp << fileURL.fileName(); + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotAddExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigAdd( false ); + } +} + +void ZipArch::unarchFileInternal() +{ + // if fileList is empty, all files are extracted. + // if destDir is empty, abort with error. + if ( m_destDir.isEmpty() || m_destDir.isNull() ) + { + kdError( 1601 ) << "There was no extract directory given." << endl; + return; + } + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_unarchiver_program; + + if ( !m_password.isEmpty() ) + *kp << "-P" << m_password; + + if ( ArkSettings::extractJunkPaths() && !m_viewFriendly ) + *kp << "-j" ; + + if ( ArkSettings::rarToLower() ) + *kp << "-L"; + + if ( ArkSettings::extractOverwrite() ) + *kp << "-o"; + else + *kp << "-n"; + + *kp << m_filename; + + // if the list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if ( m_fileList ) + { + QStringList::Iterator it; + + for ( it = m_fileList->begin(); it != m_fileList->end(); ++it ) + { + *kp << (*it); + } + } + + *kp << "-d" << m_destDir; + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotExtractExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigExtract( false ); + } +} + +bool ZipArch::passwordRequired() +{ + return m_lastShellOutput.findRev("unable to get password\n")!=-1 || m_lastShellOutput.endsWith("password inflating\n") || m_lastShellOutput.findRev("password incorrect--reenter:")!=-1 || m_lastShellOutput.endsWith("incorrect password\n"); +} + +void ZipArch::remove( QStringList *list ) +{ + if ( !list ) + return; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program << "-d" << m_filename; + + QStringList::Iterator it; + for ( it = list->begin(); it != list->end(); ++it ) + { + QString str = *it; + *kp << str; + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotDeleteExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigDelete( false ); + } +} + +#include "zip.moc" diff --git a/ark/zip.h b/ark/zip.h new file mode 100644 index 0000000..721d734 --- /dev/null +++ b/ark/zip.h @@ -0,0 +1,58 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 1997-1999: Rob Palmbos palm9744@kettering.edu + 1999: Francois-Xavier Duranceau duranceau@kde.org + 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ + +#ifndef ZIPARCH_H +#define ZIPARCH_H + +#include "arch.h" + +class QString; +class QStringList; + +class ArkWidget; + +class ZipArch : public Arch +{ + Q_OBJECT + public: + ZipArch( ArkWidget *_gui, const QString & _fileName ); + virtual ~ZipArch() { } + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir( const QString & ); + + virtual void remove( QStringList * ); + virtual void unarchFileInternal(); + virtual bool passwordRequired(); + private: + void setHeaders(); +}; + +#endif /* ZIPARCH_H */ diff --git a/ark/zoo.cpp b/ark/zoo.cpp new file mode 100644 index 0000000..9116ea5 --- /dev/null +++ b/ark/zoo.cpp @@ -0,0 +1,317 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ + +#include <config.h> + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/errno.h> +#include <string.h> + +// QT includes +#include <qfile.h> +#include <qdir.h> + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +// ark includes +#include "settings.h" +#include "arkwidget.h" +#include "arch.h" +#include "zoo.h" +#include "arkutils.h" +#include "filelistview.h" + +static QString fixTime( const QString &_strTime ); + +ZooArch::ZooArch( ArkWidget *gui, const QString & fileName ) + : Arch( gui, fileName ) +{ + m_archiver_program = m_unarchiver_program = "zoo"; + verifyCompressUtilityIsAvailable( m_archiver_program ); + verifyUncompressUtilityIsAvailable( m_unarchiver_program ); + + m_headerString = "----"; +} + +bool ZooArch::processLine( const QCString &line ) +{ + const char *_line = ( const char * )line; + char columns[11][80]; + char filename[4096]; + + // Note: I'm reversing the ratio and the length for better display + + sscanf( _line, + " %79[0-9] %79[0-9%] %79[0-9] %79[0-9] %79[a-zA-Z] %79[0-9]%79[ ]%11[ 0-9:+-]%2[C ]%4095[^\n]", + columns[1], columns[0], columns[2], columns[3], columns[7], + columns[8], columns[9], columns[4], columns[10], filename ); + + QString year = ArkUtils::fixYear( columns[8] ); + + QString strDate; + strDate.sprintf( "%s-%.2d-%.2d", year.utf8().data(), + ArkUtils::getMonth( columns[7] ), atoi( columns[3] ) ); + + strlcpy( columns[3], strDate.ascii(), sizeof( columns[3]) ); + kdDebug( 1601 ) << "New timestamp is " << columns[3] << endl; + + strlcat( columns[3], " ", sizeof( columns[3] ) ); + strlcat( columns[3], fixTime( columns[4] ).ascii(), sizeof( columns[3] ) ); + + QStringList list; + list.append( QFile::decodeName( filename ) ); + + for ( int i=0; i<4; i++ ) + { + list.append( QString::fromLocal8Bit( columns[i] ) ); + } + + m_gui->fileList()->addItem( list ); // send to GUI + + return true; +} + +void ZooArch::open() +{ + setHeaders(); + + m_buffer = ""; + m_header_removed = false; + m_finished = false; + + + KProcess *kp = m_currentProcess = new KProcess; + *kp << m_archiver_program << "l" << m_filename; + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedTOC(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotOpenExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigOpen( this, false, QString::null, 0 ); + } +} + +void ZooArch::setHeaders() +{ + ColumnList list; + list.append( FILENAME_COLUMN ); + list.append( RATIO_COLUMN ); + list.append( SIZE_COLUMN ); + list.append( PACKED_COLUMN ); + list.append( TIMESTAMP_COLUMN ); + + emit headers( list ); +} + + +void ZooArch::create() +{ + emit sigCreate( this, true, m_filename, + Arch::Extract | Arch::Delete | Arch::Add | Arch::View); +} + +void ZooArch::addDir( const QString & _dirName ) +{ + if ( ! _dirName.isEmpty() ) + { + QStringList list; + list.append( _dirName ); + addFile( list ); + } +} + +void ZooArch::addFile( const QStringList &urls ) +{ + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + *kp << m_archiver_program; + + if ( ArkSettings::replaceOnlyWithNewer() ) + *kp << "-update"; + else + *kp << "-add"; + + *kp << m_filename; + + KURL url( urls.first() ); + QDir::setCurrent( url.directory() ); + + QStringList::ConstIterator iter; + + for ( iter = urls.begin(); iter != urls.end(); ++iter ) + { + KURL fileURL( *iter ); + *kp << fileURL.fileName(); + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotAddExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigAdd( false ); + } +} + +void ZooArch::unarchFileInternal() +{ + // if _fileList is empty, we extract all. + // if _destDir is empty, abort with error. + + if ( m_destDir.isEmpty() || m_destDir.isNull() ) + { + kdError( 1601 ) << "There was no extract directory given." << endl; + return; + } + + // zoo has no option to specify the destination directory + // so we have to change to it. + + bool ret = QDir::setCurrent( m_destDir ); + // We already checked the validity of the dir before coming here + Q_ASSERT(ret); + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program; + + if ( ArkSettings::extractOverwrite() ) + { + *kp << "xOOS"; + } + else + { + *kp << "x"; + } + + *kp << m_filename; + + // if the list is empty, no filenames go on the command line, + // and we then extract everything in the archive. + if (m_fileList) + { + QStringList::Iterator it; + for ( it = m_fileList->begin(); it != m_fileList->end(); ++it ) + { + *kp << (*it); + } + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotExtractExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigExtract( false ); + } +} + +void ZooArch::remove( QStringList *list ) +{ + if (!list) + return; + + KProcess *kp = m_currentProcess = new KProcess; + kp->clearArguments(); + + *kp << m_archiver_program << "D" << m_filename; + + QStringList::Iterator it; + for ( it = list->begin(); it != list->end(); ++it ) + { + QString str = *it; + *kp << str; + } + + connect( kp, SIGNAL( receivedStdout(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( receivedStderr(KProcess*, char*, int) ), + SLOT( slotReceivedOutput(KProcess*, char*, int) ) ); + connect( kp, SIGNAL( processExited(KProcess*) ), + SLOT( slotDeleteExited(KProcess*) ) ); + + if ( !kp->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + KMessageBox::error( 0, i18n( "Could not start a subprocess." ) ); + emit sigDelete( false ); + } +} + +QString fixTime( const QString &_strTime ) +{ + // it may have come from a different time zone... get rid of trailing + // +3 or -3 etc. + QString strTime = _strTime; + + if ( strTime.contains("+") || strTime.contains("-") ) + { + QCharRef c = strTime.at( 8 ); + int offset = strTime.right( strTime.length() - 9 ).toInt(); + QString strHour = strTime.left( 2 ); + int nHour = strHour.toInt(); + if ( c == '+' || c == '-' ) + { + if ( c == '+' ) + nHour = ( nHour + offset ) % 24; + else if ( c == '-' ) + { + nHour -= offset; + if ( nHour < 0 ) + nHour += 24; + } + strTime = strTime.left( 8 ); + strTime.sprintf( "%2.2d%s", nHour, strTime.right( 6 ).utf8().data() ); + } + } + else + { + strTime = strTime.left( 8 ); + } + return strTime; +} + +#include "zoo.moc" diff --git a/ark/zoo.h b/ark/zoo.h new file mode 100644 index 0000000..0e83ce1 --- /dev/null +++ b/ark/zoo.h @@ -0,0 +1,59 @@ +/* + + ark -- archiver for the KDE project + + Copyright (C) + + 2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) + 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.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. + + 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. + +*/ +#ifndef ZOO_H +#define ZOO_H + +#include "arch.h" + +class QString; +class QCString; +class QStringList; + +class ArkWidget; + +class ZooArch : public Arch +{ + Q_OBJECT + public: + ZooArch( ArkWidget *, const QString & ); + virtual ~ZooArch() { } + + virtual void open(); + virtual void create(); + + virtual void addFile( const QStringList & ); + virtual void addDir( const QString & ); + + virtual void remove( QStringList * ); + virtual void unarchFileInternal(); + + protected slots: + virtual bool processLine( const QCString &line ); + + private: + void setHeaders(); +}; + +#endif //ZOO_H |