//================================================================================== // // File : httpfiletransfer.h // Creation date : Tue Apr 22 2003 02:00:12 GMT by Szymon Stefanek // // This config is part of the KVirc irc client distribution // Copyright (C) 2003 Szymon Stefanek (pragma at kvirc dot net) // // This program is FREE software. You can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your opinion) any later version. // // This program is distributed in the HOPE that it will be USEFUL, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, write to the Free Software Foundation, // Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //================================================================================== #include "httpfiletransfer.h" #include "kvi_app.h" #include "kvi_out.h" #include "kvi_locale.h" #include "kvi_window.h" #include "kvi_iconmanager.h" #include "kvi_netutils.h" #include "kvi_kvs_eventtriggers.h" #include "kvi_console.h" #include "kvi_kvs_script.h" #include "kvi_tal_popupmenu.h" #include static KviPointerList * g_pHttpFileTransfers = 0; static TQPixmap * g_pHttpIcon = 0; KviHttpFileTransfer::KviHttpFileTransfer() : KviFileTransfer() { init(); // ensure we're initialized g_pHttpFileTransfers->append(this); m_tStartTime = kvi_unixTime(); m_tTransferStartTime = 0; m_tTransferEndTime = 0; m_bNotifyCompletion = true; m_bAutoClean = false; m_pAutoCleanTimer = 0; m_bNoOutput = false; m_pHttpRequest = new KviHttpRequest(); connect(m_pHttpRequest,TQT_SIGNAL(status(const TQString &)),this,TQT_SLOT(statusMessage(const TQString &))); connect(m_pHttpRequest,TQT_SIGNAL(terminated(bool)),this,TQT_SLOT(transferTerminated(bool))); connect(m_pHttpRequest,TQT_SIGNAL(header(KviPointerHashTable *)),this,TQT_SLOT(headersReceived(KviPointerHashTable *))); connect(m_pHttpRequest,TQT_SIGNAL(resolvingHost(const TQString &)),this,TQT_SLOT(resolvingHost(const TQString &))); connect(m_pHttpRequest,TQT_SIGNAL(requestSent(const TQStringList &)),this,TQT_SLOT(requestSent(const TQStringList &))); connect(m_pHttpRequest,TQT_SIGNAL(contactingHost(const TQString &)),this,TQT_SLOT(contactingHost(const TQString &))); connect(m_pHttpRequest,TQT_SIGNAL(receivedResponse(const TQString &)),this,TQT_SLOT(receivedResponse(const TQString &))); connect(m_pHttpRequest,TQT_SIGNAL(connectionEstabilished()),this,TQT_SLOT(connectionEstabilished())); m_eGeneralStatus = Initializing; m_szStatusString = __tr2qs_ctx("Initializing","http"); } KviHttpFileTransfer::~KviHttpFileTransfer() { g_pHttpFileTransfers->removeRef(this); delete m_pHttpRequest; if(m_pAutoCleanTimer) { m_pAutoCleanTimer->stop(); delete m_pAutoCleanTimer; } } void KviHttpFileTransfer::autoClean() { die(); } void KviHttpFileTransfer::die() { delete this; } TQString KviHttpFileTransfer::localFileName() { return m_pHttpRequest->fileName(); } void KviHttpFileTransfer::abort() { m_pHttpRequest->abort(); } void KviHttpFileTransfer::fillContextPopup(KviTalPopupMenu * m,int column) { int id = m->insertItem(__tr2qs_ctx("Abort","http"),this,TQT_SLOT(abort())); if(!active())m->setItemEnabled(id,false); } bool KviHttpFileTransfer::active() { return ((m_eGeneralStatus == Connecting) || (m_eGeneralStatus == Downloading)); } void KviHttpFileTransfer::displayPaint(TQPainter * p,int column,int width,int height) { TQString txt; bool bIsTerminated = ((m_eGeneralStatus == Success) || (m_eGeneralStatus == Failure)); switch(column) { case COLUMN_TRANSFERTYPE: { int offset = 0; switch(m_eGeneralStatus) { case Initializing: offset = 0; break; case Connecting: offset = 0; break; case Downloading: offset = 48; break; case Success: offset = 96; break; case Failure: offset = 144; break; } p->drawPixmap(3,3,*g_pHttpIcon,offset,0,48,64); } break; case COLUMN_FILEINFO: { TQFontMetrics fm(p->font()); TQString szFrom = __tr2qs_ctx("From: ","http"); TQString szTo = __tr2qs_ctx("To: ","http"); int daW1 = fm.width(szFrom); int daW2 = fm.width(szTo); if(daW1 < daW2)daW1 = daW2; int iLineSpacing = fm.lineSpacing(); p->setPen(TQt::black); int iY = 4; p->drawText(4 + daW1,iY,width - (8 + daW1),height - 8,TQt::AlignTop | TQt::AlignLeft,m_pHttpRequest->url().url().ptr()); iY += iLineSpacing; if(!(m_pHttpRequest->fileName().isEmpty())) { p->drawText(4 + daW1,iY,width - (8 + daW1),height - 8,TQt::AlignTop | TQt::AlignLeft,m_pHttpRequest->fileName()); } iY += iLineSpacing; p->setPen(TQt::darkGray); p->drawText(4,4,width - 8,height - 8,TQt::AlignTop | TQt::AlignLeft,szFrom); p->drawText(4,4 + iLineSpacing,width - 8,height - 8,TQt::AlignTop | TQt::AlignLeft,szTo); p->setPen(TQColor(180,180,200)); iLineSpacing += 2; p->drawRect(4,height - (iLineSpacing + 4),width - 8,iLineSpacing); p->fillRect(5,height - (iLineSpacing + 3),width - 10,iLineSpacing - 2,bIsTerminated ? TQColor(210,210,210) : TQColor(190,190,240)); p->setPen(TQt::black); p->drawText(7,height - (iLineSpacing + 4),width - 14,iLineSpacing,TQt::AlignVCenter | TQt::AlignLeft,m_szStatusString); } break; case COLUMN_PROGRESS: { TQFontMetrics fm(p->font()); unsigned int uTotal = m_pHttpRequest->totalSize(); unsigned int uRecvd = m_pHttpRequest->receivedSize(); int iW = width - 8; p->setPen(bIsTerminated ? TQt::lightGray : TQColor(210,210,240)); p->drawRect(4,4,iW,12); int iAvgSpeed = -1; int iEta = -1; if(m_tTransferStartTime > 0) { int tSpan = kvi_timeSpan(m_tTransferEndTime > 0 ? m_tTransferEndTime : kvi_unixTime(),m_tTransferStartTime); if(tSpan > 0) { //debug("SPAN: %d (%d - %d)",tSpan,m_tTransferEndTime > 0 ? m_tTransferEndTime : kvi_unixTime(),m_tTransferStartTime); iAvgSpeed = uRecvd / tSpan; if(!bIsTerminated && (uTotal >= uRecvd)) { unsigned int uRemaining = uTotal - uRecvd; iEta = uRemaining / iAvgSpeed; } } } if(uTotal > 0) { double dPerc = (double)(((double)uRecvd) * 100.0) / (double)uTotal; iW -= 2; int iL = (int) ((((double)iW) * dPerc) / 100.0); //iR = iW - iL; p->fillRect(5,5,iL,10,bIsTerminated ? TQColor(140,110,110) : TQColor(200,100,100)); txt = TQString(__tr2qs_ctx("%1 of %2 (%3 %)","http")).tqarg(KviTQString::makeSizeReadable(uRecvd)) .tqarg(KviTQString::makeSizeReadable(uTotal)).tqarg(dPerc,0,'f',2); } else { txt = KviTQString::makeSizeReadable(m_pHttpRequest->receivedSize()); } p->setPen(TQt::black); p->drawText(4,19,width - 8,height - 8,TQt::AlignTop | TQt::AlignLeft,txt); int iLeftHalf = (iW - 2) / 2; int iRightHalf = iW - (iLeftHalf + 1); int iLineSpacing = fm.lineSpacing() + 2; /* txt = __tr2qs_ctx("Spd:","dcc"); txt += " "; if(iInstantSpeed >= 0) { TQString tmpisp; KviNetUtils::formatNetworkBandwidthString(tmpisp,iAvgSpeed); txt += tmpisp; } else { txt += "? B/s"; } */ txt = __tr2qs_ctx("Avg:","dcc"); txt += " "; if(iAvgSpeed >= 0) { TQString tmpspd; KviNetUtils::formatNetworkBandwidthString(tmpspd,iAvgSpeed); txt += tmpspd; } else { txt += "? B/s"; } int iDaH = height - (iLineSpacing + 4); p->setPen(TQColor(180,180,200)); p->drawRect(4,iDaH,iLeftHalf,iLineSpacing); p->fillRect(5,iDaH + 1,iLeftHalf - 2,iLineSpacing - 2,bIsTerminated ? TQColor(210,210,210) : TQColor(190,190,240)); p->setPen(bIsTerminated ? TQt::darkGray : TQt::black); p->drawText(6,iDaH,iLeftHalf - 4,iLineSpacing,TQt::AlignLeft | TQt::AlignVCenter,txt); unsigned int uD,uH,uM,uS; if(bIsTerminated) { KviTimeUtils::secondsToDaysHoursMinsSecs(kvi_timeSpan(m_tTransferEndTime,m_tTransferStartTime),&uD,&uH,&uM,&uS); txt = "TOT: "; if(uD > 0)txt += TQString(__tr2qs_ctx("%1d %2h %3m %4s","http")).tqarg(uD).tqarg(uH).tqarg(uM).tqarg(uS); else if(uH > 0)txt += TQString(__tr2qs_ctx("%2h %3m %4s","http")).tqarg(uH).tqarg(uM).tqarg(uS); else txt += TQString(__tr2qs_ctx("%3m %4s","http")).tqarg(uM).tqarg(uS); } else { if(iEta >= 0) { KviTimeUtils::secondsToDaysHoursMinsSecs(iEta,&uD,&uH,&uM,&uS); txt = "ETA: "; if(uD > 0)txt += TQString(__tr2qs_ctx("%1d %2h %3m %4s","http")).tqarg(uD).tqarg(uH).tqarg(uM).tqarg(uS); else if(uH > 0)txt += TQString(__tr2qs_ctx("%2h %3m %4s","http")).tqarg(uH).tqarg(uM).tqarg(uS); else txt += TQString(__tr2qs_ctx("%3m %4s","http")).tqarg(uM).tqarg(uS); } else { txt = "ETA: Unknown"; } } p->setPen(TQColor(180,180,200)); p->drawRect(width - (4 + iRightHalf),iDaH,iRightHalf,iLineSpacing); p->fillRect(width - (3 + iRightHalf),iDaH + 1,iRightHalf - 2,iLineSpacing - 2,bIsTerminated ? TQColor(210,210,210) : TQColor(190,190,240)); p->setPen(bIsTerminated ? TQt::darkGray : TQt::black); p->drawText(width - (2 + iRightHalf),iDaH,iRightHalf - 4,iLineSpacing,TQt::AlignLeft | TQt::AlignVCenter,txt); } break; } } int KviHttpFileTransfer::displayHeight(int iLineSpacing) { int iH = (iLineSpacing * 3) + 10; return iH >= 70 ? iH : 70; } TQString KviHttpFileTransfer::tipText() { TQString s; s = TQString("").tqarg(id()); if(m_lRequest.count() > 0) { s += ""; s += ""; } if(m_lHeaders.count() > 0) { s += ""; s += ""; } s += "
HTTP Transfer (ID %1)
Request Headers
"; for(TQStringList::ConstIterator it = m_lRequest.begin();it != m_lRequest.end();++it) { s += "   "; s += *it; s += "
"; } s += "
Response Headers
"; for(TQStringList::ConstIterator it = m_lHeaders.begin();it != m_lHeaders.end();++it) { s += "   "; s += *it; s += "
"; } s += "
"; return s; } void KviHttpFileTransfer::init() { if(g_pHttpFileTransfers)return; g_pHttpFileTransfers = new KviPointerList; g_pHttpFileTransfers->setAutoDelete(false); TQPixmap * pix = g_pIconManager->getImage("kvi_httpicons.png"); if(pix)g_pHttpIcon = new TQPixmap(*pix); else g_pHttpIcon = new TQPixmap(192,48); } void KviHttpFileTransfer::done() { if(!g_pHttpFileTransfers)return; while(KviHttpFileTransfer * t = g_pHttpFileTransfers->first()) delete t; delete g_pHttpFileTransfers; g_pHttpFileTransfers = 0; delete g_pHttpIcon; g_pHttpIcon = 0; } unsigned int KviHttpFileTransfer::runningTransfers() { if(!g_pHttpFileTransfers)return 0; return g_pHttpFileTransfers->count(); } void KviHttpFileTransfer::requestSent(const TQStringList &requestHeaders) { m_szStatusString = __tr2qs_ctx("Request sent, waiting for reply...","http"); displayUpdate(); KviWindow * out = transferWindow(); if(!out)return; if(!m_bNoOutput) out->output(KVI_OUT_GENERICSTATUS,__tr2qs_ctx("[HTTP %d]: Request data sent:","http"),id()); for(TQStringList::ConstIterator it = requestHeaders.begin();it != requestHeaders.end();++it) { if(!m_bNoOutput) out->output(KVI_OUT_GENERICSTATUS,"[HTTP %d]: %s",id(),(*it).utf8().data()); } m_lRequest = requestHeaders; } void KviHttpFileTransfer::connectionEstabilished() { m_szStatusString = __tr2qs_ctx("Connection established, sending request","http"); displayUpdate(); } void KviHttpFileTransfer::resolvingHost(const TQString &hostname) { m_szStatusString = __tr2qs_ctx("Resolving host %1","http").tqarg(hostname); displayUpdate(); } void KviHttpFileTransfer::contactingHost(const TQString &ipandport) { m_szStatusString = __tr2qs_ctx("Contacting host %1","http").tqarg(ipandport); displayUpdate(); } void KviHttpFileTransfer::receivedResponse(const TQString &response) { m_lHeaders.clear(); m_lHeaders.append(response); m_szStatusString = __tr2qs_ctx("Transferring data (%1)","http").tqarg(response); m_tTransferStartTime = kvi_unixTime(); m_eGeneralStatus = Downloading; displayUpdate(); } void KviHttpFileTransfer::statusMessage(const TQString &txt) { KviWindow * out = transferWindow(); if(out && (!m_bNoOutput)) out->output(KVI_OUT_GENERICSTATUS,"[HTTP %d]: %Q",id(),&txt); } void KviHttpFileTransfer::transferTerminated(bool bSuccess) { KviWindow * out = transferWindow(); m_tTransferEndTime = kvi_unixTime(); KviKvsVariantList vParams; vParams.append(new KviKvsVariant(bSuccess)); vParams.append(new KviKvsVariant(m_pHttpRequest->url().url())); vParams.append(new KviKvsVariant(m_pHttpRequest->fileName())); vParams.append(new KviKvsVariant(m_vMagicIdentifier)); if(m_szCompletionCallback.isNull()) { KVS_TRIGGER_EVENT(KviEvent_OnHTTPGetTerminated,out ? out : (KviWindow *)(g_pApp->activeConsole()),&vParams) } else { KviKvsScript::run(m_szCompletionCallback,out ? out : (KviWindow *)(g_pApp->activeConsole()),&vParams); } if(bSuccess) { m_szStatusString = __tr2qs_ctx("Transfer completed","http"); m_eGeneralStatus = Success; displayUpdate(); if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICSUCCESS,__tr2qs_ctx("[HTTP %d]: Transfer completed","http"),id()); g_pApp->fileDownloadTerminated(true,m_pHttpRequest->url().url().ptr(),m_pHttpRequest->fileName(),TQString(),TQString(),!m_bNotifyCompletion); } else { m_szStatusString = __tr2qs_ctx("Transfer failed","http"); m_szStatusString += ": "; m_szStatusString += m_pHttpRequest->lastError(); m_eGeneralStatus = Failure; displayUpdate(); if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICERROR,__tr2qs_ctx("[HTTP %d]: Transfer failed: %Q","http"),id(),&(m_pHttpRequest->lastError())); g_pApp->fileDownloadTerminated(false,m_pHttpRequest->url().url().ptr(),m_pHttpRequest->fileName(),TQString(),m_pHttpRequest->lastError(),!m_bNotifyCompletion); } if(m_bAutoClean) { if(m_pAutoCleanTimer)delete m_pAutoCleanTimer; m_pAutoCleanTimer = new TQTimer(); connect(m_pAutoCleanTimer,TQT_SIGNAL(timeout()),this,TQT_SLOT(autoClean())); m_pAutoCleanTimer->start(100,true); } } void KviHttpFileTransfer::headersReceived(KviPointerHashTable *h) { if(!h)return; KviWindow * out = transferWindow(); if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICSTATUS,__tr2qs_ctx("[HTTP %d]: Response headers:","http"),id()); KviPointerHashTableIterator it(*h); while(KviStr * s = it.current()) { TQString szHeader = it.currentKey(); szHeader += ": "; szHeader += s->ptr(); m_lHeaders.append(szHeader); if(out && (!m_bNoOutput))out->output(KVI_OUT_GENERICSTATUS,"[HTTP %d]: %s: %s",id(),it.currentKey(),s->ptr()); ++it; } } bool KviHttpFileTransfer::startDownload() { m_eGeneralStatus = Connecting; return m_pHttpRequest->start(); } #include "m_httpfiletransfer.moc"