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