diff options
Diffstat (limited to 'src/app/Dialogs/checksumdlg.cpp')
-rw-r--r-- | src/app/Dialogs/checksumdlg.cpp | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/src/app/Dialogs/checksumdlg.cpp b/src/app/Dialogs/checksumdlg.cpp new file mode 100644 index 0000000..6e3191d --- /dev/null +++ b/src/app/Dialogs/checksumdlg.cpp @@ -0,0 +1,603 @@ +#include "checksumdlg.h" +#include "../krusader.h" +#include <tdelocale.h> +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqcheckbox.h> +#include <klineedit.h> +#include <tdelistview.h> +#include <tqpixmap.h> +#include <kcursor.h> +#include <tdemessagebox.h> +#include <tqfile.h> +#include <tqtextstream.h> +#include <tdefiledialog.h> +#include <tqframe.h> +#include <kiconloader.h> +#include <kcombobox.h> +#include <tqfileinfo.h> +#include <kurlrequester.h> +#include "../krservices.h" +#include <tqptrlist.h> +#include <tqmap.h> +#include <tdetempfile.h> +#include <kstandarddirs.h> + +class CS_Tool; // forward +typedef void PREPARE_PROC_FUNC(TDEProcess& proc, CS_Tool *self, const TQStringList& files, + const TQString checksumFile, bool recursive, const TQString& stdoutFileName, + const TQString& stderrFileName, const TQString& type); +typedef TQStringList GET_FAILED_FUNC(const TQStringList& stdOut, const TQStringList& stdErr); + +class CS_Tool { +public: + enum Type { + MD5=0, SHA1, SHA256, TIGER, WHIRLPOOL, SFV, CRC, + SHA224, SHA384, SHA512, + NumOfTypes + }; + + Type type; + TQString binary; + bool recursive; + bool standardFormat; + PREPARE_PROC_FUNC *create, *verify; + GET_FAILED_FUNC *failed; +}; + +class CS_ToolByType { +public: + TQPtrList<CS_Tool> tools, r_tools; // normal and recursive tools +}; + +// handles md5sum and sha1sum +void sumCreateFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files, + const TQString, bool recursive, const TQString& stdoutFileName, + const TQString& stderrFileName, const TQString&) { + proc.setUseShell(true, "/bin/bash"); + proc << KrServices::fullPathName( self->binary ); + Q_ASSERT(!recursive); + proc << files << "1>" << stdoutFileName << "2>" << stderrFileName; +} + +void sumVerifyFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& /* files */, + const TQString checksumFile, bool recursive, const TQString& stdoutFileName, + const TQString& stderrFileName, const TQString& /* type */) { + proc.setUseShell(true, "/bin/bash"); + proc << KrServices::fullPathName( self->binary ); + Q_ASSERT(!recursive); + proc << "-c" << checksumFile << "1>" << stdoutFileName << "2>" << stderrFileName; +} + +TQStringList sumFailedFunc(const TQStringList& stdOut, const TQStringList& stdErr) { + // md5sum and sha1sum print "...: FAILED" for failed files and display + // the number of failures to stderr. so if stderr is empty, we'll assume all is ok + TQStringList result; + if (stdErr.size()==0) return result; + result += stdErr; + // grep for the ":FAILED" substring + const TQString tmp = TQString(": FAILED").local8Bit(); + for (uint i=0; i<stdOut.size();++i) { + if (stdOut[i].find(tmp) != -1) + result += stdOut[i]; + } + + return result; +} + +// handles *deep binaries +void deepCreateFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files, + const TQString, bool recursive, const TQString& stdoutFileName, + const TQString& stderrFileName, const TQString&) { + proc.setUseShell(true, "/bin/bash"); + proc << KrServices::fullPathName( self->binary ); + if (recursive) proc << "-r"; + proc << "-l" << files << "1>" << stdoutFileName << "2>" << stderrFileName; +} + +void deepVerifyFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files, + const TQString checksumFile, bool recursive, const TQString& stdoutFileName, + const TQString& stderrFileName, const TQString&) { + proc.setUseShell(true, "/bin/bash"); + proc << KrServices::fullPathName( self->binary ); + if (recursive) proc << "-r"; + proc << "-x" << checksumFile << files << "1>" << stdoutFileName << "2>" << stderrFileName; +} + +TQStringList deepFailedFunc(const TQStringList& stdOut, const TQStringList&/* stdErr */) { + // *deep dumps (via -x) all failed hashes to stdout + return stdOut; +} + +// handles cfv binary +void cfvCreateFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& files, + const TQString, bool recursive, const TQString& stdoutFileName, + const TQString& stderrFileName, const TQString& type) { + proc.setUseShell(true, "/bin/bash"); + proc << KrServices::fullPathName( self->binary ) << "-C" << "-VV"; + if (recursive) proc << "-rr"; + proc << "-t" << type << "-f-" << "-U" << files << "1>" << stdoutFileName << "2>" << stderrFileName; +} + +void cfvVerifyFunc(TDEProcess& proc, CS_Tool *self, const TQStringList& /* files */, + const TQString checksumFile, bool recursive, const TQString& stdoutFileName, + const TQString& stderrFileName, const TQString&type) { + proc.setUseShell(true, "/bin/bash"); + proc << KrServices::fullPathName( self->binary ) << "-M"; + if (recursive) proc << "-rr"; + proc << "-U" << "-VV" << "-t" << type << "-f" << checksumFile << "1>" << stdoutFileName << "2>" << stderrFileName;// << files; +} + +TQStringList cfvFailedFunc(const TQStringList& /* stdOut */, const TQStringList& stdErr) { + // cfv dumps all failed hashes to stderr + return stdErr; +} + +// important: this table should be ordered like so that all md5 tools should be +// one after another, and then all sha1 and so on and so forth. they tools must be grouped, +// since the code in getTools() counts on it! +CS_Tool cs_tools[] = { + // type binary recursive stdFmt create_func verify_func failed_func + {CS_Tool::MD5, "md5sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, + {CS_Tool::MD5, "md5deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, + {CS_Tool::MD5, "cfv", true, true, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, + {CS_Tool::SHA1, "sha1sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, + {CS_Tool::SHA1, "sha1deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, + {CS_Tool::SHA1, "cfv", true, true, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, + {CS_Tool::SHA224, "sha224sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, + {CS_Tool::SHA256, "sha256sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, + {CS_Tool::SHA256, "sha256deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, + {CS_Tool::SHA384, "sha384sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, + {CS_Tool::SHA512, "sha512sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, + {CS_Tool::TIGER, "tigerdeep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, + {CS_Tool::WHIRLPOOL, "whirlpooldeep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, + {CS_Tool::SFV, "cfv", true, false, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, + {CS_Tool::CRC, "cfv", true, false, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, +}; + +TQMap<TQString, CS_Tool::Type> cs_textToType; +TQMap<CS_Tool::Type, TQString> cs_typeToText; + +void initChecksumModule() { + // prepare the dictionaries - pity it has to be manually + cs_textToType["md5"]=CS_Tool::MD5; + cs_textToType["sha1"]=CS_Tool::SHA1; + cs_textToType["sha256"]=CS_Tool::SHA256; + cs_textToType["sha224"]=CS_Tool::SHA224; + cs_textToType["sha384"]=CS_Tool::SHA384; + cs_textToType["sha512"]=CS_Tool::SHA512; + cs_textToType["tiger"]=CS_Tool::TIGER; + cs_textToType["whirlpool"]=CS_Tool::WHIRLPOOL; + cs_textToType["sfv"]=CS_Tool::SFV; + cs_textToType["crc"]=CS_Tool::CRC; + + cs_typeToText[CS_Tool::MD5]="md5"; + cs_typeToText[CS_Tool::SHA1]="sha1"; + cs_typeToText[CS_Tool::SHA256]="sha256"; + cs_typeToText[CS_Tool::SHA224]="sha224"; + cs_typeToText[CS_Tool::SHA384]="sha384"; + cs_typeToText[CS_Tool::SHA512]="sha512"; + cs_typeToText[CS_Tool::TIGER]="tiger"; + cs_typeToText[CS_Tool::WHIRLPOOL]="whirlpool"; + cs_typeToText[CS_Tool::SFV]="sfv"; + cs_typeToText[CS_Tool::CRC]="crc"; + + // build the checksumFilter (for usage in KRQuery) + TQMap<TQString, CS_Tool::Type>::Iterator it; + for (it=cs_textToType.begin(); it!=cs_textToType.end(); ++it) + MatchChecksumDlg::checksumTypesFilter += ("*."+it.key()+" "); +} + +// -------------------------------------------------- + +// returns a list of tools which can work with recursive or non-recursive mode and are installed +// note: only 1 tool from each type is suggested +static TQPtrList<CS_Tool> getTools(bool folders) { + TQPtrList<CS_Tool> result; + uint i; + for (i=0; i < sizeof(cs_tools)/sizeof(CS_Tool); ++i) { + if (result.last() && result.last()->type == cs_tools[i].type) continue; // 1 from each type please + if (folders && !cs_tools[i].recursive) continue; + if (KrServices::cmdExist(cs_tools[i].binary)) + result.append(&cs_tools[i]); + } + + return result; +} + +// ------------- CreateChecksumDlg + +CreateChecksumDlg::CreateChecksumDlg(const TQStringList& files, bool containFolders, const TQString& path): + KDialogBase(Plain, i18n("Create Checksum"), Ok | Cancel, Ok, krApp) { + + TQPtrList<CS_Tool> tools = getTools(containFolders); + + if (tools.count() == 0) { // nothing was suggested?! + TQString error = i18n("<qt>Can't calculate checksum since no supported tool was found. " + "Please check the <b>Dependencies</b> page in Krusader's settings.</qt>"); + if (containFolders) + error += i18n("<qt><b>Note</b>: you've selected directories, and probably have no recursive checksum tool installed." + " Krusader currently supports <i>md5deep, sha1deep, sha256deep, tigerdeep and cfv</i></qt>"); + KMessageBox::error(0, error); + return; + } + + TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1, + KDialogBase::marginHint(), KDialogBase::spacingHint()); + + int row=0; + + // title (icon+text) + TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint()); + TQLabel *p = new TQLabel(plainPage()); + p->setPixmap(krLoader->loadIcon("application-octet-stream", TDEIcon::Desktop, 32)); + hlayout->addWidget(p); + TQLabel *l1 = new TQLabel(i18n("About to calculate checksum for the following files") + + (containFolders ? i18n(" and folders:") : ":"), plainPage()); + hlayout->addWidget(l1); + layout->addMultiCellLayout(hlayout, row, row, 0, 1, TQt::AlignLeft); + ++row; + + // file list + TDEListBox *lb = new TDEListBox(plainPage()); + lb->insertStringList(files); + layout->addMultiCellWidget(lb, row, row, 0, 1); + ++row; + + // checksum method + TQHBoxLayout *hlayout2 = new TQHBoxLayout(layout, KDialogBase::spacingHint()); + TQLabel *l2 = new TQLabel(i18n("Select the checksum method:"), plainPage()); + hlayout2->addWidget(l2); + KComboBox *method = new KComboBox(plainPage()); + // -- fill the combo with available methods + uint i; + for ( i=0; i<tools.count(); ++i ) + method->insertItem( cs_typeToText[tools.at(i)->type], i); + method->setFocus(); + hlayout2->addWidget(method); + layout->addMultiCellLayout(hlayout2, row, row, 0, 1, TQt::AlignLeft); + ++row; + + if (exec() != Accepted) return; + // else implied: run the process + tmpOut = new KTempFile(locateLocal("tmp", "krusader"), ".stdout" ); + tmpErr = new KTempFile(locateLocal("tmp", "krusader"), ".stderr" ); + TDEProcess proc; + CS_Tool *mytool = tools.at(method->currentItem()); + mytool->create(proc, mytool, KrServices::quote(files), TQString(), containFolders, + tmpOut->name(), tmpErr->name(), method->currentText()); + + krApp->startWaiting(i18n("Calculating checksums ..."), 0, true); + TQApplication::setOverrideCursor( KCursor::waitCursor() ); + bool r = proc.start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput); + if (r) while ( proc.isRunning() ) { + usleep( 500 ); + tqApp->processEvents(); + if (krApp->wasWaitingCancelled()) { // user cancelled + proc.kill(); + TQApplication::restoreOverrideCursor(); + return; + } + }; + krApp->stopWait(); + TQApplication::restoreOverrideCursor(); + if (!r || !proc.normalExit()) { + KMessageBox::error(0, i18n("<qt>There was an error while running <b>%1</b>.</qt>").arg(mytool->binary)); + return; + } + + // suggest a filename + TQString suggestedFilename = path + '/'; + if (files.count() > 1) suggestedFilename += ("checksum." + cs_typeToText[mytool->type]); + else suggestedFilename += (files[0] + '.' + cs_typeToText[mytool->type]); + // send both stdout and stderr + TQStringList stdOut, stdErr; + if (!KrServices::fileToStringList(tmpOut->textStream(), stdOut) || + !KrServices::fileToStringList(tmpErr->textStream(), stdErr)) { + KMessageBox::error(krApp, i18n("Error reading stdout or stderr")); + return; + } + + ChecksumResultsDlg dlg( stdOut, stdErr, suggestedFilename, mytool->binary, cs_typeToText[mytool->type], mytool->standardFormat); + tmpOut->unlink(); delete tmpOut; + tmpErr->unlink(); delete tmpErr; +} + +// ------------- MatchChecksumDlg + +TQString MatchChecksumDlg::checksumTypesFilter; + +MatchChecksumDlg::MatchChecksumDlg(const TQStringList& files, bool containFolders, + const TQString& path, const TQString& checksumFile): + KDialogBase(Plain, i18n("Verify Checksum"), Ok | Cancel, Ok, krApp) { + + TQPtrList<CS_Tool> tools = getTools(containFolders); + + if (tools.count() == 0) { // nothing was suggested?! + TQString error = i18n("<qt>Can't verify checksum since no supported tool was found. " + "Please check the <b>Dependencies</b> page in Krusader's settings.</qt>"); + if (containFolders) + error += i18n("<qt><b>Note</b>: you've selected directories, and probably have no recursive checksum tool installed." + " Krusader currently supports <i>md5deep, sha1deep, sha256deep, tigerdeep and cfv</i></qt>"); + KMessageBox::error(0, error); + return; + } + + TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1, + KDialogBase::marginHint(), KDialogBase::spacingHint()); + + int row=0; + + // title (icon+text) + TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint()); + TQLabel *p = new TQLabel(plainPage()); + p->setPixmap(krLoader->loadIcon("application-octet-stream", TDEIcon::Desktop, 32)); + hlayout->addWidget(p); + TQLabel *l1 = new TQLabel(i18n("About to verify checksum for the following files") + + (containFolders ? i18n(" and folders:") : ":"), plainPage()); + hlayout->addWidget(l1); + layout->addMultiCellLayout(hlayout, row, row, 0, 1, TQt::AlignLeft); + ++row; + + // file list + TDEListBox *lb = new TDEListBox(plainPage()); + lb->insertStringList(files); + layout->addMultiCellWidget(lb, row, row, 0, 1); + ++row; + + // checksum file + TQHBoxLayout *hlayout2 = new TQHBoxLayout(layout, KDialogBase::spacingHint()); + TQLabel *l2 = new TQLabel(i18n("Checksum file:"), plainPage()); + hlayout2->addWidget(l2); + KURLRequester *checksumFileReq = new KURLRequester( plainPage() ); + if (!checksumFile.isEmpty()) + checksumFileReq->setURL(checksumFile); + checksumFileReq->fileDialog()->setURL(path); + checksumFileReq->setFocus(); + hlayout2->addWidget(checksumFileReq); + layout->addMultiCellLayout(hlayout2, row, row, 0, 1, TQt::AlignLeft); + + if (exec() != Accepted) return; + TQString file = checksumFileReq->url(); + TQString extension; + if (!verifyChecksumFile(file, extension)) { + KMessageBox::error(0, i18n("<qt>Error reading checksum file <i>%1</i>.<br />Please specify a valid checksum file.</qt>").arg(file)); + return; + } + + // do we have a tool for that extension? + uint i; + CS_Tool *mytool = 0; + for ( i=0; i < tools.count(); ++i ) + if (cs_typeToText[tools.at(i)->type] == extension.lower()) { + mytool = tools.at(i); + break; + } + if (!mytool) { + KMessageBox::error(0, i18n("<qt>Krusader can't find a checksum tool that handles %1 on your system. Please check the <b>Dependencies</b> page in Krusader's settings.</qt>").arg(extension)); + return; + } + + // else implied: run the process + tmpOut = new KTempFile(locateLocal("tmp", "krusader"), ".stdout" ); + tmpErr = new KTempFile(locateLocal("tmp", "krusader"), ".stderr" ); + TDEProcess proc; + mytool->verify(proc, mytool, KrServices::quote(files), KrServices::quote(file), containFolders, tmpOut->name(), tmpErr->name(), extension); + krApp->startWaiting(i18n("Verifying checksums ..."), 0, true); + TQApplication::setOverrideCursor( KCursor::waitCursor() ); + bool r = proc.start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput); + if (r) while ( proc.isRunning() ) { + usleep( 500 ); + tqApp->processEvents(); + if (krApp->wasWaitingCancelled()) { // user cancelled + proc.kill(); + TQApplication::restoreOverrideCursor(); + return; + } + }; + if (!r || !proc.normalExit()) { + KMessageBox::error(0, i18n("<qt>There was an error while running <b>%1</b>.</qt>").arg(mytool->binary)); + return; + } + TQApplication::restoreOverrideCursor(); + krApp->stopWait(); + // send both stdout and stderr + TQStringList stdOut,stdErr; + if (!KrServices::fileToStringList(tmpOut->textStream(), stdOut) || + !KrServices::fileToStringList(tmpErr->textStream(), stdErr)) { + KMessageBox::error(krApp, i18n("Error reading stdout or stderr")); + return; + } + VerifyResultDlg dlg(mytool->failed(stdOut, stdErr)); + tmpOut->unlink(); delete tmpOut; + tmpErr->unlink(); delete tmpErr; +} + +bool MatchChecksumDlg::verifyChecksumFile(TQString path, TQString& extension) { + TQFileInfo f(path); + if (!f.exists() || f.isDir()) return false; + // find the extension + extension = path.mid(path.findRev(".")+1); + + // TODO: do we know the extension? if not, ask the user for one + + + return true; +} + +// ------------- VerifyResultDlg +VerifyResultDlg::VerifyResultDlg(const TQStringList& failed): + KDialogBase(Plain, i18n("Verify Checksum"), Close, Close, krApp) { + TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1, + KDialogBase::marginHint(), KDialogBase::spacingHint()); + + bool errors = failed.size()>0; + int row = 0; + + // create the icon and title + TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint()); + TQLabel p(plainPage()); + p.setPixmap(krLoader->loadIcon(errors ? "messagebox_critical" : "messagebox_info", TDEIcon::Desktop, 32)); + hlayout->addWidget(&p); + + TQLabel *l1 = new TQLabel((errors ? i18n("Errors were detected while verifying the checksums") : + i18n("Checksums were verified successfully")), plainPage()); + hlayout->addWidget(l1); + layout->addMultiCellLayout(hlayout,row,row,0,1, TQt::AlignLeft); + ++row; + + if (errors) { + TQLabel *l3 = new TQLabel(i18n("The following files have failed:"), plainPage()); + layout->addMultiCellWidget(l3, row, row, 0, 1); + ++row; + TDEListBox *lb2 = new TDEListBox(plainPage()); + lb2->insertStringList(failed); + layout->addMultiCellWidget(lb2, row, row, 0, 1); + ++row; + } + + exec(); +} + +// ------------- ChecksumResultsDlg + +ChecksumResultsDlg::ChecksumResultsDlg(const TQStringList& stdOut, const TQStringList& stdErr, + const TQString& suggestedFilename, const TQString& binary, const TQString& /* type */, bool standardFormat): + KDialogBase(Plain, i18n("Create Checksum"), Ok | Cancel, Ok, krApp), _binary(binary) { + TQGridLayout *layout = new TQGridLayout( plainPage(), 1, 1, + KDialogBase::marginHint(), KDialogBase::spacingHint()); + + // md5 tools display errors into stderr, so we'll use that to determine the result of the job + bool errors = stdErr.size()>0; + bool successes = stdOut.size()>0; + int row = 0; + + // create the icon and title + TQHBoxLayout *hlayout = new TQHBoxLayout(layout, KDialogBase::spacingHint()); + TQLabel p(plainPage()); + p.setPixmap(krLoader->loadIcon(errors ? "messagebox_critical" : "messagebox_info", TDEIcon::Desktop, 32)); + hlayout->addWidget(&p); + + TQLabel *l1 = new TQLabel((errors ? i18n("Errors were detected while creating the checksums") : + i18n("Checksums were created successfully")), plainPage()); + hlayout->addWidget(l1); + layout->addMultiCellLayout(hlayout,row,row,0,1, TQt::AlignLeft); + ++row; + + if (successes) { + if (errors) { + TQLabel *l2 = new TQLabel(i18n("Here are the calculated checksums:"), plainPage()); + layout->addMultiCellWidget(l2, row, row, 0, 1); + ++row; + } + TDEListView *lv = new TDEListView(plainPage()); + if(standardFormat){ + lv->addColumn(i18n("Hash")); + lv->addColumn(i18n("File")); + lv->setAllColumnsShowFocus(true); + } else { + lv->addColumn(i18n("File and hash")); + } + for ( TQStringList::ConstIterator it = stdOut.begin(); it != stdOut.end(); ++it ) { + TQString line = (*it); + if(standardFormat) { + int space = line.find(' '); + new TDEListViewItem(lv, line.left(space), line.mid(space+2)); + } else { + new TDEListViewItem(lv, line); + } + } + layout->addMultiCellWidget(lv, row, row, 0, 1); + ++row; + } + + if (errors) { + TQFrame *line1 = new TQFrame( plainPage() ); + line1->setGeometry( TQRect( 60, 210, 501, 20 ) ); + line1->setFrameShape( TQFrame::HLine ); + line1->setFrameShadow( TQFrame::Sunken ); + layout->addMultiCellWidget(line1, row, row, 0, 1); + ++row; + + TQLabel *l3 = new TQLabel(i18n("Here are the errors received:"), plainPage()); + layout->addMultiCellWidget(l3, row, row, 0, 1); + ++row; + TDEListBox *lb = new TDEListBox(plainPage()); + lb->insertStringList(stdErr); + layout->addMultiCellWidget(lb, row, row, 0, 1); + ++row; + } + + // save checksum to disk, if any hashes are found + KURLRequester *checksumFile=0; + TQCheckBox *saveFileCb=0; + if (successes) { + TQHBoxLayout *hlayout2 = new TQHBoxLayout(layout, KDialogBase::spacingHint()); + saveFileCb = new TQCheckBox(i18n("Save checksum to file:"), plainPage()); + saveFileCb->setChecked(true); + hlayout2->addWidget(saveFileCb); + + checksumFile = new KURLRequester( suggestedFilename, plainPage() ); + hlayout2->addWidget(checksumFile, TQt::AlignLeft); + layout->addMultiCellLayout(hlayout2, row, row,0,1, TQt::AlignLeft); + ++row; + connect(saveFileCb, TQ_SIGNAL(toggled(bool)), checksumFile, TQ_SLOT(setEnabled(bool))); + checksumFile->setFocus(); + } + + TQCheckBox *onePerFile=0; + if (stdOut.size() > 1 && standardFormat) { + onePerFile = new TQCheckBox(i18n("Checksum file for each source file"), plainPage()); + onePerFile->setChecked(false); + // clicking this, disables the 'save as' part + connect(onePerFile, TQ_SIGNAL(toggled(bool)), saveFileCb, TQ_SLOT(toggle())); + connect(onePerFile, TQ_SIGNAL(toggled(bool)), saveFileCb, TQ_SLOT(setDisabled(bool))); + connect(onePerFile, TQ_SIGNAL(toggled(bool)), checksumFile, TQ_SLOT(setDisabled(bool))); + layout->addMultiCellWidget(onePerFile, row, row,0,1, TQt::AlignLeft); + ++row; + } + + if (exec() == Accepted && successes) { + if (stdOut.size()>1 && standardFormat && onePerFile->isChecked()) { + savePerFile(stdOut, suggestedFilename.mid(suggestedFilename.findRev('.'))); + } else if (saveFileCb->isEnabled() && saveFileCb->isChecked() && !checksumFile->url().simplifyWhiteSpace().isEmpty()) { + saveChecksum(stdOut, checksumFile->url()); + } + } +} + +bool ChecksumResultsDlg::saveChecksum(const TQStringList& data, TQString filename) { + if (TQFile::exists(filename) && + KMessageBox::warningContinueCancel(this, + i18n("File %1 already exists.\nAre you sure you want to overwrite it?").arg(filename), + i18n("Warning"), i18n("Overwrite")) != KMessageBox::Continue) { + // find a better name to save to + filename = KFileDialog::getSaveFileName(TQString(), "*", 0, i18n("Select a file to save to")); + if (filename.simplifyWhiteSpace().isEmpty()) return false; + } + TQFile file(filename); + if (!file.open(IO_WriteOnly)) { + KMessageBox::detailedError(0, i18n("Error saving file %1").arg(filename), + file.errorString()); + return false; + } + TQTextStream stream(&file); + for ( TQStringList::ConstIterator it = data.constBegin(); it != data.constEnd(); ++it) + stream << *it << "\n"; + file.close(); + return true; +} + +void ChecksumResultsDlg::savePerFile(const TQStringList& data, const TQString& type) { + krApp->startWaiting(i18n("Saving checksum files..."), 0); + for ( TQStringList::ConstIterator it = data.begin(); it != data.end(); ++it ) { + TQString line = (*it); + TQString filename = line.mid(line.find(' ')+2)+type; + if (!saveChecksum(*it, filename)) { + KMessageBox::error(0, i18n("Errors occured while saving multiple checksums. Stopping")); + krApp->stopWait(); + return; + } + } + krApp->stopWait(); +} |