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

0001 /*
0002  * xmpp_xdata.cpp - a class for jabber:x:data forms
0003  * Copyright (C) 2003-2004  Michail Pishchagin
0004  *
0005  * This program is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU General Public License
0007  * as published by the Free Software Foundation; either version 2
0008  * of the License, or (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with this library; if not, write to the Free Software
0017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0018  *
0019  */
0020 
0021 #include "xmpp_xdata.h"
0022 #include "xmpp_xmlcommon.h"
0023 #include "xmpp/jid/jid.h"
0024 
0025 
0026 using namespace XMPP;
0027 using namespace XMLHelper;
0028 
0029 // TODO: report, item
0030 
0031 //----------------------------------------------------------------------------
0032 // XData::Field
0033 //----------------------------------------------------------------------------
0034 XData::Field::Field()
0035 {
0036 }
0037 
0038 XData::Field::~Field()
0039 {
0040 }
0041 
0042 QString XData::Field::desc() const
0043 {
0044     return _desc;
0045 }
0046 
0047 void XData::Field::setDesc(const QString &d)
0048 {
0049     _desc = d;
0050 }
0051 
0052 XData::Field::OptionList XData::Field::options() const
0053 {
0054     return _options;
0055 }
0056 
0057 void XData::Field::setOptions(XData::Field::OptionList o)
0058 {
0059     _options = o;
0060 }
0061 
0062 bool XData::Field::required() const
0063 {
0064     return _required;
0065 }
0066 
0067 void XData::Field::setRequired(bool r)
0068 {
0069     _required = r;
0070 }
0071 
0072 QString XData::Field::label() const
0073 {
0074     return _label;
0075 }
0076 
0077 void XData::Field::setLabel(const QString &l)
0078 {
0079     _label = l;
0080 }
0081 
0082 QString XData::Field::var() const
0083 {
0084     return _var;
0085 }
0086 
0087 void XData::Field::setVar(const QString &v)
0088 {
0089     _var = v;
0090 }
0091 
0092 QStringList XData::Field::value() const
0093 {
0094     return _value;
0095 }
0096 
0097 void XData::Field::setValue(const QStringList &v)
0098 {
0099     _value = v;
0100 }
0101 
0102 XData::Field::Type XData::Field::type() const
0103 {
0104     return _type;
0105 }
0106 
0107 void XData::Field::setType(XData::Field::Type t)
0108 {
0109     _type = t;
0110 }
0111 
0112 bool XData::Field::isValid() const
0113 {
0114     if ( _required && _value.isEmpty() )
0115         return false;
0116 
0117     if ( _type == Field_Hidden || _type == Field_Fixed) {
0118         return true;
0119     }
0120     if ( _type == Field_Boolean ) {
0121         if ( _value.count() != 1 )
0122             return false;
0123 
0124         QString str = _value.first();
0125         if ( str == "0" || str == "1" || str == "true" || str == "false" || str == "yes" || str == "no" )
0126             return true;
0127     }
0128     if ( _type == Field_TextSingle || _type == Field_TextPrivate ) {
0129         if ( _value.count() == 1 )
0130             return true;
0131     }
0132     if ( _type == Field_TextMulti ) {
0133         //no particular test. empty/required case already caught (see above)
0134         return true;
0135     }
0136     if ( _type == Field_ListSingle || _type == Field_ListMulti ) {
0137         //no particular test. empty/required case already caught (see above)
0138         return true;
0139     }
0140     if ( _type == Field_JidSingle ) {
0141         if ( _value.count() != 1 )
0142             return false;
0143 
0144         Jid j( _value.first() );
0145         return j.isValid();
0146     }
0147     if ( _type == Field_JidMulti ) {
0148         QStringList::ConstIterator it = _value.begin();
0149         bool allValid = true;
0150         for ( ; it != _value.end(); ++it) {
0151             Jid j(*it);
0152             if ( !j.isValid() ) {
0153                 allValid = false;
0154                 break;
0155             }
0156         }
0157         return allValid;
0158     }
0159 
0160     return false;
0161 }
0162 
0163 void XData::Field::fromXml(const QDomElement &e)
0164 {
0165     if ( e.tagName() != "field" )
0166         return;
0167 
0168     _var = e.attribute("var");
0169     _label = e.attribute("label");
0170 
0171     QString type = e.attribute("type");
0172     if ( type == "boolean" )
0173         _type = Field_Boolean;
0174     else if ( type == "fixed" )
0175         _type = Field_Fixed;
0176     else if ( type == "hidden" )
0177         _type = Field_Hidden;
0178     else if ( type == "jid-multi" )
0179         _type = Field_JidMulti;
0180     else if ( type == "jid-single" )
0181         _type = Field_JidSingle;
0182     else if ( type == "list-multi" )
0183         _type = Field_ListMulti;
0184     else if ( type == "list-single" )
0185         _type = Field_ListSingle;
0186     else if ( type == "text-multi" )
0187         _type = Field_TextMulti;
0188     else if ( type == "text-private" )
0189         _type = Field_TextPrivate;
0190     else
0191         _type = Field_TextSingle;
0192 
0193     _required = false;
0194     _desc     = QString();
0195     _options.clear();
0196     _value.clear();
0197 
0198     QDomNode n = e.firstChild();
0199     for ( ; !n.isNull(); n = n.nextSibling() ) {
0200         QDomElement i = n.toElement();
0201         if ( i.isNull() )
0202             continue;
0203 
0204         QString tag = i.tagName();
0205         if ( tag == "required" )
0206             _required = true;
0207         else if ( tag == "desc" )
0208             _desc = i.text().trimmed();
0209         else if ( tag == "option" ) {
0210             Option o;
0211             bool found;
0212             o.label = i.attribute("label");
0213 
0214             QDomElement e = findSubTag( i, "value", &found );
0215             o.value = ( found ? e.text() : QString("") );
0216             _options.append(o);
0217         }
0218         else if ( tag == "value" ) {
0219             _value.append(i.text());
0220         }
0221     }
0222 }
0223 
0224 QDomElement XData::Field::toXml(QDomDocument *doc, bool submitForm) const
0225 {
0226     QDomElement f = doc->createElement("field");
0227 
0228     // setting attributes...
0229     if ( !_var.isEmpty() )
0230         f.setAttribute("var", _var);
0231     if ( !submitForm && !_label.isEmpty() )
0232         f.setAttribute("label", _label);
0233 
0234     // now we're gonna get the 'type'
0235     QString type = "text-single";
0236     if ( _type == Field_Boolean )
0237         type = "boolean";
0238     else if ( _type == Field_Fixed )
0239         type = "fixed";
0240     else if ( _type == Field_Hidden )
0241         type = "hidden";
0242     else if ( _type == Field_JidMulti )
0243         type = "jid-multi";
0244     else if ( _type == Field_JidSingle )
0245         type = "jid-single";
0246     else if ( _type == Field_ListMulti )
0247         type = "list-multi";
0248     else if ( _type == Field_ListSingle )
0249         type = "list-single";
0250     else if ( _type == Field_TextMulti )
0251         type = "text-multi";
0252     else if ( _type == Field_TextPrivate )
0253         type = "text-private";
0254 
0255     f.setAttribute("type", type);
0256 
0257     // now, setting nested tags...
0258     if ( !submitForm && _required )
0259         f.appendChild( emptyTag(doc, "required") );
0260 
0261     if ( !submitForm && !_desc.isEmpty() )
0262         f.appendChild( textTag(doc, "desc", _desc) );
0263 
0264     if ( !submitForm && !_options.isEmpty() ) {
0265         OptionList::ConstIterator it = _options.begin();
0266         for ( ; it != _options.end(); ++it) {
0267             QDomElement o = doc->createElement("option");
0268             o.appendChild(textTag(doc, "value", (*it).value));
0269             if ( !(*it).label.isEmpty() )
0270                 o.setAttribute("label", (*it).label);
0271             f.appendChild(o);
0272         }
0273     }
0274 
0275     if ( !_value.isEmpty() ) {
0276         QStringList::ConstIterator it = _value.begin();
0277         for ( ; it != _value.end(); ++it) 
0278             f.appendChild( textTag(doc, "value", *it) );
0279     }
0280 
0281     return f;
0282 }
0283 
0284 //----------------------------------------------------------------------------
0285 // XData
0286 //----------------------------------------------------------------------------
0287 
0288 XData::XData()
0289 {
0290     d = new Private;
0291     d->type = Data_Form;
0292 }
0293 
0294 QString XData::title() const
0295 {
0296     return d->title;
0297 }
0298 
0299 void XData::setTitle(const QString &t)
0300 {
0301     d->title = t;
0302 }
0303 
0304 QString XData::instructions() const
0305 {
0306     return d->instructions;
0307 }
0308 
0309 void XData::setInstructions(const QString &i)
0310 {
0311     d->instructions = i;
0312 }
0313 
0314 XData::Type XData::type() const
0315 {
0316     return d->type;
0317 }
0318 
0319 void XData::setType(Type t)
0320 {
0321     d->type = t;
0322 }
0323 
0324 XData::FieldList XData::fields() const
0325 {
0326     return d->fields;
0327 }
0328 
0329 void XData::setFields(const FieldList &f)
0330 {
0331     d->fields = f;
0332 }
0333 
0334 void XData::fromXml(const QDomElement &e)
0335 {
0336     if ( (e.attribute("xmlns") != "jabber:x:data") && (e.namespaceURI() != "jabber:x:data") )
0337         return;
0338 
0339     QString type = e.attribute("type");
0340     if ( type == "result" )
0341         d->type = Data_Result;
0342     else if ( type == "submit" )
0343         d->type = Data_Submit;
0344     else if ( type == "cancel" )
0345         d->type = Data_Cancel;
0346     else
0347         d->type = Data_Form;
0348 
0349     d->title        = subTagText(e, "title");
0350     d->instructions = subTagText(e, "instructions");
0351 
0352     d->fields.clear();
0353 
0354     QDomNode n = e.firstChild();
0355     for ( ; !n.isNull(); n = n.nextSibling() ) {
0356         QDomElement i = n.toElement();
0357         if ( i.isNull() )
0358             continue;
0359 
0360         if ( i.tagName() == "field" ) {
0361             Field f;
0362             f.fromXml(i);
0363             d->fields.append(f);
0364         }
0365         else if ( i.tagName() == "reported" ) {
0366             d->report.clear();
0367             d->reportItems.clear();
0368 
0369             QDomNode nn = i.firstChild();
0370             for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
0371                 QDomElement ii = nn.toElement();
0372                 if ( ii.isNull() )
0373                     continue;
0374 
0375                 if ( ii.tagName() == "field" ) {
0376                     d->report.append( ReportField( ii.attribute("label"), ii.attribute("var") ) );
0377                 }
0378             }
0379         }
0380         else if ( i.tagName() == "item" ) {
0381             ReportItem item;
0382 
0383             QDomNode nn = i.firstChild();
0384             for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
0385                 QDomElement ii = nn.toElement();
0386                 if ( ii.isNull() )
0387                     continue;
0388 
0389                 if ( ii.tagName() == "field" ) {
0390                     QString name = ii.attribute("var");
0391                     QString value;
0392 
0393                     bool found;
0394                     QDomElement e = findSubTag( ii, "value", &found );
0395                     if ( found )
0396                         value = e.text();
0397 
0398                     item[name] = value;
0399                 }
0400             }
0401 
0402             d->reportItems.append( item );
0403         }
0404     }
0405 }
0406 
0407 QDomElement XData::toXml(QDomDocument *doc, bool submitForm) const
0408 {
0409     QDomElement x = doc->createElementNS("jabber:x:data", "x");
0410     x.setAttribute("xmlns", "jabber:x:data");
0411 
0412     QString type = "form";
0413     if ( d->type == Data_Result )
0414         type = "result";
0415     else if ( d->type == Data_Submit )
0416         type = "submit";
0417     else if ( d->type == Data_Cancel )
0418         type = "cancel";
0419 
0420     x.setAttribute("type", type);
0421 
0422     if ( !submitForm && !d->title.isEmpty() )
0423         x.appendChild( textTag(doc, "title", d->title) );
0424     if ( !submitForm && !d->instructions.isEmpty() )
0425         x.appendChild( textTag(doc, "instructions", d->instructions) );
0426 
0427     if ( !d->fields.isEmpty() ) {
0428         FieldList::ConstIterator it = d->fields.begin();
0429         for ( ; it != d->fields.end(); ++it) {
0430             Field f = *it;
0431             if ( !(submitForm && f.var().isEmpty()) )
0432                 x.appendChild( f.toXml(doc, submitForm) );
0433         }
0434     }
0435 
0436     return x;
0437 }
0438 
0439 const QList<XData::ReportField> &XData::report() const
0440 {
0441     return d->report;
0442 }
0443 
0444 const QList<XData::ReportItem> &XData::reportItems() const
0445 {
0446     return d->reportItems;
0447 }
0448 
0449 bool XData::isValid() const
0450 {
0451     foreach(Field f, d->fields) {
0452         if (!f.isValid())
0453             return false;
0454     }
0455     return true;
0456 }