- Change leftover port uint's to quint16, save our memory! (yes just some bits)
[konversation:konversation.git] / src / dcc / transfer.cpp
1 /*
2   This program is free software; you can redistribute it and/or modify
3   it under the terms of the GNU General Public License as published by
4   the Free Software Foundation; either version 2 of the License, or
5   (at your option) any later version.
6 */
7
8 /*
9   Copyright (C) 2002-2004 Dario Abatianni <eisfuchs@tigress.com>
10   Copyright (C) 2004-2007 Shintaro Matsuoka <shin@shoegazed.org>
11   Copyright (C) 2004,2005 John Tapsell <john@geola.co.uk>
12   Copyright (C) 2009 Bernd Buschinski <b.buschinski@web.de>
13 */
14
15 #include "transfer.h"
16 #include "application.h"
17 #include "connectionmanager.h"
18 #include "notificationhandler.h"
19 #include "preferences.h"
20
21 #include <QFileInfo>
22
23 namespace Konversation
24 {
25     namespace DCC
26     {
27         Transfer::Transfer( Type dccType, QObject* parent )
28             : QObject(parent)
29         {
30             kDebug();
31
32             m_type = dccType;
33
34             m_status = Configuring;
35
36             m_ownPort = 0;
37             m_fileSize = 0;
38             m_resumed = false;
39             m_reverse = false;
40             m_connectionId = -1;  // Not configured
41             m_timeLeft = Transfer::NotInTransfer;
42             m_transferringPosition = 0;
43             m_transferStartPosition = 0;
44             m_averageSpeed = 0.0;
45             m_currentSpeed = 0.0;
46
47             m_bufferSize = Preferences::self()->dccBufferSize();
48             m_buffer = new char[ m_bufferSize ];
49
50             connect( &m_loggerTimer, SIGNAL( timeout() ), this, SLOT( logTransfer() ) );
51
52             m_timeOffer = QDateTime::currentDateTime();
53         }
54
55         Transfer::~Transfer()
56         {
57             kDebug();
58         }
59
60         void Transfer::setConnectionId( int id )
61         {
62             if ( getStatus() == Configuring || getStatus() == Queued )
63                 m_connectionId = id;
64         }
65
66         void Transfer::setPartnerNick( const QString& nick )
67         {
68             if ( getStatus() == Configuring || getStatus() == Queued )
69                 m_partnerNick = nick;
70         }
71
72         bool Transfer::queue()
73         {
74             kDebug();
75             if ( getStatus() != Configuring )
76                 return false;
77
78             if ( m_fileName.isEmpty() )
79                 return false;
80
81             if ( m_connectionId == -1 || m_partnerNick.isEmpty() )
82                 return false;
83
84             setStatus( Queued );
85             return true;
86         }
87
88         void Transfer::startTransferLogger()
89         {
90             m_timeTransferStarted = QDateTime::currentDateTime();
91             m_loggerBaseTime.start();
92             m_loggerTimer.start( 100 );
93         }
94
95         void Transfer::finishTransferLogger()
96         {
97             if ( m_timeTransferFinished.isNull() )
98                 m_timeTransferFinished = QDateTime::currentDateTime();
99             m_loggerTimer.stop();
100             updateTransferMeters();
101         }
102
103         // called by m_loggerTimer
104         void Transfer::logTransfer()
105         {
106             m_transferLogTime.append( m_loggerBaseTime.elapsed() );
107             m_transferLogPosition.append( m_transferringPosition );
108             updateTransferMeters();
109         }
110
111         void Transfer::cleanUp()
112         {
113             kDebug();
114             delete[] m_buffer;
115             m_buffer = 0;
116             m_loggerTimer.stop();
117         }
118
119         void Transfer::removedFromView()
120         {
121             emit removed(this);
122         }
123
124         // just for convenience
125         void Transfer::failed( const QString& errorMessage )
126         {
127             cleanUp();
128             Application* konv_app = Application::instance();
129             Server* server = konv_app->getConnectionManager()->getServerByConnectionId( m_connectionId );
130             if (server)
131             {
132                 kDebug() << "notification:" << errorMessage;
133                 konv_app->notificationHandler()->dccError(server->getStatusView(), errorMessage);
134             }
135             setStatus( Failed, errorMessage );
136             emit done( this );
137         }
138
139         void Transfer::setStatus( Status status, const QString& statusDetail )
140         {
141             bool changed = ( status != m_status );
142             Status oldStatus = m_status;
143             m_status = status;
144             m_statusDetail = statusDetail;
145             if ( changed )
146             {
147                 emit statusChanged( this, m_status, oldStatus );
148             }
149
150             if (m_status == Done)
151             {
152                 Application* konv_app = Application::instance();
153                 Server* server = konv_app->getConnectionManager()->getServerByConnectionId( m_connectionId );
154                 if (server)
155                 {
156                     kDebug() << "notification:" << m_fileName;
157                     konv_app->notificationHandler()->dccTransferDone(server->getStatusView(), m_fileName);
158                 }
159             }
160         }
161
162         void Transfer::updateTransferMeters()
163         {
164             const int timeToCalc = 5;
165
166             if ( getStatus() == Transferring )
167             {
168                 // update CurrentSpeed
169
170                 // remove too old data
171                 QList<int>::iterator itTime = m_transferLogTime.begin();
172                 QList<KIO::fileoffset_t>::iterator itPos = m_transferLogPosition.begin();
173                 while ( itTime != m_transferLogTime.end() && ( m_transferLogTime.last() - (*itTime) > timeToCalc * 1000 ) )
174                 {
175                     itTime = m_transferLogTime.erase( itTime );
176                     itPos = m_transferLogPosition.erase( itPos );
177                 }
178
179                 // shift the base of the time (m_transferLoggerBaseTime)
180                 // reason: QTime can't handle a time longer than 24 hours
181                 int shiftOffset = m_loggerBaseTime.restart();
182                 itTime = m_transferLogTime.begin();
183                 for ( ; itTime != m_transferLogTime.end() ; ++itTime )
184                     (*itTime) = (*itTime) - shiftOffset;
185
186                 // The logTimer is 100ms, as 200ms is below 1sec we get "undefined" speed
187                 if ( m_transferLogTime.count() >= 2 && m_timeTransferStarted.secsTo( QDateTime::currentDateTime()) > 0)
188                 {
189                     // FIXME: precision of average speed is too bad
190                     m_averageSpeed = (double)( m_transferringPosition - m_transferStartPosition ) / (double)m_timeTransferStarted.secsTo( QDateTime::currentDateTime() );
191                     m_currentSpeed = (double)( m_transferLogPosition.last() - m_transferLogPosition.front() ) / (double)( m_transferLogTime.last() - m_transferLogTime.front() ) * 1000;
192                 }
193                 else // avoid zero devision
194                 {
195                     m_averageSpeed = Transfer::Calculating;
196                     m_currentSpeed = Transfer::Calculating;
197                 }
198
199                 // update the remaining time
200                 if  (m_transferringPosition == (KIO::fileoffset_t)m_fileSize)
201                 {
202                     m_timeLeft = 0;
203                 }
204                 else if ( m_currentSpeed <= 0 )
205                 {
206                     m_timeLeft = Transfer::InfiniteValue;
207                 }
208                 else
209                 {
210                     m_timeLeft = (int)( (double)( m_fileSize - m_transferringPosition ) / m_currentSpeed );
211                 }
212             }
213             else if ( m_status >= Done )
214             {
215                 if ( m_timeTransferStarted.secsTo( m_timeTransferFinished ) > 1 )
216                 {
217                     m_averageSpeed = (double)( m_transferringPosition - m_transferStartPosition ) / (double)m_timeTransferStarted.secsTo( m_timeTransferFinished );
218                 }
219                 else
220                 {
221                     m_averageSpeed = Transfer::InfiniteValue;
222                 }
223
224                 m_currentSpeed = 0;
225                 if (m_status == Done)
226                 {
227                     m_timeLeft = 0;
228                 }
229                 else
230                 {
231                     m_timeLeft = Transfer::NotInTransfer;
232                 }
233             }
234             else
235             {
236                 m_averageSpeed = 0;
237                 m_currentSpeed = 0;
238                 m_timeLeft = Transfer::NotInTransfer;
239             }
240         }
241
242         QString Transfer::sanitizeFileName( const QString& fileName )
243         {
244             QString fileNameTmp = QFileInfo( fileName ).fileName();
245             if ( fileNameTmp.startsWith( '.' ) )
246                 fileNameTmp.replace( 0, 1, '_' );         // Don't create hidden files
247             if ( fileNameTmp.isEmpty() )
248                 fileNameTmp = "unnamed";
249             return fileNameTmp;
250         }
251
252         quint32 Transfer::intel( quint32 value )
253         {
254             value = ( (value & 0xff000000) >> 24 ) +
255                     ( (value & 0x00ff0000) >> 8  ) +
256                     ( (value & 0x0000ff00) << 8  ) +
257                     ( (value & 0x000000ff) << 24 );
258
259             return value;
260         }
261
262         Transfer::Type Transfer::getType() const
263         {
264             return m_type;
265         }
266
267         Transfer::Status Transfer::getStatus() const
268         {
269             return m_status;
270         }
271
272         const QString& Transfer::getStatusDetail() const
273         {
274             return m_statusDetail;
275         }
276
277         QDateTime Transfer::getTimeOffer() const
278         {
279             return m_timeOffer;
280         }
281
282         int Transfer::getConnectionId() const
283         {
284             return m_connectionId;
285         }
286
287         QString Transfer::getOwnIp() const
288         {
289             return m_ownIp;
290         }
291
292         quint16 Transfer::getOwnPort() const
293         {
294             return m_ownPort;
295         }
296
297         QString Transfer::getPartnerNick() const
298         {
299             return m_partnerNick;
300         }
301
302         QString Transfer::getPartnerIp() const
303         {
304             return m_partnerIp;
305         }
306
307         quint16 Transfer::getPartnerPort() const
308         {
309             return m_partnerPort;
310         }
311
312         QString Transfer::getFileName() const
313         {
314             return m_fileName;
315         }
316
317         KIO::filesize_t Transfer::getFileSize() const
318         {
319             return m_fileSize;
320         }
321
322         KIO::fileoffset_t Transfer::getTransferringPosition() const
323         {
324             return m_transferringPosition;
325         }
326
327         KIO::fileoffset_t Transfer::getTransferStartPosition() const
328         {
329             return m_transferStartPosition;
330         }
331
332         KUrl Transfer::getFileURL() const
333         {
334             return m_fileURL;
335         }
336
337         bool Transfer::isResumed() const
338         {
339             return m_resumed;
340         }
341
342         bool Transfer::isReverse() const
343         {
344             return m_reverse;
345         }
346
347         QString Transfer::getReverseToken() const
348         {
349             return m_reverseToken;
350         }
351
352         transferspeed_t Transfer::getAverageSpeed() const
353         {
354             return m_averageSpeed;
355         }
356
357         transferspeed_t Transfer::getCurrentSpeed() const
358         {
359             return m_currentSpeed;
360         }
361
362         int Transfer::getTimeLeft() const
363         {
364             return m_timeLeft;
365         }
366
367         int Transfer::getProgress() const
368         {
369             if (getFileSize() == 0)
370             {
371                 return 0;
372             }
373             else
374             {
375                 return (int)( ( (double)getTransferringPosition() / (double)getFileSize() ) * 100.0 );
376             }
377         }
378
379         QDateTime Transfer::getTimeTransferStarted() const
380         {
381             return m_timeTransferStarted;
382         }
383
384         QDateTime Transfer::getTimeTransferFinished() const
385         {
386             return m_timeTransferFinished;
387         }
388
389         QString Transfer::transferFileName(const QString & fileName)
390         {
391             if (fileName.contains(' ') && !(fileName.startsWith('\"') && fileName.endsWith('\"')))
392                 return '\"'+fileName+'\"';
393
394             return fileName;
395         }
396
397     }
398 }
399
400 #include "transfer.moc"