File indexing completed on 2024-06-23 04:03:44

0001 /*
0002  * xmlcommon.cpp - helper functions for dealing with XML
0003  * Copyright (C) 2001, 2002  Justin Karneges
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Lesser General Public
0007  * License as published by the Free Software Foundation; either
0008  * either version 2
0009    of the License, or (at your option) any later version.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library; if not, write to the Free Software
0018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019  *
0020  */
0021 
0022 #include "xmpp_xmlcommon.h"
0023 #include "xmpp_stanza.h"
0024 
0025 #include <QString>
0026 #include <QDateTime>
0027 #include <QSize>
0028 #include <QRect>
0029 #include <QColor>
0030 
0031 //----------------------------------------------------------------------------
0032 // XDomNodeList
0033 //----------------------------------------------------------------------------
0034 XDomNodeList::XDomNodeList()
0035 {
0036 }
0037 
0038 XDomNodeList::XDomNodeList(const XDomNodeList &from) :
0039     list(from.list)
0040 {
0041 }
0042 
0043 XDomNodeList::XDomNodeList(const QDomNodeList &from)
0044 {
0045     for(int n = 0; n < from.count(); ++n)
0046         list += from.item(n);
0047 }
0048 
0049 XDomNodeList::~XDomNodeList()
0050 {
0051 }
0052 
0053 XDomNodeList & XDomNodeList::operator=(const XDomNodeList &from)
0054 {
0055     list = from.list;
0056     return *this;
0057 }
0058 
0059 bool XDomNodeList::isEmpty() const
0060 {
0061     return list.isEmpty();
0062 }
0063 
0064 QDomNode XDomNodeList::item(int index) const
0065 {
0066     return list.value(index);
0067 }
0068 
0069 uint XDomNodeList::length() const
0070 {
0071     return (uint)list.count();
0072 }
0073 
0074 bool XDomNodeList::operator==(const XDomNodeList &a) const
0075 {
0076     return (list == a.list);
0077 }
0078 
0079 void XDomNodeList::append(const QDomNode &i)
0080 {
0081     list += i;
0082 }
0083 
0084 
0085 QDateTime stamp2TS(const QString &ts)
0086 {
0087     if(ts.length() != 17)
0088         return QDateTime();
0089     int year  = QStringView(ts).mid(0,4).toInt();
0090     int month = QStringView(ts).mid(4,2).toInt();
0091     int day   = QStringView(ts).mid(6,2).toInt();
0092 
0093     int hour  = QStringView(ts).mid(9,2).toInt();
0094     int min   = QStringView(ts).mid(12,2).toInt();
0095     int sec   = QStringView(ts).mid(15,2).toInt();
0096 
0097     QDate xd;
0098     xd.setDate(year, month, day);
0099     if(!xd.isValid())
0100         return QDateTime();
0101 
0102     QTime xt;
0103     xt.setHMS(hour, min, sec);
0104     if(!xt.isValid())
0105         return QDateTime();
0106 
0107     return QDateTime(xd, xt);
0108 }
0109 
0110 bool stamp2TS(const QString &ts, QDateTime *d)
0111 {
0112     QDateTime dateTime = stamp2TS(ts);
0113     if (dateTime.isNull())
0114         return false;
0115 
0116     *d = dateTime;
0117 
0118     return true;
0119 }
0120 
0121 QString TS2stamp(const QDateTime &d)
0122 {
0123     const QString str = QString::asprintf("%04d%02d%02dT%02d:%02d:%02d",
0124         d.date().year(),
0125         d.date().month(),
0126         d.date().day(),
0127         d.time().hour(),
0128         d.time().minute(),
0129         d.time().second());
0130 
0131     return str;
0132 }
0133 
0134 QDomElement textTag(QDomDocument *doc, const QString &name, const QString &content)
0135 {
0136     QDomElement tag = doc->createElement(name);
0137     QDomText text = doc->createTextNode(content);
0138     tag.appendChild(text);
0139 
0140     return tag;
0141 }
0142 
0143 QString tagContent(const QDomElement &e)
0144 {
0145     // look for some tag content
0146     for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
0147         QDomText i = n.toText();
0148         if(i.isNull())
0149             continue;
0150         return i.data();
0151     }
0152 
0153     return "";
0154 }
0155 
0156 
0157 /**
0158  * \brief find an direct child element by name
0159  * \param e parent element
0160  * \param name name of element to find
0161  * \param found (optional/out) found?
0162  * \return the element (or a null QDomElemnt if not found)
0163  */
0164 QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found)
0165 {
0166     if(found)
0167         *found = false;
0168 
0169     for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
0170         QDomElement i = n.toElement();
0171         if(i.isNull())
0172             continue;
0173         if(i.tagName() == name) {
0174             if(found)
0175                 *found = true;
0176             return i;
0177         }
0178     }
0179 
0180     QDomElement tmp;
0181     return tmp;
0182 }
0183 
0184 
0185 /**
0186  * \brief obtain direct child elements of a certain kind.  unlike
0187  *        elementsByTagNameNS, this function does not descend beyond the first
0188  *        level of children.
0189  * \param e parent element
0190  * \param nsURI namespace of the elements to find
0191  * \param localName local name of the elements to find
0192  * \return the node list of found elements (empty list if none are found)
0193  */
0194 XDomNodeList childElementsByTagNameNS(const QDomElement &e, const QString &nsURI, const QString &localName)
0195 {
0196     XDomNodeList out;
0197     for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
0198         if(!n.isElement())
0199             continue;
0200         QDomElement i = n.toElement();
0201         if(i.namespaceURI() == nsURI && i.localName() == localName)
0202             out.append(i);
0203     }
0204     return out;
0205 }
0206 
0207 
0208 /**
0209  * \brief create a new IQ stanza
0210  * \param doc 
0211  * \param type 
0212  * \param to destination jid
0213  * \param id stanza id
0214  * \return the created stanza
0215 */
0216 QDomElement createIQ(QDomDocument *doc, const QString &type, const QString &to, const QString &id)
0217 {
0218     QDomElement iq = doc->createElement("iq");
0219     if(!type.isEmpty())
0220         iq.setAttribute("type", type);
0221     if(!to.isEmpty())
0222         iq.setAttribute("to", to);
0223     if(!id.isEmpty())
0224         iq.setAttribute("id", id);
0225 
0226     return iq;
0227 }
0228 
0229 /** \brief returns direct child element named "query"
0230  * \return the element (or a null QDomElemnt if not found)
0231 */
0232 QDomElement queryTag(const QDomElement &e)
0233 {
0234     bool found;
0235     QDomElement q = findSubTag(e, "query", &found);
0236     return q;
0237 }
0238 
0239 QString queryNS(const QDomElement &e)
0240 {
0241     bool found;
0242     QDomElement q = findSubTag(e, "query", &found);
0243     if(found)
0244         return q.attribute("xmlns");
0245 
0246     return "";
0247 }
0248 
0249 /**
0250     \brief Extracts the error code and description from the stanza element.
0251 
0252     This function finds the error element in the given stanza element \a e.
0253 
0254     You need to provide the base namespace of the stream to which this stanza belongs to
0255     (probably by using stream.baseNS() function).
0256 
0257     The error description is either error text extracted from XML
0258     or - if no text is found - the error name and description (separated by '\n') taken from RFC-3920
0259     or - if the error is not defined in the RFC - the empty string.
0260 
0261     Note: This function uses the Stanza::Error class,
0262     so it may guess missing values as defined in JEP-0086.
0263 
0264     \param e    the element representing stanza
0265     \param baseNS   the base namespace of the stream
0266     \param code if not NULL, will be filled with numeric error code
0267     \param str  if not NULL, will be filled with human readable error description
0268 */
0269 
0270 void getErrorFromElement(const QDomElement &e, const QString &baseNS, int *code, QString *str)
0271 {
0272     bool found;
0273     QDomElement tag = findSubTag(e, "error", &found);
0274     if(!found)
0275         return;
0276 
0277     XMPP::Stanza::Error err;
0278     err.fromXml(tag, baseNS);
0279 
0280     if(code)
0281         *code = err.code();
0282     if(str) {
0283         QPair<QString, QString> desc = err.description();
0284         if (err.text.isEmpty())
0285             *str = desc.first + ".\n" + desc.second;
0286         else
0287             *str = desc.first + ".\n" + desc.second + "\n" + err.text;
0288     }
0289 
0290 }
0291 
0292 QDomElement addCorrectNS(const QDomElement &e)
0293 {
0294     int x;
0295 
0296     // grab child nodes
0297     /*QDomDocumentFragment frag = e.ownerDocument().createDocumentFragment();
0298     QDomNodeList nl = e.childNodes();
0299     for(x = 0; x < nl.count(); ++x)
0300         frag.appendChild(nl.item(x).cloneNode());*/
0301 
0302     // find closest xmlns
0303     QDomNode n = e;
0304     while(!n.isNull() && !n.toElement().hasAttribute("xmlns"))
0305         n = n.parentNode();
0306     QString ns;
0307     if(n.isNull() || !n.toElement().hasAttribute("xmlns"))
0308         ns = "jabber:client";
0309     else
0310         ns = n.toElement().attribute("xmlns");
0311 
0312     // make a new node
0313     QDomElement i = e.ownerDocument().createElementNS(ns, e.tagName());
0314 
0315     // copy attributes
0316     QDomNamedNodeMap al = e.attributes();
0317     for(x = 0; x < al.count(); ++x) {
0318         QDomAttr a = al.item(x).toAttr();
0319         if(a.name() != "xmlns")
0320             i.setAttributeNodeNS(a.cloneNode().toAttr());
0321     }
0322 
0323     // copy children
0324     QDomNodeList nl = e.childNodes();
0325     for(x = 0; x < nl.count(); ++x) {
0326         QDomNode n = nl.item(x);
0327         if(n.isElement())
0328             i.appendChild(addCorrectNS(n.toElement()));
0329         else
0330             i.appendChild(n.cloneNode());
0331     }
0332 
0333     //i.appendChild(frag);
0334     return i;
0335 }
0336 
0337 //----------------------------------------------------------------------------
0338 // XMLHelper
0339 //----------------------------------------------------------------------------
0340 
0341 namespace XMLHelper {
0342 
0343 QDomElement emptyTag(QDomDocument *doc, const QString &name)
0344 {
0345     QDomElement tag = doc->createElement(name);
0346 
0347     return tag;
0348 }
0349 
0350 bool hasSubTag(const QDomElement &e, const QString &name)
0351 {
0352     bool found;
0353     findSubTag(e, name, &found);
0354     return found;
0355 }
0356 
0357 QString subTagText(const QDomElement &e, const QString &name)
0358 {
0359     bool found;
0360     QDomElement i = findSubTag(e, name, &found);
0361     if ( found )
0362         return i.text();
0363     return QString();
0364 }
0365 
0366 QDomElement textTag(QDomDocument &doc, const QString &name, const QString &content)
0367 {
0368     QDomElement tag = doc.createElement(name);
0369     QDomText text = doc.createTextNode(content);
0370     tag.appendChild(text);
0371 
0372     return tag;
0373 }
0374 
0375 QDomElement textTag(QDomDocument &doc, const QString &name, int content)
0376 {
0377     QDomElement tag = doc.createElement(name);
0378     QDomText text = doc.createTextNode(QString::number(content));
0379     tag.appendChild(text);
0380 
0381     return tag;
0382 }
0383 
0384 QDomElement textTag(QDomDocument &doc, const QString &name, bool content)
0385 {
0386     QDomElement tag = doc.createElement(name);
0387     QDomText text = doc.createTextNode(content ? "true" : "false");
0388     tag.appendChild(text);
0389 
0390     return tag;
0391 }
0392 
0393 QDomElement textTag(QDomDocument &doc, const QString &name, QSize &s)
0394 {
0395     const QString str = QString::asprintf("%d,%d", s.width(), s.height());
0396 
0397     QDomElement tag = doc.createElement(name);
0398     QDomText text = doc.createTextNode(str);
0399     tag.appendChild(text);
0400 
0401     return tag;
0402 }
0403 
0404 QDomElement textTag(QDomDocument &doc, const QString &name, QRect &r)
0405 {
0406     const QString str = QString::asprintf("%d,%d,%d,%d", r.x(), r.y(), r.width(), r.height());
0407 
0408     QDomElement tag = doc.createElement(name);
0409     QDomText text = doc.createTextNode(str);
0410     tag.appendChild(text);
0411 
0412     return tag;
0413 }
0414 
0415 QDomElement stringListToXml(QDomDocument &doc, const QString &name, const QStringList &l)
0416 {
0417     QDomElement tag = doc.createElement(name);
0418     for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
0419         tag.appendChild(textTag(doc, "item", *it));
0420 
0421     return tag;
0422 }
0423 
0424 /*QString tagContent(const QDomElement &e)
0425 {
0426     // look for some tag content
0427     for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
0428         QDomText i = n.toText();
0429         if(i.isNull())
0430             continue;
0431         return i.data();
0432     }
0433 
0434     return "";
0435 }*/
0436 
0437 /*QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found)
0438 {
0439     if(found)
0440         *found = false;
0441 
0442     for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
0443         QDomElement i = n.toElement();
0444         if(i.isNull())
0445             continue;
0446         if(i.tagName() == name) {
0447             if(found)
0448                 *found = true;
0449             return i;
0450         }
0451     }
0452 
0453     QDomElement tmp;
0454     return tmp;
0455 }*/
0456 
0457 void readEntry(const QDomElement &e, const QString &name, QString *v)
0458 {
0459     bool found = false;
0460     QDomElement tag = findSubTag(e, name, &found);
0461     if(!found)
0462         return;
0463     *v = tagContent(tag);
0464 }
0465 
0466 void readNumEntry(const QDomElement &e, const QString &name, int *v)
0467 {
0468     bool found = false;
0469     QDomElement tag = findSubTag(e, name, &found);
0470     if(!found)
0471         return;
0472     *v = tagContent(tag).toInt();
0473 }
0474 
0475 void readBoolEntry(const QDomElement &e, const QString &name, bool *v)
0476 {
0477     bool found = false;
0478     QDomElement tag = findSubTag(e, name, &found);
0479     if(!found)
0480         return;
0481     *v = (tagContent(tag) == "true") ? true: false;
0482 }
0483 
0484 void readSizeEntry(const QDomElement &e, const QString &name, QSize *v)
0485 {
0486     bool found = false;
0487     QDomElement tag = findSubTag(e, name, &found);
0488     if(!found)
0489         return;
0490     QStringList list = tagContent(tag).split(',');
0491     if(list.count() != 2)
0492         return;
0493     QSize s;
0494     s.setWidth(list[0].toInt());
0495     s.setHeight(list[1].toInt());
0496     *v = s;
0497 }
0498 
0499 void readRectEntry(const QDomElement &e, const QString &name, QRect *v)
0500 {
0501     bool found = false;
0502     QDomElement tag = findSubTag(e, name, &found);
0503     if(!found)
0504         return;
0505     QStringList list = tagContent(tag).split(',');
0506     if(list.count() != 4)
0507         return;
0508     QRect r;
0509     r.setX(list[0].toInt());
0510     r.setY(list[1].toInt());
0511     r.setWidth(list[2].toInt());
0512     r.setHeight(list[3].toInt());
0513     *v = r;
0514 }
0515 
0516 void readColorEntry(const QDomElement &e, const QString &name, QColor *v)
0517 {
0518     bool found = false;
0519     QDomElement tag = findSubTag(e, name, &found);
0520     if(!found)
0521         return;
0522     QColor c;
0523     c.setNamedColor(tagContent(tag));
0524     if(c.isValid())
0525         *v = c;
0526 }
0527 
0528 void xmlToStringList(const QDomElement &e, const QString &name, QStringList *v)
0529 {
0530     bool found = false;
0531     QDomElement tag = findSubTag(e, name, &found);
0532     if(!found)
0533         return;
0534     QStringList list;
0535     for(QDomNode n = tag.firstChild(); !n.isNull(); n = n.nextSibling()) {
0536         QDomElement i = n.toElement();
0537         if(i.isNull())
0538             continue;
0539         if(i.tagName() == "item")
0540             list += tagContent(i);
0541     }
0542     *v = list;
0543 }
0544 
0545 void setBoolAttribute(QDomElement e, const QString &name, bool b)
0546 {
0547     e.setAttribute(name, b ? "true" : "false");
0548 }
0549 
0550 void readBoolAttribute(QDomElement e, const QString &name, bool *v)
0551 {
0552     if(e.hasAttribute(name)) {
0553         QString s = e.attribute(name);
0554         *v = (s == "true") ? true: false;
0555     }
0556 }
0557 
0558 }
0559