• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

akregator

  • sources
  • kde-4.12
  • kdepim
  • akregator
  • src
article.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Akregator.
3 
4  Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
5  2005 Frank Osterfeld <osterfeld@kde.org>
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20  As a special exception, permission is given to link this program
21  with any edition of Qt, and distribute the resulting executable,
22  without including the source code for Qt in the source distribution.
23 */
24 
25 #include "article.h"
26 #include "feed.h"
27 #include "feedstorage.h"
28 #include "shared.h"
29 #include "storage.h"
30 #include "utils.h"
31 
32 #include <syndication/syndication.h>
33 
34 #include <QDateTime>
35 #include <qdom.h>
36 #include <QRegExp>
37 #include <QList>
38 
39 #include <kdebug.h>
40 #include <kurl.h>
41 
42 #include <cassert>
43 
44 using namespace boost;
45 using namespace Syndication;
46 
47 namespace {
48 
49 QString buildTitle(const QString& description)
50 {
51  QString s = description;
52  if (description.trimmed().isEmpty())
53  return QString();
54 
55  int i = s.indexOf(QLatin1Char('>'),500); /*avoid processing too much */
56  if (i != -1)
57  s = s.left(i+1);
58  QRegExp rx(QLatin1String("(<([^\\s>]*)(?:[^>]*)>)[^<]*"), Qt::CaseInsensitive);
59  QString tagName, toReplace, replaceWith;
60  while (rx.indexIn(s) != -1 )
61  {
62  tagName=rx.cap(2);
63  if (tagName==QLatin1String("SCRIPT")||tagName==QLatin1String("script"))
64  toReplace=rx.cap(0); // strip tag AND tag contents
65  else if (tagName.startsWith(QLatin1String("br")) || tagName.startsWith(QLatin1String("BR")))
66  {
67  toReplace=rx.cap(1);
68  replaceWith=QLatin1Char(' ');
69  }
70  else
71  toReplace=rx.cap(1); // strip just tag
72  s=s.replace(s.indexOf(toReplace),toReplace.length(),replaceWith); // do the deed
73  }
74  if (s.length()> 90)
75  s=s.left(90)+QLatin1String("...");
76  return s.simplified();
77 }
78 
79 }
80 
81 namespace Akregator {
82 
83 struct Article::Private : public Shared
84 {
85  Private();
86  Private( const QString& guid, Feed* feed, Backend::FeedStorage* archive );
87  Private( const ItemPtr& article, Feed* feed, Backend::FeedStorage* archive );
88 
98  enum Status
99  {
100  Deleted=0x01,
101  Trash=0x02,
102  New=0x04,
103  Read=0x08,
104  Keep=0x10
105  };
106 
107  Feed* feed;
108  QString guid;
109  Backend::FeedStorage* archive;
110  int status;
111  uint hash;
112  QDateTime pubDate;
113  mutable shared_ptr<const Enclosure> enclosure;
114 };
115 
116 namespace {
117  class EnclosureImpl : public Enclosure
118  {
119  public:
120  EnclosureImpl( const QString& url, const QString& type, uint length ) : m_url( url ), m_type( type ), m_length( length ) {}
121  /* reimp */ QString url() const { return m_url; }
122  /* reimp */ QString type() const { return m_type; }
123  /* reimp */ QString title() const { return m_title; }
124  /* reimp */ uint length() const { return m_length; }
125  /* reimp */ uint duration() const { return 0; }
126  /* reimp */ bool isNull() const { return m_url.isNull(); }
127  private:
128  QString m_url;
129  QString m_type;
130  QString m_title;
131  uint m_length;
132  };
133 }
134 
135 Article::Private::Private()
136  : feed( 0 ),
137  archive( 0 ),
138  status( 0 ),
139  hash( 0 ),
140  pubDate( QDateTime::fromTime_t( 1 ) )
141 {
142 }
143 
144 Article::Private::Private( const QString& guid_, Feed* feed_, Backend::FeedStorage* archive_ )
145  : feed( feed_ ),
146  guid( guid_ ),
147  archive( archive_ ),
148  status( archive->status( guid ) ),
149  hash( archive->hash( guid ) ),
150  pubDate( QDateTime::fromTime_t( archive->pubDate( guid ) ) )
151 {
152 }
153 
154 Article::Private::Private( const ItemPtr& article, Feed* feed_, Backend::FeedStorage* archive_ )
155  : feed( feed_ ),
156  archive( archive_ ),
157  status ( New ),
158  hash( 0 )
159 {
160  assert( archive );
161  const QList<PersonPtr> authorList = article->authors();
162 
163  QString author;
164 
165  const PersonPtr firstAuthor = !authorList.isEmpty() ? authorList.first() : PersonPtr();
166 
167  hash = Utils::calcHash(article->title() + article->description() + article->content() + article->link() + author);
168 
169  guid = article->id();
170 
171  if (!archive->contains(guid))
172  {
173  archive->addEntry(guid);
174 
175  archive->setHash(guid, hash);
176  QString title = article->title();
177  if (title.isEmpty())
178  title = buildTitle(article->description());
179  archive->setTitle(guid, title);
180  archive->setContent(guid, article->content());
181  archive->setDescription(guid, article->description());
182  archive->setLink(guid, article->link());
183  //archive->setComments(guid, article.comments());
184  //archive->setCommentsLink(guid, article.commentsLink().url());
185  archive->setGuidIsPermaLink(guid, false);
186  archive->setGuidIsHash(guid, guid.startsWith(QLatin1String("hash:")));
187  const time_t datePublished = article->datePublished();
188  if ( datePublished > 0 )
189  pubDate.setTime_t( datePublished );
190  else
191  pubDate = QDateTime::currentDateTime();
192  archive->setPubDate(guid, pubDate.toTime_t());
193  if ( firstAuthor ) {
194  archive->setAuthorName(guid, firstAuthor->name() );
195  archive->setAuthorUri(guid, firstAuthor->uri() );
196  archive->setAuthorEMail(guid, firstAuthor->email() );
197  }
198  const QList<EnclosurePtr> encs = article->enclosures();
199  if ( !encs.isEmpty() )
200  {
201  archive->setEnclosure(guid, encs[0]->url(), encs[0]->type(), encs[0]->length());
202  }
203  }
204  else
205  {
206  // always update comments count, as it's not used for hash calculation
207  //archive->setComments(guid, article.comments());
208  if (hash != archive->hash(guid)) //article is in archive, was it modified?
209  { // if yes, update
210  pubDate.setTime_t(archive->pubDate(guid));
211  archive->setHash(guid, hash);
212  QString title = article->title();
213  if (title.isEmpty())
214  title = buildTitle(article->description());
215  archive->setTitle(guid, title);
216  archive->setDescription(guid, article->description());
217  archive->setContent(guid, article->content());
218  archive->setLink(guid, article->link());
219  if ( firstAuthor ) {
220  archive->setAuthorName(guid, firstAuthor->name() );
221  archive->setAuthorUri(guid, firstAuthor->uri() );
222  archive->setAuthorEMail(guid, firstAuthor->email() );
223  }
224  //archive->setCommentsLink(guid, article.commentsLink());
225  }
226  }
227 
228  const QList<EnclosurePtr> encs = article->enclosures();
229  if (!encs.isEmpty())
230  {
231  archive->setEnclosure(guid, encs[0]->url(), encs[0]->type(), encs[0]->length());
232  }
233 
234 }
235 
236 
237 Article::Article() : d( new Private )
238 {
239 }
240 
241 Article::Article( const QString& guid, Feed* feed ) : d( new Private( guid, feed, feed->storage()->archiveFor( feed->xmlUrl() ) ) )
242 {
243 }
244 
245 Article::Article( const ItemPtr& article, Feed* feed ) : d( new Private( article, feed, feed->storage()->archiveFor( feed->xmlUrl() ) ) )
246 {
247 }
248 
249 Article::Article( const ItemPtr& article, Backend::FeedStorage* archive ) : d( new Private( article, 0, archive ) )
250 {
251 }
252 
253 bool Article::isNull() const
254 {
255  return d->archive == 0; // TODO: use proper null state
256 }
257 
258 void Article::offsetPubDate(int secs)
259 {
260  d->pubDate = d->pubDate.addSecs(secs);
261  d->archive->setPubDate(d->guid, d->pubDate.toTime_t());
262 
263 }
264 
265 void Article::setDeleted()
266 {
267  if (isDeleted())
268  return;
269 
270  setStatus(Read);
271  d->status = Private::Deleted | Private::Read;
272  d->archive->setStatus(d->guid, d->status);
273  d->archive->setDeleted(d->guid);
274 
275  if (d->feed)
276  d->feed->setArticleDeleted(*this);
277 }
278 
279 bool Article::isDeleted() const
280 {
281  return (d->status & Private::Deleted) != 0;
282 }
283 
284 Article::Article(const Article &other) : d( other.d )
285 {
286  d->ref();
287 }
288 
289 Article::~Article()
290 {
291  if ( d->deref() )
292  {
293  delete d;
294  d = 0;
295  }
296 }
297 
298 Article &Article::operator=(const Article &other)
299 {
300  Article copy( other );
301  swap( copy );
302  return *this;
303 }
304 
305 
306 bool Article::operator<(const Article &other) const
307 {
308  return pubDate() > other.pubDate() ||
309  (pubDate() == other.pubDate() && guid() < other.guid() );
310 }
311 
312 bool Article::operator<=(const Article &other) const
313 {
314  return (pubDate() > other.pubDate() || *this == other);
315 }
316 
317 bool Article::operator>(const Article &other) const
318 {
319  return pubDate() < other.pubDate() ||
320  (pubDate() == other.pubDate() && guid() > other.guid() );
321 }
322 
323 bool Article::operator>=(const Article &other) const
324 {
325  return (pubDate() > other.pubDate() || *this == other);
326 }
327 
328 bool Article::operator==(const Article &other) const
329 {
330  return d->guid == other.guid();
331 }
332 
333 bool Article::operator!=(const Article &other) const
334 {
335  return d->guid != other.guid();
336 }
337 
338 int Article::status() const
339 {
340  if ((d->status & Private::Read) != 0)
341  return Read;
342 
343  if ((d->status & Private::New) != 0)
344  return New;
345 
346  return Unread;
347 }
348 
349 void Article::setStatus(int stat)
350 {
351  int oldStatus = status();
352 
353  if (oldStatus != stat)
354  {
355  switch (stat)
356  {
357  case Read:
358  d->status = (d->status | Private::Read) & ~Private::New;
359  break;
360  case Unread:
361  d->status = (d->status & ~Private::Read) & ~Private::New;
362  break;
363  case New:
364  d->status = (d->status | Private::New) & ~Private::Read;
365  break;
366  }
367  if ( d->archive )
368  d->archive->setStatus(d->guid, d->status);
369  if (d->feed)
370  d->feed->setArticleChanged(*this, oldStatus);
371  }
372 }
373 
374 QString Article::title() const
375 {
376  QString str;
377  if ( d->archive ) {
378  str = d->archive->title(d->guid);
379  }
380  return str;
381 }
382 
383 QString Article::authorName() const
384 {
385  QString str;
386  if ( d->archive ) {
387  str = d->archive->authorName(d->guid);
388  }
389  return str;
390 }
391 
392 QString Article::authorEMail() const
393 {
394  QString str;
395  if ( d->archive ) {
396  str = d->archive->authorEMail(d->guid);
397  }
398  return str;
399 }
400 
401 QString Article::authorUri() const
402 {
403  QString str;
404  if ( d->archive ){
405  str = d->archive->authorUri(d->guid);
406  }
407  return str;
408 }
409 
410 QString Article::authorShort() const {
411  const QString name = authorName();
412  if ( !name.isEmpty() )
413  return name;
414  const QString email = authorEMail();
415  if ( !email.isEmpty() )
416  return email;
417  const QString uri = authorUri();
418  if ( !uri.isEmpty() )
419  return uri;
420  return QString();
421 }
422 
423 QString Article::authorAsHtml() const {
424  const QString name = authorName();
425  const QString email = authorEMail();
426 
427  if (!email.isEmpty()) {
428  if (!name.isEmpty())
429  return QString::fromLatin1("<a href=\"mailto:%1\">%2</a>").arg( email, name );
430  else
431  return QString::fromLatin1("<a href=\"mailto:%1\">%1</a>").arg( email );
432  }
433 
434  const QString uri = authorUri();
435  if (!name.isEmpty()) {
436  if (!uri.isEmpty())
437  return QString::fromLatin1("<a href=\"%1\">%2</a>").arg( uri, name );
438  else
439  return name;
440  }
441 
442  if ( !uri.isEmpty() )
443  return QString::fromLatin1( "<a href=\"%1\">%1</a>" ).arg( uri );
444  return QString();
445 }
446 
447 KUrl Article::link() const
448 {
449  return d->archive->link(d->guid);
450 }
451 
452 QString Article::description() const
453 {
454  return d->archive->description(d->guid);
455 }
456 
457 QString Article::content( ContentOption opt ) const
458 {
459  const QString cnt = d->archive->content( d->guid );
460  return opt == ContentAndOnlyContent ? cnt : ( !cnt.isEmpty() ? cnt : description() );
461 }
462 
463 QString Article::guid() const
464 {
465  return d->guid;
466 }
467 
468 KUrl Article::commentsLink() const
469 {
470  return d->archive->commentsLink(d->guid);
471 }
472 
473 
474 int Article::comments() const
475 {
476  return d->archive->comments(d->guid);
477 }
478 
479 
480 bool Article::guidIsPermaLink() const
481 {
482  return d->archive->guidIsPermaLink(d->guid);
483 }
484 
485 bool Article::guidIsHash() const
486 {
487  return d->archive->guidIsHash(d->guid);
488 }
489 
490 uint Article::hash() const
491 {
492  return d->hash;
493 }
494 
495 bool Article::keep() const
496 {
497  return (d->status & Private::Keep) != 0;
498 }
499 
500 void Article::setKeep(bool keep)
501 {
502  d->status = keep ? (d->status | Private::Keep) : (d->status & ~Private::Keep);
503  d->archive->setStatus(d->guid, d->status);
504  if (d->feed)
505  d->feed->setArticleChanged(*this);
506 }
507 
508 Feed* Article::feed() const
509 { return d->feed; }
510 
511 QDateTime Article::pubDate() const
512 {
513  return d->pubDate;
514 }
515 
516 shared_ptr<const Enclosure> Article::enclosure() const
517 {
518  if ( !d->enclosure )
519  {
520  QString url;
521  QString type;
522  int length;
523  bool hasEnc;
524  d->archive->enclosure( d->guid, hasEnc, url, type, length );
525  if ( hasEnc )
526  d->enclosure.reset( new EnclosureImpl( url, type, static_cast<uint>( length ) ) );
527  else
528  d->enclosure.reset( new EnclosureImpl( QString(), QString(), 0 ) );
529  }
530  return d->enclosure;
531 }
532 
533 } // namespace Akregator
Akregator::Article::ContentOption
ContentOption
Definition: article.h:68
Syndication::ItemPtr
boost::shared_ptr< Item > ItemPtr
Definition: article.h:48
Akregator::Article::operator<
bool operator<(const Article &other) const
Definition: article.cpp:306
Akregator::Article::link
KUrl link() const
Definition: article.cpp:447
Akregator::Article::guidIsHash
bool guidIsHash() const
returns if the guid is a hash or an ID taken from the source
Definition: article.cpp:485
uint
unsigned int uint
Definition: article.h:39
Status
Status
Definition: akregatorstorageexporter.cpp:64
Akregator::Article::operator>
bool operator>(const Article &other) const
Definition: article.cpp:317
Akregator::Article::operator=
Article & operator=(const Article &other)
Definition: article.cpp:298
Akregator::Article::commentsLink
KUrl commentsLink() const
Definition: article.cpp:468
Akregator::New
article was fetched in the last fetch of it's feed and not read yet.
Definition: types.h:33
feed.h
utils.h
Akregator::Article::feed
Feed * feed() const
Definition: article.cpp:508
Akregator::Article::isNull
bool isNull() const
Definition: article.cpp:253
Akregator::Article::content
QString content(ContentOption opt=ContentAndOnlyContent) const
Definition: article.cpp:457
Akregator::Article::authorEMail
QString authorEMail() const
Definition: article.cpp:392
Akregator::Article::title
QString title() const
Definition: article.cpp:374
Akregator::Article::ContentAndOnlyContent
Definition: article.h:69
Akregator::Article::Article
Article()
Definition: article.cpp:237
Akregator::Article::authorUri
QString authorUri() const
Definition: article.cpp:401
Akregator::Article::authorName
QString authorName() const
Definition: article.cpp:383
Akregator::Article::keep
bool keep() const
if true, the article should be kept even when expired
Definition: article.cpp:495
Akregator::Read
article is read
Definition: types.h:32
Akregator::Backend::FeedStorage
Definition: feedstorage.h:66
Akregator::Article::authorAsHtml
QString authorAsHtml() const
Definition: article.cpp:423
m_length
uint m_length
Definition: article.cpp:131
article.h
storage.h
Akregator::Article::isDeleted
bool isDeleted() const
Definition: article.cpp:279
Akregator::Article::hash
uint hash() const
returns a hash value used to detect changes in articles with non-hash GUIDs.
Definition: article.cpp:490
Akregator::Article::guid
QString guid() const
Definition: article.cpp:463
Akregator::Article::operator>=
bool operator>=(const Article &other) const
Definition: article.cpp:323
Akregator::Article::swap
void swap(Article &other)
Definition: article.h:87
shared.h
Akregator::Article::operator==
bool operator==(const Article &other) const
Definition: article.cpp:328
Akregator::Article::pubDate
QDateTime pubDate() const
Definition: article.cpp:511
Akregator::Article::description
QString description() const
Definition: article.cpp:452
Akregator::Article::authorShort
QString authorShort() const
Definition: article.cpp:410
Akregator::Unread
article wasn't read yet by the user
Definition: types.h:31
Akregator::Feed
represents a feed
Definition: feed.h:52
Akregator::Article::enclosure
boost::shared_ptr< const Syndication::Enclosure > enclosure() const
Definition: article.cpp:516
Akregator::Article::~Article
~Article()
Definition: article.cpp:289
Akregator::Article
A proxy class for Syndication::ItemPtr with some additional methods to assist sorting.
Definition: article.h:61
Akregator::Article::status
int status() const
Definition: article.cpp:338
Akregator::Article::guidIsPermaLink
bool guidIsPermaLink() const
Definition: article.cpp:480
Akregator::Article::operator!=
bool operator!=(const Article &other) const
Definition: article.cpp:333
Akregator::Article::comments
int comments() const
Definition: article.cpp:474
Akregator::Article::offsetPubDate
void offsetPubDate(int secs)
Definition: article.cpp:258
feedstorage.h
m_url
QString m_url
Definition: article.cpp:128
m_title
QString m_title
Definition: article.cpp:130
Akregator::Article::operator<=
bool operator<=(const Article &other) const
Definition: article.cpp:312
QList
Definition: article.h:39
m_type
QString m_type
Definition: article.cpp:129
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:58:14 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akregator

Skip menu "akregator"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal