source: psi/trunk/iris/xmpp-im/xmpp_tasks.cpp

Last change on this file was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 36.5 KB
Line 
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include"xmpp_tasks.h"
22
23#include"base64.h"
24//#include"sha1.h"
25#include"xmpp_xmlcommon.h"
26//#include"xmpp_stream.h"
27//#include"xmpp_types.h"
28#include"xmpp_vcard.h"
29
30#include<qregexp.h>
31#include<qvaluelist.h>
32
33using namespace XMPP;
34
35
36static 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
44static QString lineDecode(const QString &str)
45{
46 QString ret;
47
48 for(unsigned 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
69static 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//----------------------------------------------------------------------------
94// JT_Register
95//----------------------------------------------------------------------------
96class JT_Register::Private
97{
98public:
99 Private() {}
100
101 Form form;
102 Jid jid;
103 int type;
104};
105
106JT_Register::JT_Register(Task *parent)
107:Task(parent)
108{
109 d = new Private;
110 d->type = -1;
111}
112
113JT_Register::~JT_Register()
114{
115 delete d;
116}
117
118void JT_Register::reg(const QString &user, const QString &pass)
119{
120 d->type = 0;
121 to = client()->host();
122 iq = createIQ(doc(), "set", to.full(), id());
123 QDomElement query = doc()->createElement("query");
124 query.setAttribute("xmlns", "jabber:iq:register");
125 iq.appendChild(query);
126 query.appendChild(textTag(doc(), "username", user));
127 query.appendChild(textTag(doc(), "password", pass));
128}
129
130void JT_Register::changepw(const QString &pass)
131{
132 d->type = 1;
133 to = client()->host();
134 iq = createIQ(doc(), "set", to.full(), id());
135 QDomElement query = doc()->createElement("query");
136 query.setAttribute("xmlns", "jabber:iq:register");
137 iq.appendChild(query);
138 query.appendChild(textTag(doc(), "username", client()->user()));
139 query.appendChild(textTag(doc(), "password", pass));
140}
141
142void JT_Register::unreg(const Jid &j)
143{
144 d->type = 2;
145 to = j.isEmpty() ? client()->host() : j.full();
146 iq = createIQ(doc(), "set", to.full(), id());
147 QDomElement query = doc()->createElement("query");
148 query.setAttribute("xmlns", "jabber:iq:register");
149 iq.appendChild(query);
150
151 // this may be useful
152 if(!d->form.key().isEmpty())
153 query.appendChild(textTag(doc(), "key", d->form.key()));
154
155 query.appendChild(doc()->createElement("remove"));
156}
157
158void JT_Register::getForm(const Jid &j)
159{
160 d->type = 3;
161 to = j;
162 iq = createIQ(doc(), "get", to.full(), id());
163 QDomElement query = doc()->createElement("query");
164 query.setAttribute("xmlns", "jabber:iq:register");
165 iq.appendChild(query);
166}
167
168void JT_Register::setForm(const Form &form)
169{
170 d->type = 4;
171 to = form.jid();
172 iq = createIQ(doc(), "set", to.full(), id());
173 QDomElement query = doc()->createElement("query");
174 query.setAttribute("xmlns", "jabber:iq:register");
175 iq.appendChild(query);
176
177 // key?
178 if(!form.key().isEmpty())
179 query.appendChild(textTag(doc(), "key", form.key()));
180
181 // fields
182 for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) {
183 const FormField &f = *it;
184 query.appendChild(textTag(doc(), f.realName(), f.value()));
185 }
186}
187
188const Form & JT_Register::form() const
189{
190 return d->form;
191}
192
193void JT_Register::onGo()
194{
195 send(iq);
196}
197
198bool JT_Register::take(const QDomElement &x)
199{
200 if(!iqVerify(x, to, id()))
201 return false;
202
203 Jid from(x.attribute("from"));
204 if(x.attribute("type") == "result") {
205 if(d->type == 3) {
206 d->form.clear();
207 d->form.setJid(from);
208
209 QDomElement q = queryTag(x);
210 for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
211 QDomElement i = n.toElement();
212 if(i.isNull())
213 continue;
214
215 if(i.tagName() == "instructions")
216 d->form.setInstructions(tagContent(i));
217 else if(i.tagName() == "key")
218 d->form.setKey(tagContent(i));
219 else {
220 FormField f;
221 if(f.setType(i.tagName())) {
222 f.setValue(tagContent(i));
223 d->form += f;
224 }
225 }
226 }
227 }
228
229 setSuccess();
230 }
231 else
232 setError(x);
233
234 return true;
235}
236
237//----------------------------------------------------------------------------
238// JT_UnRegister
239//----------------------------------------------------------------------------
240class JT_UnRegister::Private
241{
242public:
243 Private() { }
244
245 Jid j;
246 JT_Register *jt_reg;
247};
248
249JT_UnRegister::JT_UnRegister(Task *parent)
250: Task(parent)
251{
252 d = new Private;
253 d->jt_reg = 0;
254}
255
256JT_UnRegister::~JT_UnRegister()
257{
258 delete d->jt_reg;
259 delete d;
260}
261
262void JT_UnRegister::unreg(const Jid &j)
263{
264 d->j = j;
265}
266
267void JT_UnRegister::onGo()
268{
269 delete d->jt_reg;
270
271 d->jt_reg = new JT_Register(this);
272 d->jt_reg->getForm(d->j);
273 connect(d->jt_reg, SIGNAL(finished()), SLOT(getFormFinished()));
274 d->jt_reg->go(false);
275}
276
277void JT_UnRegister::getFormFinished()
278{
279 disconnect(d->jt_reg, 0, this, 0);
280
281 d->jt_reg->unreg(d->j);
282 connect(d->jt_reg, SIGNAL(finished()), SLOT(unregFinished()));
283 d->jt_reg->go(false);
284}
285
286void JT_UnRegister::unregFinished()
287{
288 if ( d->jt_reg->success() )
289 setSuccess();
290 else
291 setError(d->jt_reg->statusCode(), d->jt_reg->statusString());
292
293 delete d->jt_reg;
294 d->jt_reg = 0;
295}
296
297//----------------------------------------------------------------------------
298// JT_Roster
299//----------------------------------------------------------------------------
300class JT_Roster::Private
301{
302public:
303 Private() {}
304
305 Roster roster;
306 QValueList<QDomElement> itemList;
307};
308
309JT_Roster::JT_Roster(Task *parent)
310:Task(parent)
311{
312 type = -1;
313 d = new Private;
314}
315
316JT_Roster::~JT_Roster()
317{
318 delete d;
319}
320
321void JT_Roster::get()
322{
323 type = 0;
324 //to = client()->host();
325 iq = createIQ(doc(), "get", to.full(), id());
326 QDomElement query = doc()->createElement("query");
327 query.setAttribute("xmlns", "jabber:iq:roster");
328 iq.appendChild(query);
329}
330
331void JT_Roster::set(const Jid &jid, const QString &name, const QStringList &groups)
332{
333 type = 1;
334 //to = client()->host();
335 QDomElement item = doc()->createElement("item");
336 item.setAttribute("jid", jid.full());
337 if(!name.isEmpty())
338 item.setAttribute("name", name);
339 for(QStringList::ConstIterator it = groups.begin(); it != groups.end(); ++it)
340 item.appendChild(textTag(doc(), "group", *it));
341 d->itemList += item;
342}
343
344void JT_Roster::remove(const Jid &jid)
345{
346 type = 1;
347 //to = client()->host();
348 QDomElement item = doc()->createElement("item");
349 item.setAttribute("jid", jid.full());
350 item.setAttribute("subscription", "remove");
351 d->itemList += item;
352}
353
354void JT_Roster::onGo()
355{
356 if(type == 0)
357 send(iq);
358 else if(type == 1) {
359 //to = client()->host();
360 iq = createIQ(doc(), "set", to.full(), id());
361 QDomElement query = doc()->createElement("query");
362 query.setAttribute("xmlns", "jabber:iq:roster");
363 iq.appendChild(query);
364 for(QValueList<QDomElement>::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it)
365 query.appendChild(*it);
366 send(iq);
367 }
368}
369
370const Roster & JT_Roster::roster() const
371{
372 return d->roster;
373}
374
375QString JT_Roster::toString() const
376{
377 if(type != 1)
378 return "";
379
380 QDomElement i = doc()->createElement("request");
381 i.setAttribute("type", "JT_Roster");
382 for(QValueList<QDomElement>::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it)
383 i.appendChild(*it);
384 return lineEncode(Stream::xmlToString(i));
385 return "";
386}
387
388bool JT_Roster::fromString(const QString &str)
389{
390 QDomDocument *dd = new QDomDocument;
391 if(!dd->setContent(lineDecode(str).utf8()))
392 return false;
393 QDomElement e = doc()->importNode(dd->documentElement(), true).toElement();
394 delete dd;
395
396 if(e.tagName() != "request" || e.attribute("type") != "JT_Roster")
397 return false;
398
399 type = 1;
400 d->itemList.clear();
401 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
402 QDomElement i = n.toElement();
403 if(i.isNull())
404 continue;
405 d->itemList += i;
406 }
407
408 return true;
409}
410
411bool JT_Roster::take(const QDomElement &x)
412{
413 if(!iqVerify(x, client()->host(), id()))
414 return false;
415
416 // get
417 if(type == 0) {
418 if(x.attribute("type") == "result") {
419 QDomElement q = queryTag(x);
420 d->roster = xmlReadRoster(q, false);
421 setSuccess();
422 }
423 else {
424 setError(x);
425 }
426
427 return true;
428 }
429 // set
430 else if(type == 1) {
431 if(x.attribute("type") == "result")
432 setSuccess();
433 else
434 setError(x);
435
436 return true;
437 }
438 // remove
439 else if(type == 2) {
440 setSuccess();
441 return true;
442 }
443
444 return false;
445}
446
447
448//----------------------------------------------------------------------------
449// JT_PushRoster
450//----------------------------------------------------------------------------
451JT_PushRoster::JT_PushRoster(Task *parent)
452:Task(parent)
453{
454}
455
456JT_PushRoster::~JT_PushRoster()
457{
458}
459
460bool JT_PushRoster::take(const QDomElement &e)
461{
462 // must be an iq-set tag
463 if(e.tagName() != "iq" || e.attribute("type") != "set")
464 return false;
465
466 if(!iqVerify(e, client()->host(), "", "jabber:iq:roster"))
467 return false;
468
469 roster(xmlReadRoster(queryTag(e), true));
470
471 return true;
472}
473
474
475//----------------------------------------------------------------------------
476// JT_Presence
477//----------------------------------------------------------------------------
478JT_Presence::JT_Presence(Task *parent)
479:Task(parent)
480{
481 type = -1;
482}
483
484JT_Presence::~JT_Presence()
485{
486}
487
488void JT_Presence::pres(const Status &s)
489{
490 type = 0;
491
492 tag = doc()->createElement("presence");
493 if(!s.isAvailable()) {
494 tag.setAttribute("type", "unavailable");
495 if(!s.status().isEmpty())
496 tag.appendChild(textTag(doc(), "status", s.status()));
497 }
498 else {
499 if(s.isInvisible())
500 tag.setAttribute("type", "invisible");
501
502 if(!s.show().isEmpty())
503 tag.appendChild(textTag(doc(), "show", s.show()));
504 if(!s.status().isEmpty())
505 tag.appendChild(textTag(doc(), "status", s.status()));
506
507 tag.appendChild( textTag(doc(), "priority", QString("%1").arg(s.priority()) ) );
508
509 if(!s.keyID().isEmpty()) {
510 QDomElement x = textTag(doc(), "x", s.keyID());
511 x.setAttribute("xmlns", "http://jabber.org/protocol/e2e");
512 tag.appendChild(x);
513 }
514 if(!s.xsigned().isEmpty()) {
515 QDomElement x = textTag(doc(), "x", s.xsigned());
516 x.setAttribute("xmlns", "jabber:x:signed");
517 tag.appendChild(x);
518 }
519 }
520}
521
522void JT_Presence::pres(const Jid &to, const Status &s)
523{
524 pres(s);
525 tag.setAttribute("to", to.full());
526}
527
528void JT_Presence::sub(const Jid &to, const QString &subType)
529{
530 type = 1;
531
532 tag = doc()->createElement("presence");
533 tag.setAttribute("to", to.full());
534 tag.setAttribute("type", subType);
535}
536
537void JT_Presence::onGo()
538{
539 send(tag);
540 setSuccess();
541}
542
543
544//----------------------------------------------------------------------------
545// JT_PushPresence
546//----------------------------------------------------------------------------
547JT_PushPresence::JT_PushPresence(Task *parent)
548:Task(parent)
549{
550}
551
552JT_PushPresence::~JT_PushPresence()
553{
554}
555
556bool JT_PushPresence::take(const QDomElement &e)
557{
558 if(e.tagName() != "presence")
559 return false;
560
561 Jid j(e.attribute("from"));
562 Status p;
563
564 if(e.hasAttribute("type")) {
565 QString type = e.attribute("type");
566 if(type == "unavailable") {
567 p.setIsAvailable(false);
568 }
569 else if(type == "error") {
570 QString str = "";
571 int code = 0;
572 getErrorFromElement(e, &code, &str);
573 p.setError(code, str);
574 }
575 else {
576 subscription(j, type);
577 return true;
578 }
579 }
580
581 QDomElement tag;
582 bool found;
583
584 tag = findSubTag(e, "status", &found);
585 if(found)
586 p.setStatus(tagContent(tag));
587 tag = findSubTag(e, "show", &found);
588 if(found)
589 p.setShow(tagContent(tag));
590 tag = findSubTag(e, "priority", &found);
591 if(found)
592 p.setPriority(tagContent(tag).toInt());
593
594 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
595 QDomElement i = n.toElement();
596 if(i.isNull())
597 continue;
598
599 if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:delay") {
600 if(i.hasAttribute("stamp")) {
601 QDateTime dt;
602 if(stamp2TS(i.attribute("stamp"), &dt))
603 dt = dt.addSecs(client()->timeZoneOffset() * 3600);
604 p.setTimeStamp(dt);
605 }
606 }
607 else if(i.tagName() == "x" && i.attribute("xmlns") == "gabber:x:music:info") {
608 QDomElement t;
609 bool found;
610 QString title, state;
611
612 t = findSubTag(i, "title", &found);
613 if(found)
614 title = tagContent(t);
615 t = findSubTag(i, "state", &found);
616 if(found)
617 state = tagContent(t);
618
619 if(!title.isEmpty() && state == "playing")
620 p.setSongTitle(title);
621 }
622 else if(i.tagName() == "x" && i.attribute("xmlns") == "jabber:x:signed") {
623 p.setXSigned(tagContent(i));
624 }
625 else if(i.tagName() == "x" && i.attribute("xmlns") == "http://jabber.org/protocol/e2e") {
626 p.setKeyID(tagContent(i));
627 }
628 }
629
630 presence(j, p);
631
632 return true;
633}
634
635
636//----------------------------------------------------------------------------
637// JT_Message
638//----------------------------------------------------------------------------
639static QDomElement oldStyleNS(const QDomElement &e)
640{
641 // find closest parent with a namespace
642 QDomNode par = e.parentNode();
643 while(!par.isNull() && par.namespaceURI().isNull())
644 par = par.parentNode();
645 bool noShowNS = false;
646 if(!par.isNull() && par.namespaceURI() == e.namespaceURI())
647 noShowNS = true;
648
649 QDomElement i;
650 uint x;
651 //if(noShowNS)
652 i = e.ownerDocument().createElement(e.tagName());
653 //else
654 // i = e.ownerDocument().createElementNS(e.namespaceURI(), e.tagName());
655
656 // copy attributes
657 QDomNamedNodeMap al = e.attributes();
658 for(x = 0; x < al.count(); ++x)
659 i.setAttributeNode(al.item(x).cloneNode().toAttr());
660
661 if(!noShowNS)
662 i.setAttribute("xmlns", e.namespaceURI());
663
664 // copy children
665 QDomNodeList nl = e.childNodes();
666 for(x = 0; x < nl.count(); ++x) {
667 QDomNode n = nl.item(x);
668 if(n.isElement())
669 i.appendChild(oldStyleNS(n.toElement()));
670 else
671 i.appendChild(n.cloneNode());
672 }
673 return i;
674}
675
676JT_Message::JT_Message(Task *parent, const Message &msg)
677:Task(parent)
678{
679 m = msg;
680 m.setId(id());
681}
682
683JT_Message::~JT_Message()
684{
685}
686
687void JT_Message::onGo()
688{
689 Stanza s = m.toStanza(&(client()->stream()));
690 QDomElement e = oldStyleNS(s.element());
691 send(e);
692 setSuccess();
693}
694
695
696//----------------------------------------------------------------------------
697// JT_PushMessage
698//----------------------------------------------------------------------------
699static QDomElement addCorrectNS(const QDomElement &e)
700{
701 uint x;
702
703 // grab child nodes
704 /*QDomDocumentFragment frag = e.ownerDocument().createDocumentFragment();
705 QDomNodeList nl = e.childNodes();
706 for(x = 0; x < nl.count(); ++x)
707 frag.appendChild(nl.item(x).cloneNode());*/
708
709 // find closest xmlns
710 QDomNode n = e;
711 while(!n.isNull() && !n.toElement().hasAttribute("xmlns"))
712 n = n.parentNode();
713 QString ns;
714 if(n.isNull() || !n.toElement().hasAttribute("xmlns"))
715 ns = "jabber:client";
716 else
717 ns = n.toElement().attribute("xmlns");
718
719 // make a new node
720 QDomElement i = e.ownerDocument().createElementNS(ns, e.tagName());
721
722 // copy attributes
723 QDomNamedNodeMap al = e.attributes();
724 for(x = 0; x < al.count(); ++x) {
725 QDomAttr a = al.item(x).toAttr();
726 if(a.name() != "xmlns")
727 i.setAttributeNodeNS(al.item(x).cloneNode().toAttr());
728 }
729
730 // copy children
731 QDomNodeList nl = e.childNodes();
732 for(x = 0; x < nl.count(); ++x) {
733 QDomNode n = nl.item(x);
734 if(n.isElement())
735 i.appendChild(addCorrectNS(n.toElement()));
736 else
737 i.appendChild(n.cloneNode());
738 }
739
740 //i.appendChild(frag);
741 return i;
742}
743
744JT_PushMessage::JT_PushMessage(Task *parent)
745:Task(parent)
746{
747}
748
749JT_PushMessage::~JT_PushMessage()
750{
751}
752
753bool JT_PushMessage::take(const QDomElement &e)
754{
755 if(e.tagName() != "message")
756 return false;
757
758 Stanza s = client()->stream().createStanza(addCorrectNS(e));
759 if(s.isNull()) {
760 //printf("take: bad stanza??\n");
761 return false;
762 }
763
764 Message m;
765 if(!m.fromStanza(s, client()->timeZoneOffset())) {
766 //printf("bad message\n");
767 return false;
768 }
769
770 message(m);
771 return true;
772}
773
774
775//----------------------------------------------------------------------------
776// JT_GetServices
777//----------------------------------------------------------------------------
778JT_GetServices::JT_GetServices(Task *parent)
779:Task(parent)
780{
781}
782
783void JT_GetServices::get(const Jid &j)
784{
785 agentList.clear();
786
787 jid = j;
788 iq = createIQ(doc(), "get", jid.full(), id());
789 QDomElement query = doc()->createElement("query");
790 query.setAttribute("xmlns", "jabber:iq:agents");
791 iq.appendChild(query);
792}
793
794const AgentList & JT_GetServices::agents() const
795{
796 return agentList;
797}
798
799void JT_GetServices::onGo()
800{
801 send(iq);
802}
803
804bool JT_GetServices::take(const QDomElement &x)
805{
806 if(!iqVerify(x, jid, id()))
807 return false;
808
809 if(x.attribute("type") == "result") {
810 QDomElement q = queryTag(x);
811
812 // agents
813 for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
814 QDomElement i = n.toElement();
815 if(i.isNull())
816 continue;
817
818 if(i.tagName() == "agent") {
819 AgentItem a;
820
821 a.setJid(Jid(i.attribute("jid")));
822
823 QDomElement tag;
824 bool found;
825
826 tag = findSubTag(i, "name", &found);
827 if(found)
828 a.setName(tagContent(tag));
829
830 // determine which namespaces does item support
831 QStringList ns;
832
833 tag = findSubTag(i, "register", &found);
834 if(found)
835 ns << "jabber:iq:register";
836 tag = findSubTag(i, "search", &found);
837 if(found)
838 ns << "jabber:iq:search";
839 tag = findSubTag(i, "groupchat", &found);
840 if(found)
841 ns << "jabber:iq:conference";
842 tag = findSubTag(i, "transport", &found);
843 if(found)
844 ns << "jabber:iq:gateway";
845
846 a.setFeatures(ns);
847
848 agentList += a;
849 }
850 }
851
852 setSuccess(true);
853 }
854 else {
855 setError(x);
856 }
857
858 return true;
859}
860
861
862//----------------------------------------------------------------------------
863// JT_VCard
864//----------------------------------------------------------------------------
865class JT_VCard::Private
866{
867public:
868 Private() {}
869
870 QDomElement iq;
871 Jid jid;
872 VCard vcard;
873};
874
875JT_VCard::JT_VCard(Task *parent)
876:Task(parent)
877{
878 type = -1;
879 d = new Private;
880}
881
882JT_VCard::~JT_VCard()
883{
884 delete d;
885}
886
887void JT_VCard::get(const Jid &_jid)
888{
889 type = 0;
890 d->jid = _jid;
891 d->iq = createIQ(doc(), "get", d->jid.full(), id());
892 QDomElement v = doc()->createElement("vCard");
893 v.setAttribute("xmlns", "vcard-temp");
894 v.setAttribute("version", "2.0");
895 v.setAttribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN");
896 d->iq.appendChild(v);
897}
898
899const Jid & JT_VCard::jid() const
900{
901 return d->jid;
902}
903
904const VCard & JT_VCard::vcard() const
905{
906 return d->vcard;
907}
908
909void JT_VCard::set(const VCard &card)
910{
911 type = 1;
912 d->vcard = card;
913 d->jid = "";
914 d->iq = createIQ(doc(), "set", d->jid.full(), id());
915 d->iq.appendChild(card.toXml(doc()) );
916}
917
918void JT_VCard::onGo()
919{
920 send(d->iq);
921}
922
923bool JT_VCard::take(const QDomElement &x)
924{
925 Jid to = d->jid;
926 if (to.userHost() == client()->jid().userHost())
927 to = client()->host();
928 if(!iqVerify(x, to, id()))
929 return false;
930
931 if(x.attribute("type") == "result") {
932 if(type == 0) {
933 for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) {
934 QDomElement q = n.toElement();
935 if(q.isNull())
936 continue;
937
938 if(q.tagName().upper() == "VCARD") {
939 if(d->vcard.fromXml(q)) {
940 setSuccess();
941 return true;
942 }
943 }
944 }
945
946 setError(ErrDisc + 1, tr("No VCard available"));
947 return true;
948 }
949 else {
950 setSuccess();
951 return true;
952 }
953 }
954 else {
955 setError(x);
956 }
957
958 return true;
959}
960
961
962//----------------------------------------------------------------------------
963// JT_Search
964//----------------------------------------------------------------------------
965class JT_Search::Private
966{
967public:
968 Private() {}
969
970 Jid jid;
971 Form form;
972 QValueList<SearchResult> resultList;
973};
974
975JT_Search::JT_Search(Task *parent)
976:Task(parent)
977{
978 d = new Private;
979 type = -1;
980}
981
982JT_Search::~JT_Search()
983{
984 delete d;
985}
986
987void JT_Search::get(const Jid &jid)
988{
989 type = 0;
990 d->jid = jid;
991 iq = createIQ(doc(), "get", d->jid.full(), id());
992 QDomElement query = doc()->createElement("query");
993 query.setAttribute("xmlns", "jabber:iq:search");
994 iq.appendChild(query);
995}
996
997void JT_Search::set(const Form &form)
998{
999 type = 1;
1000 d->jid = form.jid();
1001 iq = createIQ(doc(), "set", d->jid.full(), id());
1002 QDomElement query = doc()->createElement("query");
1003 query.setAttribute("xmlns", "jabber:iq:search");
1004 iq.appendChild(query);
1005
1006 // key?
1007 if(!form.key().isEmpty())
1008 query.appendChild(textTag(doc(), "key", form.key()));
1009
1010 // fields
1011 for(Form::ConstIterator it = form.begin(); it != form.end(); ++it) {
1012 const FormField &f = *it;
1013 query.appendChild(textTag(doc(), f.realName(), f.value()));
1014 }
1015}
1016
1017const Form & JT_Search::form() const
1018{
1019 return d->form;
1020}
1021
1022const QValueList<SearchResult> & JT_Search::results() const
1023{
1024 return d->resultList;
1025}
1026
1027void JT_Search::onGo()
1028{
1029 send(iq);
1030}
1031
1032bool JT_Search::take(const QDomElement &x)
1033{
1034 if(!iqVerify(x, d->jid, id()))
1035 return false;
1036
1037 Jid from(x.attribute("from"));
1038 if(x.attribute("type") == "result") {
1039 if(type == 0) {
1040 d->form.clear();
1041 d->form.setJid(from);
1042
1043 QDomElement q = queryTag(x);
1044 for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
1045 QDomElement i = n.toElement();
1046 if(i.isNull())
1047 continue;
1048
1049 if(i.tagName() == "instructions")
1050 d->form.setInstructions(tagContent(i));
1051 else if(i.tagName() == "key")
1052 d->form.setKey(tagContent(i));
1053 else {
1054 FormField f;
1055 if(f.setType(i.tagName())) {
1056 f.setValue(tagContent(i));
1057 d->form += f;
1058 }
1059 }
1060 }
1061 }
1062 else {
1063 d->resultList.clear();
1064
1065 QDomElement q = queryTag(x);
1066 for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
1067 QDomElement i = n.toElement();
1068 if(i.isNull())
1069 continue;
1070
1071 if(i.tagName() == "item") {
1072 SearchResult r(Jid(i.attribute("jid")));
1073
1074 QDomElement tag;
1075 bool found;
1076
1077 tag = findSubTag(i, "nick", &found);
1078 if(found)
1079 r.setNick(tagContent(tag));
1080 tag = findSubTag(i, "first", &found);
1081 if(found)
1082 r.setFirst(tagContent(tag));
1083 tag = findSubTag(i, "last", &found);
1084 if(found)
1085 r.setLast(tagContent(tag));
1086 tag = findSubTag(i, "email", &found);
1087 if(found)
1088 r.setEmail(tagContent(tag));
1089
1090 d->resultList += r;
1091 }
1092 }
1093 }
1094 setSuccess();
1095 }
1096 else {
1097 setError(x);
1098 }
1099
1100 return true;
1101}
1102
1103
1104//----------------------------------------------------------------------------
1105// JT_ClientVersion
1106//----------------------------------------------------------------------------
1107JT_ClientVersion::JT_ClientVersion(Task *parent)
1108:Task(parent)
1109{
1110}
1111
1112void JT_ClientVersion::get(const Jid &jid)
1113{
1114 j = jid;
1115 iq = createIQ(doc(), "get", j.full(), id());
1116 QDomElement query = doc()->createElement("query");
1117 query.setAttribute("xmlns", "jabber:iq:version");
1118 iq.appendChild(query);
1119}
1120
1121void JT_ClientVersion::onGo()
1122{
1123 send(iq);
1124}
1125
1126bool JT_ClientVersion::take(const QDomElement &x)
1127{
1128 if(!iqVerify(x, j, id()))
1129 return false;
1130
1131 if(x.attribute("type") == "result") {
1132 bool found;
1133 QDomElement q = queryTag(x);
1134 QDomElement tag;
1135 tag = findSubTag(q, "name", &found);
1136 if(found)
1137 v_name = tagContent(tag);
1138 tag = findSubTag(q, "version", &found);
1139 if(found)
1140 v_ver = tagContent(tag);
1141 tag = findSubTag(q, "os", &found);
1142 if(found)
1143 v_os = tagContent(tag);
1144
1145 setSuccess();
1146 }
1147 else {
1148 setError(x);
1149 }
1150
1151 return true;
1152}
1153
1154const Jid & JT_ClientVersion::jid() const
1155{
1156 return j;
1157}
1158
1159const QString & JT_ClientVersion::name() const
1160{
1161 return v_name;
1162}
1163
1164const QString & JT_ClientVersion::version() const
1165{
1166 return v_ver;
1167}
1168
1169const QString & JT_ClientVersion::os() const
1170{
1171 return v_os;
1172}
1173
1174
1175//----------------------------------------------------------------------------
1176// JT_ClientTime
1177//----------------------------------------------------------------------------
1178/*JT_ClientTime::JT_ClientTime(Task *parent, const Jid &_j)
1179:Task(parent)
1180{
1181 j = _j;
1182 iq = createIQ("get", j.full(), id());
1183 QDomElement query = doc()->createElement("query");
1184 query.setAttribute("xmlns", "jabber:iq:time");
1185 iq.appendChild(query);
1186}
1187
1188void JT_ClientTime::go()
1189{
1190 send(iq);
1191}
1192
1193bool JT_ClientTime::take(const QDomElement &x)
1194{
1195 if(x.attribute("id") != id())
1196 return FALSE;
1197
1198 if(x.attribute("type") == "result") {
1199 bool found;
1200 QDomElement q = queryTag(x);
1201 QDomElement tag;
1202 tag = findSubTag(q, "utc", &found);
1203 if(found)
1204 stamp2TS(tagContent(tag), &utc);
1205 tag = findSubTag(q, "tz", &found);
1206 if(found)
1207 timezone = tagContent(tag);
1208 tag = findSubTag(q, "display", &found);
1209 if(found)
1210 display = tagContent(tag);
1211
1212 setSuccess(TRUE);
1213 }
1214 else {
1215 setError(getErrorString(x));
1216 setSuccess(FALSE);
1217 }
1218
1219 return TRUE;
1220}
1221*/
1222
1223
1224//----------------------------------------------------------------------------
1225// JT_ServInfo
1226//----------------------------------------------------------------------------
1227JT_ServInfo::JT_ServInfo(Task *parent)
1228:Task(parent)
1229{
1230}
1231
1232JT_ServInfo::~JT_ServInfo()
1233{
1234}
1235
1236bool JT_ServInfo::take(const QDomElement &e)
1237{
1238 if(e.tagName() != "iq" || e.attribute("type") != "get")
1239 return false;
1240
1241 QString ns = queryNS(e);
1242 if(ns == "jabber:iq:version") {
1243 QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
1244 QDomElement query = doc()->createElement("query");
1245 query.setAttribute("xmlns", "jabber:iq:version");
1246 iq.appendChild(query);
1247 query.appendChild(textTag(doc(), "name", client()->clientName()));
1248 query.appendChild(textTag(doc(), "version", client()->clientVersion()));
1249 query.appendChild(textTag(doc(), "os", client()->OSName()));
1250 send(iq);
1251 return true;
1252 }
1253 //else if(ns == "jabber:iq:time") {
1254 // QDomElement iq = createIQ("result", e.attribute("from"), e.attribute("id"));
1255 // QDomElement query = doc()->createElement("query");
1256 // query.setAttribute("xmlns", "jabber:iq:time");
1257 // iq.appendChild(query);
1258 // QDateTime local = QDateTime::currentDateTime();
1259 // QDateTime utc = local.addSecs(-getTZOffset() * 3600);
1260 // QString str = getTZString();
1261 // query.appendChild(textTag("utc", TS2stamp(utc)));
1262 // query.appendChild(textTag("tz", str));
1263 // query.appendChild(textTag("display", QString("%1 %2").arg(local.toString()).arg(str)));
1264 // send(iq);
1265 // return TRUE;
1266 //}
1267 else if(ns == "http://jabber.org/protocol/disco#info") {
1268 QDomElement iq = createIQ(doc(), "result", e.attribute("from"), e.attribute("id"));
1269 QDomElement query = doc()->createElement("query");
1270 query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
1271 iq.appendChild(query);
1272 QDomElement feature;
1273
1274 feature = doc()->createElement("feature");
1275 feature.setAttribute("var", "http://jabber.org/protocol/bytestreams");
1276 query.appendChild(feature);
1277
1278 feature = doc()->createElement("feature");
1279 feature.setAttribute("var", "http://jabber.org/protocol/si");
1280 query.appendChild(feature);
1281
1282 feature = doc()->createElement("feature");
1283 feature.setAttribute("var", "http://jabber.org/protocol/si/profile/file-transfer");
1284 query.appendChild(feature);
1285
1286 send(iq);
1287 return true;
1288 }
1289
1290 return false;
1291}
1292
1293
1294//----------------------------------------------------------------------------
1295// JT_Gateway
1296//----------------------------------------------------------------------------
1297JT_Gateway::JT_Gateway(Task *parent)
1298:Task(parent)
1299{
1300 type = -1;
1301}
1302
1303void JT_Gateway::get(const Jid &jid)
1304{
1305 type = 0;
1306 v_jid = jid;
1307 iq = createIQ(doc(), "get", v_jid.full(), id());
1308 QDomElement query = doc()->createElement("query");
1309 query.setAttribute("xmlns", "jabber:iq:gateway");
1310 iq.appendChild(query);
1311}
1312
1313void JT_Gateway::set(const Jid &jid, const QString &prompt)
1314{
1315 type = 1;
1316 v_jid = jid;
1317 v_prompt = prompt;
1318 iq = createIQ(doc(), "set", v_jid.full(), id());
1319 QDomElement query = doc()->createElement("query");
1320 query.setAttribute("xmlns", "jabber:iq:gateway");
1321 iq.appendChild(query);
1322 query.appendChild(textTag(doc(), "prompt", v_prompt));
1323}
1324
1325void JT_Gateway::onGo()
1326{
1327 send(iq);
1328}
1329
1330Jid JT_Gateway::jid() const
1331{
1332 return v_jid;
1333}
1334
1335QString JT_Gateway::desc() const
1336{
1337 return v_desc;
1338}
1339
1340QString JT_Gateway::prompt() const
1341{
1342 return v_prompt;
1343}
1344
1345bool JT_Gateway::take(const QDomElement &x)
1346{
1347 if(!iqVerify(x, v_jid, id()))
1348 return false;
1349
1350 if(x.attribute("type") == "result") {
1351 if(type == 0) {
1352 QDomElement query = queryTag(x);
1353 bool found;
1354 QDomElement tag;
1355 tag = findSubTag(query, "desc", &found);
1356 if(found)
1357 v_desc = tagContent(tag);
1358 tag = findSubTag(query, "prompt", &found);
1359 if(found)
1360 v_prompt = tagContent(tag);
1361 }
1362 else {
1363 QDomElement query = queryTag(x);
1364 bool found;
1365 QDomElement tag;
1366 tag = findSubTag(query, "prompt", &found);
1367 if(found)
1368 v_prompt = tagContent(tag);
1369 }
1370
1371 setSuccess();
1372 }
1373 else {
1374 setError(x);
1375 }
1376
1377 return true;
1378}
1379
1380//----------------------------------------------------------------------------
1381// JT_Browse
1382//----------------------------------------------------------------------------
1383class JT_Browse::Private
1384{
1385public:
1386 QDomElement iq;
1387 Jid jid;
1388 AgentList agentList;
1389 AgentItem root;
1390};
1391
1392JT_Browse::JT_Browse (Task *parent)
1393:Task (parent)
1394{
1395 d = new Private;
1396}
1397
1398JT_Browse::~JT_Browse ()
1399{
1400 delete d;
1401}
1402
1403void JT_Browse::get (const Jid &j)
1404{
1405 d->agentList.clear();
1406
1407 d->jid = j;
1408 d->iq = createIQ(doc(), "get", d->jid.full(), id());
1409 QDomElement query = doc()->createElement("item");
1410 query.setAttribute("xmlns", "jabber:iq:browse");
1411 d->iq.appendChild(query);
1412}
1413
1414const AgentList & JT_Browse::agents() const
1415{
1416 return d->agentList;
1417}
1418
1419const AgentItem & JT_Browse::root() const
1420{
1421 return d->root;
1422}
1423
1424void JT_Browse::onGo ()
1425{
1426 send(d->iq);
1427}
1428
1429AgentItem JT_Browse::browseHelper (const QDomElement &i)
1430{
1431 AgentItem a;
1432
1433 if ( i.tagName() == "ns" )
1434 return a;
1435
1436 a.setName ( i.attribute("name") );
1437 a.setJid ( i.attribute("jid") );
1438
1439 // there are two types of category/type specification:
1440 //
1441 // 1. <item category="category_name" type="type_name" />
1442 // 2. <category_name type="type_name" />
1443
1444 if ( i.tagName() == "item" || i.tagName() == "query" )
1445 a.setCategory ( i.attribute("category") );
1446 else
1447 a.setCategory ( i.tagName() );
1448
1449 a.setType ( i.attribute("type") );
1450
1451 QStringList ns;
1452 for(QDomNode n = i.firstChild(); !n.isNull(); n = n.nextSibling()) {
1453 QDomElement i = n.toElement();
1454 if(i.isNull())
1455 continue;
1456
1457 if ( i.tagName() == "ns" )
1458 ns << i.text();
1459 }
1460
1461 // For now, conference.jabber.org returns proper namespace only
1462 // when browsing individual rooms. So it's a quick client-side fix.
1463 if ( !a.features().canGroupchat() && a.category() == "conference" )
1464 ns << "jabber:iq:conference";
1465
1466 a.setFeatures (ns);
1467
1468 return a;
1469}
1470
1471bool JT_Browse::take(const QDomElement &x)
1472{
1473 if(!iqVerify(x, d->jid, id()))
1474 return false;
1475
1476 if(x.attribute("type") == "result") {
1477 for(QDomNode n = x.firstChild(); !n.isNull(); n = n.nextSibling()) {
1478 QDomElement i = n.toElement();
1479 if(i.isNull())
1480 continue;
1481
1482 d->root = browseHelper (i);
1483
1484 for(QDomNode nn = i.firstChild(); !nn.isNull(); nn = nn.nextSibling()) {
1485 QDomElement e = nn.toElement();
1486 if ( e.isNull() )
1487 continue;
1488 if ( e.tagName() == "ns" )
1489 continue;
1490
1491 d->agentList += browseHelper (e);
1492 }
1493 }
1494
1495 setSuccess(true);
1496 }
1497 else {
1498 setError(x);
1499 }
1500
1501 return true;
1502}
1503
1504//----------------------------------------------------------------------------
1505// JT_DiscoItems
1506//----------------------------------------------------------------------------
1507class JT_DiscoItems::Private
1508{
1509public:
1510 Private() { }
1511
1512 QDomElement iq;
1513 Jid jid;
1514 DiscoList items;
1515};
1516
1517JT_DiscoItems::JT_DiscoItems(Task *parent)
1518: Task(parent)
1519{
1520 d = new Private;
1521}
1522
1523JT_DiscoItems::~JT_DiscoItems()
1524{
1525 delete d;
1526}
1527
1528void JT_DiscoItems::get(const DiscoItem &item)
1529{
1530 get(item.jid(), item.node());
1531}
1532
1533void JT_DiscoItems::get (const Jid &j, const QString &node)
1534{
1535 d->items.clear();
1536
1537 d->jid = j;
1538 d->iq = createIQ(doc(), "get", d->jid.full(), id());
1539 QDomElement query = doc()->createElement("query");
1540 query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items");
1541
1542 if ( !node.isEmpty() )
1543 query.setAttribute("node", node);
1544
1545 d->iq.appendChild(query);
1546}
1547
1548const DiscoList &JT_DiscoItems::items() const
1549{
1550 return d->items;
1551}
1552
1553void JT_DiscoItems::onGo ()
1554{
1555 send(d->iq);
1556}
1557
1558bool JT_DiscoItems::take(const QDomElement &x)
1559{
1560 if(!iqVerify(x, d->jid, id()))
1561 return false;
1562
1563 if(x.attribute("type") == "result") {
1564 QDomElement q = queryTag(x);
1565
1566 for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
1567 QDomElement e = n.toElement();
1568 if( e.isNull() )
1569 continue;
1570
1571 if ( e.tagName() == "item" ) {
1572 DiscoItem item;
1573
1574 item.setJid ( e.attribute("jid") );
1575 item.setName( e.attribute("name") );
1576 item.setNode( e.attribute("node") );
1577 item.setAction( DiscoItem::string2action(e.attribute("action")) );
1578
1579 d->items.append( item );
1580 }
1581 }
1582
1583 setSuccess(true);
1584 }
1585 else {
1586 setError(x);
1587 }
1588
1589 return true;
1590}
1591
1592//----------------------------------------------------------------------------
1593// JT_DiscoInfo
1594//----------------------------------------------------------------------------
1595class JT_DiscoInfo::Private
1596{
1597public:
1598 Private() { }
1599
1600 QDomElement iq;
1601 Jid jid;
1602 DiscoItem item;
1603};
1604
1605JT_DiscoInfo::JT_DiscoInfo(Task *parent)
1606: Task(parent)
1607{
1608 d = new Private;
1609}
1610
1611JT_DiscoInfo::~JT_DiscoInfo()
1612{
1613 delete d;
1614}
1615
1616void JT_DiscoInfo::get(const DiscoItem &item)
1617{
1618 DiscoItem::Identity id;
1619 if ( item.identities().count() == 1 )
1620 id = item.identities().first();
1621 get(item.jid(), item.node(), id);
1622}
1623
1624void JT_DiscoInfo::get (const Jid &j, const QString &node, DiscoItem::Identity ident)
1625{
1626 d->item = DiscoItem(); // clear item
1627
1628 d->jid = j;
1629 d->iq = createIQ(doc(), "get", d->jid.full(), id());
1630 QDomElement query = doc()->createElement("query");
1631 query.setAttribute("xmlns", "http://jabber.org/protocol/disco#info");
1632
1633 if ( !node.isEmpty() )
1634 query.setAttribute("node", node);
1635
1636 if ( !ident.category.isEmpty() && !ident.type.isEmpty() ) {
1637 QDomElement i = doc()->createElement("item");
1638
1639 i.setAttribute("category", ident.category);
1640 i.setAttribute("type", ident.type);
1641 if ( !ident.name.isEmpty() )
1642 i.setAttribute("name", ident.name);
1643
1644 query.appendChild( i );
1645
1646 }
1647
1648 d->iq.appendChild(query);
1649}
1650
1651const DiscoItem &JT_DiscoInfo::item() const
1652{
1653 return d->item;
1654}
1655
1656void JT_DiscoInfo::onGo ()
1657{
1658 send(d->iq);
1659}
1660
1661bool JT_DiscoInfo::take(const QDomElement &x)
1662{
1663 if(!iqVerify(x, d->jid, id()))
1664 return false;
1665
1666 if(x.attribute("type") == "result") {
1667 QDomElement q = queryTag(x);
1668
1669 DiscoItem item;
1670
1671 item.setJid( d->jid );
1672 item.setNode( q.attribute("node") );
1673
1674 QStringList features;
1675 DiscoItem::Identities identities;
1676
1677 for(QDomNode n = q.firstChild(); !n.isNull(); n = n.nextSibling()) {
1678 QDomElement e = n.toElement();
1679 if( e.isNull() )
1680 continue;
1681
1682 if ( e.tagName() == "feature" ) {
1683 features << e.attribute("var");
1684 }
1685 else if ( e.tagName() == "identity" ) {
1686 DiscoItem::Identity id;
1687
1688 id.category = e.attribute("category");
1689 id.name = e.attribute("name");
1690 id.type = e.attribute("type");
1691
1692 identities.append( id );
1693 }
1694 }
1695
1696 item.setFeatures( features );
1697 item.setIdentities( identities );
1698
1699 d->item = item;
1700
1701 setSuccess(true);
1702 }
1703 else {
1704 setError(x);
1705 }
1706
1707 return true;
1708}
1709
1710//----------------------------------------------------------------------------
1711// JT_DiscoPublish
1712//----------------------------------------------------------------------------
1713class JT_DiscoPublish::Private
1714{
1715public:
1716 Private() { }
1717
1718 QDomElement iq;
1719 Jid jid;
1720 DiscoList list;
1721};
1722
1723JT_DiscoPublish::JT_DiscoPublish(Task *parent)
1724: Task(parent)
1725{
1726 d = new Private;
1727}
1728
1729JT_DiscoPublish::~JT_DiscoPublish()
1730{
1731 delete d;
1732}
1733
1734void JT_DiscoPublish::set(const Jid &j, const DiscoList &list)
1735{
1736 d->list = list;
1737 d->jid = j;
1738
1739 d->iq = createIQ(doc(), "set", d->jid.full(), id());
1740 QDomElement query = doc()->createElement("query");
1741 query.setAttribute("xmlns", "http://jabber.org/protocol/disco#items");
1742
1743 // FIXME: unsure about this
1744 //if ( !node.isEmpty() )
1745 // query.setAttribute("node", node);
1746
1747 DiscoList::ConstIterator it = list.begin();
1748 for ( ; it != list.end(); ++it) {
1749 QDomElement w = doc()->createElement("item");
1750
1751 w.setAttribute("jid", (*it).jid().full());
1752 if ( !(*it).name().isEmpty() )
1753 w.setAttribute("name", (*it).name());
1754 if ( !(*it).node().isEmpty() )
1755 w.setAttribute("node", (*it).node());
1756 w.setAttribute("action", DiscoItem::action2string((*it).action()));
1757
1758 query.appendChild( w );
1759 }
1760
1761 d->iq.appendChild(query);
1762}
1763
1764void JT_DiscoPublish::onGo ()
1765{
1766 send(d->iq);
1767}
1768
1769bool JT_DiscoPublish::take(const QDomElement &x)
1770{
1771 if(!iqVerify(x, d->jid, id()))
1772 return false;
1773
1774 if(x.attribute("type") == "result") {
1775 setSuccess(true);
1776 }
1777 else {
1778 setError(x);
1779 }
1780
1781 return true;
1782}
1783
Note: See TracBrowser for help on using the repository browser.