File indexing completed on 2025-03-09 04:54:12

0001 /*
0002     SPDX-FileCopyrightText: 2011 Martin Bednár <serafean@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "attachmentfromfolderjob.h"
0008 
0009 #include "messagecore_debug.h"
0010 #include <KLocalizedString>
0011 
0012 #include <QBuffer>
0013 #include <QDir>
0014 #include <QScopedPointer>
0015 #include <QSharedPointer>
0016 
0017 static const mode_t archivePermsAttachment = S_IFREG | 0644;
0018 
0019 using namespace MessageCore;
0020 
0021 class AttachmentFromFolderJob::AttachmentLoadJobPrivate
0022 {
0023 public:
0024     AttachmentLoadJobPrivate(AttachmentFromFolderJob *qq);
0025 
0026     void compressFolder();
0027     void addEntity(const QFileInfoList &f, const QString &path);
0028 
0029     AttachmentFromFolderJob *const q;
0030     KZip::Compression mCompression = KZip::DeflateCompression;
0031     AttachmentPart::Ptr mCompressedFolder;
0032     QScopedPointer<KZip> mZip;
0033     QDateTime mArchiveTime = QDateTime::currentDateTime();
0034 };
0035 
0036 AttachmentFromFolderJob::AttachmentLoadJobPrivate::AttachmentLoadJobPrivate(AttachmentFromFolderJob *qq)
0037     : q(qq)
0038     , mZip(nullptr)
0039 {
0040 }
0041 
0042 void AttachmentFromFolderJob::AttachmentLoadJobPrivate::compressFolder()
0043 {
0044     qCDebug(MESSAGECORE_LOG) << "starting compression";
0045     QString fileName = q->url().fileName();
0046     QByteArray array;
0047     QBuffer dev(&array);
0048     mZip.reset(new KZip(&dev));
0049     if (!mZip->open(QIODevice::WriteOnly)) {
0050         q->setError(KJob::UserDefinedError);
0051         q->setErrorText(i18n("Could not create compressed file."));
0052         q->emitResult();
0053         return;
0054     }
0055     mZip->setCompression(mCompression);
0056     const QString filename = q->url().fileName();
0057     if (!mZip->writeDir(filename, QString(), QString(), 040755, mArchiveTime, mArchiveTime, mArchiveTime)) {
0058         qCWarning(MESSAGECORE_LOG) << " Impossible to write file " << fileName;
0059     }
0060     qCDebug(MESSAGECORE_LOG) << "writing root directory : " << filename;
0061     addEntity(QDir(q->url().path()).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Files, QDir::DirsFirst),
0062               fileName + QLatin1Char('/'));
0063     mZip->close();
0064 
0065     Q_ASSERT(mCompressedFolder == nullptr);
0066 
0067     mCompressedFolder = AttachmentPart::Ptr(new AttachmentPart);
0068     const QString newName = fileName + QLatin1StringView(".zip");
0069     mCompressedFolder->setName(newName);
0070     mCompressedFolder->setFileName(newName);
0071     mCompressedFolder->setMimeType("application/zip");
0072     mCompressedFolder->setUrl(q->url());
0073     //     mCompressedFolder->setCompressed( true );
0074     mCompressedFolder->setData(array);
0075     //     mCompressedFolder->setCompressible(false);
0076     q->setAttachmentPart(mCompressedFolder);
0077     q->emitResult();
0078 
0079     // TODO:add allowCompression bool to AttachmentPart && modify GUI to disable decompressing.
0080     //  Or leave attachment as uncompressed and let it be compressed again?
0081 }
0082 
0083 void AttachmentFromFolderJob::AttachmentLoadJobPrivate::addEntity(const QFileInfoList &f, const QString &path)
0084 {
0085     for (const QFileInfo &info : f) {
0086         qCDebug(MESSAGECORE_LOG) << q->maximumAllowedSize() << "Attachment size : " << mZip->device()->size();
0087 
0088         if (q->maximumAllowedSize() != -1 && mZip->device()->size() > q->maximumAllowedSize()) {
0089             q->setError(KJob::UserDefinedError);
0090             q->setErrorText(i18n("The resulting attachment would be larger than the maximum allowed size, aborting."));
0091             q->emitResult();
0092             return;
0093         }
0094 
0095         const QString infoFileName = info.fileName();
0096         if (info.isDir()) {
0097             qCDebug(MESSAGECORE_LOG) << "adding directory " << infoFileName << "to zip";
0098             if (!mZip->writeDir(path + infoFileName, QString(), QString(), 040755, mArchiveTime, mArchiveTime, mArchiveTime)) {
0099                 q->setError(KJob::UserDefinedError);
0100                 q->setErrorText(i18n("Could not add %1 to the archive", infoFileName));
0101                 q->emitResult();
0102                 return;
0103             }
0104             addEntity(QDir(info.filePath()).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Files, QDir::DirsFirst),
0105                       path + infoFileName + QLatin1Char('/'));
0106         }
0107 
0108         if (info.isFile()) {
0109             qCDebug(MESSAGECORE_LOG) << "Adding file " << path + infoFileName << "to zip";
0110             QFile file(info.filePath());
0111             if (!file.open(QIODevice::ReadOnly)) {
0112                 q->setError(KJob::UserDefinedError);
0113                 q->setErrorText(i18n("Could not open %1 for reading.", file.fileName()));
0114                 q->emitResult();
0115                 return;
0116             }
0117             if (!mZip->writeFile(path + infoFileName, file.readAll(), archivePermsAttachment, QString(), QString(), mArchiveTime, mArchiveTime, mArchiveTime)) {
0118                 q->setError(KJob::UserDefinedError);
0119                 q->setErrorText(i18n("Could not add %1 to the archive", file.fileName()));
0120                 q->emitResult();
0121             }
0122             file.close();
0123         }
0124     }
0125 }
0126 
0127 AttachmentFromFolderJob::AttachmentFromFolderJob(const QUrl &url, QObject *parent)
0128     : AttachmentFromUrlBaseJob(url, parent)
0129     , d(new AttachmentLoadJobPrivate(this))
0130 {
0131 }
0132 
0133 AttachmentFromFolderJob::~AttachmentFromFolderJob() = default;
0134 
0135 void AttachmentFromFolderJob::setCompression(KZip::Compression compression)
0136 {
0137     d->mCompression = compression;
0138 }
0139 
0140 KZip::Compression AttachmentFromFolderJob::compression() const
0141 {
0142     return d->mCompression;
0143 }
0144 
0145 void AttachmentFromFolderJob::doStart()
0146 {
0147     d->compressFolder();
0148 }
0149 
0150 #include "moc_attachmentfromfolderjob.cpp"