File indexing completed on 2024-04-28 05:41:59
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2009 by Rajko Albrecht * 0003 * ral@alwins-world.de * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 #include "ccontextlistener.h" 0021 #include "fronthelpers/cursorstack.h" 0022 #include "helpers/kdesvn_debug.h" 0023 #include "ksvnwidgets/authdialogimpl.h" 0024 #include "ksvnwidgets/commitmsg_impl.h" 0025 #include "ksvnwidgets/pwstorage.h" 0026 #include "ksvnwidgets/ssltrustprompt.h" 0027 #include "settings/kdesvnsettings.h" 0028 0029 #include <KLocalizedString> 0030 #include <KMessageBox> 0031 #include <KPasswordDialog> 0032 0033 #include <QFileDialog> 0034 #include <QMutex> 0035 #include <QTextStream> 0036 0037 class CContextListenerData 0038 { 0039 public: 0040 CContextListenerData(); 0041 virtual ~CContextListenerData(); 0042 0043 // data 0044 bool m_cancelMe; 0045 QMutex m_CancelMutex; 0046 0047 bool noDialogs; 0048 0049 QStringList m_updatedItems; 0050 }; 0051 0052 CContextListenerData::CContextListenerData() 0053 : m_cancelMe(false) 0054 , m_CancelMutex() 0055 , noDialogs(false) 0056 , m_updatedItems() 0057 { 0058 } 0059 0060 CContextListenerData::~CContextListenerData() 0061 { 0062 } 0063 0064 const int CContextListener::smax_actionstring = svn_wc_notify_failed_unlock + 1; 0065 0066 const char *CContextListener::action_strings[] = {I18N_NOOP("Add to revision control"), 0067 I18N_NOOP("Copy"), 0068 I18N_NOOP("Delete"), 0069 I18N_NOOP("Restore missing"), 0070 I18N_NOOP("Revert"), 0071 I18N_NOOP("Revert failed"), 0072 I18N_NOOP("Resolved"), 0073 I18N_NOOP("Skip"), 0074 I18N_NOOP("Deleted"), 0075 I18N_NOOP("Added"), 0076 I18N_NOOP("Update"), // svn_wc_notify_update_update 0077 I18N_NOOP("Update complete"), 0078 I18N_NOOP("Update external module"), 0079 nullptr, // status completed - will not send is just noisy 0080 I18N_NOOP("Status on external"), // svn_wc_notify_status_external 0081 I18N_NOOP("Commit Modified"), 0082 I18N_NOOP("Commit Added"), 0083 I18N_NOOP("Commit Deleted"), 0084 I18N_NOOP("Commit Replaced"), 0085 nullptr, // tx delta -> making ticks instead 0086 nullptr, // svn_wc_notify_blame_revision - using ticks 0087 I18N_NOOP("Locking"), 0088 I18N_NOOP("Unlocked"), 0089 I18N_NOOP("Lock failed"), 0090 I18N_NOOP("Unlock failed")}; 0091 0092 const char *CContextListener::notify_state_strings[] = {nullptr, // = 0 0093 nullptr, 0094 I18N_NOOP("unchanged"), 0095 I18N_NOOP("item wasn't present"), 0096 I18N_NOOP("unversioned item obstructed work"), 0097 // I18N_NOOP("Pristine state was modified."), // should send a signal with path instead of message? 0098 nullptr, 0099 I18N_NOOP("Modified state had mods merged in."), 0100 I18N_NOOP("Modified state got conflicting mods.")}; 0101 0102 QString CContextListener::NotifyAction(svn_wc_notify_action_t action) 0103 { 0104 if (action >= smax_actionstring || action < 0) { 0105 return QString(); 0106 } 0107 return (action_strings[action] == nullptr) ? QString() : i18n(action_strings[action]); 0108 } 0109 0110 QString CContextListener::NotifyState(svn_wc_notify_state_t state) 0111 { 0112 if (state > svn_wc_notify_state_conflicted || state < 0) { 0113 return QString(); 0114 } 0115 return (notify_state_strings[state] == nullptr) ? QString() : i18n(notify_state_strings[state]); 0116 } 0117 0118 CContextListener::CContextListener(QObject *parent) 0119 : QObject(parent) 0120 , svn::ContextListener() 0121 , m_Data(new CContextListenerData()) 0122 { 0123 } 0124 0125 CContextListener::~CContextListener() 0126 { 0127 disconnect(); 0128 delete m_Data; 0129 } 0130 0131 bool CContextListener::contextGetCachedLogin(const QString &realm, QString &username, QString &password) 0132 { 0133 PwStorage::self()->getCachedLogin(realm, username, password); 0134 return true; 0135 } 0136 0137 bool CContextListener::contextGetSavedLogin(const QString &realm, QString &username, QString &password) 0138 { 0139 if (!Kdesvnsettings::passwords_in_wallet()) { 0140 return true; 0141 } 0142 emit waitShow(true); 0143 PwStorage::self()->getLogin(realm, username, password); 0144 PwStorage::self()->setCachedLogin(realm, username, password); 0145 emit waitShow(false); 0146 /* the return value isn't interesting to us... */ 0147 return true; 0148 } 0149 0150 bool CContextListener::contextGetLogin(const QString &realm, QString &username, QString &password, bool &maySave) 0151 { 0152 bool ret = false; 0153 maySave = false; 0154 emit waitShow(true); 0155 emit sendNotify(realm); 0156 QPointer<AuthDialogImpl> auth(new AuthDialogImpl(realm, username)); 0157 if (auth->exec() == QDialog::Accepted) { 0158 username = auth->Username(); 0159 password = auth->Password(); 0160 maySave = (Kdesvnsettings::passwords_in_wallet() ? false : auth->maySave()); 0161 if (Kdesvnsettings::passwords_in_wallet() && auth->maySave()) { 0162 PwStorage::self()->setLogin(realm, username, password); 0163 } 0164 if (Kdesvnsettings::use_password_cache()) { 0165 PwStorage::self()->setCachedLogin(realm, username, password); 0166 } 0167 ret = true; 0168 } 0169 delete auth; 0170 emit waitShow(false); 0171 return ret; 0172 } 0173 0174 void CContextListener::contextNotify(const QString &aMsg) 0175 { 0176 if (aMsg.isEmpty()) { 0177 emit tickProgress(); 0178 } else { 0179 emit sendNotify(aMsg); 0180 } 0181 } 0182 0183 void CContextListener::contextNotify(const char *path, 0184 svn_wc_notify_action_t action, 0185 svn_node_kind_t /* kind */, 0186 const char *mime_type, 0187 svn_wc_notify_state_t content_state, 0188 svn_wc_notify_state_t prop_state, 0189 svn_revnum_t revision) 0190 { 0191 Q_UNUSED(mime_type); 0192 Q_UNUSED(prop_state); 0193 0194 QString msg; 0195 QString aString = NotifyAction(action); 0196 extraNotify(QString::fromUtf8(path), action, revision); 0197 if (!aString.isEmpty()) { 0198 QTextStream ts(&msg, QIODevice::WriteOnly); 0199 ts << NotifyAction(action) << " " << QString::fromUtf8(path); 0200 if (revision > -1) { 0201 ts << " (Rev " << revision << ")"; 0202 } 0203 aString = NotifyState(content_state); 0204 if (!aString.isEmpty()) { 0205 ts << "\n" << aString; 0206 } 0207 } 0208 contextNotify(msg); 0209 } 0210 0211 void CContextListener::contextNotify(const svn_wc_notify_t *action) 0212 { 0213 if (!action) { 0214 return; 0215 } 0216 // if (action->action<svn_wc_notify_locked) { 0217 contextNotify(action->path, action->action, action->kind, action->mime_type, action->content_state, action->prop_state, action->revision); 0218 // return; 0219 // } 0220 // QString aString = NotifyAction(action->action); 0221 } 0222 0223 void CContextListener::sendTick() 0224 { 0225 emit tickProgress(); 0226 } 0227 0228 bool CContextListener::contextCancel() 0229 { 0230 { 0231 QMutexLocker lock(&(m_Data->m_CancelMutex)); 0232 if (m_Data->m_cancelMe) { 0233 m_Data->m_cancelMe = false; 0234 return true; 0235 } 0236 } 0237 // otherwise deadlock! 0238 sendTick(); 0239 return false; 0240 } 0241 0242 bool CContextListener::contextGetLogMessage(QString &msg, const svn::CommitItemList &items) 0243 { 0244 bool isOk = false; 0245 emit waitShow(true); 0246 QString logMessage = Commitmsg_impl::getLogmessage(items, &isOk, nullptr, nullptr, nullptr); 0247 if (isOk) { 0248 msg = logMessage; 0249 } 0250 emit waitShow(false); 0251 return isOk; 0252 } 0253 0254 svn::ContextListener::SslServerTrustAnswer CContextListener::contextSslServerTrustPrompt(const svn::ContextListener::SslServerTrustData &data, 0255 apr_uint32_t &acceptedFailures) 0256 { 0257 CursorStack cs(Qt::ArrowCursor); 0258 0259 bool ok, saveit; 0260 emit waitShow(true); 0261 if (!SslTrustPrompt::sslTrust(data.hostname, 0262 data.fingerprint, 0263 data.validFrom, 0264 data.validUntil, 0265 data.issuerDName, 0266 data.realm, 0267 failure2Strings(acceptedFailures), 0268 &ok, 0269 &saveit)) { 0270 return DONT_ACCEPT; 0271 } 0272 emit waitShow(false); 0273 if (!saveit) { 0274 return ACCEPT_TEMPORARILY; 0275 } 0276 return ACCEPT_PERMANENTLY; 0277 } 0278 0279 bool CContextListener::contextSslClientCertPrompt(QString &certFile) 0280 { 0281 qCDebug(KDESVN_LOG) << certFile << Qt::endl; 0282 emit waitShow(true); 0283 QString afile = QFileDialog::getOpenFileName(nullptr, i18n("Open a file with a #PKCS12 certificate")); 0284 emit waitShow(false); 0285 if (afile.isEmpty()) { 0286 return false; 0287 } 0288 certFile = afile; 0289 return true; 0290 } 0291 0292 bool CContextListener::contextLoadSslClientCertPw(QString &password, const QString &realm) 0293 { 0294 PwStorage::self()->getCertPw(realm, password); 0295 return true; 0296 } 0297 0298 bool CContextListener::contextSslClientCertPwPrompt(QString &password, const QString &realm, bool &maysave) 0299 { 0300 maysave = false; 0301 emit waitShow(true); 0302 QString npass; 0303 QPointer<KPasswordDialog> dlg(new KPasswordDialog(nullptr)); 0304 dlg->setPrompt(i18n("Enter password for realm %1", realm)); 0305 dlg->setWindowTitle(realm); 0306 int res = dlg->exec(); 0307 if (res == QDialog::Accepted) { 0308 npass = dlg->password(); 0309 } 0310 bool keepPw = (dlg ? dlg->keepPassword() : false); 0311 delete dlg; 0312 0313 emit waitShow(false); 0314 if (res != QDialog::Accepted) { 0315 return false; 0316 } 0317 maysave = (Kdesvnsettings::passwords_in_wallet() ? false : keepPw); 0318 if (Kdesvnsettings::store_passwords() && keepPw) { 0319 PwStorage::self()->setCertPw(realm, password); 0320 } 0321 password = npass; 0322 return true; 0323 } 0324 0325 void CContextListener::setCanceled(bool how) 0326 { 0327 QMutexLocker lock(&(m_Data->m_CancelMutex)); 0328 m_Data->m_cancelMe = how; 0329 } 0330 0331 QStringList CContextListener::failure2Strings(apr_uint32_t acceptedFailures) 0332 { 0333 QStringList res; 0334 if (acceptedFailures & SVN_AUTH_SSL_UNKNOWNCA) { 0335 res << i18n("The certificate is not issued by a trusted authority. Use the fingerprint to validate the certificate manually."); 0336 } 0337 if (acceptedFailures & SVN_AUTH_SSL_CNMISMATCH) { 0338 res << i18n("The certificate hostname does not match."); 0339 } 0340 if (acceptedFailures & SVN_AUTH_SSL_NOTYETVALID) { 0341 res << i18n("The certificate is not yet valid."); 0342 } 0343 if (acceptedFailures & SVN_AUTH_SSL_EXPIRED) { 0344 res << i18n("The certificate has expired."); 0345 } 0346 if (acceptedFailures & SVN_AUTH_SSL_OTHER) { 0347 res << i18n("The certificate has an unknown error."); 0348 } 0349 return res; 0350 } 0351 0352 QString CContextListener::translate(const QString &what) 0353 { 0354 return i18n(what.toLocal8Bit()); 0355 } 0356 0357 /*! 0358 \fn CContextListener::contextProgress(long long int current, long long int max) 0359 */ 0360 void CContextListener::contextProgress(long long int current, long long int max) 0361 { 0362 emit netProgress(current, max); 0363 } 0364 0365 void CContextListener::maySavePlaintext(svn_boolean_t *may_save_plaintext, const QString &realmstring) 0366 { 0367 emit waitShow(true); 0368 if (may_save_plaintext) { 0369 QString question = i18n("%1\nReally store password as plain text?", realmstring); 0370 QString head = i18n("Save password"); 0371 KGuiItem contButton(i18nc("@action:button", "Store in Plain Text")); 0372 if (KMessageBox::warningContinueCancel(nullptr, question, head, contButton) == KMessageBox::Continue) { 0373 *may_save_plaintext = true; 0374 } else { 0375 *may_save_plaintext = false; 0376 } 0377 } 0378 emit waitShow(false); 0379 } 0380 0381 const QStringList &CContextListener::updatedItems() const 0382 { 0383 return m_Data->m_updatedItems; 0384 } 0385 0386 void CContextListener::cleanUpdatedItems() 0387 { 0388 m_Data->m_updatedItems.clear(); 0389 } 0390 0391 void CContextListener::extraNotify(const QString &path, svn_wc_notify_action_t action, svn_revnum_t revision) 0392 { 0393 Q_UNUSED(revision); 0394 switch (action) { 0395 case svn_wc_notify_update_update: 0396 case svn_wc_notify_update_add: 0397 case svn_wc_notify_update_delete: 0398 m_Data->m_updatedItems.append(path); 0399 break; 0400 default: 0401 break; 0402 } 0403 } 0404 0405 #include "moc_ccontextlistener.cpp"