/* * tasks.cpp - basic tasks * Copyright (C) 2001, 2002 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "xmpp_tasks.h" //#include //#include "sha1.h" #include "xmpp_xmlcommon.h" //#include "xmpp_stream.h" //#include "xmpp_types.h" #include "xmpp_vcard.h" #include #include using namespace XMPP; static QString lineEncode(QString str) { str.replace(QRegExp("\\\\"), "\\\\"); // backslash to double-backslash str.replace(QRegExp("\\|"), "\\p"); // pipe to \p str.replace(QRegExp("\n"), "\\n"); // newline to \n return str; } static QString lineDecode(const QString &str) { QString ret; for(int n = 0; n < str.length(); ++n) { if(str.at(n) == '\\') { ++n; if(n >= str.length()) break; if(str.at(n) == 'n') ret.append('\n'); if(str.at(n) == 'p') ret.append('|'); if(str.at(n) == '\\') ret.append('\\'); } else { ret.append(str.at(n)); } } return ret; } static Roster xmlReadRoster(const QDomElement &q, bool push) { Roster r; for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { RosterItem item; item.fromXml(i); if(push) item.setIsPush(true); r += item; } } return r; } //---------------------------------------------------------------------------- // JT_Session //---------------------------------------------------------------------------- // #include "protocol.h" JT_Session::JT_Session(Task *parent) : Task(parent) { } void JT_Session::onGo() { QDomElement iq = createIQ(doc(), "set", "", id()); QDomElement session = doc()->createElement("session"); session.setAttribute("xmlns",NS_SESSION); iq.appendChild(session); send(iq); } bool JT_Session::take(const QDomElement& x) { if(!iqVerify(x, "", id())) return false; if(x.attribute("type") == "result") { setSuccess(); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_Register //---------------------------------------------------------------------------- class JT_Register::Private { public: Private() {} Form form; XData xdata; bool hasXData; Jid jid; int type; }; JT_Register::JT_Register(Task *parent) :Task(parent) { d = new Private; d->type = -1; d->hasXData = false; } JT_Register::~JT_Register() { delete d; } void JT_Register::reg(const QString &user, const QString &pass) { d->type = 0; to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); query.appendChild(textTag(doc(), "username", user)); query.appendChild(textTag(doc(), "password", pass)); } void JT_Register::changepw(const QString &pass) { d->type = 1; to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); query.appendChild(textTag(doc(), "username", client()->user())); query.appendChild(textTag(doc(), "password", pass)); } void JT_Register::unreg(const Jid &j) { d->type = 2; to = j.isEmpty() ? client()->host() : j.full(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); // this may be useful if(!d->form.key().isEmpty()) query.appendChild(textTag(doc(), "key", d->form.key())); query.appendChild(doc()->createElement("remove")); } void JT_Register::getForm(const Jid &j) { d->type = 3; to = j; iq = createIQ(doc(), "get", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); } void JT_Register::setForm(const Form &form) { d->type = 4; to = form.jid(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); // key? if(!form.key().isEmpty()) query.appendChild(textTag(doc(), "key", form.key())); // fields for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) { const FormField &f = *it; query.appendChild(textTag(doc(), f.realName(), f.value())); } } void JT_Register::setForm(const Jid& to, const XData& xdata) { d->type = 4; iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:register"); iq.appendChild(query); query.appendChild(xdata.toXml(doc(), true)); } const Form & JT_Register::form() const { return d->form; } bool JT_Register::hasXData() const { return d->hasXData; } const XData& JT_Register::xdata() const { return d->xdata; } void JT_Register::onGo() { send(iq); } bool JT_Register::take(const QDomElement &x) { if(!iqVerify(x, to, id())) return false; Jid from(x.attribute("from")); if(x.attribute("type") == "result") { if(d->type == 3) { d->form.clear(); d->form.setJid(from); QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "instructions") d->form.setInstructions(tagContent(i)); else if(i.tagName() == "key") d->form.setKey(tagContent(i)); else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:data") { d->xdata.fromXml(i); d->hasXData = true; } else { FormField f; if(f.setType(i.tagName())) { f.setValue(tagContent(i)); d->form += f; } } } } setSuccess(); } else setError(x); return true; } //---------------------------------------------------------------------------- // JT_UnRegister //---------------------------------------------------------------------------- class JT_UnRegister::Private { public: Private() { } Jid j; JT_Register *jt_reg; }; JT_UnRegister::JT_UnRegister(Task *parent) : Task(parent) { d = new Private; d->jt_reg = 0; } JT_UnRegister::~JT_UnRegister() { delete d->jt_reg; delete d; } void JT_UnRegister::unreg(const Jid &j) { d->j = j; } void JT_UnRegister::onGo() { delete d->jt_reg; d->jt_reg = new JT_Register(this); d->jt_reg->getForm(d->j); connect(d->jt_reg, SIGNAL(finished()), SLOT(getFormFinished())); d->jt_reg->go(false); } void JT_UnRegister::getFormFinished() { disconnect(d->jt_reg, 0, this, 0); d->jt_reg->unreg(d->j); connect(d->jt_reg, SIGNAL(finished()), SLOT(unregFinished())); d->jt_reg->go(false); } void JT_UnRegister::unregFinished() { if ( d->jt_reg->success() ) setSuccess(); else setError(d->jt_reg->statusCode(), d->jt_reg->statusString()); delete d->jt_reg; d->jt_reg = 0; } //---------------------------------------------------------------------------- // JT_Roster //---------------------------------------------------------------------------- class JT_Roster::Private { public: Private() {} Roster roster; QList itemList; }; JT_Roster::JT_Roster(Task *parent) :Task(parent) { type = -1; d = new Private; } JT_Roster::~JT_Roster() { delete d; } void JT_Roster::get() { type = 0; //to = client()->host(); iq = createIQ(doc(), "get", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:roster"); iq.appendChild(query); } void JT_Roster::set(const Jid &jid, const QString &name, const QStringList &groups) { type = 1; //to = client()->host(); QDomElement item = doc()->createElement("item"); item.setAttribute("jid", jid.full()); if(!name.isEmpty()) item.setAttribute("name", name); for(QStringList::ConstIterator it = groups.begin(); it != groups.end(); ++it) item.appendChild(textTag(doc(), "group", *it)); d->itemList += item; } void JT_Roster::remove(const Jid &jid) { type = 1; //to = client()->host(); QDomElement item = doc()->createElement("item"); item.setAttribute("jid", jid.full()); item.setAttribute("subscription", "remove"); d->itemList += item; } void JT_Roster::onGo() { if(type == 0) send(iq); else if(type == 1) { //to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:roster"); iq.appendChild(query); for(QList::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it) query.appendChild(*it); send(iq); } } const Roster & JT_Roster::roster() const { return d->roster; } QString JT_Roster::toString() const { if(type != 1) return ""; QDomElement i = doc()->createElement("request"); i.setAttribute("type", "JT_Roster"); for(QList::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it) i.appendChild(*it); return lineEncode(Stream::xmlToString(i)); return ""; } bool JT_Roster::fromString(const QString &str) { QDomDocument *dd = new QDomDocument; if(!dd->setContent(lineDecode(str).utf8())) return false; QDomElement e = doc()->importNode(dd->documentElement(), true).toElement(); delete dd; if(e.tagName() != "request" || e.attribute("type") != "JT_Roster") return false; type = 1; d->itemList.clear(); for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; d->itemList += i; } return true; } bool JT_Roster::take(const QDomElement &x) { if(!iqVerify(x, client()->host(), id())) return false; // get if(type == 0) { if(x.attribute("type") == "result") { QDomElement q = queryTag(x); d->roster = xmlReadRoster(q, false); setSuccess(); } else { setError(x); } return true; } // set else if(type == 1) { if(x.attribute("type") == "result") setSuccess(); else setError(x); return true; } // remove else if(type == 2) { setSuccess(); return true; } return false; } //---------------------------------------------------------------------------- // JT_PushRoster //---------------------------------------------------------------------------- JT_PushRoster::JT_PushRoster(Task *parent) :Task(parent) { } JT_PushRoster::~JT_PushRoster() { } bool JT_PushRoster::take(const QDomElement &e) { // must be an iq-set tag if(e.tagName() != "iq" || e.attribute("type") != "set") return false; if(!iqVerify(e, client()->host(), "", "jabber:iq:roster")) return false; roster(xmlReadRoster(queryTag(e), true)); send(createIQ(doc(), "result", e.attribute("from"), e.attribute("id"))); return true; } //---------------------------------------------------------------------------- // JT_Presence //---------------------------------------------------------------------------- JT_Presence::JT_Presence(Task *parent) :Task(parent) { type = -1; } JT_Presence::~JT_Presence() { } void JT_Presence::pres(const Status &s) { type = 0; tag = doc()->createElement("presence"); if(!s.isAvailable()) { tag.setAttribute("type", "unavailable"); if(!s.status().isEmpty()) tag.appendChild(textTag(doc(), "status", s.status())); } else { if(s.isInvisible()) tag.setAttribute("type", "invisible"); if(!s.show().isEmpty()) tag.appendChild(textTag(doc(), "show", s.show())); if(!s.status().isEmpty()) tag.appendChild(textTag(doc(), "status", s.status())); tag.appendChild( textTag(doc(), "priority", QString("%1").arg(s.priority()) ) ); if(!s.keyID().isEmpty()) { QDomElement x = textTag(doc(), "x", s.keyID()); x.setAttribute("xmlns", "http://jabber.org/protocol/e2e"); tag.appendChild(x); } if(!s.xsigned().isEmpty()) { QDomElement x = textTag(doc(), "x", s.xsigned()); x.setAttribute("xmlns", "jabber:x:signed"); tag.appendChild(x); } if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) { QDomElement c = doc()->createElement("c"); c.setAttribute("xmlns","http://jabber.org/protocol/caps"); c.setAttribute("node",s.capsNode()); c.setAttribute("ver",s.capsVersion()); if (!s.capsExt().isEmpty()) c.setAttribute("ext",s.capsExt()); tag.appendChild(c); } if(s.isMUC()) { QDomElement m = doc()->createElement("x"); m.setAttribute("xmlns","http://jabber.org/protocol/muc"); if (!s.mucPassword().isEmpty()) { m.appendChild(textTag(doc(),"password",s.mucPassword())); } if (s.hasMUCHistory()) { QDomElement h = doc()->createElement("history"); if (s.mucHistoryMaxChars() >= 0) h.setAttribute("maxchars",s.mucHistoryMaxChars()); if (s.mucHistoryMaxStanzas() >= 0) h.setAttribute("maxstanzas",s.mucHistoryMaxStanzas()); if (s.mucHistorySeconds() >= 0) h.setAttribute("seconds",s.mucHistorySeconds()); m.appendChild(h); } tag.appendChild(m); } if(s.hasPhotoHash()) { QDomElement m = doc()->createElement("x"); m.setAttribute("xmlns", "vcard-temp:x:update"); m.appendChild(textTag(doc(), "photo", s.photoHash())); tag.appendChild(m); } } } void JT_Presence::pres(const Jid &to, const Status &s) { pres(s); tag.setAttribute("to", to.full()); } void JT_Presence::sub(const Jid &to, const QString &subType, const QString& nick) { type = 1; tag = doc()->createElement("presence"); tag.setAttribute("to", to.full()); tag.setAttribute("type", subType); if (!nick.isEmpty()) { QDomElement nick_tag = textTag(doc(),"nick",nick); nick_tag.setAttribute("xmlns","http://jabber.org/protocol/nick"); tag.appendChild(nick_tag); } } void JT_Presence::probe(const Jid &to) { type = 2; tag = doc()->createElement("presence"); tag.setAttribute("to", to.full()); tag.setAttribute("type", "probe"); } void JT_Presence::onGo() { send(tag); setSuccess(); } //---------------------------------------------------------------------------- // JT_PushPresence //---------------------------------------------------------------------------- JT_PushPresence::JT_PushPresence(Task *parent) :Task(parent) { } JT_PushPresence::~JT_PushPresence() { } bool JT_PushPresence::take(const QDomElement &e) { if(e.tagName() != "presence") return false; Jid j(e.attribute("from")); Status p; if(e.hasAttribute("type")) { QString type = e.attribute("type"); if(type == "unavailable") { p.setIsAvailable(false); } else if(type == "error") { QString str = ""; int code = 0; getErrorFromElement(e, client()->stream().baseNS(), &code, &str); p.setError(code, str); } else if(type == "subscribe" || type == "subscribed" || type == "unsubscribe" || type == "unsubscribed") { QString nick; bool found; QDomElement tag = findSubTag(e, "nick", &found); if (found && tag.attribute("xmlns") == "http://jabber.org/protocol/nick") { nick = tagContent(tag); } emit subscription(j, type, nick); return true; } } QDomElement tag; bool found; tag = findSubTag(e, "status", &found); if(found) p.setStatus(tagContent(tag)); tag = findSubTag(e, "show", &found); if(found) p.setShow(tagContent(tag)); tag = findSubTag(e, "priority", &found); if(found) p.setPriority(tagContent(tag).toInt()); for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:delay") { if(i.hasAttribute("stamp")) { QDateTime dt; if(stamp2TS(i.attribute("stamp"), &dt)) dt = dt.addSecs(client()->timeZoneOffset() * 3600); p.setTimeStamp(dt); } } else if(i.tagName() == "x" && i.attribute("xmlns") == "gabber:x:music:info") { QDomElement t; bool found; QString title, state; t = findSubTag(i, "title", &found); if(found) title = tagContent(t); t = findSubTag(i, "state", &found); if(found) state = tagContent(t); if(!title.isEmpty() && state == "playing") p.setSongTitle(title); } else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:signed") { p.setXSigned(tagContent(i)); } else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/e2e") { p.setKeyID(tagContent(i)); } else if(i.tagName() == "c" && i.attribute("xmlns") == "http://jabber.org/protocol/caps") { p.setCapsNode(i.attribute("node")); p.setCapsVersion(i.attribute("ver")); p.setCapsExt(i.attribute("ext")); } else if(i.tagName() == "x" && i.attribute("xmlns") == "vcard-temp:x:update") { QDomElement t; bool found; t = findSubTag(i, "photo", &found); if (found) p.setPhotoHash(tagContent(t)); else p.setPhotoHash(""); } else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/muc#user") { for(QDomNode muc_n = i.firstChild(); !muc_n.isNull(); muc_n = muc_n.nextSibling()) { QDomElement muc_e = muc_n.toElement(); if(muc_e.isNull()) continue; if (muc_e.tagName() == "item") p.setMUCItem(MUCItem(muc_e)); else if (muc_e.tagName() == "status") p.setMUCStatus(muc_e.attribute("code").toInt()); else if (muc_e.tagName() == "destroy") p.setMUCDestroy(MUCDestroy(muc_e)); } } #ifdef YAPSI else if(i.tagName() == "x-notify" && i.attribute("xmlns") == "yandex:informer") { QDomElement t; bool found; t = findSubTag(i, "value", &found); if (found) p.setNotifyValue(tagContent(t)); else p.setNotifyValue(QString()); } #endif } emit presence(j, p); return true; } //---------------------------------------------------------------------------- // JT_Message //---------------------------------------------------------------------------- static QDomElement oldStyleNS(const QDomElement &e) { // find closest parent with a namespace QDomNode par = e.parentNode(); while(!par.isNull() && par.namespaceURI().isNull()) par = par.parentNode(); bool noShowNS = false; if(!par.isNull() && par.namespaceURI() == e.namespaceURI()) noShowNS = true; QDomElement i; int x; //if(noShowNS) i = e.ownerDocument().createElement(e.tagName()); //else // i = e.ownerDocument().createElementNS(e.namespaceURI(), e.tagName()); // copy attributes QDomNamedNodeMap al = e.attributes(); for(x = 0; x < al.count(); ++x) i.setAttributeNode(al.item(x).cloneNode().toAttr()); if(!noShowNS) i.setAttribute("xmlns", e.namespaceURI()); // copy children QDomNodeList nl = e.childNodes(); for(x = 0; x < nl.count(); ++x) { QDomNode n = nl.item(x); if(n.isElement()) i.appendChild(oldStyleNS(n.toElement())); else i.appendChild(n.cloneNode()); } return i; } JT_Message::JT_Message(Task *parent, const Message &msg) :Task(parent) { m = msg; if (m.id().isEmpty()) m.setId(id()); } JT_Message::~JT_Message() { } void JT_Message::onGo() { Stanza s = m.toStanza(&(client()->stream())); QDomElement e = oldStyleNS(s.element()); send(e); setSuccess(); } //---------------------------------------------------------------------------- // JT_PushMessage //---------------------------------------------------------------------------- JT_PushMessage::JT_PushMessage(Task *parent) :Task(parent) { } JT_PushMessage::~JT_PushMessage() { } bool JT_PushMessage::take(const QDomElement &e) { if(e.tagName() != "message") return false; Stanza s = client()->stream().createStanza(addCorrectNS(e)); if(s.isNull()) { //printf("take: bad stanza??\n"); return false; } Message m; if(!m.fromStanza(s, client()->timeZoneOffset())) { //printf("bad message\n"); return false; } message(m); return true; } //---------------------------------------------------------------------------- // JT_GetServices //---------------------------------------------------------------------------- JT_GetServices::JT_GetServices(Task *parent) :Task(parent) { } void JT_GetServices::get(const Jid &j) { agentList.clear(); jid = j; iq = createIQ(doc(), "get", jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:agents"); iq.appendChild(query); } const AgentList & JT_GetServices::agents() const { return agentList; } void JT_GetServices::onGo() { send(iq); } bool JT_GetServices::take(const QDomElement &x) { if(!iqVerify(x, jid, id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); // agents for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "agent") { AgentItem a; a.setJid(Jid(i.attribute("jid"))); QDomElement tag; bool found; tag = findSubTag(i, "name", &found); if(found) a.setName(tagContent(tag)); // determine which namespaces does item support QStringList ns; tag = findSubTag(i, "register", &found); if(found) ns << "jabber:iq:register"; tag = findSubTag(i, "search", &found); if(found) ns << "jabber:iq:search"; tag = findSubTag(i, "groupchat", &found); if(found) ns << "jabber:iq:conference"; tag = findSubTag(i, "transport", &found); if(found) ns << "jabber:iq:gateway"; a.setFeatures(ns); agentList += a; } } setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_VCard //---------------------------------------------------------------------------- class JT_VCard::Private { public: Private() {} QDomElement iq; Jid jid; VCard vcard; }; JT_VCard::JT_VCard(Task *parent) :Task(parent) { type = -1; d = new Private; } JT_VCard::~JT_VCard() { delete d; } void JT_VCard::get(const Jid &_jid) { type = 0; d->jid = _jid; d->iq = createIQ(doc(), "get", type == 1 ? Jid().full() : d->jid.full(), id()); QDomElement v = doc()->createElement("vCard"); v.setAttribute("xmlns", "vcard-temp"); v.setAttribute("version", "2.0"); v.setAttribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN"); d->iq.appendChild(v); } const Jid & JT_VCard::jid() const { return d->jid; } const VCard & JT_VCard::vcard() const { return d->vcard; } void JT_VCard::set(const Jid &j, const VCard &card) { type = 1; d->vcard = card; d->jid = j; d->iq = createIQ(doc(), "set", d->jid.full(), id()); d->iq.appendChild(card.toXml(doc()) ); } void JT_VCard::onGo() { send(d->iq); } bool JT_VCard::take(const QDomElement &x) { Jid to = d->jid; if (to.userHost() == client()->jid().userHost()) to = client()->host(); if(!iqVerify(x, to, id())) return false; if(x.attribute("type") == "result") { if(type == 0) { for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement q = n.toElement(); if(q.isNull()) continue; if(q.tagName().upper() == "VCARD") { if(d->vcard.fromXml(q)) { setSuccess(); return true; } } } setError(ErrDisc + 1, tr("No VCard available")); return true; } else { setSuccess(); return true; } } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_Search //---------------------------------------------------------------------------- class JT_Search::Private { public: Private() {} Jid jid; Form form; QList resultList; }; JT_Search::JT_Search(Task *parent) :Task(parent) { d = new Private; type = -1; } JT_Search::~JT_Search() { delete d; } void JT_Search::get(const Jid &jid) { type = 0; d->jid = jid; iq = createIQ(doc(), "get", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:search"); iq.appendChild(query); } void JT_Search::set(const Form &form) { type = 1; d->jid = form.jid(); iq = createIQ(doc(), "set", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:search"); iq.appendChild(query); // key? if(!form.key().isEmpty()) query.appendChild(textTag(doc(), "key", form.key())); // fields for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) { const FormField &f = *it; query.appendChild(textTag(doc(), f.realName(), f.value())); } } const Form & JT_Search::form() const { return d->form; } const QList & JT_Search::results() const { return d->resultList; } void JT_Search::onGo() { send(iq); } bool JT_Search::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; Jid from(x.attribute("from")); if(x.attribute("type") == "result") { if(type == 0) { d->form.clear(); d->form.setJid(from); QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "instructions") d->form.setInstructions(tagContent(i)); else if(i.tagName() == "key") d->form.setKey(tagContent(i)); else { FormField f; if(f.setType(i.tagName())) { f.setValue(tagContent(i)); d->form += f; } } } } else { d->resultList.clear(); QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { SearchResult r(Jid(i.attribute("jid"))); QDomElement tag; bool found; tag = findSubTag(i, "nick", &found); if(found) r.setNick(tagContent(tag)); tag = findSubTag(i, "first", &found); if(found) r.setFirst(tagContent(tag)); tag = findSubTag(i, "last", &found); if(found) r.setLast(tagContent(tag)); tag = findSubTag(i, "email", &found); if(found) r.setEmail(tagContent(tag)); d->resultList += r; } } } setSuccess(); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_ClientVersion //---------------------------------------------------------------------------- JT_ClientVersion::JT_ClientVersion(Task *parent) :Task(parent) { } void JT_ClientVersion::get(const Jid &jid) { j = jid; iq = createIQ(doc(), "get", j.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:version"); iq.appendChild(query); } void JT_ClientVersion::onGo() { send(iq); } bool JT_ClientVersion::take(const QDomElement &x) { if(!iqVerify(x, j, id())) return false; if(x.attribute("type") == "result") { bool found; QDomElement q = queryTag(x); QDomElement tag; tag = findSubTag(q, "name", &found); if(found) v_name = tagContent(tag); tag = findSubTag(q, "version", &found); if(found) v_ver = tagContent(tag); tag = findSubTag(q, "os", &found); if(found) v_os = tagContent(tag); setSuccess(); } else { setError(x); } return true; } const Jid & JT_ClientVersion::jid() const { return j; } const QString & JT_ClientVersion::name() const { return v_name; } const QString & JT_ClientVersion::version() const { return v_ver; } const QString & JT_ClientVersion::os() const { return v_os; } //---------------------------------------------------------------------------- // JT_ClientTime //---------------------------------------------------------------------------- /*JT_ClientTime::JT_ClientTime(Task *parent, const Jid &_j) :Task(parent) { j = _j; iq = createIQ("get", j.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:time"); iq.appendChild(query); } void JT_ClientTime::go() { send(iq); } bool JT_ClientTime::take(const QDomElement &x) { if(x.attribute("id") != id()) return FALSE; if(x.attribute("type") == "result") { bool found; QDomElement q = queryTag(x); QDomElement tag; tag = findSubTag(q, "utc", &found); if(found) stamp2TS(tagContent(tag), &utc); tag = findSubTag(q, "tz", &found); if(found) timezone = tagContent(tag); tag = findSubTag(q, "display", &found); if(found) display = tagContent(tag); setSuccess(TRUE); } else { setError(getErrorString(x)); setSuccess(FALSE); } return TRUE; } */ //---------------------------------------------------------------------------- // JT_ServInfo //---------------------------------------------------------------------------- JT_ServInfo::JT_ServInfo(Task *parent) :Task(parent) { } JT_ServInfo::~JT_ServInfo() { } bool JT_ServInfo::take(const QDomElement &e) { if(e.tagName() != "iq" || e.attribute("type") != "get") return false; QString ns = queryNS(e); if(ns == "jabber:iq:version") { QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:version"); iq.appendChild(query); query.appendChild(textTag(doc(), "name", client()->clientName())); query.appendChild(textTag(doc(), "version", client()->clientVersion())); query.appendChild(textTag(doc(), "os", client()->OSName())); send(iq); return true; } //else if(ns == "jabber:iq:time") { // QDomElement iq = createIQ("result", e.attribute("from"), e.attribute("id")); // QDomElement query = doc()->createElement("query"); // query.setAttribute("xmlns", "jabber:iq:time"); // iq.appendChild(query); // QDateTime local = QDateTime::currentDateTime(); // QDateTime utc = local.addSecs(-getTZOffset() * 3600); // QString str = getTZString(); // query.appendChild(textTag("utc", TS2stamp(utc))); // query.appendChild(textTag("tz", str)); // query.appendChild(textTag("display", QString("%1 %2").arg(local.toString()).arg(str))); // send(iq); // return TRUE; //} else if(ns == "http://jabber.org/protocol/disco#info") { // Find out the node bool invalid_node = false; QString node; bool found; QDomElement q = findSubTag(e, "query", &found); if(found) // NOTE: Should always be true, since a NS was found above node = q.attribute("node"); QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info"); if (!node.isEmpty()) query.setAttribute("node", node); iq.appendChild(query); // Identity DiscoItem::Identity identity = client()->identity(); QDomElement id = doc()->createElement("identity"); if (!identity.category.isEmpty() && !identity.type.isEmpty()) { id.setAttribute("category",identity.category); id.setAttribute("type",identity.type); if (!identity.name.isEmpty()) { id.setAttribute("name",identity.name); } } else { // Default values id.setAttribute("category","client"); id.setAttribute("type","pc"); } query.appendChild(id); QDomElement feature; if (node.isEmpty() || node == client()->capsNode() + "#" + client()->capsVersion()) { // Standard features #ifdef FILETRANSFER // FIXME: isn't it supposed to take info from caps? feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/bytestreams"); query.appendChild(feature); feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/si"); query.appendChild(feature); feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer"); query.appendChild(feature); #endif feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/disco#info"); query.appendChild(feature); // Client-specific features QStringList clientFeatures = client()->features().list(); for (QStringList::ConstIterator i = clientFeatures.begin(); i != clientFeatures.end(); ++i) { feature = doc()->createElement("feature"); feature.setAttribute("var", *i); query.appendChild(feature); } if (node.isEmpty()) { // Extended features QStringList exts = client()->extensions(); for (QStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) { const QStringList& l = client()->extension(*i).list(); for ( QStringList::ConstIterator j = l.begin(); j != l.end(); ++j ) { feature = doc()->createElement("feature"); feature.setAttribute("var", *j); query.appendChild(feature); } } } } else if (node.startsWith(client()->capsNode() + "#")) { QString ext = node.right(node.length()-client()->capsNode().length()-1); if (client()->extensions().contains(ext)) { const QStringList& l = client()->extension(ext).list(); for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) { feature = doc()->createElement("feature"); feature.setAttribute("var", *it); query.appendChild(feature); } } else { invalid_node = true; } } else { invalid_node = true; } if (!invalid_node) { send(iq); } else { // Create error reply QDomElement error_reply = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); // Copy children for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { error_reply.appendChild(n.cloneNode()); } // Add error QDomElement error = doc()->createElement("error"); error.setAttribute("type","cancel"); error_reply.appendChild(error); QDomElement error_type = doc()->createElement("item-not-found"); error_type.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-stanzas"); error.appendChild(error_type); send(error_reply); } return true; } return false; } //---------------------------------------------------------------------------- // JT_Gateway //---------------------------------------------------------------------------- JT_Gateway::JT_Gateway(Task *parent) :Task(parent) { type = -1; } void JT_Gateway::get(const Jid &jid) { type = 0; v_jid = jid; iq = createIQ(doc(), "get", v_jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:gateway"); iq.appendChild(query); } void JT_Gateway::set(const Jid &jid, const QString &prompt) { type = 1; v_jid = jid; v_prompt = prompt; iq = createIQ(doc(), "set", v_jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:gateway"); iq.appendChild(query); query.appendChild(textTag(doc(), "prompt", v_prompt)); } void JT_Gateway::onGo() { send(iq); } Jid JT_Gateway::jid() const { return v_jid; } QString JT_Gateway::desc() const { return v_desc; } QString JT_Gateway::prompt() const { return v_prompt; } bool JT_Gateway::take(const QDomElement &x) { if(!iqVerify(x, v_jid, id())) return false; if(x.attribute("type") == "result") { if(type == 0) { QDomElement query = queryTag(x); bool found; QDomElement tag; tag = findSubTag(query, "desc", &found); if(found) v_desc = tagContent(tag); tag = findSubTag(query, "prompt", &found); if(found) v_prompt = tagContent(tag); } else { QDomElement query = queryTag(x); bool found; QDomElement tag; tag = findSubTag(query, "prompt", &found); if(found) v_prompt = tagContent(tag); } setSuccess(); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_Browse //---------------------------------------------------------------------------- class JT_Browse::Private { public: QDomElement iq; Jid jid; AgentList agentList; AgentItem root; }; JT_Browse::JT_Browse (Task *parent) :Task (parent) { d = new Private; } JT_Browse::~JT_Browse () { delete d; } void JT_Browse::get (const Jid &j) { d->agentList.clear(); d->jid = j; d->iq = createIQ(doc(), "get", d->jid.full(), id()); QDomElement query = doc()->createElement("item"); query.setAttribute("xmlns", "jabber:iq:browse"); d->iq.appendChild(query); } const AgentList & JT_Browse::agents() const { return d->agentList; } const AgentItem & JT_Browse::root() const { return d->root; } void JT_Browse::onGo () { send(d->iq); } AgentItem JT_Browse::browseHelper (const QDomElement &i) { AgentItem a; if ( i.tagName() == "ns" ) return a; a.setName ( i.attribute("name") ); a.setJid ( i.attribute("jid") ); // there are two types of category/type specification: // // 1. // 2. if ( i.tagName() == "item" || i.tagName() == "query" ) a.setCategory ( i.attribute("category") ); else a.setCategory ( i.tagName() ); a.setType ( i.attribute("type") ); QStringList ns; for(QDomNode n = i.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; if ( i.tagName() == "ns" ) ns << i.text(); } // For now, conference.jabber.org returns proper namespace only // when browsing individual rooms. So it's a quick client-side fix. if ( !a.features().canGroupchat() && a.category() == "conference" ) ns << "jabber:iq:conference"; a.setFeatures (ns); return a; } bool JT_Browse::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement i = n.toElement(); if(i.isNull()) continue; d->root = browseHelper (i); for(QDomNode nn = i.firstChild(); !nn.isNull(); nn = nn.nextSibling()) { QDomElement e = nn.toElement(); if ( e.isNull() ) continue; if ( e.tagName() == "ns" ) continue; d->agentList += browseHelper (e); } } setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_DiscoItems //---------------------------------------------------------------------------- class JT_DiscoItems::Private { public: Private() { } QDomElement iq; Jid jid; DiscoList items; }; JT_DiscoItems::JT_DiscoItems(Task *parent) : Task(parent) { d = new Private; } JT_DiscoItems::~JT_DiscoItems() { delete d; } void JT_DiscoItems::get(const DiscoItem &item) { get(item.jid(), item.node()); } void JT_DiscoItems::get (const Jid &j, const QString &node) { d->items.clear(); d->jid = j; d->iq = createIQ(doc(), "get", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); if ( !node.isEmpty() ) query.setAttribute("node", node); d->iq.appendChild(query); } const Jid & JT_DiscoItems::jid() const { return d->jid; } const DiscoList &JT_DiscoItems::items() const { return d->items; } void JT_DiscoItems::onGo () { send(d->iq); } bool JT_DiscoItems::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { QDomElement q = queryTag(x); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if( e.isNull() ) continue; if ( e.tagName() == "item" ) { DiscoItem item; item.setJid ( e.attribute("jid") ); item.setName( e.attribute("name") ); item.setNode( e.attribute("node") ); item.setAction( DiscoItem::string2action(e.attribute("action")) ); d->items.append( item ); } } setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_DiscoPublish //---------------------------------------------------------------------------- class JT_DiscoPublish::Private { public: Private() { } QDomElement iq; Jid jid; DiscoList list; }; JT_DiscoPublish::JT_DiscoPublish(Task *parent) : Task(parent) { d = new Private; } JT_DiscoPublish::~JT_DiscoPublish() { delete d; } void JT_DiscoPublish::set(const Jid &j, const DiscoList &list) { d->list = list; d->jid = j; d->iq = createIQ(doc(), "set", d->jid.full(), id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items"); // FIXME: unsure about this //if ( !node.isEmpty() ) // query.setAttribute("node", node); DiscoList::ConstIterator it = list.begin(); for ( ; it != list.end(); ++it) { QDomElement w = doc()->createElement("item"); w.setAttribute("jid", (*it).jid().full()); if ( !(*it).name().isEmpty() ) w.setAttribute("name", (*it).name()); if ( !(*it).node().isEmpty() ) w.setAttribute("node", (*it).node()); w.setAttribute("action", DiscoItem::action2string((*it).action())); query.appendChild( w ); } d->iq.appendChild(query); } void JT_DiscoPublish::onGo () { send(d->iq); } bool JT_DiscoPublish::take(const QDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { setSuccess(true); } else { setError(x); } return true; } #ifdef YAPSI //---------------------------------------------------------------------------- // JT_YaLogMessage //---------------------------------------------------------------------------- JT_YaLogMessage::JT_YaLogMessage(Task *parent) :Task(parent) { } JT_YaLogMessage::~JT_YaLogMessage() { } void JT_YaLogMessage::log(bool originLocal, const YaDateTime& timeStamp, const XMPP::Jid& accountJid, const Message &message) { originLocal_ = originLocal; timeStamp_ = timeStamp; selfJid_ = accountJid; m_ = message; if (m_.id().isEmpty()) { m_.setId(id()); } } void JT_YaLogMessage::onGo() { if (originLocal_ && m_.from().isNull()) { m_.setFrom(selfJid_); } Stanza s = m_.toStanza(&(client()->stream())); QDomElement e = oldStyleNS(s.element()); QDomElement iq = createIQ(doc(), "set", "history.ya.ru", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "yandex:history:foreign"); query.setAttribute("action", originLocal_ ? "send" : "recv"); query.setAttribute("twin", selfJid_.bare()); query.setAttribute("timestamp", timeStamp_.toYaTime_t()); query.appendChild(e); iq.appendChild(query); send(iq); } bool JT_YaLogMessage::take(const QDomElement &x) { if (!iqVerify(x, "history.ya.ru", id()) && !iqVerify(x, "ya.ru", id())) return false; if (x.attribute("type") == "result") { setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_YaRemoveHistory //---------------------------------------------------------------------------- JT_YaRemoveHistory::JT_YaRemoveHistory(Task *parent) : Task(parent) { } JT_YaRemoveHistory::~JT_YaRemoveHistory() { } void JT_YaRemoveHistory::remove(const XMPP::Jid& owner) { selfJid_ = owner; } void JT_YaRemoveHistory::remove(const XMPP::Jid& owner, const XMPP::Jid& twin) { selfJid_ = owner; twin_ = twin; } void JT_YaRemoveHistory::remove(const XMPP::Jid& owner, const XMPP::Jid& twin, const XMPP::Jid& contact) { selfJid_ = owner; twin_ = twin; contact_ = contact; } void JT_YaRemoveHistory::onGo() { Q_ASSERT(!selfJid_.isNull() && selfJid_.isValid()); QDomElement iq = createIQ(doc(), "set", "history.ya.ru", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "yandex:history:delete"); query.setAttribute("owner", selfJid_.bare()); if (!twin_.isNull() && !twin_.compare(selfJid_)) query.setAttribute("twin", twin_.bare()); if (!contact_.isNull()) query.setAttribute("opp", contact_.bare()); iq.appendChild(query); send(iq); } bool JT_YaRemoveHistory::take(const QDomElement &x) { if (!iqVerify(x, "history.ya.ru", id())) return false; if (x.attribute("type") == "result") { setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_YaRemoveHistory //---------------------------------------------------------------------------- JT_YaRetrieveHistory::JT_YaRetrieveHistory(Task *parent) : Task(parent) , messageCount_(-1) , checkUnread_(false) { } JT_YaRetrieveHistory::~JT_YaRetrieveHistory() { } void JT_YaRetrieveHistory::retrieve(const XMPP::Jid& contact, int messageCount, YaDateTime startTime) { contact_ = contact; messageCount_ = messageCount; startTime_ = startTime; } void JT_YaRetrieveHistory::checkUnread(YaDateTime startTime) { checkUnread_ = true; startTime_ = startTime; } void JT_YaRetrieveHistory::onGo() { if (!checkUnread_) { Q_ASSERT(!contact_.isNull() && contact_.isValid()); } int paginatorMax = messageCount_; QDomElement iq = createIQ(doc(), "get", "history.ya.ru", id()); QDomElement query = doc()->createElement("retrieve"); query.setAttribute("xmlns", "yandex:history:retrieve"); if (!startTime_.isNull()) { query.setAttribute("start", startTime_.toYaIsoTime()); } if (!checkUnread_) { query.setAttribute("with", contact_.bare()); // query.setAttribute("order_by", "asc"); } else { query.setAttribute("unread", "1"); paginatorMax = 100; } QDomElement set = doc()->createElement("set"); set.setAttribute("xmlns", "yandex:history:paginator"); set.appendChild(textTag(doc(), "max", QString::number(paginatorMax))); query.appendChild(set); iq.appendChild(query); send(iq); } bool JT_YaRetrieveHistory::take(const QDomElement &x) { if (!iqVerify(x, "history.ya.ru", id())) return false; if (x.attribute("type") == "result") { bool found; QDomElement q = findSubTag(x, "chat", &found); Q_ASSERT(q.attribute("xmlns") == "yandex:history:retrieve"); for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if( e.isNull() ) continue; if ( e.tagName() == "to" || e.tagName() == "from" ) { JT_YaRetrieveHistory::Chat chat; chat.timeStamp = YaDateTime::fromYaIsoTime(e.attribute("time")); chat.body = XMLHelper::subTagText(e, "body"); chat.originLocal = e.tagName() == "to"; chat.jid = e.attribute("user"); if (chat.timeStamp.isNull()) { qWarning("JT_YaRetrieveHistory::take(%s) '%s' '%s'", qPrintable(q.attribute("with")), qPrintable(e.attribute("time")), qPrintable(chat.timeStamp.toString())); } messages_ << chat; } } setSuccess(true); } else { setError(x); } return true; } const XMPP::Jid& JT_YaRetrieveHistory::contact() const { return contact_; } const QList& JT_YaRetrieveHistory::messages() const { return messages_; } //---------------------------------------------------------------------------- // JT_YaMessageRead //---------------------------------------------------------------------------- JT_YaMessageRead::JT_YaMessageRead(Task* parent) : Task(parent) { } JT_YaMessageRead::~JT_YaMessageRead() { } void JT_YaMessageRead::messageRead(const XMPP::Jid& contact, const YaDateTime& timeStamp) { contact_ = contact; timeStamp_ = timeStamp; } void JT_YaMessageRead::setTo(const XMPP::Jid& to) { to_ = to; } void JT_YaMessageRead::onGo() { QDomElement iq = createIQ(doc(), "set", to_.isNull() ? "history.ya.ru" : to_.full(), id()); QDomElement query = doc()->createElement("read"); query.setAttribute("xmlns", "yandex:history:read"); query.setAttribute("with", contact_.full()); query.setAttribute("timestamp", timeStamp_.toYaTime_t()); iq.appendChild(query); send(iq); // we won't be getting a reply, so self-destruct is the only option setSuccess(true); } bool JT_YaMessageRead::take(const QDomElement& x) { if (!iqVerify(x, "history.ya.ru", id())) return false; if (x.attribute("type") == "result") { setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_YaMoodSwitch //---------------------------------------------------------------------------- JT_YaMoodSwitch::JT_YaMoodSwitch(Task* parent) : Task(parent) , isGet_(false) , enabled_(false) { } JT_YaMoodSwitch::~JT_YaMoodSwitch() { } void JT_YaMoodSwitch::get() { isGet_ = true; enabled_ = false; } void JT_YaMoodSwitch::set(bool enabled) { isGet_ = false; enabled_ = enabled; } bool JT_YaMoodSwitch::enabled() const { Q_ASSERT(isGet_); return enabled_; } void JT_YaMoodSwitch::onGo() { QDomElement iq = createIQ(doc(), isGet_ ? "get" : "set", "", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "yandex:mood-switch"); if (!isGet_) { QDomElement moodSettings = doc()->createElement("mood-settings"); moodSettings.setAttribute("enabled", enabled_ ? "1" : "0"); query.appendChild(moodSettings); } iq.appendChild(query); send(iq); } bool JT_YaMoodSwitch::take(const QDomElement& x) { if (!iqVerify(x, client()->host(), id())) return false; if (x.attribute("type") == "result") { if (isGet_) { bool found; QDomElement q = findSubTag(x, "query", &found); Q_ASSERT(found); Q_ASSERT(q.attribute("xmlns") == "yandex:mood-switch"); QDomElement tag = findSubTag(q, "mood-settings", &found); Q_ASSERT(found); if (found) { enabled_ = tag.attribute("enabled") == "1"; } } setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_YaMaxLast //---------------------------------------------------------------------------- JT_YaMaxLast::JT_YaMaxLast(Task* parent) : Task(parent) , isGet_(false) , maxLast_(-1) { } JT_YaMaxLast::~JT_YaMaxLast() { } void JT_YaMaxLast::get() { isGet_ = true; maxLast_ = -1; } void JT_YaMaxLast::set(int maxLast) { isGet_ = false; maxLast_ = maxLast; } int JT_YaMaxLast::maxLast() const { Q_ASSERT(isGet_); return maxLast_; } void JT_YaMaxLast::onGo() { QDomElement iq = createIQ(doc(), isGet_ ? "get" : "set", "", id()); QDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "yandex:max-last"); if (!isGet_) { if (maxLast_ > -1) { query.appendChild(textTag(doc(), "max-last", QString::number(maxLast_))); } else { query.appendChild(doc()->createElement("max-last")); } } iq.appendChild(query); send(iq); } bool JT_YaMaxLast::take(const QDomElement& x) { if (!iqVerify(x, client()->host(), id())) return false; if (x.attribute("type") == "result") { if (isGet_) { bool found; QDomElement q = findSubTag(x, "query", &found); Q_ASSERT(found); Q_ASSERT(q.attribute("xmlns") == "yandex:max-last"); QString maxLast = XMLHelper::subTagText(q, "max-last"); if (maxLast.isEmpty()) { maxLast_ = -1; } else { maxLast_ = maxLast.toInt(); } } setSuccess(true); } else { setError(x); } return true; } #endif