Added include path for libv4l2 includes, rather than assuming they are
[kdenetwork.git] / kopete / libkopete / kopetetransfermanager.cpp
blobede0311ba43a61bfc2436ba3392f4cbe0a9ec945
1 /*
2 kopetetransfermanager.cpp
4 Copyright (c) 2002-2003 by Nick Betcher <nbetcher@kde.org>
5 Copyright (c) 2002-2003 by Richard Smith <kopete@metafoo.co.uk>
6 Copyright (c) 2008 by Roman Jarosz <kedgedev@centrum.cz>
8 Kopete (c) 2002-2008 by the Kopete developers <kopete-devel@kde.org>
10 *************************************************************************
11 * *
12 * This library is free software; you can redistribute it and/or *
13 * modify it under the terms of the GNU Lesser General Public *
14 * License as published by the Free Software Foundation; either *
15 * version 2 of the License, or (at your option) any later version. *
16 * *
17 *************************************************************************
20 #include <QtCore/QTimerEvent>
21 #include <QtGui/QTextDocument>
23 #include <klocale.h>
24 #include <kdebug.h>
25 #include <kfiledialog.h>
26 #include <kfileitem.h>
27 #include <kmessagebox.h>
28 #include <kio/jobuidelegate.h>
29 #include <kuiserverjobtracker.h>
31 #include "kopetemetacontact.h"
32 #include "kopetecontact.h"
33 #include "kopetemessage.h"
34 #include "kopetechatsession.h"
35 #include "kopeteuiglobal.h"
37 #include "kopetetransfermanager.h"
39 /***************************
40 * Kopete::FileTransferInfo *
41 ***************************/
43 Kopete::FileTransferInfo::FileTransferInfo()
45 mId = 0;
46 mContact = 0;
47 mSize = 0;
48 mSaveToDirectory = false;
51 Kopete::FileTransferInfo::FileTransferInfo( Kopete::Contact *contact, const QStringList& files, const unsigned long size, const QString &recipient, KopeteTransferDirection di, const unsigned int id, QString internalId, const QPixmap &preview, bool saveToDirectory )
53 mContact = contact;
54 mFiles = files;
55 mId = id;
56 mSize = size;
57 mRecipient = recipient;
58 m_intId= internalId;
59 mDirection= di;
60 mPreview = preview;
61 mSaveToDirectory = saveToDirectory;
64 /***************************
65 * Kopete::Transfer *
66 ***************************/
68 static const int TransferRateWindowLength = 10;
69 static const int TransferRateTimerDelay = 1000;
71 class Kopete::Transfer::Private
73 public:
74 Private( const Kopete::FileTransferInfo &ftInfo )
75 : info( ftInfo ), transferRateTimer( 0 )
77 memset( transferRate, 0, sizeof(transferRate) );
80 FileTransferInfo info;
81 KUrl target;
83 //if ft has one file then localUrl is file otherwise it's directory
84 KUrl localUrl;
86 int transferRate[TransferRateWindowLength];
87 int transferRateTimer;
90 Kopete::Transfer::Transfer( const Kopete::FileTransferInfo &kfti, const QString &localFile, bool showProgressInfo)
91 : KIO::Job(), d( new Private(kfti) )
93 this->setUiDelegate(new KIO::JobUiDelegate());
94 if(showProgressInfo)
95 KIO::getJobTracker()->registerJob(this);
97 KUrl targ; targ.setPath( localFile );
98 d->localUrl = targ;
99 init( targ, showProgressInfo );
102 Kopete::Transfer::Transfer( const Kopete::FileTransferInfo &kfti, const Kopete::Contact *contact, bool showProgressInfo)
103 : KIO::Job(), d( new Private(kfti) )
105 this->setUiDelegate(new KIO::JobUiDelegate());
106 if(showProgressInfo)
107 KIO::getJobTracker()->registerJob(this);
109 // TODO: use mInfo.url().fileName() after move to protocol-aware filetransfers
110 KUrl targ; targ.setPath( d->info.file() );
111 init( displayURL( contact, targ.fileName() ), showProgressInfo );
114 void Kopete::Transfer::init( const KUrl &target, bool showProgressInfo )
116 d->target = target;
117 setTotalAmount( KJob::Files, d->info.files().count() );
118 setTotalAmount( KJob::Bytes, d->info.size() );
120 if( showProgressInfo )
121 emitCopying( sourceURL(), destinationURL() );
123 connect( this, SIGNAL( result( KJob* ) ), SLOT( slotResultEmitted() ) );
125 ui()->setAutoErrorHandlingEnabled( true );
128 Kopete::Transfer::~Transfer()
130 stopTransferRateTimer();
132 delete d;
135 const Kopete::FileTransferInfo &Kopete::Transfer::info() const
137 return d->info;
140 KUrl Kopete::Transfer::displayURL( const Kopete::Contact *contact, const QString &file )
142 KUrl url;
143 url.setProtocol( QString::fromLatin1("kopete") );
145 QString host;
146 if( !contact )
147 host = QString::fromLatin1("unknown origin");
148 else if( contact->metaContact() )
149 host = contact->metaContact()->displayName();
150 else
151 host = contact->contactId();
152 url.setHost(host);
154 // url.setPath( contact->protocol()->displayName() );
156 url.setFileName( file );
157 return url;
160 void Kopete::Transfer::slotNextFile( const QString &sourceFile, const QString &destinationFile )
162 KUrl src;
163 KUrl dest;
165 kDebug() << "source: " << sourceFile << " destination: " << destinationFile;
166 if( d->info.direction() == Kopete::FileTransferInfo::Incoming )
168 KUrl url( sourceFile );
169 src = displayURL( d->info.contact(), url.fileName() );
170 dest.setPath( destinationFile );
172 else
174 src.setPath( sourceFile );
175 KUrl url( destinationFile );
176 dest = displayURL( d->info.contact(), url.fileName() );
179 setProcessedAmount( KJob::Files, processedAmount(KJob::Files) + 1 );
180 emit description(this, i18n("Copying"),
181 qMakePair(i18n("Source"), src.prettyUrl()),
182 qMakePair(i18n("Destination"), dest.prettyUrl()));
185 // TODO: add possibility of network file transfers;
186 // call mInfo->url() not file()
187 KUrl Kopete::Transfer::sourceURL()
189 if( d->info.direction() == Kopete::FileTransferInfo::Incoming )
190 return displayURL( d->info.contact(), d->info.file() );
191 else
193 KUrl url; url.setPath( d->info.file() );
194 return url;
198 KUrl Kopete::Transfer::destinationURL()
200 return d->target;
203 void Kopete::Transfer::emitCopying(const KUrl &src, const KUrl &dest)
205 emit description(this, i18n("Copying"),
206 qMakePair(i18n("Source"), src.prettyUrl()),
207 qMakePair(i18n("Destination"), dest.prettyUrl()));
210 void Kopete::Transfer::slotProcessed( unsigned int bytes )
212 if ( !d->transferRateTimer )
213 d->transferRateTimer = startTimer( TransferRateTimerDelay );
215 d->transferRate[0] += (bytes - processedAmount(KJob::Bytes));
217 setProcessedAmount( KJob::Bytes, bytes );
218 emitPercent( bytes, d->info.size() );
221 void Kopete::Transfer::timerEvent( QTimerEvent *event )
223 if ( event->timerId() != d->transferRateTimer )
225 KIO::Job::timerEvent( event );
226 return;
229 // Calculate average transferRate
230 qint64 bytesPerSecond = 0;
231 for ( int i = 0; i < TransferRateWindowLength; ++i )
232 bytesPerSecond += d->transferRate[i];
234 bytesPerSecond /= qint64( TransferRateWindowLength );
236 for ( int i = TransferRateWindowLength - 2; i >= 0; --i )
237 d->transferRate[i + 1] = d->transferRate[i];
239 d->transferRate[0] = 0;
240 emitSpeed( bytesPerSecond );
242 // Stop the timer if there is no activity.
243 if ( bytesPerSecond == 0 )
244 stopTransferRateTimer();
247 void Kopete::Transfer::slotComplete()
249 stopTransferRateTimer();
250 showHtmlMessage( i18n("File transfer %1 completed.", fileForMessage() ) );
251 emitResult();
254 void Kopete::Transfer::slotError( int error, const QString &errorText )
256 stopTransferRateTimer();
257 setError(error);
258 setErrorText(errorText);
260 showHtmlMessage( i18n("File transfer %1 failed.", fileForMessage() ) );
261 emitResult();
264 void Kopete::Transfer::slotResultEmitted()
266 if( error() == KIO::ERR_USER_CANCELED )
268 stopTransferRateTimer();
269 showHtmlMessage( i18n("You cancelled file transfer %1", fileForMessage() ) );
270 emit transferCanceled();
274 void Kopete::Transfer::slotCancelled()
276 stopTransferRateTimer();
277 showHtmlMessage( i18n("File transfer %1 cancelled.", fileForMessage() ) );
278 emitResult();
279 //slotError( KIO::ERR_ABORTED, i18n("File transfer cancelled.") );
282 bool Kopete::Transfer::showMessage( QString text ) const
284 Kopete::ChatSession *cs = d->info.contact()->manager();
285 if (! cs)
286 return false;
288 Kopete::Message msg;
289 msg.setPlainBody( text );
290 cs->appendMessage( msg );
291 return true;
294 bool Kopete::Transfer::showHtmlMessage( QString text ) const
296 Kopete::ChatSession *cs = d->info.contact()->manager();
297 if (! cs)
298 return false;
300 Kopete::Message msg;
301 msg.setHtmlBody( text );
302 cs->appendMessage( msg );
303 return true;
306 QString Kopete::Transfer::fileForMessage() const
308 if( d->info.direction() == Kopete::FileTransferInfo::Incoming )
309 return QString( "<a href=\"%1\">%2</a>" ).arg( d->localUrl.url(), Qt::escape( d->localUrl.path() ) );
310 else
311 return Qt::escape( d->info.file() );
314 void Kopete::Transfer::stopTransferRateTimer()
316 if ( d->transferRateTimer )
318 killTimer( d->transferRateTimer );
319 d->transferRateTimer = 0;
323 /***************************
324 * Kopete::TransferManager *
325 ***************************/
327 Kopete::TransferManager* Kopete::TransferManager::transferManager()
329 static TransferManager s(0L);
330 return &s;
333 Kopete::TransferManager::TransferManager( QObject *parent ) : QObject( parent )
337 Kopete::Transfer* Kopete::TransferManager::addTransfer( Kopete::Contact *contact, const QString& file, const unsigned long size, const QString &recipient, Kopete::FileTransferInfo::KopeteTransferDirection di)
339 return addTransfer( contact, QStringList(file), size, recipient, di );
342 Kopete::Transfer* Kopete::TransferManager::addTransfer( Kopete::Contact *contact, const QStringList& files, const unsigned long size, const QString &recipient, Kopete::FileTransferInfo::KopeteTransferDirection di)
344 // Use message id to make file transfer id unique because we already use it for incoming file transfer.
345 uint id = Kopete::Message::nextId();
346 Kopete::FileTransferInfo info(contact, files, size, recipient, di, id);
347 Kopete::Transfer *trans = new Kopete::Transfer(info, contact);
348 connect(trans, SIGNAL(result(KJob *)), this, SLOT(slotComplete(KJob *)));
349 mTransfersMap.insert(id, trans);
350 return trans;
353 unsigned int Kopete::TransferManager::askIncomingTransfer( Kopete::Contact *contact, const QString& file, const unsigned long size, const QString& description, QString internalId, const QPixmap &preview )
355 return askIncomingTransfer( contact, QStringList( file ), size, description, internalId, preview );
358 unsigned int Kopete::TransferManager::askIncomingTransfer( Kopete::Contact *contact, const QStringList& files, const unsigned long size, const QString& description, QString internalId, const QPixmap &preview )
360 Kopete::ChatSession *cs = contact->manager( Kopete::Contact::CanCreate );
361 if ( !cs )
362 return 0;
364 const QString dn = contact->metaContact() ? contact->metaContact()->displayName() : contact->contactId();
366 QString msgFileName;
367 foreach ( const QString &file, files )
369 QString trimmedFile = file.trimmed();
370 if ( !trimmedFile.isEmpty() )
371 msgFileName += trimmedFile + ", ";
374 // Remove ", " from end
375 if ( msgFileName.size() >= 2 )
376 msgFileName = msgFileName.left( msgFileName.size() - 2 );
378 Kopete::Message msg( contact, cs->myself() );
379 msg.setType( Kopete::Message::TypeFileTransferRequest );
380 msg.setDirection( Kopete::Message::Inbound );
381 msg.setPlainBody( description );
382 msg.setFileName( msgFileName );
383 msg.setFileSize( size );
384 msg.setFilePreview( preview );
386 Kopete::FileTransferInfo info( contact, files, size, dn, Kopete::FileTransferInfo::Incoming,
387 msg.id(), internalId, preview, (files.count() > 1) );
388 mTransferRequestInfoMap.insert( msg.id(), info );
390 cs->appendMessage( msg );
392 return msg.id();
395 void Kopete::TransferManager::saveIncomingTransfer( unsigned int id )
397 Kopete::FileTransferInfo info = mTransferRequestInfoMap.value( id );
398 if ( !info.isValid() )
399 return;
401 KConfigGroup cg( KGlobal::config(), "File Transfer" );
402 const QString defaultPath = cg.readEntry( "defaultPath", QDir::homePath() );
403 KUrl url = defaultPath + QLatin1String( "/" ) + info.file();
405 if ( info.saveToDirectory() )
406 url = getSaveDir( url );
407 else
408 url = getSaveFile( url );
410 if ( !url.isValid() )
412 emit askIncomingDone( id );
413 emit refused( info );
414 mTransferRequestInfoMap.remove( id );
415 return;
418 const QString directory = ( info.saveToDirectory() ) ? url.path() : url.directory();
419 if( !directory.isEmpty() )
420 cg.writeEntry( "defaultPath", directory );
422 Kopete::Transfer *trans = new Kopete::Transfer( info, url.path() );
423 connect( trans, SIGNAL(result(KJob *)), this, SLOT(slotComplete(KJob *)) );
424 mTransfersMap.insert( info.transferId(), trans );
425 emit askIncomingDone( id );
426 emit accepted( trans, url.path() );
427 mTransferRequestInfoMap.remove( id );
430 void Kopete::TransferManager::cancelIncomingTransfer( unsigned int id )
432 Kopete::FileTransferInfo info = mTransferRequestInfoMap.value( id );
433 if ( !info.isValid() )
434 return;
436 emit askIncomingDone( id );
437 emit refused( info );
438 mTransferRequestInfoMap.remove( id );
441 void Kopete::TransferManager::slotComplete(KJob *job)
443 Kopete::Transfer *transfer=dynamic_cast<Kopete::Transfer*>(job);
444 if(!transfer)
445 return;
447 emit done(transfer);
449 for( QMap<unsigned, Kopete::Transfer*>::Iterator it = mTransfersMap.begin();
450 it != mTransfersMap.end(); ++it )
452 if( it.value() == transfer )
454 removeTransfer(it.key());
455 break;
460 void Kopete::TransferManager::sendFile( const KUrl &file, const QString &fname, unsigned long sz,
461 bool mustBeLocal, QObject *sendTo, const char *slot )
463 KUrl url = file;
464 QString filename;
465 unsigned int size = 0;
467 //If the file location is null, then get it from a file open dialog
468 if( !url.isValid() )
469 url = KFileDialog::getOpenUrl( KUrl(), QString::fromLatin1("*"), 0l, i18n( "Kopete File Transfer" ));
470 else
472 filename = fname;
473 size = sz;
476 if( filename.isEmpty() )
477 filename = url.fileName();
479 if( size == 0 )
481 KFileItem finfo(KFileItem::Unknown, KFileItem::Unknown, url);
482 size = (unsigned long)finfo.size();
485 if( !url.isEmpty() )
487 if( mustBeLocal && !url.isLocalFile() )
489 KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
490 i18n( "Sorry, sending files which are not stored locally is not yet supported by this protocol.\n"
491 "Please copy this file to your computer and try again." ) );
493 else
495 connect( this, SIGNAL(sendFile(const KUrl&, const QString&, unsigned int)), sendTo, slot );
496 emit sendFile( url, filename, size );
497 disconnect( this, SIGNAL(sendFile(const KUrl&, const QString&, unsigned int)), sendTo, slot );
502 void Kopete::TransferManager::removeTransfer( unsigned int id )
504 mTransfersMap.remove(id);
505 //we don't need to delete the job, the job get deleted itself
508 KUrl Kopete::TransferManager::getSaveFile( const KUrl& startDir ) const
510 KUrl url = startDir;
511 for ( ;; )
513 url = KFileDialog::getSaveUrl( url, QLatin1String( "*" ), 0, i18n( "File Transfer" ) );
514 if ( !url.isValid() )
515 return url;
517 if ( !url.isLocalFile() )
519 KMessageBox::messageBox( 0, KMessageBox::Sorry, i18n( "You must provide a valid local filename" ) );
520 continue;
523 QFileInfo fileInfo( url.path() );
524 if ( fileInfo.exists() )
526 if ( !fileInfo.isWritable() )
528 KMessageBox::messageBox( 0, KMessageBox::Sorry, i18n( "You do not have permission to write to selected file" ) );
529 continue;
532 int ret = KMessageBox::warningContinueCancel( 0, i18n( "The file '%1' already exists.\nDo you want to overwrite it ?", url.path() ),
533 i18n( "Overwrite File" ), KStandardGuiItem::save() );
534 if ( ret == KMessageBox::Cancel )
535 continue;
537 else
539 QFileInfo dirInfo( url.directory() );
540 if ( !dirInfo.isDir() || !dirInfo.exists() )
542 KMessageBox::messageBox( 0, KMessageBox::Sorry, i18n( "The directory %1 does not exist", dirInfo.fileName() ) );
543 continue;
545 else if ( !dirInfo.isWritable() )
547 KMessageBox::messageBox( 0, KMessageBox::Sorry, i18n( "You do not have permission to write to selected directory" ) );
548 continue;
552 break;
554 return url;
557 KUrl Kopete::TransferManager::getSaveDir( const KUrl& startDir ) const
559 KUrl url = startDir;
560 for ( ;; )
562 url = KFileDialog::getExistingDirectoryUrl( url, 0, i18n( "File Transfer" ) );
563 if ( !url.isValid() )
564 return url;
566 if ( !url.isLocalFile() )
568 KMessageBox::messageBox( 0, KMessageBox::Sorry, i18n( "You must provide a valid local directory" ) );
569 continue;
572 QFileInfo dirInfo( url.path() );
573 if ( !dirInfo.isDir() || !dirInfo.exists() )
575 KMessageBox::messageBox( 0, KMessageBox::Sorry, i18n( "The directory %1 does not exist", dirInfo.filePath() ) );
576 continue;
578 else if ( !dirInfo.isWritable() )
580 KMessageBox::messageBox( 0, KMessageBox::Sorry, i18n( "You do not have permission to write to selected directory" ) );
581 continue;
583 break;
585 return url;
588 #include "kopetetransfermanager.moc"