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

« back to all changes in this revision

Viewing changes to iris/jabber/s5b.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
 * s5b.cpp - direct connection protocol via tcp
 
3
 * Copyright (C) 2003  Justin Karneges
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2.1 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 */
 
20
 
 
21
#include"s5b.h"
 
22
 
 
23
#include<qtimer.h>
 
24
#include<qguardedptr.h>
 
25
#include<stdlib.h>
 
26
#include<qca.h>
 
27
#include"xmpp_xmlcommon.h"
 
28
#include"socks.h"
 
29
 
 
30
#define MAXSTREAMHOSTS 5
 
31
 
 
32
//#define S5B_DEBUG
 
33
 
 
34
namespace XMPP {
 
35
 
 
36
static QString makeKey(const QString &sid, const Jid &initiator, const Jid &target)
 
37
{
 
38
        QString str = sid + initiator.full() + target.full();
 
39
        return QCA::SHA1::hashToString(str.utf8());
 
40
}
 
41
 
 
42
static bool haveHost(const StreamHostList &list, const Jid &j)
 
43
{
 
44
        for(StreamHostList::ConstIterator it = list.begin(); it != list.end(); ++it) {
 
45
                if((*it).jid().compare(j))
 
46
                        return true;
 
47
        }
 
48
        return false;
 
49
}
 
50
 
 
51
class S5BManager::Item : public QObject
 
52
{
 
53
        Q_OBJECT
 
54
public:
 
55
        enum { Idle, Initiator, Target, Active };
 
56
        enum { ErrRefused, ErrConnect, ErrWrongHost, ErrProxy };
 
57
        enum { Unknown, Fast, NotFast };
 
58
        S5BManager *m;
 
59
        int state;
 
60
        QString sid, key, out_key, out_id, in_id;
 
61
        Jid self, peer;
 
62
        StreamHostList in_hosts;
 
63
        JT_S5B *task, *proxy_task;
 
64
        SocksClient *client, *client_out;
 
65
        S5BConnector *conn, *proxy_conn;
 
66
        bool wantFast;
 
67
        StreamHost proxy;
 
68
        int targetMode; // initiator sets this once it figures it out
 
69
        bool fast; // target sets this
 
70
        bool activated;
 
71
        bool lateProxy;
 
72
        bool connSuccess;
 
73
        bool localFailed, remoteFailed;
 
74
        bool allowIncoming;
 
75
        int statusCode;
 
76
 
 
77
        Item(S5BManager *manager);
 
78
        ~Item();
 
79
 
 
80
        void reset();
 
81
        void startInitiator(const QString &_sid, const Jid &_self, const Jid &_peer, bool fast);
 
82
        void startTarget(const QString &_sid, const Jid &_self, const Jid &_peer, const StreamHostList &hosts, const QString &iq_id, bool fast);
 
83
        void handleFast(const StreamHostList &hosts, const QString &iq_id);
 
84
 
 
85
        void doOutgoing();
 
86
        void doIncoming();
 
87
        void setIncomingClient(SocksClient *sc);
 
88
 
 
89
signals:
 
90
        void accepted();
 
91
        void tryingHosts(const StreamHostList &list);
 
92
        void proxyConnect();
 
93
        void waitingForActivation();
 
94
        void connected();
 
95
        void error(int);
 
96
 
 
97
private slots:
 
98
        void jt_finished();
 
99
        void conn_result(bool b);
 
100
        void proxy_result(bool b);
 
101
        void proxy_finished();
 
102
        void sc_readyRead();
 
103
        void sc_bytesWritten(int);
 
104
        void sc_error(int);
 
105
 
 
106
private:
 
107
        void doConnectError();
 
108
        void tryActivation();
 
109
        void checkForActivation();
 
110
        void checkFailure();
 
111
        void finished();
 
112
};
 
113
 
 
114
//----------------------------------------------------------------------------
 
115
// S5BConnection
 
116
//----------------------------------------------------------------------------
 
117
class S5BConnection::Private
 
118
{
 
119
public:
 
120
        S5BManager *m;
 
121
        SocksClient *sc;
 
122
        int state;
 
123
        Jid peer;
 
124
        QString sid;
 
125
        bool remote;
 
126
        bool switched;
 
127
        bool reuseme;
 
128
        bool notifyRead, notifyClose;
 
129
        int id;
 
130
        S5BRequest req;
 
131
        Jid proxy;
 
132
};
 
133
 
 
134
static int id_conn = 0;
 
135
static int num_conn = 0;
 
136
 
 
137
S5BConnection::S5BConnection(S5BManager *m, QObject *parent)
 
138
:ByteStream(parent)
 
139
{
 
140
        d = new Private;
 
141
        d->m = m;
 
142
        d->sc = 0;
 
143
 
 
144
        ++num_conn;
 
145
        d->id = id_conn++;
 
146
#ifdef S5B_DEBUG
 
147
        printf("S5BConnection[%d]: constructing, count=%d, %p\n", d->id, num_conn, this);
 
148
#endif
 
149
 
 
150
        reset();
 
151
}
 
152
 
 
153
S5BConnection::~S5BConnection()
 
154
{
 
155
        reset(true);
 
156
 
 
157
        --num_conn;
 
158
#ifdef S5B_DEBUG
 
159
        printf("S5BConnection[%d]: destructing, count=%d\n", d->id, num_conn);
 
160
#endif
 
161
 
 
162
        delete d;
 
163
}
 
164
 
 
165
void S5BConnection::reset(bool clear)
 
166
{
 
167
        d->m->con_unlink(this);
 
168
        if(clear && d->sc) {
 
169
                delete d->sc;
 
170
                d->sc = 0;
 
171
        }
 
172
        d->state = Idle;
 
173
        d->peer = Jid();
 
174
        d->sid = QString();
 
175
        d->remote = false;
 
176
        d->switched = false;
 
177
        d->reuseme = false;
 
178
        d->notifyRead = false;
 
179
        d->notifyClose = false;
 
180
}
 
181
 
 
182
Jid S5BConnection::proxy() const
 
183
{
 
184
        return d->proxy;
 
185
}
 
186
 
 
187
void S5BConnection::setProxy(const Jid &proxy)
 
188
{
 
189
        d->proxy = proxy;
 
190
}
 
191
 
 
192
void S5BConnection::connectToJid(const Jid &peer, const QString &sid)
 
193
{
 
194
        reset(true);
 
195
        if(!d->m->isAcceptableSID(peer, sid))
 
196
                return;
 
197
 
 
198
        d->peer = peer;
 
199
        d->sid = sid;
 
200
        d->state = Requesting;
 
201
#ifdef S5B_DEBUG
 
202
        printf("S5BConnection[%d]: connecting %s [%s]\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
203
#endif
 
204
        d->m->con_connect(this);
 
205
}
 
206
 
 
207
void S5BConnection::accept()
 
208
{
 
209
        if(d->state != WaitingForAccept)
 
210
                return;
 
211
 
 
212
        d->state = Connecting;
 
213
#ifdef S5B_DEBUG
 
214
        printf("S5BConnection[%d]: accepting %s [%s]\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
215
#endif
 
216
        d->m->con_accept(this);
 
217
}
 
218
 
 
219
void S5BConnection::close()
 
220
{
 
221
        if(d->state == Idle)
 
222
                return;
 
223
 
 
224
        if(d->state == WaitingForAccept)
 
225
                d->m->con_reject(this);
 
226
        else if(d->state == Active)
 
227
                d->sc->close();
 
228
#ifdef S5B_DEBUG
 
229
        printf("S5BConnection[%d]: closing %s [%s]\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
230
#endif
 
231
        reset();
 
232
}
 
233
 
 
234
Jid S5BConnection::peer() const
 
235
{
 
236
        return d->peer;
 
237
}
 
238
 
 
239
QString S5BConnection::sid() const
 
240
{
 
241
        return d->sid;
 
242
}
 
243
 
 
244
bool S5BConnection::isRemote() const
 
245
{
 
246
        return d->remote;
 
247
}
 
248
 
 
249
int S5BConnection::state() const
 
250
{
 
251
        return d->state;
 
252
}
 
253
 
 
254
bool S5BConnection::isOpen() const
 
255
{
 
256
        if(d->state == Active)
 
257
                return true;
 
258
        else
 
259
                return false;
 
260
}
 
261
 
 
262
void S5BConnection::write(const QByteArray &buf)
 
263
{
 
264
        if(d->state == Active)
 
265
                d->sc->write(buf);
 
266
}
 
267
 
 
268
QByteArray S5BConnection::read(int bytes)
 
269
{
 
270
        if(d->sc)
 
271
                return d->sc->read(bytes);
 
272
        else
 
273
                return QByteArray();
 
274
}
 
275
 
 
276
int S5BConnection::bytesAvailable() const
 
277
{
 
278
        if(d->sc)
 
279
                return d->sc->bytesAvailable();
 
280
        else
 
281
                return 0;
 
282
}
 
283
 
 
284
int S5BConnection::bytesToWrite() const
 
285
{
 
286
        if(d->state == Active)
 
287
                return d->sc->bytesToWrite();
 
288
        else
 
289
                return 0;
 
290
}
 
291
 
 
292
void S5BConnection::man_waitForAccept(const S5BRequest &r)
 
293
{
 
294
        d->state = WaitingForAccept;
 
295
        d->remote = true;
 
296
        d->req = r;
 
297
        d->peer = r.from;
 
298
        d->sid = r.sid;
 
299
}
 
300
 
 
301
void S5BConnection::man_clientReady(SocksClient *sc)
 
302
{
 
303
        d->sc = sc;
 
304
        connect(d->sc, SIGNAL(connectionClosed()), SLOT(sc_connectionClosed()));
 
305
        connect(d->sc, SIGNAL(delayedCloseFinished()), SLOT(sc_delayedCloseFinished()));
 
306
        connect(d->sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
307
        connect(d->sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
308
        connect(d->sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
309
 
 
310
        d->state = Active;
 
311
#ifdef S5B_DEBUG
 
312
        printf("S5BConnection[%d]: %s [%s] <<< success >>>\n", d->id, d->peer.full().latin1(), d->sid.latin1());
 
313
#endif
 
314
 
 
315
        // bytes already in the stream?
 
316
        if(d->sc->bytesAvailable()) {
 
317
#ifdef S5B_DEBUG
 
318
                printf("Stream has %d bytes in it.\n", d->sc->bytesAvailable());
 
319
#endif
 
320
                d->notifyRead = true;
 
321
        }
 
322
        // closed before it got here?
 
323
        if(!d->sc->isOpen()) {
 
324
#ifdef S5B_DEBUG
 
325
                printf("Stream was closed before S5B request finished?\n");
 
326
#endif
 
327
                d->notifyClose = true;
 
328
        }
 
329
        if(d->notifyRead || d->notifyClose)
 
330
                QTimer::singleShot(0, this, SLOT(doPending()));
 
331
        connected();
 
332
}
 
333
 
 
334
void S5BConnection::doPending()
 
335
{
 
336
        if(d->notifyRead) {
 
337
                if(d->notifyClose)
 
338
                        QTimer::singleShot(0, this, SLOT(doPending()));
 
339
                sc_readyRead();
 
340
        }
 
341
        else if(d->notifyClose)
 
342
                sc_connectionClosed();
 
343
}
 
344
 
 
345
void S5BConnection::man_failed(int x)
 
346
{
 
347
        reset(true);
 
348
        if(x == S5BManager::Item::ErrRefused)
 
349
                error(ErrRefused);
 
350
        if(x == S5BManager::Item::ErrConnect)
 
351
                error(ErrConnect);
 
352
        if(x == S5BManager::Item::ErrWrongHost)
 
353
                error(ErrConnect);
 
354
        if(x == S5BManager::Item::ErrProxy)
 
355
                error(ErrProxy);
 
356
}
 
357
 
 
358
void S5BConnection::sc_connectionClosed()
 
359
{
 
360
        // if we have a pending read notification, postpone close
 
361
        if(d->notifyRead) {
 
362
#ifdef S5B_DEBUG
 
363
                printf("closed while pending read\n");
 
364
#endif
 
365
                d->notifyClose = true;
 
366
                return;
 
367
        }
 
368
        d->notifyClose = false;
 
369
        reset();
 
370
        connectionClosed();
 
371
}
 
372
 
 
373
void S5BConnection::sc_delayedCloseFinished()
 
374
{
 
375
        // echo
 
376
        delayedCloseFinished();
 
377
}
 
378
 
 
379
void S5BConnection::sc_readyRead()
 
380
{
 
381
        d->notifyRead = false;
 
382
        // echo
 
383
        readyRead();
 
384
}
 
385
 
 
386
void S5BConnection::sc_bytesWritten(int x)
 
387
{
 
388
        // echo
 
389
        bytesWritten(x);
 
390
}
 
391
 
 
392
void S5BConnection::sc_error(int)
 
393
{
 
394
        reset();
 
395
        error(ErrSocket);
 
396
}
 
397
 
 
398
//----------------------------------------------------------------------------
 
399
// S5BManager
 
400
//----------------------------------------------------------------------------
 
401
class S5BManager::Entry
 
402
{
 
403
public:
 
404
        Entry()
 
405
        {
 
406
                i = 0;
 
407
                query = 0;
 
408
        }
 
409
 
 
410
        ~Entry()
 
411
        {
 
412
                delete query;
 
413
        }
 
414
 
 
415
        S5BConnection *c;
 
416
        Item *i;
 
417
        QString sid;
 
418
        JT_S5B *query;
 
419
        StreamHost proxyInfo;
 
420
};
 
421
 
 
422
class S5BManager::Private
 
423
{
 
424
public:
 
425
        Client *client;
 
426
        S5BServer *serv;
 
427
        QPtrList<Entry> activeList;
 
428
        S5BConnectionList incomingConns;
 
429
        JT_PushS5B *ps;
 
430
};
 
431
 
 
432
S5BManager::S5BManager(Client *parent)
 
433
:QObject(parent)
 
434
{
 
435
        d = new Private;
 
436
        d->client = parent;
 
437
        d->serv = 0;
 
438
        d->activeList.setAutoDelete(true);
 
439
 
 
440
        d->ps = new JT_PushS5B(d->client->rootTask());
 
441
        connect(d->ps, SIGNAL(incoming(const S5BRequest &)), SLOT(ps_incoming(const S5BRequest &)));
 
442
}
 
443
 
 
444
S5BManager::~S5BManager()
 
445
{
 
446
        setServer(0);
 
447
        d->incomingConns.setAutoDelete(true);
 
448
        d->incomingConns.clear();
 
449
        delete d->ps;
 
450
        delete d;
 
451
}
 
452
 
 
453
Client *S5BManager::client() const
 
454
{
 
455
        return d->client;
 
456
}
 
457
 
 
458
S5BServer *S5BManager::server() const
 
459
{
 
460
        return d->serv;
 
461
}
 
462
 
 
463
void S5BManager::setServer(S5BServer *serv)
 
464
{
 
465
        if(d->serv) {
 
466
                d->serv->unlink(this);
 
467
                d->serv = 0;
 
468
        }
 
469
 
 
470
        if(serv) {
 
471
                d->serv = serv;
 
472
                d->serv->link(this);
 
473
        }
 
474
}
 
475
 
 
476
S5BConnection *S5BManager::createConnection()
 
477
{
 
478
        S5BConnection *c = new S5BConnection(this);
 
479
        return c;
 
480
}
 
481
 
 
482
S5BConnection *S5BManager::takeIncoming()
 
483
{
 
484
        if(d->incomingConns.isEmpty())
 
485
                return 0;
 
486
 
 
487
        S5BConnection *c = d->incomingConns.getFirst();
 
488
        d->incomingConns.removeRef(c);
 
489
 
 
490
        // move to activeList
 
491
        Entry *e = new Entry;
 
492
        e->c = c;
 
493
        e->sid = c->d->sid;
 
494
        d->activeList.append(e);
 
495
 
 
496
        return c;
 
497
}
 
498
 
 
499
void S5BManager::ps_incoming(const S5BRequest &req)
 
500
{
 
501
#ifdef S5B_DEBUG
 
502
        printf("S5BManager: incoming from %s\n", req.from.full().latin1());
 
503
#endif
 
504
 
 
505
        bool ok = false;
 
506
        // ensure we don't already have an incoming connection from this peer+sid
 
507
        S5BConnection *c = findIncoming(req.from, req.sid);
 
508
        if(!c) {
 
509
                // do we have an active entry with this sid already?
 
510
                Entry *e = findEntryBySID(req.from, req.sid);
 
511
                if(e) {
 
512
                        if(e->i) {
 
513
                                // loopback
 
514
                                if(req.from.compare(d->client->jid()) && (req.id == e->i->out_id)) {
 
515
#ifdef S5B_DEBUG
 
516
                                        printf("ALLOWED: loopback\n");
 
517
#endif
 
518
                                        ok = true;
 
519
                                }
 
520
                                // allowed by 'fast mode'
 
521
                                else if(e->i->state == Item::Initiator && e->i->targetMode == Item::Unknown) {
 
522
#ifdef S5B_DEBUG
 
523
                                        printf("ALLOWED: fast-mode\n");
 
524
#endif
 
525
                                        e->i->handleFast(req.hosts, req.id);
 
526
                                        return;
 
527
                                }
 
528
                        }
 
529
                }
 
530
                else {
 
531
#ifdef S5B_DEBUG
 
532
                        printf("ALLOWED: we don't have it\n");
 
533
#endif
 
534
                        ok = true;
 
535
                }
 
536
        }
 
537
        if(!ok) {
 
538
                d->ps->respondError(req.from, req.id, 406, "SID in use");
 
539
                return;
 
540
        }
 
541
 
 
542
        // create an incoming connection
 
543
        c = new S5BConnection(this);
 
544
        c->man_waitForAccept(req);
 
545
        d->incomingConns.append(c);
 
546
        incomingReady();
 
547
}
 
548
 
 
549
void S5BManager::doSuccess(const Jid &peer, const QString &id, const Jid &streamHost)
 
550
{
 
551
        d->ps->respondSuccess(peer, id, streamHost);
 
552
}
 
553
 
 
554
void S5BManager::doError(const Jid &peer, const QString &id, int code, const QString &str)
 
555
{
 
556
        d->ps->respondError(peer, id, code, str);
 
557
}
 
558
 
 
559
QString S5BManager::genUniqueSID(const Jid &peer) const
 
560
{
 
561
        // get unused key
 
562
        QString sid;
 
563
        do {
 
564
                sid = "s5b_";
 
565
                for(int i = 0; i < 4; ++i) {
 
566
                        int word = rand() & 0xffff;
 
567
                        for(int n = 0; n < 4; ++n) {
 
568
                                QString s;
 
569
                                s.sprintf("%x", (word >> (n * 4)) & 0xf);
 
570
                                sid.append(s);
 
571
                        }
 
572
                }
 
573
        } while(!isAcceptableSID(peer, sid));
 
574
        return sid;
 
575
}
 
576
 
 
577
bool S5BManager::isAcceptableSID(const Jid &peer, const QString &sid) const
 
578
{
 
579
        QString key = makeKey(sid, d->client->jid(), peer);
 
580
        QString key_out = makeKey(sid, peer, d->client->jid());
 
581
 
 
582
        // if we have a server, then check through it
 
583
        if(d->serv) {
 
584
                if(findServerEntryByHash(key) || findServerEntryByHash(key_out))
 
585
                        return false;
 
586
        }
 
587
        else {
 
588
                if(findEntryByHash(key) || findEntryByHash(key_out))
 
589
                        return false;
 
590
        }
 
591
        return true;
 
592
}
 
593
 
 
594
S5BConnection *S5BManager::findIncoming(const Jid &from, const QString &sid) const
 
595
{
 
596
        QPtrListIterator<S5BConnection> it(d->incomingConns);
 
597
        for(S5BConnection *c; (c = it.current()); ++it) {
 
598
                if(c->d->peer.compare(from) && c->d->sid == sid)
 
599
                        return c;
 
600
        }
 
601
        return 0;
 
602
}
 
603
 
 
604
S5BManager::Entry *S5BManager::findEntry(S5BConnection *c) const
 
605
{
 
606
        QPtrListIterator<Entry> it(d->activeList);
 
607
        for(Entry *e; (e = it.current()); ++it) {
 
608
                if(e->c == c)
 
609
                        return e;
 
610
        }
 
611
        return 0;
 
612
}
 
613
 
 
614
S5BManager::Entry *S5BManager::findEntry(Item *i) const
 
615
{
 
616
        QPtrListIterator<Entry> it(d->activeList);
 
617
        for(Entry *e; (e = it.current()); ++it) {
 
618
                if(e->i == i)
 
619
                        return e;
 
620
        }
 
621
        return 0;
 
622
}
 
623
 
 
624
S5BManager::Entry *S5BManager::findEntryByHash(const QString &key) const
 
625
{
 
626
        QPtrListIterator<Entry> it(d->activeList);
 
627
        for(Entry *e; (e = it.current()); ++it) {
 
628
                if(e->i && e->i->key == key)
 
629
                        return e;
 
630
        }
 
631
        return 0;
 
632
}
 
633
 
 
634
S5BManager::Entry *S5BManager::findEntryBySID(const Jid &peer, const QString &sid) const
 
635
{
 
636
        QPtrListIterator<Entry> it(d->activeList);
 
637
        for(Entry *e; (e = it.current()); ++it) {
 
638
                if(e->i && e->i->peer.compare(peer) && e->sid == sid)
 
639
                        return e;
 
640
        }
 
641
        return 0;
 
642
}
 
643
 
 
644
S5BManager::Entry *S5BManager::findServerEntryByHash(const QString &key) const
 
645
{
 
646
        const QPtrList<S5BManager> &manList = d->serv->managerList();
 
647
        QPtrListIterator<S5BManager> it(manList);
 
648
        for(S5BManager *m; (m = it.current()); ++it) {
 
649
                Entry *e = m->findEntryByHash(key);
 
650
                if(e)
 
651
                        return e;
 
652
        }
 
653
        return 0;
 
654
}
 
655
 
 
656
bool S5BManager::srv_ownsHash(const QString &key) const
 
657
{
 
658
        if(findEntryByHash(key))
 
659
                return true;
 
660
        return false;
 
661
}
 
662
 
 
663
void S5BManager::srv_incomingReady(SocksClient *sc, const QString &key)
 
664
{
 
665
        Entry *e = findEntryByHash(key);
 
666
        if(!e->i->allowIncoming) {
 
667
                sc->requestGrant(false);
 
668
                sc->deleteLater();
 
669
                return;
 
670
        }
 
671
        sc->requestGrant(true);
 
672
        e->i->setIncomingClient(sc);
 
673
}
 
674
 
 
675
void S5BManager::srv_unlink()
 
676
{
 
677
        d->serv = 0;
 
678
}
 
679
 
 
680
void S5BManager::con_connect(S5BConnection *c)
 
681
{
 
682
        if(findEntry(c))
 
683
                return;
 
684
        Entry *e = new Entry;
 
685
        e->c = c;
 
686
        e->sid = c->d->sid;
 
687
        d->activeList.append(e);
 
688
 
 
689
        if(c->d->proxy.isValid()) {
 
690
                queryProxy(e);
 
691
                return;
 
692
        }
 
693
        entryContinue(e);
 
694
}
 
695
 
 
696
void S5BManager::con_accept(S5BConnection *c)
 
697
{
 
698
        Entry *e = findEntry(c);
 
699
        if(!e)
 
700
                return;
 
701
 
 
702
        if(e->c->d->req.fast) {
 
703
                if(targetShouldOfferProxy(e)) {
 
704
                        queryProxy(e);
 
705
                        return;
 
706
                }
 
707
        }
 
708
        entryContinue(e);
 
709
}
 
710
 
 
711
void S5BManager::con_reject(S5BConnection *c)
 
712
{
 
713
        d->ps->respondError(c->d->peer, c->d->req.id, 406, "Not acceptable");
 
714
}
 
715
 
 
716
void S5BManager::con_unlink(S5BConnection *c)
 
717
{
 
718
        Entry *e = findEntry(c);
 
719
        if(!e)
 
720
                return;
 
721
 
 
722
        // active incoming request?  cancel it
 
723
        if(e->i && e->i->conn)
 
724
                d->ps->respondError(e->i->peer, e->i->out_id, 406, "Not acceptable");
 
725
        delete e->i;
 
726
        d->activeList.removeRef(e);
 
727
}
 
728
 
 
729
void S5BManager::item_accepted()
 
730
{
 
731
        Item *i = (Item *)sender();
 
732
        Entry *e = findEntry(i);
 
733
 
 
734
        e->c->accepted(); // signal
 
735
}
 
736
 
 
737
void S5BManager::item_tryingHosts(const StreamHostList &list)
 
738
{
 
739
        Item *i = (Item *)sender();
 
740
        Entry *e = findEntry(i);
 
741
 
 
742
        e->c->tryingHosts(list); // signal
 
743
}
 
744
 
 
745
void S5BManager::item_proxyConnect()
 
746
{
 
747
        Item *i = (Item *)sender();
 
748
        Entry *e = findEntry(i);
 
749
 
 
750
        e->c->proxyConnect(); // signal
 
751
}
 
752
 
 
753
void S5BManager::item_waitingForActivation()
 
754
{
 
755
        Item *i = (Item *)sender();
 
756
        Entry *e = findEntry(i);
 
757
 
 
758
        e->c->waitingForActivation(); // signal
 
759
}
 
760
 
 
761
void S5BManager::item_connected()
 
762
{
 
763
        Item *i = (Item *)sender();
 
764
        Entry *e = findEntry(i);
 
765
 
 
766
        // grab the client
 
767
        SocksClient *client = i->client;
 
768
        i->client = 0;
 
769
 
 
770
        // give it to the connection
 
771
        e->c->man_clientReady(client);
 
772
}
 
773
 
 
774
void S5BManager::item_error(int x)
 
775
{
 
776
        Item *i = (Item *)sender();
 
777
        Entry *e = findEntry(i);
 
778
 
 
779
        e->c->man_failed(x);
 
780
}
 
781
 
 
782
void S5BManager::entryContinue(Entry *e)
 
783
{
 
784
        e->i = new Item(this);
 
785
        e->i->proxy = e->proxyInfo;
 
786
 
 
787
        connect(e->i, SIGNAL(accepted()), SLOT(item_accepted()));
 
788
        connect(e->i, SIGNAL(tryingHosts(const StreamHostList &)), SLOT(item_tryingHosts(const StreamHostList &)));
 
789
        connect(e->i, SIGNAL(proxyConnect()), SLOT(item_proxyConnect()));
 
790
        connect(e->i, SIGNAL(waitingForActivation()), SLOT(item_waitingForActivation()));
 
791
        connect(e->i, SIGNAL(connected()), SLOT(item_connected()));
 
792
        connect(e->i, SIGNAL(error(int)), SLOT(item_error(int)));
 
793
 
 
794
        if(e->c->isRemote()) {
 
795
                const S5BRequest &req = e->c->d->req;
 
796
                e->i->startTarget(e->sid, d->client->jid(), e->c->d->peer, req.hosts, req.id, req.fast);
 
797
        }
 
798
        else {
 
799
                e->i->startInitiator(e->sid, d->client->jid(), e->c->d->peer, true);
 
800
                e->c->requesting(); // signal
 
801
        }
 
802
}
 
803
 
 
804
void S5BManager::queryProxy(Entry *e)
 
805
{
 
806
        QGuardedPtr<QObject> self = this;
 
807
        e->c->proxyQuery(); // signal
 
808
        if(!self)
 
809
                return;
 
810
 
 
811
#ifdef S5B_DEBUG
 
812
        printf("querying proxy: [%s]\n", e->c->d->proxy.full().latin1());
 
813
#endif
 
814
        e->query = new JT_S5B(d->client->rootTask());
 
815
        connect(e->query, SIGNAL(finished()), SLOT(query_finished()));
 
816
        e->query->requestProxyInfo(e->c->d->proxy);
 
817
        e->query->go(true);
 
818
}
 
819
 
 
820
void S5BManager::query_finished()
 
821
{
 
822
        JT_S5B *query = (JT_S5B *)sender();
 
823
        Entry *e;
 
824
        bool found = false;
 
825
        QPtrListIterator<Entry> it(d->activeList);
 
826
        for(; (e = it.current()); ++it) {
 
827
                if(e->query == query) {
 
828
                        found = true;
 
829
                        break;
 
830
                }
 
831
        }
 
832
        if(!found)
 
833
                return;
 
834
        e->query = 0;
 
835
 
 
836
#ifdef S5B_DEBUG
 
837
        printf("query finished: ");
 
838
#endif
 
839
        if(query->success()) {
 
840
                e->proxyInfo = query->proxyInfo();
 
841
#ifdef S5B_DEBUG
 
842
                printf("host/ip=[%s] port=[%d]\n", e->proxyInfo.host().latin1(), e->proxyInfo.port());
 
843
#endif
 
844
        }
 
845
        else {
 
846
#ifdef S5B_DEBUG
 
847
                printf("fail\n");
 
848
#endif
 
849
        }
 
850
 
 
851
        QGuardedPtr<QObject> self = this;
 
852
        e->c->proxyResult(query->success()); // signal
 
853
        if(!self)
 
854
                return;
 
855
 
 
856
        entryContinue(e);
 
857
}
 
858
 
 
859
bool S5BManager::targetShouldOfferProxy(Entry *e)
 
860
{
 
861
        if(!e->c->d->proxy.isValid())
 
862
                return false;
 
863
 
 
864
        // if target, don't offer any proxy if the initiator already did
 
865
        const StreamHostList &hosts = e->c->d->req.hosts;
 
866
        for(StreamHostList::ConstIterator it = hosts.begin(); it != hosts.end(); ++it) {
 
867
                if((*it).isProxy())
 
868
                        return false;
 
869
        }
 
870
 
 
871
        // ensure we don't offer the same proxy as the initiator
 
872
        if(haveHost(hosts, e->c->d->proxy))
 
873
                return false;
 
874
 
 
875
        return true;
 
876
}
 
877
 
 
878
//----------------------------------------------------------------------------
 
879
// S5BManager::Item
 
880
//----------------------------------------------------------------------------
 
881
S5BManager::Item::Item(S5BManager *manager) : QObject(0)
 
882
{
 
883
        m = manager;
 
884
        task = 0;
 
885
        proxy_task = 0;
 
886
        conn = 0;
 
887
        proxy_conn = 0;
 
888
        client = 0;
 
889
        client_out = 0;
 
890
        reset();
 
891
}
 
892
 
 
893
S5BManager::Item::~Item()
 
894
{
 
895
        reset();
 
896
}
 
897
 
 
898
void S5BManager::Item::reset()
 
899
{
 
900
        delete task;
 
901
        task = 0;
 
902
 
 
903
        delete proxy_task;
 
904
        proxy_task = 0;
 
905
 
 
906
        delete conn;
 
907
        conn = 0;
 
908
 
 
909
        delete proxy_conn;
 
910
        proxy_conn = 0;
 
911
 
 
912
        delete client;
 
913
        client = 0;
 
914
 
 
915
        delete client_out;
 
916
        client_out = 0;
 
917
 
 
918
        state = Idle;
 
919
        wantFast = false;
 
920
        targetMode = Unknown;
 
921
        fast = false;
 
922
        activated = false;
 
923
        lateProxy = false;
 
924
        connSuccess = false;
 
925
        localFailed = false;
 
926
        remoteFailed = false;
 
927
        allowIncoming = false;
 
928
}
 
929
 
 
930
void S5BManager::Item::startInitiator(const QString &_sid, const Jid &_self, const Jid &_peer, bool fast)
 
931
{
 
932
        sid = _sid;
 
933
        self = _self;
 
934
        peer = _peer;
 
935
        key = makeKey(sid, self, peer);
 
936
        out_key = makeKey(sid, peer, self);
 
937
        wantFast = fast;
 
938
 
 
939
#ifdef S5B_DEBUG
 
940
        printf("S5BManager::Item initiating request %s [%s]\n", peer.full().latin1(), sid.latin1());
 
941
#endif
 
942
        state = Initiator;
 
943
        doOutgoing();
 
944
}
 
945
 
 
946
void S5BManager::Item::startTarget(const QString &_sid, const Jid &_self, const Jid &_peer, const StreamHostList &hosts, const QString &iq_id, bool _fast)
 
947
{
 
948
        sid = _sid;
 
949
        peer = _peer;
 
950
        self = _self;
 
951
        in_hosts = hosts;
 
952
        in_id = iq_id;
 
953
        fast = _fast;
 
954
        key = makeKey(sid, self, peer);
 
955
        out_key = makeKey(sid, peer, self);
 
956
 
 
957
#ifdef S5B_DEBUG
 
958
        printf("S5BManager::Item incoming request %s [%s]\n", peer.full().latin1(), sid.latin1());
 
959
#endif
 
960
        state = Target;
 
961
        if(fast)
 
962
                doOutgoing();
 
963
        doIncoming();
 
964
}
 
965
 
 
966
void S5BManager::Item::handleFast(const StreamHostList &hosts, const QString &iq_id)
 
967
{
 
968
        targetMode = Fast;
 
969
 
 
970
        QGuardedPtr<QObject> self = this;
 
971
        accepted();
 
972
        if(!self)
 
973
                return;
 
974
 
 
975
        // if we already have a stream, then bounce this request
 
976
        if(client) {
 
977
                m->doError(peer, iq_id, 406, "Not acceptable");
 
978
        }
 
979
        else {
 
980
                in_hosts = hosts;
 
981
                in_id = iq_id;
 
982
                doIncoming();
 
983
        }
 
984
}
 
985
 
 
986
void S5BManager::Item::doOutgoing()
 
987
{
 
988
        StreamHostList hosts;
 
989
        S5BServer *serv = m->server();
 
990
        if(serv && serv->isActive() && !haveHost(in_hosts, m->client()->jid())) {
 
991
                QStringList hostList = serv->hostList();
 
992
                for(QStringList::ConstIterator it = hostList.begin(); it != hostList.end(); ++it) {
 
993
                        StreamHost h;
 
994
                        h.setJid(m->client()->jid());
 
995
                        h.setHost(*it);
 
996
                        h.setPort(serv->port());
 
997
                        hosts += h;
 
998
                }
 
999
        }
 
1000
 
 
1001
        // if the proxy is valid, then it's ok to add (the manager already ensured that it doesn't conflict)
 
1002
        if(proxy.jid().isValid())
 
1003
                hosts += proxy;
 
1004
 
 
1005
        // if we're the target and we have no streamhosts of our own, then don't even bother with fast-mode
 
1006
        if(state == Target && hosts.isEmpty()) {
 
1007
                fast = false;
 
1008
                return;
 
1009
        }
 
1010
 
 
1011
        allowIncoming = true;
 
1012
 
 
1013
        task = new JT_S5B(m->client()->rootTask());
 
1014
        connect(task, SIGNAL(finished()), SLOT(jt_finished()));
 
1015
        task->request(peer, sid, hosts, state == Initiator ? wantFast : false);
 
1016
        out_id = task->id();
 
1017
        task->go(true);
 
1018
}
 
1019
 
 
1020
void S5BManager::Item::doIncoming()
 
1021
{
 
1022
        if(in_hosts.isEmpty()) {
 
1023
                doConnectError();
 
1024
                return;
 
1025
        }
 
1026
 
 
1027
        StreamHostList list;
 
1028
        if(lateProxy) {
 
1029
                // take just the proxy streamhosts
 
1030
                for(StreamHostList::ConstIterator it = in_hosts.begin(); it != in_hosts.end(); ++it) {
 
1031
                        if((*it).isProxy())
 
1032
                                list += *it;
 
1033
                }
 
1034
                lateProxy = false;
 
1035
        }
 
1036
        else {
 
1037
                // only try doing the late proxy trick if using fast mode AND we did not offer a proxy
 
1038
                if((state == Initiator || (state == Target && fast)) && !proxy.jid().isValid()) {
 
1039
                        // take just the non-proxy streamhosts
 
1040
                        bool hasProxies = false;
 
1041
                        for(StreamHostList::ConstIterator it = in_hosts.begin(); it != in_hosts.end(); ++it) {
 
1042
                                if((*it).isProxy())
 
1043
                                        hasProxies = true;
 
1044
                                else
 
1045
                                        list += *it;
 
1046
                        }
 
1047
                        if(hasProxies) {
 
1048
                                lateProxy = true;
 
1049
 
 
1050
                                // no regular streamhosts?  wait for remote error
 
1051
                                if(list.isEmpty())
 
1052
                                        return;
 
1053
                        }
 
1054
                }
 
1055
                else
 
1056
                        list = in_hosts;
 
1057
        }
 
1058
 
 
1059
        conn = new S5BConnector;
 
1060
        connect(conn, SIGNAL(result(bool)), SLOT(conn_result(bool)));
 
1061
 
 
1062
        QGuardedPtr<QObject> self = this;
 
1063
        tryingHosts(list);
 
1064
        if(!self)
 
1065
                return;
 
1066
 
 
1067
        conn->start(list, out_key, lateProxy ? 10 : 30);
 
1068
}
 
1069
 
 
1070
void S5BManager::Item::setIncomingClient(SocksClient *sc)
 
1071
{
 
1072
#ifdef S5B_DEBUG
 
1073
        printf("S5BManager::Item: %s [%s] successful incoming connection\n", peer.full().latin1(), sid.latin1());
 
1074
#endif
 
1075
 
 
1076
        connect(sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
1077
        connect(sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
1078
        connect(sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1079
 
 
1080
        client = sc;
 
1081
        allowIncoming = false;
 
1082
}
 
1083
 
 
1084
void S5BManager::Item::jt_finished()
 
1085
{
 
1086
        JT_S5B *j = task;
 
1087
        task = 0;
 
1088
 
 
1089
#ifdef S5B_DEBUG
 
1090
        printf("jt_finished: state=%s, %s\n", state == Initiator ? "initiator" : "target", j->success() ? "ok" : "fail");
 
1091
#endif
 
1092
 
 
1093
        if(state == Initiator) {
 
1094
                if(targetMode == Unknown) {
 
1095
                        targetMode = NotFast;
 
1096
                        QGuardedPtr<QObject> self = this;
 
1097
                        accepted();
 
1098
                        if(!self)
 
1099
                                return;
 
1100
                }
 
1101
        }
 
1102
 
 
1103
        // if we've already reported successfully connecting to them, then this response doesn't matter
 
1104
        if(state == Initiator && connSuccess) {
 
1105
                tryActivation();
 
1106
                return;
 
1107
        }
 
1108
 
 
1109
        if(j->success()) {
 
1110
                // stop connecting out
 
1111
                if(conn || lateProxy) {
 
1112
                        delete conn;
 
1113
                        conn = 0;
 
1114
                        doConnectError();
 
1115
                }
 
1116
 
 
1117
                Jid streamHost = j->streamHostUsed();
 
1118
                // they connected to us?
 
1119
                if(streamHost.compare(self)) {
 
1120
                        if(client) {
 
1121
                                if(state == Initiator)
 
1122
                                        tryActivation();
 
1123
                                else
 
1124
                                        checkForActivation();
 
1125
                        }
 
1126
                        else {
 
1127
#ifdef S5B_DEBUG
 
1128
                                printf("S5BManager::Item %s claims to have connected to us, but we don't see this\n", peer.full().latin1());
 
1129
#endif
 
1130
                                reset();
 
1131
                                error(ErrWrongHost);
 
1132
                        }
 
1133
                }
 
1134
                else if(streamHost.compare(proxy.jid())) {
 
1135
                        // toss out any direct incoming, since it won't be used
 
1136
                        delete client;
 
1137
                        client = 0;
 
1138
                        allowIncoming = false;
 
1139
 
 
1140
#ifdef S5B_DEBUG
 
1141
                        printf("attempting to connect to proxy\n");
 
1142
#endif
 
1143
                        // connect to the proxy
 
1144
                        proxy_conn = new S5BConnector;
 
1145
                        connect(proxy_conn, SIGNAL(result(bool)), SLOT(proxy_result(bool)));
 
1146
                        StreamHostList list;
 
1147
                        list += proxy;
 
1148
 
 
1149
                        QGuardedPtr<QObject> self = this;
 
1150
                        proxyConnect();
 
1151
                        if(!self)
 
1152
                                return;
 
1153
 
 
1154
                        proxy_conn->start(list, key, 30);
 
1155
                }
 
1156
                else {
 
1157
#ifdef S5B_DEBUG
 
1158
                        printf("S5BManager::Item %s claims to have connected to a streamhost we never offered\n", peer.full().latin1());
 
1159
#endif
 
1160
                        reset();
 
1161
                        error(ErrWrongHost);
 
1162
                }
 
1163
        }
 
1164
        else {
 
1165
#ifdef S5B_DEBUG
 
1166
                printf("S5BManager::Item %s [%s] error\n", peer.full().latin1(), sid.latin1());
 
1167
#endif
 
1168
                remoteFailed = true;
 
1169
                statusCode = j->statusCode();
 
1170
 
 
1171
                if(lateProxy) {
 
1172
                        if(!conn)
 
1173
                                doIncoming();
 
1174
                }
 
1175
                else {
 
1176
                        // if connSuccess is true at this point, then we're a Target
 
1177
                        if(connSuccess)
 
1178
                                checkForActivation();
 
1179
                        else
 
1180
                                checkFailure();
 
1181
                }
 
1182
        }
 
1183
}
 
1184
 
 
1185
void S5BManager::Item::conn_result(bool b)
 
1186
{
 
1187
        if(b) {
 
1188
                SocksClient *sc = conn->takeClient();
 
1189
                StreamHost h = conn->streamHostUsed();
 
1190
                delete conn;
 
1191
                conn = 0;
 
1192
                connSuccess = true;
 
1193
 
 
1194
#ifdef S5B_DEBUG
 
1195
                printf("S5BManager::Item: %s [%s] successful outgoing connection\n", peer.full().latin1(), sid.latin1());
 
1196
#endif
 
1197
 
 
1198
                connect(sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
1199
                connect(sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
1200
                connect(sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1201
 
 
1202
                m->doSuccess(peer, in_id, h.jid());
 
1203
 
 
1204
                // if the first batch works, don't try proxy
 
1205
                lateProxy = false;
 
1206
 
 
1207
                // if initiator, run with this one
 
1208
                if(state == Initiator) {
 
1209
                        // if we had an incoming one, toss it
 
1210
                        delete client;
 
1211
                        client = sc;
 
1212
                        allowIncoming = false;
 
1213
                        tryActivation();
 
1214
                }
 
1215
                else {
 
1216
                        client_out = sc;
 
1217
                        checkForActivation();
 
1218
                }
 
1219
        }
 
1220
        else {
 
1221
                delete conn;
 
1222
                conn = 0;
 
1223
 
 
1224
                // if we delayed the proxies for later, try now
 
1225
                if(lateProxy) {
 
1226
                        if(remoteFailed)
 
1227
                                doIncoming();
 
1228
                }
 
1229
                else
 
1230
                        doConnectError();
 
1231
        }
 
1232
}
 
1233
 
 
1234
void S5BManager::Item::proxy_result(bool b)
 
1235
{
 
1236
#ifdef S5B_DEBUG
 
1237
        printf("proxy_result: %s\n", b ? "ok" : "fail");
 
1238
#endif
 
1239
        if(b) {
 
1240
                SocksClient *sc = proxy_conn->takeClient();
 
1241
                delete proxy_conn;
 
1242
                proxy_conn = 0;
 
1243
 
 
1244
                connect(sc, SIGNAL(readyRead()), SLOT(sc_readyRead()));
 
1245
                connect(sc, SIGNAL(bytesWritten(int)), SLOT(sc_bytesWritten(int)));
 
1246
                connect(sc, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1247
 
 
1248
                client = sc;
 
1249
 
 
1250
                // activate
 
1251
#ifdef S5B_DEBUG
 
1252
                printf("activating proxy stream\n");
 
1253
#endif
 
1254
                proxy_task = new JT_S5B(m->client()->rootTask());
 
1255
                connect(proxy_task, SIGNAL(finished()), SLOT(proxy_finished()));
 
1256
                proxy_task->requestActivation(proxy.jid(), sid, peer);
 
1257
                proxy_task->go(true);
 
1258
        }
 
1259
        else {
 
1260
                delete proxy_conn;
 
1261
                proxy_conn = 0;
 
1262
                reset();
 
1263
                error(ErrProxy);
 
1264
        }
 
1265
}
 
1266
 
 
1267
void S5BManager::Item::proxy_finished()
 
1268
{
 
1269
        JT_S5B *j = proxy_task;
 
1270
        proxy_task = 0;
 
1271
 
 
1272
        if(j->success()) {
 
1273
#ifdef S5B_DEBUG
 
1274
                printf("proxy stream activated\n");
 
1275
#endif
 
1276
                if(state == Initiator)
 
1277
                        tryActivation();
 
1278
                else
 
1279
                        checkForActivation();
 
1280
        }
 
1281
        else {
 
1282
                reset();
 
1283
                error(ErrProxy);
 
1284
        }
 
1285
}
 
1286
 
 
1287
void S5BManager::Item::sc_readyRead()
 
1288
{
 
1289
#ifdef S5B_DEBUG
 
1290
        printf("sc_readyRead\n");
 
1291
#endif
 
1292
        // only targets check for activation, and only should do it if there is no pending outgoing iq-set
 
1293
        if(state == Target && !task && !proxy_task)
 
1294
                checkForActivation();
 
1295
}
 
1296
 
 
1297
void S5BManager::Item::sc_bytesWritten(int)
 
1298
{
 
1299
#ifdef S5B_DEBUG
 
1300
        printf("sc_bytesWritten\n");
 
1301
#endif
 
1302
        // this should only happen to the initiator, and should always be 1 byte (the '\r' sent earlier)
 
1303
        finished();
 
1304
}
 
1305
 
 
1306
void S5BManager::Item::sc_error(int)
 
1307
{
 
1308
#ifdef S5B_DEBUG
 
1309
        printf("sc_error\n");
 
1310
#endif
 
1311
        reset();
 
1312
        error(ErrConnect);
 
1313
}
 
1314
 
 
1315
void S5BManager::Item::doConnectError()
 
1316
{
 
1317
        localFailed = true;
 
1318
        m->doError(peer, in_id, 404, "Could not connect to given hosts");
 
1319
        checkFailure();
 
1320
}
 
1321
 
 
1322
void S5BManager::Item::tryActivation()
 
1323
{
 
1324
#ifdef S5B_DEBUG
 
1325
        printf("tryActivation\n");
 
1326
#endif
 
1327
        if(activated) {
 
1328
#ifdef S5B_DEBUG
 
1329
                printf("already activated !?\n");
 
1330
#endif
 
1331
                return;
 
1332
        }
 
1333
 
 
1334
        if(targetMode == NotFast) {
 
1335
#ifdef S5B_DEBUG
 
1336
                printf("tryActivation: NotFast\n");
 
1337
#endif
 
1338
                // nothing to activate, we're done
 
1339
                finished();
 
1340
        }
 
1341
        else if(targetMode == Fast) {
 
1342
                // with fast mode, we don't wait for the iq reply, so delete the task (if any)
 
1343
                delete task;
 
1344
                task = 0;
 
1345
 
 
1346
#ifdef S5B_DEBUG
 
1347
                printf("sending extra CR\n");
 
1348
#endif
 
1349
                // must send [CR] to activate target streamhost
 
1350
                activated = true;
 
1351
                QByteArray a(1);
 
1352
                a[0] = '\r';
 
1353
                client->write(a);
 
1354
        }
 
1355
}
 
1356
 
 
1357
void S5BManager::Item::checkForActivation()
 
1358
{
 
1359
        QPtrList<SocksClient> clientList;
 
1360
        if(client)
 
1361
                clientList.append(client);
 
1362
        if(client_out)
 
1363
                clientList.append(client_out);
 
1364
        QPtrListIterator<SocksClient> it(clientList);
 
1365
        for(SocksClient *sc; (sc = it.current()); ++it) {
 
1366
#ifdef S5B_DEBUG
 
1367
                printf("checking for activation\n");
 
1368
#endif
 
1369
                if(fast) {
 
1370
#ifdef S5B_DEBUG
 
1371
                        printf("need CR\n");
 
1372
#endif
 
1373
                        if(sc->bytesAvailable() >= 1) {
 
1374
                                clientList.removeRef(sc);
 
1375
                                QByteArray a = sc->read(1);
 
1376
                                if(a[0] != '\r') {
 
1377
                                        delete sc;
 
1378
                                        return;
 
1379
                                }
 
1380
                                sc->disconnect(this);
 
1381
                                clientList.setAutoDelete(true);
 
1382
                                clientList.clear();
 
1383
                                client = sc;
 
1384
                                client_out = 0;
 
1385
                                activated = true;
 
1386
#ifdef S5B_DEBUG
 
1387
                                printf("activation success\n");
 
1388
#endif
 
1389
                                break;
 
1390
                        }
 
1391
                }
 
1392
                else {
 
1393
#ifdef S5B_DEBUG
 
1394
                        printf("not fast mode, no need to wait for anything\n");
 
1395
#endif
 
1396
                        clientList.removeRef(sc);
 
1397
                        sc->disconnect(this);
 
1398
                        clientList.setAutoDelete(true);
 
1399
                        clientList.clear();
 
1400
                        client = sc;
 
1401
                        client_out = 0;
 
1402
                        activated = true;
 
1403
                        break;
 
1404
                }
 
1405
        }
 
1406
 
 
1407
        if(activated) {
 
1408
                finished();
 
1409
        }
 
1410
        else {
 
1411
                // only emit waitingForActivation if there is nothing left to do
 
1412
                if((connSuccess || localFailed) && !proxy_task && !proxy_conn)
 
1413
                        waitingForActivation();
 
1414
        }
 
1415
}
 
1416
 
 
1417
void S5BManager::Item::checkFailure()
 
1418
{
 
1419
        bool failed = false;
 
1420
        if(state == Initiator) {
 
1421
                if(remoteFailed) {
 
1422
                        if((localFailed && targetMode == Fast) || targetMode == NotFast)
 
1423
                                failed = true;
 
1424
                }
 
1425
        }
 
1426
        else {
 
1427
                if(localFailed) {
 
1428
                        if((remoteFailed && fast) || !fast)
 
1429
                                failed = true;
 
1430
                }
 
1431
        }
 
1432
 
 
1433
        if(failed) {
 
1434
                if(state == Initiator) {
 
1435
                        reset();
 
1436
                        if(statusCode == 404)
 
1437
                                error(ErrConnect);
 
1438
                        else
 
1439
                                error(ErrRefused);
 
1440
                }
 
1441
                else {
 
1442
                        reset();
 
1443
                        error(ErrConnect);
 
1444
                }
 
1445
        }
 
1446
}
 
1447
 
 
1448
void S5BManager::Item::finished()
 
1449
{
 
1450
        client->disconnect(this);
 
1451
        state = Active;
 
1452
#ifdef S5B_DEBUG
 
1453
        printf("S5BManager::Item %s [%s] linked successfully\n", peer.full().latin1(), sid.latin1());
 
1454
#endif
 
1455
        connected();
 
1456
}
 
1457
 
 
1458
//----------------------------------------------------------------------------
 
1459
// S5BConnector
 
1460
//----------------------------------------------------------------------------
 
1461
class S5BConnector::Item : public QObject
 
1462
{
 
1463
        Q_OBJECT
 
1464
public:
 
1465
        SocksClient *client;
 
1466
        StreamHost host;
 
1467
        QString key;
 
1468
 
 
1469
        Item(const StreamHost &_host, const QString &_key) : QObject(0)
 
1470
        {
 
1471
                host = _host;
 
1472
                key = _key;
 
1473
                client = new SocksClient;
 
1474
                connect(client, SIGNAL(connected()), SLOT(sc_connected()));
 
1475
                connect(client, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1476
        }
 
1477
 
 
1478
        ~Item()
 
1479
        {
 
1480
                delete client;
 
1481
        }
 
1482
 
 
1483
        void start()
 
1484
        {
 
1485
                client->connectToHost(host.host(), host.port(), key, 0);
 
1486
        }
 
1487
 
 
1488
signals:
 
1489
        void result(bool);
 
1490
 
 
1491
private slots:
 
1492
        void sc_connected()
 
1493
        {
 
1494
#ifdef S5B_DEBUG
 
1495
                printf("S5BConnector[%s]: success\n", host.host().latin1());
 
1496
#endif
 
1497
                client->disconnect(this);
 
1498
                result(true);
 
1499
        }
 
1500
 
 
1501
        void sc_error(int)
 
1502
        {
 
1503
#ifdef S5B_DEBUG
 
1504
                printf("S5BConnector[%s]: error\n", host.host().latin1());
 
1505
#endif
 
1506
                delete client;
 
1507
                client = 0;
 
1508
                result(false);
 
1509
        }
 
1510
};
 
1511
 
 
1512
class S5BConnector::Private
 
1513
{
 
1514
public:
 
1515
        SocksClient *active;
 
1516
        QPtrList<Item> itemList;
 
1517
        QString key;
 
1518
        StreamHost activeHost;
 
1519
        QTimer t;
 
1520
};
 
1521
 
 
1522
S5BConnector::S5BConnector(QObject *parent)
 
1523
:QObject(parent)
 
1524
{
 
1525
        d = new Private;
 
1526
        d->active = 0;
 
1527
        d->itemList.setAutoDelete(true);
 
1528
        connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout()));
 
1529
}
 
1530
 
 
1531
S5BConnector::~S5BConnector()
 
1532
{
 
1533
        reset();
 
1534
        delete d;
 
1535
}
 
1536
 
 
1537
void S5BConnector::reset()
 
1538
{
 
1539
        d->t.stop();
 
1540
        delete d->active;
 
1541
        d->active = 0;
 
1542
        d->itemList.clear();
 
1543
}
 
1544
 
 
1545
void S5BConnector::start(const StreamHostList &hosts, const QString &key, int timeout)
 
1546
{
 
1547
        reset();
 
1548
 
 
1549
#ifdef S5B_DEBUG
 
1550
        printf("S5BConnector: starting [%p]!\n", this);
 
1551
#endif
 
1552
        for(StreamHostList::ConstIterator it = hosts.begin(); it != hosts.end(); ++it) {
 
1553
                Item *i = new Item(*it, key);
 
1554
                connect(i, SIGNAL(result(bool)), SLOT(item_result(bool)));
 
1555
                d->itemList.append(i);
 
1556
                i->start();
 
1557
        }
 
1558
        d->t.start(timeout * 1000);
 
1559
}
 
1560
 
 
1561
SocksClient *S5BConnector::takeClient()
 
1562
{
 
1563
        SocksClient *c = d->active;
 
1564
        d->active = 0;
 
1565
        return c;
 
1566
}
 
1567
 
 
1568
StreamHost S5BConnector::streamHostUsed() const
 
1569
{
 
1570
        return d->activeHost;
 
1571
}
 
1572
 
 
1573
void S5BConnector::item_result(bool b)
 
1574
{
 
1575
        Item *i = (Item *)sender();
 
1576
        if(b) {
 
1577
                d->active = i->client;
 
1578
                i->client = 0;
 
1579
                d->activeHost = i->host;
 
1580
                d->itemList.clear();
 
1581
                d->t.stop();
 
1582
#ifdef S5B_DEBUG
 
1583
                printf("S5BConnector: complete! [%p]\n", this);
 
1584
#endif
 
1585
                result(true);
 
1586
        }
 
1587
        else {
 
1588
                d->itemList.removeRef(i);
 
1589
                if(d->itemList.isEmpty()) {
 
1590
                        d->t.stop();
 
1591
#ifdef S5B_DEBUG
 
1592
                        printf("S5BConnector: failed! [%p]\n", this);
 
1593
#endif
 
1594
                        result(false);
 
1595
                }
 
1596
        }
 
1597
}
 
1598
 
 
1599
void S5BConnector::t_timeout()
 
1600
{
 
1601
        reset();
 
1602
#ifdef S5B_DEBUG
 
1603
        printf("S5BConnector: failed! (timeout)\n");
 
1604
#endif
 
1605
        result(false);
 
1606
}
 
1607
 
 
1608
//----------------------------------------------------------------------------
 
1609
// S5BServer
 
1610
//----------------------------------------------------------------------------
 
1611
class S5BServer::Item : public QObject
 
1612
{
 
1613
        Q_OBJECT
 
1614
public:
 
1615
        SocksClient *client;
 
1616
        QString host;
 
1617
        QTimer expire;
 
1618
 
 
1619
        Item(SocksClient *c) : QObject(0)
 
1620
        {
 
1621
                client = c;
 
1622
                connect(client, SIGNAL(incomingMethods(int)), SLOT(sc_incomingMethods(int)));
 
1623
                connect(client, SIGNAL(incomingRequest(const QString &, int)), SLOT(sc_incomingRequest(const QString &, int)));
 
1624
                connect(client, SIGNAL(error(int)), SLOT(sc_error(int)));
 
1625
 
 
1626
                connect(&expire, SIGNAL(timeout()), SLOT(doError()));
 
1627
                resetExpiration();
 
1628
        }
 
1629
 
 
1630
        ~Item()
 
1631
        {
 
1632
                delete client;
 
1633
        }
 
1634
 
 
1635
        void resetExpiration()
 
1636
        {
 
1637
                expire.start(30000);
 
1638
        }
 
1639
 
 
1640
signals:
 
1641
        void result(bool);
 
1642
 
 
1643
private slots:
 
1644
        void doError()
 
1645
        {
 
1646
                expire.stop();
 
1647
                delete client;
 
1648
                client = 0;
 
1649
                result(false);
 
1650
        }
 
1651
 
 
1652
        void sc_incomingMethods(int m)
 
1653
        {
 
1654
                if(m & SocksClient::AuthNone)
 
1655
                        client->chooseMethod(SocksClient::AuthNone);
 
1656
                else
 
1657
                        doError();
 
1658
        }
 
1659
 
 
1660
        void sc_incomingRequest(const QString &_host, int port)
 
1661
        {
 
1662
                if(port == 0) {
 
1663
                        host = _host;
 
1664
                        client->disconnect(this);
 
1665
                        result(true);
 
1666
                }
 
1667
                else
 
1668
                        doError();
 
1669
        }
 
1670
 
 
1671
        void sc_error(int)
 
1672
        {
 
1673
                doError();
 
1674
        }
 
1675
};
 
1676
 
 
1677
class S5BServer::Private
 
1678
{
 
1679
public:
 
1680
        SocksServer serv;
 
1681
        QStringList hostList;
 
1682
        QPtrList<S5BManager> manList;
 
1683
        QPtrList<Item> itemList;
 
1684
};
 
1685
 
 
1686
S5BServer::S5BServer(QObject *parent)
 
1687
:QObject(parent)
 
1688
{
 
1689
        d = new Private;
 
1690
        d->itemList.setAutoDelete(true);
 
1691
        connect(&d->serv, SIGNAL(incomingReady()), SLOT(ss_incomingReady()));
 
1692
}
 
1693
 
 
1694
S5BServer::~S5BServer()
 
1695
{
 
1696
        unlinkAll();
 
1697
        delete d;
 
1698
}
 
1699
 
 
1700
bool S5BServer::isActive() const
 
1701
{
 
1702
        return d->serv.isActive();
 
1703
}
 
1704
 
 
1705
bool S5BServer::start(int port)
 
1706
{
 
1707
        d->serv.stop();
 
1708
        return d->serv.listen(port);
 
1709
}
 
1710
 
 
1711
void S5BServer::stop()
 
1712
{
 
1713
        d->serv.stop();
 
1714
}
 
1715
 
 
1716
void S5BServer::setHostList(const QStringList &list)
 
1717
{
 
1718
        d->hostList = list;
 
1719
}
 
1720
 
 
1721
QStringList S5BServer::hostList() const
 
1722
{
 
1723
        return d->hostList;
 
1724
}
 
1725
 
 
1726
int S5BServer::port() const
 
1727
{
 
1728
        return d->serv.port();
 
1729
}
 
1730
 
 
1731
void S5BServer::ss_incomingReady()
 
1732
{
 
1733
        Item *i = new Item(d->serv.takeIncoming());
 
1734
#ifdef S5B_DEBUG
 
1735
        printf("S5BServer: incoming connection from %s:%d\n", i->client->peerAddress().toString().latin1(), i->client->peerPort());
 
1736
#endif
 
1737
        connect(i, SIGNAL(result(bool)), SLOT(item_result(bool)));
 
1738
        d->itemList.append(i);
 
1739
}
 
1740
 
 
1741
void S5BServer::item_result(bool b)
 
1742
{
 
1743
        Item *i = (Item *)sender();
 
1744
#ifdef S5B_DEBUG
 
1745
        printf("S5BServer item result: %d\n", b);
 
1746
#endif
 
1747
        if(!b) {
 
1748
                d->itemList.removeRef(i);
 
1749
                return;
 
1750
        }
 
1751
 
 
1752
        SocksClient *c = i->client;
 
1753
        i->client = 0;
 
1754
        QString key = i->host;
 
1755
        d->itemList.removeRef(i);
 
1756
 
 
1757
        // find the appropriate manager for this incoming connection
 
1758
        QPtrListIterator<S5BManager> it(d->manList);
 
1759
        for(S5BManager *m; (m = it.current()); ++it) {
 
1760
                if(m->srv_ownsHash(key)) {
 
1761
                        m->srv_incomingReady(c, key);
 
1762
                        return;
 
1763
                }
 
1764
        }
 
1765
 
 
1766
        // throw it away
 
1767
        delete c;
 
1768
}
 
1769
 
 
1770
void S5BServer::link(S5BManager *m)
 
1771
{
 
1772
        d->manList.append(m);
 
1773
}
 
1774
 
 
1775
void S5BServer::unlink(S5BManager *m)
 
1776
{
 
1777
        d->manList.removeRef(m);
 
1778
}
 
1779
 
 
1780
void S5BServer::unlinkAll()
 
1781
{
 
1782
        QPtrListIterator<S5BManager> it(d->manList);
 
1783
        for(S5BManager *m; (m = it.current()); ++it)
 
1784
                m->srv_unlink();
 
1785
        d->manList.clear();
 
1786
}
 
1787
 
 
1788
const QPtrList<S5BManager> & S5BServer::managerList() const
 
1789
{
 
1790
        return d->manList;
 
1791
}
 
1792
 
 
1793
//----------------------------------------------------------------------------
 
1794
// JT_S5B
 
1795
//----------------------------------------------------------------------------
 
1796
class JT_S5B::Private
 
1797
{
 
1798
public:
 
1799
        QDomElement iq;
 
1800
        Jid to;
 
1801
        Jid streamHost;
 
1802
        StreamHost proxyInfo;
 
1803
        int mode;
 
1804
        QTimer t;
 
1805
};
 
1806
 
 
1807
JT_S5B::JT_S5B(Task *parent)
 
1808
:Task(parent)
 
1809
{
 
1810
        d = new Private;
 
1811
        d->mode = -1;
 
1812
        connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout()));
 
1813
}
 
1814
 
 
1815
JT_S5B::~JT_S5B()
 
1816
{
 
1817
        delete d;
 
1818
}
 
1819
 
 
1820
void JT_S5B::request(const Jid &to, const QString &sid, const StreamHostList &hosts, bool fast)
 
1821
{
 
1822
        d->mode = 0;
 
1823
 
 
1824
        QDomElement iq;
 
1825
        d->to = to;
 
1826
        iq = createIQ(doc(), "set", to.full(), id());
 
1827
        QDomElement query = doc()->createElement("query");
 
1828
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
1829
        query.setAttribute("sid", sid);
 
1830
        iq.appendChild(query);
 
1831
        for(StreamHostList::ConstIterator it = hosts.begin(); it != hosts.end(); ++it) {
 
1832
                QDomElement shost = doc()->createElement("streamhost");
 
1833
                shost.setAttribute("jid", (*it).jid().full());
 
1834
                shost.setAttribute("host", (*it).host());
 
1835
                shost.setAttribute("port", QString::number((*it).port()));
 
1836
                if((*it).isProxy()) {
 
1837
                        QDomElement p = doc()->createElement("proxy");
 
1838
                        p.setAttribute("xmlns", "http://affinix.com/jabber/stream");
 
1839
                        shost.appendChild(p);
 
1840
                }
 
1841
                query.appendChild(shost);
 
1842
        }
 
1843
        if(fast) {
 
1844
                QDomElement e = doc()->createElement("fast");
 
1845
                e.setAttribute("xmlns", "http://affinix.com/jabber/stream");
 
1846
                query.appendChild(e);
 
1847
        }
 
1848
        d->iq = iq;
 
1849
}
 
1850
 
 
1851
void JT_S5B::requestProxyInfo(const Jid &to)
 
1852
{
 
1853
        d->mode = 1;
 
1854
 
 
1855
        QDomElement iq;
 
1856
        d->to = to;
 
1857
        iq = createIQ(doc(), "get", to.full(), id());
 
1858
        QDomElement query = doc()->createElement("query");
 
1859
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
1860
        iq.appendChild(query);
 
1861
        d->iq = iq;
 
1862
}
 
1863
 
 
1864
void JT_S5B::requestActivation(const Jid &to, const QString &sid, const Jid &target)
 
1865
{
 
1866
        d->mode = 2;
 
1867
 
 
1868
        QDomElement iq;
 
1869
        d->to = to;
 
1870
        iq = createIQ(doc(), "set", to.full(), id());
 
1871
        QDomElement query = doc()->createElement("query");
 
1872
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
1873
        query.setAttribute("sid", sid);
 
1874
        iq.appendChild(query);
 
1875
        QDomElement act = doc()->createElement("activate");
 
1876
        act.appendChild(doc()->createTextNode(target.full()));
 
1877
        query.appendChild(act);
 
1878
        d->iq = iq;
 
1879
}
 
1880
 
 
1881
void JT_S5B::onGo()
 
1882
{
 
1883
        if(d->mode == 1)
 
1884
                d->t.start(15000, true);
 
1885
        send(d->iq);
 
1886
}
 
1887
 
 
1888
void JT_S5B::onDisconnect()
 
1889
{
 
1890
        d->t.stop();
 
1891
}
 
1892
 
 
1893
bool JT_S5B::take(const QDomElement &x)
 
1894
{
 
1895
        if(d->mode == -1)
 
1896
                return false;
 
1897
 
 
1898
        if(!iqVerify(x, d->to, id()))
 
1899
                return false;
 
1900
 
 
1901
        d->t.stop();
 
1902
 
 
1903
        if(x.attribute("type") == "result") {
 
1904
                QDomElement q = queryTag(x);
 
1905
                if(d->mode == 0) {
 
1906
                        d->streamHost = "";
 
1907
                        if(!q.isNull()) {
 
1908
                                QDomElement shost = q.elementsByTagName("streamhost-used").item(0).toElement();
 
1909
                                if(!shost.isNull())
 
1910
                                        d->streamHost = shost.attribute("jid");
 
1911
                        }
 
1912
 
 
1913
                        setSuccess();
 
1914
                }
 
1915
                else if(d->mode == 1) {
 
1916
                        if(!q.isNull()) {
 
1917
                                QDomElement shost = q.elementsByTagName("streamhost").item(0).toElement();
 
1918
                                if(!shost.isNull()) {
 
1919
                                        Jid j = shost.attribute("jid");
 
1920
                                        if(j.isValid()) {
 
1921
                                                QString host = shost.attribute("host");
 
1922
                                                if(!host.isEmpty()) {
 
1923
                                                        int port = shost.attribute("port").toInt();
 
1924
                                                        StreamHost h;
 
1925
                                                        h.setJid(j);
 
1926
                                                        h.setHost(host);
 
1927
                                                        h.setPort(port);
 
1928
                                                        h.setIsProxy(true);
 
1929
                                                        d->proxyInfo = h;
 
1930
                                                }
 
1931
                                        }
 
1932
                                }
 
1933
                        }
 
1934
 
 
1935
                        setSuccess();
 
1936
                }
 
1937
                else {
 
1938
                        setSuccess();
 
1939
                }
 
1940
        }
 
1941
        else {
 
1942
                setError(x);
 
1943
        }
 
1944
 
 
1945
        return true;
 
1946
}
 
1947
 
 
1948
void JT_S5B::t_timeout()
 
1949
{
 
1950
        d->mode = -1;
 
1951
        setError(500, "Timed out");
 
1952
}
 
1953
 
 
1954
Jid JT_S5B::streamHostUsed() const
 
1955
{
 
1956
        return d->streamHost;
 
1957
}
 
1958
 
 
1959
StreamHost JT_S5B::proxyInfo() const
 
1960
{
 
1961
        return d->proxyInfo;
 
1962
}
 
1963
 
 
1964
//----------------------------------------------------------------------------
 
1965
// JT_PushS5B
 
1966
//----------------------------------------------------------------------------
 
1967
JT_PushS5B::JT_PushS5B(Task *parent)
 
1968
:Task(parent)
 
1969
{
 
1970
}
 
1971
 
 
1972
JT_PushS5B::~JT_PushS5B()
 
1973
{
 
1974
}
 
1975
 
 
1976
bool JT_PushS5B::take(const QDomElement &e)
 
1977
{
 
1978
        // must be an iq-set tag
 
1979
        if(e.tagName() != "iq")
 
1980
                return false;
 
1981
        if(e.attribute("type") != "set")
 
1982
                return false;
 
1983
        if(queryNS(e) != "http://jabber.org/protocol/bytestreams")
 
1984
                return false;
 
1985
 
 
1986
        Jid from(e.attribute("from"));
 
1987
        QDomElement q = queryTag(e);
 
1988
        QString sid = q.attribute("sid");
 
1989
 
 
1990
        StreamHostList hosts;
 
1991
        QDomNodeList nl = q.elementsByTagName("streamhost");
 
1992
        for(uint n = 0; n < nl.count(); ++n) {
 
1993
                QDomElement shost = nl.item(n).toElement();
 
1994
                if(hosts.count() < MAXSTREAMHOSTS) {
 
1995
                        Jid j = shost.attribute("jid");
 
1996
                        if(!j.isValid())
 
1997
                                continue;
 
1998
                        QString host = shost.attribute("host");
 
1999
                        if(host.isEmpty())
 
2000
                                continue;
 
2001
                        int port = shost.attribute("port").toInt();
 
2002
                        QDomElement p = shost.elementsByTagName("proxy").item(0).toElement();
 
2003
                        bool isProxy = false;
 
2004
                        if(!p.isNull() && p.attribute("xmlns") == "http://affinix.com/jabber/stream")
 
2005
                                isProxy = true;
 
2006
 
 
2007
                        StreamHost h;
 
2008
                        h.setJid(j);
 
2009
                        h.setHost(host);
 
2010
                        h.setPort(port);
 
2011
                        h.setIsProxy(isProxy);
 
2012
                        hosts += h;
 
2013
                }
 
2014
        }
 
2015
 
 
2016
        bool fast = false;
 
2017
        QDomElement t;
 
2018
        t = q.elementsByTagName("fast").item(0).toElement();
 
2019
        if(!t.isNull() && t.attribute("xmlns") == "http://affinix.com/jabber/stream")
 
2020
                fast = true;
 
2021
 
 
2022
        S5BRequest r;
 
2023
        r.from = from;
 
2024
        r.id = e.attribute("id");
 
2025
        r.sid = sid;
 
2026
        r.hosts = hosts;
 
2027
        r.fast = fast;
 
2028
 
 
2029
        incoming(r);
 
2030
        return true;
 
2031
}
 
2032
 
 
2033
void JT_PushS5B::respondSuccess(const Jid &to, const QString &id, const Jid &streamHost)
 
2034
{
 
2035
        QDomElement iq = createIQ(doc(), "result", to.full(), id);
 
2036
        QDomElement query = doc()->createElement("query");
 
2037
        query.setAttribute("xmlns", "http://jabber.org/protocol/bytestreams");
 
2038
        iq.appendChild(query);
 
2039
        QDomElement shost = doc()->createElement("streamhost-used");
 
2040
        shost.setAttribute("jid", streamHost.full());
 
2041
        query.appendChild(shost);
 
2042
        send(iq);
 
2043
}
 
2044
 
 
2045
void JT_PushS5B::respondError(const Jid &to, const QString &id, int code, const QString &str)
 
2046
{
 
2047
        QDomElement iq = createIQ(doc(), "error", to.full(), id);
 
2048
        QDomElement err = textTag(doc(), "error", str);
 
2049
        err.setAttribute("code", QString::number(code));
 
2050
        iq.appendChild(err);
 
2051
        send(iq);
 
2052
}
 
2053
 
 
2054
//----------------------------------------------------------------------------
 
2055
// StreamHost
 
2056
//----------------------------------------------------------------------------
 
2057
StreamHost::StreamHost()
 
2058
{
 
2059
        v_port = -1;
 
2060
        proxy = false;
 
2061
}
 
2062
 
 
2063
const Jid & StreamHost::jid() const
 
2064
{
 
2065
        return j;
 
2066
}
 
2067
 
 
2068
const QString & StreamHost::host() const
 
2069
{
 
2070
        return v_host;
 
2071
}
 
2072
 
 
2073
int StreamHost::port() const
 
2074
{
 
2075
        return v_port;
 
2076
}
 
2077
 
 
2078
bool StreamHost::isProxy() const
 
2079
{
 
2080
        return proxy;
 
2081
}
 
2082
 
 
2083
void StreamHost::setJid(const Jid &_j)
 
2084
{
 
2085
        j = _j;
 
2086
}
 
2087
 
 
2088
void StreamHost::setHost(const QString &host)
 
2089
{
 
2090
        v_host = host;
 
2091
}
 
2092
 
 
2093
void StreamHost::setPort(int port)
 
2094
{
 
2095
        v_port = port;
 
2096
}
 
2097
 
 
2098
void StreamHost::setIsProxy(bool b)
 
2099
{
 
2100
        proxy = b;
 
2101
}
 
2102
 
 
2103
}
 
2104
 
 
2105
#include"s5b.moc"