~ubuntu-branches/ubuntu/wily/psi/wily-proposed

« back to all changes in this revision

Viewing changes to iris/src/xmpp/xmpp-im/xmpp_ibb.cpp

  • Committer: Package Import Robot
  • Author(s): Jan Niehusmann
  • Date: 2014-07-01 21:49:34 UTC
  • mfrom: (6.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20140701214934-gt4dkgm94byi4vnn
Tags: 0.15-1
* New upstream version
* set debhelper compat level to 9
* set Standards-Version to 3.9.5 (no further changes)
* add lintian override regarding license-problem-non-free-RFC
* use qconf to regenerate configure script
* implement hardening using buildflags instead of hardening-wrapper

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 *
15
15
 * You should have received a copy of the GNU Lesser General Public
16
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
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 *
19
19
 */
20
20
 
33
33
 
34
34
static int num_conn = 0;
35
35
static int id_conn = 0;
 
36
static const char *IBB_NS = "http://jabber.org/protocol/ibb";
36
37
 
37
38
//----------------------------------------------------------------------------
38
39
// IBBConnection
43
44
        Private() {}
44
45
 
45
46
        int state;
 
47
        quint16 seq;
46
48
        Jid peer;
47
49
        QString sid;
48
50
        IBBManager *m;
49
51
        JT_IBB *j;
50
 
        QDomElement comment;
51
52
        QString iq_id;
 
53
        QString stanza;
52
54
 
53
55
        int blockSize;
54
 
        QByteArray recvbuf, sendbuf;
 
56
        QByteArray recvBuf, sendBuf;
55
57
        bool closePending, closing;
56
58
 
57
 
        int id;
 
59
        int id; // connection id
58
60
};
59
61
 
60
62
IBBConnection::IBBConnection(IBBManager *m)
61
 
:ByteStream(m)
 
63
        : BSConnection(m)
62
64
{
63
65
        d = new Private;
64
66
        d->m = m;
65
67
        d->j = 0;
 
68
        d->blockSize = IBB_PACKET_SIZE;
66
69
        reset();
67
70
 
68
71
        ++num_conn;
69
72
        d->id = id_conn++;
70
 
        QString dstr; dstr.sprintf("IBBConnection[%d]: constructing, count=%d\n", d->id, num_conn);
71
 
        d->m->client()->debug(dstr);
 
73
#ifdef IBB_DEBUG
 
74
        qDebug("IBBConnection[%d]: constructing, count=%d", d->id, num_conn);
 
75
#endif
72
76
}
73
77
 
74
78
void IBBConnection::reset(bool clear)
77
81
        d->state = Idle;
78
82
        d->closePending = false;
79
83
        d->closing = false;
 
84
        d->seq = 0;
80
85
 
81
86
        delete d->j;
82
87
        d->j = 0;
83
88
 
84
 
        d->sendbuf.resize(0);
 
89
        d->sendBuf.clear();
85
90
        if(clear)
86
 
                d->recvbuf.resize(0);
 
91
                d->recvBuf.clear();
87
92
}
88
93
 
89
94
IBBConnection::~IBBConnection()
90
95
{
91
 
        reset(true);
 
96
        d->sendBuf.clear(); // drop buffer to make closing procedure fast
 
97
        close();
92
98
 
93
99
        --num_conn;
94
 
        QString dstr; dstr.sprintf("IBBConnection[%d]: destructing, count=%d\n", d->id, num_conn);
95
 
        d->m->client()->debug(dstr);
 
100
#ifdef IBB_DEBUG
 
101
        qDebug("IBBConnection[%d]: destructing, count=%d", d->id, num_conn);
 
102
#endif
96
103
 
97
104
        delete d;
98
105
}
99
106
 
100
 
void IBBConnection::connectToJid(const Jid &peer, const QDomElement &comment)
 
107
void IBBConnection::connectToJid(const Jid &peer, const QString &sid)
101
108
{
102
109
        close();
103
110
        reset(true);
104
111
 
105
112
        d->state = Requesting;
106
113
        d->peer = peer;
107
 
        d->comment = comment;
 
114
        d->sid = sid;
108
115
 
109
 
        QString dstr; dstr.sprintf("IBBConnection[%d]: initiating request to %s\n", d->id, peer.full().toLatin1().data());
110
 
        d->m->client()->debug(dstr);
 
116
#ifdef IBB_DEBUG
 
117
        qDebug("IBBConnection[%d]: initiating request to %s", d->id, qPrintable(peer.full()));
 
118
#endif
111
119
 
112
120
        d->j = new JT_IBB(d->m->client()->rootTask());
113
121
        connect(d->j, SIGNAL(finished()), SLOT(ibb_finished()));
114
 
        d->j->request(d->peer, comment);
 
122
        d->j->request(d->peer, d->sid);
115
123
        d->j->go(true);
116
124
}
117
125
 
120
128
        if(d->state != WaitingForAccept)
121
129
                return;
122
130
 
123
 
        QString dstr; dstr.sprintf("IBBConnection[%d]: accepting %s [%s]\n", d->id, d->peer.full().toLatin1().data(), d->sid.toLatin1().data());
124
 
        d->m->client()->debug(dstr);
 
131
#ifdef IBB_DEBUG
 
132
        qDebug("IBBConnection[%d]: accepting %s [%s]", d->id,
 
133
                   qPrintable(d->peer.full()), qPrintable(d->sid));
 
134
#endif
125
135
 
126
136
        d->m->doAccept(this, d->iq_id);
127
137
        d->state = Active;
128
138
        d->m->link(this);
 
139
 
 
140
        emit connected(); // to be compatible with S5B
129
141
}
130
142
 
131
143
void IBBConnection::close()
134
146
                return;
135
147
 
136
148
        if(d->state == WaitingForAccept) {
137
 
                d->m->doReject(this, d->iq_id, 403, "Rejected");
 
149
                d->m->doReject(this, d->iq_id, Stanza::Error::Forbidden, "Rejected");
138
150
                reset();
139
151
                return;
140
152
        }
141
153
 
142
 
        QString dstr; dstr.sprintf("IBBConnection[%d]: closing\n", d->id);
143
 
        d->m->client()->debug(dstr);
 
154
#ifdef IBB_DEBUG
 
155
        qDebug("IBBConnection[%d]: closing", d->id);
 
156
#endif
144
157
 
145
158
        if(d->state == Active) {
 
159
                d->closePending = true;
 
160
                trySend();
 
161
 
146
162
                // if there is data pending to be written, then pend the closing
147
163
                if(bytesToWrite() > 0) {
148
 
                        d->closePending = true;
149
 
                        trySend();
150
164
                        return;
151
165
                }
152
 
 
153
 
                // send a close packet
154
 
                JT_IBB *j = new JT_IBB(d->m->client()->rootTask());
155
 
                j->sendData(d->peer, d->sid, QByteArray(), true);
156
 
                j->go(true);
157
166
        }
158
167
 
159
168
        reset();
169
178
        return d->peer;
170
179
}
171
180
 
172
 
QString IBBConnection::streamid() const
 
181
QString IBBConnection::sid() const
173
182
{
174
183
        return d->sid;
175
184
}
176
185
 
177
 
QDomElement IBBConnection::comment() const
 
186
BytestreamManager* IBBConnection::manager() const
178
187
{
179
 
        return d->comment;
 
188
        return d->m;
180
189
}
181
190
 
182
191
bool IBBConnection::isOpen() const
192
201
        if(d->state != Active || d->closePending || d->closing)
193
202
                return;
194
203
 
195
 
        // append to the end of our send buffer
196
 
        int oldsize = d->sendbuf.size();
197
 
        d->sendbuf.resize(oldsize + a.size());
198
 
        memcpy(d->sendbuf.data() + oldsize, a.data(), a.size());
199
 
 
 
204
        d->sendBuf += a;
200
205
        trySend();
201
206
}
202
207
 
203
208
QByteArray IBBConnection::read(int)
204
209
{
205
210
        // TODO: obey argument
206
 
        QByteArray a = d->recvbuf;
207
 
        d->recvbuf.resize(0);
 
211
        QByteArray a = d->recvBuf;
 
212
        d->recvBuf.resize(0);
208
213
        return a;
209
214
}
210
215
 
211
216
int IBBConnection::bytesAvailable() const
212
217
{
213
 
        return d->recvbuf.size();
 
218
        return d->recvBuf.size();
214
219
}
215
220
 
216
221
int IBBConnection::bytesToWrite() const
217
222
{
218
 
        return d->sendbuf.size();
 
223
        return d->sendBuf.size();
219
224
}
220
225
 
221
 
void IBBConnection::waitForAccept(const Jid &peer, const QString &sid, const QDomElement &comment, const QString &iq_id)
 
226
void IBBConnection::waitForAccept(const Jid &peer, const QString &iq_id,
 
227
                                                                  const QString &sid, int blockSize,
 
228
                                                                  const QString &stanza)
222
229
{
223
230
        close();
224
231
        reset(true);
225
232
 
226
233
        d->state = WaitingForAccept;
227
234
        d->peer = peer;
228
 
        d->sid = sid;
229
 
        d->comment = comment;
230
235
        d->iq_id = iq_id;
 
236
        d->sid = sid;
 
237
        d->blockSize = blockSize;
 
238
        d->stanza = stanza;
 
239
 
231
240
}
232
241
 
233
 
void IBBConnection::takeIncomingData(const QByteArray &a, bool close)
 
242
void IBBConnection::takeIncomingData(const IBBData &ibbData)
234
243
{
235
 
        // append to the end of our recv buffer
236
 
        int oldsize = d->recvbuf.size();
237
 
        d->recvbuf.resize(oldsize + a.size());
238
 
        memcpy(d->recvbuf.data() + oldsize, a.data(), a.size());
 
244
        if (ibbData.seq != d->seq) {
 
245
                d->m->doReject(this, d->iq_id, Stanza::Error::UnexpectedRequest, "Invalid sequence");
 
246
                return;
 
247
        }
 
248
        if (ibbData.data.size() > d->blockSize) {
 
249
                d->m->doReject(this, d->iq_id, Stanza::Error::BadRequest, "Too much data");
 
250
                return;
 
251
        }
 
252
        d->seq++;
 
253
        d->recvBuf += ibbData.data;
239
254
 
240
255
        readyRead();
 
256
}
241
257
 
242
 
        if(close) {
243
 
                reset();
244
 
                connectionClosed();
245
 
        }
 
258
void IBBConnection::setRemoteClosed()
 
259
{
 
260
        reset();
 
261
        emit connectionClosed();
246
262
}
247
263
 
248
264
void IBBConnection::ibb_finished()
252
268
 
253
269
        if(j->success()) {
254
270
                if(j->mode() == JT_IBB::ModeRequest) {
255
 
                        d->sid = j->streamid();
256
 
 
257
 
                        QString dstr; dstr.sprintf("IBBConnection[%d]: %s [%s] accepted.\n", d->id, d->peer.full().toLatin1().data(), d->sid.toLatin1().data());
258
 
                        d->m->client()->debug(dstr);
259
 
 
 
271
 
 
272
#ifdef IBB_DEBUG
 
273
                        qDebug("IBBConnection[%d]: %s [%s] accepted.", d->id,
 
274
                                   qPrintable(d->peer.full()), qPrintable(d->sid));
 
275
#endif
260
276
                        d->state = Active;
261
277
                        d->m->link(this);
262
 
                        connected();
 
278
                        emit connected();
263
279
                }
264
280
                else {
265
 
                        bytesWritten(d->blockSize);
266
 
 
267
281
                        if(d->closing) {
268
282
                                reset();
269
 
                                delayedCloseFinished();
 
283
                                emit delayedCloseFinished();
270
284
                        }
271
285
 
272
 
                        if(!d->sendbuf.isEmpty() || d->closePending)
 
286
                        if(!d->sendBuf.isEmpty() || d->closePending)
273
287
                                QTimer::singleShot(IBB_PACKET_DELAY, this, SLOT(trySend()));
 
288
 
 
289
                        bytesWritten(j->bytesWritten()); // will delete this connection if no bytes left.
274
290
                }
275
291
        }
276
292
        else {
277
293
                if(j->mode() == JT_IBB::ModeRequest) {
278
 
                        QString dstr; dstr.sprintf("IBBConnection[%d]: %s refused.\n", d->id, d->peer.full().toLatin1().data());
279
 
                        d->m->client()->debug(dstr);
280
 
 
 
294
#ifdef IBB_DEBUG
 
295
                        qDebug("IBBConnection[%d]: %s refused.", d->id, qPrintable(d->peer.full()));
 
296
#endif
281
297
                        reset(true);
282
298
                        error(ErrRequest);
283
299
                }
294
310
        if(d->j)
295
311
                return;
296
312
 
297
 
        QByteArray a;
298
 
        if(!d->sendbuf.isEmpty()) {
299
 
                // take a chunk
300
 
                if(d->sendbuf.size() < IBB_PACKET_SIZE)
301
 
                        a.resize(d->sendbuf.size());
302
 
                else
303
 
                        a.resize(IBB_PACKET_SIZE);
304
 
                memcpy(a.data(), d->sendbuf.data(), a.size());
305
 
                d->sendbuf.resize(d->sendbuf.size() - a.size());
306
 
        }
307
 
 
308
 
        bool doClose = false;
309
 
        if(d->sendbuf.isEmpty() && d->closePending)
310
 
                doClose = true;
311
 
 
312
 
        // null operation?
313
 
        if(a.isEmpty() && !doClose)
314
 
                return;
315
 
 
316
 
        printf("IBBConnection[%d]: sending [%d] bytes ", d->id, a.size());
317
 
        if(doClose)
318
 
                printf("and closing.\n");
319
 
        else
320
 
                printf("(%d bytes left)\n", d->sendbuf.size());
321
 
 
322
 
        if(doClose) {
 
313
        QByteArray a = d->sendBuf.left(d->blockSize); // IBB_PACKET_SIZE
 
314
        d->sendBuf.remove(0, a.size());
 
315
 
 
316
        if(a.isEmpty()) {
 
317
                if (!d->closePending)
 
318
                        return; // null operation?
323
319
                d->closePending = false;
324
320
                d->closing = true;
 
321
#ifdef IBB_DEBUG
 
322
                qDebug("IBBConnection[%d]: closing", d->id);
 
323
#endif
 
324
        }
 
325
        else {
 
326
#ifdef IBB_DEBUG
 
327
                qDebug("IBBConnection[%d]: sending [%d] bytes (%d bytes left)",
 
328
                           d->id, a.size(), d->sendBuf.size());
 
329
#endif
325
330
        }
326
331
 
327
 
        d->blockSize = a.size();
328
332
        d->j = new JT_IBB(d->m->client()->rootTask());
329
333
        connect(d->j, SIGNAL(finished()), SLOT(ibb_finished()));
330
 
        d->j->sendData(d->peer, d->sid, a, doClose);
 
334
        if (d->closing) {
 
335
                d->j->close(d->peer, d->sid);
 
336
        }
 
337
        else {
 
338
                d->j->sendData(d->peer, IBBData(d->sid, d->seq++, a));
 
339
        }
331
340
        d->j->go(true);
332
341
}
333
342
 
334
343
 
 
344
 
 
345
//----------------------------------------------------------------------------
 
346
// IBBData
 
347
//----------------------------------------------------------------------------
 
348
IBBData& IBBData::fromXml(const QDomElement &e)
 
349
{
 
350
        sid = e.attribute("sid"),
 
351
        seq = e.attribute("seq").toInt(),
 
352
        data = QCA::Base64().stringToArray(e.text()).toByteArray();
 
353
        return *this;
 
354
}
 
355
 
 
356
QDomElement IBBData::toXml(QDomDocument *doc) const
 
357
{
 
358
        QDomElement query = textTag(doc, "data",
 
359
                                                QCA::Base64().arrayToString(data)).toElement();
 
360
        query.setAttribute("xmlns", IBB_NS);
 
361
        query.setAttribute("seq", QString::number(seq));
 
362
        query.setAttribute("sid", sid);
 
363
        return query;
 
364
}
 
365
 
335
366
//----------------------------------------------------------------------------
336
367
// IBBManager
337
368
//----------------------------------------------------------------------------
347
378
};
348
379
 
349
380
IBBManager::IBBManager(Client *parent)
350
 
:QObject(parent)
 
381
        : BytestreamManager(parent)
351
382
{
352
383
        d = new Private;
353
384
        d->client = parent;
354
385
        
355
386
        d->ibb = new JT_IBB(d->client->rootTask(), true);
356
 
        connect(d->ibb, SIGNAL(incomingRequest(const Jid &, const QString &, const QDomElement &)), SLOT(ibb_incomingRequest(const Jid &, const QString &, const QDomElement &)));
357
 
        connect(d->ibb, SIGNAL(incomingData(const Jid &, const QString &, const QString &, const QByteArray &, bool)), SLOT(ibb_incomingData(const Jid &, const QString &, const QString &, const QByteArray &, bool)));
 
387
        connect(d->ibb,
 
388
                        SIGNAL(incomingRequest(const Jid &, const QString &,
 
389
                                                                   const QString &, int, const QString &)),
 
390
                        SLOT(ibb_incomingRequest(const Jid &, const QString &,
 
391
                                                                         const QString &, int,
 
392
                                                                         const QString &)));
 
393
        connect(d->ibb,
 
394
                        SIGNAL(incomingData(const Jid &, const QString &, const IBBData &, Stanza::Kind)),
 
395
                        SLOT(takeIncomingData(const Jid &, const QString &, const IBBData &, Stanza::Kind)));
 
396
        connect(d->ibb,
 
397
                        SIGNAL(closeRequest(const Jid &, const QString &, const QString &)),
 
398
                        SLOT(ibb_closeRequest(const Jid &, const QString &, const QString &)));
358
399
}
359
400
 
360
401
IBBManager::~IBBManager()
361
402
{
362
 
        while (!d->incomingConns.isEmpty()) {
363
 
                delete d->incomingConns.takeFirst();
364
 
        }
 
403
        qDeleteAll(d->incomingConns);
 
404
        d->incomingConns.clear();
365
405
        delete d->ibb;
366
406
        delete d;
367
407
}
368
408
 
 
409
const char* IBBManager::ns()
 
410
{
 
411
        return IBB_NS;
 
412
}
 
413
 
369
414
Client *IBBManager::client() const
370
415
{
371
416
        return d->client;
372
417
}
373
418
 
 
419
BSConnection *IBBManager::createConnection()
 
420
{
 
421
        return new IBBConnection(this);
 
422
}
 
423
 
374
424
IBBConnection *IBBManager::takeIncoming()
375
425
{
376
 
        if(d->incomingConns.isEmpty())
377
 
                return 0;
378
 
 
379
 
        IBBConnection *c = d->incomingConns.takeFirst();
380
 
        return c;
 
426
        return d->incomingConns.isEmpty()? 0 : d->incomingConns.takeFirst();
381
427
}
382
428
 
383
 
void IBBManager::ibb_incomingRequest(const Jid &from, const QString &id, const QDomElement &comment)
 
429
void IBBManager::ibb_incomingRequest(const Jid &from, const QString &id,
 
430
                                                                         const QString &sid, int blockSize,
 
431
                                                                         const QString &stanza)
384
432
{
385
 
        QString sid = genUniqueKey();
386
 
 
387
433
        // create a "waiting" connection
388
434
        IBBConnection *c = new IBBConnection(this);
389
 
        c->waitForAccept(from, sid, comment, id);
 
435
        c->waitForAccept(from, id, sid, blockSize, stanza);
390
436
        d->incomingConns.append(c);
391
 
        incomingReady();
392
 
}
393
 
 
394
 
void IBBManager::ibb_incomingData(const Jid &from, const QString &streamid, const QString &id, const QByteArray &data, bool close)
395
 
{
396
 
        IBBConnection *c = findConnection(streamid, from);
397
 
        if(!c) {
398
 
                d->ibb->respondError(from, id, 404, "No such stream");
 
437
        emit incomingReady();
 
438
}
 
439
 
 
440
void IBBManager::takeIncomingData(const Jid &from, const QString &id,
 
441
                                                                  const IBBData &data, Stanza::Kind sKind)
 
442
{
 
443
        IBBConnection *c = findConnection(data.sid, from);
 
444
        if(!c) {
 
445
                if (sKind == Stanza::IQ) {
 
446
                        d->ibb->respondError(from, id, Stanza::Error::ItemNotFound, "No such stream");
 
447
                }
 
448
                // TODO imeplement xep-0079 error processing in case of Stanza::Message
 
449
        }
 
450
        else {
 
451
                if (sKind == Stanza::IQ) {
 
452
                        d->ibb->respondAck(from, id);
 
453
                }
 
454
                c->takeIncomingData(data);
 
455
        }
 
456
}
 
457
 
 
458
void IBBManager::ibb_closeRequest(const Jid &from, const QString &id,
 
459
                                                                  const QString &sid)
 
460
{
 
461
        IBBConnection *c = findConnection(sid, from);
 
462
        if(!c) {
 
463
                d->ibb->respondError(from, id, Stanza::Error::ItemNotFound, "No such stream");
399
464
        }
400
465
        else {
401
466
                d->ibb->respondAck(from, id);
402
 
                c->takeIncomingData(data, close);
403
 
        }
404
 
}
405
 
 
406
 
QString IBBManager::genKey() const
407
 
{
408
 
        QString key = "ibb_";
409
 
 
410
 
        for(int i = 0; i < 4; ++i) {
411
 
                int word = rand() & 0xffff;
412
 
                for(int n = 0; n < 4; ++n) {
413
 
                        QString s;
414
 
                        s.sprintf("%x", (word >> (n * 4)) & 0xf);
415
 
                        key.append(s);
416
 
                }
417
 
        }
418
 
 
419
 
        return key;
420
 
}
421
 
 
422
 
QString IBBManager::genUniqueKey() const
423
 
{
424
 
        // get unused key
425
 
        QString key;
426
 
        while(1) {
427
 
                key = genKey();
428
 
 
429
 
                if(!findConnection(key))
430
 
                        break;
431
 
        }
432
 
 
433
 
        return key;
 
467
                c->setRemoteClosed();
 
468
        }
 
469
}
 
470
 
 
471
bool IBBManager::isAcceptableSID(const XMPP::Jid &jid, const QString&sid) const
 
472
{
 
473
        return findConnection(sid, jid) == NULL;
 
474
}
 
475
 
 
476
const char* IBBManager::sidPrefix() const
 
477
{
 
478
        return "ibb_";
434
479
}
435
480
 
436
481
void IBBManager::link(IBBConnection *c)
446
491
IBBConnection *IBBManager::findConnection(const QString &sid, const Jid &peer) const
447
492
{
448
493
        foreach(IBBConnection* c, d->activeConns) {
449
 
                if(c->streamid() == sid && (peer.isEmpty() || c->peer().compare(peer)) )
 
494
                if(c->sid() == sid && (peer.isEmpty() || c->peer().compare(peer)) )
450
495
                        return c;
451
496
        }
452
497
        return 0;
454
499
 
455
500
void IBBManager::doAccept(IBBConnection *c, const QString &id)
456
501
{
457
 
        d->ibb->respondSuccess(c->peer(), id, c->streamid());
 
502
        d->ibb->respondAck(c->peer(), id);
458
503
}
459
504
 
460
 
void IBBManager::doReject(IBBConnection *c, const QString &id, int code, const QString &str)
 
505
void IBBManager::doReject(IBBConnection *c, const QString &id,
 
506
                                                  Stanza::Error::ErrorCond cond, const QString &str)
461
507
{
462
 
        d->ibb->respondError(c->peer(), id, code, str);
 
508
        d->ibb->respondError(c->peer(), id, cond, str);
463
509
}
464
510
 
465
511
 
475
521
        int mode;
476
522
        bool serve;
477
523
        Jid to;
478
 
        QString streamid;
 
524
        QString sid;
 
525
        int bytesWritten;
479
526
};
480
527
 
481
528
JT_IBB::JT_IBB(Task *parent, bool serve)
490
537
        delete d;
491
538
}
492
539
 
493
 
void JT_IBB::request(const Jid &to, const QDomElement &comment)
 
540
void JT_IBB::request(const Jid &to, const QString &sid)
494
541
{
495
542
        d->mode = ModeRequest;
496
543
        QDomElement iq;
497
544
        d->to = to;
498
545
        iq = createIQ(doc(), "set", to.full(), id());
499
 
        QDomElement query = doc()->createElement("query");
500
 
        query.setAttribute("xmlns", "http://jabber.org/protocol/ibb");
501
 
        iq.appendChild(query);
502
 
        query.appendChild(comment);
503
 
        d->iq = iq;
504
 
}
505
 
 
506
 
void JT_IBB::sendData(const Jid &to, const QString &streamid, const QByteArray &a, bool close)
507
 
{
508
 
        d->mode = ModeSendData;
509
 
        QDomElement iq;
510
 
        d->to = to;
511
 
        iq = createIQ(doc(), "set", to.full(), id());
512
 
        QDomElement query = doc()->createElement("query");
513
 
        query.setAttribute("xmlns", "http://jabber.org/protocol/ibb");
514
 
        iq.appendChild(query);
515
 
        query.appendChild(textTag(doc(), "streamid", streamid));
516
 
        if(!a.isEmpty())
517
 
                query.appendChild(textTag(doc(), "data", QCA::Base64().arrayToString(a)));
518
 
        if(close) {
519
 
                QDomElement c = doc()->createElement("close");
520
 
                query.appendChild(c);
521
 
        }
522
 
        d->iq = iq;
523
 
}
524
 
 
525
 
void JT_IBB::respondSuccess(const Jid &to, const QString &id, const QString &streamid)
526
 
{
527
 
        QDomElement iq = createIQ(doc(), "result", to.full(), id);
528
 
        QDomElement query = doc()->createElement("query");
529
 
        query.setAttribute("xmlns", "http://jabber.org/protocol/ibb");
530
 
        iq.appendChild(query);
531
 
        query.appendChild(textTag(doc(), "streamid", streamid));
532
 
        send(iq);
533
 
}
534
 
 
535
 
void JT_IBB::respondError(const Jid &to, const QString &id, int code, const QString &str)
 
546
        QDomElement query = doc()->createElement("open");
 
547
        //genUniqueKey
 
548
        query.setAttribute("xmlns", IBB_NS);
 
549
        query.setAttribute("sid", sid);
 
550
        query.setAttribute("block-size", IBB_PACKET_SIZE);
 
551
        query.setAttribute("stanza", "iq");
 
552
        iq.appendChild(query);
 
553
        d->iq = iq;
 
554
}
 
555
 
 
556
void JT_IBB::sendData(const Jid &to, const IBBData &ibbData)
 
557
{
 
558
        d->mode = ModeSendData;
 
559
        QDomElement iq;
 
560
        d->to = to;
 
561
        d->bytesWritten = ibbData.data.size();
 
562
        iq = createIQ(doc(), "set", to.full(), id());
 
563
        iq.appendChild(ibbData.toXml(doc()));
 
564
        d->iq = iq;
 
565
}
 
566
 
 
567
void JT_IBB::close(const Jid &to, const QString &sid)
 
568
{
 
569
        d->mode = ModeSendData;
 
570
        QDomElement iq;
 
571
        d->to = to;
 
572
        iq = createIQ(doc(), "set", to.full(), id());
 
573
        QDomElement query = iq.appendChild(doc()->createElement("close")).toElement();
 
574
        query.setAttribute("xmlns", IBB_NS);
 
575
        query.setAttribute("sid", sid);
 
576
 
 
577
        d->iq = iq;
 
578
}
 
579
 
 
580
void JT_IBB::respondError(const Jid &to, const QString &id,
 
581
                                                  Stanza::Error::ErrorCond cond, const QString &text)
536
582
{
537
583
        QDomElement iq = createIQ(doc(), "error", to.full(), id);
538
 
        QDomElement err = textTag(doc(), "error", str);
539
 
        err.setAttribute("code", QString::number(code));
540
 
        iq.appendChild(err);
 
584
        Stanza::Error error(Stanza::Error::Cancel, cond, text);
 
585
        iq.appendChild(error.toXml(*client()->doc(), client()->stream().baseNS()));
541
586
        send(iq);
542
587
}
543
588
 
544
589
void JT_IBB::respondAck(const Jid &to, const QString &id)
545
590
{
546
 
        QDomElement iq = createIQ(doc(), "result", to.full(), id);
547
 
        send(iq);
 
591
        send( createIQ(doc(), "result", to.full(), id) );
548
592
}
549
593
 
550
594
void JT_IBB::onGo()
559
603
                if(e.tagName() != "iq" || e.attribute("type") != "set")
560
604
                        return false;
561
605
 
562
 
                if(queryNS(e) != "http://jabber.org/protocol/ibb")
563
 
                        return false;
564
 
 
565
 
                Jid from(e.attribute("from"));
 
606
                bool found;
566
607
                QString id = e.attribute("id");
567
 
                QDomElement q = queryTag(e);
568
 
 
569
 
                bool found;
570
 
                QDomElement s = findSubTag(q, "streamid", &found);
571
 
                if(!found) {
572
 
                        QDomElement comment = findSubTag(q, "comment", &found);
573
 
                        incomingRequest(from, id, comment);
574
 
                }
575
 
                else {
576
 
                        QString sid = tagContent(s);
577
 
                        QByteArray a;
578
 
                        bool close = false;
579
 
                        s = findSubTag(q, "data", &found);
580
 
                        if(found)
581
 
                                a = QCA::Base64().stringToArray(tagContent(s)).toByteArray();
582
 
                        s = findSubTag(q, "close", &found);
583
 
                        if(found)
584
 
                                close = true;
585
 
 
586
 
                        incomingData(from, sid, id, a, close);
587
 
                }
588
 
 
589
 
                return true;
 
608
                QString from = e.attribute("from");
 
609
                QDomElement openEl = findSubTag(e, "open", &found);
 
610
                if (found && openEl.attribute("xmlns") == IBB_NS) {
 
611
                        emit incomingRequest(Jid(from), id,
 
612
                                                        openEl.attribute("sid"),
 
613
                                                        openEl.attribute("block-size").toInt(),
 
614
                                                        openEl.attribute("stanza"));
 
615
                        return true;
 
616
                }
 
617
                QDomElement dataEl = findSubTag(e, "data", &found);
 
618
                if (found && dataEl.attribute("xmlns") == IBB_NS) {
 
619
                        IBBData data;
 
620
                        emit incomingData(Jid(from), id, data.fromXml(dataEl), Stanza::IQ);
 
621
                        return true;
 
622
                }
 
623
                QDomElement closeEl = findSubTag(e, "close", &found);
 
624
                if (found && closeEl.attribute("xmlns") == IBB_NS) {
 
625
                        emit closeRequest(Jid(from), id, closeEl.attribute("sid"));
 
626
                        return true;
 
627
                }
 
628
                return false;
590
629
        }
591
630
        else {
592
631
                Jid from(e.attribute("from"));
594
633
                        return false;
595
634
 
596
635
                if(e.attribute("type") == "result") {
597
 
                        QDomElement q = queryTag(e);
598
 
 
599
 
                        // request
600
 
                        if(d->mode == ModeRequest) {
601
 
                                bool found;
602
 
                                QDomElement s = findSubTag(q, "streamid", &found);
603
 
                                if(found)
604
 
                                        d->streamid = tagContent(s);
605
 
                                else
606
 
                                        d->streamid = "";
607
 
                                setSuccess();
608
 
                        }
609
 
                        // sendData
610
 
                        else {
611
 
                                // thank you for the ack, kind sir
612
 
                                setSuccess();
613
 
                        }
 
636
                        setSuccess();
614
637
                }
615
638
                else {
616
639
                        setError(e);
620
643
        }
621
644
}
622
645
 
623
 
QString JT_IBB::streamid() const
624
 
{
625
 
        return d->streamid;
626
 
}
627
 
 
628
646
Jid JT_IBB::jid() const
629
647
{
630
648
        return d->to;
635
653
        return d->mode;
636
654
}
637
655
 
 
656
int JT_IBB::bytesWritten() const
 
657
{
 
658
        return d->bytesWritten;
 
659
}
 
660