1 /*
2 * xmlcommon.cpp - helper functions for dealing with XML
3 * Copyright (C) 2001, 2002 Justin Karneges
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include <QString>
22 #include <QDateTime>
23 #include <QSize>
24 #include <QRect>
25 #include <QStringList>
26 #include <QColor>
27
28 #include "xmpp_xmlcommon.h"
29 #include "xmpp_stanza.h"
30
31 //----------------------------------------------------------------------------
32 // XDomNodeList
33 //----------------------------------------------------------------------------
XDomNodeList()34 XDomNodeList::XDomNodeList()
35 {
36 }
37
XDomNodeList(const XDomNodeList & from)38 XDomNodeList::XDomNodeList(const XDomNodeList &from) :
39 list(from.list)
40 {
41 }
42
XDomNodeList(const QDomNodeList & from)43 XDomNodeList::XDomNodeList(const QDomNodeList &from)
44 {
45 for(int n = 0; n < from.count(); ++n)
46 list += from.item(n);
47 }
48
~XDomNodeList()49 XDomNodeList::~XDomNodeList()
50 {
51 }
52
operator =(const XDomNodeList & from)53 XDomNodeList & XDomNodeList::operator=(const XDomNodeList &from)
54 {
55 list = from.list;
56 return *this;
57 }
58
isEmpty() const59 bool XDomNodeList::isEmpty() const
60 {
61 return list.isEmpty();
62 }
63
item(int index) const64 QDomNode XDomNodeList::item(int index) const
65 {
66 return list.value(index);
67 }
68
length() const69 uint XDomNodeList::length() const
70 {
71 return (uint)list.count();
72 }
73
operator ==(const XDomNodeList & a) const74 bool XDomNodeList::operator==(const XDomNodeList &a) const
75 {
76 return (list == a.list);
77 }
78
append(const QDomNode & i)79 void XDomNodeList::append(const QDomNode &i)
80 {
81 list += i;
82 }
83
84
stamp2TS(const QString & ts)85 QDateTime stamp2TS(const QString &ts)
86 {
87 if(ts.length() != 17)
88 return QDateTime();
89
90 int year = ts.mid(0,4).toInt();
91 int month = ts.mid(4,2).toInt();
92 int day = ts.mid(6,2).toInt();
93
94 int hour = ts.mid(9,2).toInt();
95 int min = ts.mid(12,2).toInt();
96 int sec = ts.mid(15,2).toInt();
97
98 QDate xd;
99 xd.setDate(year, month, day);
100 if(!xd.isValid())
101 return QDateTime();
102
103 QTime xt;
104 xt.setHMS(hour, min, sec);
105 if(!xt.isValid())
106 return QDateTime();
107
108 return QDateTime(xd, xt);
109 }
110
stamp2TS(const QString & ts,QDateTime * d)111 bool stamp2TS(const QString &ts, QDateTime *d)
112 {
113 QDateTime dateTime = stamp2TS(ts);
114 if (dateTime.isNull())
115 return false;
116
117 *d = dateTime;
118
119 return true;
120 }
121
TS2stamp(const QDateTime & d)122 QString TS2stamp(const QDateTime &d)
123 {
124 QString str;
125
126 str.sprintf("%04d%02d%02dT%02d:%02d:%02d",
127 d.date().year(),
128 d.date().month(),
129 d.date().day(),
130 d.time().hour(),
131 d.time().minute(),
132 d.time().second());
133
134 return str;
135 }
136
textTag(QDomDocument * doc,const QString & name,const QString & content)137 QDomElement textTag(QDomDocument *doc, const QString &name, const QString &content)
138 {
139 QDomElement tag = doc->createElement(name);
140 QDomText text = doc->createTextNode(content);
141 tag.appendChild(text);
142
143 return tag;
144 }
145
tagContent(const QDomElement & e)146 QString tagContent(const QDomElement &e)
147 {
148 // look for some tag content
149 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
150 QDomText i = n.toText();
151 if(i.isNull())
152 continue;
153 return i.data();
154 }
155
156 return "";
157 }
158
159
160 /**
161 * \brief obtain direct child elements of a certain kind. unlike
162 * elementsByTagNameNS, this function does not descend beyond the first
163 * level of children.
164 * \param e parent element
165 * \param nsURI namespace of the elements to find
166 * \param localName local name of the elements to find
167 * \return the node list of found elements (empty list if none are found)
168 */
childElementsByTagNameNS(const QDomElement & e,const QString & nsURI,const QString & localName)169 XDomNodeList childElementsByTagNameNS(const QDomElement &e, const QString &nsURI, const QString &localName)
170 {
171 XDomNodeList out;
172 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
173 if(!n.isElement())
174 continue;
175 QDomElement i = n.toElement();
176 if(i.namespaceURI() == nsURI && i.localName() == localName)
177 out.append(i);
178 }
179 return out;
180 }
181
182
183 /**
184 * \brief create a new IQ stanza
185 * \param doc
186 * \param type
187 * \param to destination jid
188 * \param id stanza id
189 * \return the created stanza
190 */
createIQ(QDomDocument * doc,const QString & type,const QString & to,const QString & id)191 QDomElement createIQ(QDomDocument *doc, const QString &type, const QString &to, const QString &id)
192 {
193 QDomElement iq = doc->createElement("iq");
194 if(!type.isEmpty())
195 iq.setAttribute("type", type);
196 if(!to.isEmpty())
197 iq.setAttribute("to", to);
198 if(!id.isEmpty())
199 iq.setAttribute("id", id);
200
201 return iq;
202 }
203
204 /** \brief returns direct child element named "query"
205 * \return the element (or a null QDomElemnt if not found)
206 */
queryTag(const QDomElement & e)207 QDomElement queryTag(const QDomElement &e)
208 {
209 return e.firstChildElement("query");
210 }
211
queryNS(const QDomElement & e)212 QString queryNS(const QDomElement &e)
213 {
214 return e.firstChildElement("query").attribute("xmlns");
215 }
216
217 /**
218 \brief Extracts the error code and description from the stanza element.
219
220 This function finds the error element in the given stanza element \a e.
221
222 You need to provide the base namespace of the stream to which this stanza belongs to
223 (probably by using stream.baseNS() function).
224
225 The error description is either error text extracted from XML
226 or - if no text is found - the error name and description (separated by '\n') taken from RFC-3920
227 or - if the error is not defined in the RFC - the empty string.
228
229 Note: This function uses the Stanza::Error class,
230 so it may guess missing values as defined in JEP-0086.
231
232 \param e the element representing stanza
233 \param baseNS the base namespace of the stream
234 \param code if not NULL, will be filled with numeric error code
235 \param str if not NULL, will be filled with human readable error description
236 */
237
getErrorFromElement(const QDomElement & e,const QString & baseNS,int * code,QString * str)238 void getErrorFromElement(const QDomElement &e, const QString &baseNS, int *code, QString *str)
239 {
240 QDomElement tag = e.firstChildElement("error");
241 if(tag.isNull())
242 return;
243
244 XMPP::Stanza::Error err;
245 err.fromXml(tag, baseNS);
246
247 if(code)
248 *code = err.code();
249 if(str) {
250 QPair<QString, QString> desc = err.description();
251 if (err.text.isEmpty())
252 *str = desc.first + ".\n" + desc.second;
253 else
254 *str = desc.first + ".\n" + desc.second + "\n" + err.text;
255 }
256
257 }
258
addCorrectNS(const QDomElement & e)259 QDomElement addCorrectNS(const QDomElement &e)
260 {
261 int x;
262
263 // grab child nodes
264 /*QDomDocumentFragment frag = e.ownerDocument().createDocumentFragment();
265 QDomNodeList nl = e.childNodes();
266 for(x = 0; x < nl.count(); ++x)
267 frag.appendChild(nl.item(x).cloneNode());*/
268
269 // find closest xmlns
270 QDomNode n = e;
271 while(!n.isNull() && !n.toElement().hasAttribute("xmlns") && n.toElement().namespaceURI() == "" )
272 n = n.parentNode();
273 QString ns;
274 if(n.isNull() || !n.toElement().hasAttribute("xmlns")){
275 if (n.toElement().namespaceURI () == ""){
276 ns = "jabber:client";
277 } else {
278 ns = n.toElement().namespaceURI();
279 }
280 } else {
281 ns = n.toElement().attribute("xmlns");
282 }
283 // make a new node
284 QDomElement i = e.ownerDocument().createElementNS(ns, e.tagName());
285
286 // copy attributes
287 QDomNamedNodeMap al = e.attributes();
288 for(x = 0; x < al.count(); ++x) {
289 QDomAttr a = al.item(x).toAttr();
290 if(a.name() != "xmlns")
291 i.setAttributeNodeNS(a.cloneNode().toAttr());
292 }
293
294 // copy children
295 QDomNodeList nl = e.childNodes();
296 for(x = 0; x < nl.count(); ++x) {
297 QDomNode n = nl.item(x);
298 if(n.isElement())
299 i.appendChild(addCorrectNS(n.toElement()));
300 else
301 i.appendChild(n.cloneNode());
302 }
303
304 //i.appendChild(frag);
305 return i;
306 }
307
308 //----------------------------------------------------------------------------
309 // XMLHelper
310 //----------------------------------------------------------------------------
311
312 namespace XMLHelper {
313
emptyTag(QDomDocument * doc,const QString & name)314 QDomElement emptyTag(QDomDocument *doc, const QString &name)
315 {
316 QDomElement tag = doc->createElement(name);
317
318 return tag;
319 }
320
hasSubTag(const QDomElement & e,const QString & name)321 bool hasSubTag(const QDomElement &e, const QString &name)
322 {
323 return !e.firstChildElement(name).isNull();
324 }
325
subTagText(const QDomElement & e,const QString & name)326 QString subTagText(const QDomElement &e, const QString &name)
327 {
328 QDomElement i = e.firstChildElement(name);
329 if ( !i.isNull() )
330 return i.text();
331 return QString::null;
332 }
333
textTag(QDomDocument & doc,const QString & name,const QString & content)334 QDomElement textTag(QDomDocument &doc, const QString &name, const QString &content)
335 {
336 QDomElement tag = doc.createElement(name);
337 QDomText text = doc.createTextNode(content);
338 tag.appendChild(text);
339
340 return tag;
341 }
342
textTag(QDomDocument & doc,const QString & name,int content)343 QDomElement textTag(QDomDocument &doc, const QString &name, int content)
344 {
345 QDomElement tag = doc.createElement(name);
346 QDomText text = doc.createTextNode(QString::number(content));
347 tag.appendChild(text);
348
349 return tag;
350 }
351
textTag(QDomDocument & doc,const QString & name,bool content)352 QDomElement textTag(QDomDocument &doc, const QString &name, bool content)
353 {
354 QDomElement tag = doc.createElement(name);
355 QDomText text = doc.createTextNode(content ? "true" : "false");
356 tag.appendChild(text);
357
358 return tag;
359 }
360
textTag(QDomDocument & doc,const QString & name,QSize & s)361 QDomElement textTag(QDomDocument &doc, const QString &name, QSize &s)
362 {
363 QString str;
364 str.sprintf("%d,%d", s.width(), s.height());
365
366 QDomElement tag = doc.createElement(name);
367 QDomText text = doc.createTextNode(str);
368 tag.appendChild(text);
369
370 return tag;
371 }
372
textTag(QDomDocument & doc,const QString & name,QRect & r)373 QDomElement textTag(QDomDocument &doc, const QString &name, QRect &r)
374 {
375 QString str;
376 str.sprintf("%d,%d,%d,%d", r.x(), r.y(), r.width(), r.height());
377
378 QDomElement tag = doc.createElement(name);
379 QDomText text = doc.createTextNode(str);
380 tag.appendChild(text);
381
382 return tag;
383 }
384
stringListToXml(QDomDocument & doc,const QString & name,const QStringList & l)385 QDomElement stringListToXml(QDomDocument &doc, const QString &name, const QStringList &l)
386 {
387 QDomElement tag = doc.createElement(name);
388 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
389 tag.appendChild(textTag(doc, "item", *it));
390
391 return tag;
392 }
393
394 /*QString tagContent(const QDomElement &e)
395 {
396 // look for some tag content
397 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
398 QDomText i = n.toText();
399 if(i.isNull())
400 continue;
401 return i.data();
402 }
403
404 return "";
405 }*/
406
407 /*QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found)
408 {
409 if(found)
410 *found = FALSE;
411
412 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
413 QDomElement i = n.toElement();
414 if(i.isNull())
415 continue;
416 if(i.tagName() == name) {
417 if(found)
418 *found = TRUE;
419 return i;
420 }
421 }
422
423 QDomElement tmp;
424 return tmp;
425 }*/
426
readEntry(const QDomElement & e,const QString & name,QString * v)427 void readEntry(const QDomElement &e, const QString &name, QString *v)
428 {
429 QDomElement tag = e.firstChildElement(name);
430 if(tag.isNull())
431 return;
432 *v = tagContent(tag);
433 }
434
readNumEntry(const QDomElement & e,const QString & name,int * v)435 void readNumEntry(const QDomElement &e, const QString &name, int *v)
436 {
437 QDomElement tag = e.firstChildElement(name);
438 if(tag.isNull())
439 return;
440 *v = tagContent(tag).toInt();
441 }
442
readBoolEntry(const QDomElement & e,const QString & name,bool * v)443 void readBoolEntry(const QDomElement &e, const QString &name, bool *v)
444 {
445 QDomElement tag = e.firstChildElement(name);
446 if(tag.isNull())
447 return;
448 *v = (tagContent(tag) == "true") ? true: false;
449 }
450
readSizeEntry(const QDomElement & e,const QString & name,QSize * v)451 void readSizeEntry(const QDomElement &e, const QString &name, QSize *v)
452 {
453 QDomElement tag = e.firstChildElement(name);
454 if(tag.isNull())
455 return;
456 QStringList list = tagContent(tag).split(',');
457 if(list.count() != 2)
458 return;
459 QSize s;
460 s.setWidth(list[0].toInt());
461 s.setHeight(list[1].toInt());
462 *v = s;
463 }
464
readRectEntry(const QDomElement & e,const QString & name,QRect * v)465 void readRectEntry(const QDomElement &e, const QString &name, QRect *v)
466 {
467 QDomElement tag = e.firstChildElement(name);
468 if(tag.isNull())
469 return;
470 QStringList list = tagContent(tag).split(',');
471 if(list.count() != 4)
472 return;
473 QRect r;
474 r.setX(list[0].toInt());
475 r.setY(list[1].toInt());
476 r.setWidth(list[2].toInt());
477 r.setHeight(list[3].toInt());
478 *v = r;
479 }
480
readColorEntry(const QDomElement & e,const QString & name,QColor * v)481 void readColorEntry(const QDomElement &e, const QString &name, QColor *v)
482 {
483 QDomElement tag = e.firstChildElement(name);
484 if(tag.isNull())
485 return;
486 QColor c;
487 c.setNamedColor(tagContent(tag));
488 if(c.isValid())
489 *v = c;
490 }
491
xmlToStringList(const QDomElement & e,const QString & name,QStringList * v)492 void xmlToStringList(const QDomElement &e, const QString &name, QStringList *v)
493 {
494 QDomElement tag = e.firstChildElement(name);
495 if(tag.isNull())
496 return;
497 QStringList list;
498 for(QDomNode n = tag.firstChild(); !n.isNull(); n = n.nextSibling()) {
499 QDomElement i = n.toElement();
500 if(i.isNull())
501 continue;
502 if(i.tagName() == "item")
503 list += tagContent(i);
504 }
505 *v = list;
506 }
507
setBoolAttribute(QDomElement e,const QString & name,bool b)508 void setBoolAttribute(QDomElement e, const QString &name, bool b)
509 {
510 e.setAttribute(name, b ? "true" : "false");
511 }
512
readBoolAttribute(QDomElement e,const QString & name,bool * v)513 void readBoolAttribute(QDomElement e, const QString &name, bool *v)
514 {
515 if(e.hasAttribute(name)) {
516 QString s = e.attribute(name);
517 *v = (s == "true") ? true: false;
518 }
519 }
520
521 };
522
523