~ubuntu-branches/ubuntu/dapper/psi/dapper

« back to all changes in this revision

Viewing changes to src/jabber.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2004-06-15 00:10:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040615001041-enywb6pcpe4sjsw6
Tags: 0.9.2-1
* New upstream release
* Set KDEDIR for ./configure so kde specific files get installed
* Don't install libpsiwidgets.so. It got installed in /usr/share
  where it doesn't belong. May be included (at a better location)
  later.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
** jabber.cpp - communicates with the Jabber network
3
 
** Copyright (C) 2001, 2002  Justin Karneges
4
 
**
5
 
** This program is free software; you can redistribute it and/or
6
 
** modify it under the terms of the GNU General Public License
7
 
** as published by the Free Software Foundation; either version 2
8
 
** of the License, or (at your option) any later version.
9
 
**
10
 
** This program is distributed in the hope that it will be useful,
11
 
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
** GNU General Public License for more details.
14
 
**
15
 
** You should have received a copy of the GNU General Public License
16
 
** along with this program; if not, write to the Free Software
17
 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 
**
19
 
****************************************************************************/
20
 
 
21
 
#include"jabber.h"
22
 
#include"common.h"
23
 
#include<time.h>
24
 
#include<qregexp.h>
25
 
#include<qtimer.h>
26
 
 
27
 
 
28
 
/****************************************************************************
29
 
  Jabber
30
 
****************************************************************************/
31
 
Jabber::Jabber()
32
 
{
33
 
        host = "";
34
 
        port = 5222;
35
 
 
36
 
        v_status = STATUS_OFFLINE;
37
 
        v_isActive = FALSE;
38
 
        v_offlineEnabled = FALSE;
39
 
 
40
 
        connect(&stream, SIGNAL(connected()), SLOT(streamConnected()));
41
 
        connect(&stream, SIGNAL(error(int)), SLOT(streamError(int)));
42
 
        connect(&stream, SIGNAL(receivePacket(const QDomElement &)), SLOT(receivePacket(const QDomElement &)));
43
 
 
44
 
        //io.stream = &stream;
45
 
        connect(&io, SIGNAL(done(JabTask *)), SLOT(ioDone(JabTask *)));
46
 
        connect(&io, SIGNAL(outgoingPacket(const QDomElement &)), SLOT(ioOutgoingPacket(const QDomElement &)));
47
 
        connect(&io, SIGNAL(anyDone(JabTask *)), SLOT(doUpdate()));
48
 
 
49
 
        // queue
50
 
        queue = new JT_Queue(io.root());
51
 
        connect(queue, SIGNAL(countChanged()), SLOT(doUpdate()));
52
 
}
53
 
 
54
 
Jabber::~Jabber()
55
 
{
56
 
        stream.disc();
57
 
        delete queue;
58
 
}
59
 
 
60
 
void Jabber::setHost(const QString &xhost, int xport)
61
 
{
62
 
        host = xhost;
63
 
        port = xport;
64
 
 
65
 
        me.jid = QString("%1@%2").arg(user).arg(host);
66
 
}
67
 
 
68
 
void Jabber::setAccount(const QString &xuser, const QString &xpass, const QString &xresource)
69
 
{
70
 
        user = xuser;
71
 
        pass = xpass;
72
 
        resource = xresource;
73
 
 
74
 
        me.jid = QString("%1@%2").arg(user).arg(host);
75
 
        me.nick = user;
76
 
}
77
 
 
78
 
void Jabber::setNoop(int mills)
79
 
{
80
 
        stream.setNoop(mills);
81
 
}
82
 
 
83
 
void Jabber::send(const QString &str)
84
 
{
85
 
        if(stream.isConnected()) {
86
 
                stream.sendString(str.latin1());
87
 
                pdb(DEBUG_JABBER, QString("Jabber: wrote: [\n%1]\n").arg(str.latin1()));
88
 
        }
89
 
}
90
 
 
91
 
void Jabber::streamConnected()
92
 
{
93
 
        pdb(DEBUG_JABBER, "Jabber: stream connected\n");
94
 
 
95
 
        // tell the world
96
 
        connected();
97
 
 
98
 
        if(connType == JABCONN_LOGIN) {
99
 
                JT_Login *l = new JT_Login(io.root());
100
 
                connect(l, SIGNAL(receiveAuth()), SLOT(ioAuth()));
101
 
                connect(l, SIGNAL(receivePresence(int, const QString &)), SLOT(ioPresence(int, const QString &)));
102
 
                connect(l, SIGNAL(receiveRoster(JabRoster &)), SLOT(ioReceiveRoster(JabRoster &)));
103
 
                connect(l, SIGNAL(stepChanged()), SLOT(doUpdate()));
104
 
 
105
 
                l->login(user, pass, stream.id(), resource, i_status, i_statusString, i_priority, usePlain);
106
 
                l->go();
107
 
 
108
 
                // presence daemon
109
 
                JT_PushPresence *pp = new JT_PushPresence(io.root());
110
 
                connect(pp, SIGNAL(subscription(const Jid &, int)), SLOT(pushSubscription(const Jid &, int)));
111
 
                connect(pp, SIGNAL(presence(const JT_PushPresence::Info &)), SLOT(pushPresence(const JT_PushPresence::Info &)));
112
 
 
113
 
                // roster daemon
114
 
                JT_PushRoster *pr = new JT_PushRoster(io.root());
115
 
                connect(pr, SIGNAL(roster(JabRoster &)), SLOT(pushRoster(JabRoster &)));
116
 
 
117
 
                // message daemon
118
 
                JT_PushMessage *pm = new JT_PushMessage(io.root());
119
 
                connect(pm, SIGNAL(message(const JabMessage &)), SLOT(pushMessage(const JabMessage &)));
120
 
 
121
 
                // other stuff
122
 
                new JT_ServInfo(io.root());
123
 
 
124
 
                // user branch
125
 
                userTask = new JabTask(io.root());
126
 
                connect(userTask, SIGNAL(childAdded(JabTask *)), SLOT(doUpdate()));
127
 
                connect(userTask, SIGNAL(childRemoved(JabTask *)), SLOT(doUpdate()));
128
 
        }
129
 
        else if(connType == JABCONN_REGISTER) {
130
 
                JT_Register *r = new JT_Register(io.root());
131
 
                r->reg(user, pass);
132
 
                r->go();
133
 
        }
134
 
}
135
 
 
136
 
void Jabber::streamError(int x)
137
 
{
138
 
        pdb(DEBUG_JABBER, QString("Jabber: stream error=[%1]\n").arg(x));
139
 
 
140
 
        switch(x) {
141
 
                case JABSTREAM_ERR_DNS:
142
 
                        err.msg = tr("Unable to resolve hostname");
143
 
                        err.type = JABERR_CONNECT;
144
 
                        break;
145
 
                case JABSTREAM_ERR_CONNREFUSED:
146
 
                        err.msg = tr("Connection refused");
147
 
                        err.type = JABERR_CONNECT;
148
 
                        break;
149
 
                case JABSTREAM_ERR_CONNTIMEOUT:
150
 
                        err.msg = tr("Connection timeout");
151
 
                        err.type = JABERR_CONNECT;
152
 
                        break;
153
 
                case JABSTREAM_ERR_HANDSHAKE:
154
 
                        err.msg = tr("Unable to establish stream handshake");
155
 
                        err.type = JABERR_CONNECT;
156
 
                        break;
157
 
                case JABSTREAM_ERR_DISC:
158
 
                case JABSTREAM_ERR_SOCKET:
159
 
                default:
160
 
                        err.type = JABERR_DISCONNECT;
161
 
                        break;
162
 
        }
163
 
 
164
 
        disconnected();
165
 
 
166
 
        cleanup();
167
 
        doError();
168
 
}
169
 
 
170
 
void Jabber::cleanup(bool fast)
171
 
{
172
 
        pdb(DEBUG_JABBER, "Jabber: cleanup\n");
173
 
 
174
 
        queue->stop();
175
 
        //printf("JT_Queue::toString() = [%s]\n", queue->toString().latin1());
176
 
        io.reset();
177
 
        userTask = 0;
178
 
 
179
 
        if(!fast) {
180
 
                // set all contacts to offline
181
 
                for(JabRosterEntry *i = roster.first(); i; i = roster.next()) {
182
 
                        QPtrListIterator<JabResource> it(i->res);
183
 
                        JabResource *r;
184
 
                        while((r = it.current())) {
185
 
                                // clean the jid first, in case it has an attached resource already (like /registered)
186
 
                                Jid j = QString("%1/%2").arg(cleanJid(i->jid)).arg(r->name);
187
 
                                i->res.remove(r);
188
 
                                resourceUnavailable(j);
189
 
                        }
190
 
                        // not offline mode? delete!
191
 
                        if(!v_offlineEnabled)
192
 
                                contactRemove(i);
193
 
                }
194
 
                // not offline mode?  clear our local roster
195
 
                if(!v_offlineEnabled)
196
 
                        roster.clear();
197
 
 
198
 
                // remove 'me' resources (in reverse order)
199
 
                QPtrListIterator<JabResource> it(me.res);
200
 
                it.toLast();
201
 
                JabResource *r;
202
 
                while((r = it.current())) {
203
 
                        Jid j = QString("%1/%2").arg(cleanJid(me.jid)).arg(r->name);
204
 
                        me.res.remove(r);
205
 
                        resourceUnavailable(j);
206
 
                }
207
 
        }
208
 
 
209
 
        stream.disc();
210
 
 
211
 
        v_isActive = FALSE;
212
 
        v_status = STATUS_OFFLINE;
213
 
        //presenceChanged(v_status, "");
214
 
 
215
 
        // update the offline status since we're now offline
216
 
        /*JabUpdate x;
217
 
        x.req = 0;
218
 
        x.pending = olr.numInteresting();
219
 
        statusUpdate(&x);*/
220
 
 
221
 
        JabUpdate x = makeUpdate();
222
 
        statusUpdate(&x);
223
 
}
224
 
 
225
 
void Jabber::conn()
226
 
{
227
 
        v_isActive = TRUE;
228
 
        stream.connectToHost(host, port);
229
 
 
230
 
        doUpdate();
231
 
}
232
 
 
233
 
void Jabber::disc(bool fast)
234
 
{
235
 
        if(v_isActive) {
236
 
                //JT_Presence *p = new JT_Presence(io.root());
237
 
                //p->pres(STATUS_OFFLINE, "Logged out", 0);
238
 
                //p->go();
239
 
 
240
 
                stream.disc();
241
 
                pdb(DEBUG_JABBER, "Jabber: disconnecting.\n");
242
 
        }
243
 
 
244
 
        v_isActive = FALSE;
245
 
 
246
 
        cleanup(fast);
247
 
}
248
 
 
249
 
// this should clear the contact list (and signal the changes), and clear the offline queue  (FIXME:  shouldn't this just be cleanup() ?)
250
 
void Jabber::reset()
251
 
{
252
 
        // remove everyone
253
 
        for(JabRosterEntry *i = roster.first(); i; i = roster.next())
254
 
                contactRemove(i);
255
 
        roster.clear();
256
 
 
257
 
        io.reset();
258
 
}
259
 
 
260
 
void Jabber::ioAuth()
261
 
{
262
 
}
263
 
 
264
 
void Jabber::ioPresence(int status, const QString &statusString)
265
 
{
266
 
        JabResource *r;
267
 
        r = me.res.find(resource);
268
 
        if(!r) {
269
 
                r = new JabResource;
270
 
                r->name = resource;
271
 
                me.res.append(r);
272
 
        }
273
 
        r->status = status;
274
 
        r->statusString = statusString;
275
 
        r->timeStamp = QDateTime::currentDateTime();
276
 
        Jid myjid = QString("%1/%2").arg(me.jid).arg(r->name);
277
 
        resourceAvailable(myjid, *r);
278
 
}
279
 
 
280
 
void Jabber::ioReceiveRoster(JabRoster &r)
281
 
{
282
 
        JabRosterEntry *i;
283
 
        for(i = roster.first(); i; i = roster.next())
284
 
                i->flagForDelete = TRUE;
285
 
 
286
 
        pdb(DEBUG_JABBER, QString("[Roster item(s) received: %1]\n").arg(r.size()));
287
 
        JabRosterEntry *item;
288
 
        for(item = r.first(); item != 0; item = r.next()) {
289
 
                processRosterEntryRecv(*item);
290
 
        }
291
 
 
292
 
        // remove flagged entries
293
 
        for(i = roster.first(); i; ) {
294
 
                if(i->flagForDelete) {
295
 
                        //printf("Would have deleted: [%s]\n", i->jid.latin1());
296
 
                        contactRemove(i);
297
 
                        roster.remove(i);
298
 
                        i = roster.current();
299
 
                }
300
 
                else
301
 
                        i = roster.next();
302
 
        }
303
 
 
304
 
        // release the hounds!
305
 
        queue->go();
306
 
}
307
 
 
308
 
void Jabber::pushRoster(JabRoster &r)
309
 
{
310
 
        pdb(DEBUG_JABBER, QString("[Roster item(s) received: %1]\n").arg(r.size()));
311
 
        JabRosterEntry *item;
312
 
        for(item = r.first(); item != 0; item = r.next()) {
313
 
                processRosterEntryRecv(*item);
314
 
        }
315
 
}
316
 
 
317
 
void Jabber::pushSubscription(const Jid &from, int subType)
318
 
{
319
 
        if(subType == JABSUB_SUBSCRIBE) {
320
 
                pdb(DEBUG_JABBER, QString("[%1 wants to add you to their list]\n").arg(from.full()));
321
 
                authRequest(from);
322
 
        }
323
 
        else if(subType == JABSUB_SUBSCRIBED) {
324
 
                pdb(DEBUG_JABBER, QString("[%1 has authorized you]\n").arg(from.full()));
325
 
                authGrant(from);
326
 
        }
327
 
        else if(subType == JABSUB_UNSUBSCRIBE) {
328
 
                pdb(DEBUG_JABBER, QString("[%1 has deleted you from their list]\n").arg(from.full()));
329
 
                authRemove(from);
330
 
        }
331
 
        else if(subType == JABSUB_UNSUBSCRIBED) {
332
 
                pdb(DEBUG_JABBER, QString("[%1 has removed your authorization!]\n").arg(from.full()));
333
 
                //authRemove(from);
334
 
        }
335
 
}
336
 
 
337
 
void Jabber::pushPresence(const JT_PushPresence::Info &i)
338
 
{
339
 
        if(i.status == STATUS_OFFLINE) {
340
 
                pdb(DEBUG_JABBER, QString("[%1 went offline]\n").arg(i.jid.full()));
341
 
        }
342
 
        else {
343
 
                pdb(DEBUG_JABBER, QString("[%1 is online]\n").arg(i.jid.full()));
344
 
        }
345
 
 
346
 
        JabRosterEntry *entry;
347
 
        Jid j = i.jid;
348
 
 
349
 
        // is it me?
350
 
        Jid myjid = QString("%1@%2").arg(user).arg(host);
351
 
        if(j == myjid)
352
 
                entry = &me;
353
 
        else
354
 
                entry = roster.findByJid(j.s());
355
 
 
356
 
        if(entry) {
357
 
                JabResource *r;
358
 
 
359
 
                r = entry->res.find(j.resource());
360
 
 
361
 
                // unavailable?  remove the resource
362
 
                if(i.status == STATUS_OFFLINE) {
363
 
                        if(r) {
364
 
                                entry->res.remove(r);
365
 
                                entry->unavailableStatusString = i.statusString;
366
 
                                resourceUnavailable(j);
367
 
                        }
368
 
                }
369
 
                // available? add/update the resource
370
 
                else {
371
 
                        if(!r) {
372
 
                                r = new JabResource;
373
 
                                r->name = j.resource();
374
 
                                entry->res.append(r);
375
 
 
376
 
                                QString dstr;
377
 
                                dstr = QString("Adding resource to [%1]: name=[%2], status=[%3]\n").arg(j.s()).arg(j.resource()).arg(status2txt(i.status));
378
 
                                pdb(DEBUG_JABBER, dstr);
379
 
                        }
380
 
                        else {
381
 
                                QString dstr;
382
 
                                dstr = QString("Updating resource to [%1]: name=[%2], status=[%3]\n").arg(j.s()).arg(j.resource()).arg(status2txt(i.status));
383
 
                                pdb(DEBUG_JABBER, dstr);
384
 
                        }
385
 
 
386
 
                        if(!i.songTitle.isEmpty())
387
 
                                pdb(DEBUG_JABBER, QString("Listening to: %1\n").arg(i.songTitle));
388
 
 
389
 
                        r->status = i.status;
390
 
                        r->statusString = i.statusString;
391
 
                        r->priority = i.priority;
392
 
                        r->songTitle = i.songTitle;
393
 
                        r->timeStamp = i.timeStamp;
394
 
 
395
 
                        resourceAvailable(j, *r);
396
 
                }
397
 
        }
398
 
}
399
 
 
400
 
void Jabber::pushMessage(const JabMessage &message)
401
 
{
402
 
        pdb(DEBUG_JABBER, QString("[Message]\nFrom: %1\nText: %2\n").arg(message.from.full()).arg(message.body));
403
 
 
404
 
        messageReceived(message);
405
 
}
406
 
 
407
 
void Jabber::processRosterEntryRecv(const JabRosterEntry &item)
408
 
{
409
 
        QString str;
410
 
        if(item.sub == "none")
411
 
                str = "----";
412
 
        if(item.sub == "both")
413
 
                str = "<-->";
414
 
        if(item.sub == "from")
415
 
                str = "  ->";
416
 
        if(item.sub == "to")
417
 
                str = "<-  ";
418
 
        if(item.sub == "remove")
419
 
                str = "xxxx";
420
 
 
421
 
        QString dstr; dstr.sprintf("  %s %-32s\n", str.latin1(), item.jid.latin1());
422
 
        pdb(DEBUG_JABBER, dstr);
423
 
 
424
 
        // remove from contact list
425
 
        if(item.sub == "remove") {
426
 
                JabRosterEntry *entry = roster.findByJid(item.jid);
427
 
                if(entry) {
428
 
                        contactRemove(entry);
429
 
                        roster.remove(entry);
430
 
                }
431
 
        }
432
 
        // update/add to contact list
433
 
        else {
434
 
                JabRosterEntry *entry = roster.findByJid(item.jid);
435
 
                if(entry) {
436
 
                        entry->flagForDelete = FALSE;
437
 
 
438
 
                        // don't process if we have an outgoing entry (FIXME)
439
 
                        bool ok = TRUE;
440
 
                        //JabReq *r = out.findSetRoster(item.jid);
441
 
                        //if(r && !r->active)
442
 
                        //      ok = FALSE;
443
 
 
444
 
                        if(ok) {
445
 
                                // don't copy, only update "roster-related" entries
446
 
                                entry->jid = item.jid;
447
 
                                entry->nick = item.nick;
448
 
                                entry->groups = item.groups;
449
 
                                entry->sub = item.sub;
450
 
                                entry->ask = item.ask;
451
 
 
452
 
                                contactChanged(entry);
453
 
                        }
454
 
                }
455
 
                else {
456
 
                        // add the item
457
 
                        JabRosterEntry *newEntry = new JabRosterEntry(item);
458
 
                        roster.add(newEntry);
459
 
 
460
 
                        // signal it
461
 
                        contactNew(newEntry);
462
 
                }
463
 
        }
464
 
}
465
 
 
466
 
void Jabber::login(int status, const QString &statusStr, int priority, bool plain)
467
 
{
468
 
        i_status = status;
469
 
        i_statusString = statusStr;
470
 
        i_priority = priority;
471
 
        usePlain = plain;
472
 
 
473
 
        connType = JABCONN_LOGIN;
474
 
        conn();
475
 
}
476
 
 
477
 
void Jabber::accRegister()
478
 
{
479
 
        connType = JABCONN_REGISTER;
480
 
        conn();
481
 
}
482
 
 
483
 
void Jabber::setPresence(int status, const QString &statusStr, int priority)
484
 
{
485
 
        // if we're currently logging in, alter the login
486
 
        JT_Login *l = (JT_Login*)io.find("JT_Login");
487
 
        if(l) {
488
 
                l->status = status;
489
 
                l->statusString = statusStr;
490
 
                l->priority = priority;
491
 
                return;
492
 
        }
493
 
 
494
 
        // send a presence change
495
 
        JT_Presence *p = new JT_Presence(io.root());
496
 
        connect(p, SIGNAL(receivePresence(int, const QString &)), SLOT(ioPresence(int, const QString &)));
497
 
        p->pres(status, statusStr, priority);
498
 
        p->go();
499
 
}
500
 
 
501
 
void Jabber::setRoster(const QString &jid, const QString &nick, const QString &group)
502
 
{
503
 
        /*JabReq *req = new JabReq(JABREQ_ROSTER);
504
 
        req->action = JABACT_SET;
505
 
        req->jid = jid;
506
 
        req->nick = nick;*/
507
 
 
508
 
        QStringList groups;
509
 
 
510
 
        // see if we have the entry already
511
 
        JabRosterEntry *entry = roster.findByJid(jid);
512
 
        if(entry) {
513
 
                // copy over the groups
514
 
                groups = entry->groups;
515
 
 
516
 
                if(!groups.isEmpty()) {
517
 
                        // new group not the same as the base group?
518
 
                        if(group != groups[0]) {
519
 
                                // nuke the grouplist, and start fresh with just the one group
520
 
                                groups.clear();
521
 
                                if(!group.isEmpty())
522
 
                                        groups.append(group);
523
 
                        }
524
 
                }
525
 
                else {
526
 
                        if(!group.isEmpty()) {
527
 
                                groups.append(group);
528
 
                        }
529
 
                }
530
 
        }
531
 
        else {
532
 
                if(!group.isEmpty())
533
 
                        groups.append(group);
534
 
        }
535
 
 
536
 
        JT_Roster *p = new JT_Roster(queue);
537
 
        p->set(jid, nick, groups);
538
 
        queue->addTask(p);
539
 
 
540
 
        // make the effect happen locally
541
 
        if(v_offlineEnabled) {
542
 
                if(entry) {
543
 
                        JabRosterEntry item( *entry );
544
 
                        item.nick = nick;
545
 
                        item.groups = groups;
546
 
                        processRosterEntryRecv(item);
547
 
                }
548
 
                else {
549
 
                        // FIXME: make new entry?
550
 
                }
551
 
        }
552
 
}
553
 
 
554
 
void Jabber::remove(const QString &jid)
555
 
{
556
 
        JabRosterEntry *entry = roster.findByJid(jid);
557
 
        if(!entry)
558
 
                return;
559
 
 
560
 
        JT_Roster *p = new JT_Roster(io.root());
561
 
        p->remove(entry->jid);
562
 
        p->go();
563
 
 
564
 
        // make the effect happen locally
565
 
        if(v_offlineEnabled) {
566
 
                JabRosterEntry item(*entry);
567
 
                item.sub = "remove";
568
 
                processRosterEntryRecv(item);
569
 
        }
570
 
}
571
 
 
572
 
 
573
 
void Jabber::sendMessage(const JabMessage &msg)
574
 
{
575
 
        JT_Message *p = new JT_Message(io.root(), msg);
576
 
        p->go();
577
 
}
578
 
 
579
 
// FIXME: change these to Jids instead of QString
580
 
void Jabber::subscribe(const QString &to)
581
 
{
582
 
        JT_Presence *p = new JT_Presence(io.root());
583
 
        p->sub(to, JABSUB_SUBSCRIBE);
584
 
        p->go();
585
 
}
586
 
 
587
 
void Jabber::subscribed(const QString &to)
588
 
{
589
 
        JT_Presence *p = new JT_Presence(io.root());
590
 
        p->sub(to, JABSUB_SUBSCRIBED);
591
 
        p->go();
592
 
}
593
 
 
594
 
void Jabber::unsubscribe(const QString &to)
595
 
{
596
 
        JT_Presence *p = new JT_Presence(io.root());
597
 
        p->sub(to, JABSUB_UNSUBSCRIBE);
598
 
        p->go();
599
 
 
600
 
        remove(to);
601
 
}
602
 
 
603
 
void Jabber::unsubscribed(const QString &to)
604
 
{
605
 
        JT_Presence *p = new JT_Presence(io.root());
606
 
        p->sub(to, JABSUB_UNSUBSCRIBED);
607
 
        p->go();
608
 
}
609
 
 
610
 
void Jabber::cancelTransaction(const QString &id)
611
 
{
612
 
        JabTask *j = userTask->findById(id);
613
 
        if(j)
614
 
                j->deleteLater();
615
 
}
616
 
 
617
 
QCString Jabber::encodeXML(const QString &str)
618
 
{
619
 
        QString data(str);
620
 
 
621
 
        data.replace(QRegExp("&"), "&amp;"); // This _must_ come first
622
 
        data.replace(QRegExp("<"), "&lt;");
623
 
        data.replace(QRegExp(">"), "&gt;");
624
 
        data.replace(QRegExp("\""), "&quot;");
625
 
        data.replace(QRegExp("'"), "&apos;");
626
 
 
627
 
        QCString locallyEncoded = data.utf8();
628
 
        return locallyEncoded;
629
 
        //return data;
630
 
}
631
 
 
632
 
void Jabber::insertXml(const QString &str)
633
 
{
634
 
        if(!isConnected()) {
635
 
                pdb(DEBUG_JABBER, "Jabber: can't send Xml unless connected.\n");
636
 
                return;
637
 
        }
638
 
 
639
 
        send(str);
640
 
}
641
 
 
642
 
void Jabber::agentSetStatus(const QString &jid, int x)
643
 
{
644
 
        JabRosterEntry *r = roster.findByJid(jid);
645
 
        if(!r)
646
 
                return;
647
 
 
648
 
        Jid j = r->jid;
649
 
 
650
 
        QString str;
651
 
        if(x == STATUS_OFFLINE)
652
 
                str = QString("<presence to=\"%1\" type='unavailable'/>\n").arg(encodeXML(j.full()));
653
 
        else
654
 
                str = QString("<presence to=\"%1\"/>\n").arg(encodeXML(j.full()));
655
 
 
656
 
        send(str);
657
 
        pdb(DEBUG_JABBER, QString("Jabber: agentSetStatus: [%1] [%2]\n").arg(r->jid).arg(x));
658
 
}
659
 
 
660
 
JabRosterEntry * Jabber::findByJid(const QString &jid)
661
 
{
662
 
        return roster.findByJid(jid);
663
 
}
664
 
 
665
 
void Jabber::setOfflineEnabled(bool x)
666
 
{
667
 
        v_offlineEnabled = x;
668
 
}
669
 
 
670
 
void Jabber::setCurrentRoster(JabRoster *x_roster)
671
 
{
672
 
        roster = *x_roster;
673
 
 
674
 
        //printf("rolo disk begin: [%d]\n", (int)clock() / 1000);
675
 
        // alert the world of the new entries
676
 
        for(JabRosterEntry *i = roster.first(); i; i = roster.next())
677
 
                contactNew(i);
678
 
        //printf("rolo disk end: [%d]\n", (int)clock() / 1000);
679
 
}
680
 
 
681
 
JabRoster *Jabber::getCurrentRoster()
682
 
{
683
 
        return &roster;
684
 
}
685
 
 
686
 
// this signals a delayed error, by putting it in the Qt event loop
687
 
void Jabber::delayedError()
688
 
{
689
 
        QTimer *t = new QTimer(this);
690
 
        connect(t, SIGNAL(timeout()), SLOT(doError()));
691
 
        t->start(0, TRUE);
692
 
}
693
 
 
694
 
void Jabber::doError()
695
 
{
696
 
        error(&err);
697
 
}
698
 
 
699
 
void Jabber::setOLR(const QString &str)
700
 
{
701
 
        /*QStringList list = lineDecodeList(str);
702
 
 
703
 
        for(QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
704
 
                JabReq *req = JabReq::fromString(*it);
705
 
                if(req)
706
 
                        olr.enqueue(req);
707
 
        }*/
708
 
 
709
 
        queue->fromString(str);
710
 
 
711
 
        // update the offline status since we're offline (or we should be, no sane person should call setOLR when online)
712
 
        /*JabUpdate x;
713
 
        x.req = 0;
714
 
        x.pending = olr.numInteresting();
715
 
        statusUpdate(&x);*/
716
 
 
717
 
        JabUpdate x = makeUpdate();
718
 
        statusUpdate(&x);
719
 
}
720
 
 
721
 
QString Jabber::getOLR()
722
 
{
723
 
        /*QStringList list;
724
 
 
725
 
        for(JabReq *req = olr.last(); req; req = olr.prev()) {
726
 
                QString str = req->toString();
727
 
                if(!str.isEmpty())
728
 
                        list.append(str);
729
 
        }
730
 
 
731
 
        return lineEncodeList(list);*/
732
 
 
733
 
        return queue->toString();
734
 
}
735
 
 
736
 
void Jabber::receivePacket(const QDomElement &chunk)
737
 
{
738
 
        io.incomingPacket(chunk);
739
 
}
740
 
 
741
 
void Jabber::ioDone(JabTask *p)
742
 
{
743
 
        if(p->isA("JT_Login")) {
744
 
                if(!p->success()) {
745
 
                        JT_Login *j = (JT_Login *)p;
746
 
                        if(j->type == 0)
747
 
                                err.type = JABERR_AUTH;
748
 
                        else
749
 
                                err.type = JABERR_CREATE;
750
 
                        err.msg = j->errorString();
751
 
 
752
 
                        disc();
753
 
                        //printf("jabber: failed!\n");
754
 
                        doError();
755
 
                        return;
756
 
                }
757
 
                else {
758
 
                        //printf("jabber: success!\n");
759
 
                }
760
 
        }
761
 
        else if(p->isA("JT_Register")) {
762
 
                JT_Register *r = (JT_Register *)p;
763
 
                bool b = r->success();
764
 
                QString err = r->errorString();
765
 
                r->deleteLater();
766
 
                accRegisterFinished(b, err);
767
 
                return;
768
 
        }
769
 
 
770
 
        //printf("jabber: deleting task\n");
771
 
        p->deleteLater();
772
 
 
773
 
        doUpdate();
774
 
}
775
 
 
776
 
void Jabber::ioOutgoingPacket(const QDomElement &x)
777
 
{
778
 
        stream.sendPacket(x);
779
 
}
780
 
 
781
 
JabUpdate Jabber::makeUpdate()
782
 
{
783
 
        QString str;
784
 
 
785
 
        if(isActive()) {
786
 
                JabTask *j;
787
 
                int x;
788
 
 
789
 
                // are we connected yet?
790
 
                if(!stream.isConnected())
791
 
                        str = tr("Connecting...");
792
 
                // so we must be logging in then
793
 
                else if((j = io.find("JT_Login")) && !j->isDone()) {
794
 
                        JT_Login *l = (JT_Login *)j;
795
 
                        if(l->reg)
796
 
                                str = tr("Registering...");
797
 
                        else if(l->rost)
798
 
                                str = tr("Requesting roster...");
799
 
                        else
800
 
                                str = tr("Authorizing...");
801
 
                }
802
 
                // waiting for outgoing roster requests to process?
803
 
                else if(queue->count() > 0) {
804
 
                        str = tr("Updating Roster...");
805
 
                }
806
 
                // some other type of request somewhere?
807
 
                else if((x = notSpecial()) > 0) {
808
 
                        str = tr("Awaiting response...");
809
 
                        //printf("notspecial = [%d]\n", x);
810
 
                }
811
 
                else {
812
 
                        str = tr("Connected.");
813
 
                }
814
 
        }
815
 
        else {
816
 
                if(queue->count() > 0)
817
 
                        str = tr("Requests pending.");
818
 
                else
819
 
                        str = tr("Not connected.");
820
 
        }
821
 
 
822
 
        JabUpdate x;
823
 
        x.str = str;
824
 
        x.queuePending = queue->count();
825
 
        return x;
826
 
}
827
 
 
828
 
JabUpdate Jabber::getJU()
829
 
{
830
 
        return makeUpdate();
831
 
}
832
 
 
833
 
void Jabber::doUpdate()
834
 
{
835
 
        JabUpdate x = makeUpdate();
836
 
        statusUpdate(&x);
837
 
}
838
 
 
839
 
int Jabber::notSpecial()
840
 
{
841
 
        int total = 0;
842
 
 
843
 
        // count the root
844
 
        const QObjectList *p = io.root()->children();
845
 
        if(!p)
846
 
                return total;
847
 
        QObjectListIt it(*p);
848
 
        for(JabTask *j; (j = (JabTask *)it.current()); ++it) {
849
 
                if(j->isA("JT_Login") || j->isA("JT_Queue") || j->isDone() || j->isDaemon() || (userTask && j->id() == userTask->id()))
850
 
                        continue;
851
 
                ++total;
852
 
        }
853
 
 
854
 
        // count userTask
855
 
        if(userTask) {
856
 
                const QObjectList *p = userTask->children();
857
 
                if(!p)
858
 
                        return total;
859
 
                QObjectListIt it(*p);
860
 
                for(JabTask *j; (j = (JabTask *)it.current()); ++it) {
861
 
                        if(j->isDone())
862
 
                                continue;
863
 
                        ++total;
864
 
                }
865
 
        }
866
 
 
867
 
        return total;
868
 
}
869
 
 
870
 
 
871
 
/****************************************************************************
872
 
  SHA1 - from a public domain implementation by Steve Reid (steve@edmweb.com)
873
 
****************************************************************************/
874
 
 
875
 
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
876
 
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15]^block->l[(i+2)&15]^block->l[i&15],1))
877
 
 
878
 
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
879
 
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
880
 
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
881
 
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
882
 
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
883
 
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
884
 
 
885
 
 
886
 
SHA1::SHA1()
887
 
{
888
 
        int wordSize;
889
 
 
890
 
        qSysInfo(&wordSize, &bigEndian);
891
 
}
892
 
 
893
 
unsigned long SHA1::blk0(Q_UINT32 i)
894
 
{
895
 
        if(bigEndian)
896
 
                return block->l[i];
897
 
        else
898
 
                return (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) | (rol(block->l[i],8)&0x00FF00FF));
899
 
}
900
 
 
901
 
// Hash a single 512-bit block. This is the core of the algorithm.
902
 
void SHA1::transform(Q_UINT32 state[5], unsigned char buffer[64])
903
 
{
904
 
        Q_UINT32 a, b, c, d, e;
905
 
 
906
 
        block = (CHAR64LONG16*)buffer;
907
 
 
908
 
        // Copy context->state[] to working vars
909
 
        a = state[0];
910
 
        b = state[1];
911
 
        c = state[2];
912
 
        d = state[3];
913
 
        e = state[4];
914
 
 
915
 
        // 4 rounds of 20 operations each. Loop unrolled.
916
 
        R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
917
 
        R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
918
 
        R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
919
 
        R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
920
 
        R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
921
 
        R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
922
 
        R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
923
 
        R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
924
 
        R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
925
 
        R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
926
 
        R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
927
 
        R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
928
 
        R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
929
 
        R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
930
 
        R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
931
 
        R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
932
 
        R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
933
 
        R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
934
 
        R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
935
 
        R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
936
 
 
937
 
        // Add the working vars back into context.state[]
938
 
        state[0] += a;
939
 
        state[1] += b;
940
 
        state[2] += c;
941
 
        state[3] += d;
942
 
        state[4] += e;
943
 
 
944
 
        // Wipe variables
945
 
        a = b = c = d = e = 0;
946
 
}
947
 
 
948
 
// SHA1Init - Initialize new context
949
 
void SHA1::init(SHA1_CONTEXT* context)
950
 
{
951
 
        // SHA1 initialization constants
952
 
        context->state[0] = 0x67452301;
953
 
        context->state[1] = 0xEFCDAB89;
954
 
        context->state[2] = 0x98BADCFE;
955
 
        context->state[3] = 0x10325476;
956
 
        context->state[4] = 0xC3D2E1F0;
957
 
        context->count[0] = context->count[1] = 0;
958
 
}
959
 
 
960
 
// Run your data through this
961
 
void SHA1::update(SHA1_CONTEXT* context, unsigned char* data, Q_UINT32 len)
962
 
{
963
 
        Q_UINT32 i, j;
964
 
 
965
 
        j = (context->count[0] >> 3) & 63;
966
 
        if((context->count[0] += len << 3) < (len << 3))
967
 
                context->count[1]++;
968
 
 
969
 
        context->count[1] += (len >> 29);
970
 
 
971
 
        if((j + len) > 63) {
972
 
                memcpy(&context->buffer[j], data, (i = 64-j));
973
 
                transform(context->state, context->buffer);
974
 
                for ( ; i + 63 < len; i += 64) {
975
 
                        transform(context->state, &data[i]);
976
 
                }
977
 
                j = 0;
978
 
        }
979
 
        else i = 0;
980
 
        memcpy(&context->buffer[j], &data[i], len - i);
981
 
}
982
 
 
983
 
// Add padding and return the message digest
984
 
void SHA1::final(unsigned char digest[20], SHA1_CONTEXT* context)
985
 
{
986
 
        Q_UINT32 i, j;
987
 
        unsigned char finalcount[8];
988
 
 
989
 
        for (i = 0; i < 8; i++) {
990
 
                finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
991
 
                >> ((3-(i & 3)) * 8) ) & 255);  // Endian independent
992
 
        }
993
 
        update(context, (unsigned char *)"\200", 1);
994
 
        while ((context->count[0] & 504) != 448) {
995
 
                update(context, (unsigned char *)"\0", 1);
996
 
        }
997
 
        update(context, finalcount, 8);  // Should cause a transform()
998
 
        for (i = 0; i < 20; i++) {
999
 
                digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
1000
 
        }
1001
 
 
1002
 
        // Wipe variables
1003
 
        i = j = 0;
1004
 
        memset(context->buffer, 0, 64);
1005
 
        memset(context->state, 0, 20);
1006
 
        memset(context->count, 0, 8);
1007
 
        memset(&finalcount, 0, 8);
1008
 
}
1009
 
 
1010
 
 
1011
 
/* static */ QString SHA1::digest(QString in)
1012
 
{
1013
 
        SHA1_CONTEXT context;
1014
 
        unsigned char digest[20];
1015
 
 
1016
 
        SHA1 s;
1017
 
        QCString data = in.latin1();
1018
 
 
1019
 
        s.init(&context);
1020
 
        s.update(&context, (unsigned char *)data.data(), (unsigned int)data.length());
1021
 
        s.final(digest, &context);
1022
 
 
1023
 
        QString out;
1024
 
        for(int n = 0; n < 20; ++n) {
1025
 
                QString str;
1026
 
                str.sprintf("%02x", digest[n]);
1027
 
                out.append(str);
1028
 
        }
1029
 
 
1030
 
        return out;
1031
 
}