File indexing completed on 2024-05-05 05:50:38
0001 /* 0002 SPDX-FileCopyrightText: 2008 Harald Hvaal <haraldhv@stud.ntnu.no> 0003 SPDX-FileCopyrightText: 2009 Raphael Kubo da Costa <rakuco@FreeBSD.org> 0004 0005 SPDX-License-Identifier: BSD-2-Clause 0006 */ 0007 0008 #include "addtoarchive.h" 0009 #include "archiveentry.h" 0010 #include "ark_debug.h" 0011 #include "createdialog.h" 0012 #include "jobs.h" 0013 0014 #include <KIO/JobTracker> 0015 #include <KJobTrackerInterface> 0016 #include <KLocalizedString> 0017 #include <KMessageBox> 0018 0019 #include <KFileUtils> 0020 #include <QDir> 0021 #include <QFileInfo> 0022 #include <QMimeDatabase> 0023 #include <QPointer> 0024 #include <QTimer> 0025 0026 namespace Kerfuffle 0027 { 0028 AddToArchive::AddToArchive(QObject *parent) 0029 : KJob(parent) 0030 , m_changeToFirstPath(false) 0031 , m_enableHeaderEncryption(false) 0032 { 0033 } 0034 0035 AddToArchive::~AddToArchive() 0036 { 0037 } 0038 0039 void AddToArchive::setAutoFilenameSuffix(const QString &suffix) 0040 { 0041 m_autoFilenameSuffix = suffix; 0042 } 0043 0044 void AddToArchive::setChangeToFirstPath(bool value) 0045 { 0046 m_changeToFirstPath = value; 0047 } 0048 0049 void AddToArchive::setFilename(const QUrl &path) 0050 { 0051 m_filename = path.toLocalFile(); 0052 } 0053 0054 void AddToArchive::setMimeType(const QString &mimeType) 0055 { 0056 m_mimeType = mimeType; 0057 } 0058 0059 void AddToArchive::setPassword(const QString &password) 0060 { 0061 m_password = password; 0062 } 0063 0064 void AddToArchive::setHeaderEncryptionEnabled(bool enabled) 0065 { 0066 m_enableHeaderEncryption = enabled; 0067 } 0068 0069 bool AddToArchive::showAddDialog(QWidget *parentWidget) 0070 { 0071 qCDebug(ARK) << "Opening add dialog"; 0072 0073 if (m_filename.isEmpty()) { 0074 m_filename = getFileNameForEntries(m_entries, QString()); 0075 } 0076 0077 QPointer<Kerfuffle::CreateDialog> dialog = new Kerfuffle::CreateDialog(parentWidget, // parent 0078 i18n("Compress to Archive"), // caption 0079 QUrl::fromLocalFile(QFileInfo(m_filename).path())); // startDir 0080 0081 dialog->setFileName(QFileInfo(m_filename).fileName()); 0082 0083 bool ret = dialog.data()->exec(); 0084 0085 if (ret) { 0086 qCDebug(ARK) << "CreateDialog returned URL:" << dialog.data()->selectedUrl().toString(); 0087 qCDebug(ARK) << "CreateDialog returned mime:" << dialog.data()->currentMimeType().name(); 0088 setFilename(dialog.data()->selectedUrl()); 0089 setMimeType(dialog.data()->currentMimeType().name()); 0090 setPassword(dialog.data()->password()); 0091 setHeaderEncryptionEnabled(dialog.data()->isHeaderEncryptionEnabled()); 0092 m_options.setCompressionLevel(dialog.data()->compressionLevel()); 0093 m_options.setCompressionMethod(dialog.data()->compressionMethod()); 0094 m_options.setEncryptionMethod(dialog.data()->encryptionMethod()); 0095 m_options.setVolumeSize(dialog.data()->volumeSize()); 0096 } 0097 0098 delete dialog.data(); 0099 0100 return ret; 0101 } 0102 0103 bool AddToArchive::addInput(const QUrl &url) 0104 { 0105 Archive::Entry *entry = new Archive::Entry(this); 0106 entry->setFullPath(url.toLocalFile()); 0107 m_entries << entry; 0108 0109 if (m_firstPath.isEmpty()) { 0110 QString firstEntry = url.toLocalFile(); 0111 m_firstPath = QFileInfo(firstEntry).dir().absolutePath(); 0112 } 0113 0114 return true; 0115 } 0116 0117 void AddToArchive::start() 0118 { 0119 qCDebug(ARK) << "Starting job"; 0120 0121 QTimer::singleShot(0, this, &AddToArchive::slotStartJob); 0122 } 0123 0124 bool AddToArchive::doKill() 0125 { 0126 return m_createJob && m_createJob->kill(); 0127 } 0128 0129 void AddToArchive::slotStartJob() 0130 { 0131 if (m_entries.isEmpty()) { 0132 KMessageBox::error(nullptr, i18n("No input files were given.")); 0133 emitResult(); 0134 return; 0135 } 0136 0137 if (m_filename.isEmpty()) { 0138 if (m_autoFilenameSuffix.isEmpty()) { 0139 KMessageBox::error(nullptr, 0140 xi18n("You need to either supply a filename for the archive or a suffix (such as rar, tar.gz) with the " 0141 "<command>--autofilename</command> argument.")); 0142 emitResult(); 0143 return; 0144 } 0145 0146 if (m_firstPath.isEmpty()) { 0147 qCWarning(ARK) << "Weird, this should not happen. no firstpath defined. aborting"; 0148 emitResult(); 0149 return; 0150 } 0151 0152 detectFileName(); 0153 } 0154 0155 if (m_changeToFirstPath) { 0156 if (m_firstPath.isEmpty()) { 0157 qCWarning(ARK) << "Weird, this should not happen. no firstpath defined. aborting"; 0158 emitResult(); 0159 return; 0160 } 0161 0162 const QDir stripDir(m_firstPath); 0163 0164 for (Archive::Entry *entry : std::as_const(m_entries)) { 0165 entry->setFullPath(stripDir.absoluteFilePath(entry->fullPath())); 0166 } 0167 0168 qCDebug(ARK) << "Setting GlobalWorkDir to " << stripDir.path(); 0169 m_options.setGlobalWorkDir(stripDir.path()); 0170 } 0171 0172 m_createJob = Archive::create(m_filename, m_mimeType, m_entries, m_options, this); 0173 0174 m_createJob->setProperty("immediateProgressReporting", m_immediateProgressReporting); 0175 m_createJob->setProperty("destUrl", QUrl::fromLocalFile(m_filename)); 0176 0177 if (!m_password.isEmpty()) { 0178 m_createJob->enableEncryption(m_password, m_enableHeaderEncryption); 0179 } 0180 0181 KIO::getJobTracker()->registerJob(m_createJob); 0182 connect(m_createJob, &KJob::result, this, &AddToArchive::slotFinished); 0183 m_createJob->start(); 0184 } 0185 0186 void AddToArchive::detectFileName() 0187 { 0188 const QString suffix = !m_autoFilenameSuffix.isEmpty() ? m_autoFilenameSuffix : QString(); 0189 const QString finalName = getFileNameForEntries(m_entries, suffix); 0190 0191 qCDebug(ARK) << "Autoset filename to" << finalName; 0192 m_filename = finalName; 0193 } 0194 0195 void AddToArchive::slotFinished(KJob *job) 0196 { 0197 qCDebug(ARK) << "job finished"; 0198 0199 if (job->error() && !job->errorString().isEmpty()) { 0200 KMessageBox::error(nullptr, job->errorString()); 0201 } 0202 0203 emitResult(); 0204 } 0205 0206 QString findCommonPrefixForUrls(const QList<QUrl> &list) 0207 { 0208 Q_ASSERT(!list.isEmpty()); 0209 QString prefix = list.front().fileName(); 0210 for (QList<QUrl>::const_iterator it = list.begin(); it != list.end(); ++it) { 0211 QString fileName = it->fileName(); 0212 // Strip filename of its extension, but only if present (see #362690). 0213 // Use loops to handle cases like `*.tar.gz`. 0214 while (!QMimeDatabase().mimeTypeForFile(fileName, QMimeDatabase::MatchExtension).isDefault()) { 0215 const QString strippedName = QFileInfo(fileName).completeBaseName(); 0216 if (strippedName == fileName) { 0217 break; 0218 } 0219 fileName = strippedName; 0220 } 0221 0222 if (prefix.length() > fileName.length()) { 0223 prefix.truncate(fileName.length()); 0224 } 0225 0226 for (int i = 0; i < prefix.length(); ++i) { 0227 if (prefix.at(i) != fileName.at(i)) { 0228 prefix.truncate(i); 0229 break; 0230 } 0231 } 0232 } 0233 0234 return prefix; 0235 } 0236 0237 QString AddToArchive::getFileNameForUrls(const QList<QUrl> &urls, const QString &suffix) 0238 { 0239 Q_ASSERT(!urls.isEmpty()); 0240 0241 const QFileInfo fileInfo = QFileInfo(urls.constFirst().toLocalFile()); 0242 QString base = findCommonPrefixForUrls(urls); 0243 if (urls.size() > 1 && base.length() < 5) { 0244 base = i18nc("Default name of a newly-created multi-file archive", "Archive"); 0245 } 0246 0247 const QString path = fileInfo.absolutePath() + QStringLiteral("/"); 0248 0249 if (suffix.isEmpty()) { 0250 return path + base; 0251 } 0252 QString finalName = base + QLatin1Char('.') + suffix; 0253 if (QFileInfo::exists(path + finalName)) { 0254 finalName = KFileUtils::suggestName(QUrl::fromLocalFile(path), finalName); 0255 } 0256 return path + finalName; 0257 } 0258 0259 QString AddToArchive::getFileNameForEntries(const QVector<Archive::Entry *> &entries, const QString &suffix) 0260 { 0261 QList<QUrl> urls; 0262 for (const auto &entry : entries) { 0263 urls.append(QUrl::fromLocalFile(entry->fullPath())); 0264 } 0265 return getFileNameForUrls(urls, suffix); 0266 } 0267 0268 void AddToArchive::setImmediateProgressReporting(bool immediateProgressReporting) 0269 { 0270 m_immediateProgressReporting = immediateProgressReporting; 0271 } 0272 } 0273 0274 #include "moc_addtoarchive.cpp"