Page MenuHomePhorge

nntpresource.cpp
No OneTemporary

nntpresource.cpp

/*
Copyright (c) 2007 Volker Krause <vkrause@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 "nntpresource.h"
#include "nntpcollectionattribute.h"
#include "configdialog.h"
#include "settings.h"
#include "settingsadaptor.h"
#include <attributefactory.h>
#include <cachepolicy.h>
#include <collectionmodifyjob.h>
#include <itemcreatejob.h>
#include <akonadi/kmime/messageparts.h>
#include <monitor.h>
#include <session.h>
#include <changerecorder.h>
#include <kmime/kmime_message.h>
#include <kmime/kmime_newsarticle.h>
#include <kmime/kmime_util.h>
#include <KWindowSystem>
#include <KLocalizedString>
#include <KIcon>
#include <QDateTime>
#include <QDir>
#include <QInputDialog>
#include <QLineEdit>
#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<KMime::Message> MessagePtr;
using namespace Akonadi;
NntpResource::NntpResource(const QString & id)
: ResourceBase( id )
{
AttributeFactory::registerAttribute<NntpCollectionAttribute>();
changeRecorder()->fetchCollection( true );
new SettingsAdaptor( Settings::self() );
QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ),
Settings::self(), QDBusConnection::ExportAdaptors );
}
NntpResource::~ NntpResource()
{
}
bool NntpResource::retrieveItem(const Akonadi::Item& item, const QSet<QByteArray> &parts)
{
Q_UNUSED( parts );
KIO::Job* job = KIO::storedGet( KUrl( item.remoteId() ), KIO::NoReload, KIO::HideProgressInfo );
setupKioJob( job );
connect( job, SIGNAL(result(KJob*)), SLOT(fetchArticleResult(KJob*)) );
return true;
}
void NntpResource::retrieveCollections()
{
remoteCollections.clear();
Collection rootCollection;
rootCollection.setParentCollection( Collection::root() );
rootCollection.setRemoteId( baseUrl().url() );
rootCollection.setName( Settings::self()->name() );
CachePolicy policy;
policy.setInheritFromParent( false );
policy.setSyncOnDemand( true );
policy.setLocalParts( QStringList( MessagePart::Envelope ) );
rootCollection.setCachePolicy( policy );
QStringList contentTypes;
contentTypes << Collection::mimeType();
rootCollection.setContentMimeTypes( contentTypes );
remoteCollections << rootCollection;
KUrl url = baseUrl();
QDate lastList = Settings::self()->lastGroupList().date();
if ( lastList.isValid() ) {
mIncremental = true;
url.addQueryItem( "since", QString( "%1%2%3 000000" )
.arg( lastList.year() % 100, 2, 10, QChar( '0' ) )
.arg( lastList.month(), 2, 10, QChar( '0' ) )
.arg( lastList.day(), 2, 10, QChar( '0' ) ) );
} else {
mIncremental = false;
}
KIO::ListJob* job = KIO::listDir( url, KIO::HideProgressInfo, true );
setupKioJob( job );
connect( job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)),
SLOT(listGroups(KIO::Job*,KIO::UDSEntryList)) );
connect( job, SIGNAL(result(KJob*)), SLOT(listGroupsResult(KJob*)) );
}
void NntpResource::retrieveItems( const Akonadi::Collection & col )
{
if ( !(col.contentMimeTypes().count() == 1 && col.contentMimeTypes().first() == "message/news" ) ) {
// not a newsgroup, skip it
itemsRetrievalDone();
return;
}
KUrl url = baseUrl();
url.setPath( col.remoteId() );
NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>();
if ( attr && attr->lastArticle() > 0 )
url.addQueryItem( "first", QString::number( attr->lastArticle() + 1 ) );
else
url.addQueryItem( "max", QString::number( Settings::self()->maxDownload() ) );
KIO::ListJob* job = KIO::listDir( url, KIO::HideProgressInfo, true );
setupKioJob( job );
connect( job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)),
SLOT(listGroup(KIO::Job*,KIO::UDSEntryList)) );
connect( job, SIGNAL(result(KJob*)), SLOT(listGroupResult(KJob*)) );
}
void NntpResource::listGroups(KIO::Job * job, const KIO::UDSEntryList & list)
{
Q_UNUSED( job );
QString name;
QStringList contentTypes;
contentTypes << "message/news";
for( KIO::UDSEntryList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) {
name = (*it).stringValue( KIO::UDSEntry::UDS_NAME );
if ( name.isEmpty() )
continue;
Collection c;
c.setRemoteId( name );
c.setContentMimeTypes( contentTypes );
if ( Settings::self()->flatHierarchy() ) {
c.setName( name );
c.parentCollection().setRemoteId( baseUrl().url() );
} else {
const QStringList path = name.split( '.' );
Q_ASSERT( !path.isEmpty() );
c.setName( path.last() );
c.parentCollection().setRemoteId( findParent( path ) );
}
remoteCollections << c;
}
}
void NntpResource::listGroupsResult(KJob * job)
{
if ( job->error() ) {
emit error( job->errorString() );
return;
} else {
Settings::self()->setLastGroupList( QDateTime::currentDateTime() );
}
if ( mIncremental )
collectionsRetrievedIncremental( remoteCollections, Collection::List() );
else
collectionsRetrieved( remoteCollections );
}
void NntpResource::listGroup(KIO::Job * job, const KIO::UDSEntryList & list)
{
Q_UNUSED( job );
foreach ( const KIO::UDSEntry &entry, list ) {
KUrl url = baseUrl();
url.setPath( currentCollection().remoteId() + '/' + entry.stringValue( KIO::UDSEntry::UDS_NAME ) );
Item item;
item.setRemoteId( url.url() );
item.setMimeType( "message/news" );
KMime::NewsArticle *art = new KMime::NewsArticle();
foreach ( uint field, entry.listFields() ) {
if ( field >= KIO::UDSEntry::UDS_EXTRA && field <= KIO::UDSEntry::UDS_EXTRA_END ) {
const QString value = entry.stringValue( field );
int pos = value.indexOf( ':' );
if ( pos >= value.length() - 1 )
continue; // value is empty
const QString hdrName = value.left( pos );
const QString hdrValue = value.right( value.length() - ( hdrName.length() + 2 ) );
if ( hdrName == "Subject" ) {
art->subject()->from7BitString( hdrValue.toLatin1() );
if ( art->subject()->isEmpty() )
art->subject()->fromUnicodeString( i18n( "no subject" ), art->defaultCharset() );
} else if ( hdrName == "From" ) {
art->from()->from7BitString( hdrValue.toLatin1() );
} else if ( hdrName == "Date" ) {
art->date()->from7BitString( hdrValue.toLatin1() );
} else if ( hdrName == "Message-ID" ) {
art->messageID()->from7BitString( hdrValue.simplified().toLatin1() );
} else if ( hdrName == "References" ) {
if ( !hdrValue.isEmpty() )
art->references()->from7BitString( hdrValue.toLatin1() );
} else if ( hdrName == "Lines" ) {
art->lines()->setNumberOfLines( hdrValue.toInt() );
} else {
// optional extra headers
art->setHeader( new KMime::Headers::Generic( hdrName.toLatin1(), art, hdrValue.toLatin1() ) );
}
}
}
item.setPayload( MessagePtr( art ) );
ItemCreateJob *append = new ItemCreateJob( item, currentCollection() );
// TODO: check error
Q_UNUSED( append )
}
}
void NntpResource::listGroupResult(KJob * job)
{
if ( job->error() ) {
emit error( job->errorString() );
} else {
// store last serial number
Collection col = currentCollection();
NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>( Collection::AddIfMissing );
KIO::Job *j = static_cast<KIO::Job*>( job );
if ( j->metaData().contains( "LastSerialNumber" ) )
attr->setLastArticle( j->metaData().value( "LastSerialNumber" ).toInt() );
CollectionModifyJob *modify = new CollectionModifyJob( col );
// TODO: check result signal
Q_UNUSED( modify )
}
itemsRetrievalDone();
}
KUrl NntpResource::baseUrl() const
{
KUrl url;
if ( Settings::self()->encryption() == Settings::SSL )
url.setProtocol( "nntps" );
else
url.setProtocol( "nntp" );
url.setHost( Settings::self()->server() );
url.setPort( Settings::self()->port() );
if ( Settings::self()->requiresAuthentication() ) {
url.setUser( Settings::self()->userName() );
url.setPass( Settings::self()->password() );
}
return url;
}
void NntpResource::fetchArticleResult(KJob * job)
{
if ( job->error() ) {
emit error( job->errorString() );
return;
}
KIO::StoredTransferJob *j = static_cast<KIO::StoredTransferJob*>( job );
KMime::Message *msg = new KMime::Message();
msg->setContent( KMime::CRLFtoLF( j->data() ) );
msg->parse();
Item item = currentItem();
item.setMimeType( "message/news" );
item.setPayload( MessagePtr( msg ) );
itemRetrieved( item );
}
void NntpResource::configure( WId windowId )
{
ConfigDialog dlg;
if ( windowId ) {
KWindowSystem::setMainWindow( &dlg, windowId );
}
dlg.setWindowIcon( KIcon( "message-news" ) );
if ( dlg.exec() ) {
emit configurationDialogAccepted();
} else {
emit configurationDialogRejected();
}
if ( !Settings::self()->name().isEmpty() )
setName( Settings::self()->name() );
}
void NntpResource::setupKioJob(KIO::Job * job) const
{
Q_ASSERT( job );
if ( Settings::self()->encryption() == Settings::TLS )
job->addMetaData( "tls", "on" );
else
job->addMetaData( "tls", "off" );
// TODO connect percent and status message signals to something
}
QString NntpResource::findParent(const QStringList & _path)
{
QStringList path = _path;
path.removeLast();
if ( path.isEmpty() )
return baseUrl().url();
QString rid = path.join( "." );
foreach ( const Collection &col, remoteCollections )
if ( col.remoteId() == rid )
return col.remoteId();
Collection parent;
parent.setRemoteId( rid );
QStringList ct;
ct << Collection::mimeType();
parent.setContentMimeTypes( ct );
parent.parentCollection().setRemoteId( findParent( path ) );
parent.setName( path.last() );
remoteCollections << parent;
return parent.remoteId();
}
void NntpResource::collectionChanged(const Akonadi::Collection & collection)
{
if ( collection.remoteId() == baseUrl().url() && !collection.name().isEmpty() ) {
Settings::self()->setName( collection.name() );
setName( collection.name() );
}
changeCommitted( collection );
}
AKONADI_RESOURCE_MAIN( NntpResource )

File Metadata

Mime Type
text/x-c
Expires
Fri, Nov 1, 8:19 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10074903
Default Alt Text
nntpresource.cpp (10 KB)

Event Timeline