akregator/src/librss

article.cpp
1 /*
2  * article.cpp
3  *
4  * Copyright (c) 2001, 2002, 2003, 2004 Frerich Raabe <raabe@kde.org>
5  *
6  * This program is distributed in the hope that it will be useful, but WITHOUT
7  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8  * FOR A PARTICULAR PURPOSE. For licensing and distribution details, check the
9  * accompanying file 'COPYING'.
10  */
11 #include "article.h"
12 #include "tools_p.h"
13 #include "enclosure.h"
14 #include "category.h"
15 
16 #include <kdebug.h>
17 #include <krfcdate.h>
18 #include <kurl.h>
19 #include <kurllabel.h>
20 #include <kmdcodec.h>
21 
22 #include <tqdatetime.h>
23 #include <tqdom.h>
24 
25 using namespace RSS;
26 namespace RSS
27 {
28  KMD5 md5Machine;
29 }
30 
31 struct Article::Private : public Shared
32 {
33  TQString title;
34  KURL link;
35  TQString description;
36  TQDateTime pubDate;
37  TQString guid;
38  TQString author;
39  bool guidIsPermaLink;
40  MetaInfoMap meta;
41  KURL commentsLink;
42  int numComments;
43  Enclosure enclosure;
44  TQValueList<Category> categories;
45 };
46 
47 Article::Article() : d(new Private)
48 {
49 }
50 
51 Article::Article(const Article &other) : d(0)
52 {
53  *this = other;
54 }
55 
56 Enclosure Article::enclosure() const
57 {
58  return d->enclosure;
59 }
60 
61 TQValueList<Category> Article::categories() const
62 {
63  return d->categories;
64 }
65 
66 
67 Article::Article(const TQDomNode &node, Format format, Version version) : d(new Private)
68 {
69  TQString elemText;
70 
71  d->numComments=0;
72 
73  if (!(elemText = extractTitle(node)).isNull())
74  d->title = elemText;
75 
76  if (format==AtomFeed)
77  {
78  TQDomNode n;
79  for (n = node.firstChild(); !n.isNull(); n = n.nextSibling()) {
80  const TQDomElement e = n.toElement();
81  if ( (e.tagName()==TQString::fromLatin1("link")) &&
82  (e.attribute(TQString::fromLatin1("rel"), TQString::fromLatin1("alternate")) == TQString::fromLatin1("alternate")))
83  {
84  d->link=n.toElement().attribute(TQString::fromLatin1("href"));
85  break;
86  }
87  }
88  }
89  else
90  {
91  if (!(elemText = extractNode(node, TQString::fromLatin1("link"))).isNull())
92  d->link = elemText;
93  }
94 
95 
96  // prefer content/content:encoded over summary/description for feeds that provide it
97  TQString tagName=(format==AtomFeed)? TQString::fromLatin1("content"): TQString::fromLatin1("content:encoded");
98 
99  if (!(elemText = extractNode(node, tagName, false)).isNull())
100  d->description = elemText;
101 
102  if (d->description.isEmpty())
103  {
104  if (!(elemText = extractNode(node, TQString::fromLatin1("body"), false)).isNull())
105  d->description = elemText;
106 
107  if (d->description.isEmpty()) // 3rd try: see http://www.intertwingly.net/blog/1299.html
108  {
109  if (!(elemText = extractNode(node, TQString::fromLatin1((format==AtomFeed)? "summary" : "description"), false)).isNull())
110  d->description = elemText;
111  }
112  }
113 
114  time_t time = 0;
115 
116  if (format == AtomFeed)
117  {
118  if (version == vAtom_1_0)
119  elemText = extractNode(node, TQString::fromLatin1("updated"));
120  else
121  elemText = extractNode(node, TQString::fromLatin1("issued"));
122 
123  if (!elemText.isNull())
124  time = parseISO8601Date(elemText);
125  }
126  else
127  {
128  elemText = extractNode(node, TQString::fromLatin1("pubDate"));
129  if (!elemText.isNull())
130  time = KRFCDate::parseDate(elemText);
131  }
132 
133  if (!(elemText = extractNode(node, TQString::fromLatin1("dc:date"))).isNull())
134  {
135  time = parseISO8601Date(elemText);
136  }
137 
138  // 0 means invalid, not epoch (parsers return epoch+1 when parsing epoch, see the KRFCDate::parseDate() docs)
139  if (time != 0)
140  d->pubDate.setTime_t(time);
141 
142  if (!(elemText = extractNode(node, TQString::fromLatin1("wfw:comment"))).isNull()) {
143  d->commentsLink = elemText;
144  }
145 
146  if (!(elemText = extractNode(node, TQString::fromLatin1("slash:comments"))).isNull()) {
147  d->numComments = elemText.toInt();
148  }
149 
150  TQDomElement element = TQDomNode(node).toElement();
151 
152  // in RSS 1.0, we use <item about> attribute as ID
153  // FIXME: pass format version instead of checking for attribute
154 
155  if (!element.isNull() && element.hasAttribute(TQString::fromLatin1("rdf:about")))
156  {
157  d->guid = element.attribute(TQString::fromLatin1("rdf:about")); // HACK: using ns properly did not work
158  d->guidIsPermaLink = false;
159  }
160  else
161  {
162  tagName=(format==AtomFeed)? TQString::fromLatin1("id"): TQString::fromLatin1("guid");
163  TQDomNode n = node.namedItem(tagName);
164  if (!n.isNull())
165  {
166  d->guidIsPermaLink = (format==AtomFeed)? false : true;
167  if (n.toElement().attribute(TQString::fromLatin1("isPermaLink"), "true") == "false") d->guidIsPermaLink = false;
168  if (!(elemText = extractNode(node, tagName)).isNull())
169  d->guid = elemText;
170  }
171  }
172 
173  if(d->guid.isEmpty()) {
174  d->guidIsPermaLink = false;
175 
176  md5Machine.reset();
177  TQDomNode n(node);
178  md5Machine.update(d->title.utf8());
179  md5Machine.update(d->description.utf8());
180  d->guid = TQString(md5Machine.hexDigest().data());
181  d->meta[TQString::fromLatin1("guidIsHash")] = TQString::fromLatin1("true");
182  }
183 
184  TQDomNode enclosure = element.namedItem(TQString::fromLatin1("enclosure"));
185  if (enclosure.isElement())
186  d->enclosure = Enclosure::fromXML(enclosure.toElement());
187 
188  d->author = parseItemAuthor(element, format, version);
189 
190  for (TQDomNode i = node.firstChild(); !i.isNull(); i = i.nextSibling())
191  {
192  if (i.isElement())
193  {
194  if (i.toElement().tagName() == TQString::fromLatin1("metaInfo:meta"))
195  {
196  TQString type = i.toElement().attribute(TQString::fromLatin1("type"));
197  d->meta[type] = i.toElement().text();
198  }
199  else if (i.toElement().tagName() == TQString::fromLatin1("category"))
200  {
201  d->categories.append(Category::fromXML(i.toElement()));
202  }
203  }
204  }
205 }
206 
208 {
209  if (d->deref())
210  delete d;
211 }
212 
213 TQString Article::title() const
214 {
215  return d->title;
216 }
217 
218 TQString Article::author() const
219 {
220  return d->author;
221 }
222 
223 const KURL &Article::link() const
224 {
225  return d->link;
226 }
227 
228 TQString Article::description() const
229 {
230  return d->description;
231 }
232 
233 TQString Article::guid() const
234 {
235  return d->guid;
236 }
237 
239 {
240  return d->guidIsPermaLink;
241 }
242 
243 const TQDateTime &Article::pubDate() const
244 {
245  return d->pubDate;
246 }
247 
248 const KURL &Article::commentsLink() const
249 {
250  return d->commentsLink;
251 }
252 
253 int Article::comments() const
254 {
255  return d->numComments;
256 }
257 
258 
259 TQString Article::meta(const TQString &key) const
260 {
261  return d->meta[key];
262 }
263 
264 KURLLabel *Article::widget(TQWidget *parent, const char *name) const
265 {
266  KURLLabel *label = new KURLLabel(d->link.url(), d->title, parent, name);
267  label->setUseTips(true);
268  if (!d->description.isNull())
269  label->setTipText(d->description);
270 
271  return label;
272 }
273 
275 {
276  if (this != &other) {
277  other.d->ref();
278  if (d && d->deref())
279  delete d;
280  d = other.d;
281  }
282  return *this;
283 }
284 
285 bool Article::operator==(const Article &other) const
286 {
287  return d->guid == other.guid();
288 }
Represents an article as stored in a RSS file.
Definition: article.h:38
Article & operator=(const Article &other)
Assignment operator.
Definition: article.cpp:274
TQString guid() const
RSS 2.0 and upwards.
Definition: article.cpp:233
TQValueList< Category > categories() const
returns a list of categories this article is assigned to.
Definition: article.cpp:61
bool operator==(const Article &other) const
Compares two articles.
Definition: article.cpp:285
KURLLabel * widget(TQWidget *parent=0, const char *name=0) const
Definition: article.cpp:264
TQString title() const
RSS 0.90 and upwards.
Definition: article.cpp:213
virtual ~Article()
Destructor.
Definition: article.cpp:207
bool guidIsPermaLink() const
RSS 2.0 and upwards.
Definition: article.cpp:238
TQString author() const
a string desribing the author of the item.
Definition: article.cpp:218
Article()
Default constructor.
Definition: article.cpp:47
const TQDateTime & pubDate() const
RSS 2.0 and upwards.
Definition: article.cpp:243
const KURL & link() const
RSS 0.90 and upwards.
Definition: article.cpp:223
TQString description() const
RSS 0.91 and upwards.
Definition: article.cpp:228