1
//=============================================================================
3
// File : httpfiletransfer.h
4
// Creation date : Tue Apr 22 2003 02:00:12 GMT by Szymon Stefanek
6
// This config is part of the KVirc irc client distribution
7
// Copyright (C) 2003-2008 Szymon Stefanek (pragma at kvirc dot net)
9
// This program is FREE software. You can redistribute it and/or
10
// modify it under the terms of the GNU General Public License
11
// as published by the Free Software Foundation; either version 2
12
// of the License, or (at your opinion) any later version.
14
// This program is distributed in the HOPE that it will be USEFUL,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
// See the GNU General Public License for more details.
19
// You should have received a copy of the GNU General Public License
20
// along with this program. If not, write to the Free Software Foundation,
21
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
//=============================================================================
25
#include "httpfiletransfer.h"
29
#include "kvi_locale.h"
30
#include "kvi_window.h"
31
#include "kvi_iconmanager.h"
32
#include "kvi_netutils.h"
33
#include "kvi_kvs_eventtriggers.h"
34
#include "kvi_console.h"
35
#include "kvi_kvs_script.h"
36
#include "kvi_tal_popupmenu.h"
40
static KviPointerList<KviHttpFileTransfer> * g_pHttpFileTransfers = 0;
41
static QPixmap * g_pHttpIcon = 0;
44
KviHttpFileTransfer::KviHttpFileTransfer()
47
init(); // ensure we're initialized
48
g_pHttpFileTransfers->append(this);
50
m_tStartTime = kvi_unixTime();
51
m_tTransferStartTime = 0;
52
m_tTransferEndTime = 0;
54
m_bNotifyCompletion = true;
56
m_pAutoCleanTimer = 0;
59
m_pHttpRequest = new KviHttpRequest();
61
connect(m_pHttpRequest,SIGNAL(status(const QString &)),this,SLOT(statusMessage(const QString &)));
62
connect(m_pHttpRequest,SIGNAL(terminated(bool)),this,SLOT(transferTerminated(bool)));
63
connect(m_pHttpRequest,SIGNAL(header(KviPointerHashTable<const char *,KviStr> *)),this,SLOT(headersReceived(KviPointerHashTable<const char *,KviStr> *)));
64
connect(m_pHttpRequest,SIGNAL(resolvingHost(const QString &)),this,SLOT(resolvingHost(const QString &)));
65
connect(m_pHttpRequest,SIGNAL(requestSent(const QStringList &)),this,SLOT(requestSent(const QStringList &)));
66
connect(m_pHttpRequest,SIGNAL(contactingHost(const QString &)),this,SLOT(contactingHost(const QString &)));
67
connect(m_pHttpRequest,SIGNAL(receivedResponse(const QString &)),this,SLOT(receivedResponse(const QString &)));
68
connect(m_pHttpRequest,SIGNAL(connectionEstabilished()),this,SLOT(connectionEstabilished()));
70
m_eGeneralStatus = Initializing;
71
m_szStatusString = __tr2qs_ctx("Initializing","http");
74
KviHttpFileTransfer::~KviHttpFileTransfer()
76
g_pHttpFileTransfers->removeRef(this);
77
delete m_pHttpRequest;
80
m_pAutoCleanTimer->stop();
81
delete m_pAutoCleanTimer;
85
void KviHttpFileTransfer::autoClean()
91
QString KviHttpFileTransfer::localFileName()
93
return m_pHttpRequest->fileName();
96
void KviHttpFileTransfer::abort()
98
m_pHttpRequest->abort();
101
void KviHttpFileTransfer::fillContextPopup(KviTalPopupMenu * m)
103
int id = m->insertItem(__tr2qs_ctx("Abort","http"),this,SLOT(abort()));
104
if(!active())m->setItemEnabled(id,false);
107
bool KviHttpFileTransfer::active()
109
return ((m_eGeneralStatus == Connecting) || (m_eGeneralStatus == Downloading));
112
void KviHttpFileTransfer::displayPaint(QPainter * p,int column, QRect rect)
114
int width = rect.width(), height = rect.height();
116
bool bIsTerminated = ((m_eGeneralStatus == Success) || (m_eGeneralStatus == Failure));
120
case COLUMN_TRANSFERTYPE:
123
switch(m_eGeneralStatus)
126
case Connecting: offset = 0; break;
127
case Downloading: offset = 48; break;
128
case Success: offset = 96; break;
129
case Failure: offset = 144; break;
131
p->drawPixmap(rect.left() + 3, rect.top() + 3,*g_pHttpIcon,offset,0,48,64);
134
case COLUMN_FILEINFO:
136
QFontMetrics fm(p->font());
138
QString szFrom = __tr2qs_ctx("From: ","http");
139
QString szTo = __tr2qs_ctx("To: ","http");
141
int daW1 = fm.width(szFrom);
142
int daW2 = fm.width(szTo);
143
if(daW1 < daW2)daW1 = daW2;
144
int iLineSpacing = fm.lineSpacing();
146
p->setPen(Qt::black);
148
int iY = rect.top() + 4;
150
p->drawText(rect.left() + 4 + daW1,iY,width - (8 + daW1),height - 8,Qt::AlignTop | Qt::AlignLeft,m_pHttpRequest->url().url());
152
if(!(m_pHttpRequest->fileName().isEmpty()))
154
p->drawText(rect.left() + 4 + daW1,iY,width - (8 + daW1),height - 8,Qt::AlignTop | Qt::AlignLeft,m_pHttpRequest->fileName());
159
p->setPen(Qt::darkGray);
161
p->drawText(rect.left() + 4, rect.top() + 4,width - 8,height - 8,Qt::AlignTop | Qt::AlignLeft,szFrom);
162
p->drawText(rect.left() + 4, rect.top() + 4 + iLineSpacing,width - 8,height - 8,Qt::AlignTop | Qt::AlignLeft,szTo);
164
p->setPen(QColor(180,180,200));
168
p->drawRect(rect.left() + 4, rect.top() + height - (iLineSpacing + 4),width - 8,iLineSpacing);
169
p->fillRect(rect.left() + 5, rect.top() + height - (iLineSpacing + 3),width - 10,iLineSpacing - 2,bIsTerminated ? QColor(210,210,210) : QColor(190,190,240));
170
p->setPen(Qt::black);
171
p->drawText(rect.left() + 7, rect.top() + height - (iLineSpacing + 4),width - 14,iLineSpacing,Qt::AlignVCenter | Qt::AlignLeft,m_szStatusString);
174
case COLUMN_PROGRESS:
176
QFontMetrics fm(p->font());
178
unsigned int uTotal = m_pHttpRequest->totalSize();
179
unsigned int uRecvd = m_pHttpRequest->receivedSize();
182
p->setPen(bIsTerminated ? Qt::lightGray : QColor(210,210,240));
183
p->drawRect(rect.left() + 4, rect.top() + 4,iW,12);
188
if(m_tTransferStartTime > 0)
190
int tSpan = kvi_timeSpan(m_tTransferEndTime > 0 ? m_tTransferEndTime : kvi_unixTime(),m_tTransferStartTime);
193
//debug("SPAN: %d (%d - %d)",tSpan,m_tTransferEndTime > 0 ? m_tTransferEndTime : kvi_unixTime(),m_tTransferStartTime);
194
iAvgSpeed = uRecvd / tSpan;
195
if(!bIsTerminated && (uTotal >= uRecvd))
197
unsigned int uRemaining = uTotal - uRecvd;
198
iEta = uRemaining / iAvgSpeed;
205
double dPerc = (double)(((double)uRecvd) * 100.0) / (double)uTotal;
207
int iL = (int) ((((double)iW) * dPerc) / 100.0);
209
p->fillRect(rect.left() + 5, rect.top() + 5,iL,10,bIsTerminated ? QColor(140,110,110) : QColor(200,100,100));
211
txt = QString(__tr2qs_ctx("%1 of %2 (%3 %)","http")).arg(KviQString::makeSizeReadable(uRecvd),
212
KviQString::makeSizeReadable(uTotal)).arg(dPerc,0,'f',2);
214
txt = KviQString::makeSizeReadable(m_pHttpRequest->receivedSize());
217
p->setPen(Qt::black);
219
p->drawText(rect.left() + 4, rect.top() + 19,width - 8,height - 8,Qt::AlignTop | Qt::AlignLeft,txt);
221
int iLeftHalf = (iW - 2) / 2;
222
int iRightHalf = iW - (iLeftHalf + 1);
223
int iLineSpacing = fm.lineSpacing() + 2;
225
txt = __tr2qs_ctx("Spd:","dcc");
227
if(iInstantSpeed >= 0)
230
KviNetUtils::formatNetworkBandwidthString(tmpisp,iAvgSpeed);
236
txt = __tr2qs_ctx("Avg:","dcc");
241
KviNetUtils::formatNetworkBandwidthString(tmpspd,iAvgSpeed);
249
int iDaH = height - (iLineSpacing + 4);
251
p->setPen(QColor(180,180,200));
252
p->drawRect(rect.left() + 4, rect.top() + iDaH,iLeftHalf,iLineSpacing);
253
p->fillRect(rect.left() + 5, rect.top() + iDaH + 1,iLeftHalf - 2,iLineSpacing - 2,bIsTerminated ? QColor(210,210,210) : QColor(190,190,240));
254
p->setPen(bIsTerminated ? Qt::darkGray : Qt::black);
255
p->drawText(rect.left() + 6, rect.top() + iDaH,iLeftHalf - 4,iLineSpacing,Qt::AlignLeft | Qt::AlignVCenter,txt);
257
unsigned int uD,uH,uM,uS;
261
KviTimeUtils::secondsToDaysHoursMinsSecs(kvi_timeSpan(m_tTransferEndTime,m_tTransferStartTime),&uD,&uH,&uM,&uS);
263
if(uD > 0)txt += QString(__tr2qs_ctx("%1d %2h %3m %4s","http")).arg(uD).arg(uH).arg(uM).arg(uS);
264
else if(uH > 0)txt += QString(__tr2qs_ctx("%2h %3m %4s","http")).arg(uH).arg(uM).arg(uS);
265
else txt += QString(__tr2qs_ctx("%3m %4s","http")).arg(uM, uS);
269
KviTimeUtils::secondsToDaysHoursMinsSecs(iEta,&uD,&uH,&uM,&uS);
271
if(uD > 0)txt += QString(__tr2qs_ctx("%1d %2h %3m %4s","http")).arg(uD).arg(uH).arg(uM).arg(uS);
272
else if(uH > 0)txt += QString(__tr2qs_ctx("%2h %3m %4s","http")).arg(uH).arg(uM).arg(uS);
273
else txt += QString(__tr2qs_ctx("%3m %4s","http")).arg(uM, uS);
275
txt = "ETA: Unknown";
279
p->setPen(QColor(180,180,200));
280
p->drawRect(rect.left() + width - (4 + iRightHalf), rect.top() + iDaH,iRightHalf,iLineSpacing);
281
p->fillRect(rect.left() + width - (3 + iRightHalf), rect.top() + iDaH + 1,iRightHalf - 2,iLineSpacing - 2,bIsTerminated ? QColor(210,210,210) : QColor(190,190,240));
282
p->setPen(bIsTerminated ? Qt::darkGray : Qt::black);
283
p->drawText(rect.left() + width - (2 + iRightHalf), rect.top() + iDaH,iRightHalf - 4,iLineSpacing,Qt::AlignLeft | Qt::AlignVCenter,txt);
290
int KviHttpFileTransfer::displayHeight(int iLineSpacing)
292
int iH = (iLineSpacing * 3) + 10;
293
return iH >= 70 ? iH : 70;
296
QString KviHttpFileTransfer::tipText()
299
s = QString("<table><tr><td bgcolor=\"#000000\"><font color=\"#FFFFFF\"><b>HTTP Transfer (ID %1)</b></font></td></tr>").arg(id());
301
if(m_lRequest.count() > 0)
303
s += "<tr><td bgcolor=\"#404040\"><font color=\"#FFFFFF\">Request Headers</font></td></tr>";
304
s += "<tr><td bgcolor=\"#C0C0C0\">";
305
for(QStringList::ConstIterator it = m_lRequest.begin();it != m_lRequest.end();++it)
307
s += " ";
314
if(m_lHeaders.count() > 0)
316
s += "<tr><td bgcolor=\"#404040\"><font color=\"#FFFFFF\">Response Headers</font></td></tr>";
317
s += "<tr><td bgcolor=\"#C0C0C0\">";
318
for(QStringList::ConstIterator it = m_lHeaders.begin();it != m_lHeaders.end();++it)
320
s += " ";
332
void KviHttpFileTransfer::init()
334
if(g_pHttpFileTransfers)return;
335
g_pHttpFileTransfers = new KviPointerList<KviHttpFileTransfer>;
336
g_pHttpFileTransfers->setAutoDelete(false);
338
QPixmap * pix = g_pIconManager->getImage("kvi_httpicons.png", false);
339
if(pix)g_pHttpIcon = new QPixmap(*pix);
340
else g_pHttpIcon = 0;
343
void KviHttpFileTransfer::done()
345
if(!g_pHttpFileTransfers)return;
346
while(KviHttpFileTransfer * t = g_pHttpFileTransfers->first())
348
delete g_pHttpFileTransfers;
349
g_pHttpFileTransfers = 0;
354
unsigned int KviHttpFileTransfer::runningTransfers()
356
if(!g_pHttpFileTransfers)return 0;
357
return g_pHttpFileTransfers->count();
360
void KviHttpFileTransfer::requestSent(const QStringList &requestHeaders)
362
m_szStatusString = __tr2qs_ctx("Request sent, waiting for reply...","http");
365
KviWindow * out = transferWindow();
369
out->output(KVI_OUT_GENERICSTATUS,__tr2qs_ctx("[HTTP %d]: Request data sent:","http"),id());
371
for(QStringList::ConstIterator it = requestHeaders.begin();it != requestHeaders.end();++it)
374
out->output(KVI_OUT_GENERICSTATUS,"[HTTP %d]: %s",id(),(*it).toUtf8().data());
377
m_lRequest = requestHeaders;
380
void KviHttpFileTransfer::connectionEstabilished()
382
m_szStatusString = __tr2qs_ctx("Connection established, sending request","http");
386
void KviHttpFileTransfer::resolvingHost(const QString &hostname)
388
m_szStatusString = __tr2qs_ctx("Resolving host %1","http").arg(hostname);
392
void KviHttpFileTransfer::contactingHost(const QString &ipandport)
394
m_szStatusString = __tr2qs_ctx("Contacting host %1","http").arg(ipandport);
398
void KviHttpFileTransfer::receivedResponse(const QString &response)
401
m_lHeaders.append(response);
402
m_szStatusString = __tr2qs_ctx("Transferring data (%1)","http").arg(response);
403
m_tTransferStartTime = kvi_unixTime();
404
m_eGeneralStatus = Downloading;
408
void KviHttpFileTransfer::statusMessage(const QString &txt)
410
KviWindow * out = transferWindow();
411
if(out && (!m_bNoOutput))
412
out->output(KVI_OUT_GENERICSTATUS,"[HTTP %d]: %Q",id(),&txt);
415
void KviHttpFileTransfer::transferTerminated(bool bSuccess)
417
KviWindow * out = transferWindow();
419
m_tTransferEndTime = kvi_unixTime();
421
KviKvsVariantList vParams;
422
vParams.append(new KviKvsVariant(bSuccess));
423
vParams.append(new KviKvsVariant(m_pHttpRequest->url().url()));
424
vParams.append(new KviKvsVariant(m_pHttpRequest->fileName()));
425
vParams.append(new KviKvsVariant(m_vMagicIdentifier));
427
if(m_szCompletionCallback.isNull())
429
KVS_TRIGGER_EVENT(KviEvent_OnHTTPGetTerminated,out ? out : (KviWindow *)(g_pApp->activeConsole()),&vParams)
431
KviKvsScript::run(m_szCompletionCallback,out ? out : (KviWindow *)(g_pApp->activeConsole()),&vParams);
436
m_szStatusString = __tr2qs_ctx("Transfer completed","http");
437
m_eGeneralStatus = Success;
439
if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICSUCCESS,__tr2qs_ctx("[HTTP %d]: Transfer completed","http"),id());
440
g_pApp->fileDownloadTerminated(true,m_pHttpRequest->url().url(),m_pHttpRequest->fileName(),QString(),QString(),!m_bNotifyCompletion);
442
m_szStatusString = __tr2qs_ctx("Transfer failed","http");
443
m_szStatusString += ": ";
444
m_szStatusString += m_pHttpRequest->lastError();
445
m_eGeneralStatus = Failure;
447
if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICERROR,__tr2qs_ctx("[HTTP %d]: Transfer failed: %Q","http"),id(),&(m_pHttpRequest->lastError()));
448
g_pApp->fileDownloadTerminated(false,m_pHttpRequest->url().url(),m_pHttpRequest->fileName(),QString(),m_pHttpRequest->lastError(),!m_bNotifyCompletion);
453
if(m_pAutoCleanTimer)delete m_pAutoCleanTimer;
454
m_pAutoCleanTimer = new QTimer();
455
connect(m_pAutoCleanTimer,SIGNAL(timeout()),this,SLOT(autoClean()));
456
m_pAutoCleanTimer->start(100);
457
m_TimerId=m_pAutoCleanTimer->timerId();
461
void KviHttpFileTransfer::headersReceived(KviPointerHashTable<const char *,KviStr> *h)
464
KviWindow * out = transferWindow();
466
if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICSTATUS,__tr2qs_ctx("[HTTP %d]: Response headers:","http"),id());
467
KviPointerHashTableIterator<const char *,KviStr> it(*h);
468
while(KviStr * s = it.current())
470
QString szHeader = it.currentKey();
472
szHeader += s->ptr();
473
m_lHeaders.append(szHeader);
474
if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICSTATUS,"[HTTP %d]: %s: %s",id(),it.currentKey(),s->ptr());
479
bool KviHttpFileTransfer::startDownload()
481
m_eGeneralStatus = Connecting;
482
return m_pHttpRequest->start();
485
#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES
486
#include "m_httpfiletransfer.moc"
487
#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES