~ubuntu-branches/ubuntu/jaunty/psi/jaunty

« back to all changes in this revision

Viewing changes to src/psiaccount.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 *
24
24
 */
25
25
 
26
 
#include"psiaccount.h"
27
 
 
28
 
#include<qinputdialog.h>
29
 
#include<qptrlist.h>
30
 
#include<qcstring.h>
31
 
#include<qtimer.h>
32
 
#include<qmessagebox.h>
33
 
#include<qguardedptr.h>
34
 
#include<qapplication.h>
35
 
#include<qpushbutton.h>
36
 
#include<qlayout.h>
37
 
#include<qobjectlist.h>
38
 
#include<qurl.h>
39
 
#include<qmap.h>
40
 
#include<qca.h>
41
 
#include<qfileinfo.h>
42
 
 
43
 
#include"psicon.h"
44
 
#include"profiles.h"
45
 
#include"im.h"
46
 
//#include"xmpp_client.h"
47
 
//#include"xmpp_stream.h"
48
 
//#include"xmpp_message.h"
49
 
#include"xmpp_tasks.h"
50
 
#include"xmpp_jidlink.h"
51
 
#include"s5b.h"
52
 
#include"filetransfer.h"
53
 
#include"accountdlg.h"
54
 
#include"changepwdlg.h"
55
 
#include"xmlconsole.h"
56
 
#include"userlist.h"
57
 
#include"eventdlg.h"
58
 
#include"chatdlg.h"
59
 
#include"contactview.h"
60
 
#include"groupchatdlg.h"
61
 
#include"statusdlg.h"
62
 
#include"infodlg.h"
63
 
#include"adduserdlg.h"
64
 
#include"historydlg.h"
65
 
#include"servicesdlg.h"
66
 
#include"discodlg.h"
67
 
#include"eventdb.h"
68
 
#include"jltest.h"
69
 
#include"passphrasedlg.h"
70
 
#include"vcardfactory.h"
71
 
//#include"qssl.h"
72
 
#include"sslcertdlg.h"
73
 
#include"qwextend.h"
74
 
#include"psipopup.h"
75
 
#include"fancylabel.h"
76
 
#include"iconwidget.h"
77
 
#include"base64.h"
78
 
#include"filetransdlg.h"
79
 
#include"avatars.h"
80
 
#include"tabdlg.h"
 
26
#include <QFileDialog>
 
27
#include <qinputdialog.h>
 
28
#include <qtimer.h>
 
29
#include <qmessagebox.h>
 
30
#include <qpointer.h>
 
31
#include <qapplication.h>
 
32
#include <qpushbutton.h>
 
33
#include <qlayout.h>
 
34
#include <qobject.h>
 
35
#include <qmap.h>
 
36
#include <qca.h>
 
37
#include <qfileinfo.h>
 
38
#include <QPixmap>
 
39
#include <QFrame>
 
40
#include <QList>
 
41
#include <QHostInfo>
 
42
 
 
43
#include "psiaccount.h"
 
44
#include "psiiconset.h"
 
45
#include "psicon.h"
 
46
#include "profiles.h"
 
47
#include "xmpp_tasks.h"
 
48
#include "xmpp_xmlcommon.h"
 
49
#include "s5b.h"
 
50
#include "filetransfer.h"
 
51
#include "pgpkeydlg.h"
 
52
#include "psioptions.h"
 
53
#include "textutil.h"
 
54
#include "httpauthmanager.h"
 
55
#include "pgputil.h"
 
56
#include "applicationinfo.h"
 
57
#include "pgptransaction.h"
 
58
#include "accountmanagedlg.h"
 
59
#include "changepwdlg.h"
 
60
#include "xmlconsole.h"
 
61
#include "userlist.h"
 
62
#include "psievent.h"
 
63
#include "jidutil.h"
 
64
#include "eventdlg.h"
 
65
#include "privacymanager.h"
 
66
#include "rosteritemexchangetask.h"
 
67
#include "chatdlg.h"
 
68
#include "contactview.h"
 
69
#include "mood.h"
 
70
#include "tune.h"
 
71
#ifdef USE_PEP
 
72
#include "tunecontroller.h"
 
73
#endif
 
74
#include "groupchatdlg.h"
 
75
#include "statusdlg.h"
 
76
#include "infodlg.h"
 
77
#include "adduserdlg.h"
 
78
#include "historydlg.h"
 
79
#include "capsmanager.h"
 
80
#include "registrationdlg.h"
 
81
#include "searchdlg.h"
 
82
#include "discodlg.h"
 
83
#include "eventdb.h"
 
84
#include "accountmodifydlg.h"
 
85
#include "passphrasedlg.h"
 
86
#include "voicecaller.h"
 
87
#include "voicecalldlg.h"
 
88
#ifdef HAVE_JINGLE
 
89
#include "jinglevoicecaller.h"
 
90
#endif
 
91
#ifdef GOOGLE_FT
 
92
#include "googleftmanager.h"
 
93
#endif
 
94
#include "pepmanager.h"
 
95
#include "serverinfomanager.h"
 
96
#ifdef WHITEBOARDING
 
97
#include "wbmanager.h"
 
98
#endif
 
99
#include "bookmarkmanager.h"
 
100
#include "vcardfactory.h"
 
101
//#include "qssl.h"
 
102
#include "sslcertdlg.h"
 
103
#include "mooddlg.h"
 
104
#include "qwextend.h"
 
105
#include "geolocation.h"
 
106
#include "physicallocation.h"
 
107
#include "psipopup.h"
 
108
#include "pgputil.h"
 
109
#include "translationmanager.h"
 
110
#include "iconwidget.h"
 
111
#include "filetransdlg.h"
 
112
#include "systeminfo.h"
 
113
#include "avatars.h"
 
114
#include "ahcommanddlg.h"
 
115
#include "mucjoindlg.h"
 
116
#include "ahcservermanager.h"
 
117
#include "rc.h"
 
118
#include "tabdlg.h"
 
119
#include "certutil.h"
 
120
#include "proxy.h"
 
121
#include "psicontactlist.h"
 
122
 
 
123
#ifdef PSI_PLUGINS
 
124
#include "pluginmanager.h"
 
125
#endif
 
126
 
 
127
#include <QtCrypto>
81
128
 
82
129
#if defined(Q_WS_MAC) && defined(HAVE_GROWL)
83
130
#include "psigrowlnotifier.h"
84
131
#endif
85
132
 
86
 
#include"bsocket.h"
 
133
#include "bsocket.h"
87
134
/*#ifdef Q_WS_WIN
88
 
#include<windows.h>
 
135
#include <windows.h>
89
136
typedef int socklen_t;
90
137
#else
91
 
#include<sys/socket.h>
92
 
#include<netinet/in.h>
 
138
#include <sys/socket.h>
 
139
#include <netinet/in.h>
93
140
#endif*/
94
141
 
95
 
//----------------------------------------------------------------------------
96
 
// AccountLabel
97
 
//----------------------------------------------------------------------------
98
 
AccountLabel::AccountLabel(PsiAccount *_pa, QWidget *par, bool smode)
99
 
:QLabel(par)
100
 
{
101
 
        pa = _pa;
102
 
        simpleMode = smode;
103
 
        setFrameStyle( QFrame::Panel | QFrame::Sunken );
104
 
 
105
 
        updateName();
106
 
        connect(pa, SIGNAL(updatedAccount()), this, SLOT(updateName()));
107
 
        connect(pa, SIGNAL(destroyed()), this, SLOT(deleteMe()));
108
 
}
109
 
 
110
 
AccountLabel::~AccountLabel()
111
 
{
112
 
}
113
 
 
114
 
void AccountLabel::updateName()
115
 
{
116
 
        setText(simpleMode ? pa->name() : pa->nameWithJid());
117
 
}
118
 
 
119
 
void AccountLabel::deleteMe()
120
 
{
121
 
        delete this;
122
 
}
123
 
 
124
 
 
125
 
//----------------------------------------------------------------------------
126
 
// PGPTransaction
127
 
//----------------------------------------------------------------------------
128
 
static int transid = 0;
129
 
class PGPTransaction::Private
130
 
{
131
 
public:
132
 
        Private() {}
133
 
 
134
 
        int id;
135
 
        Message m;
136
 
        QDomElement e;
137
 
        Jid j;
 
142
using namespace XMPP;
 
143
 
 
144
struct GCContact
 
145
{
 
146
        Jid jid;
 
147
        Status status;
138
148
};
139
149
 
140
 
PGPTransaction::PGPTransaction(OpenPGP::Engine *pgp)
141
 
:OpenPGP::Request(pgp)
142
 
{
143
 
        d = new Private;
144
 
        d->id = transid++;
145
 
}
146
 
 
147
 
PGPTransaction::~PGPTransaction()
148
 
{
149
 
        delete d;
150
 
}
151
 
 
152
 
int PGPTransaction::id() const
153
 
{
154
 
        return d->id;
155
 
}
156
 
 
157
 
void PGPTransaction::setMessage(const Message &m)
158
 
{
159
 
        d->m = m;
160
 
}
161
 
 
162
 
const Message & PGPTransaction::message() const
163
 
{
164
 
        return d->m;
165
 
}
166
 
 
167
 
const QDomElement & PGPTransaction::xml() const
168
 
{
169
 
        return d->e;
170
 
}
171
 
 
172
 
void PGPTransaction::setXml(const QDomElement &e)
173
 
{
174
 
        d->e = e;
175
 
}
176
 
 
177
 
Jid PGPTransaction::jid() const
178
 
{
179
 
        return d->j;
180
 
}
181
 
 
182
 
void PGPTransaction::setJid(const Jid &j)
183
 
{
184
 
        d->j = j;
185
 
}
186
 
 
187
150
//----------------------------------------------------------------------------
188
151
// BlockTransportPopup -- blocks popups on transport status changes
189
152
//----------------------------------------------------------------------------
260
223
        if ( j.user().isEmpty() ) // always show popups for transports
261
224
                return false;
262
225
 
263
 
        QObjectList *list = queryList("BlockTransportPopup");
264
 
        QObjectListIt it( *list );
265
 
 
266
 
        BlockTransportPopup *btp;
267
 
        for ( ; it.current(); ++it) {
268
 
                btp = (BlockTransportPopup *)it.current();
 
226
        QList<BlockTransportPopup *> list = findChildren<BlockTransportPopup *>();
 
227
        foreach(BlockTransportPopup* btp, list) {
269
228
                if ( j.host() == btp->jid().host() ) {
270
229
                        if ( online )
271
230
                                btp->userCounter++;
272
231
                        return true;
273
232
                }
274
233
        }
275
 
        delete list;
276
234
 
277
235
        return false;
278
236
}
280
238
//----------------------------------------------------------------------------
281
239
// PsiAccount
282
240
//----------------------------------------------------------------------------
283
 
struct item_dialog2
284
 
{
285
 
        QWidget *widget;
286
 
        QString className;
287
 
        Jid jid;
288
 
};
289
 
 
290
 
QMap<QString,QString> pgp_passphrases;
291
241
 
292
242
class PsiAccount::Private : public QObject
293
243
{
297
247
                account = parent;
298
248
        }
299
249
 
 
250
        PsiContactList* contactList;
300
251
        PsiCon *psi;
301
252
        PsiAccount *account;
 
253
        PsiOptions *options;
302
254
        Client *client;
303
255
        ContactProfile *cp;
304
256
        UserAccount acc, accnext;
305
257
        Jid jid, nextJid;
306
258
        Status loginStatus;
307
 
        QPtrList<item_dialog2> dialogList;
 
259
        bool loginWithPriority;
308
260
        EventQueue *eventQueue;
309
261
        XmlConsole *xmlConsole;
310
262
        UserList userList;
312
264
        int lastIdle;
313
265
        Status lastStatus, origStatus;
314
266
        bool nickFromVCard;
315
 
        QString cur_pgpSecretKeyID;
316
 
        QPtrList<Message> messageQueue;
 
267
        QCA::PGPKey cur_pgpSecretKey;
 
268
        QList<Message*> messageQueue;
317
269
        BlockTransportPopupList *blockTransportPopupList;
318
270
        int userCounter;
 
271
        PrivacyManager* privacyManager;
 
272
        CapsManager* capsManager;
 
273
        RosterItemExchangeTask* rosterItemExchangeTask;
 
274
        bool pepAvailable;
 
275
 
 
276
        // Tune
 
277
        Tune lastTune;
 
278
 
 
279
        // Ad-hoc commands
 
280
        AHCServerManager* ahcManager;
 
281
        RCSetStatusServer* rcSetStatusServer;
 
282
        RCSetOptionsServer* rcSetOptionsServer;
 
283
        RCForwardServer* rcForwardServer;
319
284
 
320
285
        // Avatars
321
286
        AvatarFactory* avatarFactory;
322
287
 
323
 
        // pgp related
324
 
        PassphraseDlg *ppdlg;
325
 
        QGuardedPtr<OpenPGP::Request> ppreq;
326
 
 
327
 
        QPtrList<GCContact> gcbank;
 
288
        // Voice Call
 
289
        VoiceCaller* voiceCaller;
 
290
 
 
291
#ifdef GOOGLE_FT
 
292
        // Google file transfer manager
 
293
        GoogleFTManager* googleFTManager;
 
294
#endif
 
295
        
 
296
#ifdef WHITEBOARDING
 
297
        // Whiteboard
 
298
        WbManager* wbManager;
 
299
#endif
 
300
 
 
301
        // PubSub
 
302
        ServerInfoManager* serverInfoManager;
 
303
        PEPManager* pepManager;
 
304
 
 
305
        // Bookmarks
 
306
        BookmarkManager* bookmarkManager;
 
307
 
 
308
        // HttpAuth
 
309
        HttpAuthManager* httpAuthManager;
 
310
 
 
311
        QList<GCContact*> gcbank;
328
312
        QStringList groupchats;
329
313
 
330
314
        AdvancedConnector *conn;
331
315
        ClientStream *stream;
332
316
        QCA::TLS *tls;
333
317
        QCATLSHandler *tlsHandler;
334
 
        QPtrList<QCA::Cert> certList;
335
318
        bool usingSSL;
336
319
        bool doPopups;
337
320
 
365
348
        void setEnabled( bool e )
366
349
        {
367
350
                acc.opt_enabled = e;
368
 
                psi->enableAccount(account, e);
369
351
                cp->setEnabled(e);
370
352
                account->cpUpdate(self);
371
353
 
373
355
                account->enabledChanged();
374
356
                account->updatedAccount();
375
357
        }
 
358
 
 
359
private:
 
360
        struct item_dialog2
 
361
        {
 
362
                QWidget *widget;
 
363
                Jid jid;
 
364
        };
 
365
 
 
366
        QList<item_dialog2*> dialogList;
 
367
 
 
368
        bool compareJids(const Jid& j1, const Jid& j2, bool compareResource) const
 
369
        {
 
370
                return j1.compare(j2, compareResource);
 
371
        }
 
372
 
 
373
public:
 
374
        QWidget* findDialog(const QMetaObject& mo, const Jid& jid, bool compareResource) const
 
375
        {
 
376
                foreach(item_dialog2* i, dialogList) {
 
377
                        if (mo.cast(i->widget) && compareJids(i->jid, jid, compareResource))
 
378
                                return i->widget;
 
379
                }
 
380
                return 0;
 
381
        }
 
382
 
 
383
        void findDialogs(const QMetaObject& mo, const Jid& jid, bool compareResource, QList<void*>* list) const
 
384
        {
 
385
                foreach(item_dialog2* i, dialogList) {
 
386
                        if (mo.cast(i->widget) && compareJids(i->jid, jid, compareResource))
 
387
                                list->append(i->widget);
 
388
                }
 
389
        }
 
390
 
 
391
        void dialogRegister(QWidget* w, const Jid& jid)
 
392
        {
 
393
                connect(w, SIGNAL(destroyed(QObject*)), SLOT(forceDialogUnregister(QObject*)));
 
394
                item_dialog2 *i = new item_dialog2;
 
395
                i->widget = w;
 
396
                i->jid = jid;
 
397
                dialogList.append(i);
 
398
        }
 
399
 
 
400
        void dialogUnregister(QWidget* w)
 
401
        {
 
402
                foreach(item_dialog2 *i, dialogList) {
 
403
                        if (i->widget == w) {
 
404
                                dialogList.removeAll(i);
 
405
                                delete i;
 
406
                                return;
 
407
                        }
 
408
                }
 
409
        }
 
410
 
 
411
        void deleteDialogList()
 
412
        {
 
413
                while (!dialogList.isEmpty()) {
 
414
                        item_dialog2* i = dialogList.takeFirst();
 
415
                        ChatDlg* chat = qobject_cast<ChatDlg*>(i->widget);
 
416
                        if (chat) {
 
417
                                if (psi->isChatTabbed(chat)) {
 
418
                                        psi->getManagingTabs(chat)->close(chat);
 
419
                                }
 
420
                        }
 
421
                        delete i->widget;
 
422
                        delete i;
 
423
                }
 
424
        }
 
425
 
 
426
private slots:
 
427
        void forceDialogUnregister(QObject* obj)
 
428
        {
 
429
                dialogUnregister(static_cast<QWidget*>(obj));
 
430
        }
376
431
};
377
432
 
378
 
PsiAccount::PsiAccount(const UserAccount &acc, PsiCon *parent)
379
 
:QObject(0)
 
433
PsiAccount::PsiAccount(const UserAccount &acc, PsiContactList *parent)
 
434
:QObject(parent)
380
435
{
381
436
        d = new Private( this );
382
 
        d->psi = parent;
 
437
        d->contactList = parent;
 
438
        d->psi = parent->psi();
 
439
        d->options = PsiOptions::instance();
383
440
        d->client = 0;
384
441
        d->cp = 0;
385
442
        d->userCounter = 0;
386
 
 
387
 
#ifdef AVATARS
388
 
        d->avatarFactory = new AvatarFactory(this);
389
 
#endif
390
 
 
 
443
        d->avatarFactory = 0;
 
444
        d->voiceCaller = 0;
391
445
        d->blockTransportPopupList = new BlockTransportPopupList();
392
446
 
393
447
        d->doPopups = true;
399
453
        presenceSent = false;
400
454
 
401
455
        d->loginStatus = Status("", "");
 
456
        d->loginWithPriority = false;
402
457
        d->lastIdle = 0;
403
458
        d->lastStatus = Status("", "", 0, false);
404
459
 
405
 
        d->dialogList.setAutoDelete(true);
406
460
        d->eventQueue = new EventQueue(this);
407
461
        connect(d->eventQueue, SIGNAL(queueChanged()), SIGNAL(queueChanged()));
408
462
        connect(d->eventQueue, SIGNAL(queueChanged()), d, SLOT(queueChanged()));
412
466
        d->self.setSubscription(Subscription::Both);
413
467
        d->nickFromVCard = false;
414
468
 
415
 
#ifdef AVATARS
416
 
        d->self.setAvatarFactory(d->avatarFactory);
417
 
#endif
418
 
 
419
 
        d->messageQueue.setAutoDelete(true);
420
 
        d->ppdlg = 0;
421
 
        d->ppreq = 0;
422
 
 
423
 
        d->gcbank.setAutoDelete(true);
424
 
 
425
469
        // we need to copy groupState, because later initialization will depend on that
426
470
        d->acc.groupState = acc.groupState;
427
471
 
430
474
        d->tls = 0;
431
475
        d->tlsHandler = 0;
432
476
        d->stream = 0;
433
 
        d->certList.setAutoDelete(true);
434
477
        d->usingSSL = false;
435
478
 
436
479
        // create Jabber::Client
437
480
        d->client = new Client;
438
 
        d->client->setOSName(getOSName());
439
 
        d->client->setTimeZone(getTZString(), getTZOffset());
440
 
        d->client->setClientName(PROG_NAME);
441
 
        d->client->setClientVersion(PROG_VERSION);
 
481
        d->client->setOSName(SystemInfo::instance()->os());
 
482
        d->client->setTimeZone(SystemInfo::instance()->timezoneString(), SystemInfo::instance()->timezoneOffset());
 
483
        d->client->setClientName(ApplicationInfo::name());
 
484
        d->client->setClientVersion(ApplicationInfo::version());
 
485
        d->client->setCapsNode(ApplicationInfo::capsNode());
 
486
        d->client->setCapsVersion(ApplicationInfo::capsVersion());
 
487
        
 
488
        DiscoItem::Identity identity;
 
489
        identity.category = "client";
 
490
        identity.type = "pc";
 
491
        identity.name = ApplicationInfo::name();
 
492
        d->client->setIdentity(identity);
 
493
 
 
494
        QStringList features;
 
495
        features << "http://jabber.org/protocol/commands";
 
496
        features << "http://jabber.org/protocol/rosterx";
 
497
        features << "http://jabber.org/protocol/muc";
 
498
        features << "jabber:x:data";
 
499
        d->client->setFeatures(Features(features));
442
500
 
443
501
        d->client->setFileTransferEnabled(true);
 
502
        
 
503
        setSendChatState(option.messageEvents);
444
504
 
445
505
        //connect(d->client, SIGNAL(connected()), SLOT(client_connected()));
446
506
        //connect(d->client, SIGNAL(handshaken()), SLOT(client_handshaken()));
457
517
        connect(d->client, SIGNAL(resourceUnavailable(const Jid &, const Resource &)), SLOT(client_resourceUnavailable(const Jid &, const Resource &)));
458
518
        connect(d->client, SIGNAL(presenceError(const Jid &, int, const QString &)), SLOT(client_presenceError(const Jid &, int, const QString &)));
459
519
        connect(d->client, SIGNAL(messageReceived(const Message &)), SLOT(client_messageReceived(const Message &)));
460
 
        connect(d->client, SIGNAL(subscription(const Jid &, const QString &)), SLOT(client_subscription(const Jid &, const QString &)));
 
520
        connect(d->client, SIGNAL(subscription(const Jid &, const QString &, const QString&)), SLOT(client_subscription(const Jid &, const QString &, const QString&)));
461
521
        connect(d->client, SIGNAL(debugText(const QString &)), SLOT(client_debugText(const QString &)));
462
522
        connect(d->client, SIGNAL(groupChatJoined(const Jid &)), SLOT(client_groupChatJoined(const Jid &)));
463
523
        connect(d->client, SIGNAL(groupChatLeft(const Jid &)), SLOT(client_groupChatLeft(const Jid &)));
464
524
        connect(d->client, SIGNAL(groupChatPresence(const Jid &, const Status &)), SLOT(client_groupChatPresence(const Jid &, const Status &)));
465
525
        connect(d->client, SIGNAL(groupChatError(const Jid &, int, const QString &)), SLOT(client_groupChatError(const Jid &, int, const QString &)));
466
 
        connect(d->client, SIGNAL(incomingJidLink()), SLOT(client_incomingJidLink()));
467
526
        connect(d->client->fileTransferManager(), SIGNAL(incomingReady()), SLOT(client_incomingFileTransfer()));
 
527
        
 
528
        // Privacy manager
 
529
        d->privacyManager = new PrivacyManager(d->client->rootTask());
 
530
 
 
531
        // Caps manager
 
532
        d->capsManager = new CapsManager(d->client);
 
533
        d->capsManager->setEnabled(option.useCaps);
 
534
 
 
535
        // Roster item exchange task
 
536
        d->rosterItemExchangeTask = new RosterItemExchangeTask(d->client->rootTask());
 
537
        connect(d->rosterItemExchangeTask,SIGNAL(rosterItemExchange(const Jid&, const RosterExchangeItems&)),SLOT(actionRecvRosterExchange(const Jid&,const RosterExchangeItems&)));
468
538
 
469
539
        // contactprofile context
470
540
        d->cp = new ContactProfile(this, acc.name, d->psi->contactView());
471
541
        connect(d->cp, SIGNAL(actionDefault(const Jid &)),SLOT(actionDefault(const Jid &)));
472
542
        connect(d->cp, SIGNAL(actionRecvEvent(const Jid &)),SLOT(actionRecvEvent(const Jid &)));
473
543
        connect(d->cp, SIGNAL(actionSendMessage(const Jid &)),SLOT(actionSendMessage(const Jid &)));
474
 
        connect(d->cp, SIGNAL(actionSendMessage(const JidList &)),SLOT(actionSendMessage(const JidList &)));
 
544
        connect(d->cp, SIGNAL(actionSendMessage(const QList<XMPP::Jid> &)),SLOT(actionSendMessage(const QList<XMPP::Jid> &)));
475
545
        connect(d->cp, SIGNAL(actionSendUrl(const Jid &)),SLOT(actionSendUrl(const Jid &)));
476
546
        connect(d->cp, SIGNAL(actionRemove(const Jid &)),SLOT(actionRemove(const Jid &)));
477
547
        connect(d->cp, SIGNAL(actionRename(const Jid &, const QString &)),SLOT(actionRename(const Jid &, const QString &)));
479
549
        connect(d->cp, SIGNAL(actionHistory(const Jid &)),SLOT(actionHistory(const Jid &)));
480
550
        connect(d->cp, SIGNAL(actionOpenChat(const Jid &)),SLOT(actionOpenChat(const Jid &)));
481
551
        connect(d->cp, SIGNAL(actionOpenChatSpecific(const Jid &)),SLOT(actionOpenChatSpecific(const Jid &)));
 
552
#ifdef WHITEBOARDING
 
553
        connect(d->cp, SIGNAL(actionOpenWhiteboard(const Jid &)),SLOT(actionOpenWhiteboard(const Jid &)));
 
554
        connect(d->cp, SIGNAL(actionOpenWhiteboardSpecific(const Jid &)),SLOT(actionOpenWhiteboardSpecific(const Jid &)));
 
555
#endif
482
556
        connect(d->cp, SIGNAL(actionAgentSetStatus(const Jid &, Status &)),SLOT(actionAgentSetStatus(const Jid &, Status &)));
483
557
        connect(d->cp, SIGNAL(actionInfo(const Jid &)),SLOT(actionInfo(const Jid &)));
484
558
        connect(d->cp, SIGNAL(actionAuth(const Jid &)),SLOT(actionAuth(const Jid &)));
487
561
        connect(d->cp, SIGNAL(actionAdd(const Jid &)),SLOT(actionAdd(const Jid &)));
488
562
        connect(d->cp, SIGNAL(actionGroupAdd(const Jid &, const QString &)),SLOT(actionGroupAdd(const Jid &, const QString &)));
489
563
        connect(d->cp, SIGNAL(actionGroupRemove(const Jid &, const QString &)),SLOT(actionGroupRemove(const Jid &, const QString &)));
490
 
        connect(d->cp, SIGNAL(actionTest(const Jid &)),SLOT(actionTest(const Jid &)));
 
564
        connect(d->cp, SIGNAL(actionVoice(const Jid &)),SLOT(actionVoice(const Jid &)));
491
565
        connect(d->cp, SIGNAL(actionSendFile(const Jid &)),SLOT(actionSendFile(const Jid &)));
492
566
        connect(d->cp, SIGNAL(actionSendFiles(const Jid &, const QStringList&)),SLOT(actionSendFiles(const Jid &, const QStringList&)));
 
567
        connect(d->cp, SIGNAL(actionExecuteCommand(const Jid &, const QString&)),SLOT(actionExecuteCommand(const Jid &, const QString&)));
 
568
        connect(d->cp, SIGNAL(actionExecuteCommandSpecific(const Jid &, const QString&)),SLOT(actionExecuteCommandSpecific(const Jid &, const QString&)));
 
569
        connect(d->cp, SIGNAL(actionSetMood()),SLOT(actionSetMood()));
 
570
        connect(d->cp, SIGNAL(actionSetAvatar()),SLOT(actionSetAvatar()));
 
571
        connect(d->cp, SIGNAL(actionUnsetAvatar()),SLOT(actionUnsetAvatar()));
493
572
        connect(d->cp, SIGNAL(actionDisco(const Jid &, const QString &)),SLOT(actionDisco(const Jid &, const QString &)));
494
573
        connect(d->cp, SIGNAL(actionInvite(const Jid &, const QString &)),SLOT(actionInvite(const Jid &, const QString &)));
495
574
        connect(d->cp, SIGNAL(actionAssignKey(const Jid &)),SLOT(actionAssignKey(const Jid &)));
496
575
        connect(d->cp, SIGNAL(actionUnassignKey(const Jid &)),SLOT(actionUnassignKey(const Jid &)));
497
576
 
 
577
        // Initialize server info stuff
 
578
        d->serverInfoManager = new ServerInfoManager(d->client);
 
579
        connect(d->serverInfoManager,SIGNAL(featuresChanged()),SLOT(serverFeaturesChanged()));
 
580
        
 
581
        // Initialize PubSub stuff
 
582
        d->pepManager = new PEPManager(d->client, d->serverInfoManager);
 
583
        connect(d->pepManager,SIGNAL(itemPublished(const Jid&, const QString&, const PubSubItem&)),SLOT(itemPublished(const Jid&, const QString&, const PubSubItem&)));
 
584
        connect(d->pepManager,SIGNAL(itemRetracted(const Jid&, const QString&, const PubSubRetraction&)),SLOT(itemRetracted(const Jid&, const QString&, const PubSubRetraction&)));
 
585
        d->pepAvailable = false;
 
586
 
 
587
#ifdef WHITEBOARDING
 
588
         // Initialize Whiteboard manager
 
589
        d->wbManager = new WbManager(d->client, this);
 
590
#endif
 
591
 
 
592
        // Avatars
 
593
        d->avatarFactory = new AvatarFactory(this);
 
594
        d->self.setAvatarFactory(avatarFactory());
 
595
        
 
596
        // Bookmarks
 
597
        d->bookmarkManager = new BookmarkManager(d->client);
 
598
 
 
599
#ifdef USE_PEP
 
600
        // Tune Controller
 
601
        connect(d->psi->tuneController(), SIGNAL(stopped()), SLOT(tuneStopped()));
 
602
        connect(d->psi->tuneController(), SIGNAL(playing(const Tune&)),SLOT(tunePlaying(const Tune&)));
 
603
#endif
 
604
 
 
605
        // HttpAuth
 
606
        d->httpAuthManager = new HttpAuthManager(d->client->rootTask());
 
607
        connect(d->httpAuthManager, SIGNAL(confirmationRequest(const PsiHttpAuthRequest &)), SLOT(incomingHttpAuthRequest(const PsiHttpAuthRequest &)));
 
608
 
 
609
        // Initialize Adhoc Commands server
 
610
        d->ahcManager = new AHCServerManager(this);
 
611
        d->rcSetStatusServer = 0;
 
612
        d->rcSetOptionsServer = 0;
 
613
        d->rcForwardServer = 0;
 
614
        setRCEnabled(option.useRC);
 
615
 
 
616
        // Plugins
 
617
#ifdef PSI_PLUGINS
 
618
        PluginManager::instance()->addAccount(this, d->client);
 
619
#endif
 
620
 
 
621
        // HTML
 
622
        if(PsiOptions::instance()->getOption("options.html.chat.render").toBool())
 
623
                d->client->addExtension("html",Features("http://jabber.org/protocol/xhtml-im"));
 
624
        
498
625
        // restore cached roster
499
626
        for(Roster::ConstIterator it = acc.roster.begin(); it != acc.roster.end(); ++it)
500
627
                client_rosterItemUpdated(*it);
511
638
 
512
639
        setUserAccount(acc);
513
640
 
514
 
        d->psi->link(this);
 
641
        d->contactList->link(this);
515
642
        connect(d->psi, SIGNAL(emitOptionsUpdate()), SLOT(optionsUpdate()));
516
 
        connect(d->psi, SIGNAL(pgpToggled(bool)), SLOT(pgpToggled(bool)));
517
 
        connect(d->psi, SIGNAL(pgpKeysUpdated()), SLOT(pgpKeysUpdated()));
 
643
        //connect(d->psi, SIGNAL(pgpToggled(bool)), SLOT(pgpToggled(bool)));
 
644
        connect(&PGPUtil::instance(), SIGNAL(pgpKeysUpdated()), SLOT(pgpKeysUpdated()));
518
645
 
519
646
        d->psi->setToggles(d->acc.tog_offline, d->acc.tog_away, d->acc.tog_agents, d->acc.tog_hidden,d->acc.tog_self);
520
647
 
521
648
        d->setEnabled(d->acc.opt_enabled);
522
649
 
523
 
        // auto-login ?
524
 
        if(d->acc.opt_auto && d->acc.opt_enabled)
525
 
                setStatus(Status("", "", d->acc.priority));
526
 
 
 
650
        // Listen to the capabilities manager
 
651
        connect(capsManager(),SIGNAL(capsChanged(const Jid&)),SLOT(capsChanged(const Jid&)));
 
652
        
527
653
        //printf("PsiAccount: [%s] loaded\n", name().latin1());
528
654
        d->xmlConsole = new XmlConsole(this);
529
655
        if(option.xmlConsoleOnLogin && d->acc.opt_enabled) {
530
656
                this->showXmlConsole();
531
657
                d->xmlConsole->enable();
532
658
        }
533
 
 
 
659
        
 
660
        // Voice Calling
 
661
#ifdef HAVE_JINGLE
 
662
        d->voiceCaller = new JingleVoiceCaller(this);
 
663
#endif
 
664
        if (d->voiceCaller) {
 
665
                d->client->addExtension("voice-v1", Features(QString("http://www.google.com/xmpp/protocol/voice/v1")));
 
666
                connect(d->voiceCaller,SIGNAL(incoming(const Jid&)),SLOT(incomingVoiceCall(const Jid&)));
 
667
        }
 
668
 
 
669
#ifdef GOOGLE_FT
 
670
        d->googleFTManager = new GoogleFTManager(client());
 
671
        d->client->addExtension("share-v1", Features(QString("http://www.google.com/xmpp/protocol/share/v1")));
 
672
        connect(d->googleFTManager,SIGNAL(incomingFileTransfer(GoogleFileTransfer*)),SLOT(incomingGoogleFileTransfer(GoogleFileTransfer*)));
 
673
#endif
 
674
 
 
675
        // Extended presence
 
676
        if (d->options->getOption("options.extended-presence.notify").toBool()) {
 
677
                QStringList pepNodes;
 
678
                pepNodes += "http://jabber.org/protocol/mood+notify";
 
679
                pepNodes += "http://jabber.org/protocol/tune+notify";
 
680
                pepNodes += "http://jabber.org/protocol/physloc+notify";
 
681
                pepNodes += "http://jabber.org/protocol/geoloc+notify";
 
682
                pepNodes += "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata+notify";
 
683
                d->client->addExtension("ep-notify",Features(pepNodes));
 
684
        }
 
685
                
534
686
        // load event queue from disk
535
687
        QTimer::singleShot(0, d, SLOT(loadQueue()));
536
688
}
537
689
 
538
690
PsiAccount::~PsiAccount()
539
691
{
 
692
#ifdef __GNUC__
 
693
#warning "Uncomment these"
 
694
#endif
 
695
#ifdef PSI_PLUGINS
 
696
        // PluginManager::instance()->removeClient(this);
 
697
#endif
 
698
        // nuke all related dialogs
 
699
        deleteAllDialogs();
 
700
 
540
701
        logout(true);
541
702
        QString str = name();
542
703
 
543
 
        d->messageQueue.clear();
544
 
 
545
 
        // nuke all related dialogs
546
 
        deleteAllDialogs();
 
704
        while (!d->messageQueue.isEmpty())
 
705
                delete d->messageQueue.takeFirst();
547
706
 
548
707
        d->psi->ftdlg()->killTransfers(this);
549
708
 
 
709
        if (d->voiceCaller)
 
710
                delete d->voiceCaller;
 
711
        
 
712
        delete d->ahcManager;
550
713
        delete d->cp;
 
714
        delete d->privacyManager;
 
715
        delete d->capsManager;
 
716
        delete d->pepManager;
 
717
        delete d->serverInfoManager;
 
718
#ifdef WHITEBOARDING
 
719
        delete d->wbManager;
 
720
#endif
 
721
        delete d->bookmarkManager;
551
722
        delete d->client;
 
723
        delete d->httpAuthManager;
552
724
        cleanupStream();
553
725
        delete d->eventQueue;
 
726
        delete d->avatarFactory;
554
727
 
555
728
        delete d->blockTransportPopupList;
556
729
 
557
 
        d->psi->unlink(this);
 
730
        d->contactList->unlink(this);
558
731
        delete d;
559
732
 
560
733
        //printf("PsiAccount: [%s] unloaded\n", str.latin1());
572
745
        delete d->conn;
573
746
        d->conn = 0;
574
747
 
575
 
        d->certList.clear();
576
748
        d->usingSSL = false;
577
749
 
578
750
        d->localAddress = QHostAddress();
675
847
        return d->avatarFactory;
676
848
}
677
849
 
678
 
QString PsiAccount::pgpKey() const
679
 
{
680
 
        return d->cur_pgpSecretKeyID;
 
850
VoiceCaller* PsiAccount::voiceCaller() const
 
851
{
 
852
        return d->voiceCaller;
 
853
}
 
854
 
 
855
PrivacyManager* PsiAccount::privacyManager() const
 
856
{
 
857
        return d->privacyManager;
 
858
}
 
859
 
 
860
CapsManager* PsiAccount::capsManager() const
 
861
{
 
862
        return d->capsManager;
 
863
}
 
864
 
 
865
bool PsiAccount::hasPGP() const
 
866
{
 
867
        return !d->cur_pgpSecretKey.isNull();
681
868
}
682
869
 
683
870
QHostAddress *PsiAccount::localAddress() const
684
871
{
685
872
        QString s = d->localAddress.toString();
686
 
        if(s == "0.0.0.0")
 
873
        if (s.isEmpty() || s == "0.0.0.0")
687
874
                return 0;
688
875
        return &d->localAddress;
689
876
}
728
915
        if(!d->nickFromVCard)
729
916
                setNick(j.user());
730
917
 
731
 
        d->self.setPublicKeyID(d->acc.pgpSecretKeyID);
732
 
        if(d->psi->pgp()) {
733
 
                if(d->acc.pgpSecretKeyID != d->cur_pgpSecretKeyID && loggedIn()) {
734
 
                        d->cur_pgpSecretKeyID = d->acc.pgpSecretKeyID;
 
918
        QString pgpSecretKeyID = (d->acc.pgpSecretKey.isNull() ? "" : d->acc.pgpSecretKey.keyId());
 
919
        d->self.setPublicKeyID(pgpSecretKeyID);
 
920
        if(PGPUtil::instance().pgpAvailable()) {
 
921
                bool updateStatus = !PGPUtil::instance().equals(d->acc.pgpSecretKey, d->cur_pgpSecretKey) && loggedIn();
 
922
                d->cur_pgpSecretKey = d->acc.pgpSecretKey;
 
923
                pgpKeyChanged();
 
924
                if (updateStatus) {
735
925
                        d->loginStatus.setXSigned("");
736
926
                        setStatusDirect(d->loginStatus);
737
 
                        pgpKeyChanged();
738
927
                }
739
928
        }
740
929
 
758
947
 
759
948
QString PsiAccount::nameWithJid() const
760
949
{
761
 
        return (name() + " (" + jid().full() + ')');
762
 
}
763
 
 
764
 
static QCA::Cert readCertXml(const QDomElement &e)
765
 
{
766
 
        QCA::Cert cert;
767
 
        // there should be one child data tag
768
 
        QDomElement data = e.elementsByTagName("data").item(0).toElement();
769
 
        if(!data.isNull())
770
 
                cert.fromDER(Base64::stringToArray(data.text()));
771
 
        return cert;
772
 
}
773
 
 
774
 
static QPtrList<QCA::Cert> getRootCerts(const QStringList &stores)
775
 
{
776
 
        QPtrList<QCA::Cert> list;
777
 
 
778
 
        for(QStringList::ConstIterator dit = stores.begin(); dit != stores.end(); ++dit) {
779
 
                QDir dir(*dit);
780
 
                if(!dir.exists())
781
 
                        continue;
782
 
                dir.setNameFilter("*.xml");
783
 
                QStringList entries = dir.entryList();
784
 
                for(QStringList::ConstIterator it = entries.begin(); it != entries.end(); ++it) {
785
 
                        QFile f(dir.filePath(*it));
786
 
                        if(!f.open(IO_ReadOnly))
787
 
                                continue;
788
 
                        QDomDocument doc;
789
 
                        bool ok = doc.setContent(&f);
790
 
                        f.close();
791
 
                        if(!ok)
792
 
                                continue;
793
 
 
794
 
                        QDomElement base = doc.documentElement();
795
 
                        if(base.tagName() != "store")
796
 
                                continue;
797
 
                        QDomNodeList cl = base.elementsByTagName("certificate");
798
 
 
799
 
                        int num = 0;
800
 
                        for(int n = 0; n < (int)cl.count(); ++n) {
801
 
                                QCA::Cert *cert = new QCA::Cert(readCertXml(cl.item(n).toElement()));
802
 
                                if(cert->isNull()) {
803
 
                                        delete cert;
804
 
                                        continue;
805
 
                                }
806
 
 
807
 
                                ++num;
808
 
                                list.append(cert);
809
 
                        }
810
 
                }
811
 
        }
812
 
 
813
 
        return list;
 
950
        return (name() + " (" + JIDUtil::toString(jid(),true) + ')');
 
951
}
 
952
 
 
953
// Moved out of constructor to have all accounts loaded
 
954
// when we ask for passwords.
 
955
void PsiAccount::autoLogin()
 
956
{
 
957
        // auto-login ?
 
958
        if(d->acc.opt_auto && d->acc.opt_enabled)
 
959
                setStatus(Status("", "", d->acc.priority));
814
960
}
815
961
 
816
962
// logs on with the active account settings
819
965
        if(isActive() && !doReconnect)
820
966
                return;
821
967
 
822
 
        if(d->acc.opt_ssl && !QCA::isSupported(QCA::CAP_TLS)) {
823
 
                QMessageBox::information(0, tr("%1: SSL Error").arg(name()), tr("Cannot login: SSL is enabled but no SSL/TLS (plugin) support is available."));
 
968
        if((d->acc.ssl == UserAccount::SSL_Yes || d->acc.ssl == UserAccount::SSL_Legacy) && !QCA::isSupported("tls")) {
 
969
                QMessageBox::information(0, (d->psi->contactList()->enabledAccounts().count() > 1 ? QString("%1: ").arg(name()) : "") + tr("SSL Error"), tr("Cannot login: SSL is enabled but no SSL/TLS (plugin) support is available."));
824
970
                return;
825
971
        }
826
972
 
827
973
        d->jid = d->nextJid;
828
 
        if(d->psi->pgp()) {
829
 
                d->cur_pgpSecretKeyID = d->acc.pgpSecretKeyID;
830
 
                pgpKeyChanged();
831
 
        }
832
974
 
833
975
        v_isActive = true;
834
976
        isDisconnecting = false;
838
980
 
839
981
        stateChanged();
840
982
 
 
983
        bool useHost = false;
841
984
        QString host;
842
 
        int port;
 
985
        int port = -1;
843
986
        if(d->acc.opt_host) {
 
987
                useHost = true;
844
988
                host = d->acc.host;
 
989
                if (host.isEmpty()) {
 
990
                        host = d->jid.domain();
 
991
                }
845
992
                port = d->acc.port;
846
993
        }
847
 
        else {
848
 
                host = d->jid.host();
849
 
                if(d->acc.opt_ssl)
850
 
                        port = 5223;
851
 
                else
852
 
                        port = 5222;
853
 
        }
854
994
 
855
995
        AdvancedConnector::Proxy p;
856
996
        if(d->acc.proxy_index > 0) {
861
1001
                        p.setSocks(pi.settings.host, pi.settings.port);
862
1002
                else if(pi.type == "poll") { // HTTP Poll
863
1003
                        QUrl u = pi.settings.url;
864
 
                        if(u.query().isEmpty()) {
865
 
                                QString v = host + ':' + QString::number(port);
866
 
                                QUrl::encode(v);
867
 
                                u.setQuery(QString("server=") + v);
 
1004
                        if(u.queryItems().isEmpty()) {
 
1005
                                if (useHost)
 
1006
                                        u.addQueryItem("server",host + ':' + QString::number(port));
 
1007
                                else
 
1008
                                        u.addQueryItem("server",d->jid.host());
868
1009
                        }
869
1010
                        p.setHttpPoll(pi.settings.host, pi.settings.port, u.toString());
870
1011
                        p.setPollInterval(2);
876
1017
 
877
1018
        // stream
878
1019
        d->conn = new AdvancedConnector;
879
 
        if(d->acc.opt_ssl) {
880
 
                QStringList certDirs;
881
 
                certDirs += g.pathHome + "/certs";
882
 
                certDirs += g.pathBase + "/certs";
883
 
                d->certList = getRootCerts(certDirs);
884
 
 
 
1020
        if(d->acc.ssl != UserAccount::SSL_No && QCA::isSupported("tls")) {
885
1021
                d->tls = new QCA::TLS;
886
 
                d->tls->setCertificateStore(d->certList);
 
1022
                d->tls->setTrustedCertificates(CertUtil::allCertificates());
887
1023
                d->tlsHandler = new QCATLSHandler(d->tls);
 
1024
                d->tlsHandler->setXMPPCertCheck(true);
888
1025
                connect(d->tlsHandler, SIGNAL(tlsHandshaken()), SLOT(tls_handshaken()));
889
1026
        }
890
1027
        d->conn->setProxy(p);
891
 
        d->conn->setOptHostPort(host, port);
892
 
        d->conn->setOptSSL(d->acc.opt_ssl);
 
1028
        if (useHost) {
 
1029
                d->conn->setOptHostPort(host, port);
 
1030
                d->conn->setOptSSL(d->acc.ssl == UserAccount::SSL_Legacy);
 
1031
        }
 
1032
        else if (QCA::isSupported("tls")) {
 
1033
                d->conn->setOptProbe(d->acc.legacy_ssl_probe && d->acc.ssl != UserAccount::SSL_No);
 
1034
        }
893
1035
 
894
1036
        d->stream = new ClientStream(d->conn, d->tlsHandler);
895
 
        d->stream->setOldOnly(true);
896
 
        d->stream->setAllowPlain(d->acc.opt_plain);
 
1037
        d->stream->setRequireMutualAuth(d->acc.req_mutual_auth);
 
1038
        d->stream->setSSFRange(d->acc.security_level,256);
 
1039
        d->stream->setAllowPlain(d->acc.allow_plain);
 
1040
        d->stream->setCompress(d->acc.opt_compress);
 
1041
        d->stream->setLang(TranslationManager::instance()->currentXMLLanguage());
897
1042
        if(d->acc.opt_keepAlive)
898
1043
                d->stream->setNoopTime(55000);  // prevent NAT timeouts every minute
899
1044
        else
900
1045
                d->stream->setNoopTime(0);
901
1046
        connect(d->stream, SIGNAL(connected()), SLOT(cs_connected()));
902
 
        connect(d->stream, SIGNAL(securityLayerActivated(int)), SLOT(cs_securityLayerActivated()));
 
1047
        connect(d->stream, SIGNAL(securityLayerActivated(int)), SLOT(cs_securityLayerActivated(int)));
903
1048
        connect(d->stream, SIGNAL(needAuthParams(bool, bool, bool)), SLOT(cs_needAuthParams(bool, bool, bool)));
904
1049
        connect(d->stream, SIGNAL(authenticated()), SLOT(cs_authenticated()));
905
 
        connect(d->stream, SIGNAL(connectionClosed()), SLOT(cs_connectionClosed()));
 
1050
        connect(d->stream, SIGNAL(connectionClosed()), SLOT(cs_connectionClosed()), Qt::QueuedConnection);
906
1051
        connect(d->stream, SIGNAL(delayedCloseFinished()), SLOT(cs_delayedCloseFinished()));
907
1052
        connect(d->stream, SIGNAL(warning(int)), SLOT(cs_warning(int)));
908
 
        connect(d->stream, SIGNAL(error(int)), SLOT(cs_error(int)));
 
1053
        connect(d->stream, SIGNAL(error(int)), SLOT(cs_error(int)), Qt::QueuedConnection);
909
1054
 
910
 
        Jid j = d->jid.withResource(d->acc.resource);
 
1055
        Jid j = d->jid.withResource((d->acc.opt_automatic_resource ? localHostName() : d->acc.resource ));
911
1056
        d->client->connectToServer(d->stream, j);
912
1057
}
913
1058
 
921
1066
        doReconnect = false;
922
1067
 
923
1068
        if(loggedIn()) {
 
1069
                // Extended Presence
 
1070
                if (d->options->getOption("options.extended-presence.tune.publish").toBool() && !d->lastTune.isNull())
 
1071
                        publishTune(Tune());
 
1072
 
 
1073
                d->client->removeExtension("ep");
 
1074
                d->client->removeExtension("pep");
 
1075
                        
924
1076
                // send logout status
925
1077
                d->client->setPresence(s);
926
1078
        }
932
1084
        v_isActive = false;
933
1085
        stateChanged();
934
1086
 
935
 
        QTimer::singleShot(0, this, SLOT(disconnect()));
 
1087
        // Using 100msecs; See note on disconnect() 
 
1088
        QTimer::singleShot(100, this, SLOT(disconnect()));
936
1089
}
937
1090
 
938
1091
// skz note: I had to split logout() because server seem to need some time to store status
953
1106
 
954
1107
void PsiAccount::tls_handshaken()
955
1108
{
956
 
        QCA::Cert cert = d->tls->peerCertificate();
957
 
        int r = d->tls->certificateValidityResult();
 
1109
        QCA::Certificate cert = d->tls->peerCertificateChain().primary();
 
1110
        int r = d->tls->peerIdentityResult();
 
1111
        if (r == QCA::TLS::Valid && !d->tlsHandler->certMatchesHostname()) r = QCA::TLS::HostMismatch;
958
1112
        if(r != QCA::TLS::Valid && !d->acc.opt_ignoreSSLWarnings) {
959
 
                QString str = resultToString(r);
960
 
                while(1) {
961
 
                        int n = QMessageBox::warning(0,
962
 
                                tr("%1: Server Authentication").arg(name()),
963
 
                                tr("The %1 certificate failed the authenticity test.").arg(d->jid.host()) + '\n' + tr("Reason: %1").arg(str),
964
 
                                tr("&Details..."),
965
 
                                tr("Co&ntinue"),
966
 
                                tr("&Cancel"), 0, 2);
967
 
                        if(n == 0) {
968
 
                                SSLCertDlg::showCert(cert, r);
 
1113
                QCA::Validity validity =  d->tls->peerCertificateValidity();
 
1114
                QString str = CertUtil::resultToString(r,validity);
 
1115
                QMessageBox msgBox(QMessageBox::Warning,
 
1116
                        (d->psi->contactList()->enabledAccounts().count() > 1 ? QString("%1: ").arg(name()) : "") + tr("Server Authentication"),
 
1117
                        tr("The %1 certificate failed the authenticity test.").arg(d->jid.host()) + '\n' + tr("Reason: %1.").arg(str));
 
1118
                QPushButton *detailsButton = msgBox.addButton(tr("&Details..."), QMessageBox::ActionRole);
 
1119
                QPushButton *continueButton = msgBox.addButton(tr("Co&ntinue"), QMessageBox::AcceptRole);
 
1120
                QPushButton *cancelButton = msgBox.addButton(QMessageBox::Cancel);
 
1121
                msgBox.setDefaultButton(detailsButton);
 
1122
                msgBox.setResult(QDialog::Accepted);
 
1123
 
 
1124
                connect(this, SIGNAL(disconnected()), &msgBox, SLOT(reject()));
 
1125
                connect(this, SIGNAL(reconnecting()), &msgBox, SLOT(reject()));
 
1126
 
 
1127
                while (msgBox.result() != QDialog::Rejected) {
 
1128
                        msgBox.exec();
 
1129
                        if (msgBox.clickedButton() == detailsButton) {
 
1130
                                msgBox.setResult(QDialog::Accepted);
 
1131
                                SSLCertDlg::showCert(cert, r, validity);
969
1132
                        }
970
 
                        else if(n == 1) {
 
1133
                        else if (msgBox.clickedButton() == continueButton) {
971
1134
                                d->tlsHandler->continueAfterHandshake();
972
1135
                                break;
973
1136
                        }
974
 
                        else if(n == 2) {
 
1137
                        else if (msgBox.clickedButton() == cancelButton) {
975
1138
                                logout();
976
1139
                                break;
977
1140
                        }
 
1141
                        else {  // msgBox was hidden because connection was closed
 
1142
                                break;
 
1143
                        }
978
1144
                }
979
1145
        }
980
1146
        else
981
1147
                d->tlsHandler->continueAfterHandshake();
982
1148
}
983
1149
 
 
1150
void PsiAccount::showCert()
 
1151
{
 
1152
        if (!d->tls || !d->tls->isHandshaken()) return;
 
1153
        QCA::Certificate cert = d->tls->peerCertificateChain().primary();
 
1154
        int r = d->tls->peerIdentityResult();
 
1155
        if (r == QCA::TLS::Valid && !d->tlsHandler->certMatchesHostname()) r = QCA::TLS::HostMismatch;
 
1156
        QCA::Validity validity =  d->tls->peerCertificateValidity();
 
1157
        SSLCertDlg::showCert(cert, r, validity);
 
1158
}
 
1159
 
 
1160
 
984
1161
void PsiAccount::cs_connected()
985
1162
{
986
1163
        // get IP address
987
1164
        ByteStream *bs = d->conn->stream();
988
1165
        if(bs->inherits("BSocket") || bs->inherits("XMPP::BSocket")) {
989
 
//#if QT_VERSION >= 0x030300
990
1166
                d->localAddress = ((BSocket *)bs)->address();
991
 
/*#else
992
 
                int s = ((BSocket *)bs)->socket();
993
 
                struct sockaddr addr;
994
 
                socklen_t size = sizeof(struct sockaddr);
995
 
                if(!getsockname(s, &addr, &size)) {
996
 
                        Q_UINT32 ipv4addr;
997
 
                        struct sockaddr_in *in = (struct sockaddr_in *)&addr;
998
 
                        memcpy(&ipv4addr, &in->sin_addr.s_addr, 4);
999
 
                        ipv4addr = ntohl(ipv4addr);
1000
 
                        d->localAddress = QHostAddress(ipv4addr);
1001
 
                }
1002
 
#endif*/
1003
 
        }
1004
 
}
1005
 
 
1006
 
void PsiAccount::cs_securityLayerActivated()
1007
 
{
1008
 
        d->usingSSL = true;
1009
 
        stateChanged();
1010
 
}
1011
 
 
1012
 
void PsiAccount::cs_needAuthParams(bool, bool pass, bool)
1013
 
{
 
1167
        }
 
1168
}
 
1169
 
 
1170
void PsiAccount::cs_securityLayerActivated(int layer)
 
1171
{
 
1172
        if ((layer == ClientStream::LayerSASL) && (d->stream->saslSSF() <= 1)) {
 
1173
                 // integrity protected only
 
1174
        } else {
 
1175
                d->usingSSL = true;
 
1176
                stateChanged();
 
1177
        }
 
1178
}
 
1179
 
 
1180
void PsiAccount::cs_needAuthParams(bool user, bool pass, bool realm)
 
1181
{
 
1182
        if(user) {
 
1183
                if (d->acc.customAuth && !d->acc.authid.isEmpty())
 
1184
                        d->stream->setUsername(d->acc.authid);
 
1185
                else
 
1186
                        d->stream->setUsername(d->jid.user());
 
1187
    }
 
1188
        else if (d->acc.customAuth && !d->acc.authid.isEmpty())
 
1189
                qWarning("Custom authentication user not used");
 
1190
 
1014
1191
        if(pass)
1015
1192
                d->stream->setPassword(d->acc.pass);
 
1193
 
 
1194
        if (realm) {
 
1195
                if (d->acc.customAuth && !d->acc.realm.isEmpty()) {
 
1196
                        d->stream->setRealm(d->acc.realm);
 
1197
                }
 
1198
                else {
 
1199
                        d->stream->setRealm(d->jid.domain());
 
1200
                }
 
1201
        }
 
1202
        else if (d->acc.customAuth && !d->acc.realm.isEmpty()) 
 
1203
                qWarning("Custom authentication realm not used");
 
1204
        
 
1205
        if(d->acc.customAuth) 
 
1206
                d->stream->setAuthzid(d->jid.bare());
1016
1207
        d->stream->continueAfterParams();
1017
1208
}
1018
1209
 
1019
1210
void PsiAccount::cs_authenticated()
1020
1211
{
 
1212
        //printf("PsiAccount: [%s] authenticated\n", name().latin1());
1021
1213
        d->conn->changePollInterval(10); // for http poll, slow down after login
1022
1214
 
1023
 
        d->client->start(d->jid.host(), d->jid.user(), d->acc.pass, d->acc.resource);
1024
 
 
1025
 
        //printf("PsiAccount: [%s] authenticated\n", name().latin1());
 
1215
        // Update our jid (if necessary)
 
1216
        if (!d->stream->jid().isEmpty()) {
 
1217
                d->jid = d->stream->jid().bare();
 
1218
        }
 
1219
 
 
1220
        QString resource = (d->stream->jid().resource().isEmpty() ? ( d->acc.opt_automatic_resource ? localHostName() : d->acc.resource) : d->stream->jid().resource());
 
1221
 
 
1222
        d->client->start(d->jid.host(), d->jid.user(), d->acc.pass, resource);
 
1223
        if (!d->stream->old()) {
 
1224
                JT_Session *j = new JT_Session(d->client->rootTask());
 
1225
                connect(j,SIGNAL(finished()),SLOT(sessionStart_finished()));
 
1226
                j->go(true);
 
1227
        }
 
1228
        else {
 
1229
                sessionStarted();
 
1230
        }
 
1231
}
 
1232
 
 
1233
void PsiAccount::sessionStart_finished()
 
1234
{
 
1235
        JT_Session *j = (JT_Session*)sender();
 
1236
        if ( j->success() ) {
 
1237
                sessionStarted();
 
1238
        }
 
1239
        else {
 
1240
                cs_error(-1);
 
1241
        }
 
1242
}
 
1243
 
 
1244
 
 
1245
void PsiAccount::sessionStarted()
 
1246
{
 
1247
        if (d->voiceCaller)
 
1248
                d->voiceCaller->initialize();
1026
1249
 
1027
1250
        // flag roster for delete
1028
1251
        UserListIt it(d->userList);
1045
1268
        //printf("PsiAccount: [%s] connection closed\n", name().latin1());
1046
1269
}
1047
1270
 
1048
 
void PsiAccount::cs_warning(int)
 
1271
void PsiAccount::cs_warning(int w)
1049
1272
{
1050
 
        d->stream->continueAfterWarning();
 
1273
        if (w == ClientStream::WarnNoTLS && d->acc.ssl == UserAccount::SSL_Yes) {
 
1274
                d->client->close();
 
1275
                cleanupStream();
 
1276
                v_isActive = false;
 
1277
                stateChanged();
 
1278
                disconnected();
 
1279
 
 
1280
                QMessageBox* m = new QMessageBox(QMessageBox::Critical, (d->psi->contactList()->enabledAccounts().count() > 1 ? QString("%1: ").arg(name()) : "") + tr("Server Error"), tr("The server does not support TLS encryption."), QMessageBox::Ok, 0, Qt::WDestructiveClose);
 
1281
                m->setModal(true);
 
1282
                m->show();
 
1283
        }
 
1284
        else {
 
1285
                d->stream->continueAfterWarning();
 
1286
        }
1051
1287
}
1052
1288
 
1053
1289
void PsiAccount::getErrorInfo(int err, AdvancedConnector *conn, Stream *stream, QCATLSHandler *tlsHandler, QString *_str, bool *_reconn)
1068
1304
                reconn = true;
1069
1305
        }
1070
1306
        else if(err == XMPP::ClientStream::ErrStream) {
1071
 
                int x = stream->errorCondition();
 
1307
                int x;
1072
1308
                QString s;
1073
1309
                reconn = true;
 
1310
                if (stream) // Stream can apparently be gone if you disconnect in time
 
1311
                        x = stream->errorCondition();
 
1312
                else {
 
1313
                        x = XMPP::Stream::GenericStreamError;
 
1314
                        reconn = false;
 
1315
                }
 
1316
 
1074
1317
                if(x == XMPP::Stream::GenericStreamError)
1075
1318
                        s = tr("Generic stream error");
1076
1319
                else if(x == XMPP::ClientStream::Conflict) {
1139
1382
                        s = tr("Server rejected STARTTLS");
1140
1383
                else if(x == XMPP::ClientStream::TLSFail) {
1141
1384
                        int t = tlsHandler->tlsError();
1142
 
                        if(t == QCA::TLS::ErrHandshake)
 
1385
                        if(t == QCA::TLS::ErrorHandshake)
1143
1386
                                s = tr("TLS handshake error");
1144
1387
                        else
1145
1388
                                s = tr("Broken security layer (TLS)");
1152
1395
                if(x == XMPP::ClientStream::GenericAuthError)
1153
1396
                        s = tr("Unable to login");
1154
1397
                else if(x == XMPP::ClientStream::NoMech)
1155
 
                        s = tr("No appropriate mechanism available for given security settings");
 
1398
                        s = tr("No appropriate mechanism available for given security settings (e.g. SASL library too weak, or plaintext authentication not enabled)");
1156
1399
                else if(x == XMPP::ClientStream::BadProto)
1157
1400
                        s = tr("Bad server response");
1158
1401
                else if(x == XMPP::ClientStream::BadServ)
1187
1430
        QString str;
1188
1431
        bool reconn;
1189
1432
 
 
1433
        if (!isActive()) return; // all cleaned up already
 
1434
 
1190
1435
        getErrorInfo(err, d->conn, d->stream, d->tlsHandler, &str, &reconn);
1191
1436
 
1192
1437
        d->client->close();
1215
1460
        stateChanged();
1216
1461
        disconnected();
1217
1462
 
1218
 
        QMessageBox::critical(0, tr("%1: Server Error").arg(name()), tr("There was an error communicating with the Jabber server.\nDetails: %1").arg(str));
 
1463
        QMessageBox* m = new QMessageBox(QMessageBox::Critical, (d->psi->contactList()->enabledAccounts().count() > 1 ? QString("%1: ").arg(name()) : "") + tr("Server Error"), tr("There was an error communicating with the server.\nDetails: %1").arg(str), QMessageBox::Ok, 0, Qt::WDestructiveClose);
 
1464
        m->setModal(true);
 
1465
        m->show();
1219
1466
}
1220
1467
 
1221
1468
void PsiAccount::client_rosterRequestFinished(bool success, int, const QString &)
1244
1491
        }
1245
1492
 
1246
1493
        rosterDone = true;
1247
 
        setStatusDirect(d->loginStatus);
 
1494
 
 
1495
        // Get stored options
 
1496
        // FIXME: Should be an account-specific option
 
1497
        //if (PsiOptions::instance()->getOption("options.options-storage.load").toBool())
 
1498
        //      PsiOptions::instance()->load(d->client);
 
1499
 
 
1500
        setStatusDirect(d->loginStatus, d->loginWithPriority);
1248
1501
}
1249
1502
 
1250
1503
void PsiAccount::resolveContactName()
1258
1511
        }
1259
1512
}
1260
1513
 
 
1514
void PsiAccount::serverFeaturesChanged()
 
1515
{
 
1516
        setPEPAvailable(d->serverInfoManager->hasPEP());
 
1517
}
 
1518
 
 
1519
void PsiAccount::setPEPAvailable(bool b) 
 
1520
{
 
1521
        if (d->pepAvailable == b) 
 
1522
                return;
 
1523
 
 
1524
        d->pepAvailable = b;
 
1525
 
 
1526
#ifdef PEP
 
1527
        // Publish support
 
1528
        if (b && !d->client->extensions().contains("ep")) {
 
1529
                QStringList pepNodes;
 
1530
                pepNodes += "http://jabber.org/protocol/mood";
 
1531
                pepNodes += "http://jabber.org/protocol/tune";
 
1532
                pepNodes += "http://jabber.org/protocol/physloc";
 
1533
                pepNodes += "http://jabber.org/protocol/geoloc";
 
1534
                pepNodes += "http://www.xmpp.org/extensions/xep-0084.html#ns-data";
 
1535
                pepNodes += "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata";
 
1536
                d->client->addExtension("ep",Features(pepNodes));
 
1537
                setStatusActual(d->loginStatus);
 
1538
        }
 
1539
        else if (!b && d->client->extensions().contains("ep")) {
 
1540
                d->client->removeExtension("ep");
 
1541
                setStatusActual(d->loginStatus);
 
1542
        }
 
1543
 
 
1544
        // Publish current tune information
 
1545
        if (b && d->psi->tuneController() && d->options->getOption("options.extended-presence.tune.publish").toBool()) {
 
1546
                Tune current = d->psi->tuneController()->currentTune();
 
1547
                if (!current.isNull())
 
1548
                        publishTune(current);
 
1549
        }
 
1550
#endif
 
1551
}
 
1552
 
 
1553
void PsiAccount::getBookmarks_success(const QList<URLBookmark>&, const QList<ConferenceBookmark>& conferences)
 
1554
{
 
1555
        QObject::disconnect(d->bookmarkManager,SIGNAL(getBookmarks_success(const QList<URLBookmark>&, const QList<ConferenceBookmark>&)),this,SLOT(getBookmarks_success(const QList<URLBookmark>&, const QList<ConferenceBookmark>&)));
 
1556
 
 
1557
        foreach(ConferenceBookmark c, conferences) {
 
1558
                if (!findDialog<GCMainDlg*>(Jid(c.jid().userHost())) && c.autoJoin()) {
 
1559
                        QString nick = c.nick();
 
1560
                        if (nick.isEmpty())
 
1561
                                nick = d->jid.node();
 
1562
                        
 
1563
                        MUCJoinDlg *w = new MUCJoinDlg(psi(), this);
 
1564
                        w->le_host->setText(c.jid().domain());
 
1565
                        w->le_room->setText(c.jid().node());
 
1566
                        w->le_nick->setText(nick);
 
1567
                        w->le_pass->setText(c.password());
 
1568
                        w->show();
 
1569
                        w->doJoin();
 
1570
                }
 
1571
        }
 
1572
}
 
1573
 
 
1574
void PsiAccount::incomingHttpAuthRequest(const PsiHttpAuthRequest &req)
 
1575
{
 
1576
        HttpAuthEvent *e = new HttpAuthEvent(req, this);
 
1577
        handleEvent(e);
 
1578
}
 
1579
 
1261
1580
void PsiAccount::client_rosterItemAdded(const RosterItem &r)
1262
1581
{
1263
1582
        if ( r.isPush() && r.name().isEmpty() && option.autoResolveNicksOnAdd ) {
1264
1583
                // automatically resolve nickname from vCard, if newly added item doesn't have any
1265
 
                VCardFactory::getVCard(r.jid(), d->client->rootTask(), this, SLOT(resolveContactName()));
 
1584
                VCardFactory::instance()->getVCard(r.jid(), d->client->rootTask(), this, SLOT(resolveContactName()));
1266
1585
        }
1267
1586
}
1268
1587
 
1278
1597
                // we don't have it at all, so add it
1279
1598
                u = new UserListItem;
1280
1599
                u->setRosterItem(r);
1281
 
#ifdef AVATARS
1282
 
                u->setAvatarFactory(d->avatarFactory);
1283
 
#endif
 
1600
                u->setAvatarFactory(avatarFactory());
1284
1601
                d->userList.append(u);
1285
1602
        }
1286
1603
        u->setInList(true);
1310
1627
 
1311
1628
void PsiAccount::tryVerify(UserListItem *u, UserResource *ur)
1312
1629
{
1313
 
        if(d->psi->pgp())
 
1630
        if(PGPUtil::instance().pgpAvailable()) 
1314
1631
                verifyStatus(u->jid().withResource(ur->name()), ur->status());
1315
1632
}
1316
1633
 
 
1634
void PsiAccount::incomingVoiceCall(const Jid& j)
 
1635
{
 
1636
        VoiceCallDlg* vc = new VoiceCallDlg(j,voiceCaller());
 
1637
        vc->show();
 
1638
        vc->incoming();
 
1639
}
 
1640
 
1317
1641
void PsiAccount::client_resourceAvailable(const Jid &j, const Resource &r)
1318
1642
{
 
1643
        // Notification
1319
1644
        enum PopupType {
1320
1645
                PopupOnline = 0,
1321
1646
                PopupStatusChange = 1
1327
1652
 
1328
1653
        bool doSound = false;
1329
1654
        bool doPopup = false;
1330
 
        QPtrList<UserListItem> list = findRelavent(j);
1331
 
        QPtrListIterator<UserListItem> it(list);
1332
 
        for(UserListItem *u; (u = it.current()); ++it) {
 
1655
        foreach(UserListItem* u, findRelevant(j)) {
1333
1656
                bool doAnim = false;
1334
1657
                bool local = false;
1335
1658
                if(u->isSelf() && r.name() == d->client->resource())
1337
1660
 
1338
1661
                // add/update the resource
1339
1662
                QString oldStatus, oldKey;
1340
 
                UserResource *rp;
 
1663
                UserResource* rp;
1341
1664
                UserResourceList::Iterator rit = u->userResourceList().find(j.resource());
1342
1665
                bool found = (rit == u->userResourceList().end()) ? false: true;
1343
1666
                if(!found) {
1346
1669
                        UserResource ur(r);
1347
1670
                        //ur.setSecurityEnabled(true);
1348
1671
                        if(local)
1349
 
                                ur.setClient(PROG_NAME,PROG_VERSION,getOSName());
1350
 
                        rp = &(*u->userResourceList().append(ur));
 
1672
                                ur.setClient(ApplicationInfo::name(),ApplicationInfo::version(),SystemInfo::instance()->os());
 
1673
 
 
1674
                        u->userResourceList().append(ur);
 
1675
                        rp = &u->userResourceList().last();
1351
1676
 
1352
1677
                        if(notifyOnlineOk && !local) {
1353
1678
                                doAnim = true;
1356
1681
                                        doPopup = true;
1357
1682
                                }
1358
1683
                        }
1359
 
 
1360
 
                        if(!local && option.autoVersion && !status().isInvisible()) {
1361
 
                                // do a client-version request (too easy!)
1362
 
                                JT_ClientVersion *jcv = new JT_ClientVersion(d->client->rootTask());
1363
 
                                connect(jcv, SIGNAL(finished()), SLOT(slotClientVersionFinished()));
1364
 
                                jcv->get(j);
1365
 
                                jcv->go(true);
1366
 
                        }
1367
1684
                }
1368
1685
                else {
1369
1686
                        if ( !doPopup )
1399
1716
#endif
1400
1717
        if(notifyOnlineOk && doPopup && d->doPopups && !d->blockTransportPopupList->find(j, popupType == PopupOnline) && makeSTATUS(status()) != STATUS_DND ) {
1401
1718
                QString name;
1402
 
                UserListItem *u = findFirstRelavent(j);
 
1719
                UserListItem *u = findFirstRelevant(j);
1403
1720
 
1404
1721
                PsiPopup::PopupType pt = PsiPopup::AlertNone;
1405
1722
                if ( popupType == PopupOnline )
1417
1734
        }
1418
1735
        else if ( !notifyOnlineOk )
1419
1736
                d->userCounter++;
 
1737
                
 
1738
        // Update entity capabilities. 
 
1739
        // This has to happen after the userlist item has been created.
 
1740
        if (!r.status().capsNode().isEmpty()) {
 
1741
                capsManager()->updateCaps(j,r.status().capsNode(),r.status().capsVersion(),r.status().capsExt());
 
1742
 
 
1743
                // Update the client version
 
1744
                foreach(UserListItem* u, findRelevant(j)) {
 
1745
                        UserResourceList::Iterator rit = u->userResourceList().find(j.resource());
 
1746
                        if (rit != u->userResourceList().end()) {
 
1747
                                (*rit).setClient(capsManager()->clientName(j),capsManager()->clientVersion(j),"");
 
1748
                                cpUpdate(*u,(*rit).name());
 
1749
                        }
 
1750
                }
 
1751
        }
1420
1752
}
1421
1753
 
1422
1754
void PsiAccount::client_resourceUnavailable(const Jid &j, const Resource &r)
1427
1759
        if ( j.user().isEmpty() )
1428
1760
                new BlockTransportPopup(d->blockTransportPopupList, j);
1429
1761
 
1430
 
        QPtrList<UserListItem> list = findRelavent(j);
1431
 
        QPtrListIterator<UserListItem> it(list);
1432
 
        for(UserListItem *u; (u = it.current()); ++it) {
 
1762
        foreach(UserListItem* u, findRelevant(j)) {
1433
1763
                bool local = false;
1434
1764
                if(u->isSelf() && r.name() == d->client->resource())
1435
1765
                        local = true;
1465
1795
#endif
1466
1796
        if(doPopup && d->doPopups && !d->blockTransportPopupList->find(j) && makeSTATUS(status()) != STATUS_DND ) {
1467
1797
                QString name;
1468
 
                UserListItem *u = findFirstRelavent(j);
 
1798
                UserListItem *u = findFirstRelevant(j);
1469
1799
 
1470
1800
                if (option.ppOffline) {
1471
1801
                        PsiPopup *popup = new PsiPopup(PsiPopup::AlertOffline, this);
1479
1809
 
1480
1810
void PsiAccount::client_presenceError(const Jid &j, int, const QString &str)
1481
1811
{
1482
 
        QPtrList<UserListItem> list = findRelavent(j);
1483
 
        QPtrListIterator<UserListItem> it(list);
1484
 
        for(UserListItem *u; (u = it.current()); ++it) {
 
1812
        foreach(UserListItem *u, findRelevant(j)) {
1485
1813
                simulateContactOffline(u);
1486
1814
                u->setPresenceError(str);
1487
1815
                cpUpdate(*u, j.resource(), false);
1498
1826
        }
1499
1827
 
1500
1828
        // if the sender is already in the queue, then queue this message also
1501
 
        QPtrListIterator<Message> it(d->messageQueue);
1502
 
        for(Message *mi; (mi = it.current()); ++it) {
 
1829
        foreach(Message* mi, d->messageQueue) {
1503
1830
                if(mi->from().compare(_m.from())) {
1504
1831
                        Message *m = new Message(_m);
1505
1832
                        d->messageQueue.append(m);
1507
1834
                }
1508
1835
        }
1509
1836
 
 
1837
        // check to see if message was forwarded from another resource
 
1838
        if (jid().compare(_m.from(),false)) {
 
1839
                AddressList oFrom = _m.findAddresses(Address::OriginalFrom);
 
1840
                AddressList oTo = _m.findAddresses(Address::OriginalTo);
 
1841
                if ((oFrom.count() > 0) && (oTo.count() > 0)) {
 
1842
                        // might want to store current values in MessageEvent object
 
1843
                        // replace out the from and to addresses with the original addresses
 
1844
                        _m.setFrom(oFrom[0].jid());
 
1845
                        _m.setTo(oTo[0].jid());
 
1846
                }
 
1847
        }
 
1848
        
1510
1849
        // encrypted message?
1511
 
        if(!pgpKey().isEmpty() && !_m.xencrypted().isEmpty()) {
 
1850
        if(PGPUtil::instance().pgpAvailable() && !_m.xencrypted().isEmpty()) {
1512
1851
                Message *m = new Message(_m);
1513
1852
                d->messageQueue.append(m);
1514
1853
                processMessageQueue();
1520
1859
 
1521
1860
void PsiAccount::processIncomingMessage(const Message &_m)
1522
1861
{
1523
 
        // skip empty messages
1524
 
        if(_m.body().isEmpty() && _m.urlList().isEmpty() && _m.invite().isEmpty() && !_m.containsEvents())
 
1862
        // skip empty messages, but not if the message contains a data form
 
1863
        if(_m.body().isEmpty() && _m.urlList().isEmpty() && _m.invite().isEmpty() && !_m.containsEvents() && _m.chatState() == StateNone && _m.subject().isEmpty() && _m.rosterExchangeItems().isEmpty() && _m.mucInvites().isEmpty() &&  _m.getForm().fields().empty())
1525
1864
                return;
1526
1865
 
1527
1866
        // skip headlines?
1528
1867
        if(_m.type() == "headline" && option.ignoreHeadline)
1529
1868
                return;
1530
1869
 
1531
 
        //skip if on ignore list? KEVIN, must not forget
1532
 
 
1533
1870
        if(_m.type() == "groupchat") {
1534
 
                GCMainDlg *w = (GCMainDlg *)dialogFind("GCMainDlg", Jid(_m.from().userHost()));
 
1871
                GCMainDlg *w = findDialog<GCMainDlg*>(Jid(_m.from().userHost()));
1535
1872
                if(w)
1536
1873
                        w->message(_m);
1537
1874
                return;
1538
1875
        }
1539
1876
 
1540
1877
        // only toggle if not an invite or body is not empty
1541
 
        if(_m.invite().isEmpty() && !_m.body().isEmpty())
 
1878
        if(_m.invite().isEmpty() && !_m.body().isEmpty() && _m.mucInvites().isEmpty() && _m.rosterExchangeItems().isEmpty())
1542
1879
                toggleSecurity(_m.from(), _m.wasEncrypted());
1543
1880
 
1544
 
        UserListItem *u = findFirstRelavent(_m.from());
 
1881
        UserListItem *u = findFirstRelevant(_m.from());
1545
1882
        if(u) {
1546
1883
                if(_m.type() == "chat") u->setLastMessageType(1);
1547
1884
                else u->setLastMessageType(0);
1553
1890
        // (prior to 0.9, m.from() always contained a resource)
1554
1891
        Jid j;
1555
1892
        ChatDlg *c;
1556
 
        QPtrList<UserListItem> ul = findRelavent(m.from());
 
1893
        QList<UserListItem*> ul = findRelevant(m.from());
1557
1894
 
1558
1895
        // ignore events from non-roster JIDs?
1559
1896
        if (ul.isEmpty() && option.ignoreNonRoster)
1560
1897
        {
1561
1898
                if (option.excludeGroupChatsFromIgnore)
1562
1899
                {
1563
 
                        GCMainDlg *w = (GCMainDlg *)dialogFind("GCMainDlg", Jid(_m.from().userHost()));
 
1900
                        GCMainDlg *w = findDialog<GCMainDlg*>(Jid(_m.from().userHost()));
1564
1901
                        if(!w)
1565
1902
                        {
1566
1903
                                return;
1578
1915
        else
1579
1916
                j = ul.first()->jid();
1580
1917
 
1581
 
        c = (ChatDlg *)dialogFind("ChatDlg", j);
 
1918
        // Roster item exchange
 
1919
        if (!_m.rosterExchangeItems().isEmpty()) {
 
1920
                RosterExchangeEvent* ree = new RosterExchangeEvent(j,_m.rosterExchangeItems(), _m.body(), this);
 
1921
                handleEvent(ree);
 
1922
                return;
 
1923
        }
 
1924
 
 
1925
        c = findDialog<ChatDlg*>(j);
1582
1926
        if(!c)
1583
 
                c = (ChatDlg *)dialogFind("ChatDlg", m.from().full());
1584
 
 
1585
 
        if(m.type() == "error")
1586
 
                m.setBody(m.error().text + "\n------\n" + m.body());
 
1927
                c = findDialog<ChatDlg*>(m.from().full());
 
1928
 
 
1929
        if(m.type() == "error") {
 
1930
                Stanza::Error err = m.error();
 
1931
                QPair<QString, QString> desc = err.description();
 
1932
                QString msg = desc.first + ".\n" + desc.second;
 
1933
                if (!err.text.isEmpty())
 
1934
                        msg += "\n" + err.text;
 
1935
 
 
1936
                m.setBody(msg + "\n------\n" + m.body());
 
1937
        }
1587
1938
 
1588
1939
        // change the type?
1589
 
        if(m.type() != "headline" && m.invite().isEmpty()) {
 
1940
        if(m.type() != "headline" && m.invite().isEmpty() && m.mucInvites().isEmpty()) {
1590
1941
                if(option.incomingAs == 1)
1591
1942
                        m.setType("");
1592
1943
                else if(option.incomingAs == 2)
1596
1947
                                m.setType("chat");
1597
1948
                        else
1598
1949
                                m.setType("");
1599
 
                        }
 
1950
                }
1600
1951
        }
1601
1952
 
1602
1953
        // urls or subject on a chat message?  convert back to regular message
1608
1959
        handleEvent(me);
1609
1960
}
1610
1961
 
1611
 
void PsiAccount::client_subscription(const Jid &j, const QString &str)
 
1962
void PsiAccount::client_subscription(const Jid &j, const QString &str, const QString& nick)
1612
1963
{
1613
1964
        // if they remove our subscription, then we lost presence
1614
1965
        if(str == "unsubscribed") {
1619
1970
 
1620
1971
        AuthEvent *ae = new AuthEvent(j, str, this);
1621
1972
        ae->setTimeStamp(QDateTime::currentDateTime());
 
1973
        ae->setNick(nick);
1622
1974
        handleEvent(ae);
1623
1975
}
1624
1976
 
1628
1980
        //fflush(stdout);
1629
1981
}
1630
1982
 
1631
 
void PsiAccount::client_incomingJidLink()
 
1983
#ifdef GOOGLE_FT
 
1984
void PsiAccount::incomingGoogleFileTransfer(GoogleFileTransfer* ft)
1632
1985
{
1633
 
        JidLink *jl = d->client->jidLinkManager()->takeIncoming();
1634
 
        if(!jl)
1635
 
                return;
1636
 
        //if(link_test) {
1637
 
        //      printf("[%s] -- Incoming JidLink request from [%s]\n", name().latin1(), jl->peer().full().latin1());
1638
 
        //      JLTestDlg *w = new JLTestDlg(jl->peer(), jl, this);
1639
 
        //      w->show();
1640
 
        //}
1641
 
        //else
1642
 
                jl->deleteLater();
 
1986
        if (QMessageBox::information(0, tr("Incoming file"), QString(tr("Do you want to accept %1 (%2 kb) from %3?")).arg(ft->fileName()).arg((float) ft->fileSize() / 1000).arg(ft->peer().full()), QMessageBox::Yes,QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton) == QMessageBox::Yes) {
 
1987
                GoogleFileTransferProgressDialog* d = new GoogleFileTransferProgressDialog(ft);
 
1988
                d->show();
 
1989
                ft->accept();
 
1990
        }
 
1991
        else 
 
1992
                ft->reject();
1643
1993
}
 
1994
#endif
1644
1995
 
1645
1996
void PsiAccount::client_incomingFileTransfer()
1646
1997
{
1662
2013
{
1663
2014
        if(doReconnect) {
1664
2015
                //printf("PsiAccount: [%s] reconnecting...\n", name().latin1());
 
2016
                emit reconnecting();
1665
2017
                v_isActive = false;
1666
2018
                doReconnect = false;
1667
2019
                login();
1673
2025
        return d->loginStatus;
1674
2026
}
1675
2027
 
1676
 
void PsiAccount::setStatus(const Status &_s)
 
2028
void PsiAccount::setStatus(const Status &_s,  bool withPriority)
1677
2029
{
1678
2030
        // Block all transports' contacts' status change popups from popping
1679
2031
        {
1690
2042
        doReconnect = false;
1691
2043
 
1692
2044
        Status s = _s;
1693
 
        s.setPriority(d->acc.priority);
 
2045
        if (!withPriority)
 
2046
                s.setPriority(d->acc.priority);
1694
2047
 
1695
2048
        d->loginStatus = s;
 
2049
        d->loginWithPriority = withPriority;
1696
2050
 
1697
2051
        if(s.isAvailable()) {
1698
2052
                // if client is not active then attempt to login
1699
2053
                if(!isActive()) {
1700
2054
                        Jid j = d->jid;
1701
 
                        if(d->acc.resource.isEmpty() || !j.isValid()) {
 
2055
 
 
2056
                        if(!j.isValid()) {
1702
2057
                                QMessageBox::information(0, CAP(tr("Error")), tr("Unable to login.  Ensure your account information is filled out."));
1703
2058
                                modify();
1704
2059
                                return;
1707
2062
                                bool ok = false;
1708
2063
                                QString text = QInputDialog::getText(
1709
2064
                                        tr("Need Password"),
1710
 
                                        tr("Please enter the password for %1:").arg(j.full()),
 
2065
                                        ( d->psi->contactList()->enabledAccounts().count() > 1 ? 
 
2066
                                          tr("Please enter the password for %1:").arg(JIDUtil::toString(j,true))
 
2067
                                          : tr("Please enter your password:") ),
1711
2068
                                        QLineEdit::Password, QString::null, &ok, 0);
1712
2069
                                if(ok && !text.isEmpty())
1713
2070
                                        d->acc.pass = text;
1720
2077
                // change status
1721
2078
                else {
1722
2079
                        if(rosterDone)
1723
 
                                setStatusDirect(s);
 
2080
                                setStatusDirect(s, withPriority);
1724
2081
 
1725
2082
                        if(s.isInvisible()) {//&&Pass invis to transports KEVIN
1726
2083
                                //this is a nasty hack to let the transports know we're invisible, since they get an offline packet when we go invisible
1727
 
                                QPtrListIterator<UserListItem> it(d->userList);
1728
 
                                for(UserListItem *u; (u = it.current()); ++it) {
 
2084
                                foreach(UserListItem* u, d->userList) {
1729
2085
                                        if(u->isTransport()) {
1730
2086
                                                JT_Presence *j = new JT_Presence(d->client->rootTask());
1731
2087
                                                j->pres(u->jid(), s);
1741
2097
        }
1742
2098
}
1743
2099
 
1744
 
void PsiAccount::setStatusDirect(const Status &_s)
 
2100
void PsiAccount::setStatusDirect(const Status &_s, bool withPriority)
1745
2101
{
1746
2102
        Status s = _s;
1747
 
        s.setPriority(d->acc.priority);
 
2103
        if (!withPriority)
 
2104
                s.setPriority(d->acc.priority);
1748
2105
 
1749
2106
        //printf("setting status to [%s]\n", s.status().latin1());
1750
2107
 
1751
2108
        // using pgp?
1752
 
        if(d->psi->pgp() && !d->cur_pgpSecretKeyID.isEmpty()) {
 
2109
        if(!d->cur_pgpSecretKey.isNull()) {
1753
2110
                d->loginStatus = s;
1754
2111
 
1755
2112
                // sign presence
1766
2123
        }
1767
2124
}
1768
2125
 
1769
 
void PsiAccount::setStatusActual(const Status &s)
 
2126
void PsiAccount::setStatusActual(const Status &_s)
1770
2127
{
 
2128
        Status s = _s;
 
2129
 
 
2130
        // Add entity capabilities information
 
2131
        if (capsManager()->isEnabled()) {
 
2132
                s.setCapsNode(d->client->capsNode());
 
2133
                s.setCapsVersion(d->client->capsVersion());
 
2134
                s.setCapsExt(d->client->capsExt());
 
2135
        }
 
2136
 
 
2137
        // Set the status
1771
2138
        d->loginStatus = s;
1772
 
 
1773
2139
        d->client->setPresence(s);
1774
2140
        if(presenceSent) {
1775
2141
                stateChanged();
1779
2145
                stateChanged();
1780
2146
                QTimer::singleShot(15000, this, SLOT(enableNotifyOnline()));
1781
2147
 
1782
 
                const VCard *vcard = VCardFactory::vcard(d->jid);
 
2148
                // Get the bookmarks
 
2149
                if (PsiOptions::instance()->getOption("options.muc.bookmarks.auto-join").toBool()) {
 
2150
                        connect(d->bookmarkManager,SIGNAL(getBookmarks_success(const QList<URLBookmark>&, const QList<ConferenceBookmark>&)),SLOT(getBookmarks_success(const QList<URLBookmark>&, const QList<ConferenceBookmark>&)));
 
2151
                        d->bookmarkManager->getBookmarks();
 
2152
                }
 
2153
                
 
2154
                // Get the vcard
 
2155
                const VCard *vcard = VCardFactory::instance()->vcard(d->jid);
1783
2156
                if ( option.autoVCardOnLogin || !vcard || vcard->isEmpty() || vcard->nickName().isEmpty() )
1784
 
                        VCardFactory::getVCard(d->jid, d->client->rootTask(), this, SLOT(slotCheckVCard()));
 
2157
                        VCardFactory::instance()->getVCard(d->jid, d->client->rootTask(), this, SLOT(slotCheckVCard()));
1785
2158
                else {
1786
2159
                        d->nickFromVCard = true;
1787
2160
                        setNick( vcard->nickName() );
1789
2162
        }
1790
2163
}
1791
2164
 
 
2165
void PsiAccount::capsChanged(const Jid& j)
 
2166
{
 
2167
        if (!loggedIn())
 
2168
                return;
 
2169
 
 
2170
        QString name = capsManager()->clientName(j);
 
2171
        QString version = (name.isEmpty() ? QString() : capsManager()->clientVersion(j));
 
2172
 
 
2173
        foreach(UserListItem *u, findRelevant(j)) {
 
2174
                UserResourceList::Iterator rit = u->userResourceList().find(j.resource());
 
2175
                bool found = (rit == u->userResourceList().end()) ? false: true;
 
2176
                if(!found)
 
2177
                        continue;
 
2178
                (*rit).setClient(name,version,"");
 
2179
                cpUpdate(*u);
 
2180
        }
 
2181
}
 
2182
 
 
2183
void PsiAccount::tuneStopped()
 
2184
{
 
2185
        if (loggedIn() && d->options->getOption("options.extended-presence.tune.publish").toBool()) {
 
2186
                publishTune(Tune());
 
2187
        }
 
2188
}
 
2189
 
 
2190
void PsiAccount::tunePlaying(const Tune& tune)
 
2191
{
 
2192
        if (loggedIn() && d->options->getOption("options.extended-presence.tune.publish").toBool()) {
 
2193
                publishTune(tune);
 
2194
        }
 
2195
}
 
2196
 
 
2197
void PsiAccount::publishTune(const Tune& tune)
 
2198
{
 
2199
        QDomDocument* doc = d->client->rootTask()->doc();
 
2200
        QDomElement t = doc->createElement("tune");
 
2201
        t.setAttribute("xmlns", "http://jabber.org/protocol/tune");
 
2202
        if (!tune.artist().isEmpty())
 
2203
                t.appendChild(textTag(doc, "artist", tune.artist()));
 
2204
        if (!tune.name().isEmpty())
 
2205
                t.appendChild(textTag(doc, "title", tune.name()));
 
2206
        if (!tune.album().isEmpty())
 
2207
                t.appendChild(textTag(doc, "source", tune.album()));
 
2208
        if (!tune.track().isEmpty())
 
2209
                t.appendChild(textTag(doc, "track", tune.track()));
 
2210
        if (tune.time() != 0)
 
2211
                t.appendChild(textTag(doc, "length", QString::number(tune.time())));
 
2212
 
 
2213
        d->lastTune = tune;
 
2214
        d->pepManager->publish("http://jabber.org/protocol/tune",PubSubItem("current",t));
 
2215
}
 
2216
 
1792
2217
void PsiAccount::secondsIdle(int x)
1793
2218
{
1794
2219
        if(!loggedIn())
1797
2222
        int lastIdle = d->lastIdle;
1798
2223
        Status lastStatus = d->lastStatus;
1799
2224
 
1800
 
        Resource r = *(d->client->resourceList().find(d->client->resource()));
 
2225
        ResourceList::ConstIterator it = d->client->resourceList().find(d->client->resource());
 
2226
        if (it == d->client->resourceList().end())
 
2227
                return;
 
2228
 
 
2229
        Resource r = *it;
1801
2230
        Status ls = r.status();
1802
2231
 
1803
2232
        //must avoid status change when invisible KEVIN
1822
2251
                                logout();
1823
2252
                        }
1824
2253
                        else if(option.use_asXa && option.asXa > 0 && minutes >= option.asXa) {
1825
 
                                if(ls.show() != "xa" && lastStatus.show() != "xa") {
1826
 
                                        lastStatus = Status("xa", option.asMessage, d->acc.priority);
 
2254
                                if(ls.type() != XMPP::Status::XA && lastStatus.type() != XMPP::Status::XA) {
 
2255
                                        lastStatus = Status(XMPP::Status::XA, option.asMessage, d->acc.priority);
1827
2256
                                        if(!usingAutoStatus)
1828
2257
                                                d->origStatus = d->loginStatus;
1829
2258
                                        setStatusDirect(lastStatus);
1831
2260
                                }
1832
2261
                        }
1833
2262
                        else if(option.use_asAway && option.asAway > 0 && minutes >= option.asAway) {
1834
 
                                if(ls.show() != "away" && lastStatus.show() != "away") {
1835
 
                                        lastStatus = Status("away", option.asMessage, d->acc.priority);
 
2263
                                if(ls.type() != XMPP::Status::Away && lastStatus.type() != XMPP::Status::Away) {
 
2264
                                        lastStatus = Status(XMPP::Status::Away, option.asMessage, d->acc.priority);
1836
2265
                                        if(!usingAutoStatus)
1837
2266
                                                d->origStatus = d->loginStatus;
1838
2267
                                        setStatusDirect(lastStatus);
1865
2294
        d->psi->playSound(str);
1866
2295
}
1867
2296
 
1868
 
QWidget *PsiAccount::dialogFind(const char *className, const Jid &j)
1869
 
{
1870
 
        QPtrListIterator<item_dialog2> it(d->dialogList);
1871
 
        for(item_dialog2 *i; (i = it.current()); ++it) {
1872
 
                // does the classname and jid match?
1873
 
                if(i->className == className && i->jid.compare(j)) {
1874
 
                        return i->widget;
 
2297
QString PsiAccount::localHostName()
 
2298
{
 
2299
        QString hostname = QHostInfo::localHostName();
 
2300
        int i = hostname.indexOf('.');
 
2301
        if (i != -1)
 
2302
                return hostname.left(hostname.indexOf('.'));
 
2303
        else
 
2304
                return hostname;
 
2305
}
 
2306
 
 
2307
bool PsiAccount::validRosterExchangeItem(const RosterExchangeItem& item)
 
2308
{
 
2309
        if (item.action() == RosterExchangeItem::Add) {
 
2310
                return (d->client->roster().find(item.jid(),true) == d->client->roster().end());
 
2311
        }
 
2312
        else if (item.action() == RosterExchangeItem::Delete) {
 
2313
                LiveRoster::ConstIterator i = d->client->roster().find(item.jid(),true);
 
2314
                if (i == d->client->roster().end()) 
 
2315
                        return false;
 
2316
 
 
2317
                foreach(QString group, item.groups()) {
 
2318
                        if (!(*i).groups().contains(group))
 
2319
                                return false;
1875
2320
                }
1876
 
        }
1877
 
        return 0;
 
2321
                return true;
 
2322
        }
 
2323
        else if (item.action() == RosterExchangeItem::Modify) {
 
2324
                // TODO
 
2325
                return false;
 
2326
        }
 
2327
        return false;
 
2328
}
 
2329
 
 
2330
QWidget* PsiAccount::findDialog(const QMetaObject& mo, const Jid& jid, bool compareResource) const
 
2331
{
 
2332
        return d->findDialog(mo, jid, compareResource);
 
2333
}
 
2334
 
 
2335
void PsiAccount::findDialogs(const QMetaObject& mo, const Jid& jid, bool compareResource, QList<void*>* list) const
 
2336
{
 
2337
        d->findDialogs(mo, jid, compareResource, list);
1878
2338
}
1879
2339
 
1880
2340
void PsiAccount::dialogRegister(QWidget *w, const Jid &j)
1881
2341
{
1882
 
        item_dialog2 *i = new item_dialog2;
1883
 
        i->widget = w;
1884
 
        i->className = w->className();
1885
 
        i->jid = j;
1886
 
        d->dialogList.append(i);
 
2342
        d->dialogRegister(w, j);
1887
2343
}
1888
2344
 
1889
2345
void PsiAccount::dialogUnregister(QWidget *w)
1890
2346
{
1891
 
        QPtrListIterator<item_dialog2> it(d->dialogList);
1892
 
        for(item_dialog2 *i; (i = it.current()); ++it) {
1893
 
                if(i->widget == w) {
1894
 
                        d->dialogList.removeRef(i);
1895
 
                        return;
1896
 
                }
1897
 
        }
 
2347
        d->dialogUnregister(w);
1898
2348
}
1899
2349
 
1900
2350
void PsiAccount::deleteAllDialogs()
1901
2351
{
1902
 
        QPtrListIterator<item_dialog2> it(d->dialogList);
1903
 
        for(item_dialog2 *i; (i = it.current());)
1904
 
                delete i->widget;
1905
 
        d->dialogList.clear();
 
2352
        delete d->xmlConsole;
 
2353
        d->deleteDialogList();
1906
2354
}
1907
2355
 
1908
2356
bool PsiAccount::checkConnected(QWidget *par)
1917
2365
 
1918
2366
void PsiAccount::modify()
1919
2367
{
1920
 
        AccountModifyDlg *w = (AccountModifyDlg *)dialogFind("AccountModifyDlg");
 
2368
        AccountModifyDlg *w = findDialog<AccountModifyDlg*>();
1921
2369
        if(w)
1922
2370
                bringToFront(w);
1923
2371
        else {
1928
2376
 
1929
2377
void PsiAccount::changeVCard()
1930
2378
{
1931
 
        actionInfo(d->jid);
 
2379
        actionInfo(d->jid,false);
1932
2380
}
1933
2381
 
1934
2382
void PsiAccount::changePW()
1936
2384
        if(!checkConnected())
1937
2385
                return;
1938
2386
 
1939
 
        ChangePasswordDlg *w = (ChangePasswordDlg *)dialogFind("ChangePasswordDlg");
 
2387
        ChangePasswordDlg *w = findDialog<ChangePasswordDlg*>();
1940
2388
        if(w)
1941
2389
                bringToFront(w);
1942
2390
        else {
1955
2403
        if(!checkConnected())
1956
2404
                return;
1957
2405
 
1958
 
        AddUserDlg *w = (AddUserDlg *)dialogFind("AddUserDlg");
 
2406
        AddUserDlg *w = findDialog<AddUserDlg*>();
1959
2407
        if(w)
1960
2408
                bringToFront(w);
1961
2409
        else {
1964
2412
                for(UserListItem *u; (u = it.current()); ++it) {
1965
2413
                        if(u->isTransport()) {
1966
2414
                                services += u->jid().full();
1967
 
                                names += jidnick(u->jid().full(), u->name());
 
2415
                                names += JIDUtil::nickOrJid(u->name(), u->jid().full());
1968
2416
                        }
1969
 
                        const QStringList &groups = u->groups();
1970
 
                        if(groups.isEmpty())
1971
 
                                continue;
1972
 
                        for(QStringList::ConstIterator git = groups.begin(); git != groups.end(); ++git) {
1973
 
                                if(qstringlistmatch(gl, *git) == -1)
1974
 
                                        gl.append(*git);
 
2417
                        foreach(QString group, u->groups()) {
 
2418
                                if(!gl.contains(group)) 
 
2419
                                        gl.append(group);
1975
2420
                        }
1976
2421
                }
1977
2422
 
1978
2423
                w = new AddUserDlg(services, names, gl, this);
1979
 
                connect(w, SIGNAL(add(const Jid &, const QString &, const QStringList &, bool)), SLOT(dj_add(const Jid &, const QString &, const QStringList &, bool)));
 
2424
                connect(w, SIGNAL(add(const XMPP::Jid &, const QString &, const QStringList &, bool)), SLOT(dj_add(const XMPP::Jid &, const QString &, const QStringList &, bool)));
1980
2425
                w->show();
1981
2426
        }
1982
2427
}
2003
2448
                actionSearch(jid);
2004
2449
        else if ( f.canGroupchat() )
2005
2450
                actionJoin(jid);
 
2451
        else if ( f.canCommand() )
 
2452
                actionExecuteCommand(jid, node);
2006
2453
        else if ( f.canDisco() )
2007
2454
                actionDisco(jid, node);
2008
2455
        else if ( f.isGateway() )
2015
2462
        }
2016
2463
}
2017
2464
 
2018
 
void PsiAccount::actionJoin(const Jid &j)
 
2465
void PsiAccount::actionJoin(const Jid &j, const QString& password)
2019
2466
{
2020
 
        GCJoinDlg *w = new GCJoinDlg(psi(), this);
 
2467
        MUCJoinDlg *w = new MUCJoinDlg(psi(), this);
2021
2468
 
2022
2469
        w->le_host->setText ( j.host() );
2023
2470
        w->le_room->setText ( j.user() );
 
2471
        w->le_pass->setText (password);
2024
2472
 
2025
2473
        w->show();
2026
2474
}
2059
2507
                        client_resourceUnavailable(j, r);
2060
2508
                }
2061
2509
        }
2062
 
        else
2063
 
                cpUpdate(*u);
 
2510
        u->setLastUnavailableStatus(makeStatus(STATUS_OFFLINE,""));
 
2511
        u->setLastAvailable(QDateTime());
 
2512
        cpUpdate(*u);
2064
2513
}
2065
2514
 
2066
2515
void PsiAccount::simulateRosterOffline()
2082
2531
                }
2083
2532
        }
2084
2533
 
2085
 
        d->gcbank.clear();
 
2534
        while (!d->gcbank.isEmpty())
 
2535
                delete d->gcbank.takeFirst();
2086
2536
}
2087
2537
 
2088
2538
void PsiAccount::enableNotifyOnline()
2095
2545
                notifyOnlineOk = true;
2096
2546
}
2097
2547
 
2098
 
void PsiAccount::slotClientVersionFinished()
2099
 
{
2100
 
        JT_ClientVersion *j = (JT_ClientVersion *)sender();
2101
 
        if(j->success()) {
2102
 
                QPtrList<UserListItem> list = findRelavent(j->jid());
2103
 
                QPtrListIterator<UserListItem> it(list);
2104
 
                for(UserListItem *u; (u = it.current()); ++it) {
2105
 
                        UserResourceList::Iterator rit = u->userResourceList().find(j->jid().resource());
2106
 
                        bool found = (rit == u->userResourceList().end()) ? false: true;
2107
 
                        if(!found)
2108
 
                                continue;
2109
 
 
2110
 
                        (*rit).setClient(j->name(),j->version(),j->os());
2111
 
 
2112
 
                        cpUpdate(*u);
2113
 
                        /*if(u->isSelf()) {
2114
 
                                if(d->cp->self())
2115
 
                                        d->cp->updateSelf(*u);
2116
 
                        }
2117
 
                        else
2118
 
                                d->cp->updateEntry(*u);*/
2119
 
                }
2120
 
        }
2121
 
}
2122
 
 
2123
 
QPtrList<UserListItem> PsiAccount::findRelavent(const Jid &j) const
2124
 
{
2125
 
        QPtrList<UserListItem> list;
 
2548
 
 
2549
void PsiAccount::itemRetracted(const Jid& j, const QString& n, const PubSubRetraction& item)
 
2550
{
 
2551
        // User Tune
 
2552
        if (n == "http://jabber.org/protocol/tune") {
 
2553
                // Parse tune
 
2554
                foreach(UserListItem* u, findRelevant(j)) {
 
2555
                        // FIXME: try to find the right resource using JEP-33 'replyto'
 
2556
                        //UserResourceList::Iterator rit = u->userResourceList().find(<resource>);
 
2557
                        //bool found = (rit == u->userResourceList().end()) ? false: true;
 
2558
                        //if(found) 
 
2559
                        //      (*rit).setTune(tune);
 
2560
                        u->setTune(QString());
 
2561
                        cpUpdate(*u);
 
2562
                }
 
2563
        }
 
2564
        else if (n == "http://jabber.org/protocol/mood") {
 
2565
                foreach(UserListItem* u, findRelevant(j)) {
 
2566
                        u->setMood(Mood());
 
2567
                        cpUpdate(*u);
 
2568
                }
 
2569
        }
 
2570
        else if (n == "http://jabber.org/protocol/geoloc") {
 
2571
                // FIXME: try to find the right resource using JEP-33 'replyto'
 
2572
                // see tune case above
 
2573
                foreach(UserListItem* u, findRelevant(j)) {
 
2574
                        u->setGeoLocation(GeoLocation());
 
2575
                        cpUpdate(*u);
 
2576
                }
 
2577
        }
 
2578
        else if (n == "http://jabber.org/protocol/physloc") {
 
2579
                // FIXME: try to find the right resource using JEP-33 'replyto'
 
2580
                // see tune case above
 
2581
                foreach(UserListItem* u, findRelevant(j)) {
 
2582
                        u->setPhysicalLocation(PhysicalLocation());
 
2583
                        cpUpdate(*u);
 
2584
                }
 
2585
        }
 
2586
}
 
2587
 
 
2588
void PsiAccount::itemPublished(const Jid& j, const QString& n, const PubSubItem& item)
 
2589
{
 
2590
        // User Tune
 
2591
        if (n == "http://jabber.org/protocol/tune") {
 
2592
                // Parse tune
 
2593
                QDomElement element = item.payload();
 
2594
                QDomElement e;
 
2595
                QString tune;
 
2596
                bool found;
 
2597
 
 
2598
                e = findSubTag(element, "artist", &found);
 
2599
                if (found)
 
2600
                        tune += e.text() + " - ";
 
2601
                        
 
2602
                e = findSubTag(element, "title", &found);
 
2603
                if (found)
 
2604
                        tune += e.text();
 
2605
 
 
2606
                foreach(UserListItem* u, findRelevant(j)) {
 
2607
                        // FIXME: try to find the right resource using JEP-33 'replyto'
 
2608
                        //UserResourceList::Iterator rit = u->userResourceList().find(<resource>);
 
2609
                        //bool found = (rit == u->userResourceList().end()) ? false: true;
 
2610
                        //if(found) 
 
2611
                        //      (*rit).setTune(tune);
 
2612
                        u->setTune(tune);
 
2613
                        cpUpdate(*u);
 
2614
                }
 
2615
        }
 
2616
        else if (n == "http://jabber.org/protocol/mood") {
 
2617
                Mood mood(item.payload());
 
2618
                foreach(UserListItem* u, findRelevant(j)) {
 
2619
                        u->setMood(mood);
 
2620
                        cpUpdate(*u);
 
2621
                }
 
2622
        }
 
2623
        else if (n == "http://jabber.org/protocol/geoloc") {
 
2624
                // FIXME: try to find the right resource using JEP-33 'replyto'
 
2625
                // see tune case above
 
2626
                GeoLocation geoloc(item.payload());
 
2627
                foreach(UserListItem* u, findRelevant(j)) {
 
2628
                        u->setGeoLocation(geoloc);
 
2629
                        cpUpdate(*u);
 
2630
                }
 
2631
        }
 
2632
        else if (n == "http://jabber.org/protocol/physloc") {
 
2633
                // FIXME: try to find the right resource using JEP-33 'replyto'
 
2634
                // see tune case above
 
2635
                PhysicalLocation physloc(item.payload());
 
2636
                foreach(UserListItem* u, findRelevant(j)) {
 
2637
                        u->setPhysicalLocation(physloc);
 
2638
                        cpUpdate(*u);
 
2639
                }
 
2640
        }
 
2641
}
 
2642
 
 
2643
QList<UserListItem*> PsiAccount::findRelevant(const Jid &j) const
 
2644
{
 
2645
        QList<UserListItem*> list;
2126
2646
 
2127
2647
        // self?
2128
2648
        if(j.compare(d->self.jid(), false))
2129
2649
                list.append(&d->self);
2130
2650
        else {
2131
 
                QPtrListIterator<UserListItem> it(d->userList);
2132
 
                for(UserListItem *u; (u = it.current()); ++it) {
 
2651
                foreach(UserListItem* u, d->userList) {
2133
2652
                        if(!u->jid().compare(j, false))
2134
2653
                                continue;
2135
2654
 
2136
2655
                        if(!u->jid().resource().isEmpty()) {
2137
2656
                                if(u->jid().resource() != j.resource())
2138
2657
                                        continue;
 
2658
                        } else {
 
2659
                                // skip status changes from muc participants 
 
2660
                                // if the MUC somehow got into userList.
 
2661
                                if (!j.resource().isEmpty() && d->groupchats.contains(j.bare())) continue;
2139
2662
                        }
2140
2663
                        list.append(u);
2141
2664
                }
2144
2667
        return list;
2145
2668
}
2146
2669
 
2147
 
UserListItem *PsiAccount::findFirstRelavent(const Jid &j) const
 
2670
UserListItem *PsiAccount::findFirstRelevant(const Jid &j) const
2148
2671
{
2149
 
        QPtrList<UserListItem> list = findRelavent(j);
 
2672
        QList<UserListItem*> list = findRelevant(j);
2150
2673
        if(list.isEmpty())
2151
2674
                return 0;
2152
2675
        else
2171
2694
        d->cp->updateEntry(u);
2172
2695
 
2173
2696
        if(e) {
2174
 
                d->cp->setAlert(u.jid(), is->event2icon(e));
 
2697
                d->cp->setAlert(u.jid(), PsiIconset::instance()->event2icon(e));
2175
2698
        }
2176
2699
        else
2177
2700
                d->cp->clearAlert(u.jid());
2185
2708
        d->psi->updateContactGlobal(this, j);
2186
2709
}
2187
2710
 
2188
 
QLabel *PsiAccount::accountLabel(QWidget *par, bool simpleMode)
2189
 
{
2190
 
        AccountLabel *al = new AccountLabel(this, par, simpleMode);
2191
 
        return al;
2192
 
}
2193
 
 
2194
2711
EventDlg *PsiAccount::ensureEventDlg(const Jid &j)
2195
2712
{
2196
 
        EventDlg *w = (EventDlg *)dialogFind("EventDlg", j);
 
2713
        EventDlg *w = findDialog<EventDlg*>(j);
2197
2714
        if(!w) {
2198
2715
                w = new EventDlg(j, this, true);
2199
2716
                connect(w, SIGNAL(aReadNext(const Jid &)), SLOT(processReadNext(const Jid &)));
2201
2718
                connect(w, SIGNAL(aReply(const Jid &, const QString &, const QString &, const QString &)), SLOT(dj_composeMessage(const Jid &, const QString &, const QString &, const QString &)));
2202
2719
                connect(w, SIGNAL(aAuth(const Jid &)), SLOT(dj_addAuth(const Jid &)));
2203
2720
                connect(w, SIGNAL(aDeny(const Jid &)), SLOT(dj_deny(const Jid &)));
 
2721
                connect(w, SIGNAL(aHttpConfirm(const PsiHttpAuthRequest &)), SLOT(dj_confirmHttpAuth(const PsiHttpAuthRequest &)));
 
2722
                connect(w, SIGNAL(aHttpDeny(const PsiHttpAuthRequest &)), SLOT(dj_denyHttpAuth(const PsiHttpAuthRequest &)));
 
2723
                connect(w, SIGNAL(aRosterExchange(const RosterExchangeItems &)), SLOT(dj_rosterExchange(const RosterExchangeItems &)));
2204
2724
                connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate()));
2205
2725
                connect(this, SIGNAL(updateContact(const Jid &)), w, SLOT(updateContact(const Jid &)));
 
2726
                connect(w, SIGNAL(aFormSubmit(const XData&, const QString&, const Jid&)), SLOT(dj_formSubmit(const XData&, const QString&, const Jid&)));
 
2727
                connect(w, SIGNAL(aFormCancel(const XData&, const QString&, const Jid&)), SLOT(dj_formCancel(const XData&, const QString&, const Jid&)));
2206
2728
        }
2207
2729
 
2208
2730
        return w;
2210
2732
 
2211
2733
ChatDlg *PsiAccount::ensureChatDlg(const Jid &j)
2212
2734
{
2213
 
        ChatDlg *c = (ChatDlg *)dialogFind("ChatDlg", j);
 
2735
        ChatDlg *c = findDialog<ChatDlg*>(j);
2214
2736
        if(!c) {
2215
2737
                // create the chatbox
2216
2738
                c = new ChatDlg(j, this);
2224
2746
                connect(c, SIGNAL(aInfo(const Jid &)), SLOT(actionInfo(const Jid &)));
2225
2747
                connect(c, SIGNAL(aHistory(const Jid &)), SLOT(actionHistory(const Jid &)));
2226
2748
                connect(c, SIGNAL(aFile(const Jid &)), SLOT(actionSendFile(const Jid &)));
 
2749
                connect(c, SIGNAL(aVoice(const Jid &)), SLOT(actionVoice(const Jid &)));
2227
2750
                connect(d->psi, SIGNAL(emitOptionsUpdate()), c, SLOT(optionsUpdate()));
2228
2751
                connect(this, SIGNAL(updateContact(const Jid &, bool)), c, SLOT(updateContact(const Jid &, bool)));
2229
2752
        }
2243
2766
                        QPixmap p;
2244
2767
                        if(pp)
2245
2768
                                p = *pp;
2246
 
                        reparent_good(window, 0, false);
 
2769
#ifdef __GNUC__
 
2770
#warning "Removed reparenting call from qwextend"
 
2771
#endif
 
2772
                        //reparent_good(window, 0, false);
2247
2773
                        if(!p.isNull())
2248
2774
                                c->setIcon(p);
2249
2775
                }
2269
2795
                }
2270
2796
                else {
2271
2797
                        StatusSetDlg *w = new StatusSetDlg(this, makeStatus(x, ""));
2272
 
                        connect(w, SIGNAL(set(const Status &)), SLOT(setStatus(const Status &)));
 
2798
                        connect(w, SIGNAL(set(const XMPP::Status &, bool)), SLOT(setStatus(const XMPP::Status &, bool)));
2273
2799
                        w->show();
2274
2800
                }
2275
2801
        }
2276
2802
}
2277
2803
 
2278
 
void PsiAccount::actionTest(const Jid &j)
2279
 
{
2280
 
        UserListItem *u = find(j);
2281
 
        if(!u)
2282
 
                return;
2283
 
        Jid j2 = j;
2284
 
        if(j.resource().isEmpty()) {
2285
 
                if(u->isAvailable())
2286
 
                        j2.setResource((*u->userResourceList().priority()).name());
2287
 
        }
2288
 
 
2289
 
        //S5BConnection *c = new S5BConnection(d->client->s5bManager());
2290
 
        //c->connectToJid(j2, d->client->s5bManager()->genUniqueSID(j2));
2291
 
        JLTestDlg *w = new JLTestDlg(j2, this);
2292
 
        w->show();
2293
 
}
2294
 
 
2295
 
void PsiAccount::actionSendFile(const Jid &j)
2296
 
{
2297
 
        QStringList l;
2298
 
        actionSendFiles(j, l);
2299
 
}
2300
 
 
2301
 
void PsiAccount::actionSendFiles(const Jid &j, const QStringList& l)
 
2804
void PsiAccount::actionVoice(const Jid &j)
 
2805
{
 
2806
        Q_ASSERT(voiceCaller() != NULL);
 
2807
 
 
2808
        Jid jid;
 
2809
        if (j.resource().isEmpty()) {
 
2810
                bool found = false;
 
2811
                UserListItem *u = find(j);
 
2812
                if (u) {
 
2813
                        const UserResourceList &rl = u->userResourceList();
 
2814
                        for (UserResourceList::ConstIterator it = rl.begin(); it != rl.end() && !found; ++it) {
 
2815
                                if (capsManager()->features(j.withResource((*it).name())).canVoice()) {
 
2816
                                        jid = j.withResource((*it).name());
 
2817
                                        found = true;
 
2818
                                }
 
2819
                        }
 
2820
                }
 
2821
 
 
2822
                if (!found)
 
2823
                        return;
 
2824
        }
 
2825
        else {
 
2826
                jid = j;
 
2827
        }
 
2828
 
 
2829
        VoiceCallDlg* vc = new VoiceCallDlg(jid,voiceCaller());
 
2830
        vc->show();
 
2831
        vc->call();
 
2832
}
 
2833
 
 
2834
void PsiAccount::sendFiles(const Jid& j, const QStringList& l, bool direct)
2302
2835
{
2303
2836
        Jid j2 = j;
2304
2837
        if(j.resource().isEmpty()) {
2312
2845
        if (!l.isEmpty()) {
2313
2846
                for (QStringList::ConstIterator f = l.begin(); f != l.end(); ++f ) {
2314
2847
                        QStringList fl(*f);
2315
 
                        FileRequestDlg *w = new FileRequestDlg(j2, d->psi, this, fl);
 
2848
                        FileRequestDlg *w = new FileRequestDlg(j2, d->psi, this, fl, direct);
2316
2849
                        w->show();
2317
2850
                }
2318
2851
        }
2319
2852
        else {
2320
 
                FileRequestDlg *w = new FileRequestDlg(j2, d->psi, this, l);
2321
 
                w->show();
2322
 
        }
 
2853
                FileRequestDlg *w = new FileRequestDlg(j2, d->psi, this, l, direct);
 
2854
                w->show();
 
2855
        }
 
2856
}
 
2857
 
 
2858
void PsiAccount::actionSendFile(const Jid &j)
 
2859
{
 
2860
        QStringList l;
 
2861
        sendFiles(j,l);
 
2862
}
 
2863
 
 
2864
void PsiAccount::actionSendFiles(const Jid &j, const QStringList& l)
 
2865
{
 
2866
        sendFiles(j, l);
 
2867
}
 
2868
 
 
2869
void PsiAccount::actionExecuteCommand(const Jid& j, const QString& node)
 
2870
{
 
2871
        Jid j2 = j;
 
2872
        if(j.resource().isEmpty()) {
 
2873
                UserListItem *u = find(j);
 
2874
                if(u && u->isAvailable())
 
2875
                        j2.setResource((*u->userResourceList().priority()).name());
 
2876
        }
 
2877
 
 
2878
        actionExecuteCommandSpecific(j2, node);
 
2879
}
 
2880
 
 
2881
void PsiAccount::actionExecuteCommandSpecific(const Jid& j, const QString& node)
 
2882
{
 
2883
        if (node.isEmpty()) {
 
2884
                AHCommandDlg *w = new AHCommandDlg(this,j);
 
2885
                w->show();
 
2886
        }
 
2887
        else {
 
2888
                AHCommandDlg::executeCommand(d->client,j,node);
 
2889
        }
 
2890
}
 
2891
 
 
2892
void PsiAccount::actionSetMood()
 
2893
{
 
2894
        MoodDlg *w = new MoodDlg(this);
 
2895
        w->show();
 
2896
}
 
2897
 
 
2898
void PsiAccount::actionSetAvatar()
 
2899
{
 
2900
        while(1) {
 
2901
                if(option.lastPath.isEmpty())
 
2902
                        option.lastPath = QDir::homeDirPath();
 
2903
                QString str = QFileDialog::getOpenFileName(0,tr("Choose a file"),option.lastPath, tr("Images (*.png *.xpm *.jpg *.PNG *.XPM *.JPG)"));
 
2904
                if(!str.isEmpty()) {
 
2905
                        QFileInfo fi(str);
 
2906
                        if(!fi.exists()) {
 
2907
                                QMessageBox::critical(0, tr("Error"), tr("The file specified does not exist."));
 
2908
                                continue;
 
2909
                        }
 
2910
                        option.lastPath = fi.dirPath();
 
2911
                        avatarFactory()->setSelfAvatar(str);
 
2912
                }
 
2913
                break;
 
2914
        }
 
2915
}
 
2916
 
 
2917
void PsiAccount::actionUnsetAvatar()
 
2918
{
 
2919
        avatarFactory()->setSelfAvatar("");
2323
2920
}
2324
2921
 
2325
2922
void PsiAccount::actionDefault(const Jid &j)
2347
2944
        openNextEvent(*u);
2348
2945
}
2349
2946
 
 
2947
void PsiAccount::actionRecvRosterExchange(const Jid& j, const RosterExchangeItems& items)
 
2948
{
 
2949
        handleEvent(new RosterExchangeEvent(j,items,"", this));
 
2950
}
 
2951
 
2350
2952
void PsiAccount::actionSendMessage(const Jid &j)
2351
2953
{
2352
2954
        EventDlg *w = d->psi->createEventDlg(j.full(), this);
2353
2955
        w->show();
2354
2956
}
2355
2957
 
2356
 
void PsiAccount::actionSendMessage(const JidList &j)
 
2958
void PsiAccount::actionSendMessage(const QList<XMPP::Jid> &j)
2357
2959
{
2358
2960
        QString str;
2359
2961
        bool first = true;
2360
 
        for(QValueList<Jid>::ConstIterator it = j.begin(); it != j.end(); ++it) {
 
2962
        for(QList<Jid>::ConstIterator it = j.begin(); it != j.end(); ++it) {
2361
2963
                if(!first)
2362
2964
                        str += ", ";
2363
2965
                first = false;
2378
2980
 
2379
2981
void PsiAccount::actionRemove(const Jid &j)
2380
2982
{
2381
 
#ifdef AVATARS
2382
2983
        avatarFactory()->removeManualAvatar(j);
2383
 
#endif
2384
2984
        dj_remove(j);
2385
2985
}
2386
2986
 
2391
2991
 
2392
2992
void PsiAccount::actionGroupRename(const QString &oldname, const QString &newname)
2393
2993
{
2394
 
        UserListIt it(d->userList);
2395
 
        QPtrList<UserListItem> nu;
2396
 
        for(UserListItem *u; (u = it.current()); ++it) {
 
2994
        QList<UserListItem*> nu;
 
2995
        foreach(UserListItem* u, d->userList) {
2397
2996
                if(u->inGroup(oldname)) {
2398
2997
                        u->removeGroup(oldname);
2399
2998
                        u->addGroup(newname);
2405
3004
 
2406
3005
        if(!nu.isEmpty()) {
2407
3006
                JT_Roster *r = new JT_Roster(d->client->rootTask());
2408
 
 
2409
 
                QPtrListIterator<UserListItem> it(nu);
2410
 
                for(UserListItem *u; (u = it.current()); ++it)
 
3007
                foreach(UserListItem* u, nu) {
2411
3008
                        r->set(u->jid(), u->name(), u->groups());
 
3009
                }
2412
3010
 
2413
3011
                r->go(true);
2414
3012
        }
2416
3014
 
2417
3015
void PsiAccount::actionHistory(const Jid &j)
2418
3016
{
2419
 
        HistoryDlg *w = (HistoryDlg *)dialogFind("HistoryDlg", j);
 
3017
        HistoryDlg *w = findDialog<HistoryDlg*>(j);
2420
3018
        if(w)
2421
3019
                bringToFront(w);
2422
3020
        else {
2433
3031
        connect(w, SIGNAL(aReply(const Jid &, const QString &, const QString &, const QString &)), SLOT(dj_composeMessage(const Jid &, const QString &, const QString &, const QString &)));
2434
3032
        connect(w, SIGNAL(aAuth(const Jid &)), SLOT(dj_addAuth(const Jid &)));
2435
3033
        connect(w, SIGNAL(aDeny(const Jid &)), SLOT(dj_deny(const Jid &)));
 
3034
        connect(w, SIGNAL(aRosterExchange(const RosterExchangeItems &)), SLOT(dj_rosterExchange(const RosterExchangeItems &)));
2436
3035
        connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate()));
2437
3036
        connect(this, SIGNAL(updateContact(const Jid &)), w, SLOT(updateContact(const Jid &)));
2438
3037
        w->updateEvent(e);
2453
3052
                if(e) {
2454
3053
                        res = e->from().resource();
2455
3054
                        // if we have a bare chat, change to 'res'
2456
 
                        ChatDlg *c = (ChatDlg *)dialogFind("ChatDlg", j);
 
3055
                        ChatDlg *c = findDialog<ChatDlg*>(j);
2457
3056
                        if(c)
2458
3057
                                c->setJid(j.withResource(res));
2459
3058
                }
2460
3059
                // else, is there a priority chat window available?
2461
3060
                else*/ if(u->isAvailable()) {
2462
3061
                        QString pr = (*u->userResourceList().priority()).name();
2463
 
                        if(!pr.isEmpty() && dialogFind("ChatDlg", j.withResource(pr)))
 
3062
                        if(!pr.isEmpty() && findDialog<ChatDlg*>(j.withResource(pr)))
2464
3063
                                res = pr;
2465
3064
                }
2466
3065
                else {
2481
3080
        openChat(j);
2482
3081
}
2483
3082
 
 
3083
#ifdef WHITEBOARDING
 
3084
void PsiAccount::actionOpenWhiteboard(const Jid &j)
 
3085
{
 
3086
        UserListItem *u = find(j);
 
3087
        if(!u)
 
3088
                return;
 
3089
 
 
3090
        // if 'j' is bare, we might want to switch to a specific resource
 
3091
        QString res;
 
3092
        if(j.resource().isEmpty()) {
 
3093
                if(u->isAvailable()) {
 
3094
                        QString pr = (*u->userResourceList().priority()).name();
 
3095
                        if(!pr.isEmpty())
 
3096
                                res = pr;
 
3097
                }
 
3098
        }
 
3099
 
 
3100
        if(!res.isEmpty())
 
3101
        {
 
3102
                actionOpenWhiteboardSpecific(j.withResource(res));
 
3103
        }
 
3104
        else
 
3105
        {
 
3106
                actionOpenWhiteboardSpecific(j);
 
3107
        }
 
3108
}
 
3109
 
 
3110
/*! \brief Opens a whiteboard to \a target.
 
3111
 *  \a ownJid and \a groupChat should be specified in the case of a group chat session.
 
3112
 */
 
3113
 
 
3114
void PsiAccount::actionOpenWhiteboardSpecific(const Jid &target, Jid ownJid, bool groupChat)
 
3115
{
 
3116
        if(ownJid.isEmpty())
 
3117
                ownJid = jid();
 
3118
        d->wbManager->openWhiteboard(target, ownJid, groupChat);
 
3119
}
 
3120
#endif
 
3121
 
2484
3122
void PsiAccount::actionAgentSetStatus(const Jid &j, Status &s)
2485
3123
{
2486
3124
        if ( j.user().isEmpty() ) // add all transport popups to block list
2491
3129
        p->go(true);
2492
3130
}
2493
3131
 
2494
 
void PsiAccount::actionInfo(const Jid &_j)
 
3132
void PsiAccount::actionInfo(const Jid &_j, bool showStatusInfo)
2495
3133
{
2496
3134
        bool useCache = true;
2497
3135
        Jid j;
2503
3141
                j = _j.userHost();
2504
3142
        }
2505
3143
 
2506
 
        InfoDlg *w = (InfoDlg *)dialogFind("InfoDlg", j);
 
3144
        InfoDlg *w = findDialog<InfoDlg*>(j);
2507
3145
        if(w) {
2508
3146
                w->updateStatus();
 
3147
                w->setStatusVisibility(showStatusInfo);
2509
3148
                bringToFront(w);
2510
3149
        }
2511
3150
        else {
2512
 
                const VCard *vcard = VCardFactory::vcard(j);
 
3151
                const VCard *vcard = VCardFactory::instance()->vcard(j);
2513
3152
 
2514
3153
                VCard tmp;
2515
3154
                if ( vcard )
2516
3155
                        tmp = *vcard;
2517
 
                w = new InfoDlg(j.compare(d->jid) ? InfoDlg::Self : InfoDlg::Contact, j, tmp, this, 0, 0, useCache);
 
3156
                w = new InfoDlg(j.compare(d->jid) ? InfoDlg::Self : InfoDlg::Contact, j, tmp, this, 0, useCache);
 
3157
 
 
3158
                w->setStatusVisibility(showStatusInfo);
2518
3159
                w->show();
2519
3160
 
2520
3161
                // automatically retrieve info if it doesn't exist
2578
3219
        if(!checkConnected())
2579
3220
                return;
2580
3221
 
2581
 
        RegistrationDlg *w = (RegistrationDlg *)dialogFind("RegistrationDlg", j);
 
3222
        RegistrationDlg *w = findDialog<RegistrationDlg*>(j);
2582
3223
        if(w)
2583
3224
                bringToFront(w);
2584
3225
        else {
2592
3233
        if(!checkConnected())
2593
3234
                return;
2594
3235
 
2595
 
        SearchDlg *w = (SearchDlg *)dialogFind("SearchDlg", j);
 
3236
        SearchDlg *w = findDialog<SearchDlg*>(j);
2596
3237
        if(w)
2597
3238
                bringToFront(w);
2598
3239
        else {
2599
3240
                w = new SearchDlg(j, this);
2600
 
                connect(w, SIGNAL(add(const Jid &, const QString &, const QStringList &, bool)), SLOT(dj_add(const Jid &, const QString &, const QStringList &, bool)));
 
3241
                connect(w, SIGNAL(add(const XMPP::Jid &, const QString &, const QStringList &, bool)), SLOT(dj_add(const XMPP::Jid &, const QString &, const QStringList &, bool)));
2601
3242
                connect(w, SIGNAL(aInfo(const Jid &)), SLOT(actionInfo(const Jid &)));
2602
3243
                w->show();
2603
3244
        }
2606
3247
void PsiAccount::actionInvite(const Jid &j, const QString &gc)
2607
3248
{
2608
3249
        Message m;
2609
 
        m.setTo(j);
2610
 
        m.setInvite(gc);
2611
 
        m.setBody(tr("You have been invited to %1").arg(gc));
 
3250
        Jid room(gc);
 
3251
        m.setTo(room);
 
3252
        m.addMUCInvite(MUCInvite(j));
 
3253
        
 
3254
        QString password = d->client->groupChatPassword(room.user(),room.host());
 
3255
        if (!password.isEmpty())
 
3256
                m.setMUCPassword(password);
2612
3257
        m.setTimeStamp(QDateTime::currentDateTime());
2613
3258
        dj_sendMessage(m);
2614
3259
}
2616
3261
void PsiAccount::actionAssignKey(const Jid &j)
2617
3262
{
2618
3263
        if(ensureKey(j)) {
2619
 
                UserListItem *u = findFirstRelavent(j);
 
3264
                UserListItem *u = findFirstRelevant(j);
2620
3265
                if(u)
2621
3266
                        cpUpdate(*u);
2622
3267
        }
2624
3269
 
2625
3270
void PsiAccount::actionUnassignKey(const Jid &j)
2626
3271
{
2627
 
        UserListItem *u = findFirstRelavent(j);
 
3272
        UserListItem *u = findFirstRelevant(j);
2628
3273
        if(u) {
2629
3274
                u->setPublicKeyID("");
2630
3275
                cpUpdate(*u);
2633
3278
 
2634
3279
void PsiAccount::dj_sendMessage(const Message &m, bool log)
2635
3280
{
2636
 
        UserListItem *u = findFirstRelavent(m.to());
 
3281
        UserListItem *u = findFirstRelevant(m.to());
2637
3282
        Message nm = m;
2638
3283
 
2639
 
        if(option.incomingAs == 3) {
 
3284
        if(option.incomingAs == 3) {
2640
3285
                if(u) {
2641
3286
                        switch(u->lastMessageType()) {
2642
3287
                                case 0: nm.setType(""); break;
2645
3290
                }
2646
3291
        }
2647
3292
 
 
3293
        if (!nm.body().isEmpty()) {
 
3294
                UserListItem *u = findFirstRelevant(m.to());
 
3295
                if (!u || u->subscription().type() != Subscription::Both && u->subscription().type() != Subscription::From) {
 
3296
                        nm.setNick(nick());
 
3297
                }
 
3298
        }
 
3299
 
2648
3300
        d->client->sendMessage(nm);
2649
3301
 
2650
3302
        // only toggle if not an invite or body is not empty
2668
3320
 
2669
3321
        // auto close an open messagebox (if non-chat)
2670
3322
        if(m.type() != "chat" && !m.body().isEmpty()) {
2671
 
                UserListItem *u = findFirstRelavent(m.to());
 
3323
                UserListItem *u = findFirstRelevant(m.to());
2672
3324
                if(u) {
2673
 
                        EventDlg *e = (EventDlg *)dialogFind("EventDlg", u->jid());
 
3325
                        EventDlg *e = findDialog<EventDlg*>(u->jid());
2674
3326
                        if(e)
2675
3327
                                e->closeAfterReply();
2676
3328
                }
2681
3333
{
2682
3334
        EventDlg *w = d->psi->createEventDlg(jid.full(), this);
2683
3335
        if(!body.isEmpty())
2684
 
                w->setText(qstrquote(body));
 
3336
                w->setHtml(TextUtil::plain2rich(TextUtil::quote(body)));
2685
3337
 
2686
3338
        if(!subject.isEmpty() && subject.left(3) != "Re:")
2687
3339
                w->setSubject("Re: " + subject);
2701
3353
 
2702
3354
void PsiAccount::dj_addAuth(const Jid &j)
2703
3355
{
 
3356
        dj_addAuth(j,QString());
 
3357
}
 
3358
 
 
3359
 
 
3360
void PsiAccount::dj_addAuth(const Jid &j, const QString& nick)
 
3361
{
2704
3362
        QString name;
2705
3363
        QStringList groups;
2706
3364
        UserListItem *u = d->userList.find(j);
2708
3366
                name = u->name();
2709
3367
                groups = u->groups();
2710
3368
        }
 
3369
        else if (!nick.isEmpty()){
 
3370
                name = nick;
 
3371
        }
2711
3372
 
2712
3373
        dj_add(j, name, groups, true);
2713
3374
        dj_auth(j);
2714
3375
}
2715
3376
 
2716
 
void PsiAccount::dj_add(const Jid &j, const QString &name, const QStringList &groups, bool authReq)
 
3377
void PsiAccount::dj_confirmHttpAuth(const PsiHttpAuthRequest &req)
 
3378
{
 
3379
        d->httpAuthManager->confirm(req);
 
3380
}
 
3381
 
 
3382
void PsiAccount::dj_denyHttpAuth(const PsiHttpAuthRequest &req)
 
3383
{
 
3384
        d->httpAuthManager->deny(req);
 
3385
}
 
3386
 
 
3387
void PsiAccount::dj_formSubmit(const XData& data, const QString& thread, const Jid& jid)
 
3388
{
 
3389
        Message m;
 
3390
 
 
3391
        m.setTo(jid);
 
3392
        m.setThread(thread, true);
 
3393
        m.setForm(data);
 
3394
        
 
3395
        d->client->sendMessage(m);
 
3396
}
 
3397
 
 
3398
void PsiAccount::dj_formCancel(const XData& data, const QString& thread, const Jid& jid)
 
3399
{
 
3400
        Message m;
 
3401
 
 
3402
        m.setTo(jid);
 
3403
        m.setThread(thread, true);
 
3404
        m.setForm(data);
 
3405
  
 
3406
        d->client->sendMessage(m);
 
3407
}
 
3408
 
 
3409
void PsiAccount::dj_add(const XMPP::Jid &j, const QString &name, const QStringList &groups, bool authReq)
2717
3410
{
2718
3411
        JT_Roster *r = new JT_Roster(d->client->rootTask());
2719
3412
        r->set(j, name, groups);
2725
3418
 
2726
3419
void PsiAccount::dj_authReq(const Jid &j)
2727
3420
{
2728
 
        d->client->sendSubscription(j, "subscribe");
 
3421
        d->client->sendSubscription(j, "subscribe", nick());
2729
3422
}
2730
3423
 
2731
3424
void PsiAccount::dj_auth(const Jid &j)
2799
3492
        }
2800
3493
}
2801
3494
 
 
3495
void PsiAccount::dj_rosterExchange(const RosterExchangeItems& items)
 
3496
{
 
3497
        foreach(RosterExchangeItem item, items) {
 
3498
                if (!validRosterExchangeItem(item))
 
3499
                        continue;
 
3500
                
 
3501
                if (item.action() == RosterExchangeItem::Add) {
 
3502
                        if (d->client->roster().find(item.jid(),true) == d->client->roster().end()) {
 
3503
                                dj_add(item.jid(),item.name(),item.groups(),true);
 
3504
                        }
 
3505
                }
 
3506
                else if (item.action() == RosterExchangeItem::Delete) {
 
3507
                        //dj_remove(item.jid());
 
3508
                }
 
3509
                else if (item.action() == RosterExchangeItem::Modify) {
 
3510
                        // TODO
 
3511
                }
 
3512
        }
 
3513
}
 
3514
 
2802
3515
// handle an incoming event
2803
3516
void PsiAccount::handleEvent(PsiEvent *e)
2804
3517
{
2811
3524
 
2812
3525
        // find someone to accept the event
2813
3526
        Jid j;
2814
 
        QPtrList<UserListItem> ul = findRelavent(e->from());
 
3527
        QList<UserListItem*> ul = findRelevant(e->from());
2815
3528
        if(ul.isEmpty()) {
2816
3529
                // if groupchat, then we want the full JID
2817
3530
                if(findGCContact(e->from())) {
2822
3535
                        Jid reg = bare.withResource("registered");
2823
3536
 
2824
3537
                        // see if we have a "registered" variant of the jid
2825
 
                        if(findFirstRelavent(reg)) {
 
3538
                        if(findFirstRelevant(reg)) {
2826
3539
                                j = reg;
2827
3540
                                e->setFrom(reg); // HACK!!
2828
3541
                        }
2838
3551
                j = ul.first()->jid();
2839
3552
        e->setJid(j);
2840
3553
 
 
3554
#ifdef PSI_PLUGINS
 
3555
        QDomElement eXml=e->toXml( new QDomDocument() );
 
3556
        if ( !PluginManager::instance()->processEvent( this, eXml ) )
 
3557
                return;
 
3558
        //FIXME(KIS): must now cause the event to be recreated from this xml or such. Horrid.   
 
3559
#endif
 
3560
        
2841
3561
        if(d->acc.opt_log) {
2842
3562
                if(e->type() == PsiEvent::Message || e->type() == PsiEvent::Auth) {
2843
3563
                        // don't log private messages
2851
3571
                const Message &m = me->message();
2852
3572
 
2853
3573
                // Pass message events to chat window
2854
 
                if (m.containsEvents() && m.body().isEmpty()) {
 
3574
                if ((m.containsEvents() || m.chatState() != StateNone) && m.body().isEmpty()) {
2855
3575
                        if (option.messageEvents) {
2856
 
                                ChatDlg *c = (ChatDlg *)dialogFind("ChatDlg", e->from());
 
3576
                                ChatDlg *c = findDialog<ChatDlg*>(e->from());
2857
3577
                                if(!c)
2858
 
                                        c = (ChatDlg *)dialogFind("ChatDlg", e->jid());
 
3578
                                        c = findDialog<ChatDlg*>(e->jid());
2859
3579
                                if (c)
2860
3580
                                        c->incomingMessage(m);
2861
3581
                        }
2864
3584
 
2865
3585
                // pass chat messages directly to a chat window if possible (and deal with sound)
2866
3586
                if(m.type() == "chat") {
2867
 
                        ChatDlg *c = (ChatDlg *)dialogFind("ChatDlg", e->from());
 
3587
                        ChatDlg *c = findDialog<ChatDlg*>(e->from());
2868
3588
                        if(!c)
2869
 
                                c = (ChatDlg *)dialogFind("ChatDlg", e->jid());
 
3589
                                c = findDialog<ChatDlg*>(e->jid());
2870
3590
 
2871
3591
                        if(c)
2872
3592
                                c->setJid(e->from());
2873
3593
 
2874
 
                        if ( !c || !c->isActiveWindow() || option.alertOpenChats ) {
2875
 
                                doPopup = true;
2876
 
                                popupType = PsiPopup::AlertChat;
2877
 
                        }
2878
 
 
2879
3594
                        //if the chat exists, and is either open in a tab,
2880
3595
                        //or in a window
2881
3596
                        if( c && ( d->psi->isChatTabbed(c) || !c->isHidden() ) ) {
2892
3607
                                bool firstChat = !d->eventQueue->hasChats(e->from());
2893
3608
                                playSound(option.onevent[firstChat ? eChat1: eChat2]);
2894
3609
                        }
 
3610
 
 
3611
                        if (putToQueue) {
 
3612
                                doPopup = true;
 
3613
                                popupType = PsiPopup::AlertChat;
 
3614
                        }
2895
3615
                } // /chat
2896
3616
                else if (m.type() == "headline") {
2897
3617
                        playSound(option.onevent[eHeadline]);
2912
3632
                        // FIXME: handle message errors
2913
3633
                        //msg.text = QString(tr("<big>[Error Message]</big><br>%1").arg(plain2rich(msg.text)));
2914
3634
                }
 
3635
#ifdef PSI_PLUGINS
 
3636
                UserListItem *ulItem=NULL;
 
3637
                if ( !ul.isEmpty() )
 
3638
                        ulItem=ul.first();
 
3639
                PluginManager::instance()->message(this,e->from(),ulItem,((MessageEvent*)e)->message().body());
 
3640
#endif
 
3641
        }
 
3642
        else if(e->type() == PsiEvent::HttpAuth) {
 
3643
                playSound(option.onevent[eSystem]);
2915
3644
        }
2916
3645
        else if(e->type() == PsiEvent::File) {
2917
3646
                playSound(option.onevent[eIncomingFT]);
2918
3647
                doPopup = true;
2919
3648
                popupType = PsiPopup::AlertFile;
2920
3649
        }
2921
 
        else {
 
3650
        else if(e->type() == PsiEvent::RosterExchange) {
 
3651
                RosterExchangeEvent* re = (RosterExchangeEvent*) e;
 
3652
                RosterExchangeItems items;
 
3653
                foreach(RosterExchangeItem item, re->rosterExchangeItems()) {
 
3654
                        if (validRosterExchangeItem(item))
 
3655
                                items += item;
 
3656
                }
 
3657
                if (items.isEmpty()) {
 
3658
                        delete e;
 
3659
                        return;
 
3660
                }
 
3661
                re->setRosterExchangeItems(items);
 
3662
                playSound(option.onevent[eSystem]);
 
3663
        }
 
3664
        else if (e->type() == PsiEvent::Auth) {
2922
3665
                playSound(option.onevent[eSystem]);
2923
3666
 
2924
3667
                AuthEvent *ae = (AuthEvent *)e;
2927
3670
                                // Check if we want to request auth as well
2928
3671
                                UserListItem *u = d->userList.find(ae->from());
2929
3672
                                if (!u || (u->subscription().type() != Subscription::Both && u->subscription().type() != Subscription::To)) {
2930
 
                                        dj_addAuth(ae->from());
 
3673
                                        dj_addAuth(ae->from(),ae->nick());
2931
3674
                                }
2932
3675
                                else {
2933
3676
                                        dj_auth(ae->from());
2943
3686
                        putToQueue = false;
2944
3687
                }
2945
3688
        }
 
3689
        else {
 
3690
                putToQueue = false;
 
3691
                doPopup = false;
 
3692
        }
2946
3693
 
2947
3694
#if !defined(Q_WS_MAC) || !defined(HAVE_GROWL)
2948
3695
        // Do the popup test earlier (to avoid needless JID lookups)
2950
3697
#endif
2951
3698
        if ( doPopup && d->doPopups && makeSTATUS(status()) != STATUS_DND ) {
2952
3699
                Resource r;
2953
 
                UserListItem *u = findFirstRelavent(j);
2954
 
                if ( u )
 
3700
                UserListItem *u = findFirstRelevant(j);
 
3701
                if ( u && u->priority() != u->userResourceList().end()) 
2955
3702
                        r = *(u->priority());
2956
3703
 
2957
3704
                if (((popupType == PsiPopup::AlertChat && option.ppChat) || (popupType == PsiPopup::AlertMessage && option.ppMessage) || (popupType == PsiPopup::AlertHeadline && option.ppHeadline) || (popupType == PsiPopup::AlertFile && option.ppFile)) && makeSTATUS(status()) != STATUS_DND) {
2979
3726
                u = new UserListItem;
2980
3727
                u->setJid(e->jid());
2981
3728
                u->setInList(false);
2982
 
#ifdef AVATARS
2983
 
                u->setAvatarFactory(d->avatarFactory);
2984
 
#endif
 
3729
                u->setAvatarFactory(avatarFactory());
 
3730
                QString nick;
 
3731
                if (e->type() == PsiEvent::Auth) {
 
3732
                        AuthEvent* ae = (AuthEvent*) e;
 
3733
                        nick = ae->nick();
 
3734
                }
 
3735
                else if (e->type() == PsiEvent::Message) {
 
3736
                        MessageEvent* me = (MessageEvent*) e;
 
3737
                        if (me->message().type()  != "error") 
 
3738
                                nick = me->nick();
 
3739
                }
 
3740
                u->setName(nick);
2985
3741
 
2986
3742
                // is it a private groupchat?
2987
3743
                Jid j = u->jid();
3021
3777
 
3022
3778
        bool noPopup = false;
3023
3779
        if(d->loginStatus.isAvailable()) {
3024
 
                QString show = d->loginStatus.show();
3025
 
                if(show == "dnd")
 
3780
                if(d->loginStatus.type() == XMPP::Status::DND)
3026
3781
                        noPopup = true;
3027
 
                else if((show == "away" || show == "xa") && option.noAwayPopup)
 
3782
                else if((d->loginStatus.type() == XMPP::Status::Away || d->loginStatus.type() == XMPP::Status::XA) && option.noAwayPopup)
3028
3783
                        noPopup = true;
3029
3784
        }
3030
3785
 
3084
3839
        openNextEvent(*u);
3085
3840
}
3086
3841
 
 
3842
int PsiAccount::forwardPendingEvents(const Jid &jid)
 
3843
{
 
3844
        QList<PsiEvent*> chatList;
 
3845
        d->eventQueue->extractMessages(&chatList);
 
3846
        foreach(PsiEvent* e, chatList) {
 
3847
                MessageEvent *me = (MessageEvent *) e;
 
3848
                Message m = me->message();
 
3849
 
 
3850
                AddressList oFrom = m.findAddresses(Address::OriginalFrom);
 
3851
                AddressList oTo = m.findAddresses(Address::OriginalTo);
 
3852
 
 
3853
                if (oFrom.count() == 0)
 
3854
                        m.addAddress(Address(Address::OriginalFrom, m.from()));
 
3855
                if (oTo.count() == 0)
 
3856
                        m.addAddress(Address(Address::OriginalTo, m.to()));
 
3857
 
 
3858
                m.setTimeStamp(m.timeStamp(), true);
 
3859
                m.setTo(jid);
 
3860
                m.setFrom("");
 
3861
 
 
3862
                d->client->sendMessage(m);
 
3863
 
 
3864
                // update the eventdlg
 
3865
                UserListItem *u = find(e->jid());
 
3866
                delete e;
 
3867
 
 
3868
                // update the contact
 
3869
                if(u)
 
3870
                        cpUpdate(*u);
 
3871
 
 
3872
                updateReadNext(u->jid());
 
3873
        }
 
3874
        return chatList.count();
 
3875
}
 
3876
 
3087
3877
void PsiAccount::updateReadNext(const Jid &j)
3088
3878
{
3089
3879
        // update eventdlg's read-next
3090
 
        EventDlg *w = (EventDlg *)dialogFind("EventDlg", j);
 
3880
        EventDlg *w = findDialog<EventDlg*>(j);
3091
3881
        if(w) {
3092
 
                Icon *nextAnim = 0;
 
3882
                PsiIcon *nextAnim = 0;
3093
3883
                int nextAmount = d->eventQueue->count(j);
3094
3884
                if(nextAmount > 0)
3095
 
                        nextAnim = is->event2icon(d->eventQueue->peek(j));
 
3885
                        nextAnim = PsiIconset::instance()->event2icon(d->eventQueue->peek(j));
3096
3886
                w->updateReadNext(nextAnim, nextAmount);
3097
3887
        }
3098
3888
 
3108
3898
 
3109
3899
void PsiAccount::processReadNext(const UserListItem &u)
3110
3900
{
3111
 
        EventDlg *w = (EventDlg *)dialogFind("EventDlg", u.jid());
 
3901
        EventDlg *w = findDialog<EventDlg*>(u.jid());
3112
3902
        if(!w) {
3113
3903
                // this should NEVER happen
3114
3904
                return;
3123
3913
        if(e->type() == PsiEvent::Message) {
3124
3914
                MessageEvent *me = (MessageEvent *)e;
3125
3915
                const Message &m = me->message();
3126
 
                if(m.type() == "chat")
 
3916
                if(m.type() == "chat" && m.getForm().fields().empty())
3127
3917
                        isChat = true;
3128
3918
        }
3129
3919
 
3151
3941
void PsiAccount::processChats(const Jid &j)
3152
3942
{
3153
3943
        //printf("processing chats for [%s]\n", j.full().latin1());
3154
 
        ChatDlg *c = (ChatDlg *)dialogFind("ChatDlg", j);
 
3944
        ChatDlg *c = findDialog<ChatDlg*>(j);
3155
3945
        if(!c)
3156
3946
                return;
3157
3947
 
3158
3948
        // extract the chats
3159
 
        QPtrList<PsiEvent> chatList;
 
3949
        QList<PsiEvent*> chatList;
3160
3950
        d->eventQueue->extractChats(&chatList, j);
3161
 
        chatList.setAutoDelete(true);
3162
3951
 
3163
3952
        if(!chatList.isEmpty()) {
3164
3953
                // dump the chats into the chat window, and remove the related cvlist alerts
3165
 
                QPtrListIterator<PsiEvent> it(chatList);
3166
 
                for(PsiEvent *e; (e = it.current()); ++it) {
 
3954
                foreach(PsiEvent *e, chatList) {
3167
3955
                        MessageEvent *me = (MessageEvent *)e;
3168
3956
                        const Message &m = me->message();
3169
3957
 
3172
3960
                                c->incomingMessage(m);
3173
3961
                }
3174
3962
 
3175
 
                QPtrList<UserListItem> ul = findRelavent(j);
 
3963
                QList<UserListItem*> ul = findRelevant(j);
3176
3964
                if(!ul.isEmpty()) {
3177
3965
                        UserListItem *u = ul.first();
3178
3966
                        cpUpdate(*u);
3179
3967
                        updateReadNext(u->jid());
3180
3968
                }
 
3969
 
 
3970
                while (!chatList.isEmpty())
 
3971
                        delete chatList.takeFirst();
3181
3972
        }
3182
3973
}
3183
3974
 
3184
3975
void PsiAccount::openChat(const Jid &j)
3185
3976
{
3186
3977
        ChatDlg *c = ensureChatDlg(j);
3187
 
        processChats(j);
 
3978
        QWidget *w = c;
3188
3979
        if ( option.useTabs )
3189
3980
        {
3190
3981
                if ( !d->psi->isChatTabbed(c) )
3194
3985
                }
3195
3986
                TabDlg* tabSet = d->psi->getManagingTabs(c);
3196
3987
                tabSet->selectTab(c);
 
3988
                w = tabSet;
3197
3989
        }
3198
 
        bringToFront(c);
 
3990
        processChats(j);
 
3991
        bringToFront(w);
3199
3992
}
3200
3993
 
3201
3994
void PsiAccount::chatMessagesRead(const Jid &j)
3231
4024
                d->groupchats += str;
3232
4025
 
3233
4026
        GCMainDlg *w = new GCMainDlg(this, j);
 
4027
        w->setPassword(d->client->groupChatPassword(j.user(),j.host()));
3234
4028
        connect(w, SIGNAL(aSend(const Message &)), SLOT(dj_sendMessage(const Message &)));
3235
4029
        connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate()));
3236
4030
        w->show();
3237
4031
}
3238
4032
 
3239
 
bool PsiAccount::groupChatJoin(const QString &host, const QString &room, const QString &nick)
 
4033
bool PsiAccount::groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString& pass, bool nohistory)
3240
4034
{
3241
 
        return d->client->groupChatJoin(host, room, nick);
 
4035
        if (nohistory) 
 
4036
                return d->client->groupChatJoin(host, room, nick, pass, 0);
 
4037
        else {
 
4038
                Status s = d->loginStatus;
 
4039
                s.setXSigned("");
 
4040
                return d->client->groupChatJoin(host, room, nick, pass, d->options->getOption("options.muc.context.maxchars").toInt(),d->options->getOption("options.muc.context.maxstanzas").toInt(),d->options->getOption("options.muc.context.seconds").toInt(),s);
 
4041
        }
3242
4042
}
3243
4043
 
3244
4044
void PsiAccount::groupChatChangeNick(const QString &host, const QString &room, const QString& nick, const Status &s)
3259
4059
 
3260
4060
GCContact *PsiAccount::findGCContact(const Jid &j)
3261
4061
{
3262
 
        QPtrListIterator<GCContact> it(d->gcbank);
3263
 
        for(GCContact *c; (c = it.current()); ++it) {
 
4062
        foreach(GCContact *c, d->gcbank) {
3264
4063
                if(c->jid.compare(j))
3265
4064
                        return c;
3266
4065
        }
3274
4073
 
3275
4074
void PsiAccount::client_groupChatJoined(const Jid &j)
3276
4075
{
3277
 
        d->client->groupChatSetStatus(j.host(), j.user(), d->loginStatus);
 
4076
        //d->client->groupChatSetStatus(j.host(), j.user(), d->loginStatus);
3278
4077
 
3279
 
        GCMainDlg *m = (GCMainDlg *)dialogFind("GCMainDlg", Jid(j.userHost()));
 
4078
        GCMainDlg *m = findDialog<GCMainDlg*>(Jid(j.userHost()));
3280
4079
        if(m) {
 
4080
                m->setPassword(d->client->groupChatPassword(j.user(),j.host()));
3281
4081
                m->joined();
3282
4082
                return;
3283
4083
        }
3284
 
        GCJoinDlg *w = (GCJoinDlg *)dialogFind("GCJoinDlg", j);
 
4084
        MUCJoinDlg *w = findDialog<MUCJoinDlg*>(j);
3285
4085
        if(!w)
3286
4086
                return;
3287
4087
        w->joined();
3292
4092
void PsiAccount::client_groupChatLeft(const Jid &j)
3293
4093
{
3294
4094
        // remove all associated groupchat contacts from the bank
3295
 
        QPtrListIterator<GCContact> it(d->gcbank);
3296
 
        for(GCContact *c; (c = it.current());) {
 
4095
        for(QList<GCContact*>::Iterator it = d->gcbank.begin(); it != d->gcbank.end(); ) {
 
4096
                GCContact *c = *it;
 
4097
 
3297
4098
                // contact from this room?
3298
4099
                if(!c->jid.compare(j, false)) {
3299
4100
                        ++it;
3306
4107
                }
3307
4108
 
3308
4109
                simulateContactOffline(u);
3309
 
                d->gcbank.removeRef(c);
 
4110
                it = d->gcbank.erase(it);
 
4111
                delete c;
3310
4112
        }
3311
4113
}
3312
4114
 
3313
4115
void PsiAccount::client_groupChatPresence(const Jid &j, const Status &s)
3314
4116
{
3315
 
        GCMainDlg *w = (GCMainDlg *)dialogFind("GCMainDlg", Jid(j.userHost()));
 
4117
        GCMainDlg *w = findDialog<GCMainDlg*>(Jid(j.userHost()));
3316
4118
        if(!w)
3317
4119
                return;
3318
4120
 
3326
4128
 
3327
4129
        w->presence(j.resource(), s);
3328
4130
 
3329
 
        // pass through the core presence handling also
 
4131
        // pass through the core presence handling also (so that roster items
 
4132
        // from groupchat contacts get a resource as well 
3330
4133
        Resource r;
3331
4134
        r.setName(j.resource());
3332
4135
        r.setStatus(s);
3338
4141
 
3339
4142
void PsiAccount::client_groupChatError(const Jid &j, int code, const QString &str)
3340
4143
{
3341
 
        GCMainDlg *w = (GCMainDlg *)dialogFind("GCMainDlg", Jid(j.userHost()));
 
4144
        GCMainDlg *w = findDialog<GCMainDlg*>(Jid(j.userHost()));
3342
4145
        if(w) {
3343
4146
                w->error(code, str);
3344
4147
        }
3345
4148
        else {
3346
 
                GCJoinDlg *w = (GCJoinDlg *)dialogFind("GCJoinDlg", j);
 
4149
                MUCJoinDlg *w = findDialog<MUCJoinDlg*>(j);
3347
4150
                if(w) {
3348
4151
                        w->error(code, str);
3349
4152
                }
3354
4157
{
3355
4158
        QStringList list;
3356
4159
 
3357
 
        QPtrListIterator<item_dialog2> it(d->dialogList);
3358
 
        for(item_dialog2 *i; (i = it.current()); ++it) {
3359
 
                if(i->className == "ChatDlg" && i->jid.compare(j, false))
3360
 
                        list += i->jid.resource();
3361
 
        }
 
4160
        foreach(ChatDlg* chat, findDialogs<ChatDlg*>(j, false))
 
4161
                list += chat->jid().resource();
3362
4162
 
3363
4163
        return list;
3364
4164
}
3396
4196
        return d->self.name();
3397
4197
}
3398
4198
 
3399
 
void PsiAccount::pgpToggled(bool b)
3400
 
{
3401
 
        QString oldkey = d->cur_pgpSecretKeyID;
3402
 
 
3403
 
        // gaining pgp?
3404
 
        if(b)
3405
 
                d->cur_pgpSecretKeyID = d->acc.pgpSecretKeyID;
3406
 
        // losing it?
3407
 
        else {
3408
 
                d->cur_pgpSecretKeyID = "";
3409
 
        }
3410
 
 
3411
 
        if(oldkey != d->cur_pgpSecretKeyID) {
3412
 
                pgpKeyChanged();
3413
 
                // resend status if online
3414
 
                if(loggedIn())
3415
 
                        setStatusDirect(d->loginStatus);
3416
 
        }
3417
 
}
 
4199
//void PsiAccount::pgpToggled(bool b)
 
4200
//{
 
4201
//      QCA::PGPKey oldkey = d->cur_pgpSecretKey;
 
4202
//
 
4203
//      // gaining pgp?
 
4204
//      if(b)
 
4205
//              d->cur_pgpSecretKey = d->acc.pgpSecretKey;
 
4206
//      // losing it?
 
4207
//      else {
 
4208
//              d->cur_pgpSecretKey = QCA::PGPKey();
 
4209
//      }
 
4210
//
 
4211
//      if(!PGPUtil::instance().equals(oldkey,d->cur_pgpSecretKey)) {
 
4212
//              pgpKeyChanged();
 
4213
//              // resend status if online
 
4214
//              if(loggedIn())
 
4215
//                      setStatusDirect(d->loginStatus);
 
4216
//      }
 
4217
//}
3418
4218
 
3419
4219
void PsiAccount::pgpKeysUpdated()
3420
4220
{
3421
 
        OpenPGP::KeyList list = d->psi->pgp()->publicKeys();
3422
 
 
3423
4221
        // are there any sigs that need verifying?
3424
 
        QPtrListIterator<UserListItem> it(d->userList);
3425
 
        for(UserListItem *u; (u = it.current()); ++it) {
 
4222
        foreach(UserListItem* u, d->userList) {
3426
4223
                UserResourceList &rl = u->userResourceList();
3427
4224
                for(UserResourceList::Iterator rit = rl.begin(); rit != rl.end(); ++rit) {
3428
4225
                        UserResource &r = *rit;
3429
 
                        if(!r.status().xsigned().isEmpty() && r.pgpVerifyStatus() == OpenPGP::VerifyNoKey) {
3430
 
                                bool haveKey = false;
3431
 
                                QString key = r.publicKeyID();
3432
 
                                for(OpenPGP::KeyList::ConstIterator kit = list.begin(); kit != list.end(); ++kit) {
3433
 
                                        if((*kit).keyID() == key) {
3434
 
                                                haveKey = true;
3435
 
                                                break;
3436
 
                                        }
3437
 
                                }
3438
 
                                if(haveKey)
 
4226
                        if(!r.status().xsigned().isEmpty() && r.pgpVerifyStatus() == QCA::SecureMessageSignature::NoKey) {
 
4227
                                QCA::KeyStoreEntry e = PGPUtil::instance().getPublicKeyStoreEntry(r.publicKeyID());
 
4228
                                if (!e.isNull())
3439
4229
                                        tryVerify(u, &r);
3440
4230
                        }
3441
4231
                }
3442
4232
        }
3443
4233
}
3444
4234
 
 
4235
void PsiAccount::trySignPresence()
 
4236
{
 
4237
        QCA::SecureMessageKey skey;
 
4238
        skey.setPGPSecretKey(d->cur_pgpSecretKey);
 
4239
        QByteArray plain = d->loginStatus.status().utf8();
 
4240
 
 
4241
        PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP());
 
4242
        connect(t, SIGNAL(finished()), SLOT(pgp_signFinished()));
 
4243
        t->setFormat(QCA::SecureMessage::Ascii);
 
4244
        t->setSigner(skey);
 
4245
        t->startSign(QCA::SecureMessage::Detached);
 
4246
        t->update(plain);
 
4247
        t->end();
 
4248
}
 
4249
 
 
4250
void PsiAccount::pgp_signFinished()
 
4251
{
 
4252
        PGPTransaction *t = (PGPTransaction*) sender();
 
4253
        if (t->success()) {
 
4254
                Status s = d->loginStatus;
 
4255
                s.setXSigned(PGPUtil::instance().stripHeaderFooter(QString(t->signature())));
 
4256
                setStatusActual(s);
 
4257
        }
 
4258
        else {
 
4259
                // Clear passphrase from cache
 
4260
                if (t->errorCode() == QCA::SecureMessage::ErrorPassphrase) {
 
4261
                        QCA::KeyStoreEntry ke = PGPUtil::instance().getSecretKeyStoreEntry(d->cur_pgpSecretKey.keyId());
 
4262
                        if (!ke.isNull())
 
4263
                                PGPUtil::instance().removePassphrase(ke.id());
 
4264
                }
 
4265
 
 
4266
                QMessageBox::critical(0, tr("Error"), tr("There was an error trying to sign your status.\nReason: %1.").arg(PGPUtil::instance().messageErrorString(t->errorCode())));
 
4267
 
 
4268
                logout();
 
4269
                return;
 
4270
        }
 
4271
        t->deleteLater();
 
4272
}
 
4273
 
 
4274
 
3445
4275
void PsiAccount::verifyStatus(const Jid &j, const Status &s)
3446
4276
{
3447
 
        PGPTransaction *t = new PGPTransaction(d->psi->pgp());
 
4277
        PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP());
3448
4278
        t->setJid(j);
3449
 
        connect(t, SIGNAL(finished(bool)), SLOT(pgp_verifyFinished(bool)));
3450
 
        QCString cs = s.status().utf8();
3451
 
        QByteArray buf(cs.length());
3452
 
        memcpy(buf.data(), cs.data(), buf.size());
3453
 
        t->verify(buf, OpenPGP::addHeaderFooter(s.xsigned(), 1));
3454
 
 
3455
 
        //printf("%s: verifying\n", j.full().latin1());
3456
 
}
3457
 
 
3458
 
void PsiAccount::trySignPresence()
3459
 
{
3460
 
        OpenPGP::Request *r = new OpenPGP::Request(d->psi->pgp());
3461
 
        connect(r, SIGNAL(finished(bool)), SLOT(pgp_signFinished(bool)));
3462
 
        connect(r, SIGNAL(needPassphrase()), SLOT(pgp_needPassphrase()));
3463
 
        QCString cs = d->loginStatus.status().utf8();
3464
 
        QByteArray buf(cs.length());
3465
 
        memcpy(buf.data(), cs.data(), buf.size());
3466
 
        r->sign(buf, d->cur_pgpSecretKeyID);
3467
 
}
3468
 
 
3469
 
void PsiAccount::pgp_needPassphrase()
3470
 
{
3471
 
        OpenPGP::Request *r = (OpenPGP::Request *)sender();
3472
 
        d->ppreq = r;
3473
 
 
3474
 
        if(pgp_passphrases.contains(d->cur_pgpSecretKeyID))
3475
 
                r->submitPassphrase(pgp_passphrases[d->cur_pgpSecretKeyID]);
3476
 
        else
3477
 
                promptPassphrase();
3478
 
}
3479
 
 
3480
 
void PsiAccount::promptPassphrase()
3481
 
{
3482
 
        if(d->ppdlg)
3483
 
                d->ppdlg->unblock();
3484
 
        else {
3485
 
                PassphraseDlg *w = new PassphraseDlg(0);
3486
 
                connect(w, SIGNAL(submitPassphrase(const QString &)), SLOT(submitPassphrase(const QString &)));
3487
 
                connect(w, SIGNAL(rejectPassphrase()), SLOT(rejectPassphrase()));
3488
 
                w->setCaption(tr("%1: OpenPGP Passphrase").arg(name()));
3489
 
                w->show();
3490
 
 
3491
 
                d->ppdlg = w;
3492
 
        }
3493
 
}
3494
 
 
3495
 
void PsiAccount::submitPassphrase(const QString &pp)
3496
 
{
3497
 
        d->ppreq->submitPassphrase(pp);
3498
 
}
3499
 
 
3500
 
void PsiAccount::rejectPassphrase()
3501
 
{
3502
 
        d->ppdlg = 0;
3503
 
 
3504
 
        // cancel request
3505
 
        if(d->ppreq)
3506
 
                d->ppreq->deleteLater();
3507
 
 
3508
 
        logout();
3509
 
}
3510
 
 
3511
 
void PsiAccount::pgp_signFinished(bool ok)
3512
 
{
3513
 
        OpenPGP::Request *r = (OpenPGP::Request *)sender();
3514
 
        bool badPassphrase = r->badPassphrase();
3515
 
        QString sig;
3516
 
        if(ok)
3517
 
                sig = r->signature();
3518
 
        if(d->ppdlg) {
3519
 
                pgp_passphrases[d->cur_pgpSecretKeyID] = d->ppdlg->passphrase();
3520
 
        }
3521
 
        r->deleteLater();
3522
 
 
3523
 
        if(ok) {
3524
 
                Status s = d->loginStatus;
3525
 
                s.setXSigned(OpenPGP::stripHeaderFooter(sig));
3526
 
                setStatusActual(s);
3527
 
        }
3528
 
        else {
3529
 
                if(badPassphrase) {
3530
 
                        pgp_passphrases.erase(d->cur_pgpSecretKeyID);
3531
 
                        QMessageBox::information(d->ppdlg ? d->ppdlg : 0, CAP(tr("Error")), tr("You entered a bad passphrase.  Please try again."));
3532
 
                        QTimer::singleShot(0, this, SLOT(trySignPresence()));
3533
 
                        return;
3534
 
                }
3535
 
                else {
3536
 
                        QMessageBox::information(d->ppdlg ? d->ppdlg : 0, CAP(tr("Error")), tr("There was an error during OpenPGP processing.  Check your settings and try again."));
3537
 
                        logout();
3538
 
                }
3539
 
        }
3540
 
 
3541
 
        // remove the dialog if it is there
3542
 
        if(d->ppdlg) {
3543
 
                d->ppdlg->deleteLater();
3544
 
                d->ppdlg = 0;
3545
 
        }
3546
 
}
3547
 
 
3548
 
void PsiAccount::pgp_verifyFinished(bool b)
3549
 
{
3550
 
        PGPTransaction *t = (PGPTransaction *)sender();
3551
 
 
 
4279
        connect(t, SIGNAL(finished()), SLOT(pgp_verifyFinished()));
 
4280
        t->startVerify(PGPUtil::instance().addHeaderFooter(s.xsigned(),1).utf8());
 
4281
        t->update(s.status().utf8());
 
4282
        t->end();
 
4283
}
 
4284
 
 
4285
 
 
4286
void PsiAccount::pgp_verifyFinished()
 
4287
{
 
4288
        PGPTransaction *t = (PGPTransaction*) sender();
3552
4289
        Jid j = t->jid();
3553
 
        //printf("%s: verify complete\n", j.full().latin1());
3554
 
        QPtrList<UserListItem> list = findRelavent(j);
3555
 
        QPtrListIterator<UserListItem> it(list);
3556
 
        for(UserListItem *u; (u = it.current()); ++it) {
 
4290
        foreach(UserListItem *u, findRelevant(j)) {
3557
4291
                UserResourceList::Iterator rit = u->userResourceList().find(j.resource());
3558
4292
                bool found = (rit == u->userResourceList().end()) ? false: true;
3559
4293
                if(!found)
3560
4294
                        continue;
3561
4295
                UserResource &ur = *rit;
3562
4296
 
3563
 
                if(b) {
3564
 
                        //printf("vergood\n");
3565
 
                        ur.setPublicKeyID(t->keyID());
3566
 
                        ur.setPGPVerifyStatus(t->verifyResult());
3567
 
                        ur.setSigTimestamp(t->timestamp());
 
4297
                QCA::SecureMessageSignature signer;
 
4298
                if(t->success()) {
 
4299
                        signer = t->signer();
 
4300
 
 
4301
                        ur.setPublicKeyID(signer.key().pgpPublicKey().keyId());
 
4302
                        ur.setPGPVerifyStatus(signer.identityResult());
 
4303
                        ur.setSigTimestamp(signer.timestamp());
3568
4304
 
3569
4305
                        // if the key doesn't match the assigned key, unassign it
3570
 
                        if(t->keyID() != u->publicKeyID())
 
4306
                        if(signer.key().pgpPublicKey().keyId() != u->publicKeyID())
3571
4307
                                u->setPublicKeyID("");
3572
4308
                }
3573
4309
                else {
3574
 
                        //QMessageBox::information(0, "sig verify error", QString("error verifying [%1]").arg(u->jid().full()));
3575
 
                        ur.setPGPVerifyStatus(OpenPGP::VerifyError);
 
4310
                        ur.setPGPVerifyStatus(-1);
3576
4311
                }
3577
 
 
3578
 
                //printf("updating [%s]\n", u->jid().full().latin1());
3579
4312
                cpUpdate(*u);
3580
4313
        }
3581
4314
 
3586
4319
{
3587
4320
        if(!ensureKey(_m.to()))
3588
4321
                return -1;
3589
 
        QString key = findFirstRelavent(_m.to())->publicKeyID();
3590
 
 
3591
 
        PGPTransaction *pt = new PGPTransaction(d->psi->pgp());
3592
 
        Message m = _m;
3593
 
        pt->setMessage(m); // keep a copy
3594
 
        //QByteArray a = m.generateEncryptablePayload(d->client->doc());
3595
 
        QCString cs = m.body().utf8();
3596
 
        QByteArray a(cs.length());
3597
 
        memcpy(a.data(), cs.data(), a.size());
3598
 
 
3599
 
        // encrypt
3600
 
        QStringList rcpt;
3601
 
        rcpt += key;
3602
 
        connect(pt, SIGNAL(finished(bool)), SLOT(pgp_finished(bool)));
3603
 
        pt->encrypt(a, rcpt);
3604
 
 
3605
 
        return pt->id();
 
4322
 
 
4323
        QString keyID = findFirstRelevant(_m.to())->publicKeyID();
 
4324
        QCA::KeyStoreEntry keyEntry = PGPUtil::instance().getPublicKeyStoreEntry(keyID);
 
4325
        if (keyEntry.isNull())
 
4326
                return -1;
 
4327
 
 
4328
        QCA::SecureMessageKey key;
 
4329
        key.setPGPPublicKey(keyEntry.pgpPublicKey());
 
4330
 
 
4331
        PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP());
 
4332
        t->setMessage(_m);
 
4333
        connect(t, SIGNAL(finished()), SLOT(pgp_encryptFinished()));
 
4334
        t->setFormat(QCA::SecureMessage::Ascii);
 
4335
        t->setRecipient(key);
 
4336
        t->startEncrypt();
 
4337
        t->update(_m.body().utf8());
 
4338
        t->end();
 
4339
 
 
4340
        return t->id();
3606
4341
}
3607
4342
 
3608
 
void PsiAccount::pgp_finished(bool b)
 
4343
void PsiAccount::pgp_encryptFinished()
3609
4344
{
3610
4345
        PGPTransaction *pt = (PGPTransaction *)sender();
3611
 
 
3612
4346
        int x = pt->id();
3613
 
        if(pt->type() == OpenPGP::Encrypt) {
3614
 
                if(b) {
3615
 
                        Message m = pt->message();
3616
 
                        // log the message here, before we encrypt it
3617
 
                        if(d->acc.opt_log) {
3618
 
                                MessageEvent *me = new MessageEvent(m, this);
3619
 
                                me->setOriginLocal(true);
3620
 
                                me->setTimeStamp(QDateTime::currentDateTime());
3621
 
                                logEvent(m.to(), me);
3622
 
                                delete me;
3623
 
                        }
3624
 
 
3625
 
                        Message mwrap;
3626
 
                        mwrap.setTo(m.to());
3627
 
                        mwrap.setType(m.type());
3628
 
                        QString enc = OpenPGP::stripHeaderFooter(pt->encrypted());
3629
 
                        mwrap.setBody(tr("[ERROR: This message is encrypted, and you are unable to decrypt it.]"));
3630
 
                        mwrap.setXEncrypted(enc);
3631
 
                        mwrap.setWasEncrypted(true);
3632
 
                        // FIXME: Should be done cleaner, with an extra method in Iris
3633
 
                        if (m.containsEvent(OfflineEvent)) mwrap.addEvent(OfflineEvent);
3634
 
                        if (m.containsEvent(DeliveredEvent)) mwrap.addEvent(DeliveredEvent);
3635
 
                        if (m.containsEvent(DisplayedEvent)) mwrap.addEvent(DisplayedEvent);
3636
 
                        if (m.containsEvent(ComposingEvent)) mwrap.addEvent(ComposingEvent);
3637
 
                        if (m.containsEvent(CancelEvent)) mwrap.addEvent(CancelEvent);
3638
 
                        dj_sendMessage(mwrap);
 
4347
        
 
4348
        if(pt->success()) {
 
4349
                Message m = pt->message();
 
4350
                // log the message here, before we encrypt it
 
4351
                if(d->acc.opt_log) {
 
4352
                        MessageEvent *me = new MessageEvent(m, this);
 
4353
                        me->setOriginLocal(true);
 
4354
                        me->setTimeStamp(QDateTime::currentDateTime());
 
4355
                        logEvent(m.to(), me);
 
4356
                        delete me;
3639
4357
                }
3640
 
                encryptedMessageSent(x, b);
 
4358
 
 
4359
                Message mwrap;
 
4360
                mwrap.setTo(m.to());
 
4361
                mwrap.setType(m.type());
 
4362
                QString enc = PGPUtil::instance().stripHeaderFooter(pt->read());
 
4363
                mwrap.setBody(tr("[ERROR: This message is encrypted, and you are unable to decrypt it.]"));
 
4364
                mwrap.setXEncrypted(enc);
 
4365
                mwrap.setWasEncrypted(true);
 
4366
                // FIXME: Should be done cleaner, with an extra method in Iris
 
4367
                if (m.containsEvent(OfflineEvent)) mwrap.addEvent(OfflineEvent);
 
4368
                if (m.containsEvent(DeliveredEvent)) mwrap.addEvent(DeliveredEvent);
 
4369
                if (m.containsEvent(DisplayedEvent)) mwrap.addEvent(DisplayedEvent);
 
4370
                if (m.containsEvent(ComposingEvent)) mwrap.addEvent(ComposingEvent);
 
4371
                if (m.containsEvent(CancelEvent)) mwrap.addEvent(CancelEvent);
 
4372
                mwrap.setChatState(m.chatState());
 
4373
                dj_sendMessage(mwrap);
3641
4374
        }
3642
 
 
 
4375
        emit encryptedMessageSent(x, pt->success(), pt->errorCode());
3643
4376
        pt->deleteLater();
3644
4377
}
3645
4378
 
3646
 
void PsiAccount::pgp_decryptFinished(bool b)
3647
 
{
3648
 
        PGPTransaction *pt = (PGPTransaction *)sender();
3649
 
 
 
4379
 
 
4380
void PsiAccount::processEncryptedMessage(const Message &m)
 
4381
{
 
4382
        PGPTransaction *t = new PGPTransaction(new QCA::OpenPGP());
 
4383
        t->setMessage(m);
 
4384
        connect(t, SIGNAL(finished()), SLOT(pgp_decryptFinished()));
 
4385
        t->setFormat(QCA::SecureMessage::Ascii);
 
4386
        t->startDecrypt();
 
4387
        t->update(PGPUtil::instance().addHeaderFooter(m.xencrypted(),0).utf8());
 
4388
        t->end();
 
4389
}
 
4390
 
 
4391
 
 
4392
void PsiAccount::pgp_decryptFinished()
 
4393
{
 
4394
        PGPTransaction *pt = (PGPTransaction*) sender();
3650
4395
        bool tryAgain = false;
3651
 
        if(b) {
 
4396
        if (pt->success()) {
3652
4397
                Message m = pt->message();
3653
 
                //if(m.applyDecryptedPayload(pt->decrypted(), d->client->doc()))
3654
 
                QByteArray buf = pt->decrypted();
3655
 
                QCString cs(buf.size()+1);
3656
 
                memcpy(cs.data(), buf.data(), buf.size());
3657
 
                QString str = QString::fromUtf8(cs);
3658
 
                m.setBody(str);
 
4398
                m.setBody(QString::fromUtf8(pt->read()));
3659
4399
                m.setXEncrypted("");
3660
4400
                m.setWasEncrypted(true);
3661
4401
                processIncomingMessage(m);
3662
 
 
3663
 
                //else
3664
 
                //      QMessageBox::information(0, CAP(tr("Error")), tr("A successful decryption operation resulted in an invalid message, so it has been ignored."));
3665
4402
        }
3666
4403
        else {
3667
 
                if(loggedIn()) {
 
4404
                if (loggedIn()) {
3668
4405
                        Message m;
3669
4406
                        m.setTo(pt->message().from());
3670
4407
                        m.setType("error");
 
4408
                        if (!pt->message().id().isEmpty())
 
4409
                                m.setId(pt->message().id());
3671
4410
                        m.setBody(pt->message().body());
3672
 
                        Stanza::Error err;
3673
 
                        err.condition = 500;
3674
 
                        err.text = "Unable to decrypt";
3675
 
                        m.setError(err);
 
4411
                        m.setError(Stanza::Error(Stanza::Error::Wait,
 
4412
                                                 Stanza::Error::NotAcceptable,
 
4413
                                                 "Unable to decrypt"));
3676
4414
                        d->client->sendMessage(m);
3677
4415
                }
3678
4416
        }
3679
4417
 
3680
4418
        pt->deleteLater();
3681
4419
 
3682
 
        if(tryAgain) {
 
4420
        if (tryAgain) {
3683
4421
                processEncryptedMessageNext();
3684
4422
        }
3685
4423
        else {
3687
4425
        }
3688
4426
}
3689
4427
 
3690
 
void PsiAccount::processEncryptedMessage(const Message &m)
3691
 
{
3692
 
        // decrypt
3693
 
        PGPTransaction *t = new PGPTransaction(d->psi->pgp());
3694
 
        t->setMessage(m); // keep a copy
3695
 
        connect(t, SIGNAL(needPassphrase()), SLOT(pgp_needPassphrase()));
3696
 
        connect(t, SIGNAL(finished(bool)), SLOT(pgp_decryptFinished(bool)));
3697
 
        QString str = OpenPGP::addHeaderFooter(m.xencrypted(), 0);
3698
 
        t->decrypt(str);
3699
 
}
3700
 
 
3701
4428
void PsiAccount::processMessageQueue()
3702
4429
{
3703
4430
        while(!d->messageQueue.isEmpty()) {
3704
 
                Message *mp = d->messageQueue.getFirst();
 
4431
                Message *mp = d->messageQueue.first();
3705
4432
 
3706
4433
                // encrypted?
3707
 
                if(d->psi->pgp() && !mp->xencrypted().isEmpty()) {
 
4434
                if(PGPUtil::instance().pgpAvailable() && !mp->xencrypted().isEmpty()) {
3708
4435
                        processEncryptedMessageNext();
3709
4436
                        break;
3710
4437
                }
3711
4438
 
3712
4439
                processIncomingMessage(*mp);
3713
 
                d->messageQueue.removeRef(mp);
 
4440
                d->messageQueue.remove(mp);
 
4441
                delete mp;
3714
4442
        }
3715
4443
}
3716
4444
 
3717
4445
void PsiAccount::processEncryptedMessageNext()
3718
4446
{
3719
4447
        // 'peek' and try to process it
3720
 
        Message *mp = d->messageQueue.getFirst();
 
4448
        Message *mp = d->messageQueue.first();
3721
4449
        processEncryptedMessage(*mp);
3722
4450
}
3723
4451
 
3724
4452
void PsiAccount::processEncryptedMessageDone()
3725
4453
{
3726
4454
        // 'pop' the message
3727
 
        Message *mp = d->messageQueue.getFirst();
3728
 
        d->messageQueue.removeRef(mp);
 
4455
        if (!d->messageQueue.isEmpty())
 
4456
                delete d->messageQueue.takeFirst();
3729
4457
 
3730
4458
        // do the rest of the queue
3731
4459
        processMessageQueue();
3734
4462
void PsiAccount::optionsUpdate()
3735
4463
{
3736
4464
        d->cp->updateEntry(d->self);
3737
 
}
3738
 
 
3739
 
QString PsiAccount::resultToString(int result)
3740
 
{
3741
 
        QString s;
3742
 
        switch(result) {
3743
 
                case QCA::TLS::NoCert:
3744
 
                        s = tr("The server did not present a certificate.");
3745
 
                        break;
3746
 
                case QCA::TLS::Valid:
3747
 
                        s = tr("Certificate is valid.");
3748
 
                        break;
3749
 
                case QCA::TLS::HostMismatch:
3750
 
                        s = tr("The hostname does not match the one the certificate was issued to.");
3751
 
                        break;
3752
 
                case QCA::TLS::Rejected:
3753
 
                        s = tr("Root CA is marked to reject the specified purpose.");
3754
 
                        break;
3755
 
                case QCA::TLS::Untrusted:
3756
 
                        s = tr("Certificate not trusted for the required purpose.");
3757
 
                        break;
3758
 
                case QCA::TLS::SignatureFailed:
3759
 
                        s = tr("Invalid signature.");
3760
 
                        break;
3761
 
                case QCA::TLS::InvalidCA:
3762
 
                        s = tr("Invalid CA certificate.");
3763
 
                        break;
3764
 
                case QCA::TLS::InvalidPurpose:
3765
 
                        s = tr("Invalid certificate purpose.");
3766
 
                        break;
3767
 
                case QCA::TLS::SelfSigned:
3768
 
                        s = tr("Certificate is self-signed.");
3769
 
                        break;
3770
 
                case QCA::TLS::Revoked:
3771
 
                        s = tr("Certificate has been revoked.");
3772
 
                        break;
3773
 
                case QCA::TLS::PathLengthExceeded:
3774
 
                        s = tr("Maximum certificate chain length exceeded.");
3775
 
                        break;
3776
 
                case QCA::TLS::Expired:
3777
 
                        s = tr("Certificate has expired.");
3778
 
                        break;
3779
 
                case QCA::TLS::Unknown:
3780
 
                default:
3781
 
                        s = tr("General certificate validation error.");
3782
 
                        break;
3783
 
        }
3784
 
        return s;
3785
 
}
 
4465
 
 
4466
        // Tune
 
4467
#ifdef USE_PEP
 
4468
        bool publish = d->options->getOption("options.extended-presence.tune.publish").toBool();
 
4469
        if (!d->lastTune.isNull() && !publish) {
 
4470
                publishTune(Tune());
 
4471
        }
 
4472
        else if (d->lastTune.isNull() && publish) {
 
4473
                Tune current = d->psi->tuneController()->currentTune();
 
4474
                if (!current.isNull())
 
4475
                        publishTune(current);
 
4476
        }
 
4477
#endif
 
4478
 
 
4479
        // Chat states
 
4480
        setSendChatState(option.messageEvents);
 
4481
 
 
4482
        // Remote Controlling
 
4483
        setRCEnabled(option.useRC);
 
4484
 
 
4485
        // Roster item exchange
 
4486
        d->rosterItemExchangeTask->setIgnoreNonRoster(option.ignoreNonRoster);
 
4487
 
 
4488
        // Caps manager
 
4489
        d->capsManager->setEnabled(option.useCaps);
 
4490
}
 
4491
 
 
4492
 
 
4493
void PsiAccount::setRCEnabled(bool b)
 
4494
{
 
4495
        if (b && !d->rcSetStatusServer) {
 
4496
                d->rcSetStatusServer = new RCSetStatusServer(d->ahcManager);
 
4497
                d->rcForwardServer = new RCForwardServer(d->ahcManager);
 
4498
                d->rcSetOptionsServer = new RCSetOptionsServer(d->ahcManager, d->psi);
 
4499
        }
 
4500
        else if (!b && d->rcSetStatusServer) {
 
4501
                delete d->rcSetStatusServer;
 
4502
                d->rcSetStatusServer = 0;
 
4503
                delete d->rcForwardServer;
 
4504
                d->rcForwardServer = 0;
 
4505
                delete d->rcSetOptionsServer;
 
4506
                d->rcSetOptionsServer = 0;
 
4507
        }
 
4508
}
 
4509
 
 
4510
void PsiAccount::setSendChatState(bool b)
 
4511
{
 
4512
        if (b && !d->client->extensions().contains("cs")) {
 
4513
                d->client->addExtension("cs",Features("http://jabber.org/protocol/chatstates"));
 
4514
                if (isConnected())
 
4515
                        setStatusActual(d->loginStatus);
 
4516
        }
 
4517
        else if (!b && d->client->extensions().contains("cs")) {
 
4518
                d->client->removeExtension("cs");
 
4519
                if (isConnected())
 
4520
                        setStatusActual(d->loginStatus);
 
4521
        }
 
4522
}
 
4523
 
3786
4524
 
3787
4525
void PsiAccount::invokeGCMessage(const Jid &j)
3788
4526
{
3796
4534
        u->setInList(false);
3797
4535
        u->setName(j.resource());
3798
4536
        u->setPrivate(true);
3799
 
#ifdef AVATARS
3800
 
        u->setAvatarFactory(d->avatarFactory);
3801
 
#endif
3802
4537
 
3803
4538
        // make a resource so the contact appears online
3804
4539
        UserResource ur;
3823
4558
        u->setInList(false);
3824
4559
        u->setName(j.resource());
3825
4560
        u->setPrivate(true);
3826
 
#ifdef AVATARS
3827
 
        u->setAvatarFactory(d->avatarFactory);
3828
 
#endif
3829
4561
 
3830
4562
        // make a resource so the contact appears online
3831
4563
        UserResource ur;
3835
4567
 
3836
4568
        d->userList.append(u);
3837
4569
        actionOpenChat(j);
3838
 
        d->userList.remove(u);
 
4570
        cpUpdate(*u);
 
4571
        //d->userList.remove(u);
3839
4572
}
3840
4573
 
3841
4574
void PsiAccount::invokeGCInfo(const Jid &j)
3850
4583
 
3851
4584
void PsiAccount::toggleSecurity(const Jid &j, bool b)
3852
4585
{
3853
 
        UserListItem *u = findFirstRelavent(j);
 
4586
        UserListItem *u = findFirstRelevant(j);
3854
4587
        if(!u)
3855
4588
                return;
3856
4589
 
3894
4627
 
3895
4628
bool PsiAccount::ensureKey(const Jid &j)
3896
4629
{
3897
 
        if(!d->psi->pgp())
 
4630
        if(!PGPUtil::instance().pgpAvailable())
3898
4631
                return false;
3899
4632
 
3900
 
        UserListItem *u = findFirstRelavent(j);
 
4633
        UserListItem *u = findFirstRelevant(j);
3901
4634
        if(!u)
3902
4635
                return false;
3903
4636
 
3914
4647
                        }
3915
4648
                }
3916
4649
 
3917
 
                bool inList = false;
3918
 
                OpenPGP::KeyList list = d->psi->pgp()->publicKeys();
3919
 
                for(OpenPGP::KeyList::ConstIterator lit = list.begin(); lit != list.end(); ++lit) {
3920
 
                        const OpenPGP::Key &k = *lit;
3921
 
                        if(k.keyID() == akey) {
3922
 
                                inList = true;
3923
 
                                break;
3924
 
                        }
3925
 
                }
3926
 
 
3927
 
                if(akey.isEmpty() || !inList) {
 
4650
                if(akey.isEmpty() || PGPUtil::instance().getPublicKeyStoreEntry(akey).isNull()) {
3928
4651
                        int n = QMessageBox::information(0, CAP(tr("No key")), tr(
3929
4652
                                "<p>Psi was unable to locate the OpenPGP key to use for <b>%1</b>.<br>"
3930
4653
                                "<br>"
3931
4654
                                "This can happen if you do not have the key that the contact is advertising "
3932
4655
                                "via signed presence, or if the contact is not advertising any key at all.</p>"
3933
 
                                ).arg(u->jid().full()), tr("&Choose key manually"), tr("Do &nothing"));
 
4656
                                ).arg(JIDUtil::toString(u->jid(),true)), tr("&Choose key manually"), tr("Do &nothing"));
3934
4657
                        if(n != 0)
3935
4658
                                return false;
3936
4659
                }
3937
4660
 
3938
 
                PGPKeyDlg *w = new PGPKeyDlg(list, akey, 0);
3939
 
                w->setCaption(tr("Public Key: %1").arg(j.full()));
 
4661
                // Select a key
 
4662
                PGPKeyDlg *w = new PGPKeyDlg(PGPKeyDlg::Public, akey, 0);
 
4663
                w->setWindowTitle(tr("Public Key: %1").arg(JIDUtil::toString(j,true)));
3940
4664
                int r = w->exec();
3941
 
                QString key;
 
4665
                QCA::KeyStoreEntry entry;
3942
4666
                if(r == QDialog::Accepted)
3943
 
                        key = w->keyID();
 
4667
                        entry = w->keyStoreEntry();
3944
4668
                delete w;
3945
 
                if(key.isEmpty())
 
4669
                if(entry.isNull())
3946
4670
                        return false;
3947
 
                u->setPublicKeyID(key);
 
4671
                u->setPublicKeyID(entry.pgpPublicKey().keyId());
3948
4672
                cpUpdate(*u);
3949
4673
        }
3950
4674
 
3951
4675
        return true;
3952
4676
}
3953
4677
 
3954
 
 
3955
 
//----------------------------------------------------------------------------
3956
 
// PGPKeyDlg
3957
 
//----------------------------------------------------------------------------
3958
 
class KeyViewItem : public QListViewItem
3959
 
{
3960
 
public:
3961
 
        KeyViewItem(const QString &_keyID, QListView *par)
3962
 
        :QListViewItem(par)
3963
 
        {
3964
 
                keyID = _keyID;
3965
 
        }
3966
 
 
3967
 
        QString keyID;
3968
 
};
3969
 
 
3970
 
class PGPKeyDlg::Private
3971
 
{
3972
 
public:
3973
 
        Private() {}
3974
 
 
3975
 
        QString keyID;
3976
 
        QString userID;
3977
 
};
3978
 
 
3979
 
PGPKeyDlg::PGPKeyDlg(const OpenPGP::KeyList &list, const QString &choose, QWidget *parent, const char *name)
3980
 
:PGPKeyUI(parent, name, true)
3981
 
{
3982
 
        d = new Private;
3983
 
 
3984
 
        connect(lv_keys, SIGNAL(doubleClicked(QListViewItem *)), SLOT(qlv_doubleClicked(QListViewItem *)));
3985
 
        connect(pb_ok, SIGNAL(clicked()), SLOT(do_accept()));
3986
 
        connect(pb_cancel, SIGNAL(clicked()), SLOT(reject()));
3987
 
 
3988
 
        QListViewItem *isel = 0;
3989
 
        for(OpenPGP::KeyList::ConstIterator it = list.begin(); it != list.end(); ++it) {
3990
 
                const OpenPGP::Key &k = *it;
3991
 
                KeyViewItem *i = new KeyViewItem(k.keyID(), lv_keys);
3992
 
                //i->setPixmap(0, IconsetFactory::icon("psi/gpg-yes"));
3993
 
                i->setText(0, k.keyID().right(8));
3994
 
                i->setText(1, k.userID());
3995
 
 
3996
 
                if(!choose.isEmpty() && k.keyID() == choose) {
3997
 
                        lv_keys->setSelected(i, true);
3998
 
                        isel = i;
3999
 
                }
4000
 
        }
4001
 
        if(lv_keys->childCount() > 0 && !isel)
4002
 
                lv_keys->setSelected(lv_keys->firstChild(), true);
4003
 
        else if(isel)
4004
 
                lv_keys->ensureItemVisible(isel);
4005
 
}
4006
 
 
4007
 
PGPKeyDlg::~PGPKeyDlg()
4008
 
{
4009
 
        delete d;
4010
 
}
4011
 
 
4012
 
QString PGPKeyDlg::keyID() const
4013
 
{
4014
 
        return d->keyID;
4015
 
}
4016
 
 
4017
 
QString PGPKeyDlg::userID() const
4018
 
{
4019
 
        return d->userID;
4020
 
}
4021
 
 
4022
 
void PGPKeyDlg::qlv_doubleClicked(QListViewItem *i)
4023
 
{
4024
 
        lv_keys->setSelected(i, true);
4025
 
        do_accept();
4026
 
}
4027
 
 
4028
 
void PGPKeyDlg::do_accept()
4029
 
{
4030
 
        KeyViewItem *i = (KeyViewItem *)lv_keys->selectedItem();
4031
 
        if(!i) {
4032
 
                QMessageBox::information(this, tr("Error"), tr("Please select a key."));
4033
 
                return;
4034
 
        }
4035
 
        d->keyID = i->keyID;
4036
 
        d->userID = i->text(1);
4037
 
        accept();
 
4678
ServerInfoManager* PsiAccount::serverInfoManager()
 
4679
{
 
4680
        return d->serverInfoManager;
 
4681
}
 
4682
 
 
4683
PEPManager* PsiAccount::pepManager()
 
4684
{
 
4685
        return d->pepManager;
 
4686
}
 
4687
 
 
4688
BookmarkManager* PsiAccount::bookmarkManager()
 
4689
{
 
4690
        return d->bookmarkManager;
4038
4691
}
4039
4692
 
4040
4693
#include "psiaccount.moc"