source: psi/trunk/src/servicesdlg.cpp@ 5

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

Imported original Psi 0.10 sources from Affinix

File size: 18.2 KB
Line 
1/*
2 * servicesdlg.cpp - a dialog for browsing Jabber services
3 * Copyright (C) 2001, 2002 Justin Karneges
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * 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"servicesdlg.h"
22
23#include<qpushbutton.h>
24#include<qcombobox.h>
25#include<qstringlist.h>
26#include<qlistbox.h>
27#include<qlayout.h>
28#include<qlineedit.h>
29#include<qlabel.h>
30#include<qgrid.h>
31#include<qguardedptr.h>
32#include<qlistview.h>
33#include<qgroupbox.h>
34#include<qapplication.h>
35#include<qdesktopwidget.h>
36#include"psicon.h"
37#include"psiaccount.h"
38#include"im.h"
39#include"xmpp_tasks.h"
40#include"common.h"
41#include"busywidget.h"
42#include"iconwidget.h"
43#include"xdata_widget.h"
44#include"xmpp_xdata.h"
45#include"xmpp_xmlcommon.h"
46
47using namespace XMLHelper;
48
49
50//----------------------------------------------------------------------------
51// JT_XRegister
52//----------------------------------------------------------------------------
53
54class JT_XRegister : public JT_Register
55{
56 Q_OBJECT
57public:
58 JT_XRegister(Task *parent);
59
60 void setXForm(const Form &frm, const XData &_form);
61
62 bool take(const QDomElement &);
63 QDomElement iq() const;
64
65 void onGo();
66
67private:
68 QDomElement _iq;
69};
70
71JT_XRegister::JT_XRegister( Task *parent )
72 : JT_Register( parent )
73{
74}
75
76bool JT_XRegister::take( const QDomElement &x )
77{
78 _iq = x;
79
80 return JT_Register::take( x );
81}
82
83QDomElement JT_XRegister::iq() const
84{
85 return _iq;
86}
87
88void JT_XRegister::setXForm(const Form &frm, const XData &_form)
89{
90 JT_Register::setForm( frm );
91
92 _iq = createIQ(doc(), "set", frm.jid().full(), id());
93 QDomElement query = doc()->createElement("query");
94 query.setAttribute("xmlns", "jabber:iq:register");
95 _iq.appendChild(query);
96
97 XData form( _form );
98 form.setType( XData::Data_Submit );
99 query.appendChild( form.toXml( doc() ) );
100}
101
102void JT_XRegister::onGo()
103{
104 if ( !_iq.isNull() )
105 send( _iq );
106 else
107 JT_Register::onGo();
108}
109
110//----------------------------------------------------------------------------
111// RegistrationDlg
112//----------------------------------------------------------------------------
113class RegistrationDlg::Private
114{
115public:
116 Private() {}
117
118 Jid jid;
119 PsiAccount *pa;
120
121 QPushButton *pb_close, *pb_reg;
122 QGuardedPtr<JT_XRegister> jt;
123 int type;
124 BusyWidget *busy;
125 QLabel *lb_top;
126 QGrid *gr_form;
127 Form form;
128
129 QPtrList<QLabel> lb_field;
130 QPtrList<QLineEdit> le_field;
131 XDataWidget *xdata;
132};
133
134RegistrationDlg::RegistrationDlg(const Jid &jid, PsiAccount *pa)
135:QDialog(0, 0, false, WDestructiveClose)
136{
137 d = new Private;
138 d->jid = jid;
139 d->pa = pa;
140 d->pa->dialogRegister(this, d->jid);
141 d->jt = 0;
142 d->xdata = 0;
143
144 d->lb_field.setAutoDelete(true);
145 d->le_field.setAutoDelete(true);
146
147 setCaption(tr("Registration: %1").arg(d->jid.full()));
148
149 QVBoxLayout *vb1 = new QVBoxLayout(this, 4);
150 d->lb_top = new QLabel(this);
151 d->lb_top->setFrameStyle( QFrame::Panel | QFrame::Sunken );
152 d->lb_top->hide();
153 vb1->addWidget(d->lb_top);
154
155 d->gr_form = new QGrid(2, Horizontal, this);
156 d->gr_form->setSpacing(4);
157 vb1->addWidget(d->gr_form);
158 d->gr_form->hide();
159
160 QFrame *line = new QFrame(this);
161 line->setFixedHeight(2);
162 line->setFrameStyle(QFrame::HLine | QFrame::Sunken);
163 vb1->addWidget(line);
164
165 QHBoxLayout *hb1 = new QHBoxLayout(vb1);
166 d->busy = new BusyWidget(this);
167 hb1->addWidget(d->busy);
168 hb1->addStretch(1);
169 d->pb_reg = new QPushButton(tr("&Register"), this);
170 d->pb_reg->setDefault(true);
171 connect(d->pb_reg, SIGNAL(clicked()), SLOT(doRegSet()));
172 hb1->addWidget(d->pb_reg);
173 d->pb_close = new QPushButton(tr("&Close"), this);
174 connect(d->pb_close, SIGNAL(clicked()), SLOT(close()));
175 hb1->addWidget(d->pb_close);
176
177 d->pb_reg->hide();
178
179 doRegGet();
180}
181
182RegistrationDlg::~RegistrationDlg()
183{
184 delete d->jt;
185 d->pa->dialogUnregister(this);
186 delete d;
187}
188
189/*void RegistrationDlg::closeEvent(QCloseEvent *e)
190{
191 e->ignore();
192 reject();
193}*/
194
195void RegistrationDlg::done(int r)
196{
197 if(d->busy->isActive() && d->type == 1) {
198 int n = QMessageBox::information(this, tr("Busy"), tr("<qt>Registration has already been submitted, so closing this window will not prevent the registration from happening. Do you still wish to close?</qt>"), tr("&Yes"), tr("&No"));
199 if(n != 0)
200 return;
201 }
202 QDialog::done(r);
203}
204
205void RegistrationDlg::doRegGet()
206{
207 d->lb_top->setText(tr("Fetching registration form for %1 ...").arg(d->jid.full()));
208 d->lb_top->show();
209 d->busy->start();
210
211 d->type = 0;
212 d->jt = new JT_XRegister(d->pa->client()->rootTask());
213 connect(d->jt, SIGNAL(finished()), SLOT(jt_finished()));
214 d->jt->getForm(d->jid);
215 d->jt->go(true);
216}
217
218void RegistrationDlg::doRegSet()
219{
220 if(!d->pa->checkConnected(this))
221 return;
222
223 d->jt = new JT_XRegister(d->pa->client()->rootTask());
224
225 if ( !d->xdata ) {
226 Form submitForm = d->form;
227
228 // import the changes back into the form.
229 // the QPtrList of QLineEdits should be in the same order
230 QPtrListIterator<QLineEdit> lit(d->le_field);
231 for(Form::Iterator it = submitForm.begin(); it != submitForm.end(); ++it) {
232 FormField &f = *it;
233 QLineEdit *le = lit.current();
234 f.setValue(le->text());
235 ++lit;
236 }
237
238 d->jt->setForm(submitForm);
239 }
240 else {
241 XData form;
242 form.setFields( d->xdata->fields() );
243
244 d->jt->setXForm( d->form, form );
245 }
246
247 d->gr_form->setEnabled(false);
248 d->pb_reg->setEnabled(false);
249 d->busy->start();
250
251 d->type = 1;
252 connect(d->jt, SIGNAL(finished()), SLOT(jt_finished()));
253 d->jt->go(true);
254}
255
256void RegistrationDlg::jt_finished()
257{
258 d->busy->stop();
259 d->gr_form->setEnabled(true);
260 d->pb_reg->setEnabled(true);
261 JT_XRegister *jt = d->jt;
262 d->jt = 0;
263
264 if(jt->success()) {
265 if(d->type == 0) {
266 d->form = jt->form();
267
268 bool useXData = false;
269 {
270 QDomNode n = queryTag( jt->iq() ).firstChild();
271 for( ; !n.isNull(); n = n.nextSibling()) {
272 QDomElement i = n.toElement();
273 if(i.isNull())
274 continue;
275
276 if( i.attribute( "xmlns" ) == "jabber:x:data" ) {
277 useXData = true;
278
279 XData form;
280 form.fromXml( i );
281
282 if ( !form.title().isEmpty() )
283 setCaption( form.title() );
284
285 QString str = tr("<b>Registration for \"%1\":</b><br><br>").arg(d->jid.full());
286 str += plain2rich( form.instructions() );
287 d->lb_top->setText(str);
288
289 d->xdata = new XDataWidget( d->gr_form );
290 d->xdata->setFields( form.fields() );
291
292 d->xdata->show();
293
294 break;
295 }
296 }
297 }
298
299 if ( !useXData ) {
300 QString str = tr("<b>Registration for \"%1\":</b><br><br>").arg(d->jid.full());
301 str += plain2rich(d->form.instructions());
302 d->lb_top->setText(str);
303 d->lb_top->setFixedWidth(300);
304
305 for(Form::ConstIterator it = d->form.begin(); it != d->form.end(); ++it) {
306 const FormField &f = *it;
307
308 QLabel *lb = new QLabel(f.fieldName(), d->gr_form);
309 QLineEdit *le = new QLineEdit(d->gr_form);
310 if(f.isSecret())
311 le->setEchoMode(QLineEdit::Password);
312 le->setText(f.value());
313
314 d->lb_field.append(lb);
315 d->le_field.append(le);
316 }
317
318 if (!d->le_field.isEmpty())
319 d->le_field.first()->setFocus();
320 }
321
322 d->gr_form->show();
323 d->pb_reg->show();
324 show();
325
326 qApp->processEvents();
327 resize(sizeHint());
328 }
329 else {
330 closeDialogs(this);
331 QMessageBox::information(this, tr("Success"), tr("Registration successful."));
332 close();
333 }
334 }
335 else {
336 if(d->type == 0) {
337 QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve registration form.\nReason: %1").arg(jt->statusString()));
338 close();
339 }
340 else {
341 closeDialogs(this);
342 QMessageBox::critical(this, tr("Error"), tr("Error submitting registration form.\nReason: %1").arg(jt->statusString()));
343 close();
344 }
345 }
346}
347
348//----------------------------------------------------------------------------
349// JT_XSearch
350//----------------------------------------------------------------------------
351
352class JT_XSearch : public JT_Search
353{
354 Q_OBJECT
355public:
356 JT_XSearch(Task *parent);
357
358 void setForm(const Form &frm, const XData &_form);
359
360 bool take(const QDomElement &);
361 QDomElement iq() const;
362
363 void onGo();
364
365private:
366 QDomElement _iq;
367};
368
369JT_XSearch::JT_XSearch( Task *parent )
370 : JT_Search( parent )
371{
372}
373
374bool JT_XSearch::take( const QDomElement &x )
375{
376 _iq = x;
377
378 return JT_Search::take( x );
379}
380
381QDomElement JT_XSearch::iq() const
382{
383 return _iq;
384}
385
386void JT_XSearch::setForm(const Form &frm, const XData &_form)
387{
388 JT_Search::set( frm );
389
390 _iq = createIQ(doc(), "set", frm.jid().full(), id());
391 QDomElement query = doc()->createElement("query");
392 query.setAttribute("xmlns", "jabber:iq:search");
393 _iq.appendChild(query);
394
395 XData form( _form );
396 form.setType( XData::Data_Submit );
397 query.appendChild( form.toXml( doc() ) );
398}
399
400void JT_XSearch::onGo()
401{
402 if ( !_iq.isNull() )
403 send( _iq );
404 else
405 JT_Search::onGo();
406}
407
408//----------------------------------------------------------------------------
409// SearchDlg
410//----------------------------------------------------------------------------
411class SearchDlg::Private
412{
413public:
414 Private() {}
415
416 PsiAccount *pa;
417 Jid jid;
418 Form form;
419 BusyWidget *busy;
420 QGuardedPtr<JT_XSearch> jt;
421 QGrid *gr_form;
422 int type;
423
424 QPtrList<QLabel> lb_field;
425 QPtrList<QLineEdit> le_field;
426 XDataWidget *xdata;
427 XData xdata_form;
428};
429
430SearchDlg::SearchDlg(const Jid &jid, PsiAccount *pa)
431:SearchUI(0, 0, WDestructiveClose)
432{
433 d = new Private;
434 d->pa = pa;
435 d->jid = jid;
436 d->pa->dialogRegister(this, d->jid);
437 d->jt = 0;
438 d->xdata = 0;
439
440 setCaption(caption().arg(d->jid.full()));
441
442 d->busy = busy;
443
444 d->gr_form = new QGrid(2, Horizontal, gb_search);
445 d->gr_form->setSpacing(4);
446 replaceWidget(lb_form, d->gr_form);
447 d->gr_form->hide();
448
449 pb_add->setEnabled(false);
450 pb_info->setEnabled(false);
451 pb_stop->setEnabled(false);
452 pb_search->setEnabled(false);
453
454 lv_results->setMultiSelection(true);
455 lv_results->setSelectionMode( QListView::Extended );
456 connect(lv_results, SIGNAL(selectionChanged()), SLOT(selectionChanged()));
457 connect(pb_close, SIGNAL(clicked()), SLOT(close()));
458 connect(pb_search, SIGNAL(clicked()), SLOT(doSearchSet()));
459 connect(pb_stop, SIGNAL(clicked()), SLOT(doStop()));
460 connect(pb_add, SIGNAL(clicked()), SLOT(doAdd()));
461 connect(pb_info, SIGNAL(clicked()), SLOT(doInfo()));
462
463 resize(600,440);
464
465 doSearchGet();
466}
467
468SearchDlg::~SearchDlg()
469{
470 delete d->jt;
471 d->pa->dialogUnregister(this);
472 delete d;
473}
474
475/*void SearchDlg::localUpdate(const JabRosterEntry &e)
476{
477 int oldstate = localStatus;
478 localStatus = e.localStatus();
479
480 if(localStatus == STATUS_OFFLINE) {
481 if(isBusy) {
482 busy->stop();
483 isBusy = FALSE;
484 }
485
486 pb_search->setEnabled(FALSE);
487 pb_stop->setEnabled(FALSE);
488 clear();
489 }
490 else {
491 // coming online?
492 if(oldstate == STATUS_OFFLINE) {
493 pb_search->setEnabled(TRUE);
494 }
495 }
496}*/
497
498void SearchDlg::addEntry(const QString &jid, const QString &nick, const QString &first, const QString &last, const QString &email)
499{
500 QListViewItem *lvi = new QListViewItem(lv_results);
501 lvi->setText(0, nick);
502 lvi->setText(1, first);
503 lvi->setText(2, last);
504 lvi->setText(3, email);
505 lvi->setText(4, jid);
506}
507
508void SearchDlg::doSearchGet()
509{
510 lb_instructions->setText(tr("<qt>Fetching search form for %1 ...</qt>").arg(d->jid.full()));
511 d->busy->start();
512
513 d->type = 0;
514 d->jt = new JT_XSearch(d->pa->client()->rootTask());
515 connect(d->jt, SIGNAL(finished()), SLOT(jt_finished()));
516 d->jt->get(d->jid);
517 d->jt->go(true);
518}
519
520void SearchDlg::doSearchSet()
521{
522 if(d->busy->isActive())
523 return;
524
525 if(!d->pa->checkConnected(this))
526 return;
527
528 d->jt = new JT_XSearch(d->pa->client()->rootTask());
529
530 if ( !d->xdata ) {
531 Form submitForm = d->form;
532
533 // import the changes back into the form.
534 // the QPtrList of QLineEdits should be in the same order
535 QPtrListIterator<QLineEdit> lit(d->le_field);
536 for(Form::Iterator it = submitForm.begin(); it != submitForm.end(); ++it) {
537 FormField &f = *it;
538 QLineEdit *le = lit.current();
539 f.setValue(le->text());
540 ++lit;
541 }
542
543 d->jt->set(submitForm);
544 }
545 else {
546 XData form;
547 form.setFields( d->xdata->fields() );
548
549 d->jt->setForm( d->form, form );
550 }
551
552 clear();
553
554 pb_search->setEnabled(false);
555 pb_stop->setEnabled(true);
556 d->gr_form->setEnabled(false);
557 d->busy->start();
558
559 d->type = 1;
560 connect(d->jt, SIGNAL(finished()), SLOT(jt_finished()));
561 d->jt->go(true);
562}
563
564void SearchDlg::jt_finished()
565{
566 d->busy->stop();
567 JT_XSearch *jt = d->jt;
568 d->jt = 0;
569
570 if(d->type == 1) {
571 d->gr_form->setEnabled(true);
572 pb_search->setEnabled(true);
573 pb_stop->setEnabled(false);
574 }
575
576 if(jt->success()) {
577 if(d->type == 0) {
578 d->form = jt->form();
579
580 bool useXData = false;
581 {
582 QDomNode n = queryTag( jt->iq() ).firstChild();
583 for( ; !n.isNull(); n = n.nextSibling()) {
584 QDomElement i = n.toElement();
585 if(i.isNull())
586 continue;
587
588 if( i.attribute( "xmlns" ) == "jabber:x:data" ) {
589 useXData = true;
590
591 XData form;
592 form.fromXml( i );
593
594 //if ( !form.title().isEmpty() )
595 // setCaption( form.title() );
596
597 QString str = plain2rich( form.instructions() );
598 lb_instructions->setText(str);
599
600 d->xdata = new XDataWidget( d->gr_form );
601 d->xdata->setFields( form.fields() );
602
603 d->xdata->show();
604
605 break;
606 }
607 }
608 }
609
610 if ( !useXData ) {
611 QString str = plain2rich(d->form.instructions());
612 lb_instructions->setText(str);
613
614 for(Form::ConstIterator it = d->form.begin(); it != d->form.end(); ++it) {
615 const FormField &f = *it;
616
617 QLabel *lb = new QLabel(f.fieldName(), d->gr_form);
618 QLineEdit *le = new QLineEdit(d->gr_form);
619 if(f.isSecret())
620 le->setEchoMode(QLineEdit::Password);
621 le->setText(f.value());
622
623 d->lb_field.append(lb);
624 d->le_field.append(le);
625
626 connect(le, SIGNAL(returnPressed()), this, SLOT(doSearchSet()));
627 }
628 }
629
630 d->gr_form->show();
631 pb_search->setEnabled(true);
632 show();
633
634 qApp->processEvents();
635 resize(sizeHint());
636 }
637 else {
638 if ( !d->xdata ) {
639 const QValueList<SearchResult> &list = jt->results();
640 if(list.isEmpty())
641 QMessageBox::information(this, tr("Search Results"), tr("Search returned 0 results."));
642 else {
643 for(QValueList<SearchResult>::ConstIterator it = list.begin(); it != list.end(); ++it) {
644 const SearchResult &r = *it;
645 addEntry(r.jid().full(), r.nick(), r.first(), r.last(), r.email());
646 }
647 }
648 }
649 else {
650 XData form;
651 QDomNode n = queryTag( jt->iq() ).firstChild();
652 for( ; !n.isNull(); n = n.nextSibling()) {
653 QDomElement i = n.toElement();
654 if(i.isNull())
655 continue;
656
657 if( i.attribute( "xmlns" ) == "jabber:x:data" ) {
658 form.fromXml( i );
659 break;
660 }
661 }
662
663 while ( lv_results->columns() )
664 lv_results->removeColumn( 0 );
665
666 QValueList<XData::ReportField>::ConstIterator it = form.report().begin();
667 for ( ; it != form.report().end(); ++it ) {
668 lv_results->addColumn( ( *it ).label );
669 }
670
671 QValueList<XData::ReportItem>::ConstIterator iit = form.reportItems().begin();
672 for ( ; iit != form.reportItems().end(); ++iit ) {
673 QListViewItem *lvi = new QListViewItem(lv_results);
674
675 int i = 0;
676 it = form.report().begin();
677 for ( ; it != form.report().end(); ++it ) {
678 QString name = ( *it ).name;
679 lvi->setText( i++, ( *iit )[name] );
680 }
681 }
682
683 d->xdata_form = form;
684 }
685 }
686 }
687 else {
688 if(d->type == 0) {
689 QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve search form.\nReason: %1").arg(jt->statusString()));
690 close();
691 }
692 else {
693 QMessageBox::critical(this, tr("Error"), tr("Error retrieving search results.\nReason: %1").arg(jt->statusString()));
694 }
695 }
696}
697
698void SearchDlg::clear()
699{
700 lv_results->clear();
701 pb_add->setEnabled(false);
702 pb_info->setEnabled(false);
703}
704
705void SearchDlg::doStop()
706{
707 if(!d->busy->isActive())
708 return;
709
710 delete d->jt;
711 d->jt = 0;
712
713 d->busy->stop();
714 d->gr_form->setEnabled(true);
715 pb_search->setEnabled(true);
716 pb_stop->setEnabled(false);
717}
718
719void SearchDlg::selectionChanged()
720{
721 int d = 0;
722 QListViewItem *lastChild = lv_results->firstChild();
723
724 if(!lastChild) {
725 pb_add->setEnabled(false);
726 pb_info->setEnabled(false);
727 return;
728 }
729
730 if( lastChild->isSelected() ) {
731 pb_add->setEnabled(true);
732 pb_info->setEnabled(true);
733 }
734 d++;
735
736 if ( lastChild ) {
737 while ( lastChild->nextSibling() ) {
738 lastChild = lastChild->nextSibling();
739 if( lastChild->isSelected() ) {
740 pb_add->setEnabled(true);
741 pb_info->setEnabled(true);
742 }
743 d++;
744 }
745 }
746}
747
748void SearchDlg::doAdd()
749{
750 QListViewItem *i = lv_results->firstChild();
751 QString name;
752
753 if(!i)
754 return;
755
756 int jid;
757 int nick;
758 if ( !d->xdata ) {
759 jid = 4;
760 nick = 0;
761 }
762 else {
763 jid = 0;
764 nick = 0;
765
766 int i = 0;
767 QValueList<XData::ReportField>::ConstIterator it = d->xdata_form.report().begin();
768 for ( ; it != d->xdata_form.report().end(); ++it, ++i ) {
769 QString name = ( *it ).name;
770 if ( name == "jid" )
771 jid = i;
772
773 if ( name == "nickname" || name == "nick" )
774 nick = i;
775 }
776 }
777
778 int d = 0;
779
780 if( i->isSelected() ) {
781 name = jidnick(i->text(jid), i->text(nick));
782 add(Jid(i->text(jid)), i->text(nick), QStringList(), true);
783 d++;
784 }
785
786 if( i ) {
787 while( i->nextSibling() ) {
788 i = i->nextSibling();
789 if( i->isSelected() ) {
790 name = jidnick(i->text(jid), i->text(nick));
791 add(Jid(i->text(jid)), i->text(nick), QStringList(), true);
792 d++;
793 }
794 }
795 }
796
797 if( d==1 )
798 QMessageBox::information(this, tr("Add User: Success"), tr("Added %1 to your roster.").arg(name));
799 else
800 QMessageBox::information(this, tr("Add User: Success"), tr("Added %1 users to your roster.").arg(d));
801}
802
803void SearchDlg::doInfo()
804{
805 QListViewItem *i = lv_results->firstChild();
806 QString name;
807
808 if(!i)
809 return;
810
811 int jid;
812 if ( !d->xdata ) {
813 jid = 4;
814 }
815 else {
816 jid = 0;
817
818 int i = 0;
819 QValueList<XData::ReportField>::ConstIterator it = d->xdata_form.report().begin();
820 for ( ; it != d->xdata_form.report().end(); ++it, ++i ) {
821 QString name = ( *it ).name;
822 if ( name == "jid" )
823 jid = i;
824 }
825 }
826
827 if( i->isSelected() ) {
828 aInfo(Jid(i->text(jid)));
829 }
830
831 if( i ) {
832 while( i->nextSibling() ) {
833 i = i->nextSibling();
834 if( i->isSelected() ) {
835 aInfo(Jid(i->text(jid)));
836 }
837 }
838 }
839}
840
841#include "servicesdlg.moc"
Note: See TracBrowser for help on using the repository browser.