File indexing completed on 2024-05-05 04:41:01
0001 /* 0002 SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de> 0003 SPDX-FileCopyrightText: 2007 Dukju Ahn <dukjuahn@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "svninternaljobbase.h" 0009 0010 #include <QMutex> 0011 #include <QDateTime> 0012 0013 #include <iostream> 0014 0015 #include <KLocalizedString> 0016 0017 extern "C" { 0018 #include <svn_auth.h> 0019 } 0020 0021 #include <vcs/vcsrevision.h> 0022 0023 #include <svnjobbase.h> 0024 #include "kdevsvncpp/context.hpp" 0025 #include "kdevsvncpp/apr.hpp" 0026 #include "kdevsvncpp/revision.hpp" 0027 0028 SvnInternalJobBase::SvnInternalJobBase(SvnJobBase* parentJob) 0029 : m_ctxt( new svn::Context() ) 0030 , m_guiSemaphore( 0 ) 0031 , m_mutex() 0032 , m_killMutex() 0033 , m_parentJob(parentJob) 0034 { 0035 m_ctxt->setListener(this); 0036 } 0037 0038 SvnInternalJobBase::~SvnInternalJobBase() 0039 { 0040 m_ctxt->setListener(nullptr); 0041 delete m_ctxt; 0042 m_ctxt = nullptr; 0043 } 0044 0045 void SvnInternalJobBase::defaultBegin(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) 0046 { 0047 emit started(); 0048 ThreadWeaver::Job::defaultBegin(self, thread); 0049 } 0050 0051 void SvnInternalJobBase::defaultEnd(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) 0052 { 0053 ThreadWeaver::Job::defaultEnd(self, thread); 0054 if (!self->success()) { 0055 emit failed(); 0056 } 0057 emit done(); 0058 // at this ppint this object cannot yet be deleted (e.g. as part of the parent job destruction, 0059 // ThreadWeaver logic still holds and uses a reference to finish the execution logic 0060 } 0061 0062 bool SvnInternalJobBase::contextGetLogin( const std::string& realm, 0063 std::string& username, std::string& password, 0064 bool& maySave ) 0065 { 0066 0067 emit needLogin( QString::fromUtf8( realm.c_str() ) ); 0068 m_guiSemaphore.acquire( 1 ); 0069 QMutexLocker l(&m_mutex); 0070 if( m_login_username.isEmpty() || m_login_password.isEmpty() ) 0071 return false; 0072 username = std::string(m_login_username.toUtf8().constData()); 0073 password = std::string(m_login_password.toUtf8().constData()); 0074 maySave = this->m_maySave; 0075 return true; 0076 } 0077 0078 void SvnInternalJobBase::contextNotify( const char* path, svn_wc_notify_action_t action, 0079 svn_node_kind_t kind, const char* mimetype, 0080 svn_wc_notify_state_t contentState, 0081 svn_wc_notify_state_t propState, svn_revnum_t rev ) 0082 { 0083 QString notifyString; 0084 switch( action ){ 0085 case svn_wc_notify_add: 0086 notifyString = i18nc( "A file was marked to be added to svn", "Added %1", QString::fromUtf8( path ) ); 0087 break; 0088 case svn_wc_notify_delete: 0089 notifyString = i18nc( "A file was marked for deletion from svn", "Deleted %1", QString::fromUtf8( path ) ); 0090 break; 0091 // various update notifications 0092 case svn_wc_notify_update_delete: 0093 notifyString = i18nc( "A file was deleted during an svn update operation", "Deleted %1", QString::fromUtf8( path ) ); 0094 break; 0095 case svn_wc_notify_update_add: 0096 notifyString = i18nc( "A file was added during an svn update operation", "Added %1", QString::fromUtf8( path ) ); 0097 break; 0098 case svn_wc_notify_update_update: 0099 /* If this is an inoperative dir change, do no notification. 0100 An inoperative dir change is when a directory gets closed 0101 without any props having been changed. */ 0102 if (! ((kind == svn_node_dir) 0103 && ((propState == svn_wc_notify_state_inapplicable) 0104 || (propState == svn_wc_notify_state_unknown) 0105 || (propState == svn_wc_notify_state_unchanged)))) { 0106 0107 if (kind == svn_node_file) { 0108 if (contentState == svn_wc_notify_state_conflicted) 0109 notifyString = QStringLiteral("Conflict On File"); 0110 else if (contentState == svn_wc_notify_state_merged) 0111 notifyString = QStringLiteral("File Merged"); 0112 else if (contentState == svn_wc_notify_state_changed) 0113 notifyString = QStringLiteral("File Updated"); 0114 } 0115 0116 if (propState == svn_wc_notify_state_conflicted) 0117 notifyString += QLatin1String(" Conflict On Property"); 0118 else if (propState == svn_wc_notify_state_merged) 0119 notifyString += QLatin1String(" Properties Merged"); 0120 else if (propState == svn_wc_notify_state_changed) 0121 notifyString += QLatin1String(" Properties Updated"); 0122 else 0123 notifyString += QLatin1Char(' '); 0124 0125 if (! ((contentState == svn_wc_notify_state_unchanged 0126 || contentState == svn_wc_notify_state_unknown) 0127 && (propState == svn_wc_notify_state_unchanged 0128 || propState == svn_wc_notify_state_unknown))) 0129 notifyString += QLatin1Char(' ') + QString::fromUtf8(path); 0130 0131 } 0132 break; 0133 0134 case svn_wc_notify_update_completed: 0135 // The last notification in an update (including updates of externals). 0136 notifyString = i18n("Revision %1", rev ); 0137 break; 0138 case svn_wc_notify_update_external: 0139 notifyString = i18n("Updating externals: %1", QString::fromUtf8( path ) ); 0140 break; 0141 case svn_wc_notify_status_completed: 0142 break; 0143 case svn_wc_notify_status_external: 0144 break; 0145 // various commit notifications 0146 case svn_wc_notify_commit_modified: 0147 notifyString = i18n( "Sending %1", QString::fromUtf8( path ) ); 0148 break; 0149 case svn_wc_notify_commit_added: 0150 if( mimetype ){ 0151 notifyString = i18n("Adding %1 using mimetype %2.", QString::fromUtf8(path), QString::fromUtf8(mimetype)); 0152 } else { 0153 notifyString = i18n( "Adding %1.", QString::fromUtf8( path ) ); 0154 } 0155 break; 0156 case svn_wc_notify_commit_deleted: 0157 notifyString = i18n( "Deleting %1.", QString::fromUtf8( path ) ); 0158 break; 0159 case svn_wc_notify_commit_replaced: 0160 notifyString = i18n( "Replacing %1.", QString::fromUtf8( path ) ); 0161 break; 0162 case svn_wc_notify_commit_postfix_txdelta: 0163 if ( sendFirstDelta ) { 0164 sendFirstDelta = false; 0165 notifyString=i18n("Transmitting file data "); 0166 } else { 0167 notifyString = QStringLiteral("."); 0168 } 0169 break; 0170 case svn_wc_notify_blame_revision: 0171 notifyString = i18n( "Blame finished for revision %1, path %2", rev, QString::fromUtf8( path ) ); 0172 break; 0173 case svn_wc_notify_revert: 0174 notifyString = i18n( "Reverted working copy %1", QString::fromUtf8( path ) ); 0175 break; 0176 case svn_wc_notify_failed_revert: 0177 notifyString = i18n( "Reverting failed on working copy %1", QString::fromUtf8( path ) ); 0178 break; 0179 case svn_wc_notify_copy: 0180 notifyString = i18n( "Copied %1", QString::fromUtf8( path ) ); 0181 break; 0182 default: 0183 break; 0184 } 0185 emit showNotification( QString::fromUtf8( path ), notifyString ); 0186 } 0187 0188 bool SvnInternalJobBase::contextCancel() 0189 { 0190 QMutexLocker lock( &m_killMutex ); 0191 return killed; 0192 } 0193 0194 bool SvnInternalJobBase::contextGetLogMessage( std::string& msg ) 0195 { 0196 emit needCommitMessage(); 0197 m_guiSemaphore.acquire( 1 ); 0198 QMutexLocker l( &m_mutex ); 0199 QByteArray ba = m_commitMessage.toUtf8(); 0200 msg = std::string( ba.data() ); 0201 return true; 0202 } 0203 0204 void SvnInternalJobBase::initBeforeRun() 0205 { 0206 connect( this, &SvnInternalJobBase::needCommitMessage, 0207 m_parentJob, &SvnJobBase::askForCommitMessage, Qt::QueuedConnection ); 0208 connect( this, &SvnInternalJobBase::needLogin, 0209 m_parentJob, &SvnJobBase::askForLogin, Qt::QueuedConnection ); 0210 connect( this, &SvnInternalJobBase::needSslServerTrust, 0211 m_parentJob, &SvnJobBase::askForSslServerTrust, Qt::QueuedConnection ); 0212 connect( this, &SvnInternalJobBase::showNotification, 0213 m_parentJob, &SvnJobBase::showNotification, Qt::QueuedConnection ); 0214 connect( this, &SvnInternalJobBase::needSslClientCert, 0215 m_parentJob, &SvnJobBase::askForSslClientCert, Qt::QueuedConnection ); 0216 connect( this, &SvnInternalJobBase::needSslClientCertPassword, 0217 m_parentJob, &SvnJobBase::askForSslClientCertPassword, Qt::QueuedConnection ); 0218 } 0219 0220 svn::ContextListener::SslServerTrustAnswer SvnInternalJobBase::contextSslServerTrustPrompt( 0221 const svn::ContextListener::SslServerTrustData& data, 0222 apr_uint32_t& acceptedFailures ) 0223 { 0224 0225 std::string host = data.hostname; 0226 std::string print = data.fingerprint; 0227 std::string from = data.validFrom; 0228 std::string until = data.validUntil; 0229 std::string issue = data.issuerDName; 0230 std::string realm = data.realm; 0231 acceptedFailures = data.failures; 0232 QStringList failures; 0233 if( data.failures & SVN_AUTH_SSL_NOTYETVALID ) 0234 { 0235 failures << i18n("Certificate is not yet valid."); 0236 } 0237 if( data.failures & SVN_AUTH_SSL_EXPIRED ) 0238 { 0239 failures << i18n("Certificate has expired."); 0240 } 0241 if( data.failures & SVN_AUTH_SSL_CNMISMATCH ) 0242 { 0243 failures << i18n("Certificate's CN (hostname) doesn't match the remote hostname."); 0244 } 0245 if( data.failures & SVN_AUTH_SSL_UNKNOWNCA ) 0246 { 0247 failures << i18n("Certificate authority is unknown."); 0248 } 0249 if( data.failures & SVN_AUTH_SSL_NOTYETVALID ) 0250 { 0251 failures << i18n("Other unknown error."); 0252 } 0253 emit needSslServerTrust( failures, 0254 QString::fromUtf8( host.c_str() ), 0255 QString::fromUtf8( print.c_str() ), 0256 QString::fromUtf8( from.c_str() ), 0257 QString::fromUtf8( until.c_str() ), 0258 QString::fromUtf8( issue.c_str() ), 0259 QString::fromUtf8( realm.c_str() ) ); 0260 m_guiSemaphore.acquire(1); 0261 QMutexLocker l(&m_mutex); 0262 return m_trustAnswer; 0263 } 0264 0265 bool SvnInternalJobBase::contextSslClientCertPrompt( std::string& cert ) 0266 { 0267 emit needSslClientCert( QString::fromUtf8( cert.c_str() ) ); 0268 m_guiSemaphore.acquire( 1 ); 0269 return true; 0270 } 0271 0272 bool SvnInternalJobBase::contextSslClientCertPwPrompt( std::string& pw, const std::string& realm, 0273 bool& maySave ) 0274 { 0275 Q_UNUSED(pw); 0276 Q_UNUSED(maySave); 0277 emit needSslClientCertPassword( QString::fromUtf8( realm.c_str() ) ); 0278 m_guiSemaphore.acquire( 1 ); 0279 return false; 0280 } 0281 0282 bool SvnInternalJobBase::success() const 0283 { 0284 return m_success; 0285 } 0286 0287 svn::Revision SvnInternalJobBase::createSvnCppRevisionFromVcsRevision( const KDevelop::VcsRevision& revision ) 0288 { 0289 svn::Revision rev; 0290 QVariant value = revision.revisionValue(); 0291 switch( revision.revisionType() ) 0292 { 0293 case KDevelop::VcsRevision::Special: 0294 { 0295 if( value.canConvert<KDevelop::VcsRevision::RevisionSpecialType>() ) 0296 { 0297 auto specialtype = 0298 value.value<KDevelop::VcsRevision::RevisionSpecialType>(); 0299 switch( specialtype ) 0300 { 0301 case KDevelop::VcsRevision::Head: 0302 rev = svn::Revision( svn::Revision::HEAD ); 0303 break; 0304 case KDevelop::VcsRevision::Working: 0305 rev = svn::Revision( svn::Revision::WORKING ); 0306 break; 0307 case KDevelop::VcsRevision::Base: 0308 rev = svn::Revision( svn::Revision::BASE ); 0309 break; 0310 case KDevelop::VcsRevision::Previous: 0311 rev = svn::Revision( svn_opt_revision_previous ); 0312 break; 0313 case KDevelop::VcsRevision::Start: 0314 rev = svn::Revision( svn::Revision::START ); 0315 break; 0316 default: 0317 break; 0318 } 0319 } 0320 break; 0321 } 0322 case KDevelop::VcsRevision::GlobalNumber: 0323 case KDevelop::VcsRevision::FileNumber: 0324 { 0325 bool ok; 0326 qlonglong number = value.toLongLong(&ok); 0327 if( ok ) 0328 { 0329 rev = svn::Revision( number ); 0330 } 0331 break; 0332 } 0333 case KDevelop::VcsRevision::Date: 0334 { 0335 QDateTime dt = value.toDateTime(); 0336 if( dt.isValid() ) 0337 { 0338 rev = svn::Revision( dt.toSecsSinceEpoch() ); 0339 } 0340 break; 0341 } 0342 default: 0343 break; 0344 } 0345 return rev; 0346 } 0347 0348 0349 void SvnInternalJobBase::setErrorMessage( const QString& msg ) 0350 { 0351 QMutexLocker lock( &m_mutex ); 0352 m_errorMessage = msg; 0353 } 0354 0355 QString SvnInternalJobBase::errorMessage() const 0356 { 0357 QMutexLocker lock( &m_mutex ); 0358 return m_errorMessage; 0359 } 0360 0361 void SvnInternalJobBase::kill() 0362 { 0363 QMutexLocker lock( &m_killMutex ); 0364 killed = true; 0365 } 0366 0367 #include "moc_svninternaljobbase.cpp"