~ubuntu-branches/ubuntu/karmic/kdepim/karmic-backports

« back to all changes in this revision

Viewing changes to akonadi/resources/nntp/nntpresource.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christian Mangold
  • Date: 2009-07-10 06:34:50 UTC
  • mfrom: (1.1.40 upstream)
  • Revision ID: james.westby@ubuntu.com-20090710063450-neojgew2fh0n3y0u
Tags: 4:4.2.96-0ubuntu1
* New upstream release
* Bump kde build-deps to 4.2.96

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>
3
 
 
4
 
    This library is free software; you can redistribute it and/or modify it
5
 
    under the terms of the GNU Library General Public License as published by
6
 
    the Free Software Foundation; either version 2 of the License, or (at your
7
 
    option) any later version.
8
 
 
9
 
    This library is distributed in the hope that it will be useful, but WITHOUT
10
 
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
12
 
    License for more details.
13
 
 
14
 
    You should have received a copy of the GNU Library General Public License
15
 
    along with this library; see the file COPYING.LIB.  If not, write to the
16
 
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
 
    02110-1301, USA.
18
 
*/
19
 
 
20
 
#include "nntpresource.h"
21
 
#include "nntpcollectionattribute.h"
22
 
#include "configdialog.h"
23
 
#include "settings.h"
24
 
#include "settingsadaptor.h"
25
 
 
26
 
#include <akonadi/attributefactory.h>
27
 
#include <akonadi/cachepolicy.h>
28
 
#include <akonadi/collectionmodifyjob.h>
29
 
#include <akonadi/itemcreatejob.h>
30
 
#include <akonadi/kmime/messageparts.h>
31
 
#include <akonadi/monitor.h>
32
 
#include <akonadi/session.h>
33
 
#include <akonadi/changerecorder.h>
34
 
 
35
 
#include <kmime/kmime_message.h>
36
 
#include <kmime/kmime_newsarticle.h>
37
 
#include <kmime/kmime_util.h>
38
 
 
39
 
#include <KWindowSystem>
40
 
 
41
 
#include <QDateTime>
42
 
#include <QDir>
43
 
#include <QInputDialog>
44
 
#include <QLineEdit>
45
 
 
46
 
#include <boost/shared_ptr.hpp>
47
 
typedef boost::shared_ptr<KMime::Message> MessagePtr;
48
 
 
49
 
using namespace Akonadi;
50
 
 
51
 
NntpResource::NntpResource(const QString & id)
52
 
  : ResourceBase( id )
53
 
{
54
 
  AttributeFactory::registerAttribute<NntpCollectionAttribute>();
55
 
  changeRecorder()->fetchCollection( true );
56
 
  new SettingsAdaptor( Settings::self() );
57
 
  QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ),
58
 
                              Settings::self(), QDBusConnection::ExportAdaptors );
59
 
}
60
 
 
61
 
NntpResource::~ NntpResource()
62
 
{
63
 
}
64
 
 
65
 
bool NntpResource::retrieveItem(const Akonadi::Item& item, const QSet<QByteArray> &parts)
66
 
{
67
 
  Q_UNUSED( parts );
68
 
  KIO::Job* job = KIO::storedGet( KUrl( item.remoteId() ), KIO::NoReload, KIO::HideProgressInfo );
69
 
  setupKioJob( job );
70
 
  connect( job, SIGNAL( result(KJob*) ), SLOT( fetchArticleResult(KJob*) ) );
71
 
  return true;
72
 
}
73
 
 
74
 
void NntpResource::retrieveCollections()
75
 
{
76
 
  remoteCollections.clear();
77
 
  Collection rootCollection;
78
 
  rootCollection.setParent( Collection::root() );
79
 
  rootCollection.setRemoteId( baseUrl().url() );
80
 
  rootCollection.setName( Settings::self()->name() );
81
 
  CachePolicy policy;
82
 
  policy.setInheritFromParent( false );
83
 
  policy.setSyncOnDemand( true );
84
 
  policy.setLocalParts( QStringList( MessagePart::Envelope ) );
85
 
  rootCollection.setCachePolicy( policy );
86
 
  QStringList contentTypes;
87
 
  contentTypes << Collection::mimeType();
88
 
  rootCollection.setContentMimeTypes( contentTypes );
89
 
  remoteCollections << rootCollection;
90
 
 
91
 
  KUrl url = baseUrl();
92
 
  QDate lastList = Settings::self()->lastGroupList().date();
93
 
  if ( lastList.isValid() ) {
94
 
    mIncremental = true;
95
 
    url.addQueryItem( "since",  QString("%1%2%3 000000")
96
 
        .arg( lastList.year() % 100, 2, 10, QChar( '0' ) )
97
 
        .arg( lastList.month(), 2, 10, QChar( '0' ) )
98
 
        .arg( lastList.day(), 2, 10, QChar( '0' ) ) );
99
 
  } else {
100
 
    mIncremental = false;
101
 
  }
102
 
 
103
 
  KIO::Job* job = KIO::listDir( url, KIO::HideProgressInfo, true );
104
 
  setupKioJob( job );
105
 
  connect( job, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList&)),
106
 
           SLOT(listGroups(KIO::Job*, const KIO::UDSEntryList&)) );
107
 
  connect( job, SIGNAL( result(KJob*) ), SLOT( listGroupsResult(KJob*) ) );
108
 
}
109
 
 
110
 
void NntpResource::retrieveItems( const Akonadi::Collection & col )
111
 
{
112
 
  if ( !(col.contentMimeTypes().count() == 1 && col.contentMimeTypes().first() == "message/news" ) ) {
113
 
    // not a newsgroup, skip it
114
 
    itemsRetrievalDone();
115
 
    return;
116
 
  }
117
 
 
118
 
  KUrl url = baseUrl();
119
 
  url.setPath( col.remoteId() );
120
 
 
121
 
  NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>();
122
 
  if ( attr && attr->lastArticle() > 0 )
123
 
    url.addQueryItem( "first", QString::number( attr->lastArticle() + 1 ) );
124
 
  else
125
 
    url.addQueryItem( "max", QString::number( Settings::self()->maxDownload() ) );
126
 
 
127
 
  KIO::Job* job = KIO::listDir( url, KIO::HideProgressInfo, true );
128
 
  setupKioJob( job );
129
 
  connect( job, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList&)),
130
 
           SLOT(listGroup(KIO::Job*, const KIO::UDSEntryList&)) );
131
 
  connect( job, SIGNAL( result(KJob*) ), SLOT( listGroupResult(KJob*) ) );
132
 
}
133
 
 
134
 
void NntpResource::listGroups(KIO::Job * job, const KIO::UDSEntryList & list)
135
 
{
136
 
  Q_UNUSED( job );
137
 
  QString name;
138
 
  QStringList contentTypes;
139
 
  contentTypes << "message/news";
140
 
  for( KIO::UDSEntryList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) {
141
 
    name = (*it).stringValue( KIO::UDSEntry::UDS_NAME );
142
 
    if ( name.isEmpty() )
143
 
      continue;
144
 
 
145
 
    Collection c;
146
 
    c.setRemoteId( name );
147
 
    c.setContentMimeTypes( contentTypes );
148
 
 
149
 
    if ( Settings::self()->flatHierarchy() ) {
150
 
      c.setName( name );
151
 
      c.setParentRemoteId( baseUrl().url() );
152
 
    } else {
153
 
      const QStringList path = name.split( '.' );
154
 
      Q_ASSERT( !path.isEmpty() );
155
 
      c.setName( path.last() );
156
 
      c.setParentRemoteId( findParent( path ) );
157
 
    }
158
 
 
159
 
    remoteCollections << c;
160
 
  }
161
 
}
162
 
 
163
 
void NntpResource::listGroupsResult(KJob * job)
164
 
{
165
 
  if ( job->error() ) {
166
 
    emit error( job->errorString() );
167
 
    return;
168
 
  } else {
169
 
    Settings::self()->setLastGroupList( QDateTime::currentDateTime() );
170
 
  }
171
 
  if ( mIncremental )
172
 
    collectionsRetrievedIncremental( remoteCollections, Collection::List() );
173
 
  else
174
 
    collectionsRetrieved( remoteCollections );
175
 
}
176
 
 
177
 
void NntpResource::listGroup(KIO::Job * job, const KIO::UDSEntryList & list)
178
 
{
179
 
  Q_UNUSED( job );
180
 
  foreach ( const KIO::UDSEntry &entry, list ) {
181
 
    KUrl url = baseUrl();
182
 
    url.setPath( currentCollection().remoteId() + '/' + entry.stringValue( KIO::UDSEntry::UDS_NAME ) );
183
 
    Item item;
184
 
    item.setRemoteId( url.url() );
185
 
    item.setMimeType( "message/news" );
186
 
 
187
 
    KMime::NewsArticle *art = new KMime::NewsArticle();
188
 
    foreach ( uint field, entry.listFields() ) {
189
 
      if ( field >= KIO::UDSEntry::UDS_EXTRA && field <= KIO::UDSEntry::UDS_EXTRA_END ) {
190
 
        const QString value = entry.stringValue( field );
191
 
        int pos = value.indexOf( ':' );
192
 
        if ( pos >= value.length() - 1 )
193
 
          continue; // value is empty
194
 
        const QString hdrName = value.left( pos );
195
 
        const QString hdrValue = value.right( value.length() - ( hdrName.length() + 2 ) );
196
 
 
197
 
        if ( hdrName == "Subject" ) {
198
 
          art->subject()->from7BitString( hdrValue.toLatin1() );
199
 
          if ( art->subject()->isEmpty() )
200
 
            art->subject()->fromUnicodeString( i18n("no subject"), art->defaultCharset() );
201
 
        } else if ( hdrName == "From" ) {
202
 
          art->from()->from7BitString( hdrValue.toLatin1() );
203
 
        } else if ( hdrName == "Date" ) {
204
 
          art->date()->from7BitString( hdrValue.toLatin1() );
205
 
        } else if ( hdrName == "Message-ID" ) {
206
 
          art->messageID()->from7BitString( hdrValue.simplified().toLatin1() );
207
 
        } else if ( hdrName == "References" ) {
208
 
          if( !hdrValue.isEmpty() )
209
 
            art->references()->from7BitString( hdrValue.toLatin1() );
210
 
        } else if ( hdrName == "Lines" ) {
211
 
          art->lines()->setNumberOfLines( hdrValue.toInt() );
212
 
        } else {
213
 
          // optional extra headers
214
 
          art->setHeader( new KMime::Headers::Generic( hdrName.toLatin1(), art, hdrValue.toLatin1() ) );
215
 
        }
216
 
      }
217
 
    }
218
 
 
219
 
    item.setPayload( MessagePtr( art ) );
220
 
    ItemCreateJob *append = new ItemCreateJob( item, currentCollection() );
221
 
    // TODO: check error
222
 
  }
223
 
}
224
 
 
225
 
void NntpResource::listGroupResult(KJob * job)
226
 
{
227
 
  if ( job->error() ) {
228
 
    emit error( job->errorString() );
229
 
  } else {
230
 
    // store last serial number
231
 
    Collection col = currentCollection();
232
 
    NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>( Collection::AddIfMissing );
233
 
    KIO::Job *j = static_cast<KIO::Job*>( job );
234
 
    if ( j->metaData().contains( "LastSerialNumber" ) )
235
 
      attr->setLastArticle( j->metaData().value("LastSerialNumber").toInt() );
236
 
    CollectionModifyJob *modify = new CollectionModifyJob( col );
237
 
    // TODO: check result signal
238
 
  }
239
 
 
240
 
  itemsRetrievalDone();
241
 
}
242
 
 
243
 
KUrl NntpResource::baseUrl() const
244
 
{
245
 
  KUrl url;
246
 
 if ( Settings::self()->encryption() == Settings::SSL )
247
 
    url.setProtocol( "nntps" );
248
 
  else
249
 
    url.setProtocol( "nntp" );
250
 
  url.setHost( Settings::self()->server() );
251
 
  url.setPort( Settings::self()->port() );
252
 
  if ( Settings::self()->requiresAuthentication() ) {
253
 
    url.setUser( Settings::self()->userName() );
254
 
    url.setPass( Settings::self()->password() );
255
 
  }
256
 
  return url;
257
 
}
258
 
 
259
 
void NntpResource::fetchArticleResult(KJob * job)
260
 
{
261
 
  if ( job->error() ) {
262
 
    emit error( job->errorString() );
263
 
    return;
264
 
  }
265
 
  KIO::StoredTransferJob *j = static_cast<KIO::StoredTransferJob*>( job );
266
 
  KMime::Message *msg = new KMime::Message();
267
 
  msg->setContent( KMime::CRLFtoLF( j->data() ) );
268
 
  msg->parse();
269
 
  Item item = currentItem();
270
 
  item.setMimeType( "message/news" );
271
 
  item.setPayload( MessagePtr( msg ) );
272
 
  itemRetrieved( item );
273
 
}
274
 
 
275
 
void NntpResource::configure( WId windowId )
276
 
{
277
 
  ConfigDialog dlg;
278
 
  if ( windowId )
279
 
    KWindowSystem::setMainWindow( &dlg, windowId );
280
 
  dlg.exec();
281
 
  if ( !Settings::self()->name().isEmpty() )
282
 
    setName( Settings::self()->name() );
283
 
}
284
 
 
285
 
void NntpResource::setupKioJob(KIO::Job * job) const
286
 
{
287
 
  Q_ASSERT( job );
288
 
  if ( Settings::self()->encryption() == Settings::TLS )
289
 
    job->addMetaData( "tls", "on" );
290
 
  else
291
 
    job->addMetaData( "tls", "off" );
292
 
  // TODO connect percent and status message signals to something
293
 
}
294
 
 
295
 
QString NntpResource::findParent(const QStringList & _path)
296
 
{
297
 
  QStringList path = _path;
298
 
  path.removeLast();
299
 
  if ( path.isEmpty() )
300
 
    return baseUrl().url();
301
 
  QString rid = path.join( "." );
302
 
  foreach ( const Collection &col, remoteCollections )
303
 
    if ( col.remoteId() == rid )
304
 
      return col.remoteId();
305
 
  Collection parent;
306
 
  parent.setRemoteId( rid );
307
 
  QStringList ct;
308
 
  ct << Collection::mimeType();
309
 
  parent.setContentMimeTypes( ct );
310
 
  parent.setParentRemoteId( findParent( path ) );
311
 
  parent.setName( path.last() );
312
 
  remoteCollections << parent;
313
 
  return parent.remoteId();
314
 
}
315
 
 
316
 
void NntpResource::collectionChanged(const Akonadi::Collection & collection)
317
 
{
318
 
  if ( collection.remoteId() == baseUrl().url() && !collection.name().isEmpty() ) {
319
 
    Settings::self()->setName( collection.name() );
320
 
    setName( collection.name() );
321
 
  }
322
 
  changeCommitted( collection );
323
 
}
324
 
 
325
 
AKONADI_RESOURCE_MAIN( NntpResource )
326
 
 
327
 
#include "nntpresource.moc"