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  // prefer content/content:encoded over summary/description for feeds that provide it
96  if (format == AtomFeed)
97  {
98  d->description = extractNode(node, TQString::fromLatin1("content"), false);
99  }
100  else
101  {
102  d->description = extractElementTextNS(node, ContentNamespace, TQString::fromLatin1("encoded"), false);
103  }
104 
105  if (d->description.isEmpty())
106  {
107  if (!(elemText = extractNode(node, TQString::fromLatin1("body"), false)).isNull())
108  d->description = elemText;
109 
110  if (d->description.isEmpty()) // 3rd try: see http://www.intertwingly.net/blog/1299.html
111  {
112  if (!(elemText = extractNode(node, TQString::fromLatin1((format==AtomFeed)? "summary" : "description"), false)).isNull())
113  d->description = elemText;
114  }
115  }
116 
117  time_t time = 0;
118 
119  if (format == AtomFeed)
120  {
121  if (version == vAtom_1_0)
122  elemText = extractNode(node, TQString::fromLatin1("updated"));
123  else
124  elemText = extractNode(node, TQString::fromLatin1("issued"));
125 
126  if (!elemText.isNull())
127  time = parseISO8601Date(elemText);
128  }
129  else
130  {
131  elemText = extractNode(node, TQString::fromLatin1("pubDate"));
132  if (!elemText.isNull())
133  time = KRFCDate::parseDate(elemText);
134  }
135 
136  if (!(elemText = extractElementTextNS(node, DublinCoreNamespace, TQString::fromLatin1("date"))).isNull())
137  {
138  time = parseISO8601Date(elemText);
139  }
140 
141  // 0 means invalid, not epoch (parsers return epoch+1 when parsing epoch, see the KRFCDate::parseDate() docs)
142  if (time != 0)
143  d->pubDate.setTime_t(time);
144 
145  d->commentsLink = extractElementTextNS(node, CommentAPINamespace, TQString::fromLatin1("comment"));
146  d->numComments = extractElementTextNS(node, SlashNamespace, TQString::fromLatin1("comments")).toInt();
147 
148  TQDomElement element = TQDomNode(node).toElement();
149 
150  // in RSS 1.0, we use <item about> attribute as ID
151  // FIXME: pass format version instead of checking for attribute
152 
153  if (!element.isNull() && element.hasAttributeNS(RDFNamespace, TQString::fromLatin1("about")))
154  {
155  d->guid = element.attributeNS(RDFNamespace, TQString::fromLatin1("about"), TQString::null);
156  d->guidIsPermaLink = false;
157  }
158  else
159  {
160  TQString tagName=(format==AtomFeed)? TQString::fromLatin1("id"): TQString::fromLatin1("guid");
161  TQDomNode n = node.namedItem(tagName);
162  if (!n.isNull())
163  {
164  d->guidIsPermaLink = (format==AtomFeed)? false : true;
165  if (n.toElement().attribute(TQString::fromLatin1("isPermaLink"), "true") == "false") d->guidIsPermaLink = false;
166  if (!(elemText = extractNode(node, tagName)).isNull())
167  d->guid = elemText;
168  }
169  }
170 
171  if(d->guid.isEmpty()) {
172  d->guidIsPermaLink = false;
173 
174  md5Machine.reset();
175  TQDomNode n(node);
176  md5Machine.update(d->title.utf8());
177  md5Machine.update(d->description.utf8());
178  d->guid = TQString(md5Machine.hexDigest().data());
179  d->meta[TQString::fromLatin1("guidIsHash")] = TQString::fromLatin1("true");
180  }
181 
182  TQDomNode enclosure = element.namedItem(TQString::fromLatin1("enclosure"));
183  if (enclosure.isElement())
184  d->enclosure = Enclosure::fromXML(enclosure.toElement());
185 
186  d->author = parseItemAuthor(element, format, version);
187 
188  for (TQDomNode i = node.firstChild(); !i.isNull(); i = i.nextSibling())
189  {
190  if (i.isElement())
191  {
192  if (i.toElement().tagName() == TQString::fromLatin1("metaInfo:meta"))
193  {
194  TQString type = i.toElement().attribute(TQString::fromLatin1("type"));
195  d->meta[type] = i.toElement().text();
196  }
197  else if (i.toElement().tagName() == TQString::fromLatin1("category"))
198  {
199  d->categories.append(Category::fromXML(i.toElement()));
200  }
201  }
202  }
203 }
204 
206 {
207  if (d->deref())
208  delete d;
209 }
210 
211 TQString Article::title() const
212 {
213  return d->title;
214 }
215 
216 TQString Article::author() const
217 {
218  return d->author;
219 }
220 
221 const KURL &Article::link() const
222 {
223  return d->link;
224 }
225 
226 TQString Article::description() const
227 {
228  return d->description;
229 }
230 
231 TQString Article::guid() const
232 {
233  return d->guid;
234 }
235 
237 {
238  return d->guidIsPermaLink;
239 }
240 
241 const TQDateTime &Article::pubDate() const
242 {
243  return d->pubDate;
244 }
245 
246 const KURL &Article::commentsLink() const
247 {
248  return d->commentsLink;
249 }
250 
251 int Article::comments() const
252 {
253  return d->numComments;
254 }
255 
256 
257 TQString Article::meta(const TQString &key) const
258 {
259  return d->meta[key];
260 }
261 
262 KURLLabel *Article::widget(TQWidget *parent, const char *name) const
263 {
264  KURLLabel *label = new KURLLabel(d->link.url(), d->title, parent, name);
265  label->setUseTips(true);
266  if (!d->description.isNull())
267  label->setTipText(d->description);
268 
269  return label;
270 }
271 
273 {
274  if (this != &other) {
275  other.d->ref();
276  if (d && d->deref())
277  delete d;
278  d = other.d;
279  }
280  return *this;
281 }
282 
283 bool Article::operator==(const Article &other) const
284 {
285  return d->guid == other.guid();
286 }
KURLLabel * widget(TQWidget *parent=0, const char *name=0) const
Definition: article.cpp:262
TQValueList< Category > categories() const
returns a list of categories this article is assigned to.
Definition: article.cpp:61
const KURL & link() const
RSS 0.90 and upwards.
Definition: article.cpp:221
Article & operator=(const Article &other)
Assignment operator.
Definition: article.cpp:272
virtual ~Article()
Destructor.
Definition: article.cpp:205
TQString title() const
RSS 0.90 and upwards.
Definition: article.cpp:211
TQString description() const
RSS 0.91 and upwards.
Definition: article.cpp:226
const TQDateTime & pubDate() const
RSS 2.0 and upwards.
Definition: article.cpp:241
TQString author() const
a string desribing the author of the item.
Definition: article.cpp:216
Article()
Default constructor.
Definition: article.cpp:47
bool guidIsPermaLink() const
RSS 2.0 and upwards.
Definition: article.cpp:236
TQString guid() const
RSS 2.0 and upwards.
Definition: article.cpp:231
bool operator==(const Article &other) const
Compares two articles.
Definition: article.cpp:283
Represents an article as stored in a RSS file.
Definition: article.h:37