~ubuntu-branches/ubuntu/saucy/kopete/saucy-proposed

« back to all changes in this revision

Viewing changes to protocols/oscar/liboscar/oftmetatransfer.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-06-21 02:22:39 UTC
  • Revision ID: package-import@ubuntu.com-20130621022239-63l3zc8p0nf26pt6
Tags: upstream-4.10.80
ImportĀ upstreamĀ versionĀ 4.10.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// oftmetatransfer.cpp
 
2
 
 
3
// Copyright (C)  2006
 
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., 51 Franklin Street, Fifth Floor, Boston, MA
 
18
// 02110-1301  USA
 
19
 
 
20
#include "oftmetatransfer.h"
 
21
 
 
22
#include <QtCore/QFileInfo>
 
23
#include <QtNetwork/QTcpSocket>
 
24
 
 
25
#include <kdebug.h>
 
26
 
 
27
#include "ofttransfer.h"
 
28
#include "oftprotocol.h"
 
29
 
 
30
#define BUFFER_SIZE 32768
 
31
 
 
32
OftMetaTransfer::OftMetaTransfer( const QByteArray& cookie, const QStringList &files, const QString &dir, QTcpSocket *socket )
 
33
: m_file( this ), m_socket( socket ), m_state( SetupReceive )
 
34
{
 
35
        //filetransfertask is responsible for hooking us up to the ui
 
36
        //we're responsible for hooking up the socket and timer
 
37
        connect( m_socket, SIGNAL(readyRead()), this, SLOT(socketRead()) );
 
38
        connect( m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
 
39
                 this, SLOT(socketError(QAbstractSocket::SocketError)) );
 
40
 
 
41
        initOft();
 
42
        m_oft.cookie = cookie;
 
43
        m_files = files;
 
44
        m_dir = dir;
 
45
}
 
46
 
 
47
OftMetaTransfer::OftMetaTransfer( const QByteArray& cookie, const QStringList& files, QTcpSocket *socket )
 
48
: m_file( this ), m_socket( socket ), m_state( SetupSend )
 
49
{
 
50
        //filetransfertask is responsible for hooking us up to the ui
 
51
        //we're responsible for hooking up the socket and timer
 
52
        connect( m_socket, SIGNAL(readyRead()), this, SLOT(socketRead()) );
 
53
        connect( m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
 
54
                 this, SLOT(socketError(QAbstractSocket::SocketError)) );
 
55
 
 
56
        initOft();
 
57
        m_oft.cookie = cookie;
 
58
        for ( int i = 0; i < files.size(); ++i )
 
59
        {
 
60
                QFileInfo fileInfo( files.at(i) );
 
61
                m_oft.totalSize += fileInfo.size();
 
62
        }
 
63
        m_oft.fileCount = files.size();
 
64
        m_files = files;
 
65
}
 
66
 
 
67
void OftMetaTransfer::start()
 
68
{
 
69
        if ( m_files.count() == 0 )
 
70
        {
 
71
                doCancel();
 
72
                return;
 
73
        }
 
74
 
 
75
        //filesLeft is decremented in prompt
 
76
        m_oft.filesLeft = m_oft.fileCount + 1;
 
77
        prompt();
 
78
}
 
79
 
 
80
OftMetaTransfer::~OftMetaTransfer()
 
81
{
 
82
        if( m_socket )
 
83
        {
 
84
                m_socket->close();
 
85
                delete m_socket;
 
86
                m_socket = 0;
 
87
        }
 
88
        kDebug(OSCAR_RAW_DEBUG) << "really done";
 
89
}
 
90
/*
 
91
bool OftMetaTransfer::validFile()
 
92
{
 
93
        if ( m_action == Send )
 
94
        {
 
95
                if ( ! m_file.exists() )
 
96
                {
 
97
                        emit error( KIO::ERR_DOES_NOT_EXIST, m_file.fileName() );
 
98
                        return 0;
 
99
                }
 
100
                if ( m_file.size() == 0 )
 
101
                {
 
102
                        emit error( KIO::ERR_COULD_NOT_READ, i18n("file is empty: ") + m_file.fileName() );
 
103
                        return 0;
 
104
                }
 
105
                if ( ! QFileInfo( m_file ).isReadable() )
 
106
                {
 
107
                        emit error( KIO::ERR_CANNOT_OPEN_FOR_READING, m_file.fileName() );
 
108
                        return 0;
 
109
                }
 
110
        }
 
111
        else //receive
 
112
        { //note: opening for writing clobbers the file
 
113
                if ( m_file.exists() )
 
114
                {
 
115
                        if ( ! QFileInfo( m_file ).isWritable() )
 
116
                        { //it's there and readonly
 
117
                                emit error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, m_file.fileName() );
 
118
                                return 0;
 
119
                        }
 
120
                }
 
121
                else if ( ! QFileInfo( QFileInfo( m_file ).toLocalFile() ).isWritable() )
 
122
                { //not allowed to create it
 
123
                                emit error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, m_file.fileName() );
 
124
                                return 0;
 
125
                }
 
126
        }
 
127
        return true;
 
128
}
 
129
*/
 
130
 
 
131
void OftMetaTransfer::socketError( QAbstractSocket::SocketError e )
 
132
{
 
133
        QString desc = m_socket->errorString();
 
134
        kWarning(OSCAR_RAW_DEBUG) << "socket error: " << e << " : " << desc;
 
135
        emit transferError( e, desc );
 
136
}
 
137
 
 
138
void OftMetaTransfer::socketRead()
 
139
{
 
140
        if ( m_state == Receiving ) //raw file data
 
141
                saveData();
 
142
        else //oft packet
 
143
                readOft();
 
144
}
 
145
 
 
146
void OftMetaTransfer::readOft()
 
147
{
 
148
        kDebug(OSCAR_RAW_DEBUG) ;
 
149
        QByteArray raw = m_socket->readAll(); //is this safe?
 
150
        OftProtocol p;
 
151
        uint b=0;
 
152
        //remember we're responsible for freeing this!
 
153
        OftTransfer *t = static_cast<OftTransfer*>( p.parse( raw, b ) );
 
154
        OFT data = t->data();
 
155
        kDebug(OSCAR_RAW_DEBUG) << "checksum: " << data.checksum;
 
156
        kDebug(OSCAR_RAW_DEBUG) << "sentChecksum: " << data.sentChecksum;
 
157
 
 
158
        switch( data.type )
 
159
        {
 
160
        case 0x101:
 
161
                handleReceiveSetup( data );
 
162
                break;
 
163
        case 0x202:
 
164
                handleSendSetup( data );
 
165
                break;
 
166
        case 0x204:
 
167
                handleSendDone( data );
 
168
                break;
 
169
        case 0x205:
 
170
                handleSendResumeRequest( data );
 
171
                break;
 
172
        case 0x106:
 
173
                handleReceiveResumeSetup( data );
 
174
                break;
 
175
        case 0x207:
 
176
                handleSendResumeSetup( data );
 
177
                break;
 
178
        default:
 
179
                kWarning(OSCAR_RAW_DEBUG) << "unknown type " << data.type;
 
180
        }
 
181
 
 
182
        delete t;
 
183
}
 
184
 
 
185
void OftMetaTransfer::initOft()
 
186
{
 
187
        //set up the default values for the oft
 
188
        m_oft.type = 0; //invalid
 
189
        m_oft.cookie = 0;
 
190
        m_oft.fileSize = 0;
 
191
        m_oft.modTime = 0;
 
192
        m_oft.checksum = 0xFFFF0000; //file checksum
 
193
        m_oft.bytesSent = 0;
 
194
        m_oft.sentChecksum = 0xFFFF0000; //checksum of transmitted bytes
 
195
        m_oft.flags = 0x20; //flags; 0x20=not done, 1=done
 
196
        m_oft.fileName.clear();
 
197
        m_oft.fileCount = 1;
 
198
        m_oft.filesLeft = 1;
 
199
        m_oft.partCount = 1;
 
200
        m_oft.partsLeft = 1;
 
201
        m_oft.totalSize = 0;
 
202
}
 
203
 
 
204
void OftMetaTransfer::handleReceiveSetup( const OFT &oft )
 
205
{
 
206
        if ( m_state != SetupReceive )
 
207
                return;
 
208
 
 
209
        kDebug(OSCAR_RAW_DEBUG) << "prompt" << endl
 
210
                << "\tmysize " <<  m_file.size() << endl
 
211
                << "\tsendersize " << oft.fileSize << endl;
 
212
        //do we care about anything *in* the prompt?
 
213
        //just the checksum.
 
214
 
 
215
        m_oft.checksum = oft.checksum;
 
216
        m_oft.modTime = oft.modTime;
 
217
        m_oft.fileCount = oft.fileCount;
 
218
        m_oft.filesLeft = oft.filesLeft;
 
219
        m_oft.partCount = oft.partCount;
 
220
        m_oft.partsLeft = oft.partsLeft;
 
221
        m_oft.totalSize = oft.totalSize;
 
222
        m_oft.fileName = oft.fileName;
 
223
        m_oft.bytesSent = oft.bytesSent;
 
224
        m_oft.fileSize = oft.fileSize;
 
225
 
 
226
        int currentFileIndex = oft.fileCount - oft.filesLeft;
 
227
        if ( currentFileIndex < m_files.count() )
 
228
                m_file.setFileName( m_files.at( currentFileIndex ) );
 
229
        else
 
230
                m_file.setFileName( m_dir + oft.fileName );
 
231
 
 
232
        emit fileStarted( m_oft.fileName, m_file.fileName() );
 
233
        emit fileStarted( m_file.fileName(), m_oft.fileSize );
 
234
        if ( m_file.size() > 0 && m_file.size() <= oft.fileSize )
 
235
        {
 
236
                m_oft.sentChecksum = fileChecksum( m_file );
 
237
                if ( m_file.size() < oft.fileSize )
 
238
                { //could be a partial file
 
239
                        resume();
 
240
                        return;
 
241
                }
 
242
                else if ( m_oft.checksum == m_oft.sentChecksum )
 
243
                { //apparently we've already got it
 
244
                        //TODO: set bytesSent?
 
245
                        done(); //don't redo checksum
 
246
                        return;
 
247
                }
 
248
 
 
249
                //if we didn't break then we need the whole file
 
250
                m_oft.sentChecksum = 0xffff0000;
 
251
        }
 
252
 
 
253
        m_file.open( QIODevice::WriteOnly );
 
254
        //TODO what if open failed?
 
255
        ack();
 
256
}
 
257
 
 
258
void OftMetaTransfer::handleReceiveResumeSetup( const OFT &oft )
 
259
{
 
260
        if ( m_state != SetupReceive )
 
261
                return;
 
262
 
 
263
        kDebug(OSCAR_RAW_DEBUG) << "sender resume" << endl
 
264
                << "\tfilesize\t" << oft.fileSize << endl
 
265
                << "\tmodTime\t" << oft.modTime << endl
 
266
                << "\tbytesSent\t" << oft.bytesSent << endl
 
267
                << "\tflags\t" << oft.flags << endl;
 
268
 
 
269
        QIODevice::OpenMode flags;
 
270
        if ( oft.bytesSent ) //yay, we can resume
 
271
        {
 
272
                flags = QIODevice::WriteOnly | QIODevice::Append;
 
273
        }
 
274
        else
 
275
        { //they insist on sending the whole file :(
 
276
                flags = QIODevice::WriteOnly;
 
277
                m_oft.sentChecksum = 0xffff0000;
 
278
                m_oft.bytesSent = 0;
 
279
        }
 
280
 
 
281
        m_file.open( flags );
 
282
        //TODO what if open failed?
 
283
        rAck();
 
284
}
 
285
 
 
286
void OftMetaTransfer::handleSendSetup( const OFT &oft )
 
287
{
 
288
        if ( m_state != SetupSend )
 
289
                return;
 
290
 
 
291
        kDebug(OSCAR_RAW_DEBUG) << "ack";
 
292
        emit fileStarted( m_file.fileName(), oft.fileName );
 
293
        emit fileStarted( m_file.fileName(), oft.fileSize );
 
294
 
 
295
        //time to send real data
 
296
        //TODO: validate file again, just to be sure
 
297
        m_file.open( QIODevice::ReadOnly );
 
298
        m_state = Sending;
 
299
 
 
300
        //use bytesWritten to trigger writes
 
301
        connect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) );
 
302
        write();
 
303
}
 
304
 
 
305
void OftMetaTransfer::handleSendResumeSetup( const OFT &oft )
 
306
{
 
307
        Q_UNUSED(oft);
 
308
 
 
309
        if ( m_state != SetupSend )
 
310
                return;
 
311
 
 
312
        kDebug(OSCAR_RAW_DEBUG) << "resume ack";
 
313
        //TODO: validate file again, just to be sure
 
314
        m_file.open( QIODevice::ReadOnly );
 
315
        m_file.seek( m_oft.bytesSent );
 
316
        m_state = Sending;
 
317
 
 
318
        //use bytesWritten to trigger writes
 
319
        connect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) );
 
320
        write();
 
321
}
 
322
 
 
323
void OftMetaTransfer::handleSendResumeRequest( const OFT &oft )
 
324
{
 
325
        if ( m_state != SetupSend )
 
326
                return;
 
327
 
 
328
        kDebug(OSCAR_RAW_DEBUG) << "receiver resume" << endl
 
329
                << "\tfilesize\t" << oft.fileSize << endl
 
330
                << "\tmodTime\t" << oft.modTime << endl
 
331
                << "\tbytesSent\t" << oft.bytesSent << endl
 
332
                << "\tflags\t" << oft.flags << endl;
 
333
 
 
334
        if ( fileChecksum( m_file, oft.bytesSent ) == oft.sentChecksum )
 
335
        {
 
336
                m_oft.sentChecksum = oft.sentChecksum;
 
337
                m_oft.bytesSent = oft.bytesSent; //ok, we can resume this
 
338
        }
 
339
 
 
340
        rAgree();
 
341
}
 
342
 
 
343
void OftMetaTransfer::handleSendDone( const OFT &oft )
 
344
{
 
345
        kDebug(OSCAR_RAW_DEBUG) << "done";
 
346
        emit fileFinished( m_file.fileName(), oft.bytesSent );
 
347
 
 
348
        disconnect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) );
 
349
        if ( oft.sentChecksum != m_oft.checksum )
 
350
                kDebug(OSCAR_RAW_DEBUG) << "checksums do not match!";
 
351
 
 
352
        if ( m_oft.filesLeft > 1 )
 
353
        { // Ready for next file
 
354
                m_state = SetupSend;
 
355
                prompt();
 
356
        }
 
357
        else
 
358
        { // Last file, ending connection
 
359
                connect( m_socket, SIGNAL(disconnected()), this, SLOT(emitTransferCompleted()) );
 
360
                m_socket->disconnectFromHost();
 
361
        }
 
362
}
 
363
 
 
364
void OftMetaTransfer::write()
 
365
{
 
366
        if ( m_socket->bytesToWrite() )
 
367
                return; //give hte socket time to catch up
 
368
 
 
369
        //an arbitrary amount to send each time.
 
370
        char data[BUFFER_SIZE];
 
371
 
 
372
        m_file.seek( m_oft.bytesSent );
 
373
        int read = m_file.read( data, BUFFER_SIZE );
 
374
        if( read == -1 )
 
375
        { //FIXME: handle this properly
 
376
                kWarning(OSCAR_RAW_DEBUG) << "failed to read :(";
 
377
                return;
 
378
        }
 
379
 
 
380
        int written = m_socket->write( data, read );
 
381
        if( written == -1 )
 
382
        { //FIXME: handle this properly
 
383
                kWarning(OSCAR_RAW_DEBUG) << "failed to write :(";
 
384
                return;
 
385
        }
 
386
 
 
387
        m_oft.sentChecksum = chunkChecksum( data, written,
 
388
                                            m_oft.sentChecksum, m_oft.bytesSent & 1);
 
389
        m_oft.bytesSent += written;
 
390
        
 
391
        //tell the ui
 
392
        emit fileProcessed( m_oft.bytesSent, m_oft.fileSize );
 
393
        if ( m_oft.bytesSent >= m_oft.fileSize )
 
394
        {
 
395
                m_file.close();
 
396
                disconnect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) );
 
397
                //now we sit and do nothing until either an OFT Done
 
398
                //arrives or the user cancels.
 
399
                //we *should* always get the OFT done right away.
 
400
        }
 
401
}
 
402
 
 
403
void OftMetaTransfer::saveData()
 
404
{
 
405
        QByteArray raw = m_socket->readAll(); //is this safe?
 
406
        int written = m_file.write( raw );
 
407
        if( written == -1 )
 
408
        { //FIXME: handle this properly
 
409
                kWarning(OSCAR_RAW_DEBUG) << "failed to write :(";
 
410
                return;
 
411
        }
 
412
 
 
413
        m_oft.sentChecksum = chunkChecksum( raw.constData(), raw.size(),
 
414
                                            m_oft.sentChecksum, m_oft.bytesSent & 1);
 
415
        m_oft.bytesSent += written;
 
416
        if ( written != raw.size() )
 
417
        {       //FIXME: handle this properly
 
418
                kWarning(OSCAR_RAW_DEBUG) << "didn't write everything we read";
 
419
                doCancel();
 
420
        }
 
421
 
 
422
        //tell the ui
 
423
        emit fileProcessed( m_oft.bytesSent, m_oft.fileSize );
 
424
        if ( m_oft.bytesSent >= m_oft.fileSize )
 
425
        {
 
426
                m_file.close();
 
427
                done();
 
428
        }
 
429
 
 
430
}
 
431
 
 
432
void OftMetaTransfer::sendOft()
 
433
{
 
434
        //now make a transfer out of it
 
435
        OftTransfer t( m_oft );
 
436
        int written = m_socket->write( t.toWire() );
 
437
 
 
438
        if( written == -1 ) //FIXME: handle this properly
 
439
                kDebug(OSCAR_RAW_DEBUG) << "failed to write :(";
 
440
}
 
441
 
 
442
void OftMetaTransfer::prompt()
 
443
{
 
444
        kDebug(OSCAR_RAW_DEBUG) ;
 
445
        m_oft.type = 0x0101; //type = prompt
 
446
 
 
447
        m_oft.filesLeft--;
 
448
        const int index = m_oft.fileCount - m_oft.filesLeft;
 
449
 
 
450
        m_file.setFileName( m_files.at( index ) );
 
451
        QFileInfo fileInfo( m_file );
 
452
 
 
453
        m_oft.modTime = fileInfo.lastModified().toTime_t();
 
454
        m_oft.fileSize = fileInfo.size();
 
455
        m_oft.fileName = fileInfo.fileName();
 
456
        m_oft.checksum = fileChecksum( m_file );
 
457
        m_oft.sentChecksum = 0xFFFF0000;
 
458
        m_oft.bytesSent = 0;
 
459
        sendOft();
 
460
        //now we wait for the other side to ack
 
461
}
 
462
 
 
463
void OftMetaTransfer::ack()
 
464
{
 
465
        kDebug(OSCAR_RAW_DEBUG) ;
 
466
        m_oft.type = 0x0202; //type = ack
 
467
        sendOft();
 
468
        m_state = Receiving;
 
469
}
 
470
 
 
471
void OftMetaTransfer::rAck()
 
472
{
 
473
        kDebug(OSCAR_RAW_DEBUG) ;
 
474
        m_oft.type = 0x0207; //type = resume ack
 
475
        sendOft();
 
476
        m_state = Receiving;
 
477
}
 
478
 
 
479
void OftMetaTransfer::done()
 
480
{
 
481
        kDebug(OSCAR_RAW_DEBUG) ;
 
482
        m_oft.type = 0x0204; //type = done
 
483
        if ( m_oft.sentChecksum != m_oft.checksum )
 
484
                kDebug(OSCAR_RAW_DEBUG) << "checksums do not match!";
 
485
 
 
486
        emit fileFinished( m_file.fileName(), m_oft.bytesSent );
 
487
        if ( m_oft.filesLeft == 1 )
 
488
                m_oft.flags = 1;
 
489
 
 
490
        sendOft();
 
491
 
 
492
        if ( m_oft.filesLeft > 1 )
 
493
        { //Ready for next file
 
494
                m_state = SetupReceive;
 
495
        }
 
496
        else
 
497
        { //Last file, ending connection
 
498
                m_state = Done;
 
499
 
 
500
                connect( m_socket, SIGNAL(disconnected()), this, SLOT(emitTransferCompleted()) );
 
501
                m_socket->disconnectFromHost();
 
502
        }
 
503
}
 
504
 
 
505
void OftMetaTransfer::resume()
 
506
{
 
507
        kDebug(OSCAR_RAW_DEBUG) ;
 
508
        m_oft.type = 0x0205; //type = resume
 
509
        m_oft.bytesSent = m_file.size();
 
510
        sendOft();
 
511
}
 
512
 
 
513
void OftMetaTransfer::rAgree()
 
514
{
 
515
        kDebug(OSCAR_RAW_DEBUG) ;
 
516
        m_oft.type = 0x0106; //type = sender resume
 
517
        sendOft();
 
518
}
 
519
 
 
520
void OftMetaTransfer::doCancel()
 
521
{
 
522
        kDebug(OSCAR_RAW_DEBUG) ;
 
523
        //stop our timer in case we were sending stuff
 
524
        disconnect( m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(write()) );
 
525
        m_socket->close();
 
526
        deleteLater();
 
527
}
 
528
 
 
529
void OftMetaTransfer::emitTransferCompleted()
 
530
{
 
531
        kDebug(OSCAR_RAW_DEBUG) ;
 
532
        
 
533
        emit transferCompleted();
 
534
        deleteLater(); //yay, it's ok to kill everything now
 
535
}
 
536
 
 
537
Oscar::DWORD OftMetaTransfer::fileChecksum( QFile& file, int bytes ) const
 
538
{
 
539
        Oscar::DWORD checksum = 0xFFFF0000;
 
540
        char data[BUFFER_SIZE];
 
541
        int read;
 
542
        int totalRead = 0;
 
543
 
 
544
        file.open( QIODevice::ReadOnly );
 
545
        while ( (read = file.read( data, BUFFER_SIZE )) > 0 )
 
546
        {
 
547
                if ( bytes != -1 && (totalRead + read) >= bytes )
 
548
                {
 
549
                        read = bytes - totalRead;
 
550
                        checksum = chunkChecksum( data, read, checksum, totalRead & 1);
 
551
                        break;
 
552
                }
 
553
                else
 
554
                {
 
555
                        checksum = chunkChecksum( data, read, checksum, totalRead & 1);
 
556
                }
 
557
                totalRead += read;
 
558
        }
 
559
        file.close();
 
560
        
 
561
        if ( read == -1 )
 
562
                return 0xFFFF0000;
 
563
        
 
564
        return checksum;
 
565
}
 
566
 
 
567
Oscar::DWORD OftMetaTransfer::chunkChecksum( const char *buffer, int bufferSize,
 
568
                                             Oscar::DWORD checksum, bool shiftIndex ) const
 
569
{
 
570
        //code adapted from Miranda's oft_calc_checksum
 
571
        const int evenIndex = (shiftIndex) ? 1 : 0;
 
572
        
 
573
        checksum = (checksum >> 16) & 0xffff;
 
574
        for ( int i = 0; i < bufferSize; i++ )
 
575
        {
 
576
                quint16 val = (uchar)buffer[i];
 
577
                
 
578
                if ( (i & 1) == evenIndex )
 
579
                        val = val << 8;
 
580
                
 
581
                if (checksum < val)
 
582
                        checksum -= val + 1;
 
583
                else // simulate carry
 
584
                        checksum -= val;
 
585
        }
 
586
        checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
 
587
        checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
 
588
        return checksum << 16;
 
589
}
 
590
 
 
591
#include "oftmetatransfer.moc"
 
592