diff options
Diffstat (limited to 'dcoprss')
-rw-r--r-- | dcoprss/Makefile.am | 28 | ||||
-rw-r--r-- | dcoprss/article.cpp | 49 | ||||
-rw-r--r-- | dcoprss/cache.cpp | 129 | ||||
-rw-r--r-- | dcoprss/cache.h | 86 | ||||
-rw-r--r-- | dcoprss/client.cpp | 75 | ||||
-rw-r--r-- | dcoprss/document.cpp | 307 | ||||
-rw-r--r-- | dcoprss/feedbrowser.cpp | 144 | ||||
-rw-r--r-- | dcoprss/feedbrowser.h | 66 | ||||
-rw-r--r-- | dcoprss/main.cpp | 39 | ||||
-rw-r--r-- | dcoprss/query.cpp | 271 | ||||
-rw-r--r-- | dcoprss/query.h | 120 | ||||
-rw-r--r-- | dcoprss/rssnewsfeed.h | 115 | ||||
-rw-r--r-- | dcoprss/rssservice.desktop | 88 | ||||
-rw-r--r-- | dcoprss/service.cpp | 105 | ||||
-rw-r--r-- | dcoprss/service.h | 290 | ||||
-rw-r--r-- | dcoprss/test.sh | 24 | ||||
-rw-r--r-- | dcoprss/xmlrpciface.cpp | 401 | ||||
-rw-r--r-- | dcoprss/xmlrpciface.h | 185 |
18 files changed, 2522 insertions, 0 deletions
diff --git a/dcoprss/Makefile.am b/dcoprss/Makefile.am new file mode 100644 index 00000000..2bc93d67 --- /dev/null +++ b/dcoprss/Makefile.am @@ -0,0 +1,28 @@ +bin_PROGRAMS = rssservice rssclient feedbrowser +INCLUDES = -I$(top_srcdir) $(all_includes) + +rssservice_LDFLAGS = $(KDE_RPATH) $(all_libraries) +rssservice_LDADD = $(LIB_KIO) ../librss/librss.la +rssservice_SOURCES = main.cpp service.cpp query.cpp document.cpp article.cpp query.skel service.skel xmlrpciface.cpp cache.cpp + + +# client stuff +rssclient_LDFLAGS = $(KDE_RPATH) $(all_libraries) +rssclient_LDADD = $(LIB_KDECORE) +rssclient_SOURCES = client.cpp + +feedbrowser_LDFLAGS = $(KDE_RPATH) $(all_libraries) +feedbrowser_LDADD = $(LIB_KDEUI) +feedbrowser_SOURCES = feedbrowser.skel feedbrowser.cpp + +noinst_HEADERS = service.h query.h xmlrpciface.h cache.h + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/dcoprss.pot + + +service_DATA = rssservice.desktop +servicedir = $(kde_servicesdir) + diff --git a/dcoprss/article.cpp b/dcoprss/article.cpp new file mode 100644 index 00000000..d191bd74 --- /dev/null +++ b/dcoprss/article.cpp @@ -0,0 +1,49 @@ +/* $Id$ */ +/*************************************************************************** + article.cpp - A DCOP Service to provide RSS data + ------------------- + begin : Saturday 15 February 2003 + copyright : (C) 2003 by Ian Reinhart Geiser + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include <kdebug.h> +#include <kurl.h> +#include "service.h" + +RSSArticle::RSSArticle(Article *art) : + DCOPObject(), m_Art(art) +{ + kdDebug() << "New article..." << endl; + kdDebug() << m_Art->link().prettyURL() << endl; +} + +RSSArticle::~RSSArticle() +{ + kdDebug() << "Article going away..." << endl; + delete m_Art; +} + +QString RSSArticle::title() +{ + //kdDebug() << "Get title " << m_Art->title() << endl; + return m_Art->title(); +} + +QString RSSArticle::description() +{ + return m_Art->description(); +} + +QString RSSArticle::link() +{ + return m_Art->link().prettyURL(); +} diff --git a/dcoprss/cache.cpp b/dcoprss/cache.cpp new file mode 100644 index 00000000..9c80a9a3 --- /dev/null +++ b/dcoprss/cache.cpp @@ -0,0 +1,129 @@ +/* + * cache.cpp - (c) 2003 Frerich Raabe <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "cache.h" +#include "xmlrpciface.h" + +#include <kdebug.h> +#include <kstandarddirs.h> + +#include <qdatastream.h> +#include <qfile.h> + +bool CacheEntry::isValid() const +{ + // Cache entries get invalid after on hour. One shouldn't hardcode this + // but for now it'll do. + return m_timeStamp.secsTo( QDateTime::currentDateTime() ) < 3600; +} + +Cache *Cache::m_instance = 0; + +Cache &Cache::self() +{ + if ( !m_instance ) + m_instance = new Cache; + return *m_instance; +} + +QString Cache::getCacheKey( const QString &server, const QString &method, + const QValueList<QVariant> &args ) +{ + QString key; + key = server + QString::fromLatin1( "__" ); + key += method + QString::fromLatin1( "__" ); + QValueList<QVariant>::ConstIterator it = args.begin(); + QValueList<QVariant>::ConstIterator end = args.end(); + for ( ; it != end; ++it ) + key += KXMLRPC::Query::marshal( *it ); + + return key; +} + +Cache::Cache() +{ + load(); +} + +Cache::~Cache() +{ + save(); +} + +void Cache::load() +{ + QFile file( cacheFileName() ); + if ( !file.open( IO_ReadOnly ) ) { + kdDebug() << "Failed to open cache file " << cacheFileName() << endl; + return; + } + + QDataStream stream( &file ); + while ( !stream.atEnd() ) { + QString key; + stream >> key; + + CacheEntry *entry = new CacheEntry; + stream >> *entry; + + QDict<CacheEntry>::insert( key, entry ); + } +} + +void Cache::save() +{ + QFile file( cacheFileName() ); + if ( !file.open( IO_WriteOnly ) ) { + kdDebug() << "Failed to open cache file " << cacheFileName() << endl; + return; + } + + QDataStream stream( &file ); + + QDictIterator<CacheEntry> it( *this ); + for ( ; it.current() != 0; ++it ) + stream << it.currentKey() << *it.current(); +} + +void Cache::touch( const QString &key ) +{ + CacheEntry *entry = find( key ); + if ( !entry ) + return; + entry->m_timeStamp = QDateTime::currentDateTime(); +} + +void Cache::insert( const QString &key, const KXMLRPC::Query::Result &result ) +{ + CacheEntry *entry = new CacheEntry; + entry->m_timeStamp = QDateTime::currentDateTime(); + entry->m_result = result; + QDict<CacheEntry>::insert( key, entry ); +} + +QString Cache::cacheFileName() const +{ + return locateLocal( "appdata", "cache/dcoprss.cache" ); +} + diff --git a/dcoprss/cache.h b/dcoprss/cache.h new file mode 100644 index 00000000..8248b609 --- /dev/null +++ b/dcoprss/cache.h @@ -0,0 +1,86 @@ +/* + * cache.h - (c) 2003 Frerich Raabe <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef CACHE_H +#define CACHE_H + +#include <qcstring.h> +#include <qdatetime.h> +#include <qdict.h> + +#include <xmlrpciface.h> + +class CacheEntry +{ + friend class Cache; + friend QDataStream &operator>>( QDataStream &s, CacheEntry &e ); + public: + const QDateTime &timeStamp() const { return m_timeStamp; } + const KXMLRPC::Query::Result result() const { return m_result; } + bool isValid() const; + + private: + QDateTime m_timeStamp; + KXMLRPC::Query::Result m_result; +}; + +class Cache : public QDict<CacheEntry> +{ + public: + static Cache &self(); + + static QString getCacheKey( const QString &server, + const QString &method, + const QValueList<QVariant> &args ); + + void load(); + void save(); + + void touch( const QString &key ); + + void insert( const QString &key, const KXMLRPC::Query::Result &result ); + + private: + Cache(); + Cache( const Cache &rhs ); // disabled + Cache &operator=( const Cache &rhs ); // disabled + ~Cache(); + + QString cacheFileName() const; + + static Cache *m_instance; +}; + +inline QDataStream &operator<<( QDataStream &s, const CacheEntry &e ) +{ + return s << e.timeStamp() << e.result(); +} + +inline QDataStream &operator>>( QDataStream &s, CacheEntry &e ) +{ + return s >> e.m_timeStamp >> e.m_result; +} + +#endif // CACHE_H +// vim:ts=4:sw=4:noet diff --git a/dcoprss/client.cpp b/dcoprss/client.cpp new file mode 100644 index 00000000..b74894de --- /dev/null +++ b/dcoprss/client.cpp @@ -0,0 +1,75 @@ +/* $Id$ */ +#include <kapplication.h> +#include <dcopclient.h> +#include <dcopref.h> +#include <qdatastream.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qcstring.h> +#include <kdebug.h> +#include <stdlib.h> +/* +class rssIface : virtual public DCOPObject +{ + K_DCOP +public: + + rssIface( KApplication *app) + { + // get our DCOP client and attach so that we may use it + DCOPClient *client = app->dcopClient(); + client->attach(); + QString error; + QCString appID; + kdDebug() << "Looking for rss service..." << endl; + if (!client->isApplicationRegistered("rssservice")) + { + kdDebug() << "Could not find service so I am starting it..." << endl; + if(KApplication::startServiceByName("rssservice",QStringList(), &error, &appID )) + { + kdDebug() << "Starting rssservice failed with message: " << error << endl; + exit(0); + } + } + kdDebug ()<< "Accessing rssservice..." << endl; + + if (!connectDCOPSignal(0,0, "documentUpdated(DCOPRef)", + "refresh(DCOPRef)",false)) + kdDebug() << "Could not attach signal..." << endl; + else + kdDebug() << "attached dcop signals..." << endl; + + QString url("http://freshmeat.net/backend/fm.rdf"); + DCOPRef m_rssservice("rssservice","RSSService"); + m_rssservice.call("load(QString)", url); + QStringList returnList = m_rssservice.call("list()"); + DCOPRef doc = m_rssservice.call("document(QString)", returnList[0]); + QString title = doc.call("title()"); + QString link = doc.call("link()"); + QString description = doc.call("description()"); + kdDebug() << title << endl; + kdDebug() << link << endl; + kdDebug() << description << endl; + } + + k_dcop: + virtual void refresh(DCOPRef doc) + { + QString title = doc.call("title()"); + QString link = doc.call("link()"); + QString description = doc.call("description()"); + kdDebug() << title << endl; + kdDebug() << link << endl; + kdDebug() << description << endl; + } + + private: + +}; +*/ +int main(int argc, char **argv) +{ + KApplication *app = new KApplication(argc, argv, "client", false); + + app->exec(); +} diff --git a/dcoprss/document.cpp b/dcoprss/document.cpp new file mode 100644 index 00000000..b43f600e --- /dev/null +++ b/dcoprss/document.cpp @@ -0,0 +1,307 @@ +/* $Id$ */ +/*************************************************************************** + document.cpp - A DCOP Service to provide RSS data + ------------------- + begin : Saturday 15 February 2003 + copyright : (C) 2003 by Ian Reinhart Geiser + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include <kdebug.h> +#include <qdatetime.h> +#include <kurl.h> +#include "service.h" + +RSSDocument::RSSDocument(const QString& url) : + QObject(), DCOPObject(), m_Url(url) +{ + + m_list.setAutoDelete( true ); + m_Doc = 0L; + m_pix = QPixmap(); + m_isLoading = false; + m_maxAge = 60; + m_Timeout = QDateTime::currentDateTime(); + m_state.clear(); +} + +RSSDocument::~RSSDocument() +{ + kdDebug() << "Document going away..." << endl; + + delete m_Doc; +} + +void RSSDocument::loadingComplete(Loader *ldr, Document doc, Status stat) +{ + + + if( m_Doc != 0L) + { + delete m_Doc; + + } + + if (stat != RSS::Success) + { + kdDebug() << "Document error! Loader:" << ldr->errorCode() << " Parser:" << stat << endl; + + m_isLoading = false; + m_Doc = 0L; + if( stat == RSS::ParseError ) + documentUpdateError(DCOPRef(this), 1); + else if( stat == RSS::RetrieveError ) + documentUpdateError(DCOPRef(this), 2); + else + documentUpdateError(DCOPRef(this), 3); + } + else + { + kdDebug() << "New Document is done..." << endl; + m_Doc = new Document(doc); + m_list.clear(); + Article::List list = doc.articles(); + for(Article::List::ConstIterator it = list.begin(); it != list.end(); ++it) + { + int state = m_state[(*it).title()]; + if( state == 0 ) m_state[(*it).title()] = 1; // new + else if( state == 1 ) m_state[(*it).title()] = 2; // old message now + m_list.append( new RSSArticle( new Article(*it))); + } + Image *img = m_Doc->image(); + if ( img ) + { + connect(img, SIGNAL(gotPixmap(const QPixmap &)), + SLOT(pixmapLoaded(const QPixmap &))); + img->getPixmap(); + pixmapUpdating(DCOPRef(this)); + } + m_isLoading = false; + documentUpdated(DCOPRef(this)); + + kdDebug() << "Old Mod time " << m_Timeout.toString() << endl; + m_Timeout = m_Timeout.addSecs(m_maxAge * 60 ); + kdDebug() << "New Mod time " << m_Timeout.toString() << endl; + + } +} + +void RSSDocument::pixmapLoaded(const QPixmap &pix ) +{ + m_pix = pix; + pixmapUpdated(DCOPRef(this)); +} + +QString RSSDocument::webMaster() +{ + if( m_Doc != 0L) + return m_Doc->webMaster(); + else + return ""; +} + +QString RSSDocument::managingEditor() +{ + if( m_Doc != 0L) + return m_Doc->managingEditor(); + else + return ""; +} + +QString RSSDocument::rating() +{ + if( m_Doc != 0L) + return m_Doc->rating(); + else + return ""; +} + +QDateTime RSSDocument::lastBuildDate() +{ + if( m_Doc != 0L) + return m_Doc->lastBuildDate(); + else + return QDateTime::currentDateTime(); +} + +QDateTime RSSDocument::pubDate() +{ + if( m_Doc != 0L) + return m_Doc->pubDate(); + else + return QDateTime::currentDateTime(); +} + +QString RSSDocument::copyright() +{ + if( m_Doc != 0L) + return m_Doc->copyright(); + else + return ""; +} + +QStringList RSSDocument::articles() +{ + if( m_Doc != 0L) + { + kdDebug() << "Document giving articles..." << endl; + Article::List list = m_Doc->articles(); + QStringList stringList; + + for(Article::List::ConstIterator it = list.begin(); it != list.end(); ++it) + stringList.append((*it).title()); + return stringList; + } + else + return QStringList(); +} + +DCOPRef RSSDocument::article(int idx) +{ + if(m_list.at(idx)) + return DCOPRef(m_list.at(idx)); + else + return DCOPRef(); +} + +int RSSDocument::count() +{ + if( m_Doc != 0L) + return m_Doc->articles().count(); + return 0; +} + +QString RSSDocument::link() +{ + if( m_Doc != 0L) + return m_Doc->link().prettyURL(); + else + return ""; +} + +QString RSSDocument::description() +{ + if( m_Doc != 0L) + return m_Doc->description(); + else + return ""; +} + +QString RSSDocument::title() +{ + if( m_Doc != 0L) + return m_Doc->title(); + else + return ""; +} + +QString RSSDocument::verbVersion() +{ + if( m_Doc != 0L) + return m_Doc->verbVersion(); + else + return ""; +} + +QString RSSDocument::pixmapURL() +{ + if( m_Doc != 0L) + if( m_Doc->image() ) + return m_Doc->image()->url().prettyURL(); + else + return ""; + else + return ""; +} + +QPixmap RSSDocument::pixmap() +{ + return m_pix; +} + +bool RSSDocument::documentValid() +{ + if (m_Doc != 0L) + return true; + else + return false; +} + +bool RSSDocument::pixmapValid() +{ + return !m_pix.isNull(); +} + +void RSSDocument::refresh() +{ + kdDebug() << "Mod time " << m_Timeout.toString() << endl; + kdDebug() << "Current time " << QDateTime::currentDateTime().toString() << endl; + + if(!m_isLoading && (QDateTime::currentDateTime() >= m_Timeout)) + { + kdDebug() << "Document going to refresh" << endl; + m_isLoading = true; + Loader *loader = Loader::create(this, + SLOT(loadingComplete(Loader *, Document, Status))); + loader->loadFrom(KURL( m_Url ), new FileRetriever()); + documentUpdating(DCOPRef(this)); + } + else + { + documentUpdated(DCOPRef(this)); + if(pixmapValid()) + pixmapUpdated(DCOPRef(this)); + /* + else + { + // Refactor this! + Image *img = m_Doc->image(); + if ( img ) + { + connect(img, SIGNAL(gotPixmap(const QPixmap &)), + SLOT(pixmapLoaded(const QPixmap &))); + img->getPixmap(); + pixmapUpdating(DCOPRef(this)); + } + } + */ + } + +} + +int RSSDocument::maxAge() +{ + return m_maxAge; +} + +void RSSDocument::setMaxAge(int _min) +{ + m_Timeout.addSecs(-m_maxAge); + m_maxAge = _min; + m_Timeout.addSecs(m_maxAge); +} + +int RSSDocument::state( const QString &title) const +{ + return m_state[title]; +} + +void RSSDocument::setState( const QString &title, int s ) +{ + m_state[title] = s; +} + +void RSSDocument::read( const QString &title) +{ + m_state[title] = 3; +} + +#include "service.moc" diff --git a/dcoprss/feedbrowser.cpp b/dcoprss/feedbrowser.cpp new file mode 100644 index 00000000..59a55040 --- /dev/null +++ b/dcoprss/feedbrowser.cpp @@ -0,0 +1,144 @@ +#include "feedbrowser.h" + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <klistview.h> +#include <klocale.h> +#include <dcopclient.h> + +#include <qcstring.h> +#include <qdatastream.h> +#include <qvbox.h> + +CategoryItem::CategoryItem( KListView *parent, const QString &category ) + : KListViewItem( parent ), + m_category( category ) +{ + init(); +} + +CategoryItem::CategoryItem( KListViewItem *parent, const QString &category ) + : KListViewItem( parent ), + m_category( category ) +{ + init(); +} + +void CategoryItem::init() +{ + m_populated = false; + m_dcopIface = 0; + + setText( 0, m_category.mid( m_category.findRev( '/' ) + 1 ).replace( '_', ' ' ) ); +} + +void CategoryItem::setOpen( bool open ) +{ + if ( open && !m_populated ) { + populate(); + m_populated = true; + } + KListViewItem::setOpen( open ); +} + +void CategoryItem::populate() +{ + m_dcopIface = new DCOPRSSIface( this, "m_dcopIface" ); + connect( m_dcopIface, SIGNAL( gotCategories( const QStringList & ) ), + this, SLOT( gotCategories( const QStringList & ) ) ); + m_dcopIface->getCategories( m_category ); +} + +void CategoryItem::gotCategories( const QStringList &categories ) +{ + delete m_dcopIface; + m_dcopIface = 0; + + QStringList::ConstIterator it = categories.begin(); + QStringList::ConstIterator end = categories.end(); + for ( ; it != end; ++it ) + new CategoryItem( this, *it ); + + if ( !categories.isEmpty() ) + KListViewItem::setOpen( true ); +} + +DCOPRSSIface::DCOPRSSIface( QObject *parent, const char *name ) : + QObject( parent, name ), DCOPObject( "FeedBrowser" ) +{ + connectDCOPSignal( "rssservice", "RSSQuery", "gotCategories(QStringList)", + "slotGotCategories(QStringList)", false ); +} + +void DCOPRSSIface::getCategories( const QString &cat ) +{ + QByteArray data; + QDataStream stream( data, IO_WriteOnly ); + stream << cat; + kapp->dcopClient()->send( "rssservice", "RSSQuery", + "getCategories(QString)", data ); +} + +void DCOPRSSIface::slotGotCategories( const QStringList &categories ) +{ + emit gotCategories( categories ); +} + +FeedBrowserDlg::FeedBrowserDlg( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "DCOPRSS Feed Browser" ), + Close, Close, true ) +{ + m_dcopIface = new DCOPRSSIface( this, "m_dcopIface" ); + connect( m_dcopIface, SIGNAL( gotCategories( const QStringList & ) ), + this, SLOT( gotTopCategories( const QStringList & ) ) ); + + QVBox *mainWidget = makeVBoxMainWidget(); + + m_feedList = new KListView( mainWidget, "m_feedList" ); + m_feedList->setAllColumnsShowFocus( true ); + m_feedList->setRootIsDecorated( true ); + m_feedList->addColumn( i18n( "Name" ) ); + connect( m_feedList, SIGNAL( executed( QListViewItem * ) ), + this, SLOT( itemSelected( QListViewItem * ) ) ); + connect( m_feedList, SIGNAL( returnPressed( QListViewItem * ) ), + this, SLOT( itemSelected( QListViewItem * ) ) ); + + resize( 500, 400 ); + + getTopCategories(); +} + +void FeedBrowserDlg::getTopCategories() +{ + m_dcopIface->getCategories( "Top" ); +} + +void FeedBrowserDlg::gotTopCategories( const QStringList &categories ) +{ + QStringList::ConstIterator it = categories.begin(); + QStringList::ConstIterator end = categories.end(); + for ( ; it != end; ++it ) + new CategoryItem( m_feedList, *it ); +} + +void FeedBrowserDlg::itemSelected( QListViewItem *item ) +{ + item->setOpen( !item->isOpen() ); +} + +int main( int argc, char **argv ) +{ + KGlobal::locale()->setMainCatalogue( "dcoprss" ); + KAboutData aboutData( "feedbrowser", I18N_NOOP( "Feed Browser" ), "0.1" ); + KCmdLineArgs::init( argc, argv, &aboutData ); + KApplication app; + FeedBrowserDlg *dlg = new FeedBrowserDlg( 0 ); + app.setMainWidget( dlg ); + dlg->show(); + return app.exec(); +} + +#include "feedbrowser.moc" diff --git a/dcoprss/feedbrowser.h b/dcoprss/feedbrowser.h new file mode 100644 index 00000000..829ecd5e --- /dev/null +++ b/dcoprss/feedbrowser.h @@ -0,0 +1,66 @@ +#ifndef FEEDBROWSER_H +#define FEEDBROWSER_H + +#include <qobject.h> +#include <dcopobject.h> +#include <kdialogbase.h> +#include <klistview.h> + +class DCOPRSSIface : public QObject, public DCOPObject +{ + K_DCOP + Q_OBJECT + public: + DCOPRSSIface( QObject *parent, const char *name = 0 ); + + k_dcop: + void slotGotCategories( const QStringList &categories ); + + public slots: + void getCategories( const QString &cat = "Top" ); + + signals: + void gotCategories( const QStringList &categories ); +}; + +class CategoryItem : public QObject, public KListViewItem +{ + Q_OBJECT + public: + CategoryItem( KListView *parent, const QString &category ); + CategoryItem( KListViewItem *parent, const QString &category ); + + virtual void setOpen( bool open ); + + private slots: + void gotCategories( const QStringList &categories ); + + private: + void populate(); + void init(); + + QString m_category; + bool m_populated; + DCOPRSSIface *m_dcopIface; +}; + +class FeedBrowserDlg : public KDialogBase +{ + Q_OBJECT + friend class CategoryItem; + public: + FeedBrowserDlg( QWidget *parent, const char *name = 0 ); + + private slots: + void itemSelected( QListViewItem *item ); + void gotTopCategories( const QStringList &categories ); + + private: + void getTopCategories(); + + DCOPRSSIface *m_dcopIface; + KListView *m_feedList; +}; + +#endif // FEEDBROWSER_H +// vim:ts=4:sw=4:noet diff --git a/dcoprss/main.cpp b/dcoprss/main.cpp new file mode 100644 index 00000000..fcebf8c0 --- /dev/null +++ b/dcoprss/main.cpp @@ -0,0 +1,39 @@ +/* $Id$ */ + +#include <kuniqueapplication.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <dcopclient.h> +#include "service.h" +#include "query.h" + +int main (int argc, char *argv[]) +{ + KLocale::setMainCatalogue("dcoprss"); + KAboutData aboutdata("rssservice", I18N_NOOP("KDE RSS Service"), + "0.8", I18N_NOOP("A RSS data service."), + KAboutData::License_GPL, "(C) 2003, Ian Reinhart Geiser"); + aboutdata.addAuthor("Ian Reinhart Geiser",I18N_NOOP("Developer"),"[email protected]"); + + KCmdLineArgs::init( argc, argv, &aboutdata ); + // KCmdLineArgs::addCmdLineOptions( options ); + KUniqueApplication::addCmdLineOptions(); + + if (!KUniqueApplication::start()) + { + kdDebug() << "rssservice is already running!" << endl; + return (0); + } + + KUniqueApplication app; + kdDebug() << "starting rssservice " << endl; + // This app is started automatically, no need for session management + app.disableSessionManagement(); + RSSService *service = new RSSService; + QueryService *query = new QueryService(service); + + return app.exec(); +} diff --git a/dcoprss/query.cpp b/dcoprss/query.cpp new file mode 100644 index 00000000..b2c29fdf --- /dev/null +++ b/dcoprss/query.cpp @@ -0,0 +1,271 @@ +/* $Id$ */ + +/*************************************************************************** + query.cpp - A query interface to select RSS feeds. + ------------------- + begin : Saturday 15 February 2003 + copyright : (C) 2003 by Ian Reinhart Geiser + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include "cache.h" +#include "query.h" + +#include <kdebug.h> +#include <krfcdate.h> + +#include "service.h" +#include "xmlrpciface.h" + +using KXMLRPC::Server; + +void SlotCaller::call( QObject *object, const char *slot, + const KXMLRPC::Query::Result &result ) +{ + SlotCaller caller; + connect( &caller, SIGNAL( signal( const KXMLRPC::Query::Result &) ), + object, slot ); + emit caller.signal( result ); +} + +QueryService::QueryService( RSSService *service ) : QObject(), DCOPObject( "RSSQuery" ), + m_service( service ) +{ + m_xmlrpcServer = new KXMLRPC::Server( KURL( "http://www.syndic8.com/xmlrpc.php"), this ); +} + +QStringList QueryService::listActive() +{ + if ( !m_service ) + return QStringList(); + return m_service->list(); +} + +void QueryService::cachedCall( const QString &method, + const QValueList<QVariant> &args, + const char *slot ) +{ + kdDebug() << "Calling " << method << endl; + + const QString cacheKey = Cache::getCacheKey( m_xmlrpcServer->url().url(), + method, args ); + + CacheEntry *cacheEntry = Cache::self().find( cacheKey ); + if ( cacheEntry != 0 && cacheEntry->isValid() ) { + kdDebug() << "Using cached result." << endl; + SlotCaller::call( this, slot, cacheEntry->result() ); + } else { + kdDebug() << "No cached result found, querying server." << endl; + m_xmlrpcServer->call( method, args, this, slot ); + } +} + +void QueryService::updateCache( const KXMLRPC::Query::Result &result ) +{ + const QString cacheKey = Cache::getCacheKey( result.server(), + result.method(), + result.args() ); + + CacheEntry *cacheEntry = Cache::self().find( cacheKey ); + if ( cacheEntry == 0 ) { + kdDebug() << "Inserting returned result into cache." << endl; + Cache::self().insert( cacheKey, result ); + } +} + +void QueryService::findFeeds( const QString &query ) +{ + kdDebug() << "QueryService::findFeeds()" << endl; + + QStringList args; + args << query << "headlines_rank"; + + cachedCall( "syndic8.FindFeeds", Server::toVariantList( args ), + SLOT( slotFoundFeeds( const KXMLRPC::Query::Result & ) ) ); +} + +void QueryService::findSites( const QString& query ) +{ + kdDebug() << "QueryService::findSites()" << endl; + + cachedCall( "syndic8.FindSites", Server::toVariantList( query ), + SLOT( slotFoundFeeds( const KXMLRPC::Query::Result & ) ) ); +} + +void QueryService::getFeedInfo( const QVariant& ids ) +{ + kdDebug() << "QueryService::getFeedInfo()" << endl; + + cachedCall( "syndic8.GetFeedInfo", Server::toVariantList( ids ), + SLOT( slotGotFeedInfo( const KXMLRPC::Query::Result & ) ) ); +} + +void QueryService::getCategories( const QString &category ) +{ + kdDebug() << "QueryService::getCategories()" << endl; + + if ( category == "Top" ) { + cachedCall( "syndic8.GetCategoryRoots", Server::toVariantList( QString::fromLatin1( "DMOZ" ) ), + SLOT( slotGotCategories( const KXMLRPC::Query::Result & ) ) ); + } else { + QStringList args; + args << "DMOZ" << category; + cachedCall( "syndic8.GetCategoryChildren", Server::toVariantList( args ), + SLOT( slotGotCategories( const KXMLRPC::Query::Result & ) ) ); + } +} + +void QueryService::getFeedsInCategory( const QString &category ) +{ + kdDebug() << "QueryService::getFeedsInCategory()" << endl; + + QStringList args; + args << "DMOZ" << category; + + cachedCall( "syndic8.GetFeedsInCategory", Server::toVariantList( args ), + SLOT( slotGotFeedsInCategory( const KXMLRPC::Query::Result & ) ) ); +} + +void QueryService::slotFoundFeeds( const KXMLRPC::Query::Result &result ) +{ + kdDebug() << "QueryService::slotFoundFeeds()" << endl; + if ( !result.success() ) { + kdWarning() << "Failed to query for feeds: " << result.errorString() << endl; + return; + } + + updateCache( result ); + + QValueList<int> ids; + + const QValueList<QVariant> values = result.data()[ 0 ].toList(); + QValueList<QVariant>::ConstIterator it = values.begin(); + QValueList<QVariant>::ConstIterator end = values.end(); + for ( ; it != end; ++it ) { + ids << ( *it ).toInt(); + kdDebug() << "Found feed #" << ( *it ).toInt() << endl; + } + feedIds( ids ); +} + +void QueryService::slotGotFeedInfo( const KXMLRPC::Query::Result &result ) +{ + kdDebug() << "QueryService::slotGotFeedInfo()" << endl; + if ( !result.success() ) { + kdWarning() << "Failed to get feed info: " << result.errorString() << endl; + return; + } + + updateCache( result ); + + QMap<QString, QString> links; + QValueList<RSSNewsFeed> feeds; + + const QValueList<QVariant> feedInfos = result.data(); + QValueList<QVariant>::ConstIterator it = feedInfos.begin(); + QValueList<QVariant>::ConstIterator end = feedInfos.end(); + for ( ; it != end; ++it ) { + const QMap<QString, QVariant> feedInfo = ( *it ).toMap(); + + const QString name = feedInfo[ "sitename" ].toString(); + const QString link = feedInfo[ "dataurl" ].toString(); + links[ name ] = link; + + RSSNewsFeed feed; + feed.m_id = feedInfo[ "feedid" ].toUInt(); + feed.m_name = feedInfo[ "sitename" ].toString(); + feed.m_homePage = feedInfo[ "siteurl" ].toString(); + feed.m_sourceFile = feedInfo[ "dataurl" ].toString(); + feed.m_imageUrl = feedInfo[ "imageurl" ].toString(); + feed.m_webmaster = feedInfo[ "webmaster" ].toString(); + feed.m_editor = feedInfo[ "editor" ].toString(); + feed.m_publisher = feedInfo[ "publisher" ].toString(); + feed.m_creator = feedInfo[ "creator" ].toString(); + QDateTime dateTime; + dateTime.setTime_t( KRFCDate::parseDate( feedInfo[ "date_created" ].toString() ) ); + feed.m_dateCreated = dateTime; + dateTime.setTime_t( KRFCDate::parseDate( feedInfo[ "date_approved" ].toString() ) ); + feed.m_dateApproved = dateTime; + dateTime.setTime_t( KRFCDate::parseDate( feedInfo[ "date_xml_changed" ].toString() ) ); + feed.m_dateXmlChanged = dateTime; + feed.m_fetchable = feedInfo[ "fetchable" ].toBool(); + feed.m_description = feedInfo[ "description" ].toString(); + feed.m_origin = feedInfo[ "origin" ].toString(); + feed.m_languageCode = feedInfo[ "lang_code" ].toString(); + feed.m_status = feedInfo[ "status" ].toString(); + feed.m_version = feedInfo[ "rss_version" ].toString(); + feed.m_views = feedInfo[ "views" ].toUInt(); + feed.m_headlinesPerDay = feedInfo[ "headlines_per_day" ].toUInt(); + feed.m_headlinesRank = feedInfo[ "headlines_rank" ].toUInt(); + feed.m_toolkit = feedInfo[ "toolkit" ].toString(); + feed.m_toolkitVersion = feedInfo[ "toolkit_version" ].toString(); + feed.m_pollingInterval = feedInfo[ "cur_polling_interval" ].toUInt(); + dateTime.setTime_t( feedInfo[ "last_poll_time" ].toUInt() ); + feed.m_lastPoll = dateTime; + // ### feed.m_categories missing here! + + feeds << feed; + + kdDebug() << "Retrieved data for newsfeed '" << name << "' <" << link << ">" << endl; + } + + feedInfo( links ); + feedInfo( feeds ); +} + +void QueryService::slotGotCategories( const KXMLRPC::Query::Result &result ) +{ + kdDebug() << "QueryService::slotGotCategories()" << endl; + if ( !result.success() ) { + kdWarning() << "Failed to get the list of categories: " << result.errorString() << endl; + return; + } + + updateCache( result ); + + QStringList categories; + + const QValueList<QVariant> cats = result.data()[ 0 ].toList(); + QValueList<QVariant>::ConstIterator it = cats.begin(); + QValueList<QVariant>::ConstIterator end = cats.end(); + for ( ; it != end; ++it ) + categories << ( *it ).toString(); + + kdDebug() << "Got categories: " << categories.join( ", " ) << endl; + gotCategories( categories ); + +} + +void QueryService::slotGotFeedsInCategory( const KXMLRPC::Query::Result &result ) +{ + kdDebug() << "QueryService::slotGotFeedsInCategory()" << endl; + if ( !result.success() ) { + kdWarning() << "Failed to get the feeds in the given category: " << result.errorString() << endl; + return; + } + + updateCache( result ); + + QValueList<int> ids; + + const QValueList<QVariant> values = result.data()[ 0 ].toList(); + QValueList<QVariant>::ConstIterator it = values.begin(); + QValueList<QVariant>::ConstIterator end = values.end(); + for ( ; it != end; ++it ) { + ids << ( *it ).toInt(); + kdDebug() << "Got feed in category: #" << ( *it ).toInt() << endl; + } + + gotFeedsInCategory( ids ); +} + +#include "query.moc" +// vim:ts=4:sw=4:noet diff --git a/dcoprss/query.h b/dcoprss/query.h new file mode 100644 index 00000000..d87e0505 --- /dev/null +++ b/dcoprss/query.h @@ -0,0 +1,120 @@ +/* $Id$ */ +#ifndef _QUERY_SERVICE +#define _QUERY_SERVICE + +/*************************************************************************** + query.h - A query interface to select RSS feeds. + ------------------- + begin : Saturday 15 February 2003 + copyright : (C) 2003 by Ian Reinhart Geiser + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "rssnewsfeed.h" +#include "xmlrpciface.h" + +#include <dcopobject.h> + +#include <qmap.h> +#include <qobject.h> +#include <qvaluelist.h> +#include <qvariant.h> + +class RSSService; + +/** + * Helper class which just calls the slot given it's QObject/const char* + * representation. + */ +class SlotCaller : public QObject +{ + Q_OBJECT + public: + static void call( QObject *object, const char *slot, + const KXMLRPC::Query::Result &value ); + + signals: + void signal( const KXMLRPC::Query::Result &value ); + + private: + SlotCaller() { } +}; + +class QueryService : public QObject, public DCOPObject +{ + K_DCOP + Q_OBJECT + public: + QueryService( RSSService *service ); + + k_dcop_signals: + void feedIds( QValueList<int> ids ); + void feedInfo(QMap<QString, QString> links); + void feedInfo(QValueList<RSSNewsFeed> feeds); + void gotCategories( const QStringList &categories ); + void gotFeedsInCategory( const QValueList<int> &ids ); + + k_dcop: + /** + * Lists the active feeds in use... + **/ + QStringList listActive(); // just for testing... + + /** + * Query the www.syndic8.com XML-RPC interface for the + * string. The RSS ids are treturned in a integer list. + **/ + void findFeeds( const QString& query ); + + /** + * Query the www.syndic8.com XML-RPC interface for the + * string and matches it against the SiteURL feed of + * each feed in the feed list. The RSS ids are treturned + * in a integer list. + **/ + void findSites( const QString& query ); + + /** + * Query the www.syndic8.com XML-RPC interface for the + * requested RSS feed(s). Returned is a QMap with the format + * of Name (Site URL), RSS URL + **/ + void getFeedInfo( const QVariant& ids ); + + /** + * Returns the list of subcategories in the specified category. + * If no "Top" is specified, the root categories are returned. + */ + void getCategories( const QString &category ); + + /** + * Queries the database for the list of needsfeed ID's which are + * associated with the given category. + */ + void getFeedsInCategory( const QString &category ); + + + private slots: + void slotFoundFeeds( const KXMLRPC::Query::Result &result ); + void slotGotFeedInfo( const KXMLRPC::Query::Result &result ); + void slotGotCategories( const KXMLRPC::Query::Result &result ); + void slotGotFeedsInCategory( const KXMLRPC::Query::Result &result ); + + private: + void cachedCall( const QString &method, const QValueList<QVariant> &args, + const char *slot ); + void updateCache( const KXMLRPC::Query::Result &result ); + + RSSService *m_service; + KXMLRPC::Server *m_xmlrpcServer; +}; +#endif diff --git a/dcoprss/rssnewsfeed.h b/dcoprss/rssnewsfeed.h new file mode 100644 index 00000000..3c2e04b5 --- /dev/null +++ b/dcoprss/rssnewsfeed.h @@ -0,0 +1,115 @@ +/* + * rssnewsfeed.h + * + * Copyright (c) 2003 Frerich Raabe <[email protected]> + * + * 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'. + */ +#ifndef RSSNEWSFEED_H +#define RSSNEWSFEED_H + +#include <qdatetime.h> +#include <qstringlist.h> +#include <qvariant.h> +#include <kdatastream.h> + +class QueryService; + +class RSSNewsFeed +{ + friend QDataStream &operator>>( QDataStream &stream, RSSNewsFeed &feed ); + friend QDataStream &operator<<( QDataStream &stream, const RSSNewsFeed &feed ); + friend class QueryService; + public: + unsigned int id() const { return m_id; } + QString name() const { return m_name; } + QString description() const { return m_description; } + QString origin() const { return m_origin; } + QString languageCode() const { return m_languageCode; } + QString status() const { return m_status; } + QString version() const { return m_version; } + QString homePage() const { return m_homePage; } + QString sourceFile() const { return m_sourceFile; } + QString imageUrl() const { return m_imageUrl; } + QString webmaster() const { return m_webmaster; } + QString editor() const { return m_editor; } + QString publisher() const { return m_publisher; } + QString creator() const { return m_creator; } + const QDateTime &dateCreated() const { return m_dateCreated; } + const QDateTime &dateApproved() const { return m_dateApproved; } + const QDateTime dateXmlChanged() const { return m_dateXmlChanged; } + bool fetchable() const { return m_fetchable; } + unsigned int views() const { return m_views; } + unsigned int headlinesPerDay() const { return m_headlinesPerDay; } + unsigned int headlinesRank() const { return m_headlinesRank; } + QString toolkit() const { return m_toolkit; } + QString toolkitVersion() const { return m_toolkitVersion; } + unsigned int pollingInterval() const { return m_pollingInterval; } + const QDateTime &lastPoll() const { return m_lastPoll; } + QStringList categories() const { return m_categories; } + + private: + unsigned int m_id; + QString m_name; + QString m_description; + QString m_origin; + QString m_languageCode; + QString m_status; + QString m_version; + QString m_homePage; + QString m_sourceFile; + QString m_imageUrl; + QString m_webmaster; + QString m_editor; + QString m_publisher; + QString m_creator; + QDateTime m_dateCreated; + QDateTime m_dateApproved; + QDateTime m_dateXmlChanged; + bool m_fetchable; + unsigned int m_views; + unsigned int m_headlinesPerDay; + unsigned int m_headlinesRank; + QString m_toolkit; + QString m_toolkitVersion; + unsigned int m_pollingInterval; + QDateTime m_lastPoll; + QStringList m_categories; +}; + +inline QDataStream &operator<<( QDataStream &stream, const RSSNewsFeed &feed ) +{ + return stream << feed.m_id << feed.m_name << feed.m_description + << feed.m_origin << feed.m_languageCode << feed.m_status + << feed.m_version << feed.m_homePage << feed.m_sourceFile + << feed.m_imageUrl << feed.m_webmaster << feed.m_publisher + << feed.m_creator << feed.m_dateCreated << feed.m_dateApproved + << feed.m_dateXmlChanged << feed.m_fetchable << feed.m_views + << feed.m_headlinesPerDay << feed.m_headlinesRank + << feed.m_toolkit << feed.m_toolkitVersion + << feed.m_pollingInterval << feed.m_lastPoll + << feed.m_categories; +} + +inline QDataStream &operator>>( QDataStream &stream, RSSNewsFeed &feed ) +{ + int i; + stream >> feed.m_id >> feed.m_name >> feed.m_description + >> feed.m_origin >> feed.m_languageCode >> feed.m_status + >> feed.m_version >> feed.m_homePage >> feed.m_sourceFile + >> feed.m_imageUrl >> feed.m_webmaster >> feed.m_publisher + >> feed.m_creator >> feed.m_dateCreated >> feed.m_dateApproved + >> feed.m_dateXmlChanged >> i >> feed.m_views + >> feed.m_headlinesPerDay >> feed.m_headlinesRank + >> feed.m_toolkit >> feed.m_toolkitVersion + >> feed.m_pollingInterval >> feed.m_lastPoll + >> feed.m_categories; + feed.m_fetchable = i != 0; + return stream; +} + +#endif +// vim:ts=4:sw=4:noet diff --git a/dcoprss/rssservice.desktop b/dcoprss/rssservice.desktop new file mode 100644 index 00000000..1692b267 --- /dev/null +++ b/dcoprss/rssservice.desktop @@ -0,0 +1,88 @@ +[Desktop Entry] +Type=Service +Name=rssservice +Name[bn]=আর-এস-এস সার্ভিস +Name[ca]=Servei RSS +Name[cs]=RSS služba +Name[de]=RSS-Dienst +Name[el]=υπηρεσία rss +Name[he]=שרות RSS +Name[hi]=आरएसएस-सर्विस +Name[hu]=RSS szolgáltatás +Name[it]=Servizio RSS +Name[ja]=rssサービス +Name[lt]=rss tarnyba +Name[nb]=rss-tjeneste +Name[nds]=RSS-Deenst +Name[nl]=RSS-dienst +Name[nn]=rss-teneste +Name[pl]=Usługa RSS +Name[pt_BR]=serviço rss +Name[ro]=Serviciu RSS +Name[sv]=RSS-tjänst +Name[ta]=rssசேவை +Name[th]=บริการ rss +Name[tr]=rssservisi +Exec=rssservice +X-DCOP-ServiceType=Unique +X-KDE-StartupNotify=false +Comment=RSS DCOP services +Comment[ar]= خدمات RSS DCOP +Comment[be]=Сервісы RSS для DCOP +Comment[bn]=আর-এস-এস ডিকপ সার্ভিস +Comment[br]=Servijoù DCOP RSS +Comment[bs]=RSS DCOP servisi +Comment[ca]=Serveis RSS de DCOP +Comment[cs]=RSS DCOP služby +Comment[cy]=Gwasanaethau DCOP RSS +Comment[da]=RSS DCOP-tjenester +Comment[de]=RSS DCOP-Dienste +Comment[el]=Υπηρεσίες RSS DCOP +Comment[eo]=RSS-DCOP-servoj +Comment[es]=Servicios RSS de DCOP +Comment[et]=RSS DCOP-teenused +Comment[eu]=RSS DCOP zerbitzuak +Comment[fa]=خدمات RSS DCOP +Comment[fi]=RSS-DCOP-palvelut +Comment[fr]=Services DCOP RSS +Comment[ga]=Seirbhísí DCOP RSS +Comment[gl]=Servicios RSS de DCOP +Comment[he]=שרותי RSS DCOP +Comment[hi]=आरएसएस डीकॉप सेवाएँ +Comment[hr]=RSS DCOP servisi +Comment[hu]=RSS DCOP-szolgáltatás +Comment[is]=RSS DCOP þjónustur +Comment[it]=Servizi DCOP RSS +Comment[ja]=RSS DCOP サービス +Comment[ka]=RSS DCOP სერვისები +Comment[kk]=RSS DCOP қызметтері +Comment[km]=សេវា RSS DCOP +Comment[lt]=RSS DCOP tarnyba +Comment[mk]=Сервиси за RSS DCOP +Comment[nb]=RSS DCOP -tjenester +Comment[nds]=RSS-DCOP-Deenst +Comment[ne]=RSS DCOP सेवा +Comment[nl]=RSS DCOP-diensten +Comment[nn]=RSS DCOP-tenester +Comment[pa]=RSS DCOP ਸੇਵਾਵਾਂ +Comment[pl]=Usługa DCOP dla RSS +Comment[pt]=Serviços DCOP de RSS +Comment[pt_BR]=Serviços DCOP RSS +Comment[ro]=Serviciu DCOP RSS +Comment[ru]=Службы RSS DCOP +Comment[se]=RSS DCOP-bálvalusat +Comment[sk]=RSS DCOP služby +Comment[sl]=Storitve RSS DCOP +Comment[sr]=RSS DCOP сервиси +Comment[sr@Latn]=RSS DCOP servisi +Comment[sv]=RSS DCOP-tjänster +Comment[ta]=RSS DCOP சேவைகள் +Comment[tg]=Хадамотҳои RSS DCOP +Comment[th]=บริการ RSS DCOP +Comment[tr]=RSS DCOP hizmetleri +Comment[uk]=Служби RSS DCOP +Comment[uz]=RSS DCOP xizmatlari +Comment[uz@cyrillic]=RSS DCOP хизматлари +Comment[zh_CN]=RSS DCOP 服务 +Comment[zh_HK]=RSS DCOP 服務 +Comment[zh_TW]=RSS DCOP 服務 diff --git a/dcoprss/service.cpp b/dcoprss/service.cpp new file mode 100644 index 00000000..74544dc1 --- /dev/null +++ b/dcoprss/service.cpp @@ -0,0 +1,105 @@ +/* $Id$ */ +/*************************************************************************** + service.cpp - A DCOP Service to provide RSS data + ------------------- + begin : Saturday 15 February 2003 + copyright : (C) 2003 by Ian Reinhart Geiser + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include <kdebug.h> +#include <kapplication.h> +#include <kconfig.h> +#include "service.h" +#include "cache.h" + +RSSService::RSSService() : + DCOPObject("RSSService") +{ + m_list.setAutoDelete( true ); + + loadLinks(); +} + +RSSService::~RSSService() +{ +} + + +QStringList RSSService::list() +{ + QStringList lst; + QDictIterator<RSSDocument> itr(m_list); + for(; itr.current(); ++itr) + lst.append(itr.currentKey()); + return lst; +} + +DCOPRef RSSService::add(QString id) +{ + if(m_list.find(id) == 0L) { // add a new one only if we need to + m_list.insert(id, new RSSDocument(id)); + added(id); + saveLinks(); + } + return document(id); +} + +void RSSService::remove(QString id) +{ + m_list.remove(id); + removed(id); + saveLinks(); +} + +DCOPRef RSSService::document(QString id) +{ + if( m_list[id] ) + return DCOPRef(m_list[id]); + else + return DCOPRef(); +} + +void RSSService::exit() +{ + //Save all current RSS links. + saveLinks(); + Cache::self().save(); + kapp->quit(); +} + + +void RSSService::loadLinks() +{ + KConfig *conf = kapp->config(); + conf->setGroup("RSS Links"); + const QStringList links = conf->readListEntry ("links"); + QStringList::ConstIterator it = links.begin(); + QStringList::ConstIterator end = links.end(); + for ( ; it != end; ++it ) + add( *it ); +} + +void RSSService::saveLinks() +{ + KConfig *conf = kapp->config(); + conf->setGroup("RSS Links"); + QStringList lst; + QDictIterator<RSSDocument> itr(m_list); + for(; itr.current(); ++itr) + lst.append(itr.currentKey()); + + conf->writeEntry("links", lst); + conf->sync(); +} + + + diff --git a/dcoprss/service.h b/dcoprss/service.h new file mode 100644 index 00000000..35cf229e --- /dev/null +++ b/dcoprss/service.h @@ -0,0 +1,290 @@ +/* $Id$ */ +#ifndef _RSS_SERVICE +#define _RSS_SERVICE + +/*************************************************************************** + service.h - A DCOP Service to provide RSS data + ------------------- + begin : Saturday 15 February 2003 + copyright : (C) 2003 by Ian Reinhart Geiser + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <dcopobject.h> +#include <dcopref.h> +#include <qdict.h> +#include <qptrlist.h> +#include <qstringlist.h> +#include <qstring.h> +#include <qdatetime.h> +#include <qpixmap.h> +#include <librss/global.h> +#include <librss/loader.h> +#include <librss/document.h> +#include <librss/article.h> +#include <librss/image.h> +/** +* This is a DCOP Service do not include this header in anything +* +**/ +using namespace RSS; + +class RSSDocument; +class RSSArticle; + +class RSSService : public DCOPObject +{ + K_DCOP + + private: + + QDict<RSSDocument> m_list; + + public: + RSSService(); + ~RSSService(); + void saveLinks(); + void loadLinks(); + + + k_dcop_signals: + /** + * Emmitted when a new document has been added. You can then + * use document(QString) to get the dcop ref for the object. + * Note: this document may or may not be valid at this + * point so you should connect your dcop signals and then + * do a documentValid() on the dcop ref to make sure of its + * state. + **/ + + void added(QString); + /** + * Emmitted when the document has been removed. + * note at this point the DCOPRef for this object is + * invalid and you will cannot access it any longer. + * When in doubt call a refresh on it, since if its in the + * process of loading the document call will be safely ignored + * and you will be notified of the updates. + **/ + void removed(QString); + k_dcop: + /** + * Add a new rdf file resource. This will return a dcop reference to the resource. If its a new + * one it will be added otherwise an existing resource reference will be returned. + * once this reference has been returned you may connect dcop signals and then call + * refresh on the RSSDocument. The document will not be updated until refresh is called. + **/ + DCOPRef add(QString url); + /** + * Return a list of current rss documents + **/ + QStringList list(); + /** + * Remove an rss document resource. NOTE: Be aware that others may be using this + * resource and if you remove it they may break. Likewise be aware that someone may + * decide to remove your resource on you so you should always check to see if the resource + * is valid before you access it. + **/ + void remove(QString url); + /** + * Return the reference to a requested resource. If this resource is not present a null dcopref is + * returned. + **/ + DCOPRef document(QString url); + /** + * Exit the RSSService. This will clean everything up and exit. + **/ + void exit(); +}; + +class RSSDocument : public QObject, public DCOPObject +{ + Q_OBJECT + K_DCOP + + private: + bool m_isLoading; + QString m_Url; + Document *m_Doc; + QPixmap m_pix; + QPtrList<RSSArticle> m_list; + QMap<QString,int> m_state; + QDateTime m_Timeout; + int m_maxAge; + + private slots: + void pixmapLoaded(const QPixmap&); + void loadingComplete(Loader *, Document, Status); + + public: + RSSDocument(const QString& url); + ~RSSDocument(); + + k_dcop_signals: + /** + * The pixmap is currently loading + **/ + void pixmapUpdating(DCOPRef); + /** + * The pixmap is ready for viewing + * you can then use dcopref->call("pixmap()"); to return it. + * + **/ + void pixmapUpdated(DCOPRef); + /** + * The document is currently updating + **/ + void documentUpdating(DCOPRef); + /** + * The document is ready for viewing + * you can then use dcopref->call() to access its data + **/ + void documentUpdated(DCOPRef); + /** + * The document failed to update, with and error... + * 1 - RSS Parse Error + * 2 - Could not access file + * 3 - Unknown error. + **/ + void documentUpdateError(DCOPRef, int); + + k_dcop: + /** + * Return the webmaster information from the RSS::Document + **/ + QString webMaster(); + /** + * Return the manageing editor from the RSS::Document + **/ + QString managingEditor(); + /** + * Returns the rating of the RSS::Document + **/ + QString rating(); + /** + * Returns the last build date from the RSS::Document + **/ + QDateTime lastBuildDate(); + /** + * Returns the publication date from the RSS::Document + **/ + QDateTime pubDate(); + /** + * Returns the copyright information from the RSS::Document + **/ + QString copyright(); + /** + * Returns a list of article titles + **/ + QStringList articles(); + /** + * Returns the number of articles + **/ + int count(); + /** + * Returns a dcop reference to the article from the index + **/ + DCOPRef article(int idx); + /** + * Returns the link from the RSS::Document + **/ + QString link(); + /** + * Returns the description from the RSS::Document + **/ + QString description(); + /** + * Returns the title from the RSS::Document + **/ + QString title(); + /** + * Returns the text version from the RSS::Document + **/ + QString verbVersion(); + /** + * Returns the url for the pixmap from the RSS::Document + **/ + QString pixmapURL(); + /** + * Returns the actual pixmap from the RSS::Document's RSS::Image + **/ + QPixmap pixmap(); + /** + * Returns if the RSSDocument contains a valid RSS::Document yet. + **/ + bool documentValid(); + /** + * Returns if the RSSDocument contains a valid RSS::Image + **/ + bool pixmapValid(); + /** + * Refresh the current RSS::Document. + * This must be called before the document is valid. + **/ + void refresh(); + + /** + * Return the maximum age of the RSS document (Default is 60 minutes) + **/ + int maxAge(); + + /** + * Set the maximum age of the RSS document. + **/ + void setMaxAge(int minutes); + + /** + * Returns the state of the article + * 0 - not present (deleted from the rss service) + * 1 - new + * 2 - unread + * 3 - read + */ + int state( const QString &title) const; + + /** + * Set the article state + */ + void setState( const QString &title, int s ); + + /** + * Convience method that will set a title to read. + */ + void read( const QString &title); +}; + +class RSSArticle : public DCOPObject +{ + K_DCOP + + private: + Article *m_Art; + + public: + RSSArticle(Article *art); + ~RSSArticle(); + + k_dcop: + /** + * Return the articles title + **/ + QString title(); + /** + * Return the articles description + **/ + QString description(); + /** + * Return the link to the article + **/ + QString link(); +}; +#endif diff --git a/dcoprss/test.sh b/dcoprss/test.sh new file mode 100644 index 00000000..d5d3e773 --- /dev/null +++ b/dcoprss/test.sh @@ -0,0 +1,24 @@ +#!/bin/bash +ID=`dcopstart rssservice` +#dcop $ID RSSService add "http://www.kde.org/dotkdeorg.rdf" +#dcop $ID RSSService add "http://freshmeat.net/backend/fm.rdf" + +#dcop $REF1 refresh +#dcop $REF2 refresh +echo "Articles:" +DOCS=`dcop rssservice RSSService list` +for DOC in $DOCS +do + DOCREF=`dcop rssservice RSSService document "$DOC"` + TITLE=`dcop $DOCREF title` + CNT=`dcop $DOCREF count` + echo $TITLE - $CNT + echo "------------------------------------" + while let "CNT >0" + do + let "CNT=CNT-1" + ART=`dcop $DOCREF article $CNT` + TEXT=`dcop $ART title` + echo "$CNT $TEXT" + done +done diff --git a/dcoprss/xmlrpciface.cpp b/dcoprss/xmlrpciface.cpp new file mode 100644 index 00000000..e86639eb --- /dev/null +++ b/dcoprss/xmlrpciface.cpp @@ -0,0 +1,401 @@ +/* + * kxmlrpcclient.cpp - (c) 2003 Frerich Raabe <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "xmlrpciface.h" + +#include <kdebug.h> +#include <kio/job.h> +#include <klocale.h> +#include <kmdcodec.h> + +#include <qdom.h> + +using namespace KXMLRPC; + +Query *Query::create( QObject *parent, const char *name ) +{ + return new Query( parent, name ); +} + +void Query::call( const QString &server, const QString &method, + const QValueList<QVariant> &args, const QString &userAgent ) +{ + m_buffer.open( IO_ReadWrite ); + m_server = server; + m_method = method; + m_args = args; + + const QString xmlMarkup = markupCall( method, args ); + + QByteArray postData; + QDataStream stream( postData, IO_WriteOnly ); + stream.writeRawBytes( xmlMarkup.utf8(), xmlMarkup.length() ); + + KIO::TransferJob *job = KIO::http_post( KURL( server ), postData, false ); + job->addMetaData( "UserAgent", userAgent ); + job->addMetaData( "content-type", "Content-Type: text/xml; charset=utf-8" ); + connect( job, SIGNAL( infoMessage( KIO::Job *, const QString & ) ), + this, SLOT( slotInfoMessage( KIO::Job *, const QString & ) ) ); + connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ), + this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) ); + connect( job, SIGNAL( result( KIO::Job * ) ), + this, SLOT( slotResult( KIO::Job * ) ) ); +} + +void Query::slotInfoMessage( KIO::Job *, const QString &msg ) +{ + emit infoMessage( msg ); +} + +void Query::slotData( KIO::Job *, const QByteArray &data ) +{ + m_buffer.writeBlock( data ); +} + +void Query::slotResult( KIO::Job *job ) +{ + Result response; + response.m_server = m_server; + response.m_method = m_method; + response.m_args = m_args; + + response.m_success = false; + + if ( job->error() != 0 ) { + response.m_errorCode = job->error(); + response.m_errorString = job->errorString(); + emit finished( response ); + delete this; + return; + } + + QDomDocument doc; + if ( !doc.setContent( m_buffer.buffer() ) ) { + response.m_errorCode = -1; + response.m_errorString = i18n( "Received invalid XML markup" ); + emit finished( response ); + delete this; + return; + } + + m_buffer.close(); + + if ( isMessageResponse( doc ) ) + response = parseMessageResponse( doc ); + else if ( isFaultResponse( doc ) ) + response = parseFaultResponse( doc ); + else { + response.m_errorCode = 1; + response.m_errorString = i18n( "Unknown type of XML markup received" ); + } + + // parserMessageResponse and parseFaultResponse overwrite these fields. + response.m_server = m_server; + response.m_method = m_method; + response.m_args = m_args; + + emit finished( response ); + delete this; +} + +bool Query::isMessageResponse( const QDomDocument &doc ) const +{ + return doc.documentElement().firstChild().toElement().tagName().lower() == "params"; +} + +Query::Result Query::parseMessageResponse( const QDomDocument &doc ) const +{ + Result response; + response.m_success = true; + + QDomNode paramNode = doc.documentElement().firstChild().firstChild(); + while ( !paramNode.isNull() ) { + response.m_data << demarshal( paramNode.firstChild().toElement() ); + paramNode = paramNode.nextSibling(); + } + + return response; +} + +bool Query::isFaultResponse( const QDomDocument &doc ) const +{ + return doc.documentElement().firstChild().toElement().tagName().lower() == "fault"; +} + +Query::Result Query::parseFaultResponse( const QDomDocument &doc ) const +{ + Result response; + response.m_success = false; + + QDomNode errorNode = doc.documentElement().firstChild().firstChild(); + const QVariant errorVariant = demarshal( errorNode.toElement() ); + response.m_errorCode = errorVariant.toMap()[ "faultCode" ].toInt(); + response.m_errorString = errorVariant.toMap()[ "faultString" ].toString(); + + return response; +} + +QString Query::markupCall( const QString &cmd, + const QValueList<QVariant> &args ) const +{ + QString markup = "<?xml version='1.0' ?><methodCall>"; + + markup += "<methodName>" + cmd + "</methodName>"; + + if ( !args.isEmpty() ) { + markup += "<params>"; + QValueList<QVariant>::ConstIterator it = args.begin(); + QValueList<QVariant>::ConstIterator end = args.end(); + for ( ; it != end; ++it ) + markup += "<param>" + marshal( *it ) + "</param>"; + markup += "</params>"; + } + + markup += "</methodCall>"; + + return markup; +} + +QString Query::marshal( const QVariant &arg ) +{ + QString s = "<value>"; + switch ( arg.type() ) { + case QVariant::String: + case QVariant::CString: + s += "<string>" + arg.toString() + "</string>"; + break; + case QVariant::Int: + s += "<int>" + QString::number( arg.toInt() ) + "</int>"; + break; + case QVariant::Double: + s += "<double>" + QString::number( arg.toDouble() ) + "</double>"; + break; + case QVariant::Bool: + s += "<boolean>"; + s += arg.toBool() ? "true" : "false"; + s += "</boolean>"; + break; + case QVariant::ByteArray: + s += "<base64>" + KCodecs::base64Encode( arg.toByteArray() ) + "</base64>"; + break; + case QVariant::DateTime: + s += "<datetime.iso8601>" + arg.toDateTime().toString( Qt::ISODate ) + "</datetime.iso8601>"; + break; + case QVariant::List: { + s += "<array><data>"; + const QValueList<QVariant> args = arg.toList(); + QValueList<QVariant>::ConstIterator it = args.begin(); + QValueList<QVariant>::ConstIterator end = args.end(); + for ( ; it != end; ++it ) + s += marshal( *it ); + s += "</data></array>"; + break; + } + case QVariant::Map: { + s += "<struct>"; + QMap<QString, QVariant> map = arg.toMap(); + QMap<QString, QVariant>::ConstIterator it = map.begin(); + QMap<QString, QVariant>::ConstIterator end = map.end(); + for ( ; it != end; ++it ) { + s += "<member>"; + s += "<name>" + it.key() + "</name>"; + s += marshal( it.data() ); + s += "</member>"; + } + s += "</struct>"; + break; + } + default: + kdWarning() << "Failed to marshal unknown variant type: " << arg.type() << endl; + return "<value/>"; + }; + return s + "</value>"; +} + +QVariant Query::demarshal( const QDomElement &elem ) +{ + Q_ASSERT( elem.tagName().lower() == "value" ); + + if ( !elem.firstChild().isElement() ) + return QVariant( elem.text() ); + + const QDomElement typeElement = elem.firstChild().toElement(); + const QString typeName = typeElement.tagName().lower(); + + 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().lower() == "true" || typeElement.text() == "1" ) + return QVariant( true ); + else + return QVariant( false ); + } else if ( typeName == "base64" ) + return QVariant( KCodecs::base64Decode( typeElement.text().latin1() ) ); + else if ( typeName == "datetime" || typeName == "datetime.iso8601" ) + return QVariant( QDateTime::fromString( typeElement.text(), Qt::ISODate ) ); + else if ( typeName == "array" ) { + QValueList<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 + kdWarning() << "Cannot demarshal unknown type " << typeName << endl; + + return QVariant(); +} + +Query::Query( QObject *parent, const char *name ) : QObject( parent, name ) +{ +} + +QValueList<QVariant> Server::toVariantList( const QVariant &arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( int arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( bool arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( double arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( const QString &arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( const QCString &arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( const QByteArray &arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( const QDateTime &arg ) +{ + QValueList<QVariant> args; + args << arg ; + return args; +} + +QValueList<QVariant> Server::toVariantList( const QStringList &arg ) +{ + QValueList<QVariant> args; + QStringList::ConstIterator it = arg.begin(); + QStringList::ConstIterator end = arg.end(); + for ( ; it != end; ++it ) + args << QVariant( *it ); + return args; +} + +Server::Server( const KURL &url, QObject *parent, const char *name ) + : QObject( parent, name ) +{ + if ( url.isValid() ) + m_url = url; +} + +void Server::setUrl( const KURL &url ) +{ + m_url = url.isValid() ? url : KURL(); +} + +void Server::call( const QString &method, const QValueList<QVariant> &args, + QObject *receiver, const char *slot ) +{ + if ( m_url.isEmpty() ) { + kdWarning() << "Cannot execute call to " << method << ": empty server URL" << endl; + return; + } + + Query *query = Query::create( this ); + connect( query, SIGNAL( infoMessage( const QString & ) ), + this, SIGNAL( infoMessage( const QString & ) ) ); + connect( query, SIGNAL( finished( const KXMLRPC::Query::Result & ) ), + receiver, slot ); + query->call( m_url.url(), method, args, m_userAgent ); +} + +void Server::call( const QString &method, const QValueList<QVariant> &args, + QObject *receiver, const char *slot, + QObject *infoObject, const char *infoSlot ) +{ + if ( m_url.isEmpty() ) { + kdWarning() << "Cannot execute call to " << method << ": empty server URL" << endl; + return; + } + + Query *query = Query::create( this ); + connect( query, SIGNAL( infoMessage( const QString &msg ) ), + infoObject, infoSlot ); + connect( query, SIGNAL( finished( const KXMLRPC::Query::Result & ) ), + receiver, slot ); + query->call( m_url.url(), method, args, m_userAgent ); +} + +#include "xmlrpciface.moc" +// vim:ts=4:sw=4:noet diff --git a/dcoprss/xmlrpciface.h b/dcoprss/xmlrpciface.h new file mode 100644 index 00000000..f7897e10 --- /dev/null +++ b/dcoprss/xmlrpciface.h @@ -0,0 +1,185 @@ +/* + * kxmlrpcclient.h - (c) 2003 Frerich Raabe <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef KXMLRPCCLIENT_H +#define KXMLRPCCLIENT_H + +#include <kurl.h> + +#include <qbuffer.h> +#include <qdatastream.h> +#include <qobject.h> +#include <qvariant.h> +#include <qvaluelist.h> + +class QDomDocument; +class QDomElement; + +namespace KIO +{ + class Job; +} + +namespace KXMLRPC +{ + class Query; + class QueryResult; + class Server; + + class Query : public QObject + { + Q_OBJECT + public: + class Result + { + friend class Query; + friend QDataStream &operator>>( QDataStream &s, Query::Result &r ); + public: + Result() { } + + bool success() const { return m_success; } + int errorCode() const { return m_errorCode; } + QString errorString() const { return m_errorString; } + QValueList<QVariant> data() const { return m_data; } + QString server() const { return m_server; } + QString method() const { return m_method; } + QValueList<QVariant> args() const { return m_args; } + + private: + bool m_success; + int m_errorCode; + QString m_errorString; + QValueList<QVariant> m_data; + QString m_server; + QString m_method; + QValueList<QVariant> m_args; + }; + + static Query *create( QObject *parent = 0, const char *name = 0 ); + static QString marshal( const QVariant &v ); + static QVariant demarshal( const QDomElement &e ); + + public slots: + void call( const QString &server, const QString &method, + const QValueList<QVariant> &args = QValueList<QVariant>(), + const QString &userAgent = "KDE-XMLRPC" ); + + signals: + void infoMessage( const QString &msg ); + void finished( const KXMLRPC::Query::Result &result ); + + private slots: + void slotInfoMessage( KIO::Job *job, const QString &msg ); + void slotData( KIO::Job *job, const QByteArray &data ); + void slotResult( KIO::Job *job ); + + private: + 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 QValueList<QVariant> &args ) const; + + Query( QObject *parent = 0, const char *name = 0 ); + + QBuffer m_buffer; + QString m_server; + QString m_method; + QValueList<QVariant> m_args; + }; + + class Server : public QObject + { + Q_OBJECT + public: + Server( const KURL &url = KURL(), + QObject *parent = 0, const char *name = 0 ); + + const KURL &url() const { return m_url; } + void setUrl( const KURL &url ); + + QString userAgent() const { return m_userAgent; } + void setUserAgent( const QString &userAgent) { m_userAgent = userAgent; } + + template <typename T> + void call( const QString &method, const QValueList<T> &arg, + QObject *object, const char *slot ); + + static QValueList<QVariant> toVariantList( const QVariant &arg ); + static QValueList<QVariant> toVariantList( int arg ); + static QValueList<QVariant> toVariantList( bool arg ); + static QValueList<QVariant> toVariantList( double arg ); + static QValueList<QVariant> toVariantList( const QString &arg ); + static QValueList<QVariant> toVariantList( const QCString &arg ); + static QValueList<QVariant> toVariantList( const QByteArray &arg ); + static QValueList<QVariant> toVariantList( const QDateTime &arg ); + static QValueList<QVariant> toVariantList( const QStringList &arg ); + + signals: + void infoMessage( const QString &msg ); + + public slots: + void call( const QString &method, const QValueList<QVariant> &args, + QObject *object, const char *slot ); + void call( const QString &method, const QValueList<QVariant> &args, + QObject *object, const char *slot, + QObject *infoObject, const char *infoSlot ); + + private: + KURL m_url; + QString m_userAgent; + }; + + inline QDataStream &operator>>( QDataStream &s, Query::Result &r ) + { + return s >> r.m_errorCode >> r.m_errorString >> r.m_data + >> r.m_server >> r.m_method >> r.m_args; + } +} + +template <typename T> +void KXMLRPC::Server::call( const QString &method, const QValueList<T> &arg, + QObject *object, const char *slot ) +{ + QValueList<QVariant> args; + + typename QValueList<T>::ConstIterator it = arg.begin(); + typename QValueList<T>::ConstIterator end = arg.end(); + for ( ; it != end; ++it ) + args << QVariant( *it ); + + call( method, args, object, slot ); +} + +inline QDataStream &operator<<( QDataStream &s, const KXMLRPC::Query::Result &r ) +{ + return s << r.errorCode() << r.errorString() << r.data() + << r.server() << r.method() << r.args(); +} + +#endif // KXMLRPCCLIENT_H +// vim:ts=4:sw=4:noet |