File indexing completed on 2024-05-12 17:16:23

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