/* * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "xmpp_tasks.h" #include "base64.h" //#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 TQString lineEncode(TQString str) { str.replace(TQRegExp("\\\\"), "\\\\"); // backslash to double-backslash str.replace(TQRegExp("\\|"), "\\p"); // pipe to \p str.replace(TQRegExp("\n"), "\\n"); // newline to \n return str; } static TQString lineDecode(const TQString &str) { TQString ret; for(unsigned 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 TQDomElement &q, bool push) { Roster r; for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement 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_Register //---------------------------------------------------------------------------- class JT_Register::Private { public: Private() {} Form form; Jid jid; int type; }; JT_Register::JT_Register(Task *parent) :Task(parent) { d = new Private; d->type = -1; } JT_Register::~JT_Register() { delete d; } void JT_Register::reg(const TQString &user, const TQString &pass) { d->type = 0; to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); TQDomElement 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 TQString &pass) { d->type = 1; to = client()->host(); iq = createIQ(doc(), "set", to.full(), id()); TQDomElement 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()); TQDomElement 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()); TQDomElement 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()); TQDomElement 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())); } } const Form & JT_Register::form() const { return d->form; } void JT_Register::onGo() { send(iq); } bool JT_Register::take(const TQDomElement &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); TQDomElement q = queryTag(x); for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement 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; } } } } 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, TQT_SIGNAL(finished()), TQT_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, TQT_SIGNAL(finished()), TQT_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; TQValueList 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()); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:roster"); iq.appendChild(query); } void JT_Roster::set(const Jid &jid, const TQString &name, const TQStringList &groups) { type = 1; //to = client()->host(); TQDomElement item = doc()->createElement("item"); item.setAttribute("jid", jid.full()); if(!name.isEmpty()) item.setAttribute("name", name); for(TQStringList::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(); TQDomElement 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()); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:roster"); iq.appendChild(query); for(TQValueList::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it) query.appendChild(*it); send(iq); } } const Roster & JT_Roster::roster() const { return d->roster; } TQString JT_Roster::toString() const { if(type != 1) return ""; TQDomElement i = doc()->createElement("request"); i.setAttribute("type", "JT_Roster"); for(TQValueList::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it) i.appendChild(*it); return lineEncode(Stream::xmlToString(i)); return ""; } bool JT_Roster::fromString(const TQString &str) { TQDomDocument *dd = new TQDomDocument; if(!dd->setContent(lineDecode(str).utf8())) return false; TQDomElement 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(TQDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement i = n.toElement(); if(i.isNull()) continue; d->itemList += i; } return true; } bool JT_Roster::take(const TQDomElement &x) { if(!iqVerify(x, client()->host(), id())) return false; // get if(type == 0) { if(x.attribute("type") == "result") { TQDomElement 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 TQDomElement &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)); 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", TQString("%1").arg(s.priority()) ) ); if(!s.keyID().isEmpty()) { TQDomElement x = textTag(doc(), "x", s.keyID()); x.setAttribute("xmlns", "http://jabber.org/protocol/e2e"); tag.appendChild(x); } if(!s.xsigned().isEmpty()) { TQDomElement x = textTag(doc(), "x", s.xsigned()); x.setAttribute("xmlns", "jabber:x:signed"); tag.appendChild(x); } if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) { TQDomElement 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); } } } 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 TQString &subType) { type = 1; tag = doc()->createElement("presence"); tag.setAttribute("to", to.full()); tag.setAttribute("type", subType); } 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 TQDomElement &e) { if(e.tagName() != "presence") return false; Jid j(e.attribute("from")); Status p; if(e.hasAttribute("type")) { TQString type = e.attribute("type"); if(type == "unavailable") { p.setIsAvailable(false); } else if(type == "error") { TQString str = ""; int code = 0; getErrorFromElement(e, &code, &str); p.setError(code, str); } else { subscription(j, type); return true; } } TQDomElement 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(TQDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:delay") { if(i.hasAttribute("stamp")) { TQDateTime 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") { TQDomElement t; bool found; TQString 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")); } } presence(j, p); return true; } //---------------------------------------------------------------------------- // JT_Message //---------------------------------------------------------------------------- static TQDomElement oldStyleNS(const TQDomElement &e) { // find closest parent with a namespace TQDomNode par = e.parentNode(); while(!par.isNull() && par.namespaceURI().isNull()) par = par.parentNode(); bool noShowNS = false; if(!par.isNull() && par.namespaceURI() == e.namespaceURI()) noShowNS = true; TQDomElement i; uint x; //if(noShowNS) i = e.ownerDocument().createElement(e.tagName()); //else // i = e.ownerDocument().createElementNS(e.namespaceURI(), e.tagName()); // copy attributes TQDomNamedNodeMap 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 TQDomNodeList nl = e.childNodes(); for(x = 0; x < nl.count(); ++x) { TQDomNode 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; m.setId(id()); } JT_Message::~JT_Message() { } void JT_Message::onGo() { Stanza s = m.toStanza(&(client()->stream())); TQDomElement e = oldStyleNS(s.element()); send(e); setSuccess(); } //---------------------------------------------------------------------------- // JT_PushMessage //---------------------------------------------------------------------------- static TQDomElement addCorrectNS(const TQDomElement &e) { uint x; // grab child nodes /*TQDomDocumentFragment frag = e.ownerDocument().createDocumentFragment(); TQDomNodeList nl = e.childNodes(); for(x = 0; x < nl.count(); ++x) frag.appendChild(nl.item(x).cloneNode());*/ // find closest xmlns TQDomNode n = e; while(!n.isNull() && !n.toElement().hasAttribute("xmlns")) n = n.parentNode(); TQString ns; if(n.isNull() || !n.toElement().hasAttribute("xmlns")) ns = "jabber:client"; else ns = n.toElement().attribute("xmlns"); // make a new node TQDomElement i = e.ownerDocument().createElementNS(ns, e.tagName()); // copy attributes TQDomNamedNodeMap al = e.attributes(); for(x = 0; x < al.count(); ++x) { TQDomAttr a = al.item(x).toAttr(); if(a.name() != "xmlns") i.setAttributeNodeNS(al.item(x).cloneNode().toAttr()); } // copy children TQDomNodeList nl = e.childNodes(); for(x = 0; x < nl.count(); ++x) { TQDomNode n = nl.item(x); if(n.isElement()) i.appendChild(addCorrectNS(n.toElement())); else i.appendChild(n.cloneNode()); } //i.appendChild(frag); return i; } JT_PushMessage::JT_PushMessage(Task *parent) :Task(parent) { } JT_PushMessage::~JT_PushMessage() { } bool JT_PushMessage::take(const TQDomElement &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_GetLastActivity //---------------------------------------------------------------------------- class JT_GetLastActivity::Private { public: Private() {} int seconds; TQString message; }; JT_GetLastActivity::JT_GetLastActivity(Task *parent) :Task(parent) { d = new Private; } JT_GetLastActivity::~JT_GetLastActivity() { delete d; } void JT_GetLastActivity::get(const Jid &j) { jid = j; iq = createIQ(doc(), "get", jid.full(), id()); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:last"); iq.appendChild(query); } int JT_GetLastActivity::seconds() const { return d->seconds; } const TQString &JT_GetLastActivity::message() const { return d->message; } void JT_GetLastActivity::onGo() { send(iq); } bool JT_GetLastActivity::take(const TQDomElement &x) { if(!iqVerify(x, jid, id())) return false; if(x.attribute("type") == "result") { TQDomElement q = queryTag(x); d->message = q.text(); bool ok; d->seconds = q.attribute("seconds").toInt(&ok); setSuccess(ok); } else { setError(x); } 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()); TQDomElement 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 TQDomElement &x) { if(!iqVerify(x, jid, id())) return false; if(x.attribute("type") == "result") { TQDomElement q = queryTag(x); // agents for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "agent") { AgentItem a; a.setJid(Jid(i.attribute("jid"))); TQDomElement tag; bool found; tag = findSubTag(i, "name", &found); if(found) a.setName(tagContent(tag)); // determine which namespaces does item support TQStringList 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() {} TQDomElement 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", d->jid.full(), id()); TQDomElement 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 VCard &card) { type = 1; d->vcard = card; d->jid = ""; 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 TQDomElement &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(TQDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement 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; TQValueList 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()); TQDomElement 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()); TQDomElement 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 TQValueList & JT_Search::results() const { return d->resultList; } void JT_Search::onGo() { send(iq); } bool JT_Search::take(const TQDomElement &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); TQDomElement q = queryTag(x); for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement 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(); TQDomElement q = queryTag(x); for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement i = n.toElement(); if(i.isNull()) continue; if(i.tagName() == "item") { SearchResult r(Jid(i.attribute("jid"))); TQDomElement 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()); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:version"); iq.appendChild(query); } void JT_ClientVersion::onGo() { send(iq); } bool JT_ClientVersion::take(const TQDomElement &x) { if(!iqVerify(x, j, id())) return false; if(x.attribute("type") == "result") { bool found; TQDomElement q = queryTag(x); TQDomElement 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 TQString & JT_ClientVersion::name() const { return v_name; } const TQString & JT_ClientVersion::version() const { return v_ver; } const TQString & 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()); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:time"); iq.appendChild(query); } void JT_ClientTime::go() { send(iq); } bool JT_ClientTime::take(const TQDomElement &x) { if(x.attribute("id") != id()) return FALSE; if(x.attribute("type") == "result") { bool found; TQDomElement q = queryTag(x); TQDomElement 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 TQDomElement &e) { if(e.tagName() != "iq" || e.attribute("type") != "get") return false; TQString ns = queryNS(e); if(ns == "jabber:iq:version") { TQDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); TQDomElement 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") { // TQDomElement iq = createIQ("result", e.attribute("from"), e.attribute("id")); // TQDomElement query = doc()->createElement("query"); // query.setAttribute("xmlns", "jabber:iq:time"); // iq.appendChild(query); // TQDateTime local = TQDateTime::currentDateTime(); // TQDateTime utc = local.addSecs(-getTZOffset() * 3600); // TQString str = getTZString(); // query.appendChild(textTag("utc", TS2stamp(utc))); // query.appendChild(textTag("tz", str)); // query.appendChild(textTag("display", TQString("%1 %2").arg(local.toString()).arg(str))); // send(iq); // return TRUE; //} else if(ns == "http://jabber.org/protocol/disco#info") { // Find out the node TQString node; bool found; TQDomElement q = findSubTag(e, "query", &found); if(found) // NOTE: Should always be true, since a NS was found above node = q.attribute("node"); TQDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); TQDomElement 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(); TQDomElement 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); TQDomElement feature; if (node.isEmpty() || node == client()->capsNode() + "#" + client()->capsVersion()) { // Standard features 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); feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/xhtml-im"); query.appendChild(feature); feature = doc()->createElement("feature"); feature.setAttribute("var", "http://jabber.org/protocol/disco#info"); query.appendChild(feature); if (node.isEmpty()) { // Extended features TQStringList exts = client()->extensions(); for (TQStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) { const TQStringList& l = client()->extension(*i).list(); for ( TQStringList::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() + "#")) { TQString ext = node.right(node.length()-client()->capsNode().length()-1); if (client()->extensions().contains(ext)) { const TQStringList& l = client()->extension(ext).list(); for ( TQStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) { feature = doc()->createElement("feature"); feature.setAttribute("var", *it); query.appendChild(feature); } } else { // TODO: ERROR } } else { // TODO: ERROR } send(iq); 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()); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:gateway"); iq.appendChild(query); } void JT_Gateway::set(const Jid &jid, const TQString &prompt) { type = 1; v_jid = jid; v_prompt = prompt; iq = createIQ(doc(), "set", v_jid.full(), id()); TQDomElement 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; } TQString JT_Gateway::desc() const { return v_desc; } TQString JT_Gateway::prompt() const { return v_prompt; } bool JT_Gateway::take(const TQDomElement &x) { if(!iqVerify(x, v_jid, id())) return false; if(x.attribute("type") == "result") { if(type == 0) { TQDomElement query = queryTag(x); bool found; TQDomElement tag; tag = findSubTag(query, "desc", &found); if(found) v_desc = tagContent(tag); tag = findSubTag(query, "prompt", &found); if(found) v_prompt = tagContent(tag); } else { TQDomElement query = queryTag(x); bool found; TQDomElement 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: TQDomElement 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()); TQDomElement 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 TQDomElement &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") ); TQStringList ns; for(TQDomNode n = i.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement 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 TQDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { for(TQDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement i = n.toElement(); if(i.isNull()) continue; d->root = browseHelper (i); for(TQDomNode nn = i.firstChild(); !nn.isNull(); nn = nn.nextSibling()) { TQDomElement 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() { } TQDomElement 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 TQString &node) { d->items.clear(); d->jid = j; d->iq = createIQ(doc(), "get", d->jid.full(), id()); TQDomElement 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 DiscoList &JT_DiscoItems::items() const { return d->items; } void JT_DiscoItems::onGo () { send(d->iq); } bool JT_DiscoItems::take(const TQDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { TQDomElement q = queryTag(x); for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement 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_DiscoInfo //---------------------------------------------------------------------------- class JT_DiscoInfo::Private { public: Private() { } TQDomElement iq; Jid jid; TQString node; DiscoItem item; }; JT_DiscoInfo::JT_DiscoInfo(Task *parent) : Task(parent) { d = new Private; } JT_DiscoInfo::~JT_DiscoInfo() { delete d; } void JT_DiscoInfo::get(const DiscoItem &item) { DiscoItem::Identity id; if ( item.identities().count() == 1 ) id = item.identities().first(); get(item.jid(), item.node(), id); } void JT_DiscoInfo::get (const Jid &j, const TQString &node, DiscoItem::Identity ident) { d->item = DiscoItem(); // clear item d->jid = j; d->node = node; d->iq = createIQ(doc(), "get", d->jid.full(), id()); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info"); if ( !node.isEmpty() ) query.setAttribute("node", node); if ( !ident.category.isEmpty() && !ident.type.isEmpty() ) { TQDomElement i = doc()->createElement("item"); i.setAttribute("category", ident.category); i.setAttribute("type", ident.type); if ( !ident.name.isEmpty() ) i.setAttribute("name", ident.name); query.appendChild( i ); } d->iq.appendChild(query); } /** * Original requested jid. * Is here because sometimes the responder does not include this information * in the reply. */ const Jid& JT_DiscoInfo::jid() const { return d->jid; } /** * Original requested node. * Is here because sometimes the responder does not include this information * in the reply. */ const TQString& JT_DiscoInfo::node() const { return d->node; } const DiscoItem &JT_DiscoInfo::item() const { return d->item; } void JT_DiscoInfo::onGo () { send(d->iq); } bool JT_DiscoInfo::take(const TQDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { TQDomElement q = queryTag(x); DiscoItem item; item.setJid( d->jid ); item.setNode( q.attribute("node") ); TQStringList features; DiscoItem::Identities identities; for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement e = n.toElement(); if( e.isNull() ) continue; if ( e.tagName() == "feature" ) { features << e.attribute("var"); } else if ( e.tagName() == "identity" ) { DiscoItem::Identity id; id.category = e.attribute("category"); id.name = e.attribute("name"); id.type = e.attribute("type"); identities.append( id ); } } item.setFeatures( features ); item.setIdentities( identities ); d->item = item; setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_DiscoPublish //---------------------------------------------------------------------------- class JT_DiscoPublish::Private { public: Private() { } TQDomElement 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()); TQDomElement 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) { TQDomElement 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 TQDomElement &x) { if(!iqVerify(x, d->jid, id())) return false; if(x.attribute("type") == "result") { setSuccess(true); } else { setError(x); } return true; } //---------------------------------------------------------------------------- // JT_MucPresence //---------------------------------------------------------------------------- JT_MucPresence::JT_MucPresence(Task *parent) :Task(parent) { type = -1; } JT_MucPresence::~JT_MucPresence() { } void JT_MucPresence::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", TQString("%1").arg(s.priority()) ) ); if(!s.keyID().isEmpty()) { TQDomElement x = textTag(doc(), "x", s.keyID()); x.setAttribute("xmlns", "http://jabber.org/protocol/e2e"); tag.appendChild(x); } if(!s.xsigned().isEmpty()) { TQDomElement x = textTag(doc(), "x", s.xsigned()); x.setAttribute("xmlns", "jabber:x:signed"); tag.appendChild(x); } if(!s.capsNode().isEmpty() && !s.capsVersion().isEmpty()) { TQDomElement 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); } } } void JT_MucPresence::pres(const Jid &to, const Status &s, const TQString &password) { pres(s); tag.setAttribute("to", to.full()); TQDomElement x = textTag(doc(), "x", s.xsigned()); x.setAttribute("xmlns", "http://jabber.org/protocol/muc"); x.appendChild( textTag(doc(), "password", password.latin1()) ); tag.appendChild(x); } void JT_MucPresence::onGo() { send(tag); setSuccess(); } //---------------------------------------------------------------------------- // JT_PrivateStorage //---------------------------------------------------------------------------- class JT_PrivateStorage::Private { public: Private() : type(-1) {} TQDomElement iq; TQDomElement elem; int type; }; JT_PrivateStorage::JT_PrivateStorage(Task *parent) :Task(parent) { d = new Private; } JT_PrivateStorage::~JT_PrivateStorage() { delete d; } void JT_PrivateStorage::get(const TQString& tag, const TQString& xmlns) { d->type = 0; d->iq = createIQ(doc(), "get" , TQString() , id() ); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:private"); d->iq.appendChild(query); TQDomElement s = doc()->createElement(tag); if(!xmlns.isEmpty()) s.setAttribute("xmlns", xmlns); query.appendChild(s); } void JT_PrivateStorage::set(const TQDomElement& element) { d->type = 1; d->elem=element; TQDomNode n=doc()->importNode(element,true); d->iq = createIQ(doc(), "set" , TQString() , id() ); TQDomElement query = doc()->createElement("query"); query.setAttribute("xmlns", "jabber:iq:private"); d->iq.appendChild(query); query.appendChild(n); } void JT_PrivateStorage::onGo() { send(d->iq); } bool JT_PrivateStorage::take(const TQDomElement &x) { TQString to = client()->host(); if(!iqVerify(x, to, id())) return false; if(x.attribute("type") == "result") { if(d->type == 0) { TQDomElement q = queryTag(x); for(TQDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) { TQDomElement i = n.toElement(); if(i.isNull()) continue; d->elem=i; break; } } setSuccess(); return true; } else { setError(x); } return true; } TQDomElement JT_PrivateStorage::element( ) { return d->elem; } //---------------------------------------------------------------------------- // PongServer //---------------------------------------------------------------------------- /** * \class PongServer * \brief Answers XMPP Pings */ PongServer::PongServer(Task *parent) :Task(parent) { } PongServer::~PongServer() { } bool PongServer::take(const TQDomElement &e) { if (e.tagName() != "iq" || e.attribute("type") != "get") return false; bool found = false; TQDomElement ping = findSubTag(e, "ping", &found); if (found && ping.attribute("xmlns") == "urn:xmpp:ping") { TQDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id")); send(iq); return true; } return false; }