File indexing completed on 2025-03-09 04:54:12
0001 /* 0002 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com> 0003 0004 Based on KMail code by various authors (kmmsgpartdlg). 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "attachmentpropertiesdialog.h" 0010 0011 #include "attachmentfrommimecontentjob.h" 0012 #include "ui_attachmentpropertiesdialog.h" 0013 #include "ui_attachmentpropertiesdialog_readonly.h" 0014 0015 #include "messagecore_debug.h" 0016 #include <KAboutData> 0017 0018 #include <KMime/Content> 0019 #include <KMime/Headers> 0020 0021 #include <KIO/Global> 0022 #include <KLocalizedString> 0023 #include <QDesktopServices> 0024 #include <QDialogButtonBox> 0025 #include <QMimeDatabase> 0026 #include <QMimeType> 0027 #include <QPushButton> 0028 #include <QUrlQuery> 0029 #include <QVBoxLayout> 0030 0031 using namespace MessageCore; 0032 0033 class Q_DECL_HIDDEN MessageCore::AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate 0034 { 0035 public: 0036 AttachmentPropertiesDialogPrivate(AttachmentPropertiesDialog *qq) 0037 : q(qq) 0038 { 0039 } 0040 0041 ~AttachmentPropertiesDialogPrivate() 0042 { 0043 delete ui; 0044 delete uiReadOnly; 0045 } 0046 0047 void init(const AttachmentPart::Ptr &part, bool readOnly); 0048 void polishUi(); 0049 void mimeTypeChanged(const QString &type); // slot 0050 void populateEncodings(); 0051 void populateMimeTypes(); 0052 void populateWhatsThis(); 0053 void loadFromPart(); 0054 void saveToPart(); 0055 0056 AttachmentPropertiesDialog *const q; 0057 AttachmentPart::Ptr mPart; 0058 0059 Ui::AttachmentPropertiesDialog *ui = nullptr; 0060 Ui::AttachmentPropertiesDialogReadOnly *uiReadOnly = nullptr; 0061 QVBoxLayout *mainLayout = nullptr; 0062 bool mReadOnly = false; 0063 }; 0064 0065 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::init(const AttachmentPart::Ptr &part, bool readOnly) 0066 { 0067 mReadOnly = readOnly; 0068 mPart = part; 0069 0070 auto widget = new QWidget(q); 0071 mainLayout = new QVBoxLayout; 0072 q->setLayout(mainLayout); 0073 0074 mainLayout->addWidget(widget); 0075 if (mReadOnly) { 0076 uiReadOnly = new Ui::AttachmentPropertiesDialogReadOnly; 0077 uiReadOnly->setupUi(widget); 0078 } else { 0079 ui = new Ui::AttachmentPropertiesDialog; 0080 ui->setupUi(widget); 0081 } 0082 polishUi(); 0083 q->setModal(true); 0084 0085 loadFromPart(); 0086 } 0087 0088 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::polishUi() 0089 { 0090 // Tweak the dialog, depending on whether it is read-only or not. 0091 QDialogButtonBox *buttonBox = nullptr; 0092 0093 if (mReadOnly) { 0094 buttonBox = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close, q); 0095 } else { 0096 // Update the icon when the selected mime type changes. 0097 0098 connect(ui->mimeType, &QComboBox::currentTextChanged, q, [this](const QString &str) { 0099 mimeTypeChanged(str); 0100 }); 0101 populateMimeTypes(); 0102 populateEncodings(); 0103 buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, q); 0104 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); 0105 okButton->setDefault(true); 0106 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0107 } 0108 q->connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, q, &AttachmentPropertiesDialog::slotHelp); 0109 q->connect(buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept); 0110 q->connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); 0111 mainLayout->addWidget(buttonBox); 0112 populateWhatsThis(); 0113 } 0114 0115 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::mimeTypeChanged(const QString &type) 0116 { 0117 QMimeDatabase db; 0118 const QMimeType mimeType = db.mimeTypeForName(type); 0119 QPixmap pix = 0120 QIcon::fromTheme(mimeType.iconName(), QIcon::fromTheme(QStringLiteral("unknown"))).pixmap(q->style()->pixelMetric(QStyle::PM_MessageBoxIconSize)); 0121 0122 if (mReadOnly) { 0123 uiReadOnly->mimeIcon->setPixmap(pix); 0124 } else { 0125 ui->mimeIcon->setPixmap(pix); 0126 } 0127 } 0128 0129 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::populateWhatsThis() 0130 { 0131 // FIXME These are such a mess... Make them straightforward and pretty. 0132 0133 const QString msgMimeType = i18n( 0134 "<p>The <em>MIME type</em> of the file:</p>" 0135 "<p>Normally, you do not need to touch this setting, since the " 0136 "type of the file is automatically checked; but, sometimes, %1 " 0137 "may not detect the type correctly -- here is where you can fix " 0138 "that.</p>", 0139 KAboutData::applicationData().componentName()); 0140 0141 const QString msgSize = i18n( 0142 "<p>The estimated size of the attachment:</p>" 0143 "<p>Note that, in an email message, a binary file encoded with " 0144 "base64 will take up four thirds the actual size of the file.</p>"); 0145 0146 const QString msgName = i18n( 0147 "<p>The file name of the part:</p>" 0148 "<p>Although this defaults to the name of the attached file, " 0149 "it does not specify the file to be attached; rather, it " 0150 "suggests a file name to be used by the recipient's mail agent " 0151 "when saving the part to disk.</p>"); 0152 0153 const QString msgDescription = i18n( 0154 "<p>A description of the part:</p>" 0155 "<p>This is just an informational description of the part, " 0156 "much like the Subject is for the whole message; most " 0157 "mail agents will show this information in their message " 0158 "previews alongside the attachment's icon.</p>"); 0159 0160 const QString msgEncoding = i18n( 0161 "<p>The transport encoding of this part:</p>" 0162 "<p>Normally, you do not need to change this, since %1 will use " 0163 "a decent default encoding, depending on the MIME type; yet, " 0164 "sometimes, you can significantly reduce the size of the " 0165 "resulting message, e.g. if a PostScript file does not contain " 0166 "binary data, but consists of pure text -- in this case, choosing " 0167 "\"quoted-printable\" over the default \"base64\" will save up " 0168 "to 25% in resulting message size.</p>", 0169 KAboutData::applicationData().componentName()); 0170 0171 const QString msgAutoDisplay = i18n( 0172 "<p>Check this option if you want to suggest to the " 0173 "recipient the automatic (inline) display of this part in the " 0174 "message preview, instead of the default icon view;</p>" 0175 "<p>Technically, this is carried out by setting this part's " 0176 "<em>Content-Disposition</em> header field to \"inline\" " 0177 "instead of the default \"attachment\".</p>"); 0178 0179 const QString msgSign = i18n( 0180 "<p>Check this option if you want this message part to be " 0181 "signed.</p>" 0182 "<p>The signature will be made with the key that you associated " 0183 "with the currently-selected identity.</p>"); 0184 0185 const QString msgEncrypt = i18n( 0186 "<p>Check this option if you want this message part to be " 0187 "encrypted.</p>" 0188 "<p>The part will be encrypted for the recipients of this " 0189 "message.</p>"); 0190 0191 if (mReadOnly) { 0192 uiReadOnly->size->setWhatsThis(msgSize); 0193 uiReadOnly->name->setWhatsThis(msgName); 0194 uiReadOnly->encoding->setWhatsThis(msgEncoding); 0195 } else { 0196 ui->mimeType->setWhatsThis(msgMimeType); 0197 ui->size->setWhatsThis(msgSize); 0198 ui->name->setWhatsThis(msgName); 0199 ui->encrypt->setWhatsThis(msgEncrypt); 0200 ui->sign->setWhatsThis(msgSign); 0201 ui->autoDisplay->setWhatsThis(msgAutoDisplay); 0202 ui->encoding->setWhatsThis(msgEncoding); 0203 ui->description->setWhatsThis(msgDescription); 0204 } 0205 } 0206 0207 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::populateEncodings() 0208 { 0209 using namespace KMime; 0210 using namespace KMime::Headers; 0211 0212 ui->encoding->clear(); 0213 ui->encoding->addItem(nameForEncoding(CE7Bit), int(CE7Bit)); 0214 ui->encoding->addItem(nameForEncoding(CE8Bit), int(CE8Bit)); 0215 ui->encoding->addItem(nameForEncoding(CEquPr), int(CEquPr)); 0216 ui->encoding->addItem(nameForEncoding(CEbase64), int(CEbase64)); 0217 0218 // TODO 8bit should be disabled if it is disabled in Settings. 0219 // Also, if it's a message/* part, base64 and qp should be disabled. 0220 // But since this is a dialog for power users anyway, let them shoot 0221 // themselves in the foot. (The AttachmentJob will fail when they 0222 // try to compose the message.) 0223 } 0224 0225 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::populateMimeTypes() 0226 { 0227 const QStringList list = QStringList() << QStringLiteral("text/html") << QStringLiteral("text/plain") << QStringLiteral("image/gif") 0228 << QStringLiteral("image/jpeg") << QStringLiteral("image/png") << QStringLiteral("application/octet-stream") 0229 << QStringLiteral("application/x-gunzip") << QStringLiteral("application/zip"); 0230 0231 ui->mimeType->addItems(list); 0232 } 0233 0234 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::loadFromPart() 0235 { 0236 Q_ASSERT(mPart); 0237 0238 if (mReadOnly) { 0239 uiReadOnly->mimeType->setText(QString::fromLatin1(mPart->mimeType())); 0240 mimeTypeChanged(QString::fromLatin1(mPart->mimeType())); 0241 uiReadOnly->size->setText(KIO::convertSize(mPart->size())); 0242 uiReadOnly->name->setText(mPart->name().isEmpty() ? mPart->fileName() : mPart->name()); 0243 if (mPart->description().isEmpty()) { 0244 uiReadOnly->description->hide(); 0245 uiReadOnly->descriptionLabel->hide(); 0246 } else { 0247 uiReadOnly->description->setText(mPart->description()); 0248 } 0249 uiReadOnly->encoding->setText(KMime::nameForEncoding(mPart->encoding())); 0250 } else { 0251 const QString mimeType = QString::fromLatin1(mPart->mimeType()); 0252 const int index = ui->mimeType->findText(mimeType); 0253 if (index == -1) { 0254 ui->mimeType->insertItem(0, mimeType); 0255 ui->mimeType->setCurrentIndex(0); 0256 } else { 0257 ui->mimeType->setCurrentIndex(index); 0258 } 0259 ui->size->setText(KIO::convertSize(mPart->size())); 0260 ui->name->setText(mPart->name().isEmpty() ? mPart->fileName() : mPart->name()); 0261 ui->description->setText(mPart->description()); 0262 ui->encoding->setCurrentIndex(int(mPart->encoding())); 0263 ui->autoDisplay->setChecked(mPart->isInline()); 0264 ui->encrypt->setChecked(mPart->isEncrypted()); 0265 ui->sign->setChecked(mPart->isSigned()); 0266 } 0267 } 0268 0269 static QString removeNewlines(const QString &input) 0270 { 0271 QString ret(input); 0272 ret.replace(QLatin1Char('\n'), QLatin1Char(' ')); 0273 return ret; 0274 } 0275 0276 void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::saveToPart() 0277 { 0278 Q_ASSERT(mPart); 0279 Q_ASSERT(!mReadOnly); 0280 0281 if (mReadOnly) { 0282 return; 0283 } 0284 mPart->setMimeType(ui->mimeType->currentText().toLatin1()); 0285 const QString name = removeNewlines(ui->name->text()); 0286 mPart->setName(name); 0287 mPart->setFileName(name); 0288 mPart->setDescription(removeNewlines(ui->description->text())); 0289 mPart->setInline(ui->autoDisplay->isChecked()); 0290 mPart->setSigned(ui->sign->isChecked()); 0291 mPart->setEncrypted(ui->encrypt->isChecked()); 0292 mPart->setInline(ui->autoDisplay->isChecked()); 0293 0294 if (ui->mimeType->currentText().startsWith(QLatin1StringView("message")) && ui->encoding->itemData(ui->encoding->currentIndex()) != KMime::Headers::CE7Bit 0295 && ui->encoding->itemData(ui->encoding->currentIndex()) != KMime::Headers::CE8Bit) { 0296 qCWarning(MESSAGECORE_LOG) << R"(Encoding on message/rfc822 must be "7bit" or "8bit".)"; 0297 } 0298 0299 mPart->setEncoding(KMime::Headers::contentEncoding(ui->encoding->itemData(ui->encoding->currentIndex()).toInt())); 0300 } 0301 0302 AttachmentPropertiesDialog::AttachmentPropertiesDialog(const AttachmentPart::Ptr &part, bool readOnly, QWidget *parent) 0303 : QDialog(parent) 0304 , d(new AttachmentPropertiesDialogPrivate(this)) 0305 { 0306 d->init(part, readOnly); 0307 setWindowTitle(i18nc("@title:window", "Attachment Properties")); 0308 } 0309 0310 AttachmentPropertiesDialog::AttachmentPropertiesDialog(const KMime::Content *content, QWidget *parent) 0311 : QDialog(parent) 0312 , d(new AttachmentPropertiesDialogPrivate(this)) 0313 { 0314 auto job = new AttachmentFromMimeContentJob(content, this); 0315 job->exec(); 0316 if (job->error()) { 0317 qCCritical(MESSAGECORE_LOG) << "AttachmentFromMimeContentJob failed." << job->errorString(); 0318 } 0319 0320 const AttachmentPart::Ptr part = job->attachmentPart(); 0321 d->init(part, true); 0322 setWindowTitle(i18nc("@title:window", "Attachment Properties")); 0323 } 0324 0325 AttachmentPropertiesDialog::~AttachmentPropertiesDialog() = default; 0326 0327 AttachmentPart::Ptr AttachmentPropertiesDialog::attachmentPart() const 0328 { 0329 return d->mPart; 0330 } 0331 0332 bool AttachmentPropertiesDialog::isEncryptEnabled() const 0333 { 0334 if (d->ui) { 0335 return d->ui->encrypt->isEnabled(); 0336 } 0337 return false; 0338 } 0339 0340 void AttachmentPropertiesDialog::setEncryptEnabled(bool enabled) 0341 { 0342 if (d->ui) { 0343 d->ui->encrypt->setEnabled(enabled); 0344 } 0345 } 0346 0347 bool AttachmentPropertiesDialog::isSignEnabled() const 0348 { 0349 if (d->ui) { 0350 return d->ui->sign->isEnabled(); 0351 } 0352 return false; 0353 } 0354 0355 void AttachmentPropertiesDialog::setSignEnabled(bool enabled) 0356 { 0357 if (d->ui) { 0358 d->ui->sign->setEnabled(enabled); 0359 } 0360 } 0361 0362 void AttachmentPropertiesDialog::accept() 0363 { 0364 if (!d->mReadOnly) { 0365 d->saveToPart(); 0366 } 0367 0368 QDialog::accept(); 0369 } 0370 0371 // Copy from PimCommon::Util::invokeHelp 0372 // Avoid to add PimCommon dep for this method 0373 void invokeHelp(const QString &docfile, const QString &anchor) 0374 { 0375 if (!docfile.isEmpty()) { 0376 QUrl url; 0377 url = QUrl(QStringLiteral("help:/")).resolved(QUrl(docfile)); 0378 if (!anchor.isEmpty()) { 0379 QUrlQuery query(url); 0380 query.addQueryItem(QStringLiteral("anchor"), anchor); 0381 url.setQuery(query); 0382 } 0383 // launch khelpcenter, or a browser for URIs not handled by khelpcenter 0384 QDesktopServices::openUrl(url); 0385 } 0386 } 0387 0388 void AttachmentPropertiesDialog::slotHelp() 0389 { 0390 invokeHelp(QStringLiteral("kmail2/the-composer-window.html"), QStringLiteral("attachments")); 0391 } 0392 0393 #include "moc_attachmentpropertiesdialog.cpp"