File indexing completed on 2024-04-28 05:42:09

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           *
0006  * modify it under the terms of the GNU Lesser General Public              *
0007  * License as published by the Free Software Foundation; either            *
0008  * version 2.1 of the License, or (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 GNU       *
0013  * Lesser General Public License for more details.                         *
0014  *                                                                         *
0015  * You should have received a copy of the GNU Lesser General Public        *
0016  * License along with this program (in the file LGPL.txt); if not,         *
0017  * write to the Free Software Foundation, Inc., 51 Franklin St,            *
0018  * Fifth Floor, Boston, MA  02110-1301  USA                                *
0019  *                                                                         *
0020  * This software consists of voluntary contributions made by many          *
0021  * individuals.  For exact contribution history, see the revision          *
0022  * history and logs, available at https://commits.kde.org/kdesvn.          *
0023  ***************************************************************************/
0024 
0025 #include "contextdata.h"
0026 #include "conflictdescription.h"
0027 #include "conflictresult.h"
0028 #include "context_listener.h"
0029 
0030 #include <QCoreApplication>
0031 #include <svn_config.h>
0032 #include <svn_wc.h>
0033 
0034 namespace svn
0035 {
0036 
0037 static inline char *toAprCharPtr(const QString &str, apr_pool_t *pool)
0038 {
0039     const QByteArray l = str.toUtf8();
0040     return apr_pstrndup(pool, l.data(), l.size());
0041 }
0042 
0043 ContextData::ContextData(const QString &configDir_)
0044     : listener(nullptr)
0045     , logIsSet(false)
0046     , m_promptCounter(0)
0047     , m_ConfigDir(configDir_)
0048 {
0049     const QByteArray cfgDirBa = m_ConfigDir.toUtf8();
0050     const char *c_configDir = cfgDirBa.isEmpty() ? nullptr : cfgDirBa.constData();
0051 
0052     // make sure the configuration directory exists
0053     svn_config_ensure(c_configDir, pool);
0054 
0055     // initialize authentication providers
0056     // * simple
0057     // * username
0058     // * simple pw cache of frontend app
0059     // * simple pw storage
0060     // * simple prompt
0061     // * ssl server trust file
0062     // * ssl server trust prompt
0063     // * ssl client cert pw file
0064     // * ssl client cert pw load
0065     // * ssl client cert pw prompt
0066     // * ssl client cert file
0067     // ===================
0068     // 11 providers (+1 for windowsvariant)
0069 
0070     apr_array_header_t *providers =
0071 #if defined(WIN32) // krazy:exclude=cpp
0072         apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *));
0073 #else
0074         apr_array_make(pool, 11, sizeof(svn_auth_provider_object_t *));
0075 #endif
0076     svn_auth_provider_object_t *provider;
0077 
0078 #if defined(WIN32) // krazy:exclude=cpp
0079     svn_auth_get_windows_simple_provider(&provider, pool);
0080     APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
0081 #endif
0082 
0083     svn_auth_get_simple_provider2(&provider, maySavePlaintext, this, pool);
0084     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0085 
0086     svn_auth_get_username_provider(&provider, pool);
0087     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0088 
0089     svn_auth_get_simple_prompt_provider(&provider, onCachedPrompt, this, 0, pool);
0090     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0091 
0092     svn_auth_get_simple_prompt_provider(&provider, onSavedPrompt, this, 0, pool);
0093     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0094 
0095     /* not very nice. should be infinite... */
0096     svn_auth_get_simple_prompt_provider(&provider, onSimplePrompt, this, 100000000, pool);
0097     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0098 
0099     // add ssl providers
0100 
0101     // file first then prompt providers
0102     svn_auth_get_ssl_server_trust_file_provider(&provider, pool);
0103     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0104 
0105     svn_auth_get_ssl_client_cert_file_provider(&provider, pool);
0106     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0107 
0108     svn_auth_get_ssl_client_cert_pw_file_provider2(&provider, maySavePlaintext, this, pool);
0109     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0110 
0111     svn_auth_get_ssl_server_trust_prompt_provider(&provider, onSslServerTrustPrompt, this, pool);
0112     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0113 
0114     // first try load from extra storage
0115     svn_auth_get_ssl_client_cert_pw_prompt_provider(&provider, onFirstSslClientCertPw, this, 0, pool);
0116     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0117 
0118     // plugged in 3 as the retry limit - what is a good limit?
0119     svn_auth_get_ssl_client_cert_pw_prompt_provider(&provider, onSslClientCertPwPrompt, this, 3, pool);
0120     *(svn_auth_provider_object_t **)apr_array_push(providers) = provider;
0121 
0122     svn_auth_baton_t *ab;
0123     svn_auth_open(&ab, providers, pool);
0124 
0125     // todo svn 1.8: svn_client_create_context2
0126     // initialize ctx structure
0127     svn_client_create_context(&m_ctx, pool);
0128 
0129     // get the config based on the configDir passed in
0130     svn_config_get_config(&(m_ctx->config), c_configDir, pool);
0131 
0132     // tell the auth functions where the config is
0133     if (c_configDir) {
0134         svn_auth_set_parameter(ab, SVN_AUTH_PARAM_CONFIG_DIR, c_configDir);
0135     }
0136 
0137     m_ctx->auth_baton = ab;
0138     m_ctx->notify_func = onNotify;
0139     m_ctx->notify_baton = this;
0140     m_ctx->cancel_func = onCancel;
0141     m_ctx->cancel_baton = this;
0142     m_ctx->notify_func2 = onNotify2;
0143     m_ctx->notify_baton2 = this;
0144 
0145     m_ctx->log_msg_func = onLogMsg;
0146     m_ctx->log_msg_baton = this;
0147     // subversion 1.3 functions
0148     m_ctx->log_msg_func2 = onLogMsg2;
0149     m_ctx->log_msg_baton2 = this;
0150 
0151     m_ctx->progress_func = onProgress;
0152     m_ctx->progress_baton = this;
0153 
0154     m_ctx->log_msg_func3 = onLogMsg3;
0155     m_ctx->log_msg_baton3 = this;
0156 
0157     m_ctx->conflict_func = onWcConflictResolver;
0158     m_ctx->conflict_baton = this;
0159 
0160     m_ctx->conflict_func2 = onWcConflictResolver2;
0161     m_ctx->conflict_baton2 = this;
0162 
0163     m_ctx->client_name = "SvnQt wrapper client";
0164     initMimeTypes();
0165 }
0166 
0167 ContextData::~ContextData()
0168 {
0169 }
0170 
0171 const QString &ContextData::getLogMessage() const
0172 {
0173     return logMessage;
0174 }
0175 
0176 bool ContextData::retrieveLogMessage(QString &msg, const CommitItemList &_itemlist)
0177 {
0178     bool ok = false;
0179     if (listener) {
0180         ok = listener->contextGetLogMessage(logMessage, _itemlist);
0181         if (ok) {
0182             msg = logMessage;
0183         } else {
0184             logIsSet = false;
0185         }
0186     }
0187     return ok;
0188 }
0189 
0190 void ContextData::notify(const char *path,
0191                          svn_wc_notify_action_t action,
0192                          svn_node_kind_t kind,
0193                          const char *mime_type,
0194                          svn_wc_notify_state_t content_state,
0195                          svn_wc_notify_state_t prop_state,
0196                          svn_revnum_t revision)
0197 {
0198     if (listener != nullptr) {
0199         listener->contextNotify(path, action, kind, mime_type, content_state, prop_state, revision);
0200     }
0201 }
0202 
0203 void ContextData::notify(const svn_wc_notify_t *action)
0204 {
0205     if (listener != nullptr) {
0206         listener->contextNotify(action);
0207     }
0208 }
0209 
0210 bool ContextData::cancel()
0211 {
0212     if (listener != nullptr) {
0213         return listener->contextCancel();
0214     } else {
0215         // don't cancel if no listener
0216         return false;
0217     }
0218 }
0219 const QString &ContextData::getUsername() const
0220 {
0221     return username;
0222 }
0223 
0224 const QString &ContextData::getPassword() const
0225 {
0226     return password;
0227 }
0228 
0229 bool ContextData::retrieveLogin(const char *username_, const char *realm, bool &may_save)
0230 {
0231     bool ok;
0232 
0233     if (listener == nullptr) {
0234         return false;
0235     }
0236 
0237     username = QString::fromUtf8(username_);
0238     ok = listener->contextGetLogin(QString::fromUtf8(realm), username, password, may_save);
0239 
0240     return ok;
0241 }
0242 
0243 bool ContextData::retrieveSavedLogin(const char *username_, const char *realm, bool &may_save)
0244 {
0245     bool ok;
0246     may_save = false;
0247 
0248     if (listener == nullptr) {
0249         return false;
0250     }
0251 
0252     username = QString::fromUtf8(username_);
0253     ok = listener->contextGetSavedLogin(QString::fromUtf8(realm), username, password);
0254     return ok;
0255 }
0256 
0257 bool ContextData::retrieveCachedLogin(const char *username_, const char *realm, bool &may_save)
0258 {
0259     bool ok;
0260     may_save = false;
0261 
0262     if (listener == nullptr) {
0263         return false;
0264     }
0265 
0266     username = QString::fromUtf8(username_);
0267     ok = listener->contextGetCachedLogin(QString::fromUtf8(realm), username, password);
0268     return ok;
0269 }
0270 
0271 svn_client_ctx_t *ContextData::ctx()
0272 {
0273     return m_ctx;
0274 }
0275 
0276 const QString &ContextData::configDir() const
0277 {
0278     return m_ConfigDir;
0279 }
0280 
0281 svn_error_t *ContextData::getContextData(void *baton, ContextData **data)
0282 {
0283     if (baton == nullptr)
0284         return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "invalid baton").toUtf8());
0285 
0286     ContextData *data_ = static_cast<ContextData *>(baton);
0287 
0288     if (data_->listener == nullptr)
0289         return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "invalid listener").toUtf8());
0290 
0291     *data = data_;
0292     return SVN_NO_ERROR;
0293 }
0294 
0295 void ContextData::setAuthCache(bool value)
0296 {
0297     void *param = nullptr;
0298     if (!value) {
0299         param = (void *)"1";
0300     }
0301     svn_auth_set_parameter(m_ctx->auth_baton, SVN_AUTH_PARAM_NO_AUTH_CACHE, param);
0302 }
0303 
0304 void ContextData::setLogin(const QString &usr, const QString &pwd)
0305 {
0306     username = usr;
0307     password = pwd;
0308     svn_auth_baton_t *ab = m_ctx->auth_baton;
0309     svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_USERNAME, username.toUtf8());
0310     svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD, password.toUtf8());
0311 }
0312 
0313 void ContextData::setLogMessage(const QString &msg)
0314 {
0315     logMessage = msg;
0316     if (msg.isNull()) {
0317         logIsSet = false;
0318     } else {
0319         logIsSet = true;
0320     }
0321 }
0322 
0323 svn_error_t *ContextData::onLogMsg(const char **log_msg, const char **tmp_file, apr_array_header_t *commit_items, void *baton, apr_pool_t *pool)
0324 {
0325     ContextData *data = nullptr;
0326     SVN_ERR(getContextData(baton, &data));
0327 
0328     QString msg;
0329     if (data->logIsSet) {
0330         msg = data->getLogMessage();
0331     } else {
0332         CommitItemList _items;
0333         _items.reserve(commit_items->nelts);
0334         for (int j = 0; j < commit_items->nelts; ++j) {
0335             svn_client_commit_item_t *item = ((svn_client_commit_item_t **)commit_items->elts)[j];
0336             _items.push_back(CommitItem(item));
0337         }
0338         if (!data->retrieveLogMessage(msg, _items)) {
0339             return data->generate_cancel_error();
0340         }
0341     }
0342 
0343     *log_msg = toAprCharPtr(msg, pool);
0344     *tmp_file = nullptr;
0345     return SVN_NO_ERROR;
0346 }
0347 
0348 svn_error_t *ContextData::onLogMsg2(const char **log_msg, const char **tmp_file, const apr_array_header_t *commit_items, void *baton, apr_pool_t *pool)
0349 {
0350     ContextData *data = nullptr;
0351     SVN_ERR(getContextData(baton, &data));
0352 
0353     QString msg;
0354     if (data->logIsSet) {
0355         msg = data->getLogMessage();
0356     } else {
0357         CommitItemList _items;
0358         _items.reserve(commit_items->nelts);
0359         for (int j = 0; j < commit_items->nelts; ++j) {
0360             svn_client_commit_item2_t *item = ((svn_client_commit_item2_t **)commit_items->elts)[j];
0361             _items.push_back(CommitItem(item));
0362         }
0363 
0364         if (!data->retrieveLogMessage(msg, _items)) {
0365             return data->generate_cancel_error();
0366         }
0367     }
0368 
0369     *log_msg = toAprCharPtr(msg, pool);
0370     *tmp_file = nullptr;
0371     return SVN_NO_ERROR;
0372 }
0373 
0374 svn_error_t *ContextData::onLogMsg3(const char **log_msg, const char **tmp_file, const apr_array_header_t *commit_items, void *baton, apr_pool_t *pool)
0375 {
0376     ContextData *data = nullptr;
0377     SVN_ERR(getContextData(baton, &data));
0378 
0379     QString msg;
0380     if (data->logIsSet) {
0381         msg = data->getLogMessage();
0382     } else {
0383         CommitItemList _items;
0384         _items.reserve(commit_items->nelts);
0385         for (int j = 0; j < commit_items->nelts; ++j) {
0386             svn_client_commit_item3_t *item = ((svn_client_commit_item3_t **)commit_items->elts)[j];
0387             _items.push_back(CommitItem(item));
0388         }
0389 
0390         if (!data->retrieveLogMessage(msg, _items)) {
0391             return data->generate_cancel_error();
0392         }
0393     }
0394 
0395     *log_msg = toAprCharPtr(msg, pool);
0396     *tmp_file = nullptr;
0397     return SVN_NO_ERROR;
0398 }
0399 
0400 void ContextData::onNotify(void *baton,
0401                            const char *path,
0402                            svn_wc_notify_action_t action,
0403                            svn_node_kind_t kind,
0404                            const char *mime_type,
0405                            svn_wc_notify_state_t content_state,
0406                            svn_wc_notify_state_t prop_state,
0407                            svn_revnum_t revision)
0408 {
0409     if (baton == nullptr) {
0410         return;
0411     }
0412     ContextData *data = static_cast<ContextData *>(baton);
0413     data->notify(path, action, kind, mime_type, content_state, prop_state, revision);
0414 }
0415 
0416 void ContextData::onNotify2(void *baton, const svn_wc_notify_t *action, apr_pool_t * /*tpool*/)
0417 {
0418     if (!baton) {
0419         return;
0420     }
0421     ContextData *data = static_cast<ContextData *>(baton);
0422     data->notify(action);
0423 }
0424 
0425 svn_error_t *ContextData::onCancel(void *baton)
0426 {
0427     if (baton == nullptr) {
0428         return SVN_NO_ERROR;
0429     }
0430     ContextData *data = static_cast<ContextData *>(baton);
0431     if (data->cancel()) {
0432         return data->generate_cancel_error();
0433     } else {
0434         return SVN_NO_ERROR;
0435     }
0436 }
0437 
0438 svn_error_t *
0439 ContextData::onCachedPrompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t _may_save, apr_pool_t *pool)
0440 {
0441     ContextData *data = nullptr;
0442     SVN_ERR(getContextData(baton, &data));
0443     bool may_save = _may_save != 0;
0444     if (!data->retrieveCachedLogin(username, realm, may_save)) {
0445         return SVN_NO_ERROR;
0446     }
0447     svn_auth_cred_simple_t *lcred = (svn_auth_cred_simple_t *)apr_palloc(pool, sizeof(svn_auth_cred_simple_t));
0448     lcred->password = toAprCharPtr(data->getPassword(), pool);
0449     lcred->username = toAprCharPtr(data->getUsername(), pool);
0450 
0451     // tell svn if the credentials need to be saved
0452     lcred->may_save = may_save;
0453     *cred = lcred;
0454 
0455     return SVN_NO_ERROR;
0456 }
0457 
0458 svn_error_t *
0459 ContextData::onSavedPrompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t _may_save, apr_pool_t *pool)
0460 {
0461     ContextData *data = nullptr;
0462     SVN_ERR(getContextData(baton, &data));
0463     bool may_save = _may_save != 0;
0464     if (!data->retrieveSavedLogin(username, realm, may_save)) {
0465         return SVN_NO_ERROR;
0466     }
0467     svn_auth_cred_simple_t *lcred = (svn_auth_cred_simple_t *)apr_palloc(pool, sizeof(svn_auth_cred_simple_t));
0468     lcred->password = toAprCharPtr(data->getPassword(), pool);
0469     lcred->username = toAprCharPtr(data->getUsername(), pool);
0470 
0471     // tell svn if the credentials need to be saved
0472     lcred->may_save = may_save;
0473     *cred = lcred;
0474 
0475     return SVN_NO_ERROR;
0476 }
0477 
0478 svn_error_t *
0479 ContextData::onSimplePrompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t _may_save, apr_pool_t *pool)
0480 {
0481     ContextData *data = nullptr;
0482     SVN_ERR(getContextData(baton, &data));
0483     bool may_save = _may_save != 0;
0484     if (!data->retrieveLogin(username, realm, may_save)) {
0485         return data->generate_cancel_error();
0486     }
0487 
0488     svn_auth_cred_simple_t *lcred = (svn_auth_cred_simple_t *)apr_palloc(pool, sizeof(svn_auth_cred_simple_t));
0489     lcred->password = toAprCharPtr(data->getPassword(), pool);
0490     lcred->username = toAprCharPtr(data->getUsername(), pool);
0491 
0492     // tell svn if the credentials need to be saved
0493     lcred->may_save = may_save;
0494     *cred = lcred;
0495 
0496     return SVN_NO_ERROR;
0497 }
0498 
0499 svn_error_t *ContextData::onSslServerTrustPrompt(svn_auth_cred_ssl_server_trust_t **cred,
0500                                                  void *baton,
0501                                                  const char *realm,
0502                                                  apr_uint32_t failures,
0503                                                  const svn_auth_ssl_server_cert_info_t *info,
0504                                                  svn_boolean_t may_save,
0505                                                  apr_pool_t *pool)
0506 {
0507     ContextData *data = nullptr;
0508     SVN_ERR(getContextData(baton, &data));
0509 
0510     ContextListener::SslServerTrustData trustData(failures);
0511     if (realm != nullptr) {
0512         trustData.realm = QString::fromUtf8(realm);
0513     }
0514     trustData.hostname = QString::fromUtf8(info->hostname);
0515     trustData.fingerprint = QString::fromUtf8(info->fingerprint);
0516     trustData.validFrom = QString::fromUtf8(info->valid_from);
0517     trustData.validUntil = QString::fromUtf8(info->valid_until);
0518     trustData.issuerDName = QString::fromUtf8(info->issuer_dname);
0519     trustData.maySave = may_save != 0;
0520 
0521     apr_uint32_t acceptedFailures = failures;
0522     ContextListener::SslServerTrustAnswer answer = data->listener->contextSslServerTrustPrompt(trustData, acceptedFailures);
0523 
0524     if (answer == ContextListener::DONT_ACCEPT) {
0525         *cred = nullptr;
0526     } else {
0527         svn_auth_cred_ssl_server_trust_t *cred_ = (svn_auth_cred_ssl_server_trust_t *)apr_palloc(pool, sizeof(svn_auth_cred_ssl_server_trust_t));
0528 
0529         cred_->accepted_failures = failures;
0530         if (answer == ContextListener::ACCEPT_PERMANENTLY) {
0531             cred_->may_save = true;
0532         } else {
0533             cred_->may_save = false;
0534         }
0535         *cred = cred_;
0536     }
0537 
0538     return SVN_NO_ERROR;
0539 }
0540 
0541 svn_error_t *ContextData::onSslClientCertPrompt(svn_auth_cred_ssl_client_cert_t **cred, void *baton, apr_pool_t *pool)
0542 {
0543     ContextData *data = nullptr;
0544     SVN_ERR(getContextData(baton, &data));
0545 
0546     QString certFile;
0547     if (!data->listener->contextSslClientCertPrompt(certFile)) {
0548         return data->generate_cancel_error();
0549     }
0550 
0551     svn_auth_cred_ssl_client_cert_t *cred_ = (svn_auth_cred_ssl_client_cert_t *)apr_palloc(pool, sizeof(svn_auth_cred_ssl_client_cert_t));
0552 
0553     cred_->cert_file = toAprCharPtr(certFile, pool);
0554 
0555     *cred = cred_;
0556     return SVN_NO_ERROR;
0557 }
0558 
0559 svn_error_t *
0560 ContextData::onFirstSslClientCertPw(svn_auth_cred_ssl_client_cert_pw_t **cred, void *baton, const char *realm, svn_boolean_t maySave, apr_pool_t *pool)
0561 {
0562     ContextData *data = nullptr;
0563     SVN_ERR(getContextData(baton, &data));
0564 
0565     QString password;
0566     bool may_save = maySave != 0;
0567     if (!data->listener->contextLoadSslClientCertPw(password, QString::fromUtf8(realm))) {
0568         return SVN_NO_ERROR;
0569     }
0570 
0571     svn_auth_cred_ssl_client_cert_pw_t *cred_ = (svn_auth_cred_ssl_client_cert_pw_t *)apr_palloc(pool, sizeof(svn_auth_cred_ssl_client_cert_pw_t));
0572 
0573     cred_->password = toAprCharPtr(password, pool);
0574     cred_->may_save = may_save;
0575     *cred = cred_;
0576 
0577     return SVN_NO_ERROR;
0578 }
0579 
0580 svn_error_t *
0581 ContextData::onSslClientCertPwPrompt(svn_auth_cred_ssl_client_cert_pw_t **cred, void *baton, const char *realm, svn_boolean_t maySave, apr_pool_t *pool)
0582 {
0583     ContextData *data = nullptr;
0584     SVN_ERR(getContextData(baton, &data));
0585 
0586     QString password;
0587     bool may_save = maySave != 0;
0588     if (!data->listener->contextSslClientCertPwPrompt(password, QString::fromUtf8(realm), may_save)) {
0589         return data->generate_cancel_error();
0590     }
0591 
0592     svn_auth_cred_ssl_client_cert_pw_t *cred_ = (svn_auth_cred_ssl_client_cert_pw_t *)apr_palloc(pool, sizeof(svn_auth_cred_ssl_client_cert_pw_t));
0593 
0594     cred_->password = toAprCharPtr(password, pool);
0595     cred_->may_save = may_save;
0596     *cred = cred_;
0597 
0598     return SVN_NO_ERROR;
0599 }
0600 
0601 void ContextData::setListener(ContextListener *_listener)
0602 {
0603     listener = _listener;
0604 }
0605 
0606 ContextListener *ContextData::getListener() const
0607 {
0608     return listener;
0609 }
0610 
0611 void ContextData::reset()
0612 {
0613     m_promptCounter = 0;
0614     logIsSet = false;
0615 }
0616 
0617 svn_error_t *ContextData::generate_cancel_error()
0618 {
0619     return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "Cancelled by user.").toUtf8());
0620 }
0621 
0622 void ContextData::onProgress(apr_off_t progress, apr_off_t total, void *baton, apr_pool_t *)
0623 {
0624     ContextData *data = nullptr;
0625     if (getContextData(baton, &data) != SVN_NO_ERROR) {
0626         return;
0627     }
0628     data->getListener()->contextProgress(progress, total);
0629 }
0630 
0631 void ContextData::initMimeTypes()
0632 {
0633     // code take from subversion 1.5 commandline client
0634     const char *mimetypes_file;
0635     svn_error_t *err = nullptr;
0636     svn_config_t *cfg = (svn_config_t *)apr_hash_get(m_ctx->config, SVN_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING);
0637 
0638     svn_config_get(cfg, &mimetypes_file, SVN_CONFIG_SECTION_MISCELLANY, SVN_CONFIG_OPTION_MIMETYPES_FILE, nullptr);
0639     if (mimetypes_file && *mimetypes_file) {
0640         if ((err = svn_io_parse_mimetypes_file(&(m_ctx->mimetypes_map), mimetypes_file, pool))) {
0641             svn_handle_error2(err, stderr, false, "svn: ");
0642         }
0643     }
0644 }
0645 
0646 svn_error_t *
0647 ContextData::onWcConflictResolver(svn_wc_conflict_result_t **result, const svn_wc_conflict_description_t *description, void *baton, apr_pool_t *pool)
0648 {
0649     ContextData *data = nullptr;
0650     SVN_ERR(getContextData(baton, &data));
0651     ConflictResult cresult;
0652     if (!data->getListener()->contextConflictResolve(cresult, ConflictDescription(description))) {
0653         return data->generate_cancel_error();
0654     }
0655     cresult.assignResult(result, pool);
0656     return SVN_NO_ERROR;
0657 }
0658 
0659 svn_error_t *ContextData::onWcConflictResolver2(svn_wc_conflict_result_t **result,
0660                                                 const svn_wc_conflict_description2_t *description,
0661                                                 void *baton,
0662                                                 apr_pool_t *result_pool,
0663                                                 apr_pool_t *)
0664 {
0665     ContextData *data = nullptr;
0666     SVN_ERR(getContextData(baton, &data));
0667     ConflictResult cresult;
0668     if (!data->getListener()->contextConflictResolve(cresult, ConflictDescription(description))) {
0669         return data->generate_cancel_error();
0670     }
0671     cresult.assignResult(result, result_pool);
0672     return SVN_NO_ERROR;
0673 }
0674 
0675 svn_error_t *ContextData::maySavePlaintext(svn_boolean_t *may_save_plaintext, const char *realmstring, void *baton, apr_pool_t *pool)
0676 {
0677     Q_UNUSED(pool);
0678     ContextData *data = nullptr;
0679     SVN_ERR(getContextData(baton, &data));
0680     data->getListener()->maySavePlaintext(may_save_plaintext, QString::fromUtf8(realmstring));
0681     return SVN_NO_ERROR;
0682 }
0683 
0684 bool ContextData::contextAddListItem(DirEntries *entries, const svn_dirent_t *dirent, const svn_lock_t *lock, const QString &path)
0685 {
0686     if (!getListener()) {
0687         if (!entries || !dirent) {
0688             return false;
0689         }
0690         entries->push_back(DirEntry(path, dirent, lock));
0691         return true;
0692     }
0693     return getListener()->contextAddListItem(entries, dirent, lock, path);
0694 }
0695 
0696 bool ContextListener::contextConflictResolve(ConflictResult &result, const ConflictDescription &description)
0697 {
0698     Q_UNUSED(description);
0699     result.setChoice(ConflictResult::ChoosePostpone);
0700     return true;
0701 }
0702 
0703 bool ContextListener::contextAddListItem(DirEntries *entries, const svn_dirent_t *dirent, const svn_lock_t *lock, const QString &path)
0704 {
0705     if (!entries || !dirent) {
0706         return false;
0707     }
0708     entries->push_back(DirEntry(path, dirent, lock));
0709     return true;
0710 }
0711 
0712 void ContextListener::maySavePlaintext(svn_boolean_t *may_save_plaintext, const QString &realmstring)
0713 {
0714     Q_UNUSED(realmstring);
0715     if (may_save_plaintext) {
0716         *may_save_plaintext = true;
0717     }
0718 }
0719 
0720 }