1 /*
2  * tasks.cpp - basic tasks
3  * Copyright (C) 2001, 2002  Justin Karneges
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  */
20 
21 #include <QRegExp>
22 #include <QList>
23 #include <QTimer>
24 
25 #include "xmpp_tasks.h"
26 #include "xmpp_xmlcommon.h"
27 #include "xmpp_vcard.h"
28 #include "xmpp_bitsofbinary.h"
29 #include "xmpp_captcha.h"
30 #include "xmpp/base/timezone.h"
31 #include "xmpp_caps.h"
32 
33 using namespace XMPP;
34 
35 
lineEncode(QString str)36 static QString lineEncode(QString str)
37 {
38 	str.replace(QRegExp("\\\\"), "\\\\");   // backslash to double-backslash
39 	str.replace(QRegExp("\\|"), "\\p");     // pipe to \p
40 	str.replace(QRegExp("\n"), "\\n");      // newline to \n
41 	return str;
42 }
43 
lineDecode(const QString & str)44 static QString lineDecode(const QString &str)
45 {
46 	QString ret;
47 
48 	for(int n = 0; n < str.length(); ++n) {
49 		if(str.at(n) == '\\') {
50 			++n;
51 			if(n >= str.length())
52 				break;
53 
54 			if(str.at(n) == 'n')
55 				ret.append('\n');
56 			if(str.at(n) == 'p')
57 				ret.append('|');
58 			if(str.at(n) == '\\')
59 				ret.append('\\');
60 		}
61 		else {
62 			ret.append(str.at(n));
63 		}
64 	}
65 
66 	return ret;
67 }
68 
xmlReadRoster(const QDomElement & q,bool push)69 static Roster xmlReadRoster(const QDomElement &q, bool push)
70 {
71 	Roster r;
72 
73 	for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
74 		QDomElement i = n.toElement();
75 		if(i.isNull())
76 			continue;
77 
78 		if(i.tagName() == "item") {
79 			RosterItem item;
80 			item.fromXml(i);
81 
82 			if(push)
83 				item.setIsPush(true);
84 
85 			r += item;
86 		}
87 	}
88 
89 	return r;
90 }
91 
92 //----------------------------------------------------------------------------
93 // JT_Session
94 //----------------------------------------------------------------------------
95 //
96 #include "protocol.h"
97 
JT_Session(Task * parent)98 JT_Session::JT_Session(Task *parent) : Task(parent)
99 {
100 }
101 
onGo()102 void JT_Session::onGo()
103 {
104 	QDomElement iq = createIQ(doc(), "set", "", id());
105 	QDomElement session = doc()->createElement("session");
106 	session.setAttribute("xmlns",NS_SESSION);
107 	iq.appendChild(session);
108 	send(iq);
109 }
110 
take(const QDomElement & x)111 bool JT_Session::take(const QDomElement& x)
112 {
113 	QString from = x.attribute("from");
114 	if (!from.endsWith("chat.facebook.com")) {
115 		// remove this code when chat.facebook.com is disabled completely
116 		from.clear();
117 	}
118 	if(!iqVerify(x, from, id()))
119 		return false;
120 
121 	if(x.attribute("type") == "result") {
122 		setSuccess();
123 	}
124 	else {
125 		setError(x);
126 	}
127 	return true;
128 }
129 
130 //----------------------------------------------------------------------------
131 // JT_Register
132 //----------------------------------------------------------------------------
133 class JT_Register::Private
134 {
135 public:
Private()136 	Private() {}
137 
138 	Form form;
139 	XData xdata;
140 	bool hasXData;
141 	Jid jid;
142 	int type;
143 };
144 
JT_Register(Task * parent)145 JT_Register::JT_Register(Task *parent)
146 :Task(parent)
147 {
148 	d = new Private;
149 	d->type = -1;
150 	d->hasXData = false;
151 }
152 
~JT_Register()153 JT_Register::~JT_Register()
154 {
155 	delete d;
156 }
157 
reg(const QString & user,const QString & pass)158 void JT_Register::reg(const QString &user, const QString &pass)
159 {
160 	d->type = 0;
161 	to = client()->host();
162 	iq = createIQ(doc(), "set", to.full(), id());
163 	QDomElement query = doc()->createElement("query");
164 	query.setAttribute("xmlns", "jabber:iq:register");
165 	iq.appendChild(query);
166 	query.appendChild(textTag(doc(), "username", user));
167 	query.appendChild(textTag(doc(), "password", pass));
168 }
169 
changepw(const QString & pass)170 void JT_Register::changepw(const QString &pass)
171 {
172 	d->type = 1;
173 	to = client()->host();
174 	iq = createIQ(doc(), "set", to.full(), id());
175 	QDomElement query = doc()->createElement("query");
176 	query.setAttribute("xmlns", "jabber:iq:register");
177 	iq.appendChild(query);
178 	query.appendChild(textTag(doc(), "username", client()->user()));
179 	query.appendChild(textTag(doc(), "password", pass));
180 }
181 
unreg(const Jid & j)182 void JT_Register::unreg(const Jid &j)
183 {
184 	d->type = 2;
185 	to = j.isEmpty() ? client()->host() : j.full();
186 	iq = createIQ(doc(), "set", to.full(), id());
187 	QDomElement query = doc()->createElement("query");
188 	query.setAttribute("xmlns", "jabber:iq:register");
189 	iq.appendChild(query);
190 
191 	// this may be useful
192 	if(!d->form.key().isEmpty())
193 		query.appendChild(textTag(doc(), "key", d->form.key()));
194 
195 	query.appendChild(doc()->createElement("remove"));
196 }
197 
getForm(const Jid & j)198 void JT_Register::getForm(const Jid &j)
199 {
200 	d->type = 3;
201 	to = j;
202 	iq = createIQ(doc(), "get", to.full(), id());
203 	QDomElement query = doc()->createElement("query");
204 	query.setAttribute("xmlns", "jabber:iq:register");
205 	iq.appendChild(query);
206 }
207 
setForm(const Form & form)208 void JT_Register::setForm(const Form &form)
209 {
210 	d->type = 4;
211 	to = form.jid();
212 	iq = createIQ(doc(), "set", to.full(), id());
213 	QDomElement query = doc()->createElement("query");
214 	query.setAttribute("xmlns", "jabber:iq:register");
215 	iq.appendChild(query);
216 
217 	// key?
218 	if(!form.key().isEmpty())
219 		query.appendChild(textTag(doc(), "key", form.key()));
220 
221 	// fields
222 	for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) {
223 		const FormField &f = *it;
224 		query.appendChild(textTag(doc(), f.realName(), f.value()));
225 	}
226 }
227 
setForm(const Jid & to,const XData & xdata)228 void JT_Register::setForm(const Jid& to, const XData& xdata)
229 {
230 	d->type = 4;
231 	iq = createIQ(doc(), "set", to.full(), id());
232 	QDomElement query = doc()->createElement("query");
233 	query.setAttribute("xmlns", "jabber:iq:register");
234 	iq.appendChild(query);
235 	query.appendChild(xdata.toXml(doc(), true));
236 }
237 
form() const238 const Form & JT_Register::form() const
239 {
240 	return d->form;
241 }
242 
hasXData() const243 bool JT_Register::hasXData() const
244 {
245 	return d->hasXData;
246 }
247 
xdata() const248 const XData& JT_Register::xdata() const
249 {
250 	return d->xdata;
251 }
252 
onGo()253 void JT_Register::onGo()
254 {
255 	send(iq);
256 }
257 
take(const QDomElement & x)258 bool JT_Register::take(const QDomElement &x)
259 {
260 	if(!iqVerify(x, to, id()))
261 		return false;
262 
263 	Jid from(x.attribute("from"));
264 	if(x.attribute("type") == "result") {
265 		if(d->type == 3) {
266 			d->form.clear();
267 			d->form.setJid(from);
268 
269 			QDomElement q = queryTag(x);
270 			for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
271 				QDomElement i = n.toElement();
272 				if(i.isNull())
273 					continue;
274 
275 				if(i.tagName() == "instructions")
276 					d->form.setInstructions(tagContent(i));
277 				else if(i.tagName() == "key")
278 					d->form.setKey(tagContent(i));
279 				else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:data") {
280 					d->xdata.fromXml(i);
281 					d->hasXData = true;
282 				}
283 				else if(i.tagName() == "data" && i.attribute("xmlns") == "urn:xmpp:bob") {
284 					client()->bobManager()->append(BoBData(i)); // xep-0231
285 				}
286 				else {
287 					FormField f;
288 					if(f.setType(i.tagName())) {
289 						f.setValue(tagContent(i));
290 						d->form += f;
291 					}
292 				}
293 			}
294 		}
295 
296 		setSuccess();
297 	}
298 	else
299 		setError(x);
300 
301 	return true;
302 }
303 
304 //----------------------------------------------------------------------------
305 // JT_UnRegister
306 //----------------------------------------------------------------------------
307 class JT_UnRegister::Private
308 {
309 public:
Private()310 	Private() { }
311 
312 	Jid j;
313 	JT_Register *jt_reg;
314 };
315 
JT_UnRegister(Task * parent)316 JT_UnRegister::JT_UnRegister(Task *parent)
317 : Task(parent)
318 {
319 	d = new Private;
320 	d->jt_reg = 0;
321 }
322 
~JT_UnRegister()323 JT_UnRegister::~JT_UnRegister()
324 {
325 	delete d->jt_reg;
326 	delete d;
327 }
328 
unreg(const Jid & j)329 void JT_UnRegister::unreg(const Jid &j)
330 {
331 	d->j = j;
332 }
333 
onGo()334 void JT_UnRegister::onGo()
335 {
336 	delete d->jt_reg;
337 
338 	d->jt_reg = new JT_Register(this);
339 	d->jt_reg->getForm(d->j);
340 	connect(d->jt_reg, SIGNAL(finished()), SLOT(getFormFinished()));
341 	d->jt_reg->go(false);
342 }
343 
getFormFinished()344 void JT_UnRegister::getFormFinished()
345 {
346 	disconnect(d->jt_reg, 0, this, 0);
347 
348 	d->jt_reg->unreg(d->j);
349 	connect(d->jt_reg, SIGNAL(finished()), SLOT(unregFinished()));
350 	d->jt_reg->go(false);
351 }
352 
unregFinished()353 void JT_UnRegister::unregFinished()
354 {
355 	if ( d->jt_reg->success() )
356 		setSuccess();
357 	else
358 		setError(d->jt_reg->statusCode(), d->jt_reg->statusString());
359 
360 	delete d->jt_reg;
361 	d->jt_reg = 0;
362 }
363 
364 //----------------------------------------------------------------------------
365 // JT_Roster
366 //----------------------------------------------------------------------------
367 class JT_Roster::Private
368 {
369 public:
Private()370 	Private() {}
371 
372 	Roster roster;
373 	QList<QDomElement> itemList;
374 };
375 
JT_Roster(Task * parent)376 JT_Roster::JT_Roster(Task *parent)
377 :Task(parent)
378 {
379 	type = -1;
380 	d = new Private;
381 }
382 
~JT_Roster()383 JT_Roster::~JT_Roster()
384 {
385 	delete d;
386 }
387 
get()388 void JT_Roster::get()
389 {
390 	type = 0;
391 	//to = client()->host();
392 	iq = createIQ(doc(), "get", to.full(), id());
393 	QDomElement query = doc()->createElement("query");
394 	query.setAttribute("xmlns", "jabber:iq:roster");
395 	iq.appendChild(query);
396 }
397 
set(const Jid & jid,const QString & name,const QStringList & groups)398 void JT_Roster::set(const Jid &jid, const QString &name, const QStringList &groups)
399 {
400 	type = 1;
401 	//to = client()->host();
402 	QDomElement item = doc()->createElement("item");
403 	item.setAttribute("jid", jid.full());
404 	if(!name.isEmpty())
405 		item.setAttribute("name", name);
406 	for(QStringList::ConstIterator it = groups.begin(); it != groups.end(); ++it)
407 		item.appendChild(textTag(doc(), "group", *it));
408 	d->itemList += item;
409 }
410 
remove(const Jid & jid)411 void JT_Roster::remove(const Jid &jid)
412 {
413 	type = 1;
414 	//to = client()->host();
415 	QDomElement item = doc()->createElement("item");
416 	item.setAttribute("jid", jid.full());
417 	item.setAttribute("subscription", "remove");
418 	d->itemList += item;
419 }
420 
onGo()421 void JT_Roster::onGo()
422 {
423 	if(type == 0)
424 		send(iq);
425 	else if(type == 1) {
426 		//to = client()->host();
427 		iq = createIQ(doc(), "set", to.full(), id());
428 		QDomElement query = doc()->createElement("query");
429 		query.setAttribute("xmlns", "jabber:iq:roster");
430 		iq.appendChild(query);
431 		foreach (const QDomElement& it, d->itemList)
432 			query.appendChild(it);
433 		send(iq);
434 	}
435 }
436 
roster() const437 const Roster & JT_Roster::roster() const
438 {
439 	return d->roster;
440 }
441 
toString() const442 QString JT_Roster::toString() const
443 {
444 	if(type != 1)
445 		return "";
446 
447 	QDomElement i = doc()->createElement("request");
448 	i.setAttribute("type", "JT_Roster");
449 	foreach (const QDomElement& it, d->itemList)
450 		i.appendChild(it);
451 	return lineEncode(Stream::xmlToString(i));
452 	return "";
453 }
454 
fromString(const QString & str)455 bool JT_Roster::fromString(const QString &str)
456 {
457 	QDomDocument *dd = new QDomDocument;
458 	if(!dd->setContent(lineDecode(str).toUtf8()))
459 		return false;
460 	QDomElement e = doc()->importNode(dd->documentElement(), true).toElement();
461 	delete dd;
462 
463 	if(e.tagName() != "request" || e.attribute("type") != "JT_Roster")
464 		return false;
465 
466 	type = 1;
467 	d->itemList.clear();
468 	for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
469 		QDomElement i = n.toElement();
470 		if(i.isNull())
471 			continue;
472 		d->itemList += i;
473 	}
474 
475 	return true;
476 }
477 
take(const QDomElement & x)478 bool JT_Roster::take(const QDomElement &x)
479 {
480 	if(!iqVerify(x, client()->host(), id()))
481 		return false;
482 
483 	// get
484 	if(type == 0) {
485 		if(x.attribute("type") == "result") {
486 			QDomElement q = queryTag(x);
487 			d->roster = xmlReadRoster(q, false);
488 			setSuccess();
489 		}
490 		else {
491 			setError(x);
492 		}
493 
494 		return true;
495 	}
496 	// set
497 	else if(type == 1) {
498 		if(x.attribute("type") == "result")
499 			setSuccess();
500 		else
501 			setError(x);
502 
503 		return true;
504 	}
505 	// remove
506 	else if(type == 2) {
507 		setSuccess();
508 		return true;
509 	}
510 
511 	return false;
512 }
513 
514 
515 //----------------------------------------------------------------------------
516 // JT_PushRoster
517 //----------------------------------------------------------------------------
JT_PushRoster(Task * parent)518 JT_PushRoster::JT_PushRoster(Task *parent)
519 :Task(parent)
520 {
521 }
522 
~JT_PushRoster()523 JT_PushRoster::~JT_PushRoster()
524 {
525 }
526 
take(const QDomElement & e)527 bool JT_PushRoster::take(const QDomElement &e)
528 {
529 	// must be an iq-set tag
530 	if(e.tagName() != "iq" || e.attribute("type") != "set")
531 		return false;
532 
533 	if(!iqVerify(e, client()->host(), "", "jabber:iq:roster"))
534 		return false;
535 
536 	roster(xmlReadRoster(queryTag(e), true));
537 	send(createIQ(doc(), "result", e.attribute("from"), e.attribute("id")));
538 
539 	return true;
540 }
541 
542 
543 //----------------------------------------------------------------------------
544 // JT_Presence
545 //----------------------------------------------------------------------------
JT_Presence(Task * parent)546 JT_Presence::JT_Presence(Task *parent)
547 :Task(parent)
548 {
549 	type = -1;
550 }
551 
~JT_Presence()552 JT_Presence::~JT_Presence()
553 {
554 }
555 
pres(const Status & s)556 void JT_Presence::pres(const Status &s)
557 {
558 	type = 0;
559 
560 	tag = doc()->createElement("presence");
561 	if(!s.isAvailable()) {
562 		tag.setAttribute("type", "unavailable");
563 		if(!s.status().isEmpty())
564 			tag.appendChild(textTag(doc(), "status", s.status()));
565 	}
566 	else {
567 		if(s.isInvisible())
568 			tag.setAttribute("type", "invisible");
569 
570 		if(!s.show().isEmpty())
571 			tag.appendChild(textTag(doc(), "show", s.show()));
572 		if(!s.status().isEmpty())
573 			tag.appendChild(textTag(doc(), "status", s.status()));
574 
575 		tag.appendChild( textTag(doc(), "priority", QString("%1").arg(s.priority()) ) );
576 
577 		if(!s.keyID().isEmpty()) {
578 			QDomElement x = textTag(doc(), "x", s.keyID());
579 			x.setAttribute("xmlns", "http://jabber.org/protocol/e2e");
580 			tag.appendChild(x);
581 		}
582 		if(!s.xsigned().isEmpty()) {
583 			QDomElement x = textTag(doc(), "x", s.xsigned());
584 			x.setAttribute("xmlns", "jabber:x:signed");
585 			tag.appendChild(x);
586 		}
587 
588 		if (client()->capsManager()->isEnabled()) {
589 			CapsSpec cs = client()->caps();
590 			if (cs.isValid()) {
591 				tag.appendChild(cs.toXml(doc()));
592 			}
593 		}
594 
595 		if(s.isMUC()) {
596 			QDomElement m = doc()->createElement("x");
597 			m.setAttribute("xmlns","http://jabber.org/protocol/muc");
598 			if (!s.mucPassword().isEmpty()) {
599 				m.appendChild(textTag(doc(),"password",s.mucPassword()));
600 			}
601 			if (s.hasMUCHistory()) {
602 				QDomElement h = doc()->createElement("history");
603 				if (s.mucHistoryMaxChars() >= 0)
604 					h.setAttribute("maxchars",s.mucHistoryMaxChars());
605 				if (s.mucHistoryMaxStanzas() >= 0)
606 					h.setAttribute("maxstanzas",s.mucHistoryMaxStanzas());
607 				if (s.mucHistorySeconds() >= 0)
608 					h.setAttribute("seconds",s.mucHistorySeconds());
609 				if (!s.mucHistorySince().isNull())
610 					h.setAttribute("since", s.mucHistorySince().toUTC().addSecs(1).toString(Qt::ISODate));
611 				m.appendChild(h);
612 			}
613 			tag.appendChild(m);
614 		}
615 
616 		if(s.hasPhotoHash()) {
617 			QDomElement m = doc()->createElement("x");
618 			m.setAttribute("xmlns", "vcard-temp:x:update");
619 			m.appendChild(textTag(doc(), "photo", s.photoHash()));
620 			tag.appendChild(m);
621 		}
622 
623 		// bits of binary
624 		foreach(const BoBData &bd, s.bobDataList()) {
625 			tag.appendChild(bd.toXml(doc()));
626 		}
627 	}
628 }
629 
pres(const Jid & to,const Status & s)630 void JT_Presence::pres(const Jid &to, const Status &s)
631 {
632 	pres(s);
633 	tag.setAttribute("to", to.full());
634 }
635 
sub(const Jid & to,const QString & subType,const QString & nick)636 void JT_Presence::sub(const Jid &to, const QString &subType, const QString& nick)
637 {
638 	type = 1;
639 
640 	tag = doc()->createElement("presence");
641 	tag.setAttribute("to", to.full());
642 	tag.setAttribute("type", subType);
643 	if (!nick.isEmpty()) {
644 		QDomElement nick_tag = textTag(doc(),"nick",nick);
645 		nick_tag.setAttribute("xmlns","http://jabber.org/protocol/nick");
646 		tag.appendChild(nick_tag);
647 	}
648 }
649 
probe(const Jid & to)650 void JT_Presence::probe(const Jid &to)
651 {
652 	type = 2;
653 
654 	tag = doc()->createElement("presence");
655 	tag.setAttribute("to", to.full());
656 	tag.setAttribute("type", "probe");
657 }
658 
onGo()659 void JT_Presence::onGo()
660 {
661 	send(tag);
662 	setSuccess();
663 }
664 
665 
666 //----------------------------------------------------------------------------
667 // JT_PushPresence
668 //----------------------------------------------------------------------------
JT_PushPresence(Task * parent)669 JT_PushPresence::JT_PushPresence(Task *parent)
670 :Task(parent)
671 {
672 }
673 
~JT_PushPresence()674 JT_PushPresence::~JT_PushPresence()
675 {
676 }
677 
take(const QDomElement & e)678 bool JT_PushPresence::take(const QDomElement &e)
679 {
680 	if(e.tagName() != "presence")
681 		return false;
682 
683 	Jid j(e.attribute("from"));
684 	Status p;
685 
686 	if(e.hasAttribute("type")) {
687 		QString type = e.attribute("type");
688 		if(type == "unavailable") {
689 			p.setIsAvailable(false);
690 		}
691 		else if(type == "error") {
692 			QString str = "";
693 			int code = 0;
694 			getErrorFromElement(e, client()->stream().baseNS(), &code, &str);
695 			p.setError(code, str);
696 		}
697 		else if(type == "subscribe" || type == "subscribed" || type == "unsubscribe" || type == "unsubscribed") {
698 			QString nick;
699 			QDomElement tag = e.firstChildElement("nick");
700 			if (!tag.isNull() && tag.attribute("xmlns") == "http://jabber.org/protocol/nick") {
701 				nick = tagContent(tag);
702 			}
703 			subscription(j, type, nick);
704 			return true;
705 		}
706 	}
707 
708 	QDomElement tag;
709 
710 	tag = e.firstChildElement("status");
711 	if(!tag.isNull())
712 		p.setStatus(tagContent(tag));
713 	tag = e.firstChildElement("show");
714 	if(!tag.isNull())
715 		p.setShow(tagContent(tag));
716 	tag = e.firstChildElement("priority");
717 	if(!tag.isNull())
718 		p.setPriority(tagContent(tag).toInt());
719 
720 	QDateTime stamp;
721 
722 	for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
723 		QDomElement i = n.toElement();
724 		if(i.isNull())
725 			continue;
726 
727 		if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:delay") {
728 			if(i.hasAttribute("stamp") && !stamp.isValid()) {
729 				stamp = stamp2TS(i.attribute("stamp"));
730 			}
731 		}
732 		else if(i.tagName() == "delay" && i.attribute("xmlns") == "urn:xmpp:delay") {
733 			if(i.hasAttribute("stamp") && !stamp.isValid()) {
734 				stamp = QDateTime::fromString(i.attribute("stamp").left(19), Qt::ISODate);
735 			}
736 		}
737 		else if(i.tagName() == "x" && i.attribute("xmlns") == "gabber:x:music:info") {
738 			QDomElement t;
739 			QString title, state;
740 
741 			t = i.firstChildElement("title");
742 			if(!t.isNull())
743 				title = tagContent(t);
744 			t = i.firstChildElement("state");
745 			if(!t.isNull())
746 				state = tagContent(t);
747 
748 			if(!title.isEmpty() && state == "playing")
749 				p.setSongTitle(title);
750 		}
751 		else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:signed") {
752 			p.setXSigned(tagContent(i));
753 		}
754 		else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/e2e") {
755 			p.setKeyID(tagContent(i));
756 		}
757  		else if(i.tagName() == "c" && i.attribute("xmlns") == NS_CAPS) {
758 			p.setCaps(CapsSpec::fromXml(i));
759 			if(!e.hasAttribute("type") && p.caps().isValid()) {
760 				client()->capsManager()->updateCaps(j, p.caps());
761 			}
762   		}
763 		else if(i.tagName() == "x" && i.attribute("xmlns") == "vcard-temp:x:update") {
764 			QDomElement t;
765 			t = i.firstChildElement("photo");
766 			if (!t.isNull())
767 				p.setPhotoHash(tagContent(t));
768 			else
769 				p.setPhotoHash("");
770 		}
771 		else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/muc#user") {
772 			for(QDomNode muc_n = i.firstChild(); !muc_n.isNull(); muc_n = muc_n.nextSibling()) {
773 				QDomElement muc_e = muc_n.toElement();
774 				if(muc_e.isNull())
775 					continue;
776 
777 				if (muc_e.tagName() == "item")
778 					p.setMUCItem(MUCItem(muc_e));
779 				else if (muc_e.tagName() == "status")
780 					p.addMUCStatus(muc_e.attribute("code").toInt());
781 				else if (muc_e.tagName() == "destroy")
782 					p.setMUCDestroy(MUCDestroy(muc_e));
783 			}
784 		}
785 		else if (i.tagName() == "data" && i.attribute("xmlns") == "urn:xmpp:bob") {
786 			BoBData bd(i);
787 			client()->bobManager()->append(bd);
788 			p.addBoBData(bd);
789 		}
790 	}
791 
792 
793 	if (stamp.isValid()) {
794 		if (client()->manualTimeZoneOffset()) {
795 			stamp = stamp.addSecs(client()->timeZoneOffset() * 3600);
796 		} else {
797 			stamp.setTimeSpec(Qt::UTC);
798 			stamp = stamp.toLocalTime();
799 		}
800 		p.setTimeStamp(stamp);
801 	}
802 
803 	presence(j, p);
804 
805 	return true;
806 }
807 
808 
809 //----------------------------------------------------------------------------
810 // JT_Message
811 //----------------------------------------------------------------------------
oldStyleNS(const QDomElement & e)812 static QDomElement oldStyleNS(const QDomElement &e)
813 {
814 	// find closest parent with a namespace
815 	QDomNode par = e.parentNode();
816 	while(!par.isNull() && par.namespaceURI().isNull())
817 		par = par.parentNode();
818 	bool noShowNS = false;
819 	if(!par.isNull() && par.namespaceURI() == e.namespaceURI())
820 		noShowNS = true;
821 
822 	QDomElement i;
823 	int x;
824 	//if(noShowNS)
825 		i = e.ownerDocument().createElement(e.tagName());
826 	//else
827 	//	i = e.ownerDocument().createElementNS(e.namespaceURI(), e.tagName());
828 
829 	// copy attributes
830 	QDomNamedNodeMap al = e.attributes();
831 	for(x = 0; x < al.count(); ++x)
832 		i.setAttributeNode(al.item(x).cloneNode().toAttr());
833 
834 	if(!noShowNS)
835 		i.setAttribute("xmlns", e.namespaceURI());
836 
837 	// copy children
838 	QDomNodeList nl = e.childNodes();
839 	for(x = 0; x < nl.count(); ++x) {
840 		QDomNode n = nl.item(x);
841 		if(n.isElement())
842 			i.appendChild(oldStyleNS(n.toElement()));
843 		else
844 			i.appendChild(n.cloneNode());
845 	}
846 	return i;
847 }
848 
JT_Message(Task * parent,const Message & msg)849 JT_Message::JT_Message(Task *parent, const Message &msg)
850 :Task(parent)
851 {
852 	m = msg;
853 	if (m.id().isEmpty())
854 		m.setId(id());
855 }
856 
~JT_Message()857 JT_Message::~JT_Message()
858 {
859 }
860 
onGo()861 void JT_Message::onGo()
862 {
863 	Stanza s = m.toStanza(&(client()->stream()));
864 	QDomElement e = oldStyleNS(s.element());
865 	send(e);
866 	setSuccess();
867 }
868 
869 
870 //----------------------------------------------------------------------------
871 // JT_PushMessage
872 //----------------------------------------------------------------------------
JT_PushMessage(Task * parent)873 JT_PushMessage::JT_PushMessage(Task *parent)
874 :Task(parent)
875 {
876 }
877 
~JT_PushMessage()878 JT_PushMessage::~JT_PushMessage()
879 {
880 }
881 
take(const QDomElement & e)882 bool JT_PushMessage::take(const QDomElement &e)
883 {
884 	if(e.tagName() != "message")
885 		return false;
886 
887 	QDomElement e1 = e;
888 	QDomElement forward;
889 	Message::CarbonDir cd = Message::NoCarbon;
890 
891 	Jid fromJid = Jid(e1.attribute(QLatin1String("from")));
892 	// Check for Carbon
893 	QDomNodeList list = e1.childNodes();
894 	for (int i = 0; i < list.size(); ++i) {
895 		QDomElement el = list.at(i).toElement();
896 
897 		if (el.attribute("xmlns") == QLatin1String("urn:xmpp:carbons:2")
898 		    && (el.tagName() == QLatin1String("received") || el.tagName() == QLatin1String("sent"))
899 		    && fromJid.compare(Jid(e1.attribute(QLatin1String("to"))), false)) {
900 			QDomElement el1 = el.firstChildElement();
901 			if (el1.tagName() == QLatin1String("forwarded")
902 			    && el1.attribute(QLatin1String("xmlns")) == QLatin1String("urn:xmpp:forward:0")) {
903 				QDomElement el2 = el1.firstChildElement(QLatin1String("message"));
904 				if (!el2.isNull()) {
905 					forward = el2;
906 					cd = el.tagName() == QLatin1String("received")? Message::Received : Message::Sent;
907 					break;
908 				}
909 			}
910 		}
911 		else if (el.tagName() == QLatin1String("forwarded")
912 			 && el.attribute(QLatin1String("xmlns")) == QLatin1String("urn:xmpp:forward:0")) {
913 			forward = el.firstChildElement(QLatin1String("message")); // currently only messages are supportted
914 			// TODO <delay> element support
915 			if (!forward.isNull()) {
916 				break;
917 			}
918 		}
919 	}
920 
921 	Stanza s = client()->stream().createStanza(addCorrectNS(forward.isNull()? e1 : forward));
922 	if(s.isNull()) {
923 		//printf("take: bad stanza??\n");
924 		return false;
925 	}
926 
927 	Message m;
928 	if(!m.fromStanza(s, client()->manualTimeZoneOffset(), client()->timeZoneOffset())) {
929 		//printf("bad message\n");
930 		return false;
931 	}
932 	if (!forward.isNull()) {
933 		m.setForwardedFrom(fromJid);
934 		m.setCarbonDirection(cd);
935 	}
936 
937 	emit message(m);
938 	return true;
939 }
940 
941 
942 //----------------------------------------------------------------------------
943 // JT_GetServices
944 //----------------------------------------------------------------------------
JT_GetServices(Task * parent)945 JT_GetServices::JT_GetServices(Task *parent)
946 :Task(parent)
947 {
948 }
949 
get(const Jid & j)950 void JT_GetServices::get(const Jid &j)
951 {
952 	agentList.clear();
953 
954 	jid = j;
955 	iq = createIQ(doc(), "get", jid.full(), id());
956 	QDomElement query = doc()->createElement("query");
957 	query.setAttribute("xmlns", "jabber:iq:agents");
958 	iq.appendChild(query);
959 }
960 
agents() const961 const AgentList & JT_GetServices::agents() const
962 {
963 	return agentList;
964 }
965 
onGo()966 void JT_GetServices::onGo()
967 {
968 	send(iq);
969 }
970 
take(const QDomElement & x)971 bool JT_GetServices::take(const QDomElement &x)
972 {
973 	if(!iqVerify(x, jid, id()))
974 		return false;
975 
976 	if(x.attribute("type") == "result") {
977 		QDomElement q = queryTag(x);
978 
979 		// agents
980 		for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
981 			QDomElement i = n.toElement();
982 			if(i.isNull())
983 				continue;
984 
985 			if(i.tagName() == "agent") {
986 				AgentItem a;
987 
988 				a.setJid(Jid(i.attribute("jid")));
989 
990 				QDomElement tag;
991 
992 				tag = i.firstChildElement("name");
993 				if(!tag.isNull())
994 					a.setName(tagContent(tag));
995 
996 				// determine which namespaces does item support
997 				QStringList ns;
998 
999 				tag = i.firstChildElement("register");
1000 				if(!tag.isNull())
1001 					ns << "jabber:iq:register";
1002 				tag = i.firstChildElement("search");
1003 				if(!tag.isNull())
1004 					ns << "jabber:iq:search";
1005 				tag = i.firstChildElement("groupchat");
1006 				if(!tag.isNull())
1007 					ns << "jabber:iq:conference";
1008 				tag = i.firstChildElement("transport");
1009 				if(!tag.isNull())
1010 					ns << "jabber:iq:gateway";
1011 
1012 				a.setFeatures(ns);
1013 
1014 				agentList += a;
1015 			}
1016 		}
1017 
1018 		setSuccess(true);
1019 	}
1020 	else {
1021 		setError(x);
1022 	}
1023 
1024 	return true;
1025 }
1026 
1027 
1028 //----------------------------------------------------------------------------
1029 // JT_VCard
1030 //----------------------------------------------------------------------------
1031 class JT_VCard::Private
1032 {
1033 public:
Private()1034 	Private() {}
1035 
1036 	QDomElement iq;
1037 	Jid jid;
1038 	VCard vcard;
1039 };
1040 
JT_VCard(Task * parent)1041 JT_VCard::JT_VCard(Task *parent)
1042 :Task(parent)
1043 {
1044 	type = -1;
1045 	d = new Private;
1046 }
1047 
~JT_VCard()1048 JT_VCard::~JT_VCard()
1049 {
1050 	delete d;
1051 }
1052 
get(const Jid & _jid)1053 void JT_VCard::get(const Jid &_jid)
1054 {
1055 	type = 0;
1056 	d->jid = _jid;
1057 	d->iq = createIQ(doc(), "get", type == 1 ? Jid().full() : d->jid.full(), id());
1058 	QDomElement v = doc()->createElement("vCard");
1059 	v.setAttribute("xmlns", "vcard-temp");
1060 	d->iq.appendChild(v);
1061 }
1062 
jid() const1063 const Jid & JT_VCard::jid() const
1064 {
1065 	return d->jid;
1066 }
1067 
vcard() const1068 const VCard & JT_VCard::vcard() const
1069 {
1070 	return d->vcard;
1071 }
1072 
set(const VCard & card)1073 void JT_VCard::set(const VCard &card)
1074 {
1075 	type = 1;
1076 	d->vcard = card;
1077 	d->jid = "";
1078 	d->iq = createIQ(doc(), "set", d->jid.full(), id());
1079 	d->iq.appendChild(card.toXml(doc()) );
1080 }
1081 
1082 // isTarget is when we setting target's vcard. for example in case of muc own vcard
set(const Jid & j,const VCard & card,bool isTarget)1083 void JT_VCard::set(const Jid &j, const VCard &card, bool isTarget)
1084 {
1085 	type = 1;
1086 	d->vcard = card;
1087 	d->jid = j;
1088 	d->iq = createIQ(doc(), "set", isTarget? j.full() : "", id());
1089 	d->iq.appendChild(card.toXml(doc()) );
1090 }
1091 
onGo()1092 void JT_VCard::onGo()
1093 {
1094 	send(d->iq);
1095 }
1096 
take(const QDomElement & x)1097 bool JT_VCard::take(const QDomElement &x)
1098 {
1099 	Jid to = d->jid;
1100 	if (to.bare() == client()->jid().bare())
1101 		to = client()->host();
1102 	if(!iqVerify(x, to, id()))
1103 		return false;
1104 
1105 	if(x.attribute("type") == "result") {
1106 		if(type == 0) {
1107 			for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) {
1108 				QDomElement q = n.toElement();
1109 				if(q.isNull())
1110 					continue;
1111 
1112 				if(q.tagName().toUpper() == "VCARD") {
1113 					d->vcard = VCard::fromXml(q);
1114 					if(d->vcard) {
1115 						setSuccess();
1116 						return true;
1117 					}
1118 				}
1119 			}
1120 
1121 			setError(ErrDisc + 1, tr("No VCard available"));
1122 			return true;
1123 		}
1124 		else {
1125 			setSuccess();
1126 			return true;
1127 		}
1128 	}
1129 	else {
1130 		setError(x);
1131 	}
1132 
1133 	return true;
1134 }
1135 
1136 
1137 //----------------------------------------------------------------------------
1138 // JT_Search
1139 //----------------------------------------------------------------------------
1140 class JT_Search::Private
1141 {
1142 public:
Private()1143 	Private() {}
1144 
1145 	Jid jid;
1146 	Form form;
1147 	bool hasXData;
1148 	XData xdata;
1149 	QList<SearchResult> resultList;
1150 };
1151 
JT_Search(Task * parent)1152 JT_Search::JT_Search(Task *parent)
1153 :Task(parent)
1154 {
1155 	d = new Private;
1156 	type = -1;
1157 }
1158 
~JT_Search()1159 JT_Search::~JT_Search()
1160 {
1161 	delete d;
1162 }
1163 
get(const Jid & jid)1164 void JT_Search::get(const Jid &jid)
1165 {
1166 	type = 0;
1167 	d->jid = jid;
1168 	d->hasXData = false;
1169 	d->xdata = XData();
1170 	iq = createIQ(doc(), "get", d->jid.full(), id());
1171 	QDomElement query = doc()->createElement("query");
1172 	query.setAttribute("xmlns", "jabber:iq:search");
1173 	iq.appendChild(query);
1174 }
1175 
set(const Form & form)1176 void JT_Search::set(const Form &form)
1177 {
1178 	type = 1;
1179 	d->jid = form.jid();
1180 	d->hasXData = false;
1181 	d->xdata = XData();
1182 	iq = createIQ(doc(), "set", d->jid.full(), id());
1183 	QDomElement query = doc()->createElement("query");
1184 	query.setAttribute("xmlns", "jabber:iq:search");
1185 	iq.appendChild(query);
1186 
1187 	// key?
1188 	if(!form.key().isEmpty())
1189 		query.appendChild(textTag(doc(), "key", form.key()));
1190 
1191 	// fields
1192 	for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) {
1193 		const FormField &f = *it;
1194 		query.appendChild(textTag(doc(), f.realName(), f.value()));
1195 	}
1196 }
1197 
set(const Jid & jid,const XData & form)1198 void JT_Search::set(const Jid &jid, const XData &form)
1199 {
1200 	type = 1;
1201 	d->jid = jid;
1202 	d->hasXData = false;
1203 	d->xdata = XData();
1204 	iq = createIQ(doc(), "set", d->jid.full(), id());
1205 	QDomElement query = doc()->createElement("query");
1206 	query.setAttribute("xmlns", "jabber:iq:search");
1207 	iq.appendChild(query);
1208 	query.appendChild(form.toXml(doc(), true));
1209 }
1210 
form() const1211 const Form & JT_Search::form() const
1212 {
1213 	return d->form;
1214 }
1215 
results() const1216 const QList<SearchResult> & JT_Search::results() const
1217 {
1218 	return d->resultList;
1219 }
1220 
hasXData() const1221 bool JT_Search::hasXData() const
1222 {
1223 	return d->hasXData;
1224 }
1225 
xdata() const1226 const XData & JT_Search::xdata() const
1227 {
1228 	return d->xdata;
1229 }
1230 
onGo()1231 void JT_Search::onGo()
1232 {
1233 	send(iq);
1234 }
1235 
take(const QDomElement & x)1236 bool JT_Search::take(const QDomElement &x)
1237 {
1238 	if(!iqVerify(x, d->jid, id()))
1239 		return false;
1240 
1241 	Jid from(x.attribute("from"));
1242 	if(x.attribute("type") == "result") {
1243 		if(type == 0) {
1244 			d->form.clear();
1245 			d->form.setJid(from);
1246 
1247 			QDomElement q = queryTag(x);
1248 			for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
1249 				QDomElement i = n.toElement();
1250 				if(i.isNull())
1251 					continue;
1252 
1253 				if(i.tagName() == "instructions")
1254 					d->form.setInstructions(tagContent(i));
1255 				else if(i.tagName() == "key")
1256 					d->form.setKey(tagContent(i));
1257 				else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:data") {
1258 					d->xdata.fromXml(i);
1259 					d->hasXData = true;
1260 				}
1261 				else {
1262 					FormField f;
1263 					if(f.setType(i.tagName())) {
1264 						f.setValue(tagContent(i));
1265 						d->form += f;
1266 					}
1267 				}
1268 			}
1269 		}
1270 		else {
1271 			d->resultList.clear();
1272 
1273 			QDomElement q = queryTag(x);
1274 			for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
1275 				QDomElement i = n.toElement();
1276 				if(i.isNull())
1277 					continue;
1278 
1279 				if(i.tagName() == "item") {
1280 					SearchResult r(Jid(i.attribute("jid")));
1281 
1282 					QDomElement tag;
1283 
1284 					tag = i.firstChildElement("nick");
1285 					if(!tag.isNull())
1286 						r.setNick(tagContent(tag));
1287 					tag = i.firstChildElement("first");
1288 					if(!tag.isNull())
1289 						r.setFirst(tagContent(tag));
1290 					tag = i.firstChildElement("last");
1291 					if(!tag.isNull())
1292 						r.setLast(tagContent(tag));
1293 					tag = i.firstChildElement("email");
1294 					if(!tag.isNull())
1295 						r.setEmail(tagContent(tag));
1296 
1297 					d->resultList += r;
1298 				}
1299 				else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:data") {
1300 					d->xdata.fromXml(i);
1301 					d->hasXData = true;
1302 				}
1303 			}
1304 		}
1305 		setSuccess();
1306 	}
1307 	else {
1308 		setError(x);
1309 	}
1310 
1311 	return true;
1312 }
1313 
1314 
1315 //----------------------------------------------------------------------------
1316 // JT_ClientVersion
1317 //----------------------------------------------------------------------------
JT_ClientVersion(Task * parent)1318 JT_ClientVersion::JT_ClientVersion(Task *parent)
1319 :Task(parent)
1320 {
1321 }
1322 
get(const Jid & jid)1323 void JT_ClientVersion::get(const Jid &jid)
1324 {
1325 	j = jid;
1326 	iq = createIQ(doc(), "get", j.full(), id());
1327 	QDomElement query = doc()->createElement("query");
1328 	query.setAttribute("xmlns", "jabber:iq:version");
1329 	iq.appendChild(query);
1330 }
1331 
onGo()1332 void JT_ClientVersion::onGo()
1333 {
1334 	send(iq);
1335 }
1336 
take(const QDomElement & x)1337 bool JT_ClientVersion::take(const QDomElement &x)
1338 {
1339 	if(!iqVerify(x, j, id()))
1340 		return false;
1341 
1342 	if(x.attribute("type") == "result") {
1343 		QDomElement q = queryTag(x);
1344 		QDomElement tag;
1345 		tag = q.firstChildElement("name");
1346 		if(!tag.isNull())
1347 			v_name = tagContent(tag);
1348 		tag = q.firstChildElement("version");
1349 		if(!tag.isNull())
1350 			v_ver = tagContent(tag);
1351 		tag = q.firstChildElement("os");
1352 		if(!tag.isNull())
1353 			v_os = tagContent(tag);
1354 
1355 		setSuccess();
1356 	}
1357 	else {
1358 		setError(x);
1359 	}
1360 
1361 	return true;
1362 }
1363 
jid() const1364 const Jid & JT_ClientVersion::jid() const
1365 {
1366 	return j;
1367 }
1368 
name() const1369 const QString & JT_ClientVersion::name() const
1370 {
1371 	return v_name;
1372 }
1373 
version() const1374 const QString & JT_ClientVersion::version() const
1375 {
1376 	return v_ver;
1377 }
1378 
os() const1379 const QString & JT_ClientVersion::os() const
1380 {
1381 	return v_os;
1382 }
1383 
1384 
1385 //----------------------------------------------------------------------------
1386 // JT_EntityTime
1387 //----------------------------------------------------------------------------
JT_EntityTime(Task * parent)1388 JT_EntityTime::JT_EntityTime(Task* parent) : Task(parent)
1389 {
1390 }
1391 
1392 /**
1393  * \brief Queried entity's JID.
1394  */
jid() const1395 const Jid & JT_EntityTime::jid() const
1396 {
1397 	return j;
1398 }
1399 
1400 /**
1401  * \brief Prepares the task to get information from JID.
1402  */
get(const Jid & jid)1403 void JT_EntityTime::get(const Jid &jid)
1404 {
1405 	j = jid;
1406 	iq = createIQ(doc(), "get", jid.full(), id());
1407 	QDomElement time = doc()->createElement("time");
1408 	time.setAttribute("xmlns", "urn:xmpp:time");
1409 	iq.appendChild(time);
1410 }
1411 
onGo()1412 void JT_EntityTime::onGo()
1413 {
1414 	send(iq);
1415 }
1416 
take(const QDomElement & x)1417 bool JT_EntityTime::take(const QDomElement &x)
1418 {
1419 	if (!iqVerify(x, j, id()))
1420 		return false;
1421 
1422 	if (x.attribute("type") == "result") {
1423 		QDomElement q = x.firstChildElement("time");
1424 		QDomElement tag;
1425 		tag = q.firstChildElement("utc");
1426 		do {
1427 			if (tag.isNull()) {
1428 				break;
1429 			}
1430 			utc = QDateTime::fromString(tagContent(tag), Qt::ISODate);
1431 			tag = q.firstChildElement("tzo");
1432 			if (!utc.isValid() || tag.isNull()) {
1433 				break;
1434 			}
1435 			tzo = TimeZone::tzdToInt(tagContent(tag));
1436 			if (tzo == -1) {
1437 				break;
1438 			}
1439 			setSuccess();
1440 			return true;
1441 		}
1442 		while (false);
1443 		setError(406);
1444 	}
1445 	else {
1446 		setError(x);
1447 	}
1448 
1449 	return true;
1450 }
1451 
dateTime() const1452 const QDateTime & JT_EntityTime::dateTime() const
1453 {
1454 	return utc;
1455 }
1456 
timezoneOffset() const1457 int JT_EntityTime::timezoneOffset() const
1458 {
1459 	return tzo;
1460 }
1461 
1462 
1463 //----------------------------------------------------------------------------
1464 // JT_ServInfo
1465 //----------------------------------------------------------------------------
JT_ServInfo(Task * parent)1466 JT_ServInfo::JT_ServInfo(Task *parent)
1467 :Task(parent)
1468 {
1469 }
1470 
~JT_ServInfo()1471 JT_ServInfo::~JT_ServInfo()
1472 {
1473 }
1474 
take(const QDomElement & e)1475 bool JT_ServInfo::take(const QDomElement &e)
1476 {
1477 	if(e.tagName() != "iq" || e.attribute("type") != "get")
1478 		return false;
1479 
1480 	QString ns = queryNS(e);
1481 	if(ns == "jabber:iq:version") {
1482 		QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
1483 		QDomElement query = doc()->createElement("query");
1484 		query.setAttribute("xmlns", "jabber:iq:version");
1485 		iq.appendChild(query);
1486 		query.appendChild(textTag(doc(), "name", client()->clientName()));
1487 		query.appendChild(textTag(doc(), "version", client()->clientVersion()));
1488 		query.appendChild(textTag(doc(), "os", client()->OSName() + ' ' + client()->OSVersion()));
1489 		send(iq);
1490 		return true;
1491 	}
1492 	else if(ns == "http://jabber.org/protocol/disco#info") {
1493 		// Find out the node
1494 		QString node;
1495 		QDomElement q = e.firstChildElement("query");
1496 		if(!q.isNull()) // NOTE: Should always be true, since a NS was found above
1497 			node = q.attribute("node");
1498 
1499 		if (node.isEmpty() || node == client()->caps().flatten()) {
1500 
1501 			QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
1502 			DiscoItem item = client()->makeDiscoResult(node);
1503 			iq.appendChild(item.toDiscoInfoResult(doc()));
1504 			send(iq);
1505 		}
1506 		else {
1507 			// Create error reply
1508 			QDomElement error_reply = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
1509 
1510 			// Copy children
1511 			for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
1512 				error_reply.appendChild(n.cloneNode());
1513 			}
1514 
1515 			// Add error
1516 			QDomElement error = doc()->createElement("error");
1517 			error.setAttribute("type","cancel");
1518 			error_reply.appendChild(error);
1519 			QDomElement error_type = doc()->createElement("item-not-found");
1520 			error_type.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-stanzas");
1521 			error.appendChild(error_type);
1522 			send(error_reply);
1523 		}
1524 		return true;
1525 	}
1526 	if (!ns.isEmpty()) {
1527 		return false;
1528 	}
1529 
1530 	ns = e.firstChildElement("time").attribute("xmlns");
1531 	if (ns == "urn:xmpp:time") {
1532 		QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
1533 		QDomElement time = doc()->createElement("time");
1534 		time.setAttribute("xmlns", ns);
1535 		iq.appendChild(time);
1536 
1537 		QDateTime local = QDateTime::currentDateTime();
1538 
1539 		int off = TimeZone::offsetFromUtc();
1540 		QTime t = QTime(0, 0).addSecs(qAbs(off)*60);
1541 		QString tzo = (off < 0 ? "-" : "+") + t.toString("HH:mm");
1542 		time.appendChild(textTag(doc(), "tzo", tzo));
1543 		QString localTimeStr = local.toUTC().toString(Qt::ISODate);
1544 		if (!localTimeStr.endsWith("Z"))
1545 			localTimeStr.append("Z");
1546 		time.appendChild(textTag(doc(), "utc", localTimeStr));
1547 
1548 		send(iq);
1549 		return true;
1550 	}
1551 
1552 	return false;
1553 }
1554 
1555 
1556 //----------------------------------------------------------------------------
1557 // JT_Gateway
1558 //----------------------------------------------------------------------------
JT_Gateway(Task * parent)1559 JT_Gateway::JT_Gateway(Task *parent)
1560 :Task(parent)
1561 {
1562 	type = -1;
1563 }
1564 
get(const Jid & jid)1565 void JT_Gateway::get(const Jid &jid)
1566 {
1567 	type = 0;
1568 	v_jid = jid;
1569 	iq = createIQ(doc(), "get", v_jid.full(), id());
1570 	QDomElement query = doc()->createElement("query");
1571 	query.setAttribute("xmlns", "jabber:iq:gateway");
1572 	iq.appendChild(query);
1573 }
1574 
set(const Jid & jid,const QString & prompt)1575 void JT_Gateway::set(const Jid &jid, const QString &prompt)
1576 {
1577 	type = 1;
1578 	v_jid = jid;
1579 	v_prompt = prompt;
1580 	iq = createIQ(doc(), "set", v_jid.full(), id());
1581 	QDomElement query = doc()->createElement("query");
1582 	query.setAttribute("xmlns", "jabber:iq:gateway");
1583 	iq.appendChild(query);
1584 	query.appendChild(textTag(doc(), "prompt", v_prompt));
1585 }
1586 
onGo()1587 void JT_Gateway::onGo()
1588 {
1589 	send(iq);
1590 }
1591 
jid() const1592 Jid JT_Gateway::jid() const
1593 {
1594 	return v_jid;
1595 }
1596 
desc() const1597 QString JT_Gateway::desc() const
1598 {
1599 	return v_desc;
1600 }
1601 
prompt() const1602 QString JT_Gateway::prompt() const
1603 {
1604 	return v_prompt;
1605 }
1606 
translatedJid() const1607 Jid JT_Gateway::translatedJid() const
1608 {
1609 	return v_translatedJid;
1610 }
1611 
take(const QDomElement & x)1612 bool JT_Gateway::take(const QDomElement &x)
1613 {
1614 	if(!iqVerify(x, v_jid, id()))
1615 		return false;
1616 
1617 	if(x.attribute("type") == "result") {
1618 		if(type == 0) {
1619 			QDomElement query = queryTag(x);
1620 			QDomElement tag;
1621 			tag = query.firstChildElement("desc");
1622 			if (!tag.isNull()) {
1623 				v_desc = tagContent(tag);
1624 			}
1625 			tag = query.firstChildElement("prompt");
1626 			if (!tag.isNull()) {
1627 				v_prompt = tagContent(tag);
1628 			}
1629 		}
1630 		else {
1631 			QDomElement query = queryTag(x);
1632 			QDomElement tag;
1633 			tag = query.firstChildElement("jid");
1634 			if (!tag.isNull()) {
1635 				v_translatedJid = tagContent(tag);
1636 			}
1637 			// we used to read 'prompt' in the past
1638 			// and some gateways still send it
1639 			tag = query.firstChildElement("prompt");
1640 			if (!tag.isNull()) {
1641 				v_prompt = tagContent(tag);
1642 			}
1643 		}
1644 
1645 		setSuccess();
1646 	}
1647 	else {
1648 		setError(x);
1649 	}
1650 
1651 	return true;
1652 }
1653 
1654 //----------------------------------------------------------------------------
1655 // JT_Browse
1656 //----------------------------------------------------------------------------
1657 class JT_Browse::Private
1658 {
1659 public:
1660 	QDomElement iq;
1661 	Jid jid;
1662 	AgentList agentList;
1663 	AgentItem root;
1664 };
1665 
JT_Browse(Task * parent)1666 JT_Browse::JT_Browse (Task *parent)
1667 :Task (parent)
1668 {
1669 	d = new Private;
1670 }
1671 
~JT_Browse()1672 JT_Browse::~JT_Browse ()
1673 {
1674 	delete d;
1675 }
1676 
get(const Jid & j)1677 void JT_Browse::get (const Jid &j)
1678 {
1679 	d->agentList.clear();
1680 
1681 	d->jid = j;
1682 	d->iq = createIQ(doc(), "get", d->jid.full(), id());
1683 	QDomElement query = doc()->createElement("item");
1684 	query.setAttribute("xmlns", "jabber:iq:browse");
1685 	d->iq.appendChild(query);
1686 }
1687 
agents() const1688 const AgentList & JT_Browse::agents() const
1689 {
1690 	return d->agentList;
1691 }
1692 
root() const1693 const AgentItem & JT_Browse::root() const
1694 {
1695 	return d->root;
1696 }
1697 
onGo()1698 void JT_Browse::onGo ()
1699 {
1700 	send(d->iq);
1701 }
1702 
browseHelper(const QDomElement & i)1703 AgentItem JT_Browse::browseHelper (const QDomElement &i)
1704 {
1705 	AgentItem a;
1706 
1707 	if ( i.tagName() == "ns" )
1708 		return a;
1709 
1710 	a.setName ( i.attribute("name") );
1711 	a.setJid  ( i.attribute("jid") );
1712 
1713 	// there are two types of category/type specification:
1714 	//
1715 	//   1. <item category="category_name" type="type_name" />
1716 	//   2. <category_name type="type_name" />
1717 
1718 	if ( i.tagName() == "item" || i.tagName() == "query" )
1719 		a.setCategory ( i.attribute("category") );
1720 	else
1721 		a.setCategory ( i.tagName() );
1722 
1723 	a.setType ( i.attribute("type") );
1724 
1725 	QStringList ns;
1726 	for(QDomNode n = i.firstChild(); !n.isNull(); n = n.nextSibling()) {
1727 		QDomElement i = n.toElement();
1728 		if(i.isNull())
1729 			continue;
1730 
1731 		if ( i.tagName() == "ns" )
1732 			ns << i.text();
1733 	}
1734 
1735 	// For now, conference.jabber.org returns proper namespace only
1736 	// when browsing individual rooms. So it's a quick client-side fix.
1737 	if ( !a.features().canGroupchat() && a.category() == "conference" )
1738 		ns << "jabber:iq:conference";
1739 
1740 	a.setFeatures (ns);
1741 
1742 	return a;
1743 }
1744 
take(const QDomElement & x)1745 bool JT_Browse::take(const QDomElement &x)
1746 {
1747 	if(!iqVerify(x, d->jid, id()))
1748 		return false;
1749 
1750 	if(x.attribute("type") == "result") {
1751 		for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) {
1752 			QDomElement i = n.toElement();
1753 			if(i.isNull())
1754 				continue;
1755 
1756 			d->root = browseHelper (i);
1757 
1758 			for(QDomNode nn = i.firstChild(); !nn.isNull(); nn = nn.nextSibling()) {
1759 				QDomElement e = nn.toElement();
1760 				if ( e.isNull() )
1761 					continue;
1762 				if ( e.tagName() == "ns" )
1763 					continue;
1764 
1765 				d->agentList += browseHelper (e);
1766 			}
1767 		}
1768 
1769 		setSuccess(true);
1770 	}
1771 	else {
1772 		setError(x);
1773 	}
1774 
1775 	return true;
1776 }
1777 
1778 //----------------------------------------------------------------------------
1779 // JT_DiscoItems
1780 //----------------------------------------------------------------------------
1781 class JT_DiscoItems::Private
1782 {
1783 public:
Private()1784 	Private() { }
1785 
1786 	QDomElement iq;
1787 	Jid jid;
1788 	DiscoList items;
1789 };
1790 
JT_DiscoItems(Task * parent)1791 JT_DiscoItems::JT_DiscoItems(Task *parent)
1792 : Task(parent)
1793 {
1794 	d = new Private;
1795 }
1796 
~JT_DiscoItems()1797 JT_DiscoItems::~JT_DiscoItems()
1798 {
1799 	delete d;
1800 }
1801 
get(const DiscoItem & item)1802 void JT_DiscoItems::get(const DiscoItem &item)
1803 {
1804 	get(item.jid(), item.node());
1805 }
1806 
get(const Jid & j,const QString & node)1807 void JT_DiscoItems::get (const Jid &j, const QString &node)
1808 {
1809 	d->items.clear();
1810 
1811 	d->jid = j;
1812 	d->iq = createIQ(doc(), "get", d->jid.full(), id());
1813 	QDomElement query = doc()->createElement("query");
1814 	query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items");
1815 
1816 	if ( !node.isEmpty() )
1817 		query.setAttribute("node", node);
1818 
1819 	d->iq.appendChild(query);
1820 }
1821 
items() const1822 const DiscoList &JT_DiscoItems::items() const
1823 {
1824 	return d->items;
1825 }
1826 
onGo()1827 void JT_DiscoItems::onGo ()
1828 {
1829 	send(d->iq);
1830 }
1831 
take(const QDomElement & x)1832 bool JT_DiscoItems::take(const QDomElement &x)
1833 {
1834 	if(!iqVerify(x, d->jid, id()))
1835 		return false;
1836 
1837 	if(x.attribute("type") == "result") {
1838 		QDomElement q = queryTag(x);
1839 
1840 		for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
1841 			QDomElement e = n.toElement();
1842 			if( e.isNull() )
1843 				continue;
1844 
1845 			if ( e.tagName() == "item" ) {
1846 				DiscoItem item;
1847 
1848 				item.setJid ( e.attribute("jid")  );
1849 				item.setName( e.attribute("name") );
1850 				item.setNode( e.attribute("node") );
1851 				item.setAction( DiscoItem::string2action(e.attribute("action")) );
1852 
1853 				d->items.append( item );
1854 			}
1855 		}
1856 
1857 		setSuccess(true);
1858 	}
1859 	else {
1860 		setError(x);
1861 	}
1862 
1863 	return true;
1864 }
1865 
1866 //----------------------------------------------------------------------------
1867 // JT_DiscoPublish
1868 //----------------------------------------------------------------------------
1869 class JT_DiscoPublish::Private
1870 {
1871 public:
Private()1872 	Private() { }
1873 
1874 	QDomElement iq;
1875 	Jid jid;
1876 	DiscoList list;
1877 };
1878 
JT_DiscoPublish(Task * parent)1879 JT_DiscoPublish::JT_DiscoPublish(Task *parent)
1880 : Task(parent)
1881 {
1882 	d = new Private;
1883 }
1884 
~JT_DiscoPublish()1885 JT_DiscoPublish::~JT_DiscoPublish()
1886 {
1887 	delete d;
1888 }
1889 
set(const Jid & j,const DiscoList & list)1890 void JT_DiscoPublish::set(const Jid &j, const DiscoList &list)
1891 {
1892 	d->list = list;
1893 	d->jid = j;
1894 
1895 	d->iq = createIQ(doc(), "set", d->jid.full(), id());
1896 	QDomElement query = doc()->createElement("query");
1897 	query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items");
1898 
1899 	// FIXME: unsure about this
1900 	//if ( !node.isEmpty() )
1901 	//	query.setAttribute("node", node);
1902 
1903 	DiscoList::ConstIterator it = list.begin();
1904 	for ( ; it != list.end(); ++it) {
1905 		QDomElement w = doc()->createElement("item");
1906 
1907 		w.setAttribute("jid", (*it).jid().full());
1908 		if ( !(*it).name().isEmpty() )
1909 			w.setAttribute("name", (*it).name());
1910 		if ( !(*it).node().isEmpty() )
1911 		w.setAttribute("node", (*it).node());
1912 		w.setAttribute("action", DiscoItem::action2string((*it).action()));
1913 
1914 		query.appendChild( w );
1915 	}
1916 
1917 	d->iq.appendChild(query);
1918 }
1919 
onGo()1920 void JT_DiscoPublish::onGo ()
1921 {
1922 	send(d->iq);
1923 }
1924 
take(const QDomElement & x)1925 bool JT_DiscoPublish::take(const QDomElement &x)
1926 {
1927 	if(!iqVerify(x, d->jid, id()))
1928 		return false;
1929 
1930 	if(x.attribute("type") == "result") {
1931 		setSuccess(true);
1932 	}
1933 	else {
1934 		setError(x);
1935 	}
1936 
1937 	return true;
1938 }
1939 
1940 
1941 // ---------------------------------------------------------
1942 // JT_BoBServer
1943 // ---------------------------------------------------------
JT_BoBServer(Task * parent)1944 JT_BoBServer::JT_BoBServer(Task *parent)
1945 	: Task(parent)
1946 {
1947 
1948 }
1949 
take(const QDomElement & e)1950 bool JT_BoBServer::take(const QDomElement &e)
1951 {
1952 	if (e.tagName() != "iq" || e.attribute("type") != "get")
1953 		return false;
1954 
1955 	QDomElement data = e.firstChildElement("data");
1956 	if (data.attribute("xmlns") == "urn:xmpp:bob") {
1957 		QDomElement iq;
1958 		BoBData bd = client()->bobManager()->bobData(data.attribute("cid"));
1959 		if (bd.isNull()) {
1960 			iq = createIQ(client()->doc(), "error",
1961 						  e.attribute("from"), e.attribute("id"));
1962 			Stanza::Error error(Stanza::Error::Cancel,
1963 								Stanza::Error::ItemNotFound);
1964 			iq.appendChild(error.toXml(*doc(), client()->stream().baseNS()));
1965 		}
1966 		else {
1967 			iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
1968 			iq.appendChild(bd.toXml(doc()));
1969 		}
1970 		send(iq);
1971 		return true;
1972 	}
1973 	return false;
1974 }
1975 
1976 
1977 //----------------------------------------------------------------------------
1978 // JT_BitsOfBinary
1979 //----------------------------------------------------------------------------
1980 class JT_BitsOfBinary::Private
1981 {
1982 public:
Private()1983 	Private() { }
1984 
1985 	QDomElement iq;
1986 	Jid jid;
1987 	QString cid;
1988 	BoBData data;
1989 };
1990 
JT_BitsOfBinary(Task * parent)1991 JT_BitsOfBinary::JT_BitsOfBinary(Task *parent)
1992 : Task(parent)
1993 {
1994 	d = new Private;
1995 }
1996 
~JT_BitsOfBinary()1997 JT_BitsOfBinary::~JT_BitsOfBinary()
1998 {
1999 	delete d;
2000 }
2001 
get(const Jid & j,const QString & cid)2002 void JT_BitsOfBinary::get(const Jid &j, const QString &cid)
2003 {
2004 	d->jid = j;
2005 	d->cid = cid;
2006 
2007 	d->data = client()->bobManager()->bobData(cid);
2008 	if (d->data.isNull()) {
2009 		d->iq = createIQ(doc(), "get", d->jid.full(), id());
2010 		QDomElement data = doc()->createElement("data");
2011 		data.setAttribute("xmlns", "urn:xmpp:bob");
2012 		data.setAttribute("cid", cid);
2013 		d->iq.appendChild(data);
2014 	}
2015 }
2016 
onGo()2017 void JT_BitsOfBinary::onGo()
2018 {
2019 	if (d->data.isNull()) {
2020 		send(d->iq);
2021 	}
2022 	else {
2023 		setSuccess();
2024 	}
2025 }
2026 
take(const QDomElement & x)2027 bool JT_BitsOfBinary::take(const QDomElement &x)
2028 {
2029 	if (!iqVerify(x, d->jid, id())) {
2030 		return false;
2031 	}
2032 
2033 	if (x.attribute("type") == "result") {
2034 		QDomElement data = x.firstChildElement("data");
2035 
2036 		if (!data.isNull() && data.attribute("cid") == d->cid) { // check xmlns?
2037 			d->data.fromXml(data);
2038 			client()->bobManager()->append(d->data);
2039 		}
2040 
2041 		setSuccess();
2042 	}
2043 	else {
2044 		setError(x);
2045 	}
2046 
2047 	return true;
2048 }
2049 
data()2050 BoBData &JT_BitsOfBinary::data()
2051 {
2052 	return d->data;
2053 }
2054 
2055 //----------------------------------------------------------------------------
2056 // JT_PongServer
2057 //----------------------------------------------------------------------------
2058 /**
2059  * \class JT_PongServer
2060  * \brief Answers XMPP Pings
2061  */
2062 
JT_PongServer(Task * parent)2063 JT_PongServer::JT_PongServer(Task *parent)
2064 :Task(parent)
2065 {
2066 
2067 }
2068 
take(const QDomElement & e)2069 bool JT_PongServer::take(const QDomElement &e)
2070 {
2071 	if (e.tagName() != "iq" || e.attribute("type") != "get")
2072 		return false;
2073 
2074 	QDomElement ping = e.firstChildElement("ping");
2075 	if (!e.isNull() && ping.attribute("xmlns") == "urn:xmpp:ping") {
2076 		QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
2077 		send(iq);
2078 		return true;
2079 	}
2080 	return false;
2081 }
2082 
2083 //---------------------------------------------------------------------------
2084 // JT_CaptchaChallenger
2085 //---------------------------------------------------------------------------
2086 class JT_CaptchaChallenger::Private
2087 {
2088 public:
2089 	Jid j;
2090 	CaptchaChallenge challenge;
2091 };
2092 
JT_CaptchaChallenger(Task * parent)2093 JT_CaptchaChallenger::JT_CaptchaChallenger(Task *parent) :
2094     Task(parent),
2095     d(new Private)
2096 {
2097 }
2098 
~JT_CaptchaChallenger()2099 JT_CaptchaChallenger::~JT_CaptchaChallenger()
2100 {
2101 	delete d;
2102 }
2103 
set(const Jid & j,const CaptchaChallenge & c)2104 void JT_CaptchaChallenger::set(const Jid &j, const CaptchaChallenge &c)
2105 {
2106 	d->j = j;
2107 	d->challenge = c;
2108 }
2109 
onGo()2110 void JT_CaptchaChallenger::onGo()
2111 {
2112 	setTimeout(CaptchaValidTimeout);
2113 
2114 	Message m;
2115 	m.setId(id());
2116 	m.setBody(d->challenge.explanation());
2117 	m.setUrlList(d->challenge.urls());
2118 
2119 	XData form = d->challenge.form();
2120 	XData::FieldList fl = form.fields();
2121 	XData::FieldList::Iterator it;
2122 	for (it = fl.begin(); it < fl.end(); ++it) {
2123 		if (it->var() == "challenge" && it->type() == XData::Field::Field_Hidden) {
2124 			it->setValue(QStringList() << id());
2125 		}
2126 	}
2127 	if (it == fl.end()) {
2128 		XData::Field f;
2129 		f.setType(XData::Field::Field_Hidden);
2130 		f.setVar("challenge");
2131 		f.setValue(QStringList() << id());
2132 		fl.append(f);
2133 	}
2134 	form.setFields(fl);
2135 
2136 	m.setForm(form);
2137 	m.setTo(d->j);
2138 	client()->sendMessage(m);
2139 }
2140 
take(const QDomElement & x)2141 bool JT_CaptchaChallenger::take(const QDomElement &x)
2142 {
2143 	if(x.tagName() == "message" && x.attribute("id") == id() &&
2144 	        Jid(x.attribute("from")) == d->j && !x.firstChildElement("error").isNull())
2145 	{
2146 		setError(x);
2147 		return true;
2148 	}
2149 
2150 	XDomNodeList nl;
2151 	XData xd;
2152 	QString rid = x.attribute("id");
2153 	if (rid.isEmpty() || x.tagName() != "iq" ||
2154 	        Jid(x.attribute("from")) != d->j || x.attribute("type") != "set" ||
2155 	        (nl = childElementsByTagNameNS(x, "urn:xmpp:captcha", "captcha")).isEmpty() ||
2156 	        (nl = childElementsByTagNameNS(nl.item(0).toElement(), "jabber:x:data", "x")).isEmpty() ||
2157 	        (xd.fromXml(nl.item(0).toElement()), xd.getField("challenge").value().value(0) != id()))
2158 	{
2159 		return false;
2160 	}
2161 
2162 	CaptchaChallenge::Result r = d->challenge.validateResponse(xd);
2163 	QDomElement iq;
2164 	if (r == CaptchaChallenge::Passed) {
2165 		iq = createIQ(doc(), "result", d->j.full(), rid);
2166 	} else {
2167 		Stanza::Error::ErrorCond ec;
2168 		if (r == CaptchaChallenge::Unavailable) {
2169 			ec = Stanza::Error::ServiceUnavailable;
2170 		} else {
2171 			ec = Stanza::Error::NotAcceptable;
2172 		}
2173 		iq = createIQ(doc(), "error", d->j.full(), rid);
2174 		Stanza::Error error(Stanza::Error::Cancel, ec);
2175 		iq.appendChild(error.toXml(*doc(), client()->stream().baseNS()));
2176 	}
2177 	send(iq);
2178 
2179 	setSuccess();
2180 
2181 	return true;
2182 }
2183 
2184 
2185 //---------------------------------------------------------------------------
2186 // JT_CaptchaSender
2187 //---------------------------------------------------------------------------
JT_CaptchaSender(Task * parent)2188 JT_CaptchaSender::JT_CaptchaSender(Task *parent) :
2189     Task(parent)
2190 {}
2191 
set(const Jid & j,const XData & xd)2192 void JT_CaptchaSender::set(const Jid &j, const XData &xd)
2193 {
2194 	to = j;
2195 
2196 	iq = createIQ(doc(), "set", to.full(), id());
2197 	iq.appendChild(doc()->createElementNS("urn:xmpp:captcha", "captcha"))
2198 	        .appendChild(xd.toXml(doc(), true));
2199 }
2200 
onGo()2201 void JT_CaptchaSender::onGo()
2202 {
2203 	send(iq);
2204 }
2205 
take(const QDomElement & x)2206 bool JT_CaptchaSender::take(const QDomElement &x)
2207 {
2208 	if (!iqVerify(x, to, id())) {
2209 		return false;
2210 	}
2211 
2212 	if (x.attribute("type") == "result") {
2213 		setSuccess();
2214 	}
2215 	else {
2216 		setError(x);
2217 	}
2218 
2219 	return true;
2220 }
2221 
2222 //----------------------------------------------------------------------------
2223 // JT_MessageCarbons
2224 //----------------------------------------------------------------------------
JT_MessageCarbons(Task * parent)2225 JT_MessageCarbons::JT_MessageCarbons(Task *parent)
2226 	: Task(parent)
2227 {
2228 
2229 }
2230 
enable()2231 void JT_MessageCarbons::enable()
2232 {
2233 	_iq = createIQ(doc(), "set", "", id());
2234 
2235 	QDomElement enable = doc()->createElement("enable");
2236 	enable.setAttribute("xmlns", "urn:xmpp:carbons:2");
2237 
2238 	_iq.appendChild(enable);
2239 }
2240 
disable()2241 void JT_MessageCarbons::disable()
2242 {
2243 	_iq = createIQ(doc(), "set", "", id());
2244 
2245 	QDomElement disable = doc()->createElement("disable");
2246 	disable.setAttribute("xmlns", "urn:xmpp:carbons:2");
2247 
2248 	_iq.appendChild(disable);
2249 }
2250 
onGo()2251 void JT_MessageCarbons::onGo()
2252 {
2253 	send(_iq);
2254 	setSuccess();
2255 }
2256 
take(const QDomElement & e)2257 bool JT_MessageCarbons::take(const QDomElement &e)
2258 {
2259 	if (e.tagName() != "iq" || e.attribute("type") != "result")
2260 		return false;
2261 
2262 	bool res = iqVerify(e, Jid(), id());
2263 	return res;
2264 }
2265