File indexing completed on 2024-04-21 05:50:43
0001 /* 0002 SPDX-FileCopyrightText: 2008-2022 Rolf Eike Beer <kde@opensource.sf-tec.de> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "kgpgtransaction.h" 0007 #include "kgpg_transactions_debug.h" 0008 #include "kgpg_general_debug.h" 0009 #include "kgpgtransactionprivate.h" 0010 0011 #include "gpgproc.h" 0012 #include "kgpginterface.h" 0013 0014 #include <QByteArray> 0015 0016 #include <QUrl> 0017 #include <QWidget> 0018 0019 #include <KConfigGroup> 0020 #include <KNewPasswordDialog> 0021 #include <KLocalizedString> 0022 #include <KPasswordDialog> 0023 0024 KGpgTransaction::KGpgTransaction(QObject *parent, const bool allowChaining) 0025 : QObject(parent), 0026 d(new KGpgTransactionPrivate(this, allowChaining)) 0027 { 0028 } 0029 0030 KGpgTransaction::~KGpgTransaction() 0031 { 0032 delete d; 0033 } 0034 0035 void 0036 KGpgTransaction::start() 0037 { 0038 d->m_inputProcessResult = false; 0039 d->m_inputProcessDone = (d->m_inputTransaction == nullptr); 0040 0041 setSuccess(TS_OK); 0042 d->m_idhints.clear(); 0043 d->m_tries = 3; 0044 if (preStart()) { 0045 d->m_ownProcessFinished = false; 0046 if (d->m_inputTransaction != nullptr) 0047 d->m_inputTransaction->start(); 0048 #ifdef KGPG_DEBUG_TRANSACTIONS 0049 qCDebug(KGPG_LOG_TRANSACTIONS) << this << d->m_process->program(); 0050 #endif /* KGPG_DEBUG_TRANSACTIONS */ 0051 d->m_process->start(); 0052 Q_EMIT infoProgress(0, 1); 0053 } else { 0054 Q_EMIT done(d->m_success); 0055 } 0056 } 0057 0058 void 0059 KGpgTransaction::write(const QByteArray &a, const bool lf) 0060 { 0061 if (lf) 0062 d->write(a + '\n'); 0063 else 0064 d->write(a); 0065 } 0066 0067 void 0068 KGpgTransaction::write(const int i) 0069 { 0070 write(QByteArray::number(i)); 0071 } 0072 0073 void 0074 KGpgTransaction::askNewPassphrase(const QString& text) 0075 { 0076 Q_EMIT statusMessage(i18n("Requesting Passphrase")); 0077 0078 d->m_newPasswordDialog = new KNewPasswordDialog(qobject_cast<QWidget *>(parent())); 0079 d->m_newPasswordDialog->setPrompt(text); 0080 d->m_newPasswordDialog->setAllowEmptyPasswords(false); 0081 connect(d->m_newPasswordDialog, &KNewPasswordDialog::newPassword, d, &KGpgTransactionPrivate::slotPassphraseEntered); 0082 connect(d->m_newPasswordDialog, &KNewPasswordDialog::rejected, d, &KGpgTransactionPrivate::slotPassphraseAborted); 0083 connect(d->m_process, &GPGProc::processExited, d->m_newPasswordDialog, &KNewPasswordDialog::rejected); 0084 d->m_newPasswordDialog->show(); 0085 } 0086 0087 int 0088 KGpgTransaction::getSuccess() const 0089 { 0090 return d->m_success; 0091 } 0092 0093 void 0094 KGpgTransaction::setSuccess(const int v) 0095 { 0096 #ifdef KGPG_DEBUG_TRANSACTIONS 0097 qCDebug(KGPG_LOG_TRANSACTIONS) << "old" << d->m_success << "new" << v; 0098 #endif /* KGPG_DEBUG_TRANSACTIONS */ 0099 d->m_success = v; 0100 } 0101 0102 KGpgTransaction::ts_boolanswer 0103 KGpgTransaction::boolQuestion(const QString& line) 0104 { 0105 Q_UNUSED(line) 0106 0107 return BA_UNKNOWN; 0108 } 0109 0110 KGpgTransaction::ts_boolanswer 0111 KGpgTransaction::confirmOverwrite(QUrl ¤tFile) 0112 { 0113 Q_UNUSED(currentFile) 0114 0115 return BA_UNKNOWN; 0116 } 0117 0118 bool 0119 KGpgTransaction::hintLine(const ts_hintType hint, const QString &args) 0120 { 0121 switch (hint) { 0122 case HT_KEYEXPIRED: 0123 case HT_PINENTRY_LAUNCHED: 0124 return !args.isEmpty(); 0125 default: 0126 return true; 0127 } 0128 } 0129 0130 void 0131 KGpgTransaction::finish() 0132 { 0133 } 0134 0135 void 0136 KGpgTransaction::setDescription(const QString &description) 0137 { 0138 d->m_description = description; 0139 } 0140 0141 void 0142 KGpgTransaction::waitForInputTransaction() 0143 { 0144 Q_ASSERT(d->m_inputTransaction != nullptr); 0145 0146 if (d->m_inputProcessDone) 0147 return; 0148 0149 d->m_inputTransaction->waitForFinished(); 0150 } 0151 0152 void 0153 KGpgTransaction::unexpectedLine(const QString &line) 0154 { 0155 qCDebug(KGPG_LOG_GENERAL) << this << "unexpected input line" << line << "for command" << d->m_process->program(); 0156 } 0157 0158 bool 0159 KGpgTransaction::passphraseRequested() 0160 { 0161 return askPassphrase(); 0162 } 0163 0164 bool 0165 KGpgTransaction::passphraseReceived() 0166 { 0167 return true; 0168 } 0169 0170 bool 0171 KGpgTransaction::preStart() 0172 { 0173 return true; 0174 } 0175 0176 void 0177 KGpgTransaction::postStart() 0178 { 0179 } 0180 0181 void 0182 KGpgTransaction::addIdHint(QString txt) 0183 { 0184 int cut = txt.indexOf(QLatin1Char( ' ' ), 22, Qt::CaseInsensitive); 0185 txt.remove(0, cut); 0186 0187 if (txt.contains(QLatin1Char( '(' ), Qt::CaseInsensitive)) 0188 txt = txt.section(QLatin1Char( '(' ), 0, 0) + txt.section(QLatin1Char( ')' ), -1); 0189 0190 txt.replace(QLatin1Char( '<' ), QLatin1String( "<" )); 0191 0192 if (!d->m_idhints.contains(txt)) 0193 d->m_idhints << txt; 0194 } 0195 0196 QString 0197 KGpgTransaction::getIdHints() const 0198 { 0199 return d->m_idhints.join( i18n(" or " )); 0200 } 0201 0202 GPGProc * 0203 KGpgTransaction::getProcess() 0204 { 0205 return d->m_process; 0206 } 0207 0208 int 0209 KGpgTransaction::addArgument(const QString &arg) 0210 { 0211 int r = d->m_process->program().count(); 0212 0213 *d->m_process << arg; 0214 0215 return r; 0216 } 0217 0218 void 0219 KGpgTransaction::addArguments(const QStringList &args) 0220 { 0221 *d->m_process << args; 0222 } 0223 0224 void 0225 KGpgTransaction::replaceArgument(const int pos, const QString &arg) 0226 { 0227 QStringList args(d->m_process->program()); 0228 d->m_process->clearProgram(); 0229 0230 args.replace(pos, arg); 0231 0232 d->m_process->setProgram(args); 0233 } 0234 0235 void 0236 KGpgTransaction::insertArgument(const int pos, const QString &arg) 0237 { 0238 insertArguments(pos, QStringList(arg)); 0239 } 0240 0241 void 0242 KGpgTransaction::insertArguments(const int pos, const QStringList &args) 0243 { 0244 QStringList tmp(d->m_process->program()); 0245 0246 int tmppos = pos; 0247 for (const QString &s : args) { 0248 tmp.insert(tmppos++, s); 0249 } 0250 d->m_process->setProgram(tmp); 0251 0252 int move = args.count(); 0253 for (int *ref : std::as_const(d->m_argRefs)) { 0254 if (*ref >= pos) 0255 *ref += move; 0256 } 0257 } 0258 0259 void 0260 KGpgTransaction::addArgumentRef(int *ref) 0261 { 0262 d->m_argRefs.append(ref); 0263 } 0264 0265 bool 0266 KGpgTransaction::askPassphrase(const QString &message) 0267 { 0268 Q_EMIT statusMessage(i18n("Requesting Passphrase")); 0269 0270 if (d->m_passwordDialog == nullptr) { 0271 d->m_passwordDialog = new KPasswordDialog(qobject_cast<QWidget *>(parent())); 0272 0273 QString passdlgmessage; 0274 if (message.isEmpty()) { 0275 QString userIDs(getIdHints()); 0276 if (userIDs.isEmpty()) 0277 userIDs = i18n("[No user id found]"); 0278 else 0279 userIDs.replace(QLatin1Char( '<' ), QLatin1String( "<" )); 0280 0281 passdlgmessage = i18n("Enter passphrase for <b>%1</b>", userIDs); 0282 } else { 0283 passdlgmessage = message; 0284 } 0285 0286 d->m_passwordDialog->setPrompt(passdlgmessage); 0287 0288 connect(d->m_passwordDialog, &KPasswordDialog::gotPassword, d, &KGpgTransactionPrivate::slotPassphraseEntered); 0289 connect(d->m_passwordDialog, &KPasswordDialog::rejected, d, &KGpgTransactionPrivate::slotPassphraseAborted); 0290 connect(d->m_process, &GPGProc::processExited, d->m_passwordDialog, &KPasswordDialog::rejected); 0291 } else { 0292 // we already have a dialog, so this is a "bad passphrase" situation 0293 --d->m_tries; 0294 0295 d->m_passwordDialog->showErrorMessage(i18np("<p><b>Bad passphrase</b>. You have 1 try left.</p>", 0296 "<p><b>Bad passphrase</b>. You have %1 tries left.</p>", d->m_tries), 0297 KPasswordDialog::PasswordError); 0298 } 0299 0300 d->m_passwordDialog->show(); 0301 0302 return true; 0303 } 0304 0305 void 0306 KGpgTransaction::setExpectedFingerprints(const QStringList &fingerprints) 0307 { 0308 d->m_expectedFingerprints = fingerprints; 0309 } 0310 0311 void 0312 KGpgTransaction::setGnuPGHome(const QString &home) 0313 { 0314 QStringList tmp(d->m_process->program()); 0315 0316 Q_ASSERT(tmp.count() > 3); 0317 int homepos = tmp.indexOf(QLatin1String("--options"), 1); 0318 if (homepos == -1) 0319 homepos = tmp.indexOf(QLatin1String("--homedir"), 1); 0320 Q_ASSERT(homepos != -1); 0321 Q_ASSERT(homepos + 1 < tmp.count()); 0322 0323 tmp[homepos] = QLatin1String("--homedir"); 0324 tmp[homepos + 1] = home; 0325 0326 d->m_process->setProgram(tmp); 0327 } 0328 0329 int 0330 KGpgTransaction::waitForFinished(const int msecs) 0331 { 0332 int ret = TS_OK; 0333 0334 if (d->m_inputTransaction != nullptr) { 0335 ret = d->m_inputTransaction->waitForFinished(msecs); 0336 if ((ret != TS_OK) && (msecs != -1)) 0337 return ret; 0338 } 0339 0340 bool b = d->m_process->waitForFinished(msecs); 0341 0342 if (ret != TS_OK) 0343 return ret; 0344 0345 if (!b) 0346 return TS_USER_ABORTED; 0347 else 0348 return getSuccess(); 0349 } 0350 0351 const QString & 0352 KGpgTransaction::getDescription() const 0353 { 0354 return d->m_description; 0355 } 0356 0357 void 0358 KGpgTransaction::setInputTransaction(KGpgTransaction *ta) 0359 { 0360 Q_ASSERT(d->m_chainingAllowed); 0361 0362 if (d->m_inputTransaction != nullptr) 0363 clearInputTransaction(); 0364 d->m_inputTransaction = ta; 0365 0366 GPGProc *proc = ta->getProcess(); 0367 proc->setStandardOutputProcess(d->m_process); 0368 connect(ta, &KGpgTransaction::done, d, &KGpgTransactionPrivate::slotInputTransactionDone); 0369 } 0370 0371 void 0372 KGpgTransaction::clearInputTransaction() 0373 { 0374 disconnect(d->m_inputTransaction, &KGpgTransaction::done, d, &KGpgTransactionPrivate::slotInputTransactionDone); 0375 d->m_inputTransaction = nullptr; 0376 } 0377 0378 bool 0379 KGpgTransaction::hasInputTransaction() const 0380 { 0381 return (d->m_inputTransaction != nullptr); 0382 } 0383 0384 void 0385 KGpgTransaction::kill() 0386 { 0387 d->m_process->kill(); 0388 } 0389 0390 void 0391 KGpgTransaction::newPassphraseEntered() 0392 { 0393 }