Package: tellico Version: 2.3.5+dfsg.1-4 Severity: wishlist Tags: patch Dear Maintainer, *** Please consider answering these questions, where appropriate ***
* What led up to the situation? * What exactly did you do (or not do) that was effective (or ineffective)? * What was the outcome of this action? * What outcome did you expect instead? *** End of the template - remove these lines *** -- System Information: Debian Release: 7.1 APT prefers stable APT policy: (500, 'stable') Architecture: i386 (i686) Kernel: Linux 3.2.0-4-686-pae (SMP w/1 CPU core) Locale: LANG=fr_FR.UTF8, LC_CTYPE=fr_FR.UTF8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages tellico depends on: ii kde-runtime 4:4.8.4-2 ii libc6 2.13-38 ii libexempi3 2.2.0-1 ii libgcc1 1:4.7.2-5 ii libkabc4 4:4.8.4-2 ii libkcal4 4:4.8.4-2 ii libkcddb4 4:4.8.4-2 ii libkdecore5 4:4.8.4-4 ii libkdeui5 4:4.8.4-4 ii libkhtml5 4:4.8.4-4 ii libkio5 4:4.8.4-4 ii libknewstuff3-4 4:4.8.4-4 ii libkparts4 4:4.8.4-4 ii libkresources4 4:4.8.4-2 ii libksane0 4:4.8.4-1 ii libkxmlrpcclient4 4:4.8.4-2 ii libnepomuk4 4:4.8.4-4 ii libpoppler-qt4-3 0.18.4-6 ii libqimageblitz4 1:0.0.6-4 ii libqjson0 0.7.1-7 ii libqt4-dbus 4:4.8.2+dfsg-11 ii libqt4-xml 4:4.8.2+dfsg-11 ii libqtcore4 4:4.8.2+dfsg-11 ii libqtgui4 4:4.8.2+dfsg-11 ii libsolid4 4:4.8.4-4 ii libstdc++6 4.7.2-5 ii libtag1c2a 1.7.2-1 ii libxml2 2.8.0+dfsg1-7+nmu1 ii libxslt1.1 1.1.26-14.1 ii libyaz4 4.2.30-2 ii tellico-data 2.3.5+dfsg.1-4 ii tellico-scripts 2.3.5+dfsg.1-4 Versions of packages tellico recommends: ii khelpcenter4 4:4.8.4-2 tellico suggests no packages. -- no debconf information Although kdepimlibs is an optional dependency, tellico does not compile without kdepimlibs5-dev. This is a knwown error and a patch is proposed by the upstream. I have slightly modified the patch, and I can generate the debian package without the kdepimlibs dependancy
Description: <short summary of the patch> TODO: Put a short summary on the line above and replace this paragraph with a longer explanation of this change. Complete the meta-information with other relevant fields (see below for details). To make it easier, the information below has been extracted from the changelog. Adjust it or drop it. . tellico (2.3.5+dfsg.1-4) unstable; urgency=low . * Fix passing of hardening flags. Thanks Simon Ruderich. Closes: #669190. Author: Regis Boudin <re...@debian.org> Bug-Debian: http://bugs.debian.org/669190 --- The information above should follow the Patch Tagging Guidelines, please checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here are templates for supplementary fields that you might want to add: Origin: <vendor|upstream|other>, <url of original patch> Bug: <url in upstream bugtracker> Bug-Debian: http://bugs.debian.org/<bugnumber> Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber> Forwarded: <no|not-needed|url proving that it has been forwarded> Reviewed-By: <name and email of someone who approved the patch> Last-Update: <YYYY-MM-DD> --- tellico-2.3.5+dfsg.1.orig/src/fetch/CMakeLists.txt +++ tellico-2.3.5+dfsg.1/src/fetch/CMakeLists.txt @@ -55,7 +55,14 @@ TARGET_LINK_LIBRARIES(fetch btparse ) -TARGET_LINK_LIBRARIES(fetch ${KDEPIMLIBS_KXMLRPCCLIENT_LIBS}) +# Versions of KDE prior to 4.7 have a character encoding bug in libkxmlrpc +# Use internal version of libkxmlrpc if so +IF (KDEPIMLIBS_FOUND AND ${KDE_VERSION} VERSION_GREATER "4.6.99") + TARGET_LINK_LIBRARIES(fetch ${KDEPIMLIBS_KXMLRPCCLIENT_LIBS}) +ELSE (KDEPIMLIBS_FOUND AND ${KDE_VERSION} VERSION_GREATER "4.6.99") + ADD_SUBDIRECTORY(xmlrpc) + TARGET_LINK_LIBRARIES(fetch xmlrpc) +ENDIF (KDEPIMLIBS_FOUND AND ${KDE_VERSION} VERSION_GREATER "4.6.99") IF( YAZ_FOUND ) TARGET_LINK_LIBRARIES(fetch ${YAZ_LIBRARIES}) @@ -68,3 +75,4 @@ ENDIF( QJSON_FOUND ) ########### install files ############### INSTALL(FILES z3950-servers.cfg DESTINATION ${TELLICO_DATA_INSTALL_DIR} ) + --- tellico-2.3.5+dfsg.1.orig/src/fetch/moviemeterfetcher.cpp +++ tellico-2.3.5+dfsg.1/src/fetch/moviemeterfetcher.cpp @@ -22,7 +22,7 @@ * * ***************************************************************************/ -#include <config.h> +#include "config.h" #include "moviemeterfetcher.h" #include "../collections/videocollection.h" #include "../images/imagefactory.h" @@ -40,7 +40,15 @@ #include <QGridLayout> #include <QTextCodec> +// we use an internal copy of kxmlrpc for versions before 4.7 +// since it doesn't handle character encoding correctly +// see https://git.reviewboard.kde.org/r/101838/ +#include <kdeversion.h> +#if defined(HAVE_KXMLRPC) && KDE_IS_VERSION(4,7,0) #include <kxmlrpcclient/client.h> +#else +#include "xmlrpc/client.h" +#endif namespace { static const char* MOVIEMETER_API_KEY = "t80a06uf736d0yd00jpynpdsgea255yk"; @@ -371,3 +379,4 @@ QString MovieMeterFetcher::ConfigWidget: } #include "moviemeterfetcher.moc" + --- /dev/null +++ tellico-2.3.5+dfsg.1/src/fetch/xmlrpc/query.h @@ -0,0 +1,103 @@ +/****************************************************************************** + * Copyright (C) 2003 - 2004 by Frerich Raabe <ra...@kde.org> * + * Tobias Koenig <to...@kde.org> * + * Copyright (C) 2006 by Narayan Newton <narayannew...@gmail.com> * + * * + * This program 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. For licensing and distribution * + * details, check the accompanying file 'COPYING.BSD'. * + *****************************************************************************/ +/** + @file + + This file is part of KXmlRpc and defines our internal classes. + + @author Frerich Raabe <ra...@kde.org> + @author Tobias Koenig <to...@kde.org> + @author Narayan Newton <narayannew...@gmail.com> +*/ + +#ifndef KXML_RPC_QUERY_H +#define KXML_RPC_QUERY_H + +#undef QT_NO_CAST_FROM_ASCII + +#include <QtCore/QList> +#include <QtCore/QObject> +#include <QtCore/QVariant> +#include <QtCore/QMap> +#include <kio/job.h> + +class QString; + +/** Namespace for XmlRpc related classes */ +namespace KXmlRpc { + +/** + @brief + Query is a class that represents an individual XML-RPC call. + + This is an internal class and is only used by the KXmlRpc::Client class. + @internal + */ +class Query : public QObject +{ + friend class Result; + Q_OBJECT + + public: + /** + Constructs a query. + + @param id an optional id for the query. + @param parent an optional parent for the query. + */ + static Query *create( const QVariant &id = QVariant(), QObject *parent = 0 ); + + public Q_SLOTS: + /** + Calls the specified method on the specified server with + the given argument list. + + @param server the server to contact. + @param method the method to call. + @param args an argument list to pass to said method. + @param jobMetaData additional arguments to pass to the KIO::Job. + */ + void call( const QString &server, const QString &method, + const QList<QVariant> &args, + const QMap<QString, QString> &jobMetaData ); + + Q_SIGNALS: + /** + A signal sent when we receive a result from the server. + */ + void message( const QList<QVariant> &result, const QVariant &id ); + + /** + A signal sent when we receive an error from the server. + */ + void fault( int, const QString &, const QVariant &id ); + + /** + A signal sent when a query finishes. + */ + void finished( Query * ); + + private: + explicit Query( const QVariant &id, QObject *parent = 0 ); + ~Query(); + + class Private; + Private *const d; + + Q_PRIVATE_SLOT( d, void slotData( KIO::Job *, const QByteArray & ) ) + Q_PRIVATE_SLOT( d, void slotResult( KJob * ) ) +}; + +} // namespace XmlRpc + +#endif + + --- /dev/null +++ tellico-2.3.5+dfsg.1/src/fetch/xmlrpc/client.cpp @@ -0,0 +1,223 @@ +/***************************************************************************** + * Copyright (C) 2003 - 2004 by Frerich Raabe <ra...@kde.org> * + * Tobias Koenig <to...@kde.org> * + * Copyright (C) 2006 by Narayan Newton <narayannew...@gmail.com> * + * * + * This program 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. For licensing and distribution * + * details, check the accompanying file 'COPYING.BSD'. * + *****************************************************************************/ +/** + @file + This file is part of the API for accessing XML-RPC Servers + and defines the Client class. + + @brief + Defines the Client class. + + @author Frerich Raabe <ra...@kde.org> + @author Tobias Koenig <to...@kde.org> + @author Narayan Newton <narayannew...@gmail.com> +*/ + +#include "client.h" +#include "query.h" + +#include <kio/job.h> +#include <kdebug.h> +#include <klocale.h> +#include <kurl.h> + +#include <QtCore/QVariant> + +using namespace KXmlRpc; + +class Client::Private +{ + public: + Private() : mUserAgent( "KDE XMLRPC resources" ), mDigestAuth( false ){} + + void queryFinished( Query * ); + + KUrl mUrl; + QString mUserAgent; + bool mDigestAuth; + QList<Query*> mPendingQueries; +}; + +void Client::Private::queryFinished( Query *query ) +{ + mPendingQueries.removeAll( query ); + query->deleteLater(); +} + +Client::Client( QObject *parent ) + : QObject( parent ), d( new Private ) +{ +} + +Client::Client( const KUrl &url, QObject *parent ) + : QObject( parent ), d( new Private ) +{ + d->mUrl = url; +} + +Client::~Client() +{ + QList<Query *>::Iterator it; + for ( it = d->mPendingQueries.begin(); it != d->mPendingQueries.end(); ++it ) { + (*it)->deleteLater(); + } + + d->mPendingQueries.clear(); + + delete d; +} + +void Client::setUrl( const KUrl &url ) +{ + d->mUrl = url.isValid() ? url : KUrl(); +} + +KUrl Client::url() const +{ + return d->mUrl; +} + +QString Client::userAgent() const +{ + return d->mUserAgent; +} + +void Client::setUserAgent( const QString &userAgent ) +{ + d->mUserAgent = userAgent; +} + +bool Client::isDigestAuthEnabled() const +{ + return d->mDigestAuth; +} + +void Client::setDigestAuthEnabled( bool enabled ) +{ + d->mDigestAuth = enabled; +} + +void Client::call( const QString &method, const QList<QVariant> &args, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, const QVariant &id ) +{ + + QMap<QString, QString> metaData; + + if ( d->mUrl.isEmpty() ) { + kWarning() << "Cannot execute call to" << method << ": empty server URL"; + } + + //Fill metadata, with userAgent and possible digest auth + if ( d->mUserAgent.isEmpty() ) { + metaData["UserAgent"] = "KDE-XMLRPC"; + } else { + metaData["UserAgent"] = d->mUserAgent; + } + + if ( d->mDigestAuth ) { + metaData["WWW-Authenticate:"] = "Digest"; + } + + Query *query = Query::create( id, this ); + connect( query, SIGNAL(message(const QList<QVariant> &,const QVariant &)), msgObj, messageSlot ); + connect( query, SIGNAL(fault(int,const QString &,const QVariant &)), faultObj, faultSlot ); + connect( query, SIGNAL(finished(Query *)), this, SLOT(queryFinished(Query *)) ); + d->mPendingQueries.append( query ); + + query->call( d->mUrl.url(), method, args, metaData ); +} + +void Client::call( const QString &method, const QVariant &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + args << arg ; + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Client::call( const QString &method, int arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Client::call( const QString &method, bool arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Client::call( const QString &method, double arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Client::call( const QString &method, const QString &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Client::call( const QString &method, const QByteArray &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + args << QVariant( arg ); + call( method, args, faultObj, faultSlot, msgObj, messageSlot, id ); +} + +void Client::call( const QString &method, const QDateTime &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Client::call( const QString &method, const QStringList &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + for ( int i = 0; i < arg.count(); ++i ) { + args << QVariant( arg[ i ] ); + } + + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +#include "client.moc" + --- /dev/null +++ tellico-2.3.5+dfsg.1/src/fetch/xmlrpc/CMakeLists.txt @@ -0,0 +1,9 @@ +########### next target ############### + +SET(xmlrpc_STAT_SRCS + query.cpp + client.cpp + ) + +KDE4_ADD_LIBRARY(xmlrpc STATIC ${xmlrpc_STAT_SRCS}) + --- /dev/null +++ tellico-2.3.5+dfsg.1/src/fetch/xmlrpc/query.cpp @@ -0,0 +1,454 @@ +/****************************************************************************** + * Copyright (C) 2003 - 2004 by Frerich Raabe <ra...@kde.org> * + * Tobias Koenig <to...@kde.org> * + * Copyright (C) 2006 by Narayan Newton <narayannew...@gmail.com> * + * * + * This program 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. For licensing and distribution * + * details, check the accompanying file 'COPYING.BSD'. * + *****************************************************************************/ +/** + @file + + This file is part of KXmlRpc and defines our internal classes. + + @author Frerich Raabe <ra...@kde.org> + @author Tobias Koenig <to...@kde.org> + @author Narayan Newton <narayannew...@gmail.com> +*/ + +#include "query.h" + +#include <kdebug.h> +#include <klocale.h> + +#include <QtCore/QDateTime> +#include <QtCore/QVariant> +#include <QtXml/QDomDocument> + + +using namespace KXmlRpc; + +/** + @file + + Implementation of Query +**/ + +namespace KXmlRpc { + +/** + @brief + Result is an internal class that represents a response + from a XML-RPC server. + + This is an internal class and is only used by Query. + @internal + */ +class Result +{ + friend class Query; + friend class Query::Private; + + public: + /** + Constructs a result. + */ + Result(); + + /** + Destroys a result. + */ + ~Result(); + + /** + Returns true if the method call succeeded, false + if there was an XML-RPC fault. + + @see errorCode(), errorString() + */ + bool success() const; + + /** + Returns the error code of the fault. + + @see success(), errorString() + */ + int errorCode() const; + + /** + Returns the error string that describes the fault. + + @see success, errorCode() + */ + QString errorString() const; + + /** + Returns the data sent to us from the server. + */ + QList<QVariant> data() const; + + private: + bool mSuccess; + int mErrorCode; + QString mErrorString; + QList<QVariant> mData; +}; + +} // namespace KXmlRpcClient + +KXmlRpc::Result::Result() +{ +} + +KXmlRpc::Result::~Result() +{ +} + +bool KXmlRpc::Result::success() const +{ + return mSuccess; +} + +int KXmlRpc::Result::errorCode() const +{ + return mErrorCode; +} + +QString KXmlRpc::Result::errorString() const +{ + return mErrorString; +} + +QList<QVariant> KXmlRpc::Result::data() const +{ + return mData; +} + +class Query::Private +{ + public: + Private( Query *parent ) + : mParent( parent ) + { + } + + bool isMessageResponse( const QDomDocument &doc ) const; + bool isFaultResponse( const QDomDocument &doc ) const; + + Result parseMessageResponse( const QDomDocument &doc ) const; + Result parseFaultResponse( const QDomDocument &doc ) const; + + QString markupCall( const QString &method, const QList<QVariant> &args ) const; + QString marshal( const QVariant &value ) const; + QVariant demarshal( const QDomElement &element ) const; + + void slotData( KIO::Job *job, const QByteArray &data ); + void slotResult( KJob *job ); + + Query *mParent; + QByteArray mBuffer; + QVariant mId; + QList<KJob*> mPendingJobs; +}; + +bool Query::Private::isMessageResponse( const QDomDocument &doc ) const +{ + return doc.documentElement().firstChild().toElement().tagName().toLower() + == "params"; +} + +bool Query::Private::isFaultResponse( const QDomDocument &doc ) const +{ + return doc.documentElement().firstChild().toElement().tagName().toLower() + == "fault"; +} + +Result Query::Private::parseMessageResponse( const QDomDocument &doc ) const +{ + Result response; + response.mSuccess = true; + + QDomNode paramNode = doc.documentElement().firstChild().firstChild(); + while ( !paramNode.isNull() ) { + response.mData << demarshal( paramNode.firstChild().toElement() ); + paramNode = paramNode.nextSibling(); + } + + return response; +} + +Result Query::Private::parseFaultResponse( const QDomDocument &doc ) const +{ + Result response; + response.mSuccess = false; + + QDomNode errorNode = doc.documentElement().firstChild().firstChild(); + const QVariant errorVariant = demarshal( errorNode.toElement() ); + response.mErrorCode = errorVariant.toMap() [ "faultCode" ].toInt(); + response.mErrorString = errorVariant.toMap() [ "faultString" ].toString(); + + return response; +} + +QString Query::Private::markupCall( const QString &cmd, + const QList<QVariant> &args ) const +{ + QString markup = "<?xml version=\"1.0\" ?>\r\n<methodCall>\r\n"; + + markup += "<methodName>" + cmd + "</methodName>\r\n"; + + if ( !args.isEmpty() ) { + + markup += "<params>\r\n"; + QList<QVariant>::ConstIterator it = args.begin(); + QList<QVariant>::ConstIterator end = args.end(); + for ( ; it != end; ++it ) { + markup += "<param>\r\n" + marshal( *it ) + "</param>\r\n"; + } + markup += "</params>\r\n"; + } + + markup += "</methodCall>\r\n"; + + return markup; +} + +QString Query::Private::marshal( const QVariant &arg ) const +{ + switch ( arg.type() ) { + + case QVariant::String: + return "<value><string><![CDATA[" + arg.toString() + "]]></string></value>\r\n"; + case QVariant::StringList: + { + QStringList data = arg.toStringList(); + QStringListIterator dataIterator(data); + QString markup; + markup += "<value><array><data>"; + while ( dataIterator.hasNext() ) { + markup += "<value><string><![CDATA[" + dataIterator.next() + "]]></string></value>\r\n"; + } + markup += "</data></array></value>"; + return markup; + } + case QVariant::Int: + return "<value><int>" + QString::number( arg.toInt() ) + "</int></value>\r\n"; + case QVariant::Double: + return "<value><double>" + QString::number( arg.toDouble() ) + "</double></value>\r\n"; + case QVariant::Bool: + { + QString markup = "<value><boolean>"; + markup += arg.toBool() ? "1" : "0"; + markup += "</boolean></value>\r\n"; + return markup; + } + case QVariant::ByteArray: + return "<value><base64>" + arg.toByteArray().toBase64() + "</base64></value>\r\n"; + case QVariant::DateTime: + { + return "<value><dateTime.iso8601>" + + arg.toDateTime().toString( Qt::ISODate ) + + "</dateTime.iso8601></value>\r\n"; + } + case QVariant::List: + { + QString markup = "<value><array><data>\r\n"; + const QList<QVariant> args = arg.toList(); + QList<QVariant>::ConstIterator it = args.begin(); + QList<QVariant>::ConstIterator end = args.end(); + for ( ; it != end; ++it ) { + markup += marshal( *it ); + } + markup += "</data></array></value>\r\n"; + return markup; + } + case QVariant::Map: + { + QString markup = "<value><struct>\r\n"; + QMap<QString, QVariant> map = arg.toMap(); + QMap<QString, QVariant>::ConstIterator it = map.constBegin(); + QMap<QString, QVariant>::ConstIterator end = map.constEnd(); + for ( ; it != end; ++it ) { + markup += "<member>\r\n"; + markup += "<name>" + it.key() + "</name>\r\n"; + markup += marshal( it.value() ); + markup += "</member>\r\n"; + } + markup += "</struct></value>\r\n"; + return markup; + } + default: + kWarning() << "Failed to marshal unknown variant type:" << arg.type(); + }; + + return QString(); +} + +QVariant Query::Private::demarshal( const QDomElement &element ) const +{ + Q_ASSERT( element.tagName().toLower() == "value" ); + + const QDomElement typeElement = element.firstChild().toElement(); + const QString typeName = typeElement.tagName().toLower(); + + if ( typeName == "string" ) { + return QVariant( typeElement.text() ); + } else if ( typeName == "i4" || typeName == "int" ) { + return QVariant( typeElement.text().toInt() ); + } else if ( typeName == "double" ) { + return QVariant( typeElement.text().toDouble() ); + } else if ( typeName == "boolean" ) { + + if ( typeElement.text().toLower() == "true" || typeElement.text() == "1" ) { + return QVariant( true ); + } else { + return QVariant( false ); + } + } else if ( typeName == "base64" ) { + return QVariant( QByteArray::fromBase64( typeElement.text().toLatin1() ) ); + } else if ( typeName == "datetime" || typeName == "datetime.iso8601" ) { + QDateTime date; + QString dateText = typeElement.text(); + // Test for broken use of Basic ISO8601 date and extended ISO8601 time + if ( 17 <= dateText.length() && dateText.length() <= 18 && + dateText.at( 4 ) != '-' && dateText.at( 11 ) == ':' ) { + if ( dateText.endsWith( 'Z' ) ) { + date = QDateTime::fromString( dateText, "yyyyMMddTHH:mm:ssZ" ); + } else { + date = QDateTime::fromString( dateText, "yyyyMMddTHH:mm:ss" ); + } + } else { + date = QDateTime::fromString( dateText, Qt::ISODate ); + } + return QVariant( date ); + } else if ( typeName == "array" ) { + QList<QVariant> values; + QDomNode valueNode = typeElement.firstChild().firstChild(); + while ( !valueNode.isNull() ) { + values << demarshal( valueNode.toElement() ); + valueNode = valueNode.nextSibling(); + } + return QVariant( values ); + } else if ( typeName == "struct" ) { + + QMap<QString, QVariant> map; + QDomNode memberNode = typeElement.firstChild(); + while ( !memberNode.isNull() ) { + const QString key = memberNode.toElement().elementsByTagName( + "name" ).item( 0 ).toElement().text(); + const QVariant data = demarshal( memberNode.toElement().elementsByTagName( + "value" ).item( 0 ).toElement() ); + map[ key ] = data; + memberNode = memberNode.nextSibling(); + } + return QVariant( map ); + } else { + kWarning() << "Cannot demarshal unknown type" << typeName; + } + return QVariant(); +} + +void Query::Private::slotData( KIO::Job *, const QByteArray &data ) +{ + unsigned int oldSize = mBuffer.size(); + mBuffer.resize( oldSize + data.size() ); + memcpy( mBuffer.data() + oldSize, data.data(), data.size() ); +} + +void Query::Private::slotResult( KJob *job ) +{ + mPendingJobs.removeAll( job ); + + if ( job->error() != 0 ) { + emit mParent->fault( job->error(), job->errorString(), mId ); + emit mParent->finished( mParent ); + return; + } + +// const QString data = QString::fromUtf8( mBuffer.data(), mBuffer.size() ); + + QDomDocument doc; + QString errMsg; + int errLine, errCol; + if ( !doc.setContent( mBuffer, false, &errMsg, &errLine, &errCol ) ) { + emit mParent->fault( -1, i18n( "Received invalid XML markup: %1 at %2:%3", + errMsg, errLine, errCol ), mId ); + emit mParent->finished( mParent ); + return; + } + + mBuffer.truncate( 0 ); + + if ( isMessageResponse( doc ) ) { + emit mParent->message( parseMessageResponse( doc ).data(), mId ); + } else if ( isFaultResponse( doc ) ) { + emit mParent->fault( parseFaultResponse( doc ).errorCode(), + parseFaultResponse( doc ).errorString(), mId ); + } else { + emit mParent->fault( 1, i18n( "Unknown type of XML markup received" ), + mId ); + } + + emit mParent->finished( mParent ); +} + +Query *Query::create( const QVariant &id, QObject *parent ) +{ + return new Query( id, parent ); +} + +void Query::call( const QString &server, + const QString &method, + const QList<QVariant> &args, + const QMap<QString, QString> &jobMetaData ) +{ + + const QString xmlMarkup = d->markupCall( method, args ); + + QMap<QString, QString>::const_iterator mapIter; + QByteArray postData; + QDataStream stream( &postData, QIODevice::WriteOnly ); + stream.writeRawData( xmlMarkup.toUtf8(), xmlMarkup.toUtf8().length() ); + + KIO::TransferJob *job = KIO::http_post( KUrl( server ), postData, KIO::HideProgressInfo ); + + if ( !job ) { + kWarning() << "Unable to create KIO job for" << server; + return; + } + + job->addMetaData( "content-type", "Content-Type: text/xml; charset=utf-8" ); + job->addMetaData( "ConnectTimeout", "50" ); + + for ( mapIter = jobMetaData.begin(); mapIter != jobMetaData.end(); ++mapIter ) { + job->addMetaData( mapIter.key(), mapIter.value() ); + } + + connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ), + this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) ); + connect( job, SIGNAL( result( KJob * ) ), + this, SLOT( slotResult( KJob * ) ) ); + + d->mPendingJobs.append( job ); +} + +Query::Query( const QVariant &id, QObject *parent ) + : QObject( parent ), d( new Private( this ) ) +{ + d->mId = id; +} + +Query::~Query() +{ + QList<KJob*>::Iterator it; + for ( it = d->mPendingJobs.begin(); it != d->mPendingJobs.end(); ++it ) { + (*it)->kill(); + } + delete d; +} + +#include "query.moc" + + --- /dev/null +++ tellico-2.3.5+dfsg.1/src/fetch/xmlrpc/client.h @@ -0,0 +1,323 @@ +/****************************************************************************** + * Copyright (C) 2003 - 2004 by Frerich Raabe <ra...@kde.org> * + * Tobias Koenig <to...@kde.org> * + * Copyright (C) 2006 by Narayan Newton <narayannew...@gmail.com> * + * * + * This program 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. For licensing and distribution * + * details, check the accompanying file 'COPYING.BSD'. * + *****************************************************************************/ +/** + @file + This file is part of the API for accessing XML-RPC Servers + and defines the Client class. + + @brief + Defines the Client class. + + @author Frerich Raabe <ra...@kde.org> + @author Tobias Koenig <to...@kde.org> + @author Narayan Newton <narayannew...@gmail.com> +*/ + +#ifndef KXML_RPC_CLIENT_H +#define KXML_RPC_CLIENT_H + +#undef QT_NO_CAST_FROM_ASCII + +#include <kurl.h> + +#include <QtCore/QList> +#include <QtCore/QObject> +#include <QtCore/QVariant> + +/** Names for XmlRpc related classes */ +namespace KXmlRpc { + +/** + @brief + A class that represents a connection to a XML-RPC server. + This is the main interface to the XML-RPC client library. + + @code + KXmlRpc::Client *c = new Client(KUrl( "http://localhost" ), this); + c->setUserAgent( "Test/1.0" ); + c->call( "xmlrpc.command1", "Hi!", + this, SLOT( gotData( const QList<QVariant>&, const QVariant ) ), + this, SLOT( gotError( const QString&, const QVariant& ) ) ); + @endcode + + @author Narayan Newton <narayannew...@gmail.com> + */ +class Client : public QObject +{ + Q_OBJECT + + public: + /** + Constructs a XML-RPC Client. + + @param parent the parent of this object, defaults to NULL. + */ + explicit Client( QObject *parent = 0 ); + + /** + Constructs a XML-RPC Client, which will connect to @p url. + + @param url the url of the xml-rpc server. + @param parent the parent of this object, defaults to NULL. + */ + explicit Client( const KUrl &url, QObject *parent = 0 ); + + /** + Destroys the XML-RPC Client. + */ + ~Client(); + + /** + Returns the current url the XML-RPC Client will connect to. + + @see setUrl() + */ + KUrl url() const; + + /** + Sets the url the Client will connect to. + + @param url the url for the xml-rpc server we will be connecting to. + + @see url() + */ + void setUrl( const KUrl &url ); + + /** + Returns the user agent string currently used by the Client. + + @see setUserAgent() + */ + QString userAgent() const; + + /** + Sets the userAgent string the Client will use to identify itself. + + @param userAgent the user agent string to use. + + @see userAgent() + */ + void setUserAgent( const QString &userAgent ); + + /** + Returns true if HTTP-Digest authentication is enabled, false + if not. + + @see setDigestAuthEnabled() + */ + bool isDigestAuthEnabled() const; + + /** + Enables/disables HTTP-Digest authentication + + @see isDigestAuthEnabled() + */ + + void setDigestAuthEnabled( bool enabled ); + + public Q_SLOTS: + /** + Calls the given method on a XML-RPC server, with the given + argument list. + + @param method the method on the server we are going to be calling + @param args the argument list to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our #Client object, defaults to empty + */ + void call( const QString &method, const QList<QVariant> &args, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + argument. + + @param method the method on the server we are going to be calling + @param arg the argument to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, const QVariant &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + int as the argument. + + @param method the method on the server we are going to be calling + @param arg the int to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, int arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + bool as the argument. + + @param method the method on the server we are going to be calling + @param arg the bool to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, bool arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + double as the argument. + + @param method the method on the server we are going to be calling + @param arg the double to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, double arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + string as the argument. + + @param method the method on the server we are going to be calling + @param arg the string to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, const QString &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + byte array as the argument. + + @param method the method on the server we are going to be calling + @param arg the array to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, const QByteArray &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + date as the argument + + @param method the method on the server we are going to be calling + @param arg the date and/or time to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, const QDateTime &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + /** + Calls the given method on a XML-RPC server, with the given + string list as the argument + + @param method the method on the server we are going to be calling + @param arg the list of strings to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty + */ + void call( const QString &method, const QStringList &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id = QVariant() ); + + private: + class Private; + Private *const d; + + template <typename T> + void call( const QString &method, const QList<T> &arg, + QObject *obj1, const char *messageSlot, + QObject *obj2, const char *faultSlot, + const QVariant &id = QVariant() ); + + Q_PRIVATE_SLOT( d, void queryFinished( Query * ) ) +}; + +/** + Calls the given method on a XML-RPC server with the given + list of type T arguments. + + @param method the method on the server we are going to be calling + @param arg the list of type T to pass to the server + @param msgObj the object containing the data slot + @param messageSlot the data slot itself + @param faultObj the object containing the error slot + @param faultSlot the error slot itself + @param id the id for our Client object, defaults to empty +*/ +template <typename T> +void Client::call( const QString &method, const QList<T> &arg, + QObject *msgObj, const char *messageSlot, + QObject *faultObj, const char *faultSlot, + const QVariant &id ) +{ + QList<QVariant> args; + + for ( int i = 0; i < arg.count(); ++i ) { + args << QVariant( arg[ i ] ); + } + + return call( method, args, faultObj, faultSlot, msgObj, messageSlot, id ); +} + +} + +#endif +