<commit_before>/**
 * KQOAuth - An OAuth authentication library for Qt.
 *
 * Author: Johan Paul (johan.paul@d-pointer.com)
 *         http://www.d-pointer.com
 *
 *  KQOAuth is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  KQOAuth is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with KQOAuth.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <QByteArray>
#include <QDateTime>
#include <QCryptographicHash>
#include <QPair>
#include <QStringList>

#include <QtDebug>
#include <QtAlgorithms>

#include "kqoauthrequest.h"
#include "kqoauthrequest_p.h"
#include "kqoauthutils.h"
#include "kqoauthglobals.h"

//////////// Private d_ptr implementation /////////

KQOAuthRequestPrivate::KQOAuthRequestPrivate()
{

}

KQOAuthRequestPrivate::~KQOAuthRequestPrivate()
{

}

// This method will not include the "oauthSignature" paramater, since it is calculated from these parameters.
void KQOAuthRequestPrivate::prepareRequest() {

    // If parameter list is not empty, we don't want to insert these values by
    // accident a second time. So giving up.
    if( !requestParameters.isEmpty() ) {
        return;
    }

    switch ( requestType ) {
    case KQOAuthRequest::TemporaryCredentials:
        requestParameters.append( qMakePair( OAUTH_KEY_CALLBACK, QString(QUrl::toPercentEncoding( oauthCallbackUrl.toString()) )));  // This is so ugly that it is almost beautiful.
        requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
        requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
        requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
        requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
        insertAdditionalParams(requestParameters);
        break;

    case KQOAuthRequest::AccessToken:
        requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
        requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
        requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
        requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERIFIER, oauthVerifier ));
        requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken ));
        insertAdditionalParams(requestParameters);
        break;

    case KQOAuthRequest::AuthorizedRequest:
        requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
        requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
        requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
        requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
        requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken ));
        insertAdditionalParams(requestParameters);
        break;

    default:
        break;
    }
}

void KQOAuthRequestPrivate::insertAdditionalParams(QList< QPair<QString, QString> > &requestParams) {
    QList<QString> additionalKeys = this->additionalParams.keys();
    QList<QString> additionalValues = this->additionalParams.values();

    for(int i=0; i<additionalKeys.size(); i++) {
        requestParams.append( qMakePair(QString(QUrl::toPercentEncoding(additionalKeys.at(i))),
                                        QString(QUrl::toPercentEncoding(additionalValues.at(i))))
                             );
    }

    if (oauthHttpMethod == KQOAuthRequest::POST) {
        insertPostBody();
    }
}

void KQOAuthRequestPrivate::insertPostBody() {
    QList<QString> postBodyKeys = this->additionalParams.keys();
    QList<QString> postBodyValues = this->additionalParams.values();

    postBodyContent.clear();
    bool first = true;
    for(int i=0; i<postBodyKeys.size(); i++) {
        if(!first) {
            postBodyContent.append("&");
        } else {
            first = false;
        }

        QString key = postBodyKeys.at(i);
        QString value = postBodyValues.at(i);

        postBodyContent.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() +
                               QUrl::toPercentEncoding(value));
    }

}

void KQOAuthRequestPrivate::signRequest() {
    QString signature = this->oauthSignature();
    requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE, signature) );
}

QString KQOAuthRequestPrivate::oauthSignature()  {
    QByteArray baseString = this->requestBaseString();

    QString signature = KQOAuthUtils::hmac_sha1(baseString, oauthConsumerSecretKey + "&" + oauthTokenSecret);
    return QString( QUrl::toPercentEncoding( signature ) );
}

bool normalizedParameterSort(const QPair<QString, QString> &left, const QPair<QString, QString> &right) {
    QString keyLeft = left.first;
    QString valueLeft = left.second;
    QString keyRight = right.first;
    QString valueRight = right.second;

    if(keyLeft == keyRight) {
        return (valueLeft < valueRight);
    } else {
        return (keyLeft < keyRight);
    }
}
QByteArray KQOAuthRequestPrivate::requestBaseString() {
    QByteArray baseString;

    // Every request has these as the commont parameters.
    baseString.append( oauthHttpMethodString.toUtf8() + "&");                                                     // HTTP method
    baseString.append( QUrl::toPercentEncoding( oauthRequestEndpoint.toString(QUrl::RemoveQuery) ) + "&" ); // The path and query components

    QList< QPair<QString, QString> > baseStringParameters;
    baseStringParameters.append(requestParameters);

    // Sort the request parameters. These parameters have been
    // initialized earlier.
    qSort(baseStringParameters.begin(),
          baseStringParameters.end(),
          normalizedParameterSort
          );

    // Last append the request parameters correctly encoded.
    baseString.append( encodedParamaterList(baseStringParameters) );

    return baseString;
}

QByteArray KQOAuthRequestPrivate::encodedParamaterList(const QList< QPair<QString, QString> > &parameters) {
    QByteArray resultList;

    bool first = true;
    QPair<QString, QString> parameter;
    foreach (parameter, parameters) {
        if(!first) {
            resultList.append( "%26" );
        } else {
            first = false;
        }

        // Here we don't need to explicitely encode the strings to UTF-8 since
        // QUrl::toPercentEncoding() takes care of that for us.
        resultList.append( QUrl::toPercentEncoding(parameter.first)     // Parameter key
                           + "%3D"                                      // '=' encoded
                           + QUrl::toPercentEncoding(parameter.second)  // Parameter value
                          );
    }

    return resultList;
}

QString KQOAuthRequestPrivate::oauthTimestamp() const {
    // This is basically for unit tests only. In most cases we don't set the nonce beforehand.
    if (!oauthTimestamp_.isEmpty()) {
        return oauthTimestamp_;
    }

#if QT_VERSION >= 0x040700
    return QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#else
   return QString::number(QDateTime::currentDateTime().toUTC().toTime_t());
#endif

}

QString KQOAuthRequestPrivate::oauthNonce() const {
    // This is basically for unit tests only. In most cases we don't set the nonce beforehand.
    if (!oauthNonce_.isEmpty()) {
        return oauthNonce_;
    }

    return QString::number(qrand());
}

bool KQOAuthRequestPrivate::validateRequest() const {
    switch ( requestType ) {
    case KQOAuthRequest::TemporaryCredentials:
        if (oauthRequestEndpoint.isEmpty()
            || oauthConsumerKey.isEmpty()
            || oauthNonce_.isEmpty()
            || oauthSignatureMethod.isEmpty()
            || oauthTimestamp_.isEmpty()
            || oauthVersion.isEmpty())
        {
            return false;
        }
        return true;

    case KQOAuthRequest::AccessToken:
        if (oauthRequestEndpoint.isEmpty()
            ||  oauthVerifier.isEmpty()
            || oauthConsumerKey.isEmpty()
            || oauthNonce_.isEmpty()
            || oauthSignatureMethod.isEmpty()
            || oauthTimestamp_.isEmpty()
            || oauthToken.isEmpty()
            || oauthTokenSecret.isEmpty()
            || oauthVersion.isEmpty())
        {
            return false;
        }
        return true;

    case KQOAuthRequest::AuthorizedRequest:
        if (oauthRequestEndpoint.isEmpty()
            || oauthConsumerKey.isEmpty()
            || oauthNonce_.isEmpty()
            || oauthSignatureMethod.isEmpty()
            || oauthTimestamp_.isEmpty()
            || oauthToken.isEmpty()
            || oauthTokenSecret.isEmpty()
            || oauthVersion.isEmpty())
        {
            return false;
        }
        return true;

    default:
        return false;
    }

    // We should not come here.
    return false;
}

QByteArray KQOAuthRequestPrivate::requestBody() const {
    return postBodyContent;
}

//////////// Public implementation ////////////////

KQOAuthRequest::KQOAuthRequest(QObject *parent) :
    QObject(parent),
    d_ptr(new KQOAuthRequestPrivate)
{
}

KQOAuthRequest::~KQOAuthRequest()
{
    delete d_ptr;
}

void KQOAuthRequest::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) {
    Q_D(KQOAuthRequest);

    if (!requestEndpoint.isValid()) {
        qWarning() << "Endpoint URL is not valid. Ignoring. This request might not work.";
        return;
    }

    if (type < 0 || type > KQOAuthRequest::AuthorizedRequest) {
        qWarning() << "Invalid request type. Ignoring. This request might not work.";
        return;
    }

    // Clear the request
    clearRequest();

    // Set smart defaults.
    d->requestType = type;
    d->oauthRequestEndpoint = requestEndpoint;
    d->oauthTimestamp_ = d->oauthTimestamp();
    d->oauthNonce_ = d->oauthNonce();
    this->setSignatureMethod(KQOAuthRequest::HMAC_SHA1);
    this->setHttpMethod(KQOAuthRequest::POST);
    d->oauthVersion = "1.0"; // Currently supports only version 1.0
}

void KQOAuthRequest::setConsumerKey(const QString &consumerKey) {
    Q_D(KQOAuthRequest);
    d->oauthConsumerKey = consumerKey;
}

void KQOAuthRequest::setConsumerSecretKey(const QString &consumerSecretKey) {
    Q_D(KQOAuthRequest);
    d->oauthConsumerSecretKey = consumerSecretKey;
}

void KQOAuthRequest::setCallbackUrl(const QUrl &callbackUrl) {
    Q_D(KQOAuthRequest);

    d->oauthCallbackUrl = callbackUrl;
}

void KQOAuthRequest::setSignatureMethod(KQOAuthRequest::RequestSignatureMethod requestMethod) {
    Q_D(KQOAuthRequest);
    QString requestMethodString;

    switch (requestMethod) {
    case KQOAuthRequest::PLAINTEXT:
        requestMethodString = "PLAINTEXT";
        break;
    case KQOAuthRequest::HMAC_SHA1:
        requestMethodString = "HMAC-SHA1";
        break;
    case KQOAuthRequest::RSA_SHA1:
        requestMethodString = "RSA-SHA1";
        break;
    default:
        // We should not come here
        qWarning() << "Invalid signature method set.";
        break;
    }

    d->oauthSignatureMethod = requestMethodString;
}

void KQOAuthRequest::setTokenSecret(const QString &tokenSecret) {
    Q_D(KQOAuthRequest);

    d->oauthTokenSecret = tokenSecret;
}

void KQOAuthRequest::setToken(const QString &token) {
    Q_D(KQOAuthRequest);

    d->oauthToken = token;
}

void KQOAuthRequest::setVerifier(const QString &verifier) {
    Q_D(KQOAuthRequest);

    d->oauthVerifier = verifier;
}

void KQOAuthRequest::setHttpMethod(KQOAuthRequest::RequestHttpMethod httpMethod) {
    Q_D(KQOAuthRequest);

    QString requestHttpMethodString;

    switch (httpMethod) {
    case KQOAuthRequest::GET:
        requestHttpMethodString = "GET";
        break;
    case KQOAuthRequest::POST:
        requestHttpMethodString = "POST";
        break;
    default:
        qWarning() << "Invalid HTTP method set.";
        break;
    }

    d->oauthHttpMethod = httpMethod;
    d->oauthHttpMethodString = requestHttpMethodString;
}

KQOAuthRequest::RequestHttpMethod KQOAuthRequest::httpMethod() const {
    Q_D(const KQOAuthRequest);

    return d->oauthHttpMethod;
}

void KQOAuthRequest::setAdditionalParameters(const KQOAuthParameters &additionalParams) {
    Q_D(KQOAuthRequest);

    d->additionalParams = additionalParams;
}

KQOAuthParameters KQOAuthRequest::additionalParameters() const {
    Q_D(const KQOAuthRequest);

    return d->additionalParams;
}

KQOAuthRequest::RequestType KQOAuthRequest::requestType() const {
    Q_D(const KQOAuthRequest);

    return d->requestType;
}

QUrl KQOAuthRequest::requestEndpoint() const {
    Q_D(const KQOAuthRequest);

    return d->oauthRequestEndpoint;
}

QList<QByteArray> KQOAuthRequest::requestParameters() {
    Q_D(KQOAuthRequest);

    QList<QByteArray> requestParamList;

    d->prepareRequest();
    if (!d->validateRequest() ) {
        qWarning() << "Request is not valid! I will still sign it, but it will probably not work.";
    }
    d->signRequest();

    QPair<QString, QString> requestParam;
    QString param;
    QString value;
    foreach (requestParam, d->requestParameters) {
        param = requestParam.first;
        value = requestParam.second;
        requestParamList.append(QString(param + "=\"" + value +"\"").toUtf8());
    }

    return requestParamList;
}

bool KQOAuthRequest::isValid() const {
    Q_D(const KQOAuthRequest);

    return d->validateRequest();
}

void KQOAuthRequest::clearRequest() {
    Q_D(KQOAuthRequest);

    d->oauthRequestEndpoint = "";
    d->oauthHttpMethodString = "";
    d->oauthConsumerKey = "";
    d->oauthConsumerSecretKey = "";
    d->oauthToken = "";
    d->oauthTokenSecret = "";
    d->oauthSignatureMethod = "";
    d->oauthCallbackUrl = "";
    d->oauthVerifier = "";
    d->oauthTimestamp_ = "";
    d->oauthNonce_ = "";
    d->requestParameters.clear();
    d->additionalParams.clear();
}

<commit_msg>Fixed HMAC-SHA1 secret creation as per OAuth 1.0 spec<commit_after>/**
 * KQOAuth - An OAuth authentication library for Qt.
 *
 * Author: Johan Paul (johan.paul@d-pointer.com)
 *         http://www.d-pointer.com
 *
 *  KQOAuth is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  KQOAuth is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with KQOAuth.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <QByteArray>
#include <QDateTime>
#include <QCryptographicHash>
#include <QPair>
#include <QStringList>

#include <QtDebug>
#include <QtAlgorithms>

#include "kqoauthrequest.h"
#include "kqoauthrequest_p.h"
#include "kqoauthutils.h"
#include "kqoauthglobals.h"

//////////// Private d_ptr implementation /////////

KQOAuthRequestPrivate::KQOAuthRequestPrivate()
{

}

KQOAuthRequestPrivate::~KQOAuthRequestPrivate()
{

}

// This method will not include the "oauthSignature" paramater, since it is calculated from these parameters.
void KQOAuthRequestPrivate::prepareRequest() {

    // If parameter list is not empty, we don't want to insert these values by
    // accident a second time. So giving up.
    if( !requestParameters.isEmpty() ) {
        return;
    }

    switch ( requestType ) {
    case KQOAuthRequest::TemporaryCredentials:
        requestParameters.append( qMakePair( OAUTH_KEY_CALLBACK, QString(QUrl::toPercentEncoding( oauthCallbackUrl.toString()) )));  // This is so ugly that it is almost beautiful.
        requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
        requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
        requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
        requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
        insertAdditionalParams(requestParameters);
        break;

    case KQOAuthRequest::AccessToken:
        requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
        requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
        requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
        requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERIFIER, oauthVerifier ));
        requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken ));
        insertAdditionalParams(requestParameters);
        break;

    case KQOAuthRequest::AuthorizedRequest:
        requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
        requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
        requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
        requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
        requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
        requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken ));
        insertAdditionalParams(requestParameters);
        break;

    default:
        break;
    }
}

void KQOAuthRequestPrivate::insertAdditionalParams(QList< QPair<QString, QString> > &requestParams) {
    QList<QString> additionalKeys = this->additionalParams.keys();
    QList<QString> additionalValues = this->additionalParams.values();

    for(int i=0; i<additionalKeys.size(); i++) {
        requestParams.append( qMakePair(QString(QUrl::toPercentEncoding(additionalKeys.at(i))),
                                        QString(QUrl::toPercentEncoding(additionalValues.at(i))))
                             );
    }

    if (oauthHttpMethod == KQOAuthRequest::POST) {
        insertPostBody();
    }
}

void KQOAuthRequestPrivate::insertPostBody() {
    QList<QString> postBodyKeys = this->additionalParams.keys();
    QList<QString> postBodyValues = this->additionalParams.values();

    postBodyContent.clear();
    bool first = true;
    for(int i=0; i<postBodyKeys.size(); i++) {
        if(!first) {
            postBodyContent.append("&");
        } else {
            first = false;
        }

        QString key = postBodyKeys.at(i);
        QString value = postBodyValues.at(i);

        postBodyContent.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() +
                               QUrl::toPercentEncoding(value));
    }

}

void KQOAuthRequestPrivate::signRequest() {
    QString signature = this->oauthSignature();
    requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE, signature) );
}

QString KQOAuthRequestPrivate::oauthSignature()  {
    /**
     * http://oauth.net/core/1.0/#anchor16
     * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] where the
     * Signature Base String is the text and the key is the concatenated values (each first encoded per Parameter
     * Encoding) of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty.
     **/
    QByteArray baseString = this->requestBaseString();

    QString secret = QString(QUrl::toPercentEncoding(oauthConsumerSecretKey)) + "&" + QString(QUrl::toPercentEncoding(oauthTokenSecret));
    QString signature = KQOAuthUtils::hmac_sha1(baseString, secret);
    return QString( QUrl::toPercentEncoding( signature ) );
}

bool normalizedParameterSort(const QPair<QString, QString> &left, const QPair<QString, QString> &right) {
    QString keyLeft = left.first;
    QString valueLeft = left.second;
    QString keyRight = right.first;
    QString valueRight = right.second;

    if(keyLeft == keyRight) {
        return (valueLeft < valueRight);
    } else {
        return (keyLeft < keyRight);
    }
}
QByteArray KQOAuthRequestPrivate::requestBaseString() {
    QByteArray baseString;

    // Every request has these as the commont parameters.
    baseString.append( oauthHttpMethodString.toUtf8() + "&");                                                     // HTTP method
    baseString.append( QUrl::toPercentEncoding( oauthRequestEndpoint.toString(QUrl::RemoveQuery) ) + "&" ); // The path and query components

    QList< QPair<QString, QString> > baseStringParameters;
    baseStringParameters.append(requestParameters);

    // Sort the request parameters. These parameters have been
    // initialized earlier.
    qSort(baseStringParameters.begin(),
          baseStringParameters.end(),
          normalizedParameterSort
          );

    // Last append the request parameters correctly encoded.
    baseString.append( encodedParamaterList(baseStringParameters) );

    return baseString;
}

QByteArray KQOAuthRequestPrivate::encodedParamaterList(const QList< QPair<QString, QString> > &parameters) {
    QByteArray resultList;

    bool first = true;
    QPair<QString, QString> parameter;
    foreach (parameter, parameters) {
        if(!first) {
            resultList.append( "%26" );
        } else {
            first = false;
        }

        // Here we don't need to explicitely encode the strings to UTF-8 since
        // QUrl::toPercentEncoding() takes care of that for us.
        resultList.append( QUrl::toPercentEncoding(parameter.first)     // Parameter key
                           + "%3D"                                      // '=' encoded
                           + QUrl::toPercentEncoding(parameter.second)  // Parameter value
                          );
    }

    return resultList;
}

QString KQOAuthRequestPrivate::oauthTimestamp() const {
    // This is basically for unit tests only. In most cases we don't set the nonce beforehand.
    if (!oauthTimestamp_.isEmpty()) {
        return oauthTimestamp_;
    }

#if QT_VERSION >= 0x040700
    return QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#else
   return QString::number(QDateTime::currentDateTime().toUTC().toTime_t());
#endif

}

QString KQOAuthRequestPrivate::oauthNonce() const {
    // This is basically for unit tests only. In most cases we don't set the nonce beforehand.
    if (!oauthNonce_.isEmpty()) {
        return oauthNonce_;
    }

    return QString::number(qrand());
}

bool KQOAuthRequestPrivate::validateRequest() const {
    switch ( requestType ) {
    case KQOAuthRequest::TemporaryCredentials:
        if (oauthRequestEndpoint.isEmpty()
            || oauthConsumerKey.isEmpty()
            || oauthNonce_.isEmpty()
            || oauthSignatureMethod.isEmpty()
            || oauthTimestamp_.isEmpty()
            || oauthVersion.isEmpty())
        {
            return false;
        }
        return true;

    case KQOAuthRequest::AccessToken:
        if (oauthRequestEndpoint.isEmpty()
            ||  oauthVerifier.isEmpty()
            || oauthConsumerKey.isEmpty()
            || oauthNonce_.isEmpty()
            || oauthSignatureMethod.isEmpty()
            || oauthTimestamp_.isEmpty()
            || oauthToken.isEmpty()
            || oauthTokenSecret.isEmpty()
            || oauthVersion.isEmpty())
        {
            return false;
        }
        return true;

    case KQOAuthRequest::AuthorizedRequest:
        if (oauthRequestEndpoint.isEmpty()
            || oauthConsumerKey.isEmpty()
            || oauthNonce_.isEmpty()
            || oauthSignatureMethod.isEmpty()
            || oauthTimestamp_.isEmpty()
            || oauthToken.isEmpty()
            || oauthTokenSecret.isEmpty()
            || oauthVersion.isEmpty())
        {
            return false;
        }
        return true;

    default:
        return false;
    }

    // We should not come here.
    return false;
}

QByteArray KQOAuthRequestPrivate::requestBody() const {
    return postBodyContent;
}

//////////// Public implementation ////////////////

KQOAuthRequest::KQOAuthRequest(QObject *parent) :
    QObject(parent),
    d_ptr(new KQOAuthRequestPrivate)
{
}

KQOAuthRequest::~KQOAuthRequest()
{
    delete d_ptr;
}

void KQOAuthRequest::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) {
    Q_D(KQOAuthRequest);

    if (!requestEndpoint.isValid()) {
        qWarning() << "Endpoint URL is not valid. Ignoring. This request might not work.";
        return;
    }

    if (type < 0 || type > KQOAuthRequest::AuthorizedRequest) {
        qWarning() << "Invalid request type. Ignoring. This request might not work.";
        return;
    }

    // Clear the request
    clearRequest();

    // Set smart defaults.
    d->requestType = type;
    d->oauthRequestEndpoint = requestEndpoint;
    d->oauthTimestamp_ = d->oauthTimestamp();
    d->oauthNonce_ = d->oauthNonce();
    this->setSignatureMethod(KQOAuthRequest::HMAC_SHA1);
    this->setHttpMethod(KQOAuthRequest::POST);
    d->oauthVersion = "1.0"; // Currently supports only version 1.0
}

void KQOAuthRequest::setConsumerKey(const QString &consumerKey) {
    Q_D(KQOAuthRequest);
    d->oauthConsumerKey = consumerKey;
}

void KQOAuthRequest::setConsumerSecretKey(const QString &consumerSecretKey) {
    Q_D(KQOAuthRequest);
    d->oauthConsumerSecretKey = consumerSecretKey;
}

void KQOAuthRequest::setCallbackUrl(const QUrl &callbackUrl) {
    Q_D(KQOAuthRequest);

    d->oauthCallbackUrl = callbackUrl;
}

void KQOAuthRequest::setSignatureMethod(KQOAuthRequest::RequestSignatureMethod requestMethod) {
    Q_D(KQOAuthRequest);
    QString requestMethodString;

    switch (requestMethod) {
    case KQOAuthRequest::PLAINTEXT:
        requestMethodString = "PLAINTEXT";
        break;
    case KQOAuthRequest::HMAC_SHA1:
        requestMethodString = "HMAC-SHA1";
        break;
    case KQOAuthRequest::RSA_SHA1:
        requestMethodString = "RSA-SHA1";
        break;
    default:
        // We should not come here
        qWarning() << "Invalid signature method set.";
        break;
    }

    d->oauthSignatureMethod = requestMethodString;
}

void KQOAuthRequest::setTokenSecret(const QString &tokenSecret) {
    Q_D(KQOAuthRequest);

    d->oauthTokenSecret = tokenSecret;
}

void KQOAuthRequest::setToken(const QString &token) {
    Q_D(KQOAuthRequest);

    d->oauthToken = token;
}

void KQOAuthRequest::setVerifier(const QString &verifier) {
    Q_D(KQOAuthRequest);

    d->oauthVerifier = verifier;
}

void KQOAuthRequest::setHttpMethod(KQOAuthRequest::RequestHttpMethod httpMethod) {
    Q_D(KQOAuthRequest);

    QString requestHttpMethodString;

    switch (httpMethod) {
    case KQOAuthRequest::GET:
        requestHttpMethodString = "GET";
        break;
    case KQOAuthRequest::POST:
        requestHttpMethodString = "POST";
        break;
    default:
        qWarning() << "Invalid HTTP method set.";
        break;
    }

    d->oauthHttpMethod = httpMethod;
    d->oauthHttpMethodString = requestHttpMethodString;
}

KQOAuthRequest::RequestHttpMethod KQOAuthRequest::httpMethod() const {
    Q_D(const KQOAuthRequest);

    return d->oauthHttpMethod;
}

void KQOAuthRequest::setAdditionalParameters(const KQOAuthParameters &additionalParams) {
    Q_D(KQOAuthRequest);

    d->additionalParams = additionalParams;
}

KQOAuthParameters KQOAuthRequest::additionalParameters() const {
    Q_D(const KQOAuthRequest);

    return d->additionalParams;
}

KQOAuthRequest::RequestType KQOAuthRequest::requestType() const {
    Q_D(const KQOAuthRequest);

    return d->requestType;
}

QUrl KQOAuthRequest::requestEndpoint() const {
    Q_D(const KQOAuthRequest);

    return d->oauthRequestEndpoint;
}

QList<QByteArray> KQOAuthRequest::requestParameters() {
    Q_D(KQOAuthRequest);

    QList<QByteArray> requestParamList;

    d->prepareRequest();
    if (!d->validateRequest() ) {
        qWarning() << "Request is not valid! I will still sign it, but it will probably not work.";
    }
    d->signRequest();

    QPair<QString, QString> requestParam;
    QString param;
    QString value;
    foreach (requestParam, d->requestParameters) {
        param = requestParam.first;
        value = requestParam.second;
        requestParamList.append(QString(param + "=\"" + value +"\"").toUtf8());
    }

    return requestParamList;
}

bool KQOAuthRequest::isValid() const {
    Q_D(const KQOAuthRequest);

    return d->validateRequest();
}

void KQOAuthRequest::clearRequest() {
    Q_D(KQOAuthRequest);

    d->oauthRequestEndpoint = "";
    d->oauthHttpMethodString = "";
    d->oauthConsumerKey = "";
    d->oauthConsumerSecretKey = "";
    d->oauthToken = "";
    d->oauthTokenSecret = "";
    d->oauthSignatureMethod = "";
    d->oauthCallbackUrl = "";
    d->oauthVerifier = "";
    d->oauthTimestamp_ = "";
    d->oauthNonce_ = "";
    d->requestParameters.clear();
    d->additionalParams.clear();
}

<|endoftext|>


<commit_before>// Author: Wim Lavrijsen   March 2008

// Bindings
#include "PyROOT.h"
#include "TPySelector.h"
#include "TPyReturn.h"
#include "ObjectProxy.h"
#include "MethodProxy.h"
#include "RootWrapper.h"
#include "MemoryRegulator.h"

//- ROOT
#include "TPython.h"
#include "TString.h"

//______________________________________________________________________________
//                      Python equivalent PROOF base class
//                      ==================================
//
// The problem with deriving a python class from a PyROOT bound class and then
// handing it back to a C++ framework, is that the virtual function dispatching
// of C++ is completely oblivious to the methods overridden in python. To work
// within the PROOF (C++) framework, a python class should derive from the class
// TPySelector. This class provides the proper overrides on the C++ side, and
// then forwards them, as apropriate, to python.
//
// This is an example set of scripts:
//
// ### PROOF running script, very close to equivalent .C (prooftest.py)
// import time
// from ROOT import *
//
// dataset = TDSet( 'TTree', 'h42' )
// dataset.Add( 'root:// .... myfile.root' )
//
// proof = TProof.Open('')
// time.sleep(1)                     # needed for GUI to settle
// print dataset.Process( 'TPySelector', 'aapje' )
// ### EOF
//
// ### selector module (aapje.py, name has to match as per above)
// from ROOT import TPySelector
//
// class MyPySelector( TPySelector ):
//    def Begin( self ):
//       print 'py: beginning'
//
//    def SlaveBegin( self, tree ):
//       print 'py: slave beginning'
//
//    def Process( self, entry ):
//       if self.fChain.GetEntry( entry ) <= 0:
//          return 0
//       print 'py: processing', self.fChain.MyVar
//       return 1
//
//   def SlaveTerminate( self ):
//       print 'py: slave terminating'
//
//   def Terminate( self ):
//       print 'py: terminating'
// ### EOF

//- data ---------------------------------------------------------------------
ClassImp(TPySelector)

//- private helpers ----------------------------------------------------------
void TPySelector::SetupPySelf()
{
   if ( fPySelf && fPySelf != Py_None )
      return;                      // already created ...

   TString impst = TString::Format( "import %s", GetOption() );

// use TPython to ensure that the interpreter is initialized
   if ( ! TPython::Exec( (const char*)impst ) ) {
      Abort( "failed to load provided python module" );  // Exec already printed error trace
      return;
   }

// get the TPySelector python class
   PyObject* tpysel = PyObject_GetAttrString(
      PyImport_AddModule( const_cast< char* >( "libPyROOT" ) ),
      const_cast< char* >( "TPySelector" ) );

// get handle to the module
   PyObject* pymod = PyImport_AddModule( const_cast< char* >( GetOption() ) );

// get the module dictionary to loop over
   PyObject* dict = PyModule_GetDict( pymod );
   Py_INCREF( dict );

// locate the TSelector derived class
   PyObject* allvalues = PyDict_Values( dict );

   PyObject* pyclass = 0;
   for ( int i = 0; i < PyList_GET_SIZE( allvalues ); ++i ) {
      PyObject* value = PyList_GET_ITEM( allvalues, i );
      Py_INCREF( value );

      if ( PyType_Check( value ) && PyObject_IsSubclass( value, tpysel ) ) {
         if ( PyObject_Compare(	value, tpysel ) ) {    // i.e., if not equal
            pyclass = value;
            break;
         }
      }

      Py_DECREF( value );
   }

   Py_DECREF( allvalues );
   Py_DECREF( dict );
   Py_DECREF( tpysel );

   if ( ! pyclass ) {
      Abort( "no TSelector derived class available in provided module" );
      return;
   }

   PyObject* args = PyTuple_New( 0 );
   PyObject* self = PyObject_Call( pyclass, args, 0 );
   Py_DECREF( args );
   Py_DECREF( pyclass );

// final check before declaring success ...
   if ( ! self || ! PyROOT::ObjectProxy_Check( self ) ) {
      if ( ! PyErr_Occurred() )
         PyErr_SetString( PyExc_RuntimeError, "could not create python selector" );
      Py_XDECREF( self );
      Abort( 0 );
      return;
   }

// steal reference to new self, since the deletion will come from the C++ side
   Py_DECREF( fPySelf );
   fPySelf = self;

// inject ourselves into the base of self; destroy old identity if need be (which happens
// if the user calls the default ctor unnecessarily)
   TPySelector* oldselector = (TPySelector*)((PyROOT::ObjectProxy*)fPySelf)->fObject;
   ((PyROOT::ObjectProxy*)fPySelf)->fObject = this;
   if ( oldselector ) {
      PyROOT::TMemoryRegulator::UnregisterObject( oldselector );
      delete oldselector;
   }
}

//____________________________________________________________________________
PyObject* TPySelector::CallSelf( const char* method, PyObject* pyobject )
{
// Forward <method> to python.
   if ( ! fPySelf || fPySelf == Py_None ) {
      Py_INCREF( Py_None );
      return Py_None;
   }

   PyObject* result = 0;

// get the named method and check for python side overload by not accepting the
// binding's methodproxy
   PyObject* pymethod = PyObject_GetAttrString( fPySelf, const_cast< char* >( method ) );
   if ( ! PyROOT::MethodProxy_CheckExact( pymethod ) ) {
      if ( pyobject )
         result = PyObject_CallFunction( pymethod, const_cast< char* >( "O" ), pyobject );
      else
         result = PyObject_CallFunction( pymethod, const_cast< char* >( "" ) );
   } else {
   // silently ignore if method not overridden (note that the above can't lead
   // to a python exception, since this (TPySelector) class contains the method
   // so it is always to be found)
      Py_INCREF( Py_None );
      result = Py_None;
   }

   Py_XDECREF( pymethod );

   if ( ! result )
      Abort( 0 );

   return result;
}

//- constructors/destructor --------------------------------------------------
TPySelector::TPySelector( TTree*, PyObject* self ) : fChain( 0 ), fPySelf( 0 )
{
// Construct a TSelector derived with <self> as the underlying, which is
// generally 0 to start out with in the current PROOF framework.
   if ( self ) {
   // steal reference as this is us, as seen from python
      fPySelf = self;
   } else {
      Py_INCREF( Py_None );        // using None allows clearer diagnostics
      fPySelf = Py_None;
   }
}

//____________________________________________________________________________
TPySelector::~TPySelector()
{
// Destructor. Only deref if still holding on to Py_None (circular otherwise).
   if ( fPySelf == Py_None )
      Py_DECREF( fPySelf );
}

//- public functions ---------------------------------------------------------
Int_t TPySelector::Version() const {
// Return version number of this selector. First forward; if not overridden, then
// yield an obvious "undefined" number,
   PyObject* result = const_cast< TPySelector* >( this )->CallSelf( "Version" );
   if ( result && result != Py_None ) {
      Int_t ires = (Int_t)PyLong_AsLong( result );
      Py_DECREF( result );
      return ires;
   } else if ( result == Py_None ) {
      Py_DECREF( result );
   }
   return -99;
}

//____________________________________________________________________________
Int_t TPySelector::GetEntry( Long64_t entry, Int_t getall )
{
// Boilerplate get entry; same as for generated code; not forwarded.
   return fChain ? fChain->GetTree()->GetEntry( entry, getall ) : 0;
}

//____________________________________________________________________________
void TPySelector::Init( TTree* tree )
{
// Initialize with the current tree to be used; not forwarded (may be called
// multiple times, and is called from Begin() and SlaveBegin() ).
   if ( ! tree )
      return;

// set the fChain beforehand so that the python side may correct if needed
   fChain = tree;

// forward call
   PyObject* pytree = PyROOT::BindRootObject( (void*)tree, tree->IsA() );
   PyObject* result = CallSelf( "Init", pytree );
   Py_DECREF( pytree );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
Bool_t TPySelector::Notify()
{
// Forward call to derived Notify() if available.
   PyObject* result = CallSelf( "Notify" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );

// by default, return kTRUE, b/c the Abort will stop the processing anyway on
// a real error, so if we get here it usually means that there is no Notify()
// override on the python side of things
   return kTRUE;
}

//____________________________________________________________________________
void TPySelector::Begin( TTree* )
{
// First function called, and used to setup the python self; forward call.
   SetupPySelf();

// As per the generated code: the tree argument is deprecated (on PROOF 0 is
// passed), and hence not forwarded.
   PyObject* result = CallSelf( "Begin" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
void TPySelector::SlaveBegin( TTree* tree )
{
// First function called on worker node, needs to make sure python self is setup,
// then store the tree to be used, initialize client, and forward call.
   SetupPySelf();
   Init( tree );

   PyObject* result = 0;
   if ( tree ) {
      PyObject* pytree = PyROOT::BindRootObject( (void*)tree, tree->IsA() );
      result = CallSelf( "SlaveBegin", pytree );
      Py_DECREF( pytree );
   } else {
      result = CallSelf( "SlaveBegin", Py_None );
   }

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
Bool_t TPySelector::Process( Long64_t entry )
{
// Actual processing; call is forwarded to python self.
   if ( ! fPySelf || fPySelf == Py_None ) {
   // would like to set a python error, but can't risk that in case of a
   // configuration problem, as it would be absorbed ...

   // simply returning kFALSE will not stop processing; need to set abort
      Abort( "no python selector instance available" );
      return kFALSE;
   }

   PyObject* result = PyObject_CallMethod( fPySelf,
      const_cast< char* >( "Process" ), const_cast< char* >( "L" ), entry );
   if ( ! result ) {
      Abort( 0 );
      return kFALSE;
   }

   Bool_t bresult = (Bool_t)PyLong_AsLong( result );
   Py_DECREF( result );
   return bresult;
}

//____________________________________________________________________________
void TPySelector::SlaveTerminate()
{
// End of client; call is forwarded to python self.
   PyObject* result = CallSelf( "SlaveTerminate" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
void TPySelector::Terminate()
{
// End of job; call is forwarded to python self.
   PyObject* result = CallSelf( "Terminate" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
void TPySelector::Abort( const char* why, EAbort what )
{
// If no 'why' given, read from python error
   if ( ! why && PyErr_Occurred() ) {
      PyObject *pytype = 0, *pyvalue = 0, *pytrace = 0;
      PyErr_Fetch( &pytype, &pyvalue, &pytrace );

   // abort is delayed (done at end of loop, message is current)
      PyObject* pystr = PyObject_Str( pyvalue );
      Abort( PyString_AS_STRING( pystr ), what );
      Py_DECREF( pystr );

      PyErr_Restore( pytype, pyvalue, pytrace );
   } else
      TSelector::Abort( why ? why : "", what );
}
<commit_msg> o) fix for: "warning: suggest explicit braces to avoid ambiguous 'else'" on slc4_amd64_gcc43<commit_after>// Author: Wim Lavrijsen   March 2008

// Bindings
#include "PyROOT.h"
#include "TPySelector.h"
#include "TPyReturn.h"
#include "ObjectProxy.h"
#include "MethodProxy.h"
#include "RootWrapper.h"
#include "MemoryRegulator.h"

//- ROOT
#include "TPython.h"
#include "TString.h"

//______________________________________________________________________________
//                      Python equivalent PROOF base class
//                      ==================================
//
// The problem with deriving a python class from a PyROOT bound class and then
// handing it back to a C++ framework, is that the virtual function dispatching
// of C++ is completely oblivious to the methods overridden in python. To work
// within the PROOF (C++) framework, a python class should derive from the class
// TPySelector. This class provides the proper overrides on the C++ side, and
// then forwards them, as apropriate, to python.
//
// This is an example set of scripts:
//
// ### PROOF running script, very close to equivalent .C (prooftest.py)
// import time
// from ROOT import *
//
// dataset = TDSet( 'TTree', 'h42' )
// dataset.Add( 'root:// .... myfile.root' )
//
// proof = TProof.Open('')
// time.sleep(1)                     # needed for GUI to settle
// print dataset.Process( 'TPySelector', 'aapje' )
// ### EOF
//
// ### selector module (aapje.py, name has to match as per above)
// from ROOT import TPySelector
//
// class MyPySelector( TPySelector ):
//    def Begin( self ):
//       print 'py: beginning'
//
//    def SlaveBegin( self, tree ):
//       print 'py: slave beginning'
//
//    def Process( self, entry ):
//       if self.fChain.GetEntry( entry ) <= 0:
//          return 0
//       print 'py: processing', self.fChain.MyVar
//       return 1
//
//   def SlaveTerminate( self ):
//       print 'py: slave terminating'
//
//   def Terminate( self ):
//       print 'py: terminating'
// ### EOF

//- data ---------------------------------------------------------------------
ClassImp(TPySelector)

//- private helpers ----------------------------------------------------------
void TPySelector::SetupPySelf()
{
   if ( fPySelf && fPySelf != Py_None )
      return;                      // already created ...

   TString impst = TString::Format( "import %s", GetOption() );

// use TPython to ensure that the interpreter is initialized
   if ( ! TPython::Exec( (const char*)impst ) ) {
      Abort( "failed to load provided python module" );  // Exec already printed error trace
      return;
   }

// get the TPySelector python class
   PyObject* tpysel = PyObject_GetAttrString(
      PyImport_AddModule( const_cast< char* >( "libPyROOT" ) ),
      const_cast< char* >( "TPySelector" ) );

// get handle to the module
   PyObject* pymod = PyImport_AddModule( const_cast< char* >( GetOption() ) );

// get the module dictionary to loop over
   PyObject* dict = PyModule_GetDict( pymod );
   Py_INCREF( dict );

// locate the TSelector derived class
   PyObject* allvalues = PyDict_Values( dict );

   PyObject* pyclass = 0;
   for ( int i = 0; i < PyList_GET_SIZE( allvalues ); ++i ) {
      PyObject* value = PyList_GET_ITEM( allvalues, i );
      Py_INCREF( value );

      if ( PyType_Check( value ) && PyObject_IsSubclass( value, tpysel ) ) {
         if ( PyObject_Compare(	value, tpysel ) ) {    // i.e., if not equal
            pyclass = value;
            break;
         }
      }

      Py_DECREF( value );
   }

   Py_DECREF( allvalues );
   Py_DECREF( dict );
   Py_DECREF( tpysel );

   if ( ! pyclass ) {
      Abort( "no TSelector derived class available in provided module" );
      return;
   }

   PyObject* args = PyTuple_New( 0 );
   PyObject* self = PyObject_Call( pyclass, args, 0 );
   Py_DECREF( args );
   Py_DECREF( pyclass );

// final check before declaring success ...
   if ( ! self || ! PyROOT::ObjectProxy_Check( self ) ) {
      if ( ! PyErr_Occurred() )
         PyErr_SetString( PyExc_RuntimeError, "could not create python selector" );
      Py_XDECREF( self );
      Abort( 0 );
      return;
   }

// steal reference to new self, since the deletion will come from the C++ side
   Py_DECREF( fPySelf );
   fPySelf = self;

// inject ourselves into the base of self; destroy old identity if need be (which happens
// if the user calls the default ctor unnecessarily)
   TPySelector* oldselector = (TPySelector*)((PyROOT::ObjectProxy*)fPySelf)->fObject;
   ((PyROOT::ObjectProxy*)fPySelf)->fObject = this;
   if ( oldselector ) {
      PyROOT::TMemoryRegulator::UnregisterObject( oldselector );
      delete oldselector;
   }
}

//____________________________________________________________________________
PyObject* TPySelector::CallSelf( const char* method, PyObject* pyobject )
{
// Forward <method> to python.
   if ( ! fPySelf || fPySelf == Py_None ) {
      Py_INCREF( Py_None );
      return Py_None;
   }

   PyObject* result = 0;

// get the named method and check for python side overload by not accepting the
// binding's methodproxy
   PyObject* pymethod = PyObject_GetAttrString( fPySelf, const_cast< char* >( method ) );
   if ( ! PyROOT::MethodProxy_CheckExact( pymethod ) ) {
      if ( pyobject )
         result = PyObject_CallFunction( pymethod, const_cast< char* >( "O" ), pyobject );
      else
         result = PyObject_CallFunction( pymethod, const_cast< char* >( "" ) );
   } else {
   // silently ignore if method not overridden (note that the above can't lead
   // to a python exception, since this (TPySelector) class contains the method
   // so it is always to be found)
      Py_INCREF( Py_None );
      result = Py_None;
   }

   Py_XDECREF( pymethod );

   if ( ! result )
      Abort( 0 );

   return result;
}

//- constructors/destructor --------------------------------------------------
TPySelector::TPySelector( TTree*, PyObject* self ) : fChain( 0 ), fPySelf( 0 )
{
// Construct a TSelector derived with <self> as the underlying, which is
// generally 0 to start out with in the current PROOF framework.
   if ( self ) {
   // steal reference as this is us, as seen from python
      fPySelf = self;
   } else {
      Py_INCREF( Py_None );        // using None allows clearer diagnostics
      fPySelf = Py_None;
   }
}

//____________________________________________________________________________
TPySelector::~TPySelector()
{
// Destructor. Only deref if still holding on to Py_None (circular otherwise).
   if ( fPySelf == Py_None ) {
      Py_DECREF( fPySelf );
   }
}

//- public functions ---------------------------------------------------------
Int_t TPySelector::Version() const {
// Return version number of this selector. First forward; if not overridden, then
// yield an obvious "undefined" number,
   PyObject* result = const_cast< TPySelector* >( this )->CallSelf( "Version" );
   if ( result && result != Py_None ) {
      Int_t ires = (Int_t)PyLong_AsLong( result );
      Py_DECREF( result );
      return ires;
   } else if ( result == Py_None ) {
      Py_DECREF( result );
   }
   return -99;
}

//____________________________________________________________________________
Int_t TPySelector::GetEntry( Long64_t entry, Int_t getall )
{
// Boilerplate get entry; same as for generated code; not forwarded.
   return fChain ? fChain->GetTree()->GetEntry( entry, getall ) : 0;
}

//____________________________________________________________________________
void TPySelector::Init( TTree* tree )
{
// Initialize with the current tree to be used; not forwarded (may be called
// multiple times, and is called from Begin() and SlaveBegin() ).
   if ( ! tree )
      return;

// set the fChain beforehand so that the python side may correct if needed
   fChain = tree;

// forward call
   PyObject* pytree = PyROOT::BindRootObject( (void*)tree, tree->IsA() );
   PyObject* result = CallSelf( "Init", pytree );
   Py_DECREF( pytree );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
Bool_t TPySelector::Notify()
{
// Forward call to derived Notify() if available.
   PyObject* result = CallSelf( "Notify" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );

// by default, return kTRUE, b/c the Abort will stop the processing anyway on
// a real error, so if we get here it usually means that there is no Notify()
// override on the python side of things
   return kTRUE;
}

//____________________________________________________________________________
void TPySelector::Begin( TTree* )
{
// First function called, and used to setup the python self; forward call.
   SetupPySelf();

// As per the generated code: the tree argument is deprecated (on PROOF 0 is
// passed), and hence not forwarded.
   PyObject* result = CallSelf( "Begin" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
void TPySelector::SlaveBegin( TTree* tree )
{
// First function called on worker node, needs to make sure python self is setup,
// then store the tree to be used, initialize client, and forward call.
   SetupPySelf();
   Init( tree );

   PyObject* result = 0;
   if ( tree ) {
      PyObject* pytree = PyROOT::BindRootObject( (void*)tree, tree->IsA() );
      result = CallSelf( "SlaveBegin", pytree );
      Py_DECREF( pytree );
   } else {
      result = CallSelf( "SlaveBegin", Py_None );
   }

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
Bool_t TPySelector::Process( Long64_t entry )
{
// Actual processing; call is forwarded to python self.
   if ( ! fPySelf || fPySelf == Py_None ) {
   // would like to set a python error, but can't risk that in case of a
   // configuration problem, as it would be absorbed ...

   // simply returning kFALSE will not stop processing; need to set abort
      Abort( "no python selector instance available" );
      return kFALSE;
   }

   PyObject* result = PyObject_CallMethod( fPySelf,
      const_cast< char* >( "Process" ), const_cast< char* >( "L" ), entry );
   if ( ! result ) {
      Abort( 0 );
      return kFALSE;
   }

   Bool_t bresult = (Bool_t)PyLong_AsLong( result );
   Py_DECREF( result );
   return bresult;
}

//____________________________________________________________________________
void TPySelector::SlaveTerminate()
{
// End of client; call is forwarded to python self.
   PyObject* result = CallSelf( "SlaveTerminate" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
void TPySelector::Terminate()
{
// End of job; call is forwarded to python self.
   PyObject* result = CallSelf( "Terminate" );

   if ( ! result )
      Abort( 0 );

   Py_XDECREF( result );
}

//____________________________________________________________________________
void TPySelector::Abort( const char* why, EAbort what )
{
// If no 'why' given, read from python error
   if ( ! why && PyErr_Occurred() ) {
      PyObject *pytype = 0, *pyvalue = 0, *pytrace = 0;
      PyErr_Fetch( &pytype, &pyvalue, &pytrace );

   // abort is delayed (done at end of loop, message is current)
      PyObject* pystr = PyObject_Str( pyvalue );
      Abort( PyString_AS_STRING( pystr ), what );
      Py_DECREF( pystr );

      PyErr_Restore( pytype, pyvalue, pytrace );
   } else
      TSelector::Abort( why ? why : "", what );
}
<|endoftext|>


<commit_before>/*

@Copyright Barrett Adair 2015-2017
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

*/

#ifndef BOOST_CLBL_TRTS_BOOST_CLBL_TRTS_HPP
#define BOOST_CLBL_TRTS_BOOST_CLBL_TRTS_HPP

#include <boost/callable_traits/detail/core.hpp>
#include <boost/callable_traits/add_member_const.hpp>
#include <boost/callable_traits/add_member_cv.hpp>
#include <boost/callable_traits/add_member_lvalue_reference.hpp>
#include <boost/callable_traits/add_member_rvalue_reference.hpp>
#include <boost/callable_traits/add_member_volatile.hpp>
#include <boost/callable_traits/add_noexcept.hpp>
#include <boost/callable_traits/add_transaction_safe.hpp>
#include <boost/callable_traits/add_varargs.hpp>
#include <boost/callable_traits/apply_member_pointer.hpp>
#include <boost/callable_traits/apply_return.hpp>
#include <boost/callable_traits/args.hpp>
#include <boost/callable_traits/class_of.hpp>
#include <boost/callable_traits/function_type.hpp>
#include <boost/callable_traits/has_member_qualifiers.hpp>
#include <boost/callable_traits/has_varargs.hpp>
#include <boost/callable_traits/has_void_return.hpp>
#include <boost/callable_traits/is_const_member.hpp>
#include <boost/callable_traits/is_invocable.hpp>
#include <boost/callable_traits/is_lvalue_reference_member.hpp>
#include <boost/callable_traits/is_reference_member.hpp>
#include <boost/callable_traits/is_rvalue_reference_member.hpp>
#include <boost/callable_traits/is_noexcept.hpp>
#include <boost/callable_traits/is_transaction_safe.hpp>
#include <boost/callable_traits/is_volatile_member.hpp>
#include <boost/callable_traits/qualified_class_of.hpp>
#include <boost/callable_traits/remove_member_const.hpp>
#include <boost/callable_traits/remove_member_cv.hpp>
#include <boost/callable_traits/remove_member_reference.hpp>
#include <boost/callable_traits/remove_member_volatile.hpp>
#include <boost/callable_traits/remove_noexcept.hpp>
#include <boost/callable_traits/remove_transaction_safe.hpp>
#include <boost/callable_traits/remove_varargs.hpp>
#include <boost/callable_traits/return_type.hpp>

#endif
<commit_msg>Delete callable_traits.hpp<commit_after><|endoftext|>


<commit_before>#include "tlang.h"
#include <taichi/util.h>
#include <taichi/visual/gui.h>

TC_NAMESPACE_BEGIN

using namespace Tlang;

auto test_loop = []() {
  CoreState::set_trigger_gdb_when_crash(true);
  Float a, b;

  int n = 16;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = 8;

  prog.buffer(0).stream(0).group(0).place(a, b);

  Expr i = Expr::index(0);
  for_loop(i, range(0, n), [&]() {
    // ***
    a[i] = a[i] * b[i];
  });

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    prog.data(a, i) = i;
    prog.data(b, i) = i * 2;
  }

  prog();

  for (int i = 0; i < n; i++) {
    auto val = prog.data(a, i);
    auto gt = i * i * 2;
    if (abs(gt - val) > 1e-5_f) {
      TC_P(i);
      TC_P(val);
      TC_P(gt);
      TC_ERROR("");
    }
  }
};

TC_REGISTER_TASK(test_loop);

auto advection = []() {
  bool use_adapter = true;

  const int n = 512, nattr = 4;

  Float attr[2][nattr], v[2];

  Program prog(Arch::x86_64, n * n);

  for (int k = 0; k < 2; k++) {
    for (int i = 0; i < nattr; i++) {
      prog.buffer(k).stream(0).group(0).place(attr[k][i]);
    }
    prog.buffer(2).stream(0).group(0).place(v[k]);
  }
  prog.config.group_size = use_adapter ? nattr : 1;
  prog.config.num_groups = 2;

  // ** gs = 2
  auto index = Expr::index(0);
  Int32 xi = index % imm(n) / imm(1);
  Int32 yi = index % imm(n * n) / imm(n);

  auto offset_x = floor(v[0][index]);
  auto offset_y = floor(v[1][index]);
  auto wx = v[0][index] - offset_x;
  auto wy = v[1][index] - offset_y;

  if (use_adapter) {
    prog.adapter(0).set(2, 1);
    prog.adapter(0).convert(offset_x);
    prog.adapter(0).convert(offset_y);

    prog.adapter(1).set(2, 1);
    prog.adapter(1).convert(wx);
    prog.adapter(1).convert(wy);
  }

  // ** gs = 1
  auto offset = cast<int32>(offset_x) * imm(n) + cast<int32>(offset_y) * imm(1);

  auto clamp = [](const Expr &e) { return min(max(imm(2), e), imm(n - 2)); };

  // weights
  auto w00 = (imm(1.0f) - wx) * (imm(1.0f) - wy);
  auto w01 = (imm(1.0f) - wx) * wy;
  auto w10 = wx * (imm(1.0f) - wy);
  auto w11 = wx * wy;

  w00.name("w00");
  w01.name("w01");
  w10.name("w10");
  w11.name("w11");

  Expr node = Expr::index(0) + offset;
  Int32 i = clamp(node / imm(n)).name("i");
  Int32 j = clamp(node % imm(n)).name("j");
  node = i * imm(n) + j;
  node.name("node");

  if (use_adapter) {
    prog.adapter(2).set(1, 4);
    prog.adapter(2).convert(w00);
    prog.adapter(2).convert(w01);
    prog.adapter(2).convert(w10);
    prog.adapter(2).convert(w11);

    prog.adapter(3).set(1, 4);
    prog.adapter(3).convert(node);
  }

  // ** gs = 4
  for (int k = 0; k < nattr; k++) {
    auto v00 = attr[0][k][node + imm(0)];
    auto v01 = attr[0][k][node + imm(1)];
    auto v10 = attr[0][k][node + imm(n)];
    auto v11 = attr[0][k][node + imm(n + 1)];

    attr[1][k][index] = w00 * v00 + w01 * v01 + w10 * v10 + w11 * v11;
    // attr[1][k][index] = v00;
    attr[1][k][index].name(fmt::format("output{}", k));
  }

  prog.compile();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      for (int k = 0; k < nattr; k++) {
        prog.data(attr[0][k], i * n + j) = i % 128 / 128.0_f;
      }
      real s = 3.0_f / n;
      prog.data(v[0], i * n + j) = s * (j - n / 2);
      prog.data(v[1], i * n + j) = -s * (i - n / 2);
    }
  }

  GUI gui("Advection", n, n);

  for (int f = 0; f < 1000; f++) {
    for (int t = 0; t < 3; t++) {
      prog();

      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          for (int k = 0; k < nattr; k++) {
            gui.buffer[i][j] = Vector4(prog.data(attr[1][k], i * n + j));
          }
        }
      }
    }

    gui.update();
    gui.screenshot(fmt::format("images/{:04d}.png", f));
    prog.swap_buffers(0, 1);
  }
};
TC_REGISTER_TASK(advection);

// a * b * vec
void test_adapter1(int vec_size) {
  Float a, b;
  Vector v(vec_size), u(vec_size);

  int n = 128;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = vec_size;
  prog.config.num_groups = 8;

  prog.buffer(0).stream(0).group(0).place(a, b);
  for (int i = 0; i < vec_size; i++) {
    prog.buffer(1).stream(0).group(0).place(v(i));
  }

  auto ind = Expr::index(0);

  auto &adapter = prog.adapter(0);
  auto ab = a[ind] * b[ind];

  adapter.set(1, vec_size);
  adapter.convert(ab);

  for (int d = 0; d < vec_size; d++) {
    v(d)[ind] = ab * v(d)[ind];
  }

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    prog.data(a, i) = i;
    prog.data(b, i) = 2.0_f * (i + 1);
    for (int j = 0; j < vec_size; j++) {
      prog.data(v(j), i) = 1.0_f * j / (i + 1);
    }
  }

  prog();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < vec_size; j++) {
      auto val = prog.data(v(j), i);
      auto gt = i * j * 2;
      if (abs(gt - val) > 1e-3_f) {
        TC_P(i);
        TC_P(j);
        TC_P(val);
        TC_P(gt);
        TC_ERROR("");
      }
    }
  }
}

// Vec<vec_size> reduction
void test_adapter2(int vec_size) {
  Vector v(vec_size);
  Float sum;

  int n = 64;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = 1;
  prog.config.num_groups = 8;

  for (int i = 0; i < vec_size; i++) {
    prog.buffer(1).stream(0).group(0).place(v(i));
  }
  prog.buffer(0).stream(0).group(0).place(sum);

  auto ind = Expr::index(0);

  auto v_ind = v[ind];

  for (int i = 0; i < vec_size; i++) {
    v_ind(i).set(Expr::load_if_pointer(v_ind(i)));
    TC_P(v_ind(i)->node_type_name());
  }

  auto &adapter = prog.adapter(0);
  adapter.set(vec_size, 1);
  for (int i = 0; i < vec_size; i++) {
    adapter.convert(v_ind(i));
  }

  Expr acc = Expr::create_imm(0.0_f);
  for (int d = 0; d < vec_size; d++) {
    acc = acc + v_ind(d);
  }

  sum[ind] = acc;

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < vec_size; j++) {
      prog.data(v(j), i) = j + i;
    }
  }

  prog();

  for (int i = 0; i < n; i++) {
    auto val = prog.data(sum, i);
    auto gt = vec_size * (vec_size - 1) / 2 + i * vec_size;
    if (abs(gt - val) > 1e-5_f) {
      TC_P(i);
      TC_P(val);
      TC_P(gt);
      TC_ERROR("");
    }
  }
}

// reduce(vec_a<n> - vec_b<n>) * vec_c<2n>
void test_adapter3(int vec_size) {
  Vector a(vec_size), b(vec_size), c(vec_size * 2);
  Float sum;

  int n = 64;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = vec_size * 2;
  prog.config.num_groups = 8;

  for (int i = 0; i < vec_size; i++) {
    prog.buffer(0).stream(0).group(0).place(a(i));
    prog.buffer(1).stream(0).group(0).place(b(i));
  }

  for (int i = 0; i < vec_size * 2; i++) {
    prog.buffer(2).stream(0).group(0).place(c(i));
  }

  auto ind = Expr::index(0);

  auto aind = a[ind];
  auto bind = b[ind];
  auto cind = c[ind];

  auto diff = aind.element_wise_prod(aind) - bind.element_wise_prod(bind);

  {
    auto &adapter = prog.adapter(0);
    adapter.set(vec_size, 1);
    for (int i = 0; i < vec_size; i++)
      adapter.convert(diff(i));
  }

  Expr acc = Expr::create_imm(0.0_f);
  for (int d = 0; d < vec_size; d++) {
    acc = acc + diff(d);
  }

  {
    auto &adapter = prog.adapter(1);
    adapter.set(1, vec_size * 2);
    adapter.convert(acc);
    for (int i = 0; i < vec_size * 2; i++)
      c(i)[ind] = c(i)[ind] * acc;
  }

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < vec_size; j++) {
      prog.data(a(j), i) = i + j + 1;
      prog.data(b(j), i) = i + j;
    }
    for (int j = 0; j < vec_size * 2; j++) {
      prog.data(c(j), i) = i - 2 + j;
    }
  }

  prog();

  for (int i = 0; i < n; i++) {
    real s = 0;
    for (int j = 0; j < vec_size; j++) {
      s += sqr(i + j + 1) - sqr(i + j);
    }
    for (int j = 0; j < vec_size * 2; j++) {
      auto val = prog.data(c(j), i);
      auto gt = s * (i - 2 + j);
      if (abs(gt - val) > 1e-3_f) {
        TC_P(i);
        TC_P(j);
        TC_P(val);
        TC_P(gt);
        TC_ERROR("");
      }
    }
  }
}

auto test_adapter = []() {
  test_adapter3(1);
  test_adapter3(2);
  test_adapter3(4);
  test_adapter3(8);

  test_adapter1(1);
  test_adapter1(2);
  test_adapter1(4);
  test_adapter1(8);

  test_adapter2(1);
  test_adapter2(2);
  test_adapter2(4);
  test_adapter2(8);

};

// TODO: random access

TC_REGISTER_TASK(test_adapter);

/*
#define For(i, range) \
  {                   \
    Index i; for_loop(i, range, [&](Index i)

#define End )
*/

TC_NAMESPACE_END<commit_msg>prepare for intrinsics codegen<commit_after>#include "tlang.h"
#include <taichi/util.h>
#include <taichi/visual/gui.h>

TC_NAMESPACE_BEGIN

using namespace Tlang;

auto test_loop = []() {
  CoreState::set_trigger_gdb_when_crash(true);
  Float a, b;

  int n = 16;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = 8;

  prog.buffer(0).stream(0).group(0).place(a, b);

  Expr i = Expr::index(0);
  for_loop(i, range(0, n), [&]() {
    // ***
    a[i] = a[i] * b[i];
  });

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    prog.data(a, i) = i;
    prog.data(b, i) = i * 2;
  }

  prog();

  for (int i = 0; i < n; i++) {
    auto val = prog.data(a, i);
    auto gt = i * i * 2;
    if (abs(gt - val) > 1e-5_f) {
      TC_P(i);
      TC_P(val);
      TC_P(gt);
      TC_ERROR("");
    }
  }
};

TC_REGISTER_TASK(test_loop);

auto advection = []() {
  bool use_adapter = true;

  const int n = 512, nattr = 4;

  Float attr[2][nattr], v[2];

  Program prog(Arch::x86_64, n * n);

  for (int k = 0; k < 2; k++) {
    for (int i = 0; i < nattr; i++) {
      prog.buffer(k).stream(0).group(0).place(attr[k][i]);
    }
    prog.buffer(2).stream(0).group(0).place(v[k]);
  }
  prog.config.group_size = use_adapter ? nattr : 1;
  prog.config.num_groups = 8;

  // ** gs = 2
  auto index = Expr::index(0);
  Int32 xi = index % imm(n) / imm(1);
  Int32 yi = index % imm(n * n) / imm(n);

  auto offset_x = floor(v[0][index]);
  auto offset_y = floor(v[1][index]);
  auto wx = v[0][index] - offset_x;
  auto wy = v[1][index] - offset_y;

  if (use_adapter) {
    prog.adapter(0).set(2, 1);
    prog.adapter(0).convert(offset_x);
    prog.adapter(0).convert(offset_y);

    prog.adapter(1).set(2, 1);
    prog.adapter(1).convert(wx);
    prog.adapter(1).convert(wy);
  }

  // ** gs = 1
  auto offset = cast<int32>(offset_x) * imm(n) + cast<int32>(offset_y) * imm(1);

  auto clamp = [](const Expr &e) { return min(max(imm(2), e), imm(n - 2)); };

  // weights
  auto w00 = (imm(1.0f) - wx) * (imm(1.0f) - wy);
  auto w01 = (imm(1.0f) - wx) * wy;
  auto w10 = wx * (imm(1.0f) - wy);
  auto w11 = wx * wy;

  w00.name("w00");
  w01.name("w01");
  w10.name("w10");
  w11.name("w11");

  Expr node = Expr::index(0) + offset;
  Int32 i = clamp(node / imm(n)).name("i");
  Int32 j = clamp(node % imm(n)).name("j");
  node = i * imm(n) + j;
  node.name("node");

  if (use_adapter) {
    prog.adapter(2).set(1, 4);
    prog.adapter(2).convert(w00);
    prog.adapter(2).convert(w01);
    prog.adapter(2).convert(w10);
    prog.adapter(2).convert(w11);

    prog.adapter(3).set(1, 4);
    prog.adapter(3).convert(node);
  }

  // ** gs = 4
  for (int k = 0; k < nattr; k++) {
    auto v00 = attr[0][k][node + imm(0)];
    auto v01 = attr[0][k][node + imm(1)];
    auto v10 = attr[0][k][node + imm(n)];
    auto v11 = attr[0][k][node + imm(n + 1)];

    attr[1][k][index] = w00 * v00 + w01 * v01 + w10 * v10 + w11 * v11;
    // attr[1][k][index] = v00;
    attr[1][k][index].name(fmt::format("output{}", k));
  }

  prog.compile();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      for (int k = 0; k < nattr; k++) {
        prog.data(attr[0][k], i * n + j) = i % 128 / 128.0_f;
      }
      real s = 3.0_f / n;
      prog.data(v[0], i * n + j) = s * (j - n / 2);
      prog.data(v[1], i * n + j) = -s * (i - n / 2);
    }
  }

  GUI gui("Advection", n, n);

  for (int f = 0; f < 1000; f++) {
    for (int t = 0; t < 3; t++) {
      prog();

      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          for (int k = 0; k < nattr; k++) {
            gui.buffer[i][j] = Vector4(prog.data(attr[1][k], i * n + j));
          }
        }
      }
    }

    gui.update();
    gui.screenshot(fmt::format("images/{:04d}.png", f));
    prog.swap_buffers(0, 1);
  }
};
TC_REGISTER_TASK(advection);

// a * b * vec
void test_adapter1(int vec_size) {
  Float a, b;
  Vector v(vec_size), u(vec_size);

  int n = 128;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = vec_size;
  prog.config.num_groups = 8;

  prog.buffer(0).stream(0).group(0).place(a, b);
  for (int i = 0; i < vec_size; i++) {
    prog.buffer(1).stream(0).group(0).place(v(i));
  }

  auto ind = Expr::index(0);

  auto &adapter = prog.adapter(0);
  auto ab = a[ind] * b[ind];

  adapter.set(1, vec_size);
  adapter.convert(ab);

  for (int d = 0; d < vec_size; d++) {
    v(d)[ind] = ab * v(d)[ind];
  }

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    prog.data(a, i) = i;
    prog.data(b, i) = 2.0_f * (i + 1);
    for (int j = 0; j < vec_size; j++) {
      prog.data(v(j), i) = 1.0_f * j / (i + 1);
    }
  }

  prog();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < vec_size; j++) {
      auto val = prog.data(v(j), i);
      auto gt = i * j * 2;
      if (abs(gt - val) > 1e-3_f) {
        TC_P(i);
        TC_P(j);
        TC_P(val);
        TC_P(gt);
        TC_ERROR("");
      }
    }
  }
}

// Vec<vec_size> reduction
void test_adapter2(int vec_size) {
  Vector v(vec_size);
  Float sum;

  int n = 64;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = 1;
  prog.config.num_groups = 8;

  for (int i = 0; i < vec_size; i++) {
    prog.buffer(1).stream(0).group(0).place(v(i));
  }
  prog.buffer(0).stream(0).group(0).place(sum);

  auto ind = Expr::index(0);

  auto v_ind = v[ind];

  for (int i = 0; i < vec_size; i++) {
    v_ind(i).set(Expr::load_if_pointer(v_ind(i)));
    TC_P(v_ind(i)->node_type_name());
  }

  auto &adapter = prog.adapter(0);
  adapter.set(vec_size, 1);
  for (int i = 0; i < vec_size; i++) {
    adapter.convert(v_ind(i));
  }

  Expr acc = Expr::create_imm(0.0_f);
  for (int d = 0; d < vec_size; d++) {
    acc = acc + v_ind(d);
  }

  sum[ind] = acc;

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < vec_size; j++) {
      prog.data(v(j), i) = j + i;
    }
  }

  prog();

  for (int i = 0; i < n; i++) {
    auto val = prog.data(sum, i);
    auto gt = vec_size * (vec_size - 1) / 2 + i * vec_size;
    if (abs(gt - val) > 1e-5_f) {
      TC_P(i);
      TC_P(val);
      TC_P(gt);
      TC_ERROR("");
    }
  }
}

// reduce(vec_a<n> - vec_b<n>) * vec_c<2n>
void test_adapter3(int vec_size) {
  Vector a(vec_size), b(vec_size), c(vec_size * 2);
  Float sum;

  int n = 64;

  Program prog(Arch::x86_64, n);
  prog.config.group_size = vec_size * 2;
  prog.config.num_groups = 8;

  for (int i = 0; i < vec_size; i++) {
    prog.buffer(0).stream(0).group(0).place(a(i));
    prog.buffer(1).stream(0).group(0).place(b(i));
  }

  for (int i = 0; i < vec_size * 2; i++) {
    prog.buffer(2).stream(0).group(0).place(c(i));
  }

  auto ind = Expr::index(0);

  auto aind = a[ind];
  auto bind = b[ind];
  auto cind = c[ind];

  auto diff = aind.element_wise_prod(aind) - bind.element_wise_prod(bind);

  {
    auto &adapter = prog.adapter(0);
    adapter.set(vec_size, 1);
    for (int i = 0; i < vec_size; i++)
      adapter.convert(diff(i));
  }

  Expr acc = Expr::create_imm(0.0_f);
  for (int d = 0; d < vec_size; d++) {
    acc = acc + diff(d);
  }

  {
    auto &adapter = prog.adapter(1);
    adapter.set(1, vec_size * 2);
    adapter.convert(acc);
    for (int i = 0; i < vec_size * 2; i++)
      c(i)[ind] = c(i)[ind] * acc;
  }

  prog.materialize_layout();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < vec_size; j++) {
      prog.data(a(j), i) = i + j + 1;
      prog.data(b(j), i) = i + j;
    }
    for (int j = 0; j < vec_size * 2; j++) {
      prog.data(c(j), i) = i - 2 + j;
    }
  }

  prog();

  for (int i = 0; i < n; i++) {
    real s = 0;
    for (int j = 0; j < vec_size; j++) {
      s += sqr(i + j + 1) - sqr(i + j);
    }
    for (int j = 0; j < vec_size * 2; j++) {
      auto val = prog.data(c(j), i);
      auto gt = s * (i - 2 + j);
      if (abs(gt - val) > 1e-3_f) {
        TC_P(i);
        TC_P(j);
        TC_P(val);
        TC_P(gt);
        TC_ERROR("");
      }
    }
  }
}

auto test_adapter = []() {
  test_adapter3(1);
  test_adapter3(2);
  test_adapter3(4);
  test_adapter3(8);

  test_adapter1(1);
  test_adapter1(2);
  test_adapter1(4);
  test_adapter1(8);

  test_adapter2(1);
  test_adapter2(2);
  test_adapter2(4);
  test_adapter2(8);

};

// TODO: random access

TC_REGISTER_TASK(test_adapter);

/*
#define For(i, range) \
  {                   \
    Index i; for_loop(i, range, [&](Index i)

#define End )
*/

TC_NAMESPACE_END<|endoftext|>


<commit_before>#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include "test_common.h"

int main()
{
    printf("Starting scout\n");
    pid_t scout_pid = fork();
    switch (scout_pid) {
    case -1:
        perror("fork");
        exit(1);
    case 0:
        if (execlp("conn_scout",
                   "conn_scout", "socket_control",
                   "rmnet0", "12500", "100",
                   "tiwlan0", "125000", "1",
                   NULL) < 0) {
            perror("execlp");
            exit(1);
        }
    }
    sleep(1);

    pid_t test_pid = fork();
    switch (test_pid) {
    case -1:
        perror("fork");
        exit(1);
    case 0:
        if (execlp("fake_intnw_test",
                   "fake_intnw_test", "-h", "141.212.110.132",
                   NULL) < 0) {
            perror("execlp");
            exit(1);
        }
    }

    int status = -1;
    if (waitpid(test_pid, &status, 0) != test_pid) {
        perror("test waitpid");
        exit(1);
    }
    if (WEXITSTATUS(status) != 0) {
        printf("Tests failed?\n");
    } else {
        printf("Tests passed.\n");
    }
    kill(scout_pid, SIGINT);
    if (waitpid(scout_pid, NULL, 0) != scout_pid) {
        perror("scout waitpid");
        exit(1);
    }

    return 0;
}
<commit_msg>Update wifi iface name for nexus one.<commit_after>#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include "test_common.h"

int main()
{
    printf("Starting scout\n");
    pid_t scout_pid = fork();
    switch (scout_pid) {
    case -1:
        perror("fork");
        exit(1);
    case 0:
        if (execlp("conn_scout",
                   "conn_scout", "socket_control",
                   "rmnet0", "12500", "100",
                   "eth0", "125000", "1",
                   NULL) < 0) {
            perror("execlp");
            exit(1);
        }
    }
    sleep(1);

    pid_t test_pid = fork();
    switch (test_pid) {
    case -1:
        perror("fork");
        exit(1);
    case 0:
        if (execlp("fake_intnw_test",
                   "fake_intnw_test", "-h", "141.212.110.132",
                   NULL) < 0) {
            perror("execlp");
            exit(1);
        }
    }

    int status = -1;
    if (waitpid(test_pid, &status, 0) != test_pid) {
        perror("test waitpid");
        exit(1);
    }
    if (WEXITSTATUS(status) != 0) {
        printf("Tests failed?\n");
    } else {
        printf("Tests passed.\n");
    }
    kill(scout_pid, SIGINT);
    if (waitpid(scout_pid, NULL, 0) != scout_pid) {
        perror("scout waitpid");
        exit(1);
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <fstream>

#include <boost/format.hpp>

#include <object/file.hh>
#include <object/output-stream.hh>
#include <object/symbols.hh>

#include <runner/raise.hh>

namespace object
{
  OutputStream::OutputStream(int fd, bool own)
    : fd_(fd)
    , own_(own)
  {
    proto_add(proto ? proto : Object::proto);
  }

  OutputStream::OutputStream(rOutputStream model)
    : fd_(model->fd_)
    , own_(false)
  {
    proto_add(proto);
  }

  OutputStream::~OutputStream()
  {
    if (own_ && fd_ != -1)
      if (::close(fd_))
        RAISE(libport::strerror(errno));
  }

  void
  OutputStream::checkFD_() const
  {
    if (fd_ == -1)
      RAISE("Stream is closed");
  }

  /*-------------.
  | Urbi methods |
  `-------------*/

  void OutputStream::init(rFile f)
  {
    libport::path path = f->value_get()->value_get();
    fd_ = open(path.to_string().c_str(), O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);

    if (fd_ < 0)
    {
      boost::format fmt("Unable to open file for writing: %s");
      fd_ = 0;
      RAISE(str(fmt % path));
    }
    own_ = true;
  }

  rOutputStream OutputStream::putByte(unsigned char c)
  {
    checkFD_();
    // FIXME: bufferize
    size_t size = write(fd_, &c, 1);
    assert_eq(size, 1);
    (void)size;
    return this;
  }

  void OutputStream::flush()
  {
    checkFD_();
    // FIXME: nothing since not bufferized for now
  }

  rOutputStream
  OutputStream::put(rObject o)
  {
    checkFD_();
    std::string str = o->call(SYMBOL(asString))->as<String>()->value_get();
    size_t str_size = str.size();
    size_t size = write(fd_, str.c_str(), str_size);
    assert_eq(size, str_size);
    (void)size;
    return this;
  }

  void
  OutputStream::close()
  {
    checkFD_();
    if (::close(fd_))
      RAISE(libport::strerror(errno));
    fd_ = -1;
  }

  /*--------------.
  | Urbi bindings |
  `--------------*/

  rObject
  OutputStream::proto_make()
  {
    return new OutputStream(STDOUT_FILENO, false);
  }

  void
  OutputStream::initialize(object::CxxObject::Binder<object::OutputStream>& bind)
  {
    bind(SYMBOL(LT_LT), &OutputStream::put    );
    bind(SYMBOL(close), &OutputStream::close  );
    bind(SYMBOL(flush), &OutputStream::flush  );
    bind(SYMBOL(init),  &OutputStream::init   );
    bind(SYMBOL(put),   &OutputStream::putByte);
  }

  URBI_CXX_OBJECT_REGISTER(OutputStream);
}
<commit_msg>build: fix warning.<commit_after>#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <fstream>

#include <boost/format.hpp>

#include <object/file.hh>
#include <object/output-stream.hh>
#include <object/symbols.hh>

#include <runner/raise.hh>

namespace object
{
  OutputStream::OutputStream(int fd, bool own)
    : fd_(fd)
    , own_(own)
  {
    proto_add(proto ? proto : Object::proto);
  }

  OutputStream::OutputStream(rOutputStream model)
    : fd_(model->fd_)
    , own_(false)
  {
    proto_add(proto);
  }

  OutputStream::~OutputStream()
  {
    if (own_ && fd_ != -1)
      if (::close(fd_))
        RAISE(libport::strerror(errno));
  }

  void
  OutputStream::checkFD_() const
  {
    if (fd_ == -1)
      RAISE("Stream is closed");
  }

  /*-------------.
  | Urbi methods |
  `-------------*/

  void OutputStream::init(rFile f)
  {
    libport::path path = f->value_get()->value_get();
    fd_ = open(path.to_string().c_str(), O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);

    if (fd_ < 0)
    {
      boost::format fmt("Unable to open file for writing: %s");
      fd_ = 0;
      RAISE(str(fmt % path));
    }
    own_ = true;
  }

  rOutputStream OutputStream::putByte(unsigned char c)
  {
    checkFD_();
    // FIXME: bufferize
    size_t size = write(fd_, &c, 1);
    assert_eq(size, 1u);
    (void)size;
    return this;
  }

  void OutputStream::flush()
  {
    checkFD_();
    // FIXME: nothing since not bufferized for now
  }

  rOutputStream
  OutputStream::put(rObject o)
  {
    checkFD_();
    std::string str = o->call(SYMBOL(asString))->as<String>()->value_get();
    size_t str_size = str.size();
    size_t size = write(fd_, str.c_str(), str_size);
    assert_eq(size, str_size);
    (void)size;
    return this;
  }

  void
  OutputStream::close()
  {
    checkFD_();
    if (::close(fd_))
      RAISE(libport::strerror(errno));
    fd_ = -1;
  }

  /*--------------.
  | Urbi bindings |
  `--------------*/

  rObject
  OutputStream::proto_make()
  {
    return new OutputStream(STDOUT_FILENO, false);
  }

  void
  OutputStream::initialize(object::CxxObject::Binder<object::OutputStream>& bind)
  {
    bind(SYMBOL(LT_LT), &OutputStream::put    );
    bind(SYMBOL(close), &OutputStream::close  );
    bind(SYMBOL(flush), &OutputStream::flush  );
    bind(SYMBOL(init),  &OutputStream::init   );
    bind(SYMBOL(put),   &OutputStream::putByte);
  }

  URBI_CXX_OBJECT_REGISTER(OutputStream);
}
<|endoftext|>


<commit_before><commit_msg>Remove unused include.<commit_after><|endoftext|>


<commit_before>#include "newcertificatewizard.h"

#include "ui_chooseprotocolpage.h"
#include "ui_enterdetailspage.h"
#include "ui_overviewpage.h"
#include "ui_resultpage.h"

#include <kleo/dn.h>

#include <KConfigGroup>
#include <KGlobal>
#include <KLocale>
#include <KDebug>

#include <QRegExpValidator>
#include <QLineEdit>

using namespace Kleo;
using namespace Kleo::NewCertificateUi;

namespace {

    class ChooseProtocolPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit ChooseProtocolPage( QWidget * p=0 )
            : QWizardPage( p ),
              initialized( false ),
              ui()
        {
            ui.setupUi( this );

            connect( ui.pgpCLB,  SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
            connect( ui.x509CLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );

            registerField( "pgp", ui.pgpCLB );
        }

        /* reimp */ void initializePage() {
            if ( !initialized ) {
                connect( ui.pgpCLB,  SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
                connect( ui.x509CLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
            }
            initialized = true;
        }

        /* reimp */ bool isComplete() const {
            return ui.pgpCLB->isChecked() || ui.x509CLB->isChecked() ;
        }

    private:
        bool initialized : 1;
        Ui_ChooseProtocolPage ui;
    };

    class EnterDetailsPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit EnterDetailsPage( QWidget * p=0 )
            : QWizardPage( p ), ui()
        {
            ui.setupUi( this );
            updateForm();
        }

        /* reimp */ bool isComplete() const;
        /* reimp */ void initializePage() {
            updateForm();
        }
        /* reimp */ void cleanupPage() {
            savedValues.clear();
            for ( QVector< QPair<QString,QLineEdit*> >::const_iterator it = attributePairList.begin(), end = attributePairList.end() ; it != end ; ++it )
                savedValues[it->first] = it->second->text().trimmed();
        }

    private:
        void updateForm();
        void clearForm();

    private:
        QVector< QPair<QString,QLineEdit*> > attributePairList;
        QList<QWidget*> dynamicWidgets;
        QMap<QString,QString> savedValues;
        Ui_EnterDetailsPage ui;
    };

    class OverviewPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit OverviewPage( QWidget * p=0 )
            : QWizardPage( p ), ui()
        {
            setCommitPage( true );
            setButtonText( QWizard::CommitButton, i18nc("@action", "Create") );
        }

    private:
        Ui_OverviewPage ui;
    };

    class ResultPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit ResultPage( QWidget * p=0 )
            : QWizardPage( p ), ui()
        {

        }

    private:
        Ui_ResultPage ui;
    };
}

class NewCertificateWizard::Private {
    friend class ::Kleo::NewCertificateWizard;
    NewCertificateWizard * const q;
public:
    explicit Private( NewCertificateWizard * qq )
        : q( qq ),
          ui( q )
    {

    }

private:
    struct Ui {
        ChooseProtocolPage chooseProtocolPage;
        EnterDetailsPage enterDetailsPage;
        OverviewPage overviewPage;
        ResultPage resultPage;

        explicit Ui( NewCertificateWizard * q )
            : chooseProtocolPage( q ),
              enterDetailsPage( q ),
              overviewPage( q ),
              resultPage( q )
        {
            q->setPage( ChooseProtocolPageId, &chooseProtocolPage );
            q->setPage( EnterDetailsPageId,   &enterDetailsPage   );
            q->setPage( OverviewPageId,       &overviewPage       );
            q->setPage( ResultPageId,         &resultPage         );

            q->setStartId( ChooseProtocolPageId );
        }

    } ui;

};

NewCertificateWizard::NewCertificateWizard( QWidget * p )
    : QWizard( p ), d( new Private( this ) )
{

}

NewCertificateWizard::~NewCertificateWizard() {}

static QString pgpLabel( const QString & attr ) {
    if ( attr == "NAME" )
        return i18n("Name");
    if ( attr == "COMMENT" )
        return i18n("Comment");
    if ( attr == "EMAIL" )
        return i18n("EMail");
    return QString();
}

static QString attributeLabel( const QString & attr, bool required, bool pgp ) {
  if ( attr.isEmpty() )
    return QString();
  const QString label = pgp ? pgpLabel( attr ) : Kleo::DNAttributeMapper::instance()->name2label( attr ) ;
  if ( !label.isEmpty() )
      if ( pgp )
          return label + ':';
      else
          return i18nc("Format string for the labels in the \"Your Personal Data\" page",
                       "%1 (%2):", label, attr );
  else
    return attr + ':';
}

static QString attributeFromKey( QString key ) {
  return key.remove( '!' );
}

namespace {
    class LineEdit : public QWidget {
        Q_OBJECT
    public:
        explicit LineEdit( const QString & text, bool required, QWidget * parent )
            : QWidget( parent ),
              lineEdit( text, this ),
              label( required ? i18n("(required)") : i18n("(optional)"), this ),
              layout( this )
        {
            KDAB_SET_OBJECT_NAME( lineEdit );
            KDAB_SET_OBJECT_NAME( label );
            KDAB_SET_OBJECT_NAME( layout );

            layout.addWidget( &lineEdit );
            layout.addWidget( &label );
        }

    public:
        QLineEdit lineEdit;
        QLabel label;
        QHBoxLayout layout;
    };
}

void EnterDetailsPage::updateForm() {

    clearForm();

    const KConfigGroup config( KGlobal::config(), "CertificateCreationWizard" );

    const bool pgp = field("pgp").toBool();

    QStringList attrOrder = config.readEntry( pgp ? "OpenPGPAttributeOrder" : "DNAttributeOrder", QStringList() );
    if ( attrOrder.empty() )
        if ( pgp )
            attrOrder << "NAME!" << "EMAIL!" << "COMMENT";
        else
            attrOrder << "CN!" << "L" << "OU" << "O!" << "C!" << "EMAIL!";

    Q_FOREACH( const QString & rawKey, attrOrder ) {
        const QString key = rawKey.trimmed().toUpper();
        const QString attr = attributeFromKey( key );
        if ( attr.isEmpty() )
            continue;
        const QString preset = savedValues.value( attr, config.readEntry( attr, QString() ) );
        const bool required = key.endsWith( QLatin1Char('!') );
        const QString label = config.readEntry( attr + "_label",
                                                attributeLabel( attr, required, pgp ) );

        LineEdit * const le = new LineEdit( preset, required, ui.formLayout->parentWidget() );
        ui.formLayout->addRow( label, le );

        if ( config.isEntryImmutable( attr ) )
            le->lineEdit.setEnabled( false );

        QString regex = config.readEntry( attr + "_regex" );
        if ( regex.isEmpty() )
            regex = "[^\\s].*"; // !empty
        le->lineEdit.setValidator( new QRegExpValidator( QRegExp( regex ), le ) );

        attributePairList.append( qMakePair(key, &le->lineEdit) );

        connect( &le->lineEdit, SIGNAL(textChanged(QString)),
                 SIGNAL(completeChanged()) );

        dynamicWidgets.push_back( ui.formLayout->labelForField( le ) );
        dynamicWidgets.push_back( le );
    }
}

void EnterDetailsPage::clearForm() {
    qDeleteAll( dynamicWidgets );
    dynamicWidgets.clear();
    attributePairList.clear();
}

static bool requirementsAreMet( const QVector< QPair<QString,QLineEdit*> > & list ) {
    for ( QVector< QPair<QString,QLineEdit*> >::const_iterator it = list.begin() ;
          it != list.end() ; ++it ) {
    const QLineEdit * le = (*it).second;
    if ( !le )
      continue;
    const QString key = (*it).first;
    kDebug() << "requirementsAreMet(): checking \"" << key << "\" against \"" << le->text() << "\":";
    if ( key.endsWith('!') && !le->hasAcceptableInput() ) {
      kDebug() << "required field has non-acceptable input!";
      return false;
    }
    kDebug() << "ok" << endl;
  }
  return true;
}

namespace {
    bool EnterDetailsPage::isComplete() const {
        return requirementsAreMet( attributePairList );
    }
}

#include "moc_newcertificatewizard.cpp"
#include "newcertificatewizard.moc"
<commit_msg>Fix required fields forgetting their value on Back<commit_after>#include "newcertificatewizard.h"

#include "ui_chooseprotocolpage.h"
#include "ui_enterdetailspage.h"
#include "ui_overviewpage.h"
#include "ui_resultpage.h"

#include <kleo/dn.h>

#include <KConfigGroup>
#include <KGlobal>
#include <KLocale>
#include <KDebug>

#include <QRegExpValidator>
#include <QLineEdit>

using namespace Kleo;
using namespace Kleo::NewCertificateUi;

namespace {

    class ChooseProtocolPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit ChooseProtocolPage( QWidget * p=0 )
            : QWizardPage( p ),
              initialized( false ),
              ui()
        {
            ui.setupUi( this );

            connect( ui.pgpCLB,  SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
            connect( ui.x509CLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );

            registerField( "pgp", ui.pgpCLB );
        }

        /* reimp */ void initializePage() {
            if ( !initialized ) {
                connect( ui.pgpCLB,  SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
                connect( ui.x509CLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
            }
            initialized = true;
        }

        /* reimp */ bool isComplete() const {
            return ui.pgpCLB->isChecked() || ui.x509CLB->isChecked() ;
        }

    private:
        bool initialized : 1;
        Ui_ChooseProtocolPage ui;
    };

    class EnterDetailsPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit EnterDetailsPage( QWidget * p=0 )
            : QWizardPage( p ), ui()
        {
            ui.setupUi( this );
            updateForm();
        }

        /* reimp */ bool isComplete() const;
        /* reimp */ void initializePage() {
            updateForm();
        }
        /* reimp */ void cleanupPage() {
            savedValues.clear();
            for ( QVector< QPair<QString,QLineEdit*> >::const_iterator it = attributePairList.begin(), end = attributePairList.end() ; it != end ; ++it )
                savedValues[it->first] = it->second->text().trimmed();
        }

    private:
        void updateForm();
        void clearForm();

    private:
        QVector< QPair<QString,QLineEdit*> > attributePairList;
        QList<QWidget*> dynamicWidgets;
        QMap<QString,QString> savedValues;
        Ui_EnterDetailsPage ui;
    };

    class OverviewPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit OverviewPage( QWidget * p=0 )
            : QWizardPage( p ), ui()
        {
            setCommitPage( true );
            setButtonText( QWizard::CommitButton, i18nc("@action", "Create") );
        }

    private:
        Ui_OverviewPage ui;
    };

    class ResultPage : public QWizardPage {
        Q_OBJECT
    public:
        explicit ResultPage( QWidget * p=0 )
            : QWizardPage( p ), ui()
        {

        }

    private:
        Ui_ResultPage ui;
    };
}

class NewCertificateWizard::Private {
    friend class ::Kleo::NewCertificateWizard;
    NewCertificateWizard * const q;
public:
    explicit Private( NewCertificateWizard * qq )
        : q( qq ),
          ui( q )
    {

    }

private:
    struct Ui {
        ChooseProtocolPage chooseProtocolPage;
        EnterDetailsPage enterDetailsPage;
        OverviewPage overviewPage;
        ResultPage resultPage;

        explicit Ui( NewCertificateWizard * q )
            : chooseProtocolPage( q ),
              enterDetailsPage( q ),
              overviewPage( q ),
              resultPage( q )
        {
            q->setPage( ChooseProtocolPageId, &chooseProtocolPage );
            q->setPage( EnterDetailsPageId,   &enterDetailsPage   );
            q->setPage( OverviewPageId,       &overviewPage       );
            q->setPage( ResultPageId,         &resultPage         );

            q->setStartId( ChooseProtocolPageId );
        }

    } ui;

};

NewCertificateWizard::NewCertificateWizard( QWidget * p )
    : QWizard( p ), d( new Private( this ) )
{

}

NewCertificateWizard::~NewCertificateWizard() {}

static QString pgpLabel( const QString & attr ) {
    if ( attr == "NAME" )
        return i18n("Name");
    if ( attr == "COMMENT" )
        return i18n("Comment");
    if ( attr == "EMAIL" )
        return i18n("EMail");
    return QString();
}

static QString attributeLabel( const QString & attr, bool required, bool pgp ) {
  if ( attr.isEmpty() )
    return QString();
  const QString label = pgp ? pgpLabel( attr ) : Kleo::DNAttributeMapper::instance()->name2label( attr ) ;
  if ( !label.isEmpty() )
      if ( pgp )
          return label + ':';
      else
          return i18nc("Format string for the labels in the \"Your Personal Data\" page",
                       "%1 (%2):", label, attr );
  else
    return attr + ':';
}

static QString attributeFromKey( QString key ) {
  return key.remove( '!' );
}

namespace {
    class LineEdit : public QWidget {
        Q_OBJECT
    public:
        explicit LineEdit( const QString & text, bool required, QWidget * parent )
            : QWidget( parent ),
              lineEdit( text, this ),
              label( required ? i18n("(required)") : i18n("(optional)"), this ),
              layout( this )
        {
            KDAB_SET_OBJECT_NAME( lineEdit );
            KDAB_SET_OBJECT_NAME( label );
            KDAB_SET_OBJECT_NAME( layout );

            layout.addWidget( &lineEdit );
            layout.addWidget( &label );
        }

    public:
        QLineEdit lineEdit;
        QLabel label;
        QHBoxLayout layout;
    };
}

void EnterDetailsPage::updateForm() {

    clearForm();

    const KConfigGroup config( KGlobal::config(), "CertificateCreationWizard" );

    const bool pgp = field("pgp").toBool();

    QStringList attrOrder = config.readEntry( pgp ? "OpenPGPAttributeOrder" : "DNAttributeOrder", QStringList() );
    if ( attrOrder.empty() )
        if ( pgp )
            attrOrder << "NAME!" << "EMAIL!" << "COMMENT";
        else
            attrOrder << "CN!" << "L" << "OU" << "O!" << "C!" << "EMAIL!";

    Q_FOREACH( const QString & rawKey, attrOrder ) {
        const QString key = rawKey.trimmed().toUpper();
        const QString attr = attributeFromKey( key );
        if ( attr.isEmpty() )
            continue;
        const QString preset = savedValues.value( key, config.readEntry( attr, QString() ) );
        const bool required = key.endsWith( QLatin1Char('!') );
        const QString label = config.readEntry( attr + "_label",
                                                attributeLabel( attr, required, pgp ) );

        LineEdit * const le = new LineEdit( preset, required, ui.formLayout->parentWidget() );
        ui.formLayout->addRow( label, le );

        if ( config.isEntryImmutable( attr ) )
            le->lineEdit.setEnabled( false );

        QString regex = config.readEntry( attr + "_regex" );
        if ( regex.isEmpty() )
            regex = "[^\\s].*"; // !empty
        le->lineEdit.setValidator( new QRegExpValidator( QRegExp( regex ), le ) );

        attributePairList.append( qMakePair(key, &le->lineEdit) );

        connect( &le->lineEdit, SIGNAL(textChanged(QString)),
                 SIGNAL(completeChanged()) );

        dynamicWidgets.push_back( ui.formLayout->labelForField( le ) );
        dynamicWidgets.push_back( le );
    }
}

void EnterDetailsPage::clearForm() {
    qDeleteAll( dynamicWidgets );
    dynamicWidgets.clear();
    attributePairList.clear();
}

static bool requirementsAreMet( const QVector< QPair<QString,QLineEdit*> > & list ) {
    for ( QVector< QPair<QString,QLineEdit*> >::const_iterator it = list.begin() ;
          it != list.end() ; ++it ) {
    const QLineEdit * le = (*it).second;
    if ( !le )
      continue;
    const QString key = (*it).first;
    kDebug() << "requirementsAreMet(): checking \"" << key << "\" against \"" << le->text() << "\":";
    if ( key.endsWith('!') && !le->hasAcceptableInput() ) {
      kDebug() << "required field has non-acceptable input!";
      return false;
    }
    kDebug() << "ok" << endl;
  }
  return true;
}

namespace {
    bool EnterDetailsPage::isComplete() const {
        return requirementsAreMet( attributePairList );
    }
}

#include "moc_newcertificatewizard.cpp"
#include "newcertificatewizard.moc"
<|endoftext|>