~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): Alessandro Ghersi, Alessandro Ghersi, Harald Sitter
  • Date: 2009-06-27 04:40:05 UTC
  • mfrom: (1.1.39 upstream)
  • Revision ID: james.westby@ubuntu.com-20090627044005-4y2vm9xz7rvmzi4p
Tags: 4:4.2.95svn20090701-0ubuntu1
[ Alessandro Ghersi ]
* New upstream release
  - Bump build-deps
* Remove akonadi-kde and libmaildir4 packages
  - remove akonadi-kde.install and libmaildir4.install
  - remove libmaildir4 from debian/rules
  - remove akonadi-kde and libmaildir4 from depends
  - remove akonadi-kde and libmaildir4 from installgen
* Update kdepim-dev.install
* Update kpilot.install
* Add akonadi-kde and libmaildir4 transitional packages

[ Harald Sitter ]
* KAddressbook replaces Kontact << 4.2.85 (LP: #378373)

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"