+
+
+void CoreTransfer::start()
+{
+ if (!_peer || state() != Pending || direction() != Receive)
+ return;
+
+ setupConnectionForReceive();
+}
+
+
+void CoreTransfer::setupConnectionForReceive()
+{
+ if (port() == 0) {
+ setError(tr("Reverse DCC not supported yet!"));
+ return;
+ }
+
+ setState(Connecting);
+
+ _socket = new QTcpSocket(this);
+ connect(_socket, SIGNAL(connected()), SLOT(startReceiving()));
+ connect(_socket, SIGNAL(disconnected()), SLOT(onSocketDisconnected()));
+ connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onSocketError(QAbstractSocket::SocketError)));
+ connect(_socket, SIGNAL(readyRead()), SLOT(onDataReceived()));
+
+ _socket->connectToHost(address(), port());
+}
+
+
+void CoreTransfer::startReceiving()
+{
+ setState(Transferring);
+}
+
+
+void CoreTransfer::onDataReceived()
+{
+ if (_reading) // since we're spinning the event loop, we may get another readyRead() and thus reentrancy
+ return;
+ _reading = true;
+
+ while (_socket->bytesAvailable()) {
+ QByteArray data = _socket->read(chunkSize);
+ _pos += data.size();
+ if (!relayData(data, true))
+ return;
+
+ QCoreApplication::processEvents(); // don't block the rest of the core/client communication
+ if (!_socket) // just in case something happened during spinning the event loop that killed our socket
+ return;
+ }
+
+ // Send ack to sender. The DCC protocol only specifies 32 bit values, but modern clients (i.e. those who can send files
+ // larger than 4 GB) will ignore this anyway...
+ quint32 ack = qToBigEndian((quint32)_pos);// qDebug() << Q_FUNC_INFO << _pos;
+ _socket->write((char *)&ack, 4);
+
+ if (_pos > fileSize()) {
+ qWarning() << "DCC Receive: Got more data than expected!";
+ setError(tr("DCC Receive: Got more data than expected!"));
+ }
+ else if (_pos == fileSize()) {
+ qDebug() << "DCC Receive: Transfer finished";
+ if (relayData(QByteArray(), false)) // empty buffer
+ setState(Completed);
+ }
+
+ _reading = false;
+}
+
+
+bool CoreTransfer::relayData(const QByteArray &data, bool requireChunkSize)
+{
+ // safeguard against a disconnecting quasselclient
+ if (!_peer) {
+ setError(tr("DCC Receive: Quassel Client disconnected during transfer!"));
+ return false;
+ }
+ _buffer.append(data);
+
+ // we only want to send data to the client once we have reached the chunksize
+ if (_buffer.size() > 0 && (_buffer.size() >= chunkSize || !requireChunkSize)) {
+ SYNC_OTHER(dataReceived, ARG(_peer), ARG(_buffer));
+ _buffer.clear();
+ }
+
+ return true;
+}