diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /knewstuff | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'knewstuff')
40 files changed, 5500 insertions, 0 deletions
diff --git a/knewstuff/Mainpage.dox b/knewstuff/Mainpage.dox new file mode 100644 index 000000000..ed863f4e2 --- /dev/null +++ b/knewstuff/Mainpage.dox @@ -0,0 +1,35 @@ +/** \mainpage Collaborative Data Sharing in KDE Applications + +The \b KNewStuff2 library adds data sharing capabilities to %KDE +applications. Technically, it implements the +<a href="http://ghns.freedesktop.org/">GHNS</a> and +DXS specifications. The library consists of three parts: the data management core +and GHNS protocol implementation, the DXS web service handler, and the user interface +classes like dialogs and buttons. + +Application authors should not use all of the classes directly, which are installed +only for the purpose of implementing functionality on top of \b KNewStuff2; instead, +the high-level KNS::Engine class provides everything an application needs. +Both upload and download scenarios are handled by the engine. There are only two +preparation steps necessary before this class can be used: the setup of a GHNS repository, +and the creation of a <b>*.knsrc</b> file which will determine all aspects of the +application's \b KNewStuff2 usage. + +All of the related information such as <b>*.knsrc</b> files, repositories and security +can be found in the <a href="http://techbase.kde.org/Development/Tutorials/K_Hot_New_Stuff2">KNewStuff2 tutorial</a>. + +@authors +Josef Spillner \<spillner@kde.org\> +Jeremy Whiting \<jeremy@scitools.com\> + +@maintainers +Jeremy Whiting \<jeremy@scitools.com\> + +@licenses +@lgpl + +*/ + +// DOXYGEN_REFERENCES = kdecore kdeui kio +// DOXYGEN_SET_PROJECT_NAME = KNewStuff +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/knewstuff/Makefile.am b/knewstuff/Makefile.am new file mode 100644 index 000000000..c3d4605f7 --- /dev/null +++ b/knewstuff/Makefile.am @@ -0,0 +1,41 @@ +INCLUDES = $(all_includes) + +METASOURCES = AUTO + +lib_LTLIBRARIES = libknewstuff.la + +libknewstuff_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -version-info 1:0 +libknewstuff_la_LIBADD = $(LIB_KIO) +libknewstuff_la_SOURCES = engine.cpp entry.cpp downloaddialog.cpp \ + uploaddialog.cpp providerdialog.cpp provider.cpp knewstuff.cpp \ + knewstuffgeneric.cpp knewstuffbutton.cpp knewstuffsecure.cpp security.cpp + +bin_PROGRAMS = khotnewstuff + +khotnewstuff_LDFLAGS = $(all_libraries) $(KDE_RPATH) +khotnewstuff_LDADD = libknewstuff.la +khotnewstuff_SOURCES = khotnewstuff.cpp + +EXTRA_PROGRAMS = testnewstuff ghns + +testnewstuff_LDFLAGS = $(all_libraries) $(KDE_RPATH) +testnewstuff_LDADD = libknewstuff.la +testnewstuff_SOURCES = testnewstuff.cpp + +ghns_LDFLAGS = $(all_libraries) $(KDE_RPATH) +ghns_LDADD = libknewstuff.la +ghns_SOURCES = ghns.cpp + +knewstuffdir = $(kde_datadir)/knewstuff +knewstuff_DATA = types + +kde_conf_DATA = khotnewstuffrc + +knsdir = $(includedir)/knewstuff +kns_HEADERS = downloaddialog.h engine.h entry.h knewstuffgeneric.h knewstuff.h providerdialog.h provider.h uploaddialog.h knewstuffbutton.h knewstuffsecure.h +noinst_HEADERS = testnewstuff.h ghns.h security.h + +KDE_ICON=AUTO + +include ../admin/Doxyfile.am + diff --git a/knewstuff/README.knewstuff b/knewstuff/README.knewstuff new file mode 100644 index 000000000..cdf4c79b3 --- /dev/null +++ b/knewstuff/README.knewstuff @@ -0,0 +1,50 @@ +KNewStuff library - application data sharing framework for KDE + +KNewStuff implements the "Get Hot New Stuff" (GHNS) architecture and +provides KDE applications with easy-to-use upload and download mechanisms, +with optional popularity counters, ratings, digital signatures, uncompression +and post-installation DCOP/scripting hooks. + +* GHNS Standard and related software + http://ghns.berlios.de/ + +* Documentation +- API docs + http://developer.kde.org/documentation/library/cvs-api/knewstuff/html/ +- KNewStuff tutorial + http://www.kstuff.org/docs/tutorial/ +- KNewStuffSecure tutorial + http://developer.kde.org/documentation/tutorials/knewstuffsecure/ + +* Repositories +Currently, about 7 repositories exist for a variety of KDE applications using +KNewStuff for either download or upload or both. +Please have a look at the repository browser: +-> http://www.kstuff.org/hotstuff/index.php?p=browser +If you want automatic upload processing, download counting and administration +capabilities, as well as a web frontend, check out the Hotstuff scripts: +-> http://www.kstuff.org/source/index.php?p=cvs +For testing, feel free to use the kstuff.org infrastructure, as it is up and +running 24x7. + +* Future +Immediate plans: +- merge download dialog engine functionality into the engine class +- incremental updates of directories, + including cache +- after installation, return QStringList of installed items so no scanning + will be necessary anymore +- how to "fake" installations? (suggestions from TSDgeos) + knewstuff should know about already installed items +Future plans: +- kick-ass web interface with history and contributions +- integration with KDE SOAP messaging framework and KWSDL to access DXS +- hm.... :-) + +Josef Spillner, 01.04.2004, last updated 07.06.2005 + +Add d pointers to ALL public classes for KDE 4 or maintaining binary +compatibility is a nightmare. 12/3/05. + +Rich. + diff --git a/knewstuff/cr16-action-knewstuff.png b/knewstuff/cr16-action-knewstuff.png Binary files differnew file mode 100644 index 000000000..ef5ea45e2 --- /dev/null +++ b/knewstuff/cr16-action-knewstuff.png diff --git a/knewstuff/cr32-action-knewstuff.png b/knewstuff/cr32-action-knewstuff.png Binary files differnew file mode 100644 index 000000000..757e92668 --- /dev/null +++ b/knewstuff/cr32-action-knewstuff.png diff --git a/knewstuff/cr64-action-knewstuff.png b/knewstuff/cr64-action-knewstuff.png Binary files differnew file mode 100644 index 000000000..ad6d5e566 --- /dev/null +++ b/knewstuff/cr64-action-knewstuff.png diff --git a/knewstuff/data/README b/knewstuff/data/README new file mode 100644 index 000000000..6e50ceb2c --- /dev/null +++ b/knewstuff/data/README @@ -0,0 +1,5 @@ +This directory contains example files for the providers list and the description +of downloadable entries. + +It also contains the DTDs for the XML files. You can check the XML files for +validity e.g with "xmllint <filename> --valid". diff --git a/knewstuff/data/knewstuff.dtd b/knewstuff/data/knewstuff.dtd new file mode 100644 index 000000000..b8f6ecd4e --- /dev/null +++ b/knewstuff/data/knewstuff.dtd @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!ELEMENT knewstuff (stuff*)> +<!ELEMENT stuff (name,author,licence,summary*,version,release,releasedate, + preview*,payload*,rating?,downloads?)> + <!ATTLIST stuff type CDATA #IMPLIED> + +<!ELEMENT name (#PCDATA)> + +<!ELEMENT author (#PCDATA)> + <!ATTLIST author email CDATA #REQUIRED> + +<!ELEMENT licence (#PCDATA)> + +<!ELEMENT summary (#PCDATA)> + <!ATTLIST summary lang CDATA #REQUIRED> + +<!ELEMENT version (#PCDATA)> + +<!ELEMENT release (#PCDATA)> + +<!ELEMENT releasedate (#PCDATA)> + +<!ELEMENT url (#PCDATA)> + +<!ELEMENT preview (#PCDATA)> + <!ATTLIST preview lang CDATA #REQUIRED> + +<!ELEMENT payload (#PCDATA)> + <!ATTLIST payload lang CDATA #REQUIRED> + +<!ELEMENT rating (#PCDATA)> + +<!ELEMENT downloads (#PCDATA)> diff --git a/knewstuff/data/knewstuff.xml b/knewstuff/data/knewstuff.xml new file mode 100644 index 000000000..f7ba326ec --- /dev/null +++ b/knewstuff/data/knewstuff.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE knewstuff SYSTEM "knewstuff.dtd"> +<knewstuff> + <stuff type="korganizer/calendar"> + <name>worldcup2002</name> + <author email="schumacher@kde.org">Cornelius Schumacher</author> + <licence>GPL</licence> + <summary lang="en">Soccer world cup 2002</summary> + <version>1.0</version> + <release>1</release> + <releasedate>2002-06-19</releasedate> + <preview lang="en"></preview> + <payload lang="en">http://korganizer.kde.org/knewstuff/korganizer/calendar/worldcup2002.ics</payload> + <rating>5</rating> + <downloads>0</downloads> + </stuff> +</knewstuff> diff --git a/knewstuff/data/knewstuffproviders.dtd b/knewstuff/data/knewstuffproviders.dtd new file mode 100644 index 000000000..aebbdb39e --- /dev/null +++ b/knewstuff/data/knewstuffproviders.dtd @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!ELEMENT knewstuffproviders (provider+)> + +<!ELEMENT provider (noupload?,title)> + <!ATTLIST provider downloadurl CDATA #REQUIRED> + <!ATTLIST provider uploadurl CDATA #REQUIRED> + <!ATTLIST provider nouploadurl CDATA #IMPLIED> + <!ATTLIST provider icon CDATA #IMPLIED> + <!ATTLIST provider webaccess CDATA #IMPLIED> + +<!ELEMENT noupload EMPTY> + +<!ELEMENT title (#PCDATA)> diff --git a/knewstuff/data/providers.xml b/knewstuff/data/providers.xml new file mode 100644 index 000000000..c76897a95 --- /dev/null +++ b/knewstuff/data/providers.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE knewstuffproviders SYSTEM "knewstuffproviders.dtd"> +<knewstuffproviders> + <provider downloadurl="http://korganizer.kde.org/knewstuff/korganizer/calendar/knewstuff.xml" + uploadurl="ftp://some.upload.server" + icon="korganizer" + webaccess="http://some.webfrontend.server"> + <title>KOrganizer Home Page</title> + </provider> +</knewstuffproviders> diff --git a/knewstuff/downloaddialog.cpp b/knewstuff/downloaddialog.cpp new file mode 100644 index 000000000..51028dfab --- /dev/null +++ b/knewstuff/downloaddialog.cpp @@ -0,0 +1,878 @@ +/* + This file is part of KNewStuff. + Copyright (c) 2003 Josef Spillner <spillner@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "downloaddialog.h" +#include "downloaddialog.moc" + +#include <klocale.h> +#include <klistview.h> +#include <kdebug.h> +#include <kio/job.h> +#include <kio/netaccess.h> +#include <kmessagebox.h> +#include <kurl.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kiconloader.h> + +#include <knewstuff/entry.h> +#include <knewstuff/knewstuffgeneric.h> +#include <knewstuff/engine.h> + +#include <qlayout.h> +#include <qpushbutton.h> +#include <qdom.h> +#include <qlabel.h> +#include <qtextbrowser.h> +#include <qtabwidget.h> +#include <qtimer.h> // hack + +using namespace KNS; + +struct DownloadDialog::Private +{ + QString m_providerlist; + QWidget *m_page; + KListView *m_lvtmp_r, *m_lvtmp_d, *m_lvtmp_l; + QPtrList<Entry> m_installlist; + QMap<KIO::Job*, Provider*> m_variantjobs; + QMap<KIO::Job*, QStringList> m_variants; + QMap<Provider*, Provider*> m_newproviders; +}; + +class NumSortListViewItem : public KListViewItem +{ + public: + NumSortListViewItem( QListView * parent, QString label1, QString label2 = QString::null, QString label3 = QString::null, QString label4 = QString::null, QString label5 = QString::null, QString label6 = QString::null, QString label7 = QString::null, QString label8 = QString::null ) : + KListViewItem( parent, label1, label2, label3, label4, label5, label6, label7, label8 ) + { + } + + QString key(int col, bool asc) const { + if (col == 2) + { + QString s; + s.sprintf("%08d", text(col).toInt()); + return s; + } + return KListViewItem::key( col, asc ); + } +}; + +class DateSortListViewItem : public KListViewItem +{ + public: + DateSortListViewItem( QListView * parent, QString label1, QString label2 = QString::null, QString label3 = QString::null, QString label4 = QString::null, QString label5 = QString::null, QString label6 = QString::null, QString label7 = QString::null, QString label8 = QString::null ) : + KListViewItem( parent, label1, label2, label3, label4, label5, label6, label7, label8 ) + { + } + + QString key(int col, bool asc) const { + if (col == 2) + { + QString s; + QDate date = KGlobal::locale()->readDate(text(col)); + s.sprintf("%08d", date.year() * 366 + date.dayOfYear()); + return s; + } + return KListViewItem::key( col, asc ); + } +}; + +// BEGIN deprecated for KDE 4 +DownloadDialog::DownloadDialog(Engine *engine, QWidget *) +: KDialogBase(KDialogBase::IconList, i18n("Get Hot New Stuff"), + KDialogBase::Close, KDialogBase::Close) +{ + init(engine); +} + +DownloadDialog::DownloadDialog(QWidget *) +: KDialogBase(KDialogBase::IconList, i18n("Get Hot New Stuff"), + KDialogBase::Close, KDialogBase::Close) +{ + init(0); +} + +void DownloadDialog::open(QString type) +{ + DownloadDialog d; + d.setType(type); + d.load(); + d.exec(); +} +// END deprecated for KDE 4 + +DownloadDialog::DownloadDialog(Engine *engine, QWidget *, const QString& caption) +: KDialogBase(KDialogBase::IconList, (caption.isNull() ? i18n("Get Hot New Stuff") : caption), + KDialogBase::Close, KDialogBase::Close) +{ + init(engine); +} + +DownloadDialog::DownloadDialog(QWidget *, const QString& caption) +: KDialogBase(KDialogBase::IconList, (caption.isNull() ? i18n("Get Hot New Stuff") : caption), + KDialogBase::Close, KDialogBase::Close) +{ + init(0); +} + +void DownloadDialog::init(Engine *engine) +{ + resize(700, 400); + d = new Private(); + + m_engine = engine; + d->m_page = NULL; + + connect(this, SIGNAL(aboutToShowPage(QWidget*)), SLOT(slotPage(QWidget*))); + + if(!engine) + { + m_loader = new ProviderLoader(this); + connect(m_loader, SIGNAL(providersLoaded(Provider::List*)), SLOT(slotProviders(Provider::List*))); + } + + m_entries.setAutoDelete(true); +} + +DownloadDialog::~DownloadDialog() +{ + for (QMap<QWidget *, QValueList<QPushButton *>* >::const_iterator it = m_buttons.constBegin(); it != m_buttons.constEnd(); ++it) + delete it.data(); + for (QMap<QWidget *, QValueList<KListView *>* >::const_iterator it = m_map.constBegin(); it != m_map.constEnd(); ++it) + delete it.data(); + delete d; +} + +void DownloadDialog::load() +{ + m_loader->load(m_filter, d->m_providerlist); +} + +void DownloadDialog::load(QString providerList) +{ + m_loader->load(m_filter, providerList); +} + +void DownloadDialog::clear() +{ + QMap<QWidget*, QValueList<KListView*>* >::Iterator it; + QMap<QWidget*, QValueList<KListView*>* >::Iterator end(m_map.end()); + for(it = m_map.begin(); it != end; ++it) + { + QValueList<KListView*> *v = it.data(); + kdDebug() << "clear listviews in " << v << endl; + if(v) + { + (*(v->at(0)))->clear(); + (*(v->at(1)))->clear(); + (*(v->at(2)))->clear(); + + //delete (*it); + } + + delete it.key(); + } + m_map.clear(); +} + +void DownloadDialog::slotProviders(Provider::List *list) +{ + Provider *p; + /*QFrame *frame;*/ + + for(p = list->first(); p; p = list->next()) + { + kdDebug() << "++ provider ++ " << p->name() << endl; + + if(!m_filter.isEmpty()) + loadProvider(p); + else + addProvider(p); + /*if(p == list->getFirst()) + slotPage(m_frame);*/ // only if !qtbug + } +} + +void DownloadDialog::addProvider(Provider *p) +{ + QFrame *frame; + QTabWidget *ctl; + QWidget *w_d, *w_r, *w_l; + QWidget *w2; + QTextBrowser *rt; + QString tmp; + int ret; + QPixmap pix; + + if(m_map.count() == 0) + { + frame = addPage(i18n("Welcome"), i18n("Welcome"), QPixmap("")); + delete frame; + } + + kdDebug() << "addProvider()/begin" << endl; + + ret = true; + if(p->icon().path().isEmpty()) ret = false; + else + { + if(!p->icon().protocol().isEmpty()) + { + ret = KIO::NetAccess::download(p->icon(), tmp, this); + if(ret) pix = QPixmap(tmp); + } + else + { + pix = KGlobal::iconLoader()->loadIcon(p->icon().path(), KIcon::Panel); + ret = true; + } + } + if(!ret) pix = KGlobal::iconLoader()->loadIcon("knewstuff", KIcon::Panel); + frame = addPage(p->name(), p->name(), pix); + m_frame = frame; + + w2 = new QWidget(frame); + w_d = new QWidget(frame); + w_r = new QWidget(frame); + w_l = new QWidget(frame); + + ctl = new QTabWidget(frame); + ctl->addTab(w_r, i18n("Highest Rated")); + ctl->addTab(w_d, i18n("Most Downloads")); + ctl->addTab(w_l, i18n("Latest")); + + m_curtab = 0; + connect(ctl, SIGNAL(currentChanged(QWidget *)), SLOT(slotTab())); + + QHBoxLayout *box = new QHBoxLayout(frame); + box->add(ctl); + + d->m_lvtmp_r = new KListView(w_r); + d->m_lvtmp_r->addColumn(i18n("Name")); + d->m_lvtmp_r->addColumn(i18n("Version")); + d->m_lvtmp_r->addColumn(i18n("Rating")); + d->m_lvtmp_r->setSorting(2, false); + + d->m_lvtmp_d = new KListView(w_d); + d->m_lvtmp_d->addColumn(i18n("Name")); + d->m_lvtmp_d->addColumn(i18n("Version")); + d->m_lvtmp_d->addColumn(i18n("Downloads")); + d->m_lvtmp_d->setSorting(2, false); + + d->m_lvtmp_l = new KListView(w_l); + d->m_lvtmp_l->addColumn(i18n("Name")); + d->m_lvtmp_l->addColumn(i18n("Version")); + d->m_lvtmp_l->addColumn(i18n("Release Date")); + d->m_lvtmp_l->setSorting(2, false); + + connect(d->m_lvtmp_r, SIGNAL(clicked(QListViewItem*)), SLOT(slotSelected())); + connect(d->m_lvtmp_d, SIGNAL(clicked(QListViewItem*)), SLOT(slotSelected())); + connect(d->m_lvtmp_l, SIGNAL(clicked(QListViewItem*)), SLOT(slotSelected())); + + rt = new QTextBrowser(frame); + rt->setMinimumWidth(150); + + QPushButton *in = new QPushButton(i18n("Install"), frame); + QPushButton *de = new QPushButton(i18n("Details"), frame); + in->setEnabled(false); + de->setEnabled(false); + + box->addSpacing(spacingHint()); + QVBoxLayout *vbox = new QVBoxLayout(box); + vbox->add(rt); + vbox->addSpacing(spacingHint()); + vbox->add(de); + vbox->add(in); + + connect(rt, SIGNAL(linkClicked(const QString&)), SLOT(slotEmail(const QString&))); + + connect(in, SIGNAL(clicked()), SLOT(slotInstall())); + connect(de, SIGNAL(clicked()), SLOT(slotDetails())); + + QVBoxLayout *box2 = new QVBoxLayout(w_r); + box2->add(d->m_lvtmp_r); + QVBoxLayout *box3 = new QVBoxLayout(w_d); + box3->add(d->m_lvtmp_d); + QVBoxLayout *box4 = new QVBoxLayout(w_l); + box4->add(d->m_lvtmp_l); + + QValueList<KListView*> *v = new QValueList<KListView*>; + *v << d->m_lvtmp_r << d->m_lvtmp_d << d->m_lvtmp_l; + m_map[frame] = v; + m_rts[frame] = rt; + QValueList<QPushButton*> *vb = new QValueList<QPushButton*>; + *vb << in << de; + m_buttons[frame] = vb; + m_providers[frame] = p; + + kdDebug() << "addProvider()/end; d->m_lvtmp_r = " << d->m_lvtmp_r << endl; + + if(m_engine) slotPage(frame); + + QTimer::singleShot(100, this, SLOT(slotFinish())); +} + +void DownloadDialog::slotResult(KIO::Job *job) +{ + QDomDocument dom; + QDomElement knewstuff; + + kdDebug() << "got data: " << m_data[job] << endl; + + kapp->config()->setGroup("KNewStuffStatus"); + + dom.setContent(m_data[job]); + knewstuff = dom.documentElement(); + + for(QDomNode pn = knewstuff.firstChild(); !pn.isNull(); pn = pn.nextSibling()) + { + QDomElement stuff = pn.toElement(); + + kdDebug() << "element: " << stuff.tagName() << endl; + + if(stuff.tagName() == "stuff") + { + Entry *entry = new Entry(stuff); + kdDebug() << "TYPE::" << entry->type() << " FILTER::" << m_filter << endl; + if(!entry->type().isEmpty()) + { + if((!m_filter.isEmpty()) && (entry->type() != m_filter)) continue; + } + + /*if((!m_filter.isEmpty()) && (m_jobs[job])) + { + Provider *p = m_jobs[job]; + if(d->m_newproviders[p]) + { + addProvider(p); + slotPage(m_frame); + d->m_newproviders[p] = 0; + } + }*/ + if((!m_filter.isEmpty()) && (d->m_variantjobs[job])) + { + Provider *p = d->m_variantjobs[job]; + if(d->m_newproviders[p]) + { + addProvider(p); + slotPage(m_frame); + d->m_newproviders[p] = 0; + } + } + + /*if(m_jobs[job]) addEntry(entry); + else*/ + if(d->m_variantjobs[job]) addEntry(entry, d->m_variants[job]); + } + } +} + +int DownloadDialog::installStatus(Entry *entry) +{ + QDate date; + QString datestring; + int installed; + + QString lang = KGlobal::locale()->language(); + + kapp->config()->setGroup("KNewStuffStatus"); + datestring = kapp->config()->readEntry(entry->name(lang)); + if(datestring.isNull()) installed = 0; + else + { + date = QDate::fromString(datestring, Qt::ISODate); + if(!date.isValid()) installed = 0; + else if(date < entry->releaseDate()) installed = -1; + else installed = 1; + } + + return installed; +} + +void DownloadDialog::addEntry(Entry *entry, const QStringList& variants) +{ + QPixmap pix; + int installed; + + installed = installStatus(entry); + + if(installed > 0) pix = KGlobal::iconLoader()->loadIcon("ok", KIcon::Small); + else if(installed < 0) pix = KGlobal::iconLoader()->loadIcon("history", KIcon::Small); + else pix = QPixmap(); + + QString lang = KGlobal::locale()->language(); + + if(variants.contains("score")) + { + KListViewItem *tmp_r = new NumSortListViewItem(lv_r, + entry->name(lang), entry->version(), QString("%1").arg(entry->rating())); + tmp_r->setPixmap(0, pix); + } + if(variants.contains("downloads")) + { + KListViewItem *tmp_d = new NumSortListViewItem(lv_d, + entry->name(lang), entry->version(), QString("%1").arg(entry->downloads())); + tmp_d->setPixmap(0, pix); + } + if(variants.contains("latest")) + { + KListViewItem *tmp_l = new DateSortListViewItem(lv_l, + entry->name(lang), entry->version(), KGlobal::locale()->formatDate(entry->releaseDate())); + tmp_l->setPixmap(0, pix); + } + + m_entries.append(entry); + + kdDebug() << "added entry " << entry->name() << " for variants " << variants << endl; +} + +void DownloadDialog::addEntry(Entry *entry) +{ + QStringList variants; + + variants << "score"; + variants << "downloads"; + variants << "latest"; + + addEntry(entry, variants); + + // not used anymore due to variants (but still used by engine) + kdDebug() << "added entry " << entry->name() << endl; +} + +void DownloadDialog::slotData(KIO::Job *job, const QByteArray &a) +{ + QCString tmp(a, a.size() + 1); + m_data[job].append(QString::fromUtf8(tmp)); +} + +void DownloadDialog::slotDetails() +{ + Entry *e = getEntry(); + if(!e) return; + + QString lang = KGlobal::locale()->language(); + + QString info = i18n + ( + "Name: %1\n" + "Author: %2\n" + "License: %3\n" + "Version: %4\n" + "Release: %5\n" + "Rating: %6\n" + "Downloads: %7\n" + "Release date: %8\n" + "Summary: %9\n" + ).arg(e->name(lang) + ).arg(e->author() + ).arg(e->license() + ).arg(e->version() + ).arg(e->release() + ).arg(e->rating() + ).arg(e->downloads() + ).arg(KGlobal::locale()->formatDate(e->releaseDate()) + ).arg(e->summary(lang) + ); + + info.append(i18n + ( + "Preview: %1\n" + "Payload: %2\n" + ).arg(e->preview().url() + ).arg(e->payload().url() + )); + + KMessageBox::information(this, info, i18n("Details")); +} + +QListViewItem *DownloadDialog::currentEntryItem() +{ + if((m_curtab == 0) && (lv_r->selectedItem())) return lv_r->selectedItem(); + if((m_curtab == 1) && (lv_d->selectedItem())) return lv_d->selectedItem(); + if((m_curtab == 2) && (lv_l->selectedItem())) return lv_l->selectedItem(); + + return 0; +} + +void DownloadDialog::slotInstall() +{ + Entry *e = getEntry(); + if(!e) return; + + d->m_lvtmp_r->setEnabled( false ); + d->m_lvtmp_l->setEnabled( false ); + d->m_lvtmp_d->setEnabled( false ); + m_entryitem = currentEntryItem(); + m_entryname = m_entryitem->text(0); + + kdDebug() << "download entry now" << endl; + + if(m_engine) + { + m_engine->download(e); + install(e); + } + else + { + m_s = new KNewStuffGeneric(e->type(), this); + m_entry = e; + KURL source = e->payload(); + KURL dest = KURL(m_s->downloadDestination(e)); + + KIO::FileCopyJob *job = KIO::file_copy(source, dest, -1, true); + connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotInstalled(KIO::Job*))); + } +} + +void DownloadDialog::install(Entry *e) +{ + kapp->config()->setGroup("KNewStuffStatus"); + kapp->config()->writeEntry(m_entryname, e->releaseDate().toString(Qt::ISODate)); + kapp->config()->sync(); + + QPixmap pix = KGlobal::iconLoader()->loadIcon("ok", KIcon::Small); + + QString lang = KGlobal::locale()->language(); + + if(m_entryitem) + { + m_entryitem->setPixmap(0, pix); + + QListViewItem *item; + item = lv_r->findItem(e->name(lang), 0); + if(item) item->setPixmap(0, pix); + item = lv_d->findItem(e->name(lang), 0); + if(item) item->setPixmap(0, pix); + item = lv_l->findItem(e->name(lang), 0); + if(item) item->setPixmap(0, pix); + } + + if(currentEntryItem() == m_entryitem) + { + QPushButton *in; + in = *(m_buttons[d->m_page]->at(0)); + if(in) in->setEnabled(false); + } + + d->m_installlist.append(e); + d->m_lvtmp_r->setEnabled( true ); + d->m_lvtmp_l->setEnabled( true ); + d->m_lvtmp_d->setEnabled( true ); +} + +void DownloadDialog::slotInstalled(KIO::Job *job) +{ + bool ret = job && (job->error() == 0); + if(ret) + { + KIO::FileCopyJob *cjob = ::qt_cast<KIO::FileCopyJob*>(job); + if(cjob) + { + ret = m_s->install(cjob->destURL().path()); + } + else ret = false; + } + + if(ret) + { + install(m_entry); + + KMessageBox::information(this, i18n("Installation successful."), i18n("Installation")); + } + else KMessageBox::error(this, i18n("Installation failed."), i18n("Installation")); + d->m_lvtmp_r->setEnabled( true ); + d->m_lvtmp_l->setEnabled( true ); + d->m_lvtmp_d->setEnabled( true ); + + delete m_s; +} + +void DownloadDialog::slotTab() +{ + int tab = static_cast<const QTabWidget *>(sender())->currentPageIndex(); + kdDebug() << "switch tab to: " << tab << endl; + + Entry *eold = getEntry(); + m_curtab = tab; + Entry *e = getEntry(); + + if(e == eold) return; + + if(e) + { + slotSelected(); + } + else + { + QPushButton *de, *in; + in = *(m_buttons[d->m_page]->at(0)); + de = *(m_buttons[d->m_page]->at(1)); + + if(in) in->setEnabled(false); + if(de) de->setEnabled(false); + + m_rt->clear(); + } +} + +void DownloadDialog::slotSelected() +{ + QString tmp; + bool enabled; + Entry *e = getEntry(); + QString lang = KGlobal::locale()->language(); + bool ret; + + if(e) + { + QString lang = KGlobal::locale()->language(); + + QListViewItem *item; + if(m_curtab != 0) + { + lv_r->clearSelection(); + item = lv_r->findItem(e->name(lang), 0); + if(item) lv_r->setSelected(item, true); + } + if(m_curtab != 1) + { + lv_d->clearSelection(); + item = lv_d->findItem(e->name(lang), 0); + if(item) lv_d->setSelected(item, true); + } + if(m_curtab != 2) + { + lv_l->clearSelection(); + item = lv_l->findItem(e->name(lang), 0); + if(item) lv_l->setSelected(item, true); + } + + if(!e->preview(lang).isValid()) + { + ret = 0; + } + else + { + ret = KIO::NetAccess::download(e->preview(lang), tmp, this); + } + + QString desc = QString("<b>%1</b><br>").arg(e->name(lang)); + if(!e->authorEmail().isNull()) + { + desc += QString("<a href='mailto:" + e->authorEmail() + "'>" + e->author() + "</a>"); + } + else + { + desc += QString("%1").arg(e->author()); + } + desc += QString("<br>%1").arg(KGlobal::locale()->formatDate(e->releaseDate())); + desc += QString("<br><br>"); + if(ret) + { + desc += QString("<img src='%1'>").arg(tmp); + } + else + { + desc += i18n("Preview not available."); + } + desc += QString("<br><i>%1</i>").arg(e->summary(lang)); + desc += QString("<br>(%1)").arg(e->license()); + + m_rt->clear(); + m_rt->setText(desc); + + if(installStatus(e) == 1) enabled = false; + else enabled = true; + + QPushButton *de, *in; + in = *(m_buttons[d->m_page]->at(0)); + de = *(m_buttons[d->m_page]->at(1)); + if(in) in->setEnabled(enabled); + if(de) de->setEnabled(true); + } +} + +void DownloadDialog::slotEmail(const QString& link) +{ + kdDebug() << "EMAIL: " << link << endl; + kapp->invokeMailer(link); + slotSelected(); // QTextBrowser oddity workaround as it cannot handle mailto: URLs +} + +Entry *DownloadDialog::getEntry() +{ + QListViewItem *entryItem = currentEntryItem(); + + if(!entryItem) + return 0; + + QString entryName = entryItem->text(0); + + QString lang = KGlobal::locale()->language(); + + for(Entry *e = m_entries.first(); e; e = m_entries.next()) + if(e->name(lang) == entryName) + return e; + + return 0; +} + +void DownloadDialog::slotPage(QWidget *w) +{ + Provider *p; + + kdDebug() << "changed widget!!!" << endl; + + if(m_map.find(w) == m_map.end()) return; + + d->m_page = w; + + lv_r = *(m_map[w]->at(0)); + lv_d = *(m_map[w]->at(1)); + lv_l = *(m_map[w]->at(2)); + p = m_providers[w]; + m_rt = m_rts[w]; + + kdDebug() << "valid change!!!; lv_r = " << lv_r << endl; + + if(m_engine) return; + + if(!m_filter.isEmpty()) return; + + lv_r->clear(); + lv_d->clear(); + lv_l->clear(); + + kdDebug() << "-- fetch -- " << p->downloadUrl() << endl; + + loadProvider(p); +} + +void DownloadDialog::loadProvider(Provider *p) +{ + QMap<KIO::Job*, Provider*>::Iterator it; + + for(it = d->m_variantjobs.begin(); it != d->m_variantjobs.end(); it++) + { + if(it.data() == p) + { + kdDebug() << "-- found provider data in cache" << endl; + slotResult(it.key()); + return; + } + } + + QStringList variants; + variants << "score"; + variants << "downloads"; + variants << "latest"; + + // Optimise URLs so each unique URL only gets fetched once + + QMap<QString, QStringList> urls; + + for(QStringList::Iterator it = variants.begin(); it != variants.end(); it++) + { + QString url = p->downloadUrlVariant((*it)).url(); + if(!urls.contains(url)) + { + urls[url] = QStringList(); + } + urls[url] << (*it); + + it = variants.remove(it); + } + + // Now fetch the URLs while keeping the variant list for each attached + + for(QMap<QString, QStringList>::Iterator it = urls.begin(); it != urls.end(); it++) + { + QString url = it.key(); + QStringList urlvariants = it.data(); + + KIO::TransferJob *variantjob = KIO::get(url); + d->m_newproviders[p] = p; + d->m_variantjobs[variantjob] = p; + d->m_variants[variantjob] = urlvariants; + m_data[variantjob] = ""; + + connect(variantjob, SIGNAL(result(KIO::Job*)), SLOT(slotResult(KIO::Job*))); + connect(variantjob, SIGNAL(data(KIO::Job*, const QByteArray&)), + SLOT(slotData(KIO::Job*, const QByteArray&))); + } + + if(variants.count() == 0) return; + + // If not all variants are given, use default URL for those + + kdDebug() << "-- reached old downloadurl section; variants left: " << variants.count() << endl; + + KIO::TransferJob *job = KIO::get(p->downloadUrl()); + + d->m_newproviders[p] = p; + d->m_variantjobs[job] = p; + d->m_variants[job] = variants; + //m_jobs[job] = p; // not used anymore due to variants + m_data[job] = ""; + + connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotResult(KIO::Job*))); + connect(job, SIGNAL(data(KIO::Job*, const QByteArray&)), + SLOT(slotData(KIO::Job*, const QByteArray&))); +} + +void DownloadDialog::setType(QString type) +{ + m_filter = type; +} + +void DownloadDialog::setProviderList(const QString& providerList) +{ + d->m_providerlist = providerList; +} + +void DownloadDialog::slotOk() +{ +} + +void DownloadDialog::slotApply() +{ +} + +void DownloadDialog::open(const QString& type, const QString& caption) +{ + DownloadDialog d(0, caption); + d.setType(type); + d.load(); + d.exec(); +} + +void DownloadDialog::slotFinish() +{ + showPage(1); + //updateBackground(); +} + +QPtrList<Entry> DownloadDialog::installedEntries() +{ + return d->m_installlist; +} diff --git a/knewstuff/downloaddialog.h b/knewstuff/downloaddialog.h new file mode 100644 index 000000000..dd9d6dae4 --- /dev/null +++ b/knewstuff/downloaddialog.h @@ -0,0 +1,257 @@ +/* + This file is part of KNewStuff. + Copyright (c) 2003 Josef Spillner <spillner@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFF_DOWNLOADDIALOG_H +#define KNEWSTUFF_DOWNLOADDIALOG_H + +#include <kdialogbase.h> +#include <knewstuff/provider.h> + +namespace KIO +{ + class Job; +} + +class KListView; +class QTextBrowser; +class QFrame; +class KNewStuffGeneric; + +namespace KNS +{ + +class ProviderLoader; +class Entry; +class Provider; +class Engine; + +/** + * @short Common download dialog for data browsing and installation. + * + * It provides an easy-to-use convenience method named open() which does all + * the work, unless a more complex operation is needed. + * \code + * KNewStuff::DownloadDialog::open("kdesktop/wallpapers"); + * \endcode + * + * @author Josef Spillner (spillner@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + */ +class KDE_EXPORT DownloadDialog : public KDialogBase +{ + Q_OBJECT + struct Private; + public: + /** + Constructor. + + @param engine a pre-built engine object, or NULL if the download + dialog should create an engine on its own + @param parent the parent window + @param caption the dialog caption + */ + DownloadDialog(Engine *engine, QWidget *parent, const QString& caption); + + /** + Alternative constructor. + Always uses an internal engine. + + @param parent the parent window + @param caption the dialog caption + */ + DownloadDialog(QWidget *parent, const QString& caption); + + /** + Destructor. + */ + ~DownloadDialog(); + + /** + Restricts the display of available data to a certain data type. + + @param type a Hotstuff data type such as "korganizer/calendar" + */ + void setType(QString type); + // ### KDE 4.0: use const QString& + + /** + Fetches descriptions of all available data, optionally considering + a previously set type. + */ + void load(); + + /** + Explicitly uses this provider list instead of the one read from + the application configuration. + + @param providerList the URL of the provider list + + @since 3.4 + */ + void setProviderList(const QString& providerList); + + /** + Fetches descriptions of all available data, optionally considering + a previously set type. + + @param providerList the URl to the list of providers; if empty + we first try the ProvidersUrl from KGlobal::config, then we + fall back to a hardcoded value. + */ + void load(QString providerList); // KDE4: merge with load() above + + /** + Adds another provider to the download dialog. + This is normally done internally. + + @param p the Hotstuff provider to be added + */ + void addProvider(Provider *p); + + /** + Adds an additional entry to the current provider. + This is normally done internally. + + @param entry a Hotstuff data entry to be added + */ + void addEntry(Entry *entry); + + /** + Adds an additional entry to the current provider. + This is normally done internal. + This version takes into accounts the download variant. + + @param entry a Hotstuff data entry to be added + @param variants all variants this entry is intended for + */ + void addEntry(Entry *entry, const QStringList& variants); + + /** + Clears the entry list of the current provider. + This is normally done internally. + */ + void clear(); + + /** + Constructor. + + @param engine a pre-built engine object, or NULL if the download + dialog should create an engine on its own + @param parent the parent window + */ + DownloadDialog(Engine *engine, QWidget *parent = 0); + // ### KDE 4.0: remove and make caption/parent argument optional + + /** + Alternative constructor. + Always uses an internal engine. + + @param parent the parent window + */ + DownloadDialog(QWidget *parent = 0); + // ### KDE 4.0: remove and make caption/parent argument optional + + /** + Opens the download dialog. + This is a convenience method which automatically sets up the dialog. + @see setType() + @see load() + + @param type a data type such as "korganizer/calendar" + @param caption the dialog caption + */ + static void open(const QString& type, const QString& caption); + + /** + Opens the download dialog. + This is a convenience method which automatically sets up the dialog. + @see setType() + @see load() + + @param type a data type such as "korganizer/calendar" + @deprecated use open( const QString& type, const QString& caption ); + */ + static void open(QString type) KDE_DEPRECATED; // ### KDE 4.0: remove and make caption/parent argument optional + + /** + Returns the list of installed data entries. + + @return list of data entries which have been installed + */ + QPtrList<Entry> installedEntries(); + // ### KDE 4.0: the open() method should return this + + public slots: + /** + Availability of the provider list. + + @param list list of Hotstuff providers + */ + void slotProviders(Provider::List *list); + + protected slots: + void slotApply(); + void slotOk(); + + private slots: + void slotResult(KIO::Job *job); + void slotData(KIO::Job *job, const QByteArray &a); + void slotInstall(); + void slotDetails(); + void slotInstalled(KIO::Job *job); + void slotTab(); + void slotSelected(); + void slotPage(QWidget *w); + void slotFinish(); + void slotEmail(const QString& link); + + private: + void init(Engine *e); + Entry *getEntry(); + void loadProvider(Provider *p); + void install(Entry *e); + int installStatus(Entry *e); + QListViewItem *currentEntryItem(); + + ProviderLoader *m_loader; + QString m_entryname; + KListView *lv_r, *lv_d, *lv_l; + QTextBrowser *m_rt; + QFrame *m_frame; + QListViewItem *m_entryitem; + QPtrList<Entry> m_entries; + Entry *m_entry; + KNewStuffGeneric *m_s; + int m_curtab; + QMap<QWidget*, QValueList<KListView*>* > m_map; + QMap<QWidget*, Provider*> m_providers; + QMap<QWidget*, QTextBrowser*> m_rts; + QMap<QWidget*, QValueList<QPushButton*>* > m_buttons; + QMap<KIO::Job*, Provider*> m_jobs; + QMap<KIO::Job*, QString> m_data; + QString m_filter; + Engine *m_engine; + Private *d; +}; + +} + +#endif + diff --git a/knewstuff/engine.cpp b/knewstuff/engine.cpp new file mode 100644 index 000000000..4feda926c --- /dev/null +++ b/knewstuff/engine.cpp @@ -0,0 +1,428 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qcstring.h> +#include <qdom.h> +#include <qfileinfo.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kio/job.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> + +#include "knewstuff.h" +#include "downloaddialog.h" +#include "uploaddialog.h" +#include "providerdialog.h" + +#include "engine.h" +#include "engine.moc" + +using namespace KNS; + +struct Engine::Private +{ + bool mIgnoreInstallResult; + KNewStuff *mNewStuff; +}; + +Engine::Engine( KNewStuff *newStuff, const QString &type, + QWidget *parentWidget ) : + mParentWidget( parentWidget ), mDownloadDialog( 0 ), + mUploadDialog( 0 ), mProviderDialog( 0 ), mUploadProvider( 0 ), + d(new Private), mType( type ) +{ + d->mNewStuff = newStuff; + d->mIgnoreInstallResult = false; + mProviderLoader = new ProviderLoader( mParentWidget ); +} + +Engine::Engine( KNewStuff *newStuff, const QString &type, + const QString &providerList, QWidget *parentWidget ) : + mParentWidget( parentWidget ), + mDownloadDialog( 0 ), mUploadDialog( 0 ), + mProviderDialog( 0 ), mUploadProvider( 0 ), + mProviderList( providerList ), d(new Private), + mType( type ) +{ + d->mNewStuff = newStuff; + d->mIgnoreInstallResult = false; + mProviderLoader = new ProviderLoader( mParentWidget ); +} + +Engine::~Engine() +{ + delete d; + delete mProviderLoader; + + delete mUploadDialog; + delete mDownloadDialog; +} + +void Engine::download() +{ + kdDebug() << "Engine::download()" << endl; + + connect( mProviderLoader, + SIGNAL( providersLoaded( Provider::List * ) ), + SLOT( getMetaInformation( Provider::List * ) ) ); + mProviderLoader->load( mType, mProviderList ); +} + +void Engine::getMetaInformation( Provider::List *providers ) +{ + mProviderLoader->disconnect(); + + mNewStuffJobData.clear(); + + if ( !mDownloadDialog ) { + mDownloadDialog = new DownloadDialog( this, mParentWidget ); + mDownloadDialog->show(); + } + mDownloadDialog->clear(); + + Provider *p; + for ( p = providers->first(); p; p = providers->next() ) { + if ( p->downloadUrl().isEmpty() ) continue; + + KIO::TransferJob *job = KIO::get( p->downloadUrl(), false, false ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotNewStuffJobResult( KIO::Job * ) ) ); + connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ), + SLOT( slotNewStuffJobData( KIO::Job *, const QByteArray & ) ) ); + + mNewStuffJobData.insert( job, "" ); + mProviderJobs[ job ] = p; + } +} + +void Engine::slotNewStuffJobData( KIO::Job *job, const QByteArray &data ) +{ + if ( data.isEmpty() ) return; + + kdDebug() << "Engine:slotNewStuffJobData()" << endl; + + QCString str( data, data.size() + 1 ); + + mNewStuffJobData[ job ].append( QString::fromUtf8( str ) ); +} + +void Engine::slotNewStuffJobResult( KIO::Job *job ) +{ + if ( job->error() ) { + kdDebug() << "Error downloading new stuff descriptions." << endl; + job->showErrorDialog( mParentWidget ); + } else { + QString knewstuffDoc = mNewStuffJobData[ job ]; + + kdDebug() << "---START---" << endl << knewstuffDoc << "---END---" << endl; + + mDownloadDialog->addProvider( mProviderJobs[ job ] ); + + QDomDocument doc; + if ( !doc.setContent( knewstuffDoc ) ) { + kdDebug() << "Error parsing knewstuff.xml." << endl; + return; + } else { + QDomElement knewstuff = doc.documentElement(); + + if ( knewstuff.isNull() ) { + kdDebug() << "No document in knewstuffproviders.xml." << endl; + } else { + QDomNode p; + for ( p = knewstuff.firstChild(); !p.isNull(); p = p.nextSibling() ) { + QDomElement stuff = p.toElement(); + if ( stuff.tagName() != "stuff" ) continue; + if ( stuff.attribute("type", mType) != mType ) continue; + + Entry *entry = new Entry( stuff ); + + mDownloadDialog->show(); + + mDownloadDialog->addEntry( entry ); + + kdDebug() << "KNEWSTUFF: " << entry->name() << endl; + + kdDebug() << " SUMMARY: " << entry->summary() << endl; + kdDebug() << " VERSION: " << entry->version() << endl; + kdDebug() << " RELEASEDATE: " << entry->releaseDate().toString() << endl; + kdDebug() << " RATING: " << entry->rating() << endl; + + kdDebug() << " LANGS: " << entry->langs().join(", ") << endl; + } + } + } + } + + mNewStuffJobData.remove( job ); + mProviderJobs.remove( job ); + + if ( mNewStuffJobData.count() == 0 ) { + mDownloadDialog->show(); + mDownloadDialog->raise(); + } +} + +void Engine::download( Entry *entry ) +{ + kdDebug() << "Engine::download(entry)" << endl; + + KURL source = entry->payload(); + mDownloadDestination = d->mNewStuff->downloadDestination( entry ); + + if ( mDownloadDestination.isEmpty() ) { + kdDebug() << "Empty downloadDestination. Cancelling download." << endl; + return; + } + + KURL destination = KURL( mDownloadDestination ); + + kdDebug() << " SOURCE: " << source.url() << endl; + kdDebug() << " DESTINATION: " << destination.url() << endl; + + KIO::FileCopyJob *job = KIO::file_copy( source, destination, -1, true ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotDownloadJobResult( KIO::Job * ) ) ); +} + +void Engine::slotDownloadJobResult( KIO::Job *job ) +{ + if ( job->error() ) { + kdDebug() << "Error downloading new stuff payload." << endl; + job->showErrorDialog( mParentWidget ); + return; + } + + if ( d->mNewStuff->install( mDownloadDestination ) ) { + if ( !d->mIgnoreInstallResult ) { + KMessageBox::information( mParentWidget, + i18n("Successfully installed hot new stuff.") ); + } + } else + if ( !d->mIgnoreInstallResult ){ + KMessageBox::error( mParentWidget, + i18n("Failed to install hot new stuff.") ); + } +} + +void Engine::upload(const QString &fileName, const QString &previewName ) +{ + mUploadFile = fileName; + mPreviewFile = previewName; + + connect( mProviderLoader, + SIGNAL( providersLoaded( Provider::List * ) ), + SLOT( selectUploadProvider( Provider::List * ) ) ); + mProviderLoader->load( mType ); +} + +void Engine::selectUploadProvider( Provider::List *providers ) +{ + kdDebug() << "Engine:selectUploadProvider()" << endl; + + mProviderLoader->disconnect(); + + if ( !mProviderDialog ) { + mProviderDialog = new ProviderDialog( this, mParentWidget ); + } + + mProviderDialog->clear(); + + mProviderDialog->show(); + mProviderDialog->raise(); + + for( Provider *p = providers->first(); p; p = providers->next() ) { + mProviderDialog->addProvider( p ); + } +} + +void Engine::requestMetaInformation( Provider *provider ) +{ + mUploadProvider = provider; + + if ( !mUploadDialog ) { + mUploadDialog = new UploadDialog( this, mParentWidget ); + } + mUploadDialog->setPreviewFile( mPreviewFile ); + mUploadDialog->setPayloadFile( mUploadFile ); + mUploadDialog->show(); + mUploadDialog->raise(); +} + +void Engine::upload( Entry *entry ) +{ + if ( mUploadFile.isNull()) { + mUploadFile = entry->fullName(); + mUploadFile = locateLocal( "data", QString(kapp->instanceName()) + "/upload/" + mUploadFile ); + + if ( !d->mNewStuff->createUploadFile( mUploadFile ) ) { + KMessageBox::error( mParentWidget, i18n("Unable to create file to upload.") ); + emit uploadFinished( false ); + return; + } + } + + QString lang = entry->langs().first(); + QFileInfo fi( mUploadFile ); + entry->setPayload( KURL::fromPathOrURL( fi.fileName() ), lang ); + + if ( !createMetaFile( entry ) ) { + emit uploadFinished( false ); + return; + } + + QString text = i18n("The files to be uploaded have been created at:\n"); + text.append( i18n("Data file: %1\n").arg( mUploadFile) ); + if (!mPreviewFile.isEmpty()) { + text.append( i18n("Preview image: %1\n").arg( mPreviewFile) ); + } + text.append( i18n("Content information: %1\n").arg( mUploadMetaFile) ); + text.append( i18n("Those files can now be uploaded.\n") ); + text.append( i18n("Beware that any people might have access to them at any time.") ); + + QString caption = i18n("Upload Files"); + + if ( mUploadProvider->noUpload() ) { + KURL noUploadUrl = mUploadProvider->noUploadUrl(); + if ( noUploadUrl.isEmpty() ) { + text.append( i18n("Please upload the files manually.") ); + KMessageBox::information( mParentWidget, text, caption ); + } else { + int result = KMessageBox::questionYesNo( mParentWidget, text, caption, + i18n("Upload Info"), + KStdGuiItem::close() ); + if ( result == KMessageBox::Yes ) { + kapp->invokeBrowser( noUploadUrl.url() ); + } + } + } else { + int result = KMessageBox::questionYesNo( mParentWidget, text, caption, + i18n("&Upload"), KStdGuiItem::cancel() ); + if ( result == KMessageBox::Yes ) { + KURL destination = mUploadProvider->uploadUrl(); + destination.setFileName( fi.fileName() ); + + KIO::FileCopyJob *job = KIO::file_copy( KURL::fromPathOrURL( mUploadFile ), destination ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotUploadPayloadJobResult( KIO::Job * ) ) ); + } else { + emit uploadFinished( false ); + } + } +} + +bool Engine::createMetaFile( Entry *entry ) +{ + QDomDocument doc("knewstuff"); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + QDomElement de = doc.createElement("knewstuff"); + doc.appendChild( de ); + + entry->setType(type()); + de.appendChild( entry->createDomElement( doc, de ) ); + + kdDebug() << "--DOM START--" << endl << doc.toString() + << "--DOM_END--" << endl; + + if ( mUploadMetaFile.isNull() ) { + mUploadMetaFile = entry->fullName() + ".meta"; + mUploadMetaFile = locateLocal( "data", QString(kapp->instanceName()) + "/upload/" + mUploadMetaFile ); + } + + QFile f( mUploadMetaFile ); + if ( !f.open( IO_WriteOnly ) ) { + mUploadMetaFile = QString::null; + return false; + } + + QTextStream ts( &f ); + ts.setEncoding( QTextStream::UnicodeUTF8 ); + ts << doc.toString(); + + f.close(); + + return true; +} + +void Engine::slotUploadPayloadJobResult( KIO::Job *job ) +{ + if ( job->error() ) { + kdDebug() << "Error uploading new stuff payload." << endl; + job->showErrorDialog( mParentWidget ); + emit uploadFinished( false ); + return; + } + + if (mPreviewFile.isEmpty()) { + slotUploadPreviewJobResult(job); + return; + } + + QFileInfo fi( mPreviewFile ); + + KURL previewDestination = mUploadProvider->uploadUrl(); + previewDestination.setFileName( fi.fileName() ); + + KIO::FileCopyJob *newJob = KIO::file_copy( KURL::fromPathOrURL( mPreviewFile ), previewDestination ); + connect( newJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotUploadPreviewJobResult( KIO::Job * ) ) ); +} + +void Engine::slotUploadPreviewJobResult( KIO::Job *job ) +{ + if ( job->error() ) { + kdDebug() << "Error uploading new stuff preview." << endl; + job->showErrorDialog( mParentWidget ); + emit uploadFinished( true ); + return; + } + + QFileInfo fi( mUploadMetaFile ); + + KURL metaDestination = mUploadProvider->uploadUrl(); + metaDestination.setFileName( fi.fileName() ); + + KIO::FileCopyJob *newJob = KIO::file_copy( KURL::fromPathOrURL( mUploadMetaFile ), metaDestination ); + connect( newJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotUploadMetaJobResult( KIO::Job * ) ) ); +} + +void Engine::slotUploadMetaJobResult( KIO::Job *job ) +{ + mUploadMetaFile = QString::null; + if ( job->error() ) { + kdDebug() << "Error uploading new stuff metadata." << endl; + job->showErrorDialog( mParentWidget ); + emit uploadFinished( false ); + return; + } + + KMessageBox::information( mParentWidget, + i18n("Successfully uploaded new stuff.") ); + emit uploadFinished( true ); +} + +void Engine::ignoreInstallResult(bool ignore) +{ + d->mIgnoreInstallResult = ignore; +} diff --git a/knewstuff/engine.h b/knewstuff/engine.h new file mode 100644 index 000000000..0d4941095 --- /dev/null +++ b/knewstuff/engine.h @@ -0,0 +1,188 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFF_ENGINE_H +#define KNEWSTUFF_ENGINE_H + +#include <qmap.h> +#include <qobject.h> +#include <qstring.h> + +#include "entry.h" +#include "provider.h" + +namespace KIO { class Job; } + +class KNewStuff; + +namespace KNS { + +class DownloadDialog; +class UploadDialog; +class ProviderDialog; + +/** + * @short Central class combining all possible KNewStuff operations. + * + * In most cases, Engine objects are built and used internally. + * Using this class explicitely does however give fine-grained control about the + * upload and download operations. + * + * @author Cornelius Schumacher (schumacher@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + */ +class KDE_EXPORT Engine : public QObject +{ + Q_OBJECT + struct Private; + public: + /** + Constructor. + + @param newStuff a KNewStuff object + @param type the Hotstuff data type such as "korganizer/calendar" + @param parentWidget the parent window + */ + Engine( KNewStuff *newStuff, const QString &type, QWidget *parentWidget = 0 ); + /** + Constructor. + + @param newStuff a KNewStuff object + @param type the Hotstuff data type such as "korganizer/calendar" + @param providerList the URL of the provider list + @param parentWidget the parent window + */ + Engine( KNewStuff *newStuff, const QString &type, const QString &providerList, QWidget *parentWidget = 0 ); + + /** + Destructor. + */ + virtual ~Engine(); + + /** + Returns the previously set data type. + + @return the Hotstuff data type + */ + QString type() const { return mType; } + + /** + Returns the previously set parent widget. + + @return parent widget + */ + QWidget *parentWidget() const { return mParentWidget; } + + /** + Initiates the download process, retrieving provider lists and invoking + the download dialog. + */ + void download(); + + /** + Initiates the upload process, invoking the provider selection dialog + and the file upload dialog. + + @param fileName name of the payload data file + @param previewName name of the preview image file + */ + void upload( const QString &fileName = QString::null, const QString &previewName = QString::null ); + + /** + Downloads the specified data file. + + @param entry the Hotstuff data object to be downloaded + */ + void download( Entry *entry ); + + /** + Asynchronous lookup of provider information such as upload and + download locations, icon etc. + + @param provider the Hotstuff provider to request information from + */ + void requestMetaInformation( Provider *provider ); + + /** + Uploads the specified data file to the provider-dependent location. + + @param entry the Hotstuff data object to be uploaded + */ + void upload( Entry *entry ); + + /** + Ignores the return value of the install method. Used internally to + avoid showing of the success/failure dialog when installation is done + in another place, like in @ref KNewStuffSecure + */ + void ignoreInstallResult(bool ignore); + + signals: + /** Emitted when the upload has finished. + @param result indicates the success/failure of the upload + */ + void uploadFinished( bool result ); + protected slots: + void getMetaInformation( Provider::List *providers ); + void selectUploadProvider( Provider::List *providers ); + + void slotNewStuffJobData( KIO::Job *job, const QByteArray &data ); + void slotNewStuffJobResult( KIO::Job *job ); + + void slotDownloadJobResult( KIO::Job *job ); + + void slotUploadPayloadJobResult( KIO::Job *job ); + void slotUploadPreviewJobResult (KIO::Job *job ); + void slotUploadMetaJobResult( KIO::Job *job ); + + protected: + bool createMetaFile( Entry * ); + + private: + QWidget *mParentWidget; + + ProviderLoader *mProviderLoader; + + QMap<KIO::Job *,QString> mNewStuffJobData; + QMap<KIO::Job *,Provider *> mProviderJobs; + + QPtrList<Entry> mNewStuffList; + + DownloadDialog *mDownloadDialog; + UploadDialog *mUploadDialog; + ProviderDialog *mProviderDialog; + + QString mDownloadDestination; + + Provider *mUploadProvider; + + QString mUploadMetaFile; + QString mUploadFile; + QString mPreviewFile; + QString mProviderList; + + Private* d; + + QString mType; +}; + +} + +#endif diff --git a/knewstuff/entry.cpp b/knewstuff/entry.cpp new file mode 100644 index 000000000..1a7f580db --- /dev/null +++ b/knewstuff/entry.cpp @@ -0,0 +1,385 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "entry.h" + +#include <qptrdict.h> +#include <qwindowdefs.h> + +#include <kglobal.h> +#include <klocale.h> + +using namespace KNS; + +// BCI for KDE 3.5 only + +class EntryPrivate +{ + public: + EntryPrivate(){} + QString mEmail; + QMap<QString,QString> mNameMap; +}; + +static QPtrDict<EntryPrivate> *d_ptr = 0; + +static EntryPrivate *d(const Entry *e) +{ + if(!d_ptr) + { + d_ptr = new QPtrDict<EntryPrivate>(); + d_ptr->setAutoDelete(true); + } + EntryPrivate *ret = d_ptr->find((void*)e); + if(!ret) + { + ret = new EntryPrivate(); + d_ptr->replace((void*)e, ret); + } + return ret; +} + +QString Entry::authorEmail() const +{ + return d(this)->mEmail; +} + +void Entry::setAuthorEmail( const QString& email ) +{ + d(this)->mEmail = email; +} + +QString Entry::name( const QString &lang ) const +{ + if ( d(this)->mNameMap.isEmpty() ) return QString::null; + + if ( !d(this)->mNameMap[ lang ].isEmpty() ) return d(this)->mNameMap[ lang ]; + else { + QStringList langs = KGlobal::locale()->languageList(); + for(QStringList::Iterator it = langs.begin(); it != langs.end(); ++it) + if( !d(this)->mNameMap[ *it ].isEmpty() ) return d(this)->mNameMap[ *it ]; + } + if ( !d(this)->mNameMap[ QString::null ].isEmpty() ) return d(this)->mNameMap[ QString::null ]; + else return *(mSummaryMap.begin()); +} + +void Entry::setName( const QString &name, const QString &lang ) +{ + d(this)->mNameMap.insert( lang, name ); + + if ( mLangs.find( lang ) == mLangs.end() ) mLangs.append( lang ); +} + +// BCI part ends here + +Entry::Entry() : + mRelease( 0 ), mReleaseDate( QDate::currentDate() ), mRating( 0 ), + mDownloads( 0 ) +{ +} + +Entry::Entry( const QDomElement &e ) : + mRelease( 0 ), mRating( 0 ), mDownloads( 0 ) +{ + parseDomElement( e ); +} + +Entry::~Entry() +{ + if (d_ptr) + { + EntryPrivate *p = d_ptr->find(this); + if (p) + d_ptr->remove(p); + + if (d_ptr->isEmpty()) + { + delete d_ptr; + d_ptr = 0L; + } + } +} + + +void Entry::setName( const QString &name ) +{ + mName = name; +} + +QString Entry::name() const +{ + return mName; +} + + +void Entry::setType( const QString &type ) +{ + mType = type; +} + +QString Entry::type() const +{ + return mType; +} + + +void Entry::setAuthor( const QString &author ) +{ + mAuthor = author; +} + +QString Entry::author() const +{ + return mAuthor; +} + + +void Entry::setLicence( const QString &license ) +{ + mLicence = license; +} + +QString Entry::license() const +{ + return mLicence; +} + + +void Entry::setSummary( const QString &text, const QString &lang ) +{ + mSummaryMap.insert( lang, text ); + + if ( mLangs.find( lang ) == mLangs.end() ) mLangs.append( lang ); +} + +QString Entry::summary( const QString &lang ) const +{ + if ( mSummaryMap.isEmpty() ) return QString::null; + + if ( !mSummaryMap[ lang ].isEmpty() ) return mSummaryMap[ lang ]; + else { + QStringList langs = KGlobal::locale()->languageList(); + for(QStringList::Iterator it = langs.begin(); it != langs.end(); ++it) + if( !mSummaryMap[ *it ].isEmpty() ) return mSummaryMap[ *it ]; + } + if ( !mSummaryMap[ QString::null ].isEmpty() ) return mSummaryMap[ QString::null ]; + else return *(mSummaryMap.begin()); +} + + +void Entry::setVersion( const QString &version ) +{ + mVersion = version; +} + +QString Entry::version() const +{ + return mVersion; +} + + +void Entry::setRelease( int release ) +{ + mRelease = release; +} + +int Entry::release() const +{ + return mRelease; +} + + +void Entry::setReleaseDate( const QDate &d ) +{ + mReleaseDate = d; +} + +QDate Entry::releaseDate() const +{ + return mReleaseDate; +} + + +void Entry::setPayload( const KURL &url, const QString &lang ) +{ + mPayloadMap.insert( lang, url ); + + if ( mLangs.find( lang ) == mLangs.end() ) mLangs.append( lang ); +} + +KURL Entry::payload( const QString &lang ) const +{ + KURL payload = mPayloadMap[ lang ]; + if ( payload.isEmpty() ) { + QStringList langs = KGlobal::locale()->languageList(); + for(QStringList::Iterator it = langs.begin(); it != langs.end(); ++it) + if( !mPayloadMap[ *it ].isEmpty() ) return mPayloadMap[ *it ]; + } + if ( payload.isEmpty() ) payload = mPayloadMap [ QString::null ]; + if ( payload.isEmpty() && !mPayloadMap.isEmpty() ) { + payload = *(mPayloadMap.begin()); + } + return payload; +} + + +void Entry::setPreview( const KURL &url, const QString &lang ) +{ + mPreviewMap.insert( lang, url ); + + if ( mLangs.find( lang ) == mLangs.end() ) mLangs.append( lang ); +} + +KURL Entry::preview( const QString &lang ) const +{ + KURL preview = mPreviewMap[ lang ]; + if ( preview.isEmpty() ) { + QStringList langs = KGlobal::locale()->languageList(); + for(QStringList::Iterator it = langs.begin(); it != langs.end(); ++it) + if( !mPreviewMap[ *it ].isEmpty() ) return mPreviewMap[ *it ]; + } + if ( preview.isEmpty() ) preview = mPreviewMap [ QString::null ]; + if ( preview.isEmpty() && !mPreviewMap.isEmpty() ) { + preview = *(mPreviewMap.begin()); + } + return preview; +} + + +void Entry::setRating( int rating ) +{ + mRating = rating; +} + +int Entry::rating() +{ + return mRating; +} + + +void Entry::setDownloads( int downloads ) +{ + mDownloads = downloads; +} + +int Entry::downloads() +{ + return mDownloads; +} + +QString Entry::fullName() +{ + if ( version().isEmpty() ) + return name(); + else + return name() + "-" + version() + "-" + QString::number( release() ); +} + +QStringList Entry::langs() +{ + return mLangs; +} + +void Entry::parseDomElement( const QDomElement &element ) +{ + if ( element.tagName() != "stuff" ) return; + mType = element.attribute("type"); + + QDomNode n; + for( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e = n.toElement(); + if ( e.tagName() == "name" ) + { + QString lang = e.attribute( "lang" ); + setName( e.text().stripWhiteSpace(), lang ); + if(lang.isNull()) setName( e.text().stripWhiteSpace() ); /* primary key - no i18n */ + } + if ( e.tagName() == "author" ) { + setAuthor( e.text().stripWhiteSpace() ); + QString email = e.attribute( "email" ); + setAuthorEmail( email ); + } + if ( e.tagName() == "email" ) setAuthorEmail( e.text().stripWhiteSpace() ); /* kde-look; change on server! */ + if ( e.tagName() == "licence" ) setLicence( e.text().stripWhiteSpace() ); + if ( e.tagName() == "summary" ) { + QString lang = e.attribute( "lang" ); + setSummary( e.text().stripWhiteSpace(), lang ); + } + if ( e.tagName() == "version" ) setVersion( e.text().stripWhiteSpace() ); + if ( e.tagName() == "release" ) setRelease( e.text().toInt() ); + if ( e.tagName() == "releasedate" ) { + QDate date = QDate::fromString( e.text().stripWhiteSpace(), Qt::ISODate ); + setReleaseDate( date ); + } + if ( e.tagName() == "preview" ) { + QString lang = e.attribute( "lang" ); + setPreview( KURL( e.text().stripWhiteSpace() ), lang ); + } + if ( e.tagName() == "payload" ) { + QString lang = e.attribute( "lang" ); + setPayload( KURL( e.text().stripWhiteSpace() ), lang ); + } + if ( e.tagName() == "rating" ) setRating( e.text().toInt() ); + if ( e.tagName() == "downloads" ) setDownloads( e.text().toInt() ); + } +} + +QDomElement Entry::createDomElement( QDomDocument &doc, + QDomElement &parent ) +{ + QDomElement entry = doc.createElement( "stuff" ); + entry.setAttribute("type", mType); + parent.appendChild( entry ); + + addElement( doc, entry, "name", name() ); + addElement( doc, entry, "author", author() ); + addElement( doc, entry, "email", authorEmail() ); + addElement( doc, entry, "licence", license() ); + addElement( doc, entry, "version", version() ); + addElement( doc, entry, "release", QString::number( release() ) ); + addElement( doc, entry, "rating", QString::number( rating() ) ); + addElement( doc, entry, "downloads", QString::number( downloads() ) ); + + addElement( doc, entry, "releasedate", + releaseDate().toString( Qt::ISODate ) ); + + QStringList ls = langs(); + QStringList::ConstIterator it; + for( it = ls.begin(); it != ls.end(); ++it ) { + QDomElement e = addElement( doc, entry, "summary", summary( *it ) ); + e.setAttribute( "lang", *it ); + e = addElement( doc, entry, "preview", preview( *it ).url() ); + e.setAttribute( "lang", *it ); + e = addElement( doc, entry, "payload", payload( *it ).url() ); + e.setAttribute( "lang", *it ); + } + + return entry; +} + +QDomElement Entry::addElement( QDomDocument &doc, QDomElement &parent, + const QString &tag, const QString &value ) +{ + QDomElement n = doc.createElement( tag ); + n.appendChild( doc.createTextNode( value ) ); + parent.appendChild( n ); + + return n; +} diff --git a/knewstuff/entry.h b/knewstuff/entry.h new file mode 100644 index 000000000..0b6ba3fdd --- /dev/null +++ b/knewstuff/entry.h @@ -0,0 +1,281 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFF_ENTRY_H +#define KNEWSTUFF_ENTRY_H + +#include <qdatetime.h> +#include <qdom.h> +#include <qmap.h> +#include <qstring.h> +#include <qstringlist.h> + +#include <kurl.h> + +namespace KNS { + +/** + * @short KNewStuff data entry container. + * + * This class provides accessor methods to the data objects + * as used by KNewStuff. + * It should probably not be used directly by the application. + * + * @author Cornelius Schumacher (schumacher@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + */ +class KDE_EXPORT Entry +{ + public: + Entry(); + /** + * Constructor. + */ + Entry( const QDomElement & ); + + /** + * Destructor. + */ + ~Entry(); + + /** + * Sets the (unique) name for this data object. + */ + void setName( const QString & ); + + /** + * Sets the (internationalised) name for this data object. + */ + void setName( const QString &, const QString & ); + + /** + * Retrieve the name of the data object. + * + * @return object name + */ + QString name() const; + + /** + * Retrieve the internationalised name of the data object. + * + * @return object name (potentially translated) + */ + QString name( const QString &lang ) const; + + /** + * Sets the application type, e.g. 'kdesktop/wallpaper'. + */ + void setType( const QString & ); + + /** + * Retrieve the type of the data object. + * + * @return object type + */ + QString type() const; + + /** + * Sets the full name of the object's author. + */ + void setAuthor( const QString & ); + + /** + * Retrieve the author's name of the object. + * + * @return object author + */ + QString author() const; + + /** + * Sets the email address of the object's author. + */ + void setAuthorEmail( const QString & ); + + /** + * Retrieve the author's email address of the object. + * + * @return object author email address + */ + QString authorEmail() const; + + /** + * Sets the license (abbreviation) applicable to the object. + */ + void setLicence( const QString & ); + + /** + * Retrieve the license name of the object. + * + * @return object license + */ + QString license() const; + + /** + * Sets a short description on what the object is all about. + */ + void setSummary( const QString &, const QString &lang = QString::null ); + + /** + * Retrieve a short description about the object. + * + * @param lang preferred language, or QString::null for KDE default + * @return object description + */ + QString summary( const QString &lang = QString::null ) const; + + /** + * Sets the version number. + */ + void setVersion( const QString & ); + + /** + * Retrieve the version string of the object. + * + * @return object version + */ + QString version() const; + + /** + * Sets the release number, which is increased for feature-equal objects + * with the same version number, but slightly updated contents. + */ + void setRelease( int ); + + /** + * Retrieve the release number of the object + * + * @return object release + */ + int release() const; + + /** + * Sets the release date. + */ + void setReleaseDate( const QDate & ); + + /** + * Retrieve the date of the object's publication. + * + * @return object release date + */ + QDate releaseDate() const; + + /** + * Sets the object's file. + */ + void setPayload( const KURL &, const QString &lang = QString::null ); + + /** + * Retrieve the file name of the object. + * + * @param lang preferred language, or QString::null for KDE default + * @return object filename + */ + KURL payload( const QString &lang = QString::null ) const; + + /** + * Sets the object's preview file, if available. This should be a + * picture file. + */ + void setPreview( const KURL &, const QString &lang = QString::null ); + + /** + * Retrieve the file name of an image containing a preview of the object. + * + * @param lang preferred language, or QString::null for KDE default + * @return object preview filename + */ + KURL preview( const QString &lang = QString::null ) const; + + /** + * Sets the rating between 0 (worst) and 10 (best). + * + * @internal + */ + void setRating( int ); + + /** + * Retrieve the rating for the object, which has been determined by its + * users and thus might change over time. + * + * @return object rating + */ + int rating(); + + /** + * Sets the number of downloads. + * + * @internal + */ + void setDownloads( int ); + + /** + * Retrieve the download count for the object, which has been determined + * by its hosting sites and thus might change over time. + * + * @return object download count + */ + int downloads(); + + /** + * Return the full name for the meta information. It is constructed as + * name-version-release. + */ + QString fullName(); + + /** + * Return the list of languages this object supports. + */ + QStringList langs(); + + /** + * @internal + */ + void parseDomElement( const QDomElement & ); + + /** + * @internal + */ + QDomElement createDomElement( QDomDocument &, QDomElement &parent ); + + protected: + QDomElement addElement( QDomDocument &doc, QDomElement &parent, + const QString &tag, const QString &value ); + + private: + QString mName; + QString mType; + QString mAuthor; + QString mLicence; + QMap<QString,QString> mSummaryMap; + QString mVersion; + int mRelease; + QDate mReleaseDate; + QMap<QString,KURL> mPayloadMap; + QMap<QString,KURL> mPreviewMap; + int mRating; + int mDownloads; + + QStringList mLangs; +}; + +} + +#endif diff --git a/knewstuff/ghns.cpp b/knewstuff/ghns.cpp new file mode 100644 index 000000000..6c273b03a --- /dev/null +++ b/knewstuff/ghns.cpp @@ -0,0 +1,93 @@ +/* + This file is part of KDE. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include <iostream> + +#include <qlayout.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qlabel.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kprocess.h> +#include <kdialog.h> + +#include "knewstuffgeneric.h" + +#include "ghns.h" + +using namespace std; + +GhnsWidget::GhnsWidget() +{ + mWallpapers = new KNewStuffGeneric( "kdesktop/wallpaper", this ); + + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setMargin( KDialog::marginHint() ); + topLayout->setSpacing( KDialog::spacingHint() ); + + topLayout->addWidget( new QLabel( i18n("Get hot new stuff:"), this ) ); + + QPushButton *button = new QPushButton( "Wallpapers", this ); + topLayout->addWidget( button ); + connect( button, SIGNAL( clicked() ), SLOT( downloadWallpapers() ) ); + + topLayout->addSpacing( 5 ); + + QBoxLayout *buttonLayout = new QHBoxLayout( topLayout ); + + buttonLayout->addStretch(); + + QPushButton *closeButton = new QPushButton( "Close", this ); + buttonLayout->addWidget( closeButton ); + connect( closeButton, SIGNAL( clicked() ), kapp, SLOT( quit() ) ); +} + +GhnsWidget::~GhnsWidget() +{ + delete mWallpapers; +} + +void GhnsWidget::downloadWallpapers() +{ + kdDebug() << "downloadWallpapers()" << endl; + + mWallpapers->download(); +} + +int main(int argc,char **argv) +{ + KAboutData aboutData("ghns","Get Hot New Stuff","0.1"); + KCmdLineArgs::init(argc,argv,&aboutData); + + KApplication app; + + GhnsWidget wid; + app.setMainWidget( &wid ); + wid.show(); + + app.exec(); +} + +#include "ghns.moc" diff --git a/knewstuff/ghns.h b/knewstuff/ghns.h new file mode 100644 index 000000000..4823bf526 --- /dev/null +++ b/knewstuff/ghns.h @@ -0,0 +1,47 @@ +/* + This file is part of KDE. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef GHNS_H +#define GHNS_H + +#include <stdlib.h> + +#include <qpushbutton.h> + +#include <kapplication.h> +#include <kdebug.h> + +#include "knewstuff.h" + +class GhnsWidget : public QWidget +{ + Q_OBJECT + public: + GhnsWidget(); + ~GhnsWidget(); + + public slots: + void downloadWallpapers(); + + private: + KNewStuff *mWallpapers; +}; + +#endif diff --git a/knewstuff/khotnewstuff.cpp b/knewstuff/khotnewstuff.cpp new file mode 100644 index 000000000..e479bd3b3 --- /dev/null +++ b/knewstuff/khotnewstuff.cpp @@ -0,0 +1,55 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> + +#include "downloaddialog.h" + +static const KCmdLineOptions op[] = +{ + {"type <type>", I18N_NOOP("Display only media of this type"), 0}, + {"+[providerlist]", I18N_NOOP("Provider list to use"), 0}, + KCmdLineLastOption +}; + +int main(int argc, char **argv) +{ + KAboutData about("khotnewstuff", "KHotNewStuff", "0.2"); + KCmdLineArgs *args; + + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions(op); + args = KCmdLineArgs::parsedArgs(); + + KApplication i; + + KNS::DownloadDialog d; + if(args->isSet("type")) d.setType(args->getOption("type")); + if(args->count() == 1) d.setProviderList(args->arg(0)); + d.load(); + d.exec(); + + return 0; +} + diff --git a/knewstuff/khotnewstuffrc b/knewstuff/khotnewstuffrc new file mode 100644 index 000000000..737ad61c2 --- /dev/null +++ b/knewstuff/khotnewstuffrc @@ -0,0 +1,3 @@ +[KNewStuff] +ProvidersUrl=http://www.kstuff.org/hotstuff/providers/index.xml + diff --git a/knewstuff/knewstuff.cpp b/knewstuff/knewstuff.cpp new file mode 100644 index 000000000..5387e647f --- /dev/null +++ b/knewstuff/knewstuff.cpp @@ -0,0 +1,86 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kaction.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kstandarddirs.h> + +#include "engine.h" + +#include "knewstuff.h" + +using namespace KNS; + +KAction* KNS::standardAction(const QString& what, + const QObject *recvr, + const char *slot, KActionCollection* parent, + const char *name) +{ + return new KAction(i18n("Download New %1").arg(what), "knewstuff", + 0, recvr, slot, parent, name); +} + +KNewStuff::KNewStuff( const QString &type, QWidget *parentWidget ) +{ + mEngine = new Engine( this, type, parentWidget ); +} + +KNewStuff::KNewStuff( const QString &type, const QString &providerList, QWidget *parentWidget ) +{ + mEngine = new Engine( this, type, providerList, parentWidget ); +} + +QString KNewStuff::type() const +{ + return mEngine->type(); +} + +QWidget *KNewStuff::parentWidget() const +{ + return mEngine->parentWidget(); +} + +KNewStuff::~KNewStuff() +{ + delete mEngine; +} + +void KNewStuff::download() +{ + mEngine->download(); +} + +QString KNewStuff::downloadDestination( Entry * ) +{ + return KGlobal::dirs()->saveLocation( "tmp" ) + + KApplication::randomString( 10 ); +} + +void KNewStuff::upload() +{ + mEngine->upload(); +} + +void KNewStuff::upload( const QString &fileName, const QString previewName ) +{ + mEngine->upload(fileName, previewName); +} diff --git a/knewstuff/knewstuff.h b/knewstuff/knewstuff.h new file mode 100644 index 000000000..ab03ade51 --- /dev/null +++ b/knewstuff/knewstuff.h @@ -0,0 +1,161 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFF_H +#define KNEWSTUFF_H + +#include <qstring.h> + +#include <kdemacros.h> + +class QObject; +class QWidget; +class KAction; +class KActionCollection; + +namespace KNS { +class Engine; +class Entry; + +KDE_EXPORT KAction* standardAction(const QString& what, + const QObject *recvr, + const char *slot, + KActionCollection* parent, + const char *name = 0); +} + +/** + * @short This class provides the functionality to download and upload "new stuff". + * + * Applications have to subclass KNewStuff, implement the pure virtual functions + * and link to against libknewstuff. + * + * By calling download() the download process is started which means that a list + * of "providers" is fetched from a "master server", information about new stuff + * is collected from the providers and presented to the user. Selected entries + * get downloaded and installed to the application. The required functions to + * install new stuff are provided by implementing install(). The location where + * the downloaded files are stored can be customized by reimplementing + * downloadDestination(). + * + * By calling upload() the upload process is started which means the user has to + * select a provider from the list fetched from the master server and to put in + * information about the entry to be uploaded. Then the file to be uploaded is + * fetched from the application by calling createUploadFile() and transfered to + * the upload destination specified in the provider list. + * + * @author Cornelius Schumacher (schumacher@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + * + * @since 3.3 + */ +class KDE_EXPORT KNewStuff +{ + public: + /** + Constructor. + + @param type type of data to be handled, should be something like + korganizer/calendar, kword/template, kdesktop/wallpaper + @param parentWidget parent widget of dialogs opened by the KNewStuff + engine + */ + KNewStuff( const QString &type, QWidget *parentWidget = 0 ); + + /** + Constructor. + + @param type type of data to be handled, should be something like + korganizer/calendar, kword/template, kdesktop/wallpaper + @param providerList the URL of the provider list + @param parentWidget parent widget of dialogs opened by the KNewStuff + engine + */ + KNewStuff( const QString &type, const QString &providerList, QWidget *parentWidget = 0 ); + virtual ~KNewStuff(); + + /** + Return type of data. + */ + QString type() const; + + /** + Return parent widget. + */ + QWidget *parentWidget() const; + + /** + Start download process. + */ + void download(); + + /** + Start upload process. + */ + void upload(); + + /** + Upload with pre-defined files. + */ + void upload( const QString &fileName, const QString previewName ); + + /** + Install file to application. The given fileName points to the file + downloaded by the KNewStuff engine. This is a temporary file by default. + The application can do whatever is needed to handle the information + contained in the file. + + The function returns true, when the installation + was successful and false if were errors. + + @param fileName name of downloaded file + */ + virtual bool install( const QString &fileName ) = 0; + /** + Create a file to be uploaded to a "new stuff provider" and return the + filename. The format of the file is application specific. The only + constraint is that the corresponding install() implementation is able to + use the file. + + @param fileName name of the file to be written + @return @c true on success, @c false on error. + */ + virtual bool createUploadFile( const QString &fileName ) = 0; + + /** + Return a filename which should be used as destination for downloading the + specified new stuff entry. Reimplement this function, if you don't want + the new stuff to be downloaded to a temporary file. + */ + virtual QString downloadDestination( KNS::Entry *entry ); + + + protected: + /** + Get the pointer to the engine. Needed by subclasses to access the KNS::Engine object. + */ + KNS::Engine *engine() { return mEngine; } + + + private: + KNS::Engine *mEngine; +}; + +#endif diff --git a/knewstuff/knewstuffbutton.cpp b/knewstuff/knewstuffbutton.cpp new file mode 100644 index 000000000..97be51df5 --- /dev/null +++ b/knewstuff/knewstuffbutton.cpp @@ -0,0 +1,90 @@ +/* + Copyright (c) 2004 Aaron J. Seigo <aseigo@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kiconloader.h> +#include <klocale.h> + +#include "downloaddialog.h" +#include "knewstuffbutton.h" +#include "knewstuffbutton.moc" + +namespace KNS +{ + +Button::Button(const QString& what, + const QString& providerList, + const QString& resourceType, + QWidget* parent, const char* name) + : KPushButton(parent, name), + d(0), + m_providerList(providerList), + m_type(resourceType), + m_downloadDialog(0) +{ + setButtonText(what); + init(); +} + +Button::Button(QWidget* parent, const char* name) + : KPushButton(parent, name), + d(0), + m_downloadDialog(0) +{ + setButtonText(i18n("Download New Stuff")); + init(); +} + +void Button::init() +{ + setIconSet(SmallIconSet("knewstuff")); + connect(this, SIGNAL(clicked()), SLOT(showDialog())); +} + +void Button::setButtonText(const QString& what) +{ + setText(i18n("Download New %1").arg(what)); +} + +void Button::setProviderList(const QString& providerList) +{ + m_providerList = providerList; +} + +void Button::setResourceType(const QString& resourceType) +{ + m_type = resourceType; +} + +void Button::showDialog() +{ + emit aboutToShowDialog(); + + if (!m_downloadDialog) + { + m_downloadDialog = new DownloadDialog(0, this); + } + + m_downloadDialog->setType(m_type); + m_downloadDialog->load(m_providerList); + + m_downloadDialog->exec(); // TODO: make non-modal? + emit dialogFinished(); +} + +} diff --git a/knewstuff/knewstuffbutton.h b/knewstuff/knewstuffbutton.h new file mode 100644 index 000000000..bcc090cd4 --- /dev/null +++ b/knewstuff/knewstuffbutton.h @@ -0,0 +1,115 @@ +/* + Copyright (c) 2004 Aaron J. Seigo <aseigo@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _khotnewbutton_h +#define _khotnewbutton_h + +#include <kpushbutton.h> + +namespace KNS +{ + +class DownloadDialog; + +/** + * KHotNewStuff push button that makes using KHNS in an application + * more convenient by encapsulating most of the details involved in + * using KHotNewStuff in the button itself. + * + * @since 3.4 + */ +class Button : public KPushButton +{ + Q_OBJECT + + public: + /** + * Constructor used when the details of the KHotNewStuff + * download is known when the button is created. + * + * @param what text describing what is being downloaded. will be + * shown on the button as "Download New <what>" + * @param providerList the URL to the list of providers; if empty + * we first try the ProvidersUrl from KGlobal::config, then we + * fall back to a hardcoded value + * @param resourceType the Hotstuff data type for this downlaod such + * as "korganizer/calendar" + * @param parent the parent widget + * @param name the name to be used for this widget + */ + Button(const QString& what, + const QString& providerList, + const QString& resourceType, + QWidget* parent, const char* name); + + /** + * Constructor used when the details of the KHotNewStuff + * download is not known in advance of the button being created. + * + * @param parent the parent widget + * @param name the name to be used for this widget + */ + Button(QWidget* parent, const char* name); + + /** + * set the URL to the list of providers for this button to use + */ + void setProviderList(const QString& providerList); + + /** + * the Hotstuff data type for this downlaod such as + * "korganizer/calendar" + */ + void setResourceType(const QString& resourceType); + + /** + * set the text that should appear on the button. will be prefaced + * with i18n("Download New") + */ + void setButtonText(const QString& what); + + signals: + /** + * emitted when the Hot New Stuff dialog is about to be shown, usually + * as a result of the user having click on the button + */ + void aboutToShowDialog(); + + /** + * emitted when the Hot New Stuff dialog has been closed + */ + void dialogFinished(); + + protected slots: + void showDialog(); + + private: + void init(); + + class ButtonPrivate; + ButtonPrivate* d; + + QString m_providerList; + QString m_type; + DownloadDialog* m_downloadDialog; +}; + +} + +#endif diff --git a/knewstuff/knewstuffgeneric.cpp b/knewstuff/knewstuffgeneric.cpp new file mode 100644 index 000000000..c1be1ccca --- /dev/null +++ b/knewstuff/knewstuffgeneric.cpp @@ -0,0 +1,146 @@ +/* + This file is part of KDE. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qfile.h> +#include <qtextstream.h> +#include <qdir.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kprocess.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <ktar.h> + +#include "entry.h" + +#include "knewstuffgeneric.h" + +using namespace std; + +KNewStuffGeneric::KNewStuffGeneric( const QString &type, QWidget *parent ) + : KNewStuff( type, parent ) +{ + mConfig = KGlobal::config(); +} + +KNewStuffGeneric::~KNewStuffGeneric() +{ +} + +bool KNewStuffGeneric::install( const QString &fileName ) +{ + kdDebug() << "KNewStuffGeneric::install(): " << fileName << endl; + QStringList list, list2; + + mConfig->setGroup("KNewStuff"); + + QString uncompress = mConfig->readEntry( "Uncompress" ); + if ( !uncompress.isEmpty() ) { + kdDebug() << "Uncompression method: " << uncompress << endl; + KTar tar(fileName, uncompress); + tar.open(IO_ReadOnly); + const KArchiveDirectory *dir = tar.directory(); + dir->copyTo(destinationPath(0)); + tar.close(); + QFile::remove(fileName); + } + + QString cmd = mConfig->readEntry( "InstallationCommand" ); + if ( !cmd.isEmpty() ) { + kdDebug() << "InstallationCommand: " << cmd << endl; + list = QStringList::split( " ", cmd ); + for ( QStringList::iterator it = list.begin(); it != list.end(); ++it ) { + list2 << (*it).replace("%f", fileName); + } + KProcess proc; + proc << list2; + proc.start( KProcess::Block ); + } + + return true; +} + +bool KNewStuffGeneric::createUploadFile( const QString & /*fileName*/ ) +{ + return false; +} + +QString KNewStuffGeneric::destinationPath( KNS::Entry *entry ) +{ + QString path, file, target, ext; + + mConfig->setGroup("KNewStuff"); + + if ( entry ) + { + ext = entry->payload().fileName().section('.', 1); + if ( ! ext.isEmpty() ) ext = "." + ext; + + target = entry->fullName() + ext; + } + else target = "/"; + QString res = mConfig->readEntry( "StandardResource" ); + if ( res.isEmpty() ) + { + target = mConfig->readEntry("TargetDir"); + if ( !target.isEmpty()) + { + res = "data"; + if ( entry ) target.append("/" + entry->fullName() + ext); + else target.append("/"); + } + } + if ( res.isEmpty() ) + { + path = mConfig->readEntry( "InstallPath" ); + } + if ( res.isEmpty() && path.isEmpty() ) + { + if ( !entry ) return QString::null; + else return KNewStuff::downloadDestination( entry ); + } + + if ( !path.isEmpty() ) + { + file = QDir::home().path() + "/" + path + "/"; + if ( entry ) file += entry->fullName() + ext; + } + else file = locateLocal( res.utf8() , target ); + + return file; +} + +QString KNewStuffGeneric::downloadDestination( KNS::Entry *entry ) +{ + QString file = destinationPath(entry); + + if ( KStandardDirs::exists( file ) ) { + int result = KMessageBox::warningContinueCancel( parentWidget(), + i18n("The file '%1' already exists. Do you want to overwrite it?") + .arg( file ), + QString::null, i18n("Overwrite") ); + if ( result == KMessageBox::Cancel ) return QString::null; + } + + return file; +} diff --git a/knewstuff/knewstuffgeneric.h b/knewstuff/knewstuffgeneric.h new file mode 100644 index 000000000..5443e24a3 --- /dev/null +++ b/knewstuff/knewstuffgeneric.h @@ -0,0 +1,86 @@ +/* + This file is part of KDE. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFFGENERIC_H +#define KNEWSTUFFGENERIC_H + +#include "knewstuff.h" + +class KConfig; + +/** + * @short Basic KNewStuff class with predefined actions. + * + * This class is used for data uploads and installation. + * \code + * QString payload, preview; + * KNewStuffGeneric *ns = new KNewStuffGeneric("kamikaze/level", this); + * ns->upload(payload, preview); + * \endcode + * + * @author Cornelius Schumacher (schumacher@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + */ +class KDE_EXPORT KNewStuffGeneric : public KNewStuff +{ + public: + /** + Constructor. + + @param type a Hotstuff data type such as "korganizer/calendar" + @param parent the parent window. + */ + KNewStuffGeneric( const QString &type, QWidget *parent = 0 ); + ~KNewStuffGeneric(); + + /** + Installs a downloaded file according to the application's configuration. + + @param fileName filename of the donwloaded file + @return @c true in case of installation success, @c false otherwise + */ + bool install( const QString &fileName ); + + /** + Creates a file suitable for upload. + Note that this method always fails, since using KNewStuffGeneric + means that the provided file must already be in a usable format. + + @param fileName the name of the file to upload after its creation + @return @c true in case of creation success, @c false otherwise + */ + bool createUploadFile( const QString &fileName ); + + /** + Queries the preferred destination file for a download. + + @param entry a Hotstuff data entry + @return destination filename, or 0 to return directory only + */ + QString downloadDestination( KNS::Entry *entry ); + + private: + QString destinationPath( KNS::Entry *entry ); + + KConfig *mConfig; +}; + +#endif diff --git a/knewstuff/knewstuffsecure.cpp b/knewstuff/knewstuffsecure.cpp new file mode 100644 index 000000000..270d9449c --- /dev/null +++ b/knewstuff/knewstuffsecure.cpp @@ -0,0 +1,240 @@ +/*************************************************************************** + knewstuffsecure.cpp - description + ------------------- + begin : Tue Jun 22 12:19:55 2004 + copyright : (C) 2004, 2005 by Andras Mantia <amantia@kde.org> + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ +//qt includes +#include <qfileinfo.h> + +//kde includes +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kio/netaccess.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ktar.h> +#include <ktempdir.h> + +//app includes +#include "engine.h" +#include "knewstuffsecure.h" +#include "security.h" + +using namespace KNS; + +KNewStuffSecure::KNewStuffSecure(const QString &type, QWidget *parentWidget) + : KNewStuff(type, parentWidget) +{ + m_tempDir = 0L; + connect(engine(), SIGNAL(uploadFinished(bool)), SLOT(slotUploadFinished(bool))); +} + + +KNewStuffSecure::~KNewStuffSecure() +{ + removeTempDirectory(); +} + +bool KNewStuffSecure::install(const QString &fileName) +{ + bool ok = true; + + removeTempDirectory(); + m_tempDir = new KTempDir(); + m_tempDir->setAutoDelete(true); + KTar tar(fileName, "application/x-gzip"); + if (tar.open(IO_ReadOnly)) + { + const KArchiveDirectory *directory = tar.directory(); + directory->copyTo(m_tempDir->name(), true); + m_tarName = ""; + QStringList entries = directory->entries(); + for (QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) + { + if (*it != "signature" && *it != "md5sum") + { + m_tarName = *it; + break; + } + } + tar.close(); + if (m_tarName.isEmpty()) + ok = false; + else + { + m_tarName.prepend(m_tempDir->name()); + connect(Security::ref(), SIGNAL(validityResult(int)), this, SLOT(slotValidated(int))); + Security::ref()->checkValidity(m_tarName); + } + } else + ok = false; + if (!ok) + KMessageBox::error(parentWidget(), i18n("There was an error with the downloaded resource tarball file. Possible causes are damaged archive or invalid directory structure in the archive."), i18n("Resource Installation Error")); + return ok; +} + +void KNewStuffSecure::slotValidated(int result) +{ + QString errorString; + QString signatureStr; + bool valid = true; + if (result == -1) + { + errorString ="<br>- " + i18n("No keys were found."); + valid = false; + } else + if (result == 0) + { + errorString ="<br>- " + i18n("The validation failed for unknown reason."); + valid = false; + } else + { + KeyStruct key = Security::ref()->signatureKey(); + if (!(result & Security::MD5_OK )) + { + errorString = "<br>- " + i18n("The MD5SUM check failed, the archive might be broken."); + valid = false; + } + if (result & Security::SIGNED_BAD) + { + errorString += "<br>- " + i18n("The signature is bad, the archive might be broken or altered."); + valid = false; + } + if (result & Security::SIGNED_OK) + { + if (result & Security::TRUSTED) + { + kdDebug() << "Signed and trusted " << endl; + } else + { + errorString += "<br>- " + i18n("The signature is valid, but untrusted."); + valid = false; + } + } + if (result & Security::UNKNOWN) + { + errorString += "<br>- " + i18n("The signature is unknown."); + valid = false; + } else + { + signatureStr = i18n("The resource was signed with key <i>0x%1</i>, belonging to <i>%2 <%3></i>.").arg(key.id.right(8)).arg(key.name).arg(key.mail); + } + } + if (!valid) + { + signatureStr.prepend( "<br>"); + if (KMessageBox::warningContinueCancel(parentWidget(), i18n("<qt>There is a problem with the resource file you have downloaded. The errors are :<b>%1</b><br>%2<br><br>Installation of the resource is <b>not recommended</b>.<br><br>Do you want to proceed with the installation?</qt>").arg(errorString).arg(signatureStr), i18n("Problematic Resource File")) == KMessageBox::Continue) + valid = true; + } else + KMessageBox::information(parentWidget(), i18n("<qt>%1<br><br>Press OK to install it.</qt>").arg(signatureStr), i18n("Valid Resource"), "Show Valid Signature Information"); + if (valid) + { + installResource(); + emit installFinished(); + } else + { + KConfig *cfg = KGlobal::config(); + cfg->deleteGroup("KNewStuffStatus"); + cfg->setGroup("KNewStuffStatus"); + for (QMap<QString, QString>::ConstIterator it = m_installedResources.constBegin(); it != m_installedResources.constEnd(); ++it) + { + cfg->writeEntry(it.key(), it.data()); + } + cfg->sync(); + } + removeTempDirectory(); + disconnect(Security::ref(), SIGNAL(validityResult(int)), this, SLOT(slotValidated(int))); +} + +void KNewStuffSecure::downloadResource() +{ + KConfig *cfg = KGlobal::config(); + m_installedResources = cfg->entryMap("KNewStuffStatus"); + engine()->ignoreInstallResult(true); + KNewStuff::download(); +} + +bool KNewStuffSecure::createUploadFile(const QString &fileName) +{ + Q_UNUSED(fileName); + return true; +} + +void KNewStuffSecure::uploadResource(const QString& fileName) +{ + connect(Security::ref(), SIGNAL(fileSigned(int)), this, SLOT(slotFileSigned(int))); + removeTempDirectory(); + m_tempDir = new KTempDir(); + m_tempDir->setAutoDelete(true); + QFileInfo f(fileName); + m_signedFileName = m_tempDir->name() + "/" + f.fileName(); + KIO::NetAccess::file_copy(KURL::fromPathOrURL(fileName), KURL::fromPathOrURL(m_signedFileName), -1, true); + Security::ref()->signFile(m_signedFileName); +} + +void KNewStuffSecure::slotFileSigned(int result) +{ + if (result == 0) + { + KMessageBox::error(parentWidget(), i18n("The signing failed for unknown reason.")); + } else + { + if (result & Security::BAD_PASSPHRASE) + { + if (KMessageBox::warningContinueCancel(parentWidget(), i18n("There are no keys usable for signing or you did not entered the correct passphrase.\nProceed without signing the resource?")) == KMessageBox::Cancel) + { + disconnect(Security::ref(), SIGNAL(fileSigned(int)), this, SLOT(slotFileSigned(int))); + removeTempDirectory(); + return; + } + } + KTar tar(m_signedFileName + ".signed", "application/x-gzip"); + tar.open(IO_WriteOnly); + QStringList files; + files << m_signedFileName; + files << m_tempDir->name() + "/md5sum"; + files << m_tempDir->name() + "/signature"; + + for (QStringList::Iterator it_f = files.begin(); it_f != files.end(); ++it_f) + { + QFile file(*it_f); + file.open(IO_ReadOnly); + QByteArray bArray = file.readAll(); + tar.writeFile(QFileInfo(file).fileName(), "user", "group", bArray.size(), bArray.data()); + file.close(); + } + tar.close(); + KIO::NetAccess::file_move(KURL::fromPathOrURL(m_signedFileName + ".signed"), KURL::fromPathOrURL(m_signedFileName), -1, true); + KNewStuff::upload(m_signedFileName, QString::null); + disconnect(Security::ref(), SIGNAL(fileSigned(int)), this, SLOT(slotFileSigned(int))); + } +} + +void KNewStuffSecure::slotUploadFinished(bool result) +{ + Q_UNUSED(result); + removeTempDirectory(); +} + +void KNewStuffSecure::removeTempDirectory() +{ + if (m_tempDir) + { + KIO::NetAccess::del(KURL().fromPathOrURL(m_tempDir->name()), parentWidget()); + delete m_tempDir; + m_tempDir = 0L; + } +} + +#include "knewstuffsecure.moc" diff --git a/knewstuff/knewstuffsecure.h b/knewstuff/knewstuffsecure.h new file mode 100644 index 000000000..2aed131a3 --- /dev/null +++ b/knewstuff/knewstuffsecure.h @@ -0,0 +1,101 @@ +/*************************************************************************** + knewstuffsecure.h - description + ------------------- + begin : Tue Jun 22 12:19:55 2004 + copyright : (C) 2004, 2005 by Andras Mantia <amantia@kde.org> + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef KNEWSTUFFSECURE_H +#define KNEWSTUFFSECURE_H + +//qt includes +#include <qobject.h> + +//kde includes +#include "knewstuff.h" + +class KTempDir; +/** +Makes possible downloading and installing signed resource files from a server. +You must subclass it and implement the @ref installResource() pure +virtual method to install a resource. For uploading you must create a resource +tarball (which is installabale by @ref installResource()) and call the +@ref uploadResource() method with this tarball as the argument. +Signing and verification is done by the gpg application, so the user must +have it installed, otherwise this class does not give any extra security compared +to the standard KNewStuff class. + +@since 3.4 + +@author Andras Mantia <amantia@kde.org> +*/ +class KDE_EXPORT KNewStuffSecure : public QObject, public KNewStuff +{ + Q_OBJECT + +public: + /** Constructor. + + @param type type of data to be handled, should be something like + korganizer/calendar, kword/template, kdesktop/wallpaper + @param parentWidget parent widget of dialogs opened by the KNewStuff + engine + */ + KNewStuffSecure(const QString &type, QWidget *parentWidget=0); + virtual ~KNewStuffSecure(); + + /** Installs the downloaded resource. Do not call or reimplement directly. + It's reimplemented from KNewStuff for internal reasons. + */ + bool install( const QString &fileName ); + + /** Reimplemented for internal reasons. */ + bool createUploadFile(const QString &fileName); + + /** Initiates a download. This is the method that must be called in + * order to download a signed resource. */ + void downloadResource(); + + /** Signs the file and uploads to the central server. + * @param fileName The file to be signed and uploaded + */ + void uploadResource(const QString &fileName); + + +private slots: + /** Checks the validity of the downloaded tarball and installs it*/ + void slotValidated(int result); + /** The file is signed, so it can be uploaded.*/ + void slotFileSigned(int result); + /** Called when the upload has finished. + @param result the result of the upload + Be careful if you reimplement it, as it deletes the temporary directory + m_tempDir used for upload. You must also delete it (call the parent's method) + if you reimplement it. + */ + void slotUploadFinished(bool result); + +signals: + void installFinished(); + +protected: + /** Installs the resource specified by m_tarName. Implement it in the subclass. */ + virtual void installResource() = 0; + /** Removes the temporary directory m_tempDir. */ + void removeTempDirectory(); + + KTempDir *m_tempDir; + QString m_tarName; + QString m_signedFileName; + QMap<QString, QString> m_installedResources; +}; + +#endif diff --git a/knewstuff/provider.cpp b/knewstuff/provider.cpp new file mode 100644 index 000000000..83e78ef92 --- /dev/null +++ b/knewstuff/provider.cpp @@ -0,0 +1,290 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kconfig.h> +#include <kdebug.h> +#include <kio/job.h> +#include <kglobal.h> +#include <kmessagebox.h> +#include <klocale.h> + +#include <qptrdict.h> +#include <qwindowdefs.h> + +#include "provider.h" +#include "provider.moc" + +using namespace KNS; + +// BCI for KDE 3.5 only + +class ProviderPrivate +{ + public: + ProviderPrivate(){} + KURL mDownloadUrlLatest; + KURL mDownloadUrlScore; + KURL mDownloadUrlDownloads; +}; + +static QPtrDict<ProviderPrivate> *d_ptr_prov = 0; + +static ProviderPrivate *d_prov(const Provider *p) +{ + if(!d_ptr_prov) + { + d_ptr_prov = new QPtrDict<ProviderPrivate>(); + d_ptr_prov->setAutoDelete(true); + } + ProviderPrivate *ret = d_ptr_prov->find((void*)p); + if(!ret) + { + ret = new ProviderPrivate(); + d_ptr_prov->replace((void*)p, ret); + } + return ret; +} + +KURL Provider::downloadUrlVariant( QString variant ) const +{ + if((variant == "latest") && (d_prov(this)->mDownloadUrlLatest.isValid())) + return d_prov(this)->mDownloadUrlLatest; + if((variant == "score") && (d_prov(this)->mDownloadUrlScore.isValid())) + return d_prov(this)->mDownloadUrlScore; + if((variant == "downloads") && (d_prov(this)->mDownloadUrlDownloads.isValid())) + return d_prov(this)->mDownloadUrlDownloads; + + return mDownloadUrl; +} + +// BCI part ends here + +Provider::Provider() : mNoUpload( false ) +{ +} + +Provider::Provider( const QDomElement &e ) : mNoUpload( false ) +{ + parseDomElement( e ); +} + +Provider::~Provider() +{ + if (d_ptr_prov) + { + ProviderPrivate *p = d_ptr_prov->find(this); + if (p) + d_ptr_prov->remove(p); + + if (d_ptr_prov->isEmpty()) + { + delete d_ptr_prov; + d_ptr_prov = 0L; + } + } +} + + +void Provider::setName( const QString &name ) +{ + mName = name; +} + +QString Provider::name() const +{ + return mName; +} + + +void Provider::setIcon( const KURL &url ) +{ + mIcon = url; +} + +KURL Provider::icon() const +{ + return mIcon; +} + + +void Provider::setDownloadUrl( const KURL &url ) +{ + mDownloadUrl = url; +} + +KURL Provider::downloadUrl() const +{ + return mDownloadUrl; +} + + +void Provider::setUploadUrl( const KURL &url ) +{ + mUploadUrl = url; +} + +KURL Provider::uploadUrl() const +{ + return mUploadUrl; +} + + +void Provider::setNoUploadUrl( const KURL &url ) +{ + mNoUploadUrl = url; +} + +KURL Provider::noUploadUrl() const +{ + return mNoUploadUrl; +} + + +void Provider::setNoUpload( bool enabled ) +{ + mNoUpload = enabled; +} + +bool Provider::noUpload() const +{ + return mNoUpload; +} + + +void Provider::parseDomElement( const QDomElement &element ) +{ + if ( element.tagName() != "provider" ) return; + + setDownloadUrl( KURL( element.attribute("downloadurl") ) ); + setUploadUrl( KURL( element.attribute("uploadurl") ) ); + setNoUploadUrl( KURL( element.attribute("nouploadurl") ) ); + + d_prov(this)->mDownloadUrlLatest = KURL( element.attribute("downloadurl-latest") ); + d_prov(this)->mDownloadUrlScore = KURL( element.attribute("downloadurl-score") ); + d_prov(this)->mDownloadUrlDownloads = KURL( element.attribute("downloadurl-downloads") ); + + KURL iconurl( element.attribute("icon") ); + if(!iconurl.isValid()) iconurl.setPath( element.attribute("icon") ); + setIcon( iconurl ); + + QDomNode n; + for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement p = n.toElement(); + + if ( p.tagName() == "noupload" ) setNoUpload( true ); + if ( p.tagName() == "title" ) setName( p.text().stripWhiteSpace() ); + } +} + +QDomElement Provider::createDomElement( QDomDocument &doc, QDomElement &parent ) +{ + QDomElement entry = doc.createElement( "stuff" ); + parent.appendChild( entry ); + + QDomElement n = doc.createElement( "name" ); + n.appendChild( doc.createTextNode( name() ) ); + entry.appendChild( n ); + + return entry; +} + + +ProviderLoader::ProviderLoader( QWidget *parentWidget ) : + QObject( parentWidget ) +{ + mProviders.setAutoDelete( true ); +} + +void ProviderLoader::load( const QString &type, const QString &providersList ) +{ + kdDebug() << "ProviderLoader::load()" << endl; + + mProviders.clear(); + mJobData = ""; + + KConfig *cfg = KGlobal::config(); + cfg->setGroup("KNewStuff"); + + QString providersUrl = providersList; + if( providersUrl.isEmpty() ) + providersUrl = cfg->readEntry( "ProvidersUrl" ); + + if ( providersUrl.isEmpty() ) { + // TODO: Replace the default by the real one. + QString server = cfg->readEntry( "MasterServer", + "http://korganizer.kde.org" ); + + providersUrl = server + "/knewstuff/" + type + "/providers.xml"; + } + + kdDebug() << "ProviderLoader::load(): providersUrl: " << providersUrl << endl; + + KIO::TransferJob *job = KIO::get( KURL( providersUrl ), false, false ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotJobResult( KIO::Job * ) ) ); + connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ), + SLOT( slotJobData( KIO::Job *, const QByteArray & ) ) ); + +// job->dumpObjectInfo(); +} + +void ProviderLoader::slotJobData( KIO::Job *, const QByteArray &data ) +{ + kdDebug() << "ProviderLoader::slotJobData()" << endl; + + if ( data.size() == 0 ) return; + + QCString str( data, data.size() + 1 ); + + mJobData.append( QString::fromUtf8( str ) ); +} + +void ProviderLoader::slotJobResult( KIO::Job *job ) +{ + if ( job->error() ) { + job->showErrorDialog( static_cast<QWidget *>(parent()) ); + } + + kdDebug() << "--PROVIDERS-START--" << endl << mJobData << "--PROV_END--" + << endl; + + QDomDocument doc; + if ( !doc.setContent( mJobData ) ) { + KMessageBox::error( static_cast<QWidget *>(parent()), i18n("Error parsing providers list.") ); + return; + } + + QDomElement providers = doc.documentElement(); + + if ( providers.isNull() ) { + kdDebug() << "No document in Providers.xml." << endl; + } + + QDomNode n; + for ( n = providers.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement p = n.toElement(); + + if ( p.tagName() == "provider" ) { + mProviders.append( new Provider( p ) ); + } + } + + emit providersLoaded( &mProviders ); +} diff --git a/knewstuff/provider.h b/knewstuff/provider.h new file mode 100644 index 000000000..e990fa919 --- /dev/null +++ b/knewstuff/provider.h @@ -0,0 +1,214 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFF_PROVIDER_H +#define KNEWSTUFF_PROVIDER_H + +#include <qcstring.h> +#include <qdom.h> +#include <qobject.h> +#include <qptrlist.h> +#include <qstring.h> + +#include <kurl.h> + +namespace KIO { class Job; } + +namespace KNS { + +/** + * @short KNewStuff provider container. + * + * This class provides accessors for the provider object. + * as used by KNewStuff. + * It should probably not be used directly by the application. + * + * @author Cornelius Schumacher (schumacher@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + */ +class KDE_EXPORT Provider +{ + public: + typedef QPtrList<Provider> List; + + /** + * Constructor. + */ + Provider(); + + /** + * Constructor with XML feed. + */ + Provider( const QDomElement & ); + + /** + * Destructor. + */ + ~Provider(); + + /** + * Sets the common name of the provider. + */ + void setName( const QString & ); + + /** + * Retrieves the common name of the provider. + * + * @return provider name + */ + QString name() const; + + /** + * Sets the download URL. + */ + void setDownloadUrl( const KURL & ); + + /** + * Retrieves the download URL. + * + * @return download URL + */ + KURL downloadUrl() const; + + /** + * Variant to retrieve 'tagged' download URLs. + * Variant can be one of 'score', 'downloads', 'latest'. + * + * @return download specific URL + */ + KURL downloadUrlVariant( QString variant ) const; + + /** + * Sets the upload URL. + */ + void setUploadUrl( const KURL & ); + + /** + * Retrieves the upload URL. + * + * @return upload URL + */ + KURL uploadUrl() const; + + /** + * Sets the URL where a user is led if the provider does not support + * uploads. + * + * @see setNoUpload + */ + void setNoUploadUrl( const KURL & ); + + /** + * Retrieves the URL where a user is led if the provider does not + * support uploads. + * + * @return website URL + */ + KURL noUploadUrl() const; + + /** + * Indicate whether provider supports uploads. + */ + void setNoUpload( bool ); + + /** + * Query whether provider supports uploads. + * + * @return upload support status + */ + bool noUpload() const; + + /** + * Sets the URL for an icon for this provider. + * The icon should be in 32x32 format. If not set, the default icon + * of KDialogBase is used. + */ + void setIcon( const KURL & ); + + /** + * Retrieves the icon URL for this provider. + * + * @return icon URL + */ + KURL icon() const; + + protected: + void parseDomElement( const QDomElement & ); + + QDomElement createDomElement( QDomDocument &, QDomElement &parent ); + + private: + QString mName; + KURL mDownloadUrl; + KURL mUploadUrl; + KURL mNoUploadUrl; + KURL mIcon; + bool mNoUpload; +}; + +/** + * KNewStuff provider loader. + * This class sets up a list of all possible providers by querying + * the main provider database for this specific application. + * It should probably not be used directly by the application. + */ +class KDE_EXPORT ProviderLoader : public QObject +{ + Q_OBJECT + public: + /** + * Constructor. + * + * @param parentWidget the parent widget + */ + ProviderLoader( QWidget *parentWidget ); + + /** + * Starts asynchronously loading the list of providers of the + * specified type. + * + * @param type data type such as 'kdesktop/wallpaper'. + * @param providerList the URl to the list of providers; if empty + * we first try the ProvidersUrl from KGlobal::config, then we + * fall back to a hardcoded value. + */ + void load( const QString &type, const QString &providerList = QString::null ); + + signals: + /** + * Indicates that the list of providers has been successfully loaded. + */ + void providersLoaded( Provider::List * ); + + protected slots: + void slotJobData( KIO::Job *, const QByteArray & ); + void slotJobResult( KIO::Job * ); + + private: + QWidget *mParentWidget; + + QString mJobData; + + Provider::List mProviders; +}; + +} + +#endif diff --git a/knewstuff/providerdialog.cpp b/knewstuff/providerdialog.cpp new file mode 100644 index 000000000..00374a341 --- /dev/null +++ b/knewstuff/providerdialog.cpp @@ -0,0 +1,95 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qlayout.h> +#include <qstring.h> +#include <qlabel.h> + +#include <klistview.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include "engine.h" +#include "provider.h" + +#include "providerdialog.h" +#include "providerdialog.moc" + +using namespace KNS; + +class ProviderItem : public KListViewItem +{ + public: + ProviderItem( KListView *parent, Provider *provider ) : + KListViewItem( parent ), mProvider( provider ) + { + setText( 0, provider->name() ); + } + + Provider *provider() { return mProvider; } + + private: + Provider *mProvider; +}; + +ProviderDialog::ProviderDialog( Engine *engine, QWidget *parent ) : + KDialogBase( Plain, i18n("Hot New Stuff Providers"), Ok | Cancel, Cancel, + parent, 0, false, true ), + mEngine( engine ) +{ + QFrame *topPage = plainPage(); + + QBoxLayout *topLayout = new QVBoxLayout( topPage ); + + QLabel *description = new QLabel( i18n("Please select one of the providers listed below:"), topPage ); + topLayout->addWidget( description ); + + mListView = new KListView( topPage ); + mListView->addColumn( i18n("Name") ); + topLayout->addWidget( mListView ); +} + +void ProviderDialog::clear() +{ + mListView->clear(); +} + +void ProviderDialog::addProvider( Provider *provider ) +{ + new ProviderItem( mListView, provider ); + if ( mListView->childCount() == 1 ) { + mListView->setSelected(mListView->firstChild(), true); + } else if (mListView->childCount() > 1) { + mListView->setSelected(mListView->firstChild(), false); + } +} + +void ProviderDialog::slotOk() +{ + ProviderItem *item = static_cast<ProviderItem *>( mListView->selectedItem() ); + if ( !item ) { + KMessageBox::error( this, i18n("No provider selected.") ); + return; + } + + mEngine->requestMetaInformation( item->provider() ); + + accept(); +} diff --git a/knewstuff/providerdialog.h b/knewstuff/providerdialog.h new file mode 100644 index 000000000..c75cc3a1d --- /dev/null +++ b/knewstuff/providerdialog.h @@ -0,0 +1,76 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFF_PROVIDERDIALOG_H +#define KNEWSTUFF_PROVIDERDIALOG_H + +#include <kdialogbase.h> + +class KListView; + +namespace KNS { + +class Provider; +class Engine; + +/** + * @short Dialog displaying a list of Hotstuff providers. + * + * This is normally used in the process of uploading data, thus limiting the + * list to providers which support uploads. + * One of the providers is then chosen by the user for further operation. + * + * @author Cornelius Schumacher (schumacher@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + */ +class ProviderDialog : public KDialogBase +{ + Q_OBJECT + public: + /** + Constructor. + + @param engine a KNewStuff engine object + @param parent the parent window + */ + ProviderDialog( Engine *engine, QWidget *parent ); + + /** + Clears the list of providers. + */ + void clear(); + + /** + Adds a Hotstuff provider to the list. + */ + void addProvider( Provider * ); + + protected slots: + void slotOk(); + + private: + Engine *mEngine; + + KListView *mListView; +}; + +} + +#endif diff --git a/knewstuff/security.cpp b/knewstuff/security.cpp new file mode 100644 index 000000000..f7099c722 --- /dev/null +++ b/knewstuff/security.cpp @@ -0,0 +1,344 @@ +/*************************************************************************** + security.cpp - description + ------------------- + begin : Thu Jun 24 11:22:12 2004 + copyright : (C) 2004, 2005 by Andras Mantia <amantia@kde.org> + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ + + //qt includes +#include <qfile.h> +#include <qfileinfo.h> +#include <qstringlist.h> +#include <qtimer.h> + + //kde includes +#include <kdebug.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kmdcodec.h> +#include <kmessagebox.h> +#include <kpassdlg.h> +#include <kprocio.h> + + //app includes +#include "security.h" + +using namespace KNS; + +Security::Security() +{ + m_keysRead = false; + m_gpgRunning = false; + readKeys(); + readSecretKeys(); +} + + +Security::~Security() +{ +} + +void Security::readKeys() +{ + if (m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(readKeys())); + return; + } + m_runMode = List; + m_keys.clear(); + KProcIO *readProcess=new KProcIO(); + *readProcess << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-keys"; + connect(readProcess, SIGNAL(processExited(KProcess *)), this, SLOT(slotProcessExited(KProcess *))); + connect(readProcess, SIGNAL(readReady(KProcIO *)) ,this, SLOT(slotDataArrived(KProcIO *))); + if (!readProcess->start(KProcess::NotifyOnExit, true)) + KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and retrieve the available keys. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>")); + else + m_gpgRunning = true; +} + +void Security::readSecretKeys() +{ + if (m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(readSecretKeys())); + return; + } + m_runMode = ListSecret; + KProcIO *readProcess=new KProcIO(); + *readProcess << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-secret-keys"; + connect(readProcess, SIGNAL(processExited(KProcess *)), this, SLOT(slotProcessExited(KProcess *))); + connect(readProcess, SIGNAL(readReady(KProcIO *)) ,this, SLOT(slotDataArrived(KProcIO *))); + if (readProcess->start(KProcess::NotifyOnExit, true)) + m_gpgRunning = true; +} + +void Security::slotProcessExited(KProcess *process) +{ + switch (m_runMode) + { + case ListSecret: + m_keysRead = true; + break; + case Verify: emit validityResult(m_result); + break; + case Sign: emit fileSigned(m_result); + break; + + } + m_gpgRunning = false; + delete process; +} + +void Security::slotDataArrived(KProcIO *procIO) +{ + QString data; + while (procIO->readln(data, true) != -1) + { + switch (m_runMode) + { + case List: + case ListSecret: + if (data.startsWith("pub") || data.startsWith("sec")) + { + KeyStruct key; + if (data.startsWith("pub")) + key.secret = false; + else + key.secret = true; + QStringList line = QStringList::split(":", data, true); + key.id = line[4]; + QString shortId = key.id.right(8); + QString trustStr = line[1]; + key.trusted = false; + if (trustStr == "u" || trustStr == "f") + key.trusted = true; + data = line[9]; + key.mail=data.section('<', -1, -1); + key.mail.truncate(key.mail.length() - 1); + key.name=data.section('<',0,0); + if (key.name.find("(")!=-1) + key.name=key.name.section('(',0,0); + m_keys[shortId] = key; + } + break; + case Verify: + data = data.section("]",1,-1).stripWhiteSpace(); + if (data.startsWith("GOODSIG")) + { + m_result &= SIGNED_BAD_CLEAR; + m_result |= SIGNED_OK; + QString id = data.section(" ", 1 , 1).right(8); + if (!m_keys.contains(id)) + { + m_result |= UNKNOWN; + } else + { + m_signatureKey = m_keys[id]; + } + } else + if (data.startsWith("NO_PUBKEY")) + { + m_result &= SIGNED_BAD_CLEAR; + m_result |= UNKNOWN; + } else + if (data.startsWith("BADSIG")) + { + m_result |= SIGNED_BAD; + QString id = data.section(" ", 1 , 1).right(8); + if (!m_keys.contains(id)) + { + m_result |= UNKNOWN; + } else + { + m_signatureKey = m_keys[id]; + } + } else + if (data.startsWith("TRUST_ULTIMATE")) + { + m_result &= SIGNED_BAD_CLEAR; + m_result |= TRUSTED; + } + break; + + case Sign: + if (data.find("passphrase.enter") != -1) + { + QCString password; + KeyStruct key = m_keys[m_secretKey]; + int result = KPasswordDialog::getPassword(password, i18n("<qt>Enter passphrase for key <b>0x%1</b>, belonging to<br><i>%2<%3></i>:</qt>").arg(m_secretKey).arg(key.name).arg(key.mail)); + if (result == KPasswordDialog::Accepted) + { + procIO->writeStdin(password, true); + password.fill(' '); + } + else + { + m_result |= BAD_PASSPHRASE; + slotProcessExited(procIO); + return; + } + } else + if (data.find("BAD_PASSPHRASE") != -1) + { + m_result |= BAD_PASSPHRASE; + } + break; + } + } +} + +void Security::checkValidity(const QString& filename) +{ + m_fileName = filename; + slotCheckValidity(); +} + +void Security::slotCheckValidity() +{ + if (!m_keysRead || m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(slotCheckValidity())); + return; + } + if (m_keys.count() == 0) + { + emit validityResult(-1); + return; + } + + m_result = 0; + m_runMode = Verify; + QFileInfo f(m_fileName); + //check the MD5 sum + QString md5sum; + const char* c = ""; + KMD5 context(c); + QFile file(m_fileName); + if (file.open(IO_ReadOnly)) + { + context.reset(); + context.update(file); + md5sum = context.hexDigest(); + file.close(); + } + file.setName(f.dirPath() + "/md5sum"); + if (file.open(IO_ReadOnly)) + { + QString md5sum_file; + file.readLine(md5sum_file, 50); + if (!md5sum.isEmpty() && !md5sum_file.isEmpty() && md5sum_file.startsWith(md5sum)) + m_result |= MD5_OK; + file.close(); + } + m_result |= SIGNED_BAD; + m_signatureKey.id = ""; + m_signatureKey.name = ""; + m_signatureKey.mail = ""; + m_signatureKey.trusted = false; + + //verify the signature + KProcIO *verifyProcess=new KProcIO(); + *verifyProcess<<"gpg"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--verify" << f.dirPath() + "/signature"<< m_fileName; + connect(verifyProcess, SIGNAL(processExited(KProcess *)),this, SLOT(slotProcessExited(KProcess *))); + connect(verifyProcess, SIGNAL(readReady(KProcIO *)),this, SLOT(slotDataArrived(KProcIO *))); + if (verifyProcess->start(KProcess::NotifyOnExit,true)) + m_gpgRunning = true; + else + { + KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and check the validity of the file. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>")); + emit validityResult(0); + delete verifyProcess; + } +} + +void Security::signFile(const QString &fileName) +{ + m_fileName = fileName; + slotSignFile(); +} + +void Security::slotSignFile() +{ + if (!m_keysRead || m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(slotSignFile())); + return; + } + + QStringList secretKeys; + for (QMap<QString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it) + { + if (it.data().secret) + secretKeys.append(it.key()); + } + + if (secretKeys.count() == 0) + { + emit fileSigned(-1); + return; + } + + m_result = 0; + QFileInfo f(m_fileName); + + //create the MD5 sum + QString md5sum; + const char* c = ""; + KMD5 context(c); + QFile file(m_fileName); + if (file.open(IO_ReadOnly)) + { + context.reset(); + context.update(file); + md5sum = context.hexDigest(); + file.close(); + } + file.setName(f.dirPath() + "/md5sum"); + if (file.open(IO_WriteOnly)) + { + QTextStream stream(&file); + stream << md5sum; + m_result |= MD5_OK; + file.close(); + } + + if (secretKeys.count() > 1) + { + bool ok; + secretKeys = KInputDialog::getItemList(i18n("Select Signing Key"), i18n("Key used for signing:"), secretKeys, secretKeys[0], false, &ok); + if (ok) + m_secretKey = secretKeys[0]; + else + { + emit fileSigned(0); + return; + } + } else + m_secretKey = secretKeys[0]; + + //verify the signature + KProcIO *signProcess=new KProcIO(); + *signProcess<<"gpg"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--no-tty"<<"--detach-sign" << "-u" << m_secretKey << "-o" << f.dirPath() + "/signature" << m_fileName; + connect(signProcess, SIGNAL(processExited(KProcess *)),this, SLOT(slotProcessExited(KProcess *))); + connect(signProcess, SIGNAL(readReady(KProcIO *)),this, SLOT(slotDataArrived(KProcIO *))); + m_runMode = Sign; + if (signProcess->start(KProcess::NotifyOnExit,true)) + m_gpgRunning = true; + else + { + KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and sign the file. Make sure that <i>gpg</i> is installed, otherwise signing of the resources will not be possible.</qt>")); + emit fileSigned(0); + delete signProcess; + } +} + +#include "security.moc" diff --git a/knewstuff/security.h b/knewstuff/security.h new file mode 100644 index 000000000..03117fd96 --- /dev/null +++ b/knewstuff/security.h @@ -0,0 +1,141 @@ +/*************************************************************************** + security.h - description + ------------------- + begin : Thu Jun 24 11:22:12 2004 + copyright : (C) 2004, 2005 by Andras Mantia <amantia@kde.org> + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ + + +#ifndef SECURITY_H +#define SECURITY_H + +//qt includes +#include <qmap.h> +#include <qobject.h> + +class KProcIO; +class KProcess; + +struct KeyStruct { + QString id; + QString name; + QString mail; + bool trusted; + bool secret; +}; + +/** +Handles security releated issues, like signing, verifying. +It is a private class, not meant to be used by third party applications. + +@author Andras Mantia <amantia@kde.org> +*/ + +namespace KNS { + +class Security : public QObject +{ +Q_OBJECT +public: + static Security* const ref() + { + static Security *m_ref; + if (!m_ref) m_ref = new Security(); + return m_ref; + } + ~Security(); + + + /** Verifies the integrity and the signature of a tarball file. + * @param fileName the file to be verified. It should be a tar.gz (.tgz) file. The directory where + * the file is should contain a "signature" and a "md5sum" file, otherwise verification will fail. + * The method is asynchronous and the result is signalled with @ref validityResult. + */ + void checkValidity(const QString &fileName); + + /** Creates a signature and an md5sum file for the fileName and packs + * everything into a gzipped tarball. + * @param fileName the file with full path to sign + * + * The method is asynchronous and the result is signalled with @ref fileSigned. + */ + void signFile(const QString &fileName); + /** Get the key used for signing. This method is valid only if: + * - the checkValidity was called + * - the result of the validity check does not have the UNKNOWN bit set + * + * @return the key used for signing the file + */ + KeyStruct signatureKey() {return m_signatureKey;} + + enum Results { + MD5_OK = 1, /// The MD5 sum check is OK + SIGNED_OK = 2, /// The file is signed with a good signature + SIGNED_BAD = 4, /// The file is signed with a bad signature + TRUSTED = 8, /// The signature is trusted + UNKNOWN = 16, ///The key is unknown + SIGNED_BAD_CLEAR = 27, ///used to clear the SIGNED_BAD flag + BAD_PASSPHRASE = 32 ///wrong passhprase entered + }; + +public slots: + /** Reads the available public keys */ + void readKeys(); + /** Reads the available secret keys */ + void readSecretKeys(); + /** Verifies the integrity and the signature of a tarball file (see m_fileName). + */ + void slotCheckValidity(); + + /** Creates a signature and an md5sum file for the m_fileName and packs + * everything into a gzipped tarball. + */ + void slotSignFile(); + +private: + Security(); + + enum RunMode { + List = 0, ///read the public keys + ListSecret, ///read the secret keys + Verify, ///verify the signature + Sign ///create signature + }; + + KeyStruct m_signatureKey; + int m_result; + int m_runMode; + bool m_gpgRunning; /// true if gpg is currently running + bool m_keysRead; /// true if all the keys were read + QMap<QString, KeyStruct> m_keys; /// holds information about the available key + QString m_fileName; /// the file to sign/verify + QString m_secretKey; /// the key used for signing + +private slots: + void slotProcessExited(KProcess *process); + void slotDataArrived(KProcIO *process); + +signals: + /** Sent when the validity check is done. + * + * @return the result of the check. See @ref Results + */ + void validityResult(int result); + /** Sent when the signing is done. + * + * @return the result of the operation. See @ref Results + */ + void fileSigned(int result); +}; + +} + +#endif diff --git a/knewstuff/testnewstuff.cpp b/knewstuff/testnewstuff.cpp new file mode 100644 index 000000000..f9bc84ef2 --- /dev/null +++ b/knewstuff/testnewstuff.cpp @@ -0,0 +1,120 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <iostream> + +#include <qlayout.h> +#include <qfile.h> +#include <qtextstream.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kprocess.h> +#include <kdialog.h> + +#include "testnewstuff.h" +#include "testnewstuff.moc" + +using namespace std; + +bool TestNewStuff::install( const QString &fileName ) +{ + kdDebug() << "TestNewStuff::install(): " << fileName << endl; + QFile f( fileName ); + if ( !f.open( IO_ReadOnly ) ) { + kdDebug() << "Error opening file." << endl; + return false; + } + QTextStream ts( &f ); + kdDebug() << "--BEGIN-NEW_STUFF--" << endl; + cout << ts.read().utf8(); + kdDebug() << "---END-NEW_STUFF---" << endl; + return true; +} + +bool TestNewStuff::createUploadFile( const QString &fileName ) +{ + KProcess p; + p << "touch" << fileName; + p.start(KProcess::Block); + kdDebug() << "TestNewStuff::createUploadFile(): " << fileName << endl; + return true; +} + + +MyWidget::MyWidget() +{ + mNewStuff = new TestNewStuff; + + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setMargin( KDialog::marginHint() ); + topLayout->setSpacing( KDialog::spacingHint() ); + + QPushButton *downloadButton = new QPushButton( "Download", this ); + topLayout->addWidget( downloadButton ); + connect( downloadButton, SIGNAL( clicked() ), SLOT( download() ) ); + + QPushButton *uploadButton = new QPushButton( "Upload", this ); + topLayout->addWidget( uploadButton ); + connect( uploadButton, SIGNAL( clicked() ), SLOT( upload() ) ); + + topLayout->addSpacing( 5 ); + + QPushButton *closeButton = new QPushButton( "Close", this ); + topLayout->addWidget( closeButton ); + connect( closeButton, SIGNAL( clicked() ), kapp, SLOT( quit() ) ); +} + +MyWidget::~MyWidget() +{ + delete mNewStuff; +} + +void MyWidget::download() +{ + kdDebug() << "MyWidget::download()" << endl; + + mNewStuff->download(); +} + +void MyWidget::upload() +{ + kdDebug() << "MyWidget::download()" << endl; + + mNewStuff->upload(); +} + + +int main(int argc,char **argv) +{ + KAboutData aboutData("knewstufftest","KNewStuff Test","0.1"); + KCmdLineArgs::init(argc,argv,&aboutData); + + KApplication app; + + MyWidget wid; + app.setMainWidget( &wid ); + wid.show(); + + app.exec(); +} diff --git a/knewstuff/testnewstuff.h b/knewstuff/testnewstuff.h new file mode 100644 index 000000000..b1981f723 --- /dev/null +++ b/knewstuff/testnewstuff.h @@ -0,0 +1,58 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef TESTNEWSTUFF_H +#define TESTNEWSTUFF_H + +#include <stdlib.h> + +#include <qpushbutton.h> + +#include <kapplication.h> +#include <kdebug.h> + +#include "knewstuff.h" + +class TestNewStuff : public KNewStuff +{ + public: + TestNewStuff() : KNewStuff( "korganizer/calendar" ) {} + + bool install( const QString &fileName ); + + bool createUploadFile( const QString &fileName ); +}; + +class MyWidget : public QWidget +{ + Q_OBJECT + public: + MyWidget(); + ~MyWidget(); + + public slots: + void upload(); + void download(); + + private: + KNewStuff *mNewStuff; +}; + +#endif diff --git a/knewstuff/types b/knewstuff/types new file mode 100644 index 000000000..6f47cbf63 --- /dev/null +++ b/knewstuff/types @@ -0,0 +1,7 @@ +[kdesktop/wallpaper] +StandardResource=wallpaper +InstallationCommand=dcop kdesktop KBackgroundIface setWallpaper %f 2 + +[kamikaze/level] +TargetDir=kamikaze + diff --git a/knewstuff/uploaddialog.cpp b/knewstuff/uploaddialog.cpp new file mode 100644 index 000000000..433cb9c4c --- /dev/null +++ b/knewstuff/uploaddialog.cpp @@ -0,0 +1,206 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qcombobox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qspinbox.h> +#include <qstring.h> +#include <ktextedit.h> + +#include <klistview.h> +#include <klocale.h> +#include <kdebug.h> +#include <kurlrequester.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kuser.h> + +#include "engine.h" +#include "entry.h" + +#include "uploaddialog.h" +#include "uploaddialog.moc" + +using namespace KNS; + +UploadDialog::UploadDialog( Engine *engine, QWidget *parent ) : + KDialogBase( Plain, i18n("Share Hot New Stuff"), Ok | Cancel, Cancel, + parent, 0, false, true ), + mEngine( engine ) +{ + mEntryList.setAutoDelete( true ); + + QFrame *topPage = plainPage(); + + QGridLayout *topLayout = new QGridLayout( topPage ); + topLayout->setSpacing( spacingHint() ); + + QLabel *nameLabel = new QLabel( i18n("Name:"), topPage ); + topLayout->addWidget( nameLabel, 0, 0 ); + mNameEdit = new QLineEdit( topPage ); + topLayout->addWidget( mNameEdit, 0, 1 ); + + QLabel *authorLabel = new QLabel( i18n("Author:"), topPage ); + topLayout->addWidget( authorLabel, 1, 0 ); + mAuthorEdit = new QLineEdit( topPage ); + topLayout->addWidget( mAuthorEdit, 1, 1 ); + + QLabel *emailLabel = new QLabel( i18n("Email:"), topPage ); + topLayout->addWidget( emailLabel, 2, 0 ); + mEmailEdit = new QLineEdit( topPage ); + topLayout->addWidget( mEmailEdit, 2, 1 ); + + QLabel *versionLabel = new QLabel( i18n("Version:"), topPage ); + topLayout->addWidget( versionLabel, 3, 0 ); + mVersionEdit = new QLineEdit( topPage ); + topLayout->addWidget( mVersionEdit, 3, 1 ); + + QLabel *releaseLabel = new QLabel( i18n("Release:"), topPage ); + topLayout->addWidget( releaseLabel, 4, 0 ); + mReleaseSpin = new QSpinBox( topPage ); + mReleaseSpin->setMinValue( 1 ); + topLayout->addWidget( mReleaseSpin, 4, 1 ); + + QLabel *licenceLabel = new QLabel( i18n("License:"), topPage ); + topLayout->addWidget( licenceLabel, 5, 0 ); + mLicenceCombo = new QComboBox( topPage ); + mLicenceCombo->setEditable( true ); + mLicenceCombo->insertItem( i18n("GPL") ); + mLicenceCombo->insertItem( i18n("LGPL") ); + mLicenceCombo->insertItem( i18n("BSD") ); + topLayout->addWidget( mLicenceCombo, 5, 1 ); + + QLabel *languageLabel = new QLabel( i18n("Language:"), topPage ); + topLayout->addWidget( languageLabel, 6, 0 ); + mLanguageCombo = new QComboBox( topPage ); + topLayout->addWidget( mLanguageCombo, 6, 1 ); + mLanguageCombo->insertStringList( KGlobal::locale()->languageList() ); + + QLabel *previewLabel = new QLabel( i18n("Preview URL:"), topPage ); + topLayout->addWidget( previewLabel, 7, 0 ); + mPreviewUrl = new KURLRequester( topPage ); + topLayout->addWidget( mPreviewUrl, 7, 1 ); + + QLabel *summaryLabel = new QLabel( i18n("Summary:"), topPage ); + topLayout->addMultiCellWidget( summaryLabel, 8, 8, 0, 1 ); + mSummaryEdit = new KTextEdit( topPage ); + topLayout->addMultiCellWidget( mSummaryEdit, 9, 9, 0, 1 ); + + KUser user; + mAuthorEdit->setText(user.fullName()); +} + +UploadDialog::~UploadDialog() +{ + mEntryList.clear(); +} + +void UploadDialog::slotOk() +{ + if ( mNameEdit->text().isEmpty() ) { + KMessageBox::error( this, i18n("Please put in a name.") ); + return; + } + + Entry *entry = new Entry; + + mEntryList.append( entry ); + + entry->setName( mNameEdit->text() ); + entry->setAuthor( mAuthorEdit->text() ); + entry->setAuthorEmail( mEmailEdit->text() ); + entry->setVersion( mVersionEdit->text() ); + entry->setRelease( mReleaseSpin->value() ); + entry->setLicence( mLicenceCombo->currentText() ); + entry->setPreview( KURL( mPreviewUrl->url().section("/", -1) ), mLanguageCombo->currentText() ); + entry->setSummary( mSummaryEdit->text(), mLanguageCombo->currentText() ); + + if ( mPayloadUrl.isValid() ) { + KConfig *conf = kapp->config(); + conf->setGroup( QString("KNewStuffUpload:%1").arg(mPayloadUrl.fileName()) ); + conf->writeEntry("name", mNameEdit->text()); + conf->writeEntry("author", mAuthorEdit->text()); + conf->writeEntry("email", mEmailEdit->text()); + conf->writeEntry("version", mVersionEdit->text()); + conf->writeEntry("release", mReleaseSpin->value()); + conf->writeEntry("licence", mLicenceCombo->currentText()); + conf->writeEntry("preview", mPreviewUrl->url()); + conf->writeEntry("summary", mSummaryEdit->text()); + conf->writeEntry("language", mLanguageCombo->currentText()); + conf->sync(); + } + + mEngine->upload( entry ); + + accept(); +} + +void UploadDialog::setPreviewFile( const QString &previewFile ) +{ + mPreviewUrl->setURL( previewFile ); +} + +void UploadDialog::setPayloadFile( const QString &payloadFile ) +{ + mPayloadUrl = payloadFile; + + KConfig *conf = kapp->config(); + conf->setGroup( QString("KNewStuffUpload:%1").arg(mPayloadUrl.fileName()) ); + QString name = conf->readEntry("name"); + QString author = conf->readEntry("author"); + QString email = conf->readEntry("email"); + QString version = conf->readEntry("version"); + QString release = conf->readEntry("release"); + QString preview = conf->readEntry("preview"); + QString summary = conf->readEntry("summary"); + QString lang = conf->readEntry("language"); + QString licence = conf->readEntry("licence"); + + mNameEdit->clear(); + mAuthorEdit->clear(); + mEmailEdit->clear(); + mVersionEdit->clear(); + mReleaseSpin->setValue(1); + mPreviewUrl->clear(); + mSummaryEdit->clear(); + mLanguageCombo->setCurrentItem(0); + mLicenceCombo->setCurrentItem(0); + + if(!name.isNull()) + { + int prefill = KMessageBox::questionYesNo(this, i18n("Old upload information found, fill out fields?"),QString::null,i18n("Fill Out"),i18n("Do Not Fill Out")); + if(prefill == KMessageBox::Yes) + { + mNameEdit->setText(name); + mAuthorEdit->setText(author); + mEmailEdit->setText(email); + mVersionEdit->setText(version); + mReleaseSpin->setValue(release.toInt()); + mPreviewUrl->setURL(preview); + mSummaryEdit->setText(summary); + if(!lang.isEmpty()) mLanguageCombo->setCurrentText(lang); + if(!licence.isEmpty()) mLicenceCombo->setCurrentText(licence); + } + } +} + diff --git a/knewstuff/uploaddialog.h b/knewstuff/uploaddialog.h new file mode 100644 index 000000000..c76de02df --- /dev/null +++ b/knewstuff/uploaddialog.h @@ -0,0 +1,103 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KNEWSTUFF_UPLOADDIALOG_H +#define KNEWSTUFF_UPLOADDIALOG_H + +#include <kdialogbase.h> + +class QLineEdit; +class QSpinBox; +class KURLRequester; +class QTextEdit; +class QComboBox; + +namespace KNS { + +class Engine; +class Entry; + +/** + * @short KNewStuff file upload dialog. + * + * Using this dialog, data can easily be uploaded to the Hotstuff servers. + * It should however not be used on its own, instead a KNewStuff (or + * KNewStuffGeneric) object invokes it. + * + * @author Cornelius Schumacher (schumacher@kde.org) + * \par Maintainer: + * Josef Spillner (spillner@kde.org) + */ +class UploadDialog : public KDialogBase +{ + Q_OBJECT + public: + /** + Constructor. + + @param engine a KNewStuff engine object to be used for uploads + @param parent the parent window + */ + UploadDialog( Engine *engine, QWidget *parent ); + + /** + Destructor. + */ + ~UploadDialog(); + + /** + Sets the preview filename. + This is only meaningful if the application supports previews. + + @param previewFile the preview image file + */ + void setPreviewFile( const QString &previewFile ); + + /** + Sets the payload filename. + This is optional, but necessary if the application wants to support + reusing previously filled out form data based on the filename. + + @param payloadFile the payload data file + */ + void setPayloadFile( const QString &payloadFile ); + + protected slots: + void slotOk(); + + private: + Engine *mEngine; + + QLineEdit *mNameEdit; + QLineEdit *mAuthorEdit; + QLineEdit *mEmailEdit; + QLineEdit *mVersionEdit; + QSpinBox *mReleaseSpin; + KURLRequester *mPreviewUrl; + QTextEdit *mSummaryEdit; + QComboBox *mLanguageCombo; + QComboBox *mLicenceCombo; + + QPtrList<Entry> mEntryList; + KURL mPayloadUrl; +}; + +} + +#endif |