summaryrefslogtreecommitdiffstats
path: root/src/kvilib/net
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 02:13:59 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 02:13:59 +0000
commita6d58bb6052ac8cb01805a48c4ad2f129126116f (patch)
treedd867a099fcbb263a8009a9fb22695b87855dad6 /src/kvilib/net
downloadkvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.tar.gz
kvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.zip
Added KDE3 version of kvirc
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kvirc@1095341 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/kvilib/net')
-rw-r--r--src/kvilib/net/Makefile.am5
-rw-r--r--src/kvilib/net/kvi_dns.cpp450
-rw-r--r--src/kvilib/net/kvi_dns.h142
-rw-r--r--src/kvilib/net/kvi_http.cpp1440
-rw-r--r--src/kvilib/net/kvi_http.h209
-rw-r--r--src/kvilib/net/kvi_netutils.cpp1504
-rw-r--r--src/kvilib/net/kvi_netutils.h104
-rw-r--r--src/kvilib/net/kvi_socket.cpp31
-rw-r--r--src/kvilib/net/kvi_socket.h356
-rw-r--r--src/kvilib/net/kvi_sockettype.h45
-rw-r--r--src/kvilib/net/kvi_ssl.cpp687
-rw-r--r--src/kvilib/net/kvi_ssl.h180
-rw-r--r--src/kvilib/net/kvi_url.cpp164
-rw-r--r--src/kvilib/net/kvi_url.h63
-rw-r--r--src/kvilib/net/moc_kvi_dns.cpp137
-rw-r--r--src/kvilib/net/moc_kvi_http.cpp263
16 files changed, 5780 insertions, 0 deletions
diff --git a/src/kvilib/net/Makefile.am b/src/kvilib/net/Makefile.am
new file mode 100644
index 00000000..c84487eb
--- /dev/null
+++ b/src/kvilib/net/Makefile.am
@@ -0,0 +1,5 @@
+###############################################################################
+# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <[email protected]>
+###############################################################################
+
+EXTRA_DIST = *.cpp *.h
diff --git a/src/kvilib/net/kvi_dns.cpp b/src/kvilib/net/kvi_dns.cpp
new file mode 100644
index 00000000..faa2e126
--- /dev/null
+++ b/src/kvilib/net/kvi_dns.cpp
@@ -0,0 +1,450 @@
+//=============================================================================
+//
+// File : kvi_dns.cpp
+// Creation date : Sat Jul 21 2000 17:19:31 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2000-2007 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.
+//
+//=============================================================================
+#define __KVILIB__
+
+#include "kvi_dns.h"
+#include "kvi_error.h"
+#include "kvi_netutils.h"
+
+#include <errno.h>
+
+#ifdef COMPILE_ON_WINDOWS
+ #include <winsock2.h>
+
+ #ifdef COMPILE_IPV6_SUPPORT
+ #ifdef WIN2K
+ #include <ws2ip6.h>
+ #else
+ #include <ws2tcpip.h>
+ //#include <tpipv6.h>
+ #endif
+ #endif
+#else
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h>
+#endif
+
+// this is for FreeBSD
+#ifndef EAI_ADDRFAMILY
+ #define EAI_ADDRFAMILY EAI_FAMILY
+#endif
+
+#ifndef EAI_NODATA
+ #define EAI_NODATA 0
+#endif
+
+
+
+KviDnsResult::KviDnsResult()
+{
+ m_iError = KviError_success;
+ m_pHostnameList = new KviPointerList<QString>;
+ m_pHostnameList->setAutoDelete(true);
+ m_pIpAddressList = new KviPointerList<QString>;
+ m_pIpAddressList->setAutoDelete(true);
+
+}
+
+KviDnsResult::~KviDnsResult()
+{
+ delete m_pHostnameList;
+ delete m_pIpAddressList;
+}
+
+void KviDnsResult::appendHostname(const QString &host)
+{
+ m_pHostnameList->append(new QString(host));
+}
+
+
+void KviDnsResult::appendAddress(const QString &addr)
+{
+ m_pIpAddressList->append(new QString(addr));
+}
+
+
+
+KviDnsThread::KviDnsThread(KviDns * pDns)
+{
+ m_pParentDns = pDns;
+}
+
+KviDnsThread::~KviDnsThread()
+{
+}
+
+int KviDnsThread::translateDnsError(int iErr)
+{
+#if defined(COMPILE_IPV6_SUPPORT) || !defined(COMPILE_ON_WINDOWS)
+
+ switch(iErr)
+ {
+ case EAI_FAMILY: return KviError_unsupportedAddressFamily; break;
+#if !defined(COMPILE_ON_WINDOWS) && defined(EAI_ADDRFAMILY) && (EAI_ADDRFAMILY != EAI_FAMILY)
+ case EAI_ADDRFAMILY: return KviError_unsupportedAddressFamily; break;
+#endif
+// NOT FreeBSD ARE WE?
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+// YARR
+ case EAI_NODATA: return KviError_validNameButNoIpAddress; break;
+#endif
+ case EAI_FAIL: return KviError_unrecoverableNameserverError; break;
+ case EAI_AGAIN: return KviError_dnsTemporaneousFault; break;
+ // this should never happen
+ case EAI_BADFLAGS: return KviError_dnsInternalErrorBadFlags; break;
+ case EAI_MEMORY: return KviError_dnsInternalErrorOutOfMemory; break;
+ // got this when experimenting with protocols
+ case EAI_SERVICE: return KviError_dnsInternalErrorServiceNotSupported; break;
+#ifndef COMPILE_ON_WINDOWS
+ case EAI_NONAME: return KviError_dnsNoName; break;
+#endif
+ // got this when experimenting with protocols
+ case EAI_SOCKTYPE: return KviError_dnsInternalErrorUnsupportedSocketType; break;
+#ifndef COMPILE_ON_WINDOWS
+ case EAI_SYSTEM: return -errno;
+#endif
+ }
+
+#endif
+ return KviError_dnsQueryFailed;
+}
+
+void KviDnsThread::postDnsError(KviDnsResult * dns,int iErr)
+{
+ dns->setError(iErr);
+ KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA);
+ e->setData(dns);
+ postEvent(m_pParentDns,e);
+}
+
+void KviDnsThread::run()
+{
+ KviDnsResult * dns = new KviDnsResult();
+
+ dns->setQuery(m_szQuery);
+
+ if(m_szQuery.isEmpty())
+ {
+ postDnsError(dns,KviError_noHostToResolve);
+ return;
+ }
+
+#ifndef COMPILE_IPV6_SUPPORT
+ if(m_queryType != KviDns::IpV4)
+ {
+ if(m_queryType == KviDns::IpV6)
+ {
+ postDnsError(dns,KviError_noIpV6Support);
+ return;
+ }
+ m_queryType = KviDns::IpV4;
+ }
+#endif
+
+#if defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_IPV6_SUPPORT)
+
+ if(m_queryType == KviDns::IpV6)
+ {
+ postDnsError(dns,KviError_noIpV6Support);
+ return;
+ }
+
+ // gethostbyaddr and gethostbyname are thread-safe on Windoze
+ struct in_addr inAddr;
+ struct hostent *pHostEntry = 0;
+
+
+ // DIE DIE!....I hope that this stuff will disappear sooner or later :)
+
+ if(KviNetUtils::stringIpToBinaryIp(m_szQuery,&inAddr))
+ {
+ pHostEntry = gethostbyaddr((const char *)&inAddr,sizeof(inAddr),AF_INET);
+ } else {
+ pHostEntry = gethostbyname(m_szQuery);
+ }
+
+ if(!pHostEntry)
+ {
+ switch(h_errno)
+ {
+ case HOST_NOT_FOUND: dns->setError(KviError_hostNotFound); break;
+ case NO_ADDRESS: dns->setError(KviError_validNameButNoIpAddress); break;
+ case NO_RECOVERY: dns->setError(KviError_unrecoverableNameserverError); break;
+ case TRY_AGAIN: dns->setError(KviError_dnsTemporaneousFault); break;
+ default: dns->setError(KviError_dnsQueryFailed); break;
+ }
+ } else {
+ dns->appendHostname(pHostEntry->h_name);
+ QString szIp;
+ KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr)),szIp);
+ dns->appendAddress(szIp);
+
+ int idx = 1;
+ while(pHostEntry->h_addr_list[idx])
+ {
+ QString tmp;
+ KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr_list[idx])),tmp);
+ if(tmp.hasData())dns->appendAddress(tmp);
+ ++idx;
+ }
+ if(pHostEntry->h_aliases[0])
+ {
+ dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[0]));
+ if(pHostEntry->h_aliases[1])dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[1]));
+ }
+ }
+
+
+#else //!COMPILE_ON_WINDOWS || COMPILE_IPV6_SUPPORT
+
+ int retVal;
+
+
+//#ifdef HAVE_GETNAMEINFO
+ struct sockaddr_in ipv4Addr;
+
+#ifdef COMPILE_IPV6_SUPPORT
+ struct sockaddr_in6 ipv6Addr;
+ bool bIsIpV6Ip = false;
+#endif
+
+ bool bIsIpV4Ip = KviNetUtils::stringIpToBinaryIp(m_szQuery,(struct in_addr *)&(ipv4Addr.sin_addr));
+
+#ifdef COMPILE_IPV6_SUPPORT
+ if(!bIsIpV4Ip)bIsIpV6Ip = KviNetUtils::stringIpToBinaryIp_V6(m_szQuery,(struct in6_addr *)&(ipv6Addr.sin6_addr));
+#endif
+
+//#ifdef HAVE_GETNAMEINFO
+
+#ifdef COMPILE_IPV6_SUPPORT
+ if(bIsIpV4Ip || bIsIpV6Ip)
+ {
+#else
+ if(bIsIpV4Ip)
+ {
+#endif
+ // use getnameinfo...
+ char retname[1025]; // should be enough....
+
+#ifdef COMPILE_IPV6_SUPPORT
+ if(bIsIpV4Ip)
+ {
+#endif
+ ipv4Addr.sin_family = AF_INET;
+ ipv4Addr.sin_port = 0;
+ // NI_NAMEREQD as last param ?
+ retVal = getnameinfo((struct sockaddr *)&ipv4Addr,sizeof(ipv4Addr),retname,1025,0,0,NI_NAMEREQD);
+#ifdef COMPILE_IPV6_SUPPORT
+ } else {
+ ipv6Addr.sin6_family = AF_INET6;
+ ipv6Addr.sin6_port = 0;
+ retVal = getnameinfo((struct sockaddr *)&ipv6Addr,sizeof(ipv6Addr),retname,1025,0,0,NI_NAMEREQD);
+ }
+#endif
+
+ if(retVal != 0)dns->setError(translateDnsError(retVal));
+ else {
+ dns->appendHostname(retname);
+ dns->appendAddress(m_szQuery);
+ }
+
+ } else {
+//#endif //HAVE_GETNAMEINFO
+
+
+//#ifdef COMPILE_IPV6_SUPPORT
+// struct in6_addr in6Addr;
+//#endif
+ struct addrinfo * pRet = 0;
+ struct addrinfo * pNext;
+ struct addrinfo hints;
+ hints.ai_flags = 0; //AI_CANONNAME; <-- for IPV6 it makes cannoname to point to the IP address!
+#ifdef COMPILE_IPV6_SUPPORT
+ hints.ai_family = (m_queryType == KviDns::IpV6) ? PF_INET6 : ((m_queryType == KviDns::IpV4) ? PF_INET : PF_UNSPEC);
+#else
+ hints.ai_family = PF_INET;
+#endif
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ hints.ai_addrlen = 0;
+ hints.ai_canonname = 0;
+ hints.ai_addr = 0;
+ hints.ai_next = 0;
+
+ retVal = getaddrinfo(KviQString::toUtf8(m_szQuery).data(),0,&hints,&pRet);
+
+ if(retVal != 0)dns->setError(translateDnsError(retVal));
+ else {
+ dns->appendHostname(pRet->ai_canonname ? QString::fromUtf8(pRet->ai_canonname) : m_szQuery);
+ QString szIp;
+#ifdef COMPILE_IPV6_SUPPORT
+ if(pRet->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pRet->ai_addr))->sin6_addr,szIp);
+ else {
+#endif
+ KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pRet->ai_addr))->sin_addr,szIp);
+#ifdef COMPILE_IPV6_SUPPORT
+ }
+#endif
+ dns->appendAddress(szIp);
+
+ pNext = pRet->ai_next;
+ while(pNext)
+ {
+ QString tmp;
+#ifdef COMPILE_IPV6_SUPPORT
+ if(pNext->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pNext->ai_addr))->sin6_addr,tmp);
+ else {
+#endif
+ KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pNext->ai_addr))->sin_addr,tmp);
+#ifdef COMPILE_IPV6_SUPPORT
+ }
+#endif
+ if(!tmp.isEmpty())dns->appendAddress(tmp);
+
+ if(pNext->ai_canonname)
+ {
+ // FIXME: only of not equal to other names ?
+ dns->appendHostname(QString::fromUtf8(pNext->ai_canonname));
+ }
+
+ pNext = pNext->ai_next;
+
+ }
+ }
+ if(pRet)freeaddrinfo(pRet);
+//#ifdef HAVE_GETNAMEINFO
+ }
+//#endif //HAVE_GETNAMEINFO
+
+#endif // !COMPILE_ON_WINDOWS
+
+
+ KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA);
+ e->setData(dns);
+ postEvent(m_pParentDns,e);
+}
+
+
+
+
+KviDns::KviDns()
+: QObject()
+{
+ m_pSlaveThread = new KviDnsThread(this);
+ m_pDnsResult = new KviDnsResult();
+ m_pAuxData = 0;
+ m_state = Idle;
+}
+
+KviDns::~KviDns()
+{
+ if(m_pSlaveThread)delete m_pSlaveThread; // will eventually terminate it (but it will also block us!!!)
+ KviThreadManager::killPendingEvents(this);
+ if(m_pDnsResult)delete m_pDnsResult;
+ if(m_pAuxData)debug("You're leaking memory man! m_pAuxData is non 0!");
+}
+
+
+bool KviDns::isRunning() const
+{
+ return (m_state == Busy);
+};
+
+bool KviDns::lookup(const QString &query,QueryType type)
+{
+ if(m_state == Busy)return false;
+ m_pSlaveThread->setQuery(KviQString::trimmed(query),type);
+ bool bStarted = m_pSlaveThread->start();
+ m_state = bStarted ? Busy : Failure;
+ return bStarted;
+}
+
+int KviDns::error()
+{
+ if(!m_pDnsResult)return KviError_dnsQueryFailed;
+ return m_pDnsResult->error();
+}
+
+KviDnsResult * KviDns::result()
+{
+ if(!m_pDnsResult)m_pDnsResult = new KviDnsResult();
+ return m_pDnsResult;
+}
+
+KviPointerList<QString> * KviDns::hostnameList()
+{
+ return result()->hostnameList();
+}
+
+KviPointerList<QString> * KviDns::ipAddressList()
+{
+ return result()->ipAddressList();
+}
+
+int KviDns::hostnameCount()
+{
+ return result()->hostnameList()->count();
+}
+
+int KviDns::ipAddressCount()
+{
+ return result()->ipAddressList()->count();
+}
+
+const QString & KviDns::firstHostname()
+{
+ QString * pStr = result()->hostnameList()->first();
+ if(pStr)return *pStr;
+ return KviQString::empty;
+}
+
+const QString & KviDns::firstIpAddress()
+{
+ QString * pStr = result()->ipAddressList()->first();
+ if(pStr)return *pStr;
+ return KviQString::empty;
+}
+
+const QString & KviDns::query()
+{
+ return result()->query();
+}
+
+bool KviDns::event(QEvent *e)
+{
+ if(e->type() == KVI_THREAD_EVENT)
+ {
+ if(((KviThreadEvent *)e)->id() == KVI_DNS_THREAD_EVENT_DATA)
+ {
+ if(m_pDnsResult)delete m_pDnsResult;
+ m_pDnsResult = ((KviThreadDataEvent<KviDnsResult> *)e)->getData();
+ m_state = (m_pDnsResult->error() == KviError_success) ? Success : Failure;
+ emit lookupDone(this);
+ return true;
+ } // else ops... unknown thread event ?
+ }
+ return QObject::event(e);
+}
+
diff --git a/src/kvilib/net/kvi_dns.h b/src/kvilib/net/kvi_dns.h
new file mode 100644
index 00000000..3f423c24
--- /dev/null
+++ b/src/kvilib/net/kvi_dns.h
@@ -0,0 +1,142 @@
+#ifndef _KVI_DNS_H_
+#define _KVI_DNS_H_
+
+//=============================================================================
+//
+// File : kvi_dns.h
+// Creation date : Sat Jul 21 2000 13:59:11 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2007 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 "kvi_settings.h"
+#include "kvi_heapobject.h"
+#include "kvi_thread.h"
+#include "kvi_qstring.h"
+
+
+class KviDnsThread; // not part of the API
+
+
+class KVILIB_API KviDnsResult : public KviHeapObject
+{
+ friend class KviDns;
+ friend class KviDnsThread;
+protected:
+ KviDnsResult();
+public:
+ ~KviDnsResult();
+protected:
+ int m_iError;
+ KviPointerList<QString> * m_pHostnameList;
+ KviPointerList<QString> * m_pIpAddressList;
+ QString m_szQuery;
+public:
+ int error(){ return m_iError; };
+ // never store nor delete these pointers!
+ // (these are NEVER 0)
+ KviPointerList<QString> * hostnameList(){ return m_pHostnameList; };
+ KviPointerList<QString> * ipAddressList(){ return m_pIpAddressList; };
+ const QString &query(){ return m_szQuery; };
+protected:
+ void setError(int iError){ m_iError = iError; };
+ void setQuery(const QString &query){ m_szQuery = query; };
+ void appendHostname(const QString &host);
+ void appendAddress(const QString &addr);
+};
+
+
+
+class KVILIB_API KviDns : public QObject, public KviHeapObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool blockingDelete READ isRunning)
+public:
+ KviDns();
+ ~KviDns();
+public:
+ enum QueryType { IpV4 , IpV6 , Any };
+ enum State { Idle , Busy , Failure , Success };
+protected:
+ void * m_pAuxData;
+ KviDnsThread * m_pSlaveThread;
+ KviDnsResult * m_pDnsResult;
+ State m_state;
+public:
+ /////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Public interface
+ //
+
+ // Lookup start
+ bool lookup(const QString &szQuery,QueryType type);
+
+ // Current object state
+ State state(){ return m_state; };
+
+ // Results (return always non null-data..but valid results only if state() == Success or Failure)
+ int error();
+ const QString & firstHostname();
+ const QString & firstIpAddress();
+ int hostnameCount();
+ int ipAddressCount();
+ KviPointerList<QString> * hostnameList();
+ KviPointerList<QString> * ipAddressList();
+ const QString & query();
+ bool isRunning() const;
+
+ // Auxiliary data store
+ void setAuxData(void * pAuxData){ m_pAuxData = pAuxData; };
+ void * releaseAuxData(){ void * pData = m_pAuxData; m_pAuxData = 0; return pData; };
+protected:
+ virtual bool event(QEvent *e);
+private:
+ KviDnsResult * result();
+signals:
+ void lookupDone(KviDns *);
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// INTERNAL CLASSES
+//
+
+#define KVI_DNS_THREAD_EVENT_DATA (KVI_THREAD_USER_EVENT_BASE + 7432)
+
+class KviDnsThread : public KviThread
+{
+ friend class KviDns;
+protected:
+ KviDnsThread(KviDns * pDns);
+ ~KviDnsThread();
+protected:
+ QString m_szQuery;
+ KviDns::QueryType m_queryType;
+ KviDns * m_pParentDns;
+public:
+ void setQuery(const QString &query,KviDns::QueryType type){ m_szQuery = query; m_queryType = type; };
+protected:
+ virtual void run();
+ int translateDnsError(int iErr);
+ void postDnsError(KviDnsResult * dns,int iErr);
+};
+
+
+#endif //_KVI_DNS_H_
diff --git a/src/kvilib/net/kvi_http.cpp b/src/kvilib/net/kvi_http.cpp
new file mode 100644
index 00000000..2e94abbe
--- /dev/null
+++ b/src/kvilib/net/kvi_http.cpp
@@ -0,0 +1,1440 @@
+//=============================================================================
+//
+// File : kvi_http.cpp
+// Creation date : Sat Aug 17 13:43:32 2002 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002-2006 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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#include <qdir.h>
+#include <qtimer.h>
+//#include <zlib.h>
+
+#include "kvi_http.h"
+#include "kvi_locale.h"
+#include "kvi_netutils.h"
+#include "kvi_dns.h"
+#include "kvi_error.h"
+#include "kvi_debug.h"
+#include "kvi_socket.h"
+#include "kvi_time.h"
+#ifdef COMPILE_SSL_SUPPORT
+ #include "kvi_ssl.h"
+#endif
+
+
+#define KVI_HTTP_REQUEST_THREAD_EVENT_CONNECTED (KVI_THREAD_USER_EVENT_BASE + 0xCAFE)
+#define KVI_HTTP_REQUEST_THREAD_EVENT_REQUESTSENT (KVI_THREAD_USER_EVENT_BASE + 0xCAFF)
+
+KviHttpRequest::KviHttpRequest()
+: QObject()
+{
+ m_pDns = 0;
+ m_pThread = 0;
+ m_pFile = 0;
+ m_pPrivateData = 0;
+ m_bHeaderProcessed = false;
+ m_pBuffer = new KviDataBuffer();
+
+ resetStatus();
+ resetData();
+}
+
+KviHttpRequest::~KviHttpRequest()
+{
+ resetInternalStatus();
+ delete m_pBuffer;
+}
+
+void KviHttpRequest::abort()
+{
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Aborted");
+ emit terminated(false);
+}
+
+void KviHttpRequest::resetInternalStatus()
+{
+ if(m_pThread)delete m_pThread;
+ if(m_pDns)delete m_pDns;
+
+ m_pDns = 0;
+ m_pThread = 0;
+
+ if(!m_pFile)return;
+ m_pFile->close();
+ delete m_pFile;
+ m_pFile = 0;
+
+ m_pBuffer->clear();
+ m_bHeaderProcessed = false;
+
+ KviThreadManager::killPendingEvents(this);
+}
+
+void KviHttpRequest::resetStatus()
+{
+ m_szLastError = __tr2qs("No request");
+ m_uTotalSize = 0;
+ m_uReceivedSize = 0;
+}
+
+void KviHttpRequest::resetData()
+{
+ m_szFileName = "";
+ m_eProcessingType = WholeFile;
+ m_eExistingFileAction = RenameIncoming;
+ m_url = "";
+ m_uMaxContentLength = 0;
+ m_uContentOffset = 0;
+ m_bChunkedTransferEncoding = false;
+ m_bGzip = false;
+ m_bIgnoreRemainingData = false;
+ m_uRemainingChunkSize = 0;
+}
+
+void KviHttpRequest::reset()
+{
+ resetStatus();
+ resetData();
+ resetInternalStatus();
+}
+
+bool KviHttpRequest::get(const KviUrl &u,ProcessingType p,const QString &szFileName)
+{
+ reset();
+ setUrl(u);
+ setProcessingType(p);
+ setFileName(szFileName);
+ return start();
+}
+
+bool KviHttpRequest::start()
+{
+ // ensure that the file is closed
+ resetInternalStatus();
+ resetStatus();
+
+ if(m_eProcessingType == StoreToFile)
+ {
+ if(m_szFileName.isEmpty())
+ {
+ m_szLastError = __tr2qs("No filename specified for the \"StoreToFile\" processing type");
+ return false;
+ }
+
+ if((m_eExistingFileAction == Resume) && (m_uContentOffset == 0))
+ {
+ // determine the content offset automatically
+ if(KviFile::exists(m_szFileName))
+ {
+ // we check it
+ QFileInfo fi(m_szFileName);
+ m_uContentOffset = fi.size();
+ }
+ }
+ }
+
+ if(m_url.host().isEmpty())
+ {
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Invalid URL: Missing hostname");
+ return false;
+ }
+
+ if((!kvi_strEqualCI(m_url.protocol().ptr(),"http")) && (!kvi_strEqualCI(m_url.protocol().ptr(),"https")))
+ {
+ resetInternalStatus();
+ m_szLastError=__tr2qs("Unsupported protocol %1").arg(m_url.protocol().ptr());
+ return false;
+ }
+
+ if(kvi_isValidStringIp(m_url.host().ptr()))
+ {
+ m_szIp = m_url.host();
+ QTimer::singleShot(10,this,SLOT(haveServerIp()));
+ return true;
+ }
+
+ return startDnsLookup();
+}
+
+bool KviHttpRequest::startDnsLookup()
+{
+ m_pDns = new KviDns();
+ connect(m_pDns,SIGNAL(lookupDone(KviDns *)),this,SLOT(dnsLookupDone(KviDns *)));
+
+ if(!m_pDns->lookup(m_url.host().ptr(),KviDns::IpV4))
+ {
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Unable to start the DNS lookup");
+ return false;
+ }
+
+ QString tmp;
+ KviQString::sprintf(tmp,__tr2qs("Looking up host %s"),m_url.host().ptr());
+ emit status(tmp); // FIXME
+
+ emit resolvingHost(QString(m_url.host().ptr()));
+
+ return true;
+}
+
+void KviHttpRequest::dnsLookupDone(KviDns *d)
+{
+ if(d->state() == KviDns::Success)
+ {
+ m_szIp = d->firstIpAddress();
+ delete m_pDns;
+ m_pDns = 0;
+ QString tmp;
+ KviQString::sprintf(tmp,__tr2qs("Host %s resolved to %Q"),m_url.host().ptr(),&m_szIp);
+ emit status(tmp);
+ haveServerIp();
+ } else {
+ int iErr = d->error();
+ resetInternalStatus();
+ m_szLastError = KviError::getDescription(iErr);
+ emit terminated(false);
+ }
+}
+
+void KviHttpRequest::haveServerIp()
+{
+ unsigned short uPort = m_url.port();
+ if(uPort == 0)uPort = 80;
+
+ QString tmp;
+ KviQString::sprintf(tmp,"%Q:%u",&m_szIp,uPort);
+ emit contactingHost(tmp);
+
+ if(m_pThread)delete m_pThread;
+
+ m_pThread = new KviHttpRequestThread(
+ this,
+ m_url.host().ptr(),
+ m_szIp,
+ uPort,
+ m_url.path().ptr(),
+ m_uContentOffset,
+ (m_eProcessingType == HeadersOnly) ? KviHttpRequestThread::Head : (m_szPostData.isEmpty() ? KviHttpRequestThread::Get : KviHttpRequestThread::Post),
+ m_szPostData,
+ kvi_strEqualCI(m_url.protocol().ptr(),"https"));
+
+ if(!m_pThread->start())
+ {
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Unable to start the request slave thread");
+ emit terminated(false);
+ return;
+ }
+
+ KviQString::sprintf(tmp,__tr2qs("Contacting host %Q on port %u"),&m_szIp,uPort);
+ emit status(tmp);
+}
+
+bool KviHttpRequest::event(QEvent *e)
+{
+ if(e->type() == KVI_THREAD_EVENT)
+ {
+ switch(((KviThreadEvent *)e)->id())
+ {
+ case KVI_THREAD_EVENT_BINARYDATA:
+ {
+ KviDataBuffer * b = ((KviThreadDataEvent<KviDataBuffer> *)e)->getData();
+ processData(b);
+ delete b;
+ return true;
+ }
+ break;
+ case KVI_HTTP_REQUEST_THREAD_EVENT_CONNECTED:
+ emit connectionEstabilished();
+ emit status(__tr2qs("Connection established, sending request"));
+ return true;
+ break;
+ case KVI_HTTP_REQUEST_THREAD_EVENT_REQUESTSENT:
+ {
+ QString * req = ((KviThreadDataEvent<QString> *)e)->getData();
+#ifdef COMPILE_USE_QT4
+ QStringList sl = req->split("\r\n");
+#else
+ QStringList sl = QStringList::split("\r\n",*req);
+#endif
+ emit requestSent(sl);
+ delete req;
+ return true;
+ }
+ break;
+ case KVI_THREAD_EVENT_SUCCESS:
+ if(!m_pThread && !m_bHeaderProcessed)
+ {
+ // the thread has already been deleted
+ // probably because the response was something like a 404
+ // just ignore the event
+ return true;
+ }
+ switch(m_eProcessingType)
+ {
+ case WholeFile:
+ // happens always
+ emit binaryData(*m_pBuffer);
+ break;
+ case Blocks:
+ // an unprocessed block ?.. should never happend.. but well :D
+ if(m_pBuffer->size() > 0)emit binaryData(*m_pBuffer);
+ break;
+ case Lines:
+ if(m_pBuffer->size() > 0)
+ {
+ // something left in the buffer and has no trailing LF
+ KviStr tmp((const char *)(m_pBuffer->data()),m_pBuffer->size());
+ emit data(tmp);
+ }
+ break;
+ case StoreToFile:
+ // same as above... should never happen.. but well :D
+ if(m_pFile && m_pBuffer->size() > 0)m_pFile->writeBlock((const char *)(m_pBuffer->data()),m_pBuffer->size());
+ break;
+ default:
+ // nothing... just make gcc happy
+ break;
+ }
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Success");
+ emit terminated(true);
+ return true;
+ break;
+ case KVI_THREAD_EVENT_ERROR:
+ {
+ KviStr * err = ((KviThreadDataEvent<KviStr> *)e)->getData();
+ m_szLastError = __tr2qs_no_xgettext(err->ptr());
+ delete err;
+ resetInternalStatus();
+ emit terminated(false);
+ return true;
+ }
+ break;
+ case KVI_THREAD_EVENT_MESSAGE:
+ {
+ KviStr * msg = ((KviThreadDataEvent<KviStr> *)e)->getData();
+ emit status(__tr2qs_no_xgettext(msg->ptr()));
+ delete msg;
+ return true;
+ }
+ break;
+ }
+ }
+ return QObject::event(e);
+}
+
+void KviHttpRequest::emitLines(KviDataBuffer * pDataBuffer)
+{
+ int idx = pDataBuffer->find((const unsigned char *)"\n",1);
+ while(idx != -1)
+ {
+ KviStr tmp((const char *)(m_pBuffer->data()),idx);
+ tmp.stripRight('\r');
+ pDataBuffer->remove(idx + 1);
+ idx = pDataBuffer->find((const unsigned char *)"\n",1);
+ emit data(tmp);
+ }
+}
+
+// header += "Accept: ";
+// QString acceptHeader = metaData("accept");
+// if (!acceptHeader.isEmpty())
+// header += acceptHeader;
+// else
+// header += DEFAULT_ACCEPT_HEADER;
+// header += "\r\n";
+//
+//#ifdef DO_GZIP
+// if (m_request.allowCompressedPage)
+// header += "Accept-Encoding: x-gzip, x-deflate, gzip, deflate, identity\r\n";
+//#endif
+//
+// if (!m_request.charsets.isEmpty())
+// header += "Accept-Charset: " + m_request.charsets + "\r\n";
+//
+// if (!m_request.languages.isEmpty())
+// header += "Accept-Language: " + m_request.languages + "\r\n";
+//
+//
+// /* support for virtual hosts and required by HTTP 1.1 */
+// header += "Host: ";
+// header += "Pragma: no-cache\r\n"; /* for HTTP/1.0 caches */
+// header += "Cache-control: no-cache\r\n"; /* for HTTP >=1.1 caches */
+
+// header += "Referer: "; //Don't try to correct spelling!
+// header += m_request.referrer;
+// header += "\r\n";
+bool KviHttpRequest::openFile()
+{
+ if(m_eProcessingType != StoreToFile)return true;
+
+ bool bAppend = false;
+
+ // take action when the file is existing
+ if(KviFile::exists(m_szFileName))
+ {
+ switch(m_eExistingFileAction)
+ {
+ case Resume:
+ {
+ bAppend = true;
+ }
+ break;
+ case RenameIncoming:
+ {
+ int i=0;
+ QString tmp = m_szFileName;
+ do {
+ i++;
+ m_szFileName = tmp + QString(".kvirnm-%1").arg(i);
+ } while(KviFile::exists(m_szFileName));
+ }
+ break;
+ case RenameExisting:
+ {
+ int i=0;
+ QString tmp;
+ do {
+ i++;
+ tmp = m_szFileName + QString(".kvirnm-%1").arg(i);
+ } while(KviFile::exists(tmp));
+ QDir d;
+ if(!d.rename(m_szFileName,tmp))
+ {
+ // fail :(
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Failed to rename the existing file, please rename manually and retry");
+ emit terminated(false);
+ return false;
+ }
+ }
+ break;
+ case Overwrite:
+ default:
+ // nothing
+ break;
+ }
+ }
+
+ m_pFile = new KviFile(m_szFileName);
+
+ if(!m_pFile->openForWriting(bAppend))
+ {
+ resetInternalStatus();
+ KviQString::sprintf(m_szLastError,__tr2qs("Can't open file \"%Q\" for writing"),&m_szFileName);
+ emit terminated(false);
+ return false;
+ }
+
+ return true;
+}
+
+
+
+
+
+bool KviHttpRequest::processHeader(KviStr &szHeader)
+{
+ int idx = szHeader.findFirstIdx("\r\n");
+ KviStr szResponse;
+ if(idx != -1)
+ {
+ szResponse = szHeader.left(idx);
+ szHeader.cutLeft(idx + 2);
+ } else {
+ szResponse = szHeader;
+ szHeader = "";
+ }
+
+ szResponse.stripWhiteSpace();
+
+ bool bValid = false;
+
+ unsigned int uStatus = 0;
+
+ // check the response value
+ if(kvi_strEqualCSN(szResponse.ptr(),"HTTP",4))
+ {
+ KviStr szR = szResponse;
+ szR.cutToFirst(' ');
+ szR.stripWhiteSpace();
+ int idx = szR.findFirstIdx(' ');
+ KviStr szNumber;
+ if(idx != -1)szNumber = szR.left(idx);
+ else szNumber = szR;
+ bool bOk;
+ uStatus = szNumber.toUInt(&bOk);
+ if(bOk)bValid = true;
+ }
+
+ if(!bValid)
+ {
+ // the response is invalid ?
+ resetInternalStatus();
+ m_szLastError=__tr2qs("Invalid HTTP response: %s").arg(szResponse.ptr());
+ emit terminated(false);
+ return false;
+ }
+
+ QString tmp;
+ KviQString::sprintf(tmp,__tr2qs("Received HTTP response: %s"),szResponse.ptr());
+
+ emit status(tmp);
+ emit receivedResponse(QString(szResponse.ptr()));
+
+ KviPointerList<KviStr> hlist;
+ hlist.setAutoDelete(true);
+
+ idx = szHeader.findFirstIdx("\r\n");
+ while(idx != -1)
+ {
+ if(idx > 0)
+ {
+ hlist.append(new KviStr(szHeader.ptr(),idx));
+ szHeader.cutLeft(idx + 2);
+ }
+ idx = szHeader.findFirstIdx("\r\n");
+ }
+ if(szHeader.hasData())hlist.append(new KviStr(szHeader));
+
+ KviPointerHashTable<const char *,KviStr> hdr(11,false,true);
+ hdr.setAutoDelete(true);
+
+ for(KviStr * s = hlist.first();s;s = hlist.next())
+ {
+ idx = s->findFirstIdx(":");
+ if(idx != -1)
+ {
+ KviStr szName = s->left(idx);
+ s->cutLeft(idx + 1);
+ s->stripWhiteSpace();
+ hdr.replace(szName.ptr(),new KviStr(*s));
+ //debug("FOUND HEADER (%s)=(%s)",szName.ptr(),s->ptr());
+ }
+ }
+
+ KviStr * size = hdr.find("Content-length");
+ if(size)
+ {
+ bool bOk;
+ m_uTotalSize = size->toUInt(&bOk);
+ if(!bOk)m_uTotalSize = 0;
+ }
+
+ KviStr * contentEncoding = hdr.find("Content-encoding");
+ if(contentEncoding)
+ {
+ m_bGzip = contentEncoding->equalsCI("gzip");
+ }
+
+ KviStr * transferEncoding = hdr.find("Transfer-Encoding");
+ if(transferEncoding)
+ {
+ if(kvi_strEqualCI(transferEncoding->ptr(),"chunked"))
+ {
+ // be prepared to handle the chunked transfer encoding as required by HTTP/1.1
+ m_bChunkedTransferEncoding = true;
+ m_uRemainingChunkSize = 0;
+ }
+ }
+
+ emit header(&hdr);
+
+ // check the status
+
+ // case 200: // OK
+ // case 206: // Partial content
+
+ // case 100: // Continue ??
+ // case 101: // Switching protocols ???
+ // case 201: // Created
+ // case 202: // Accepted
+ // case 203: // Non-Authoritative Information
+ // case 204: // No content
+ // case 205: // Reset content
+ // case 300: // Multiple choices
+ // case 301: // Moved permanently
+ // case 302: // Found
+ // case 303: // See Other
+ // case 304: // Not modified
+ // case 305: // Use Proxy
+ // case 306: // ???
+ // case 307: // Temporary Redirect
+ // case 400: // Bad request
+ // case 401: // Unauthorized
+ // case 402: // Payment Required
+ // case 403: // Forbidden
+ // case 404: // Not found
+ // case 405: // Method not allowed
+ // case 406: // Not acceptable
+ // case 407: // Proxy authentication required
+ // case 408: // Request timeout
+ // case 409: // Conflict
+ // case 410: // Gone
+ // case 411: // Length required
+ // case 412: // Precondition failed
+ // case 413: // Request entity too large
+ // case 414: // Request-URI Too Long
+ // case 415: // Unsupported media type
+ // case 416: // Requested range not satisfiable
+ // case 417: // Expectation Failed
+ // case 500: // Internal server error
+ // case 501: // Not implemented
+ // case 502: // Bad gateway
+ // case 503: // Service unavailable
+ // case 504: // Gateway timeout
+ // case 505: // HTTP Version not supported
+
+ if((uStatus != 200) && (uStatus != 206))
+ {
+ // this is not "OK" and not "Partial content"
+ // Error , redirect or something confusing
+ if(m_eProcessingType != HeadersOnly)
+ {
+ // this is an error then
+ resetInternalStatus();
+ m_szLastError = szResponse.ptr();
+ emit terminated(false);
+ return false;
+ } // else the server will terminate (it was a HEAD request)
+ }
+
+ if((m_uMaxContentLength > 0) && (m_uTotalSize > ((unsigned int)m_uMaxContentLength)))
+ {
+ resetInternalStatus();
+ m_szLastError=__tr2qs("Stream exceeding maximum length");
+ emit terminated(false);
+ return false;
+ }
+
+ // fixme: could check for data type etc...
+
+ return true;
+}
+#define BUFFER_SIZE 32768
+
+void KviHttpRequest::processData(KviDataBuffer * data)
+{
+// unsigned char obuffer[BUFFER_SIZE];
+ if(m_bChunkedTransferEncoding && m_bIgnoreRemainingData)
+ {
+ // In chunked transfer encoding mode there may be additional headers
+ // after the last chunk of data. We simply ignore them.
+ return;
+ }
+
+ if(!m_bHeaderProcessed)
+ {
+ // time to process the header
+ m_pBuffer->append(*data);
+
+ int idx = m_pBuffer->find((const unsigned char *)"\r\n\r\n",4);
+ if(idx == -1)
+ {
+ // header not complete
+ if(m_pBuffer->size() > 4096)
+ {
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Header too long: exceeded 4096 bytes");
+ emit terminated(false);
+ }
+ return;
+ }
+ KviStr szHeader((const char *)(m_pBuffer->data()),idx);
+ m_pBuffer->remove(idx + 4);
+
+ if(!processHeader(szHeader))return;
+ m_bHeaderProcessed = true;
+
+ if(m_eProcessingType == StoreToFile)
+ {
+ if(!openFile())return;
+ }
+
+ m_uReceivedSize = m_pBuffer->size();
+
+
+ // here the header is complete and the eventual remaining data is in m_pBuffer. data has been already used.
+
+ } else {
+ // header already processed
+ m_uReceivedSize += data->size();
+
+ // here the header is complete and some data *might* be already in m_pBuffer. data is unused yet.
+
+ // Optimisation: If the transfer is NOT chunked (so we don't have to parse it)
+ // and the requested processing type is either Blocks or StoreToFile
+ // then we just can avoid to copy the data to m_pBuffer.
+ // This is a good optimisation since for large files we can save allocating
+ // space for and moving megabytes of data...
+
+
+ if((!m_bChunkedTransferEncoding) && ((m_eProcessingType == Blocks) || (m_eProcessingType == StoreToFile)))
+ {
+ switch(m_eProcessingType)
+ {
+ case Blocks:
+ emit binaryData(*data);
+ break;
+ case StoreToFile:
+ m_pFile->writeBlock((const char *)(data->data()),data->size());
+ break;
+ }
+
+ if(((m_uTotalSize > 0) && (m_uReceivedSize > m_uTotalSize)) || ((m_uMaxContentLength > 0) && (m_uReceivedSize > m_uMaxContentLength)))
+ {
+ resetInternalStatus();
+ m_szLastError=__tr2qs("Stream exceeded expected length");
+ emit terminated(false);
+ }
+
+ return;
+ }
+
+ // need to append to m_pBuffer and process it
+ m_pBuffer->append(*data);
+ }
+
+ // we're processing data in m_pBuffer here
+ if(m_bChunkedTransferEncoding)
+ {
+ // The transfer encoding is chunked: the buffer contains
+ // chunks of data with an initial header composed
+ // of a hexadecimal length, an optional bullshit and a single CRLF
+ // The transfer terminates when we read a last chunk of size 0
+ // that may be followed by optional headers...
+ // This sux :)
+ while(m_pBuffer->size() > 0) // <-- note that we may exit from this loop also for other conditions (there is a goto below)
+ {
+ // we process chunks of parts of chunks at a time.
+ if(m_uRemainingChunkSize > 0)
+ {
+ // process the current chunk data
+ unsigned int uProcessSize = m_uRemainingChunkSize;
+ if(uProcessSize > m_pBuffer->size())uProcessSize = m_pBuffer->size();
+ m_uRemainingChunkSize -= uProcessSize;
+
+ switch(m_eProcessingType)
+ {
+ case Blocks:
+ if(m_pBuffer->size() == uProcessSize)
+ {
+ // avoid copying to a new buffer
+ emit binaryData(*m_pBuffer);
+ } else {
+ // must copy
+ KviDataBuffer tmp(uProcessSize,m_pBuffer->data());
+ emit binaryData(tmp);
+ m_pBuffer->remove(uProcessSize);
+ }
+ break;
+ case Lines:
+ if(m_pBuffer->size() == uProcessSize)
+ {
+ // avoid copying to a new buffer
+ emitLines(m_pBuffer);
+ } else {
+ // must copy
+ KviDataBuffer tmp(uProcessSize,m_pBuffer->data());
+ emitLines(&tmp);
+ m_pBuffer->remove(uProcessSize);
+ }
+ break;
+ case StoreToFile:
+ m_pFile->writeBlock((const char *)(m_pBuffer->data()),uProcessSize);
+ m_pBuffer->remove(uProcessSize);
+ break;
+ default:
+ // nothing.. just make gcc happy
+ break;
+ }
+ // now either the buffer is empty or there is another chunk header: continue looping
+ } else {
+ // We're looking for the beginning of a chunk now.
+ // Note that we might be at the end of a previous chunk that has a CRLF terminator
+ // we need to skip it.
+ int crlf = m_pBuffer->find((const unsigned char *)"\r\n",2);
+ if(crlf != -1)
+ {
+ if(crlf == 0)
+ {
+ // This is a plain CRLF at the beginning of the buffer BEFORE a chunk header.
+ // It comes from the previous chunk terminator. Skip it.
+ m_pBuffer->remove(2);
+ } else {
+ // got a chunk header
+ KviStr szHeader((const char *)(m_pBuffer->data()),crlf);
+ szHeader.cutFromFirst(' ');
+ // now szHeader should contain a hexadecimal chunk length... (why the hell it is hex and not decimal ????)
+ QString szHexHeader = szHeader.ptr();
+ bool bOk;
+ m_uRemainingChunkSize = szHexHeader.toLong(&bOk,16);
+ if(!bOk)
+ {
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Protocol error: invalid chunk size");
+ emit terminated(false);
+ return;
+ }
+ m_pBuffer->remove(crlf+2);
+ if(m_uRemainingChunkSize == 0)
+ {
+ // this is the last chunk of data. It may be followed by optional headers
+ // but we actually don't need them (since we're surely not in HEAD mode)
+ m_bIgnoreRemainingData = true;
+ m_pBuffer->clear();
+ goto check_stream_length;
+ }
+ }
+ // the rest is valid data of a non-zero chunk: continue looping
+ } else {
+ // chunk header not complete
+ if(m_pBuffer->size() > 4096)
+ {
+ resetInternalStatus();
+ m_szLastError = __tr2qs("Chunk header too long: exceeded 4096 bytes");
+ emit terminated(false);
+ return;
+ }
+ goto check_stream_length;
+ }
+ }
+ }
+ } else {
+ // the transfer encoding is not chunked: m_pBuffer contains only valid data
+ switch(m_eProcessingType)
+ {
+ case Blocks:
+ if(m_pBuffer->size() > 0)emit binaryData(*m_pBuffer);
+ m_pBuffer->clear();
+ break;
+ case Lines:
+ if(m_pBuffer->size() > 0)emitLines(m_pBuffer);
+ break;
+ case StoreToFile:
+ m_pFile->writeBlock((const char *)(m_pBuffer->data()),m_pBuffer->size());
+ m_pBuffer->clear();
+ break;
+ default:
+ // nothing.. just make gcc happy
+ break;
+ }
+ }
+
+check_stream_length:
+
+ if(((m_uTotalSize > 0) && (m_uReceivedSize > m_uTotalSize)) || ((m_uMaxContentLength > 0) && (m_uReceivedSize > m_uMaxContentLength)))
+ {
+ resetInternalStatus();
+ m_szLastError=__tr2qs("Stream exceeded expected length");
+ emit terminated(false);
+ }
+ return;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+KviHttpRequestThread::KviHttpRequestThread(
+ KviHttpRequest * r,
+ const QString &szHost,
+ const QString &szIp,
+ unsigned short uPort,
+ const QString & szPath,
+ unsigned int uContentOffset,
+ RequestMethod m,
+ const QString &szPostData,
+ bool bUseSSL
+) : KviSensitiveThread()
+{
+ m_pRequest = r;
+ m_szHost = szHost;
+ m_szIp = szIp;
+ m_szPath = szPath;
+ m_uPort = uPort > 0 ? uPort : 80;
+ m_uContentOffset = uContentOffset;
+ m_eRequestMethod = m;
+ m_szPostData = szPostData;
+ m_sock = KVI_INVALID_SOCKET;
+ m_bUseSSL = bUseSSL;
+#ifdef COMPILE_SSL_SUPPORT
+ m_pSSL = 0;
+#endif
+}
+
+KviHttpRequestThread::~KviHttpRequestThread()
+{
+}
+
+bool KviHttpRequestThread::processInternalEvents()
+{
+ while(KviThreadEvent *e = dequeueEvent())
+ {
+ switch(e->id())
+ {
+ case KVI_THREAD_EVENT_TERMINATE:
+ {
+ delete e;
+ return false;
+ }
+ break;
+ default:
+ debug("Unrecognized event in http thread");
+ delete e;
+ return false;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool KviHttpRequestThread::failure(const char *error)
+{
+ if(error)
+ {
+ postEvent(m_pRequest,new KviThreadDataEvent<KviStr>(KVI_THREAD_EVENT_ERROR,new KviStr(error)));
+ } /*else {
+ postEvent(m_pRequest,new KviThreadDataEvent<KviStr>(KVI_THREAD_EVENT_ERROR,new KviStr(__tr2qs("Aborted"))));
+ }*/
+ return false;
+}
+
+
+bool KviHttpRequestThread::selectForWrite(int iTimeoutInSecs)
+{
+
+ kvi_time_t startTime = kvi_unixTime();
+
+ for(;;)
+ {
+ if(!processInternalEvents())
+ {
+ return failure(0);
+ }
+
+ fd_set writeSet;
+
+ FD_ZERO(&writeSet);
+
+ FD_SET(m_sock,&writeSet);
+
+ struct timeval tmv;
+ tmv.tv_sec = 0;
+ tmv.tv_usec = 1000; // we wait 1000 usecs for an event
+
+
+ int nRet = kvi_socket_select(m_sock + 1,0,&writeSet,0,&tmv);
+
+ if(nRet > 0)
+ {
+ if(FD_ISSET(m_sock,&writeSet))
+ {
+ // connected!
+ return true;
+ }
+ } else {
+ if(nRet < 0)
+ {
+ int err = kvi_socket_error();
+#ifdef COMPILE_ON_WINDOWS
+ if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK))
+#else
+ if((err != EAGAIN) && (err != EINTR))
+#endif
+ {
+ return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err)));
+ }
+ }
+ }
+
+
+ if((time(0) - startTime) > iTimeoutInSecs)return failure(__tr_no_lookup("Operation timed out"));
+
+ usleep(100000); // 1/10 sec
+ }
+
+ return false;
+}
+
+bool KviHttpRequestThread::sslFailure()
+{
+#ifdef COMPILE_SSL_SUPPORT
+ KviStr buffer;
+ if(m_pSSL->getLastErrorString(buffer))
+ {
+ failure(buffer.ptr());
+ } else {
+ failure(__tr_no_lookup("Unexpected SSL error"));
+ }
+#endif
+ return false;
+}
+
+bool KviHttpRequestThread::connectToRemoteHost()
+{
+ m_sock = kvi_socket_create(KVI_SOCKET_PF_INET,KVI_SOCKET_TYPE_STREAM,0); //tcp
+ if(m_sock == KVI_INVALID_SOCKET)
+ return failure(__tr_no_lookup("Failed to create the socket"));
+
+ if(!kvi_socket_setNonBlocking(m_sock))
+ return failure(__tr_no_lookup("Failed to enter non blocking mode"));
+
+ sockaddr_in saddr;
+
+ if(!KviNetUtils::stringIpToBinaryIp(m_szIp,&(saddr.sin_addr)))
+ return failure(__tr_no_lookup("Invalid target address"));
+
+ saddr.sin_port = htons(m_uPort);
+ saddr.sin_family = AF_INET;
+
+ if(!kvi_socket_connect(m_sock,(struct sockaddr *)&saddr,sizeof(saddr)))
+ {
+ int err = kvi_socket_error();
+ if(!kvi_socket_recoverableConnectError(err))
+ {
+ return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err)));
+ }
+ }
+
+ // now loop selecting for write
+
+ //#warning "This should be a tuneable timeout"
+ if(!selectForWrite(60))return false;
+
+ int sockError;
+ int iSize=sizeof(sockError);
+ if(!kvi_socket_getsockopt(m_sock,SOL_SOCKET,SO_ERROR,(void *)&sockError,&iSize))sockError = -1;
+ if(sockError != 0)
+ {
+ //failed
+ if(sockError > 0)sockError = KviError::translateSystemError(sockError);
+ else sockError = KviError_unknownError;
+ return failure(KviError::getUntranslatedDescription(sockError));
+ }
+
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_bUseSSL)
+ {
+ m_pSSL = new KviSSL();
+ if(!m_pSSL->initContext(KviSSL::Client))
+ return failure(__tr_no_lookup("Failed to initialize the SSL context"));
+ if(!m_pSSL->initSocket(m_sock))
+ return failure(__tr_no_lookup("Failed to initialize the SSL connection"));
+
+ for(;;)
+ {
+ switch(m_pSSL->connect())
+ {
+ case KviSSL::Success:
+ // done: connected.
+ return true;
+ break;
+ case KviSSL::WantRead:
+ if(!selectForRead(60))return false;
+ break;
+ case KviSSL::WantWrite:
+ if(!selectForWrite(60))return false;
+ break;
+ case KviSSL::RemoteEndClosedConnection:
+ return failure(__tr_no_lookup("Remote end has closed the connection"));
+ break;
+ case KviSSL::SSLError:
+ return sslFailure();
+ break;
+ case KviSSL::SyscallError:
+ {
+ // syscall problem
+ int err = kvi_socket_error();
+ if(!kvi_socket_recoverableError(err))
+ {
+ // Declare problems :)
+ return failure(__tr_no_lookup("Unrecoverable SSL error during handshake"));
+ } // else can recover ? (EAGAIN , EINTR ?) ... should select for read or for write
+ }
+ break;
+ default:
+ return sslFailure();
+ break;
+ }
+ }
+
+ // never here
+ return true;
+ }
+#endif
+
+ return true;
+}
+
+
+bool KviHttpRequestThread::sendBuffer(const char * buffer,int bufLen,int iTimeoutInSecs)
+{
+ const char * ptr = buffer;
+ int curLen = bufLen;
+
+ time_t startTime = time(0);
+
+ for(;;)
+ {
+ if(!processInternalEvents())return failure();
+
+ int wrtn;
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ wrtn = m_pSSL->write((char *)ptr,curLen);
+ } else {
+#endif
+ wrtn = kvi_socket_send(m_sock,ptr,curLen);
+#ifdef COMPILE_SSL_SUPPORT
+ }
+#endif
+
+ if(wrtn > 0)
+ {
+ curLen -= wrtn;
+
+ if(curLen <= 0)break;
+
+ ptr += wrtn;
+ } else {
+ if(wrtn < 0)
+ {
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ // ops...might be an SSL error
+ switch(m_pSSL->getProtocolError(wrtn))
+ {
+ case KviSSL::WantWrite:
+ if(!selectForWrite(60))return false;
+ break;
+ case KviSSL::WantRead:
+ if(!selectForRead(60))return false;
+ break;
+ case KviSSL::SyscallError:
+ if(wrtn == 0)
+ {
+ return failure(__tr_no_lookup("Remote end has closed the connection"));
+ } else {
+ int iSSLErr = m_pSSL->getLastError(true);
+ if(iSSLErr != 0)
+ {
+ return sslFailure();
+ } else {
+ goto handle_system_error;
+ }
+ }
+ break;
+ case KviSSL::SSLError:
+ return sslFailure();
+ break;
+ default:
+ return sslFailure();
+ break;
+ }
+ } else {
+#endif //COMPILE_SSL_SUPPORT
+
+handle_system_error:
+ int err = kvi_socket_error();
+#ifdef COMPILE_ON_WINDOWS
+ if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK))
+#else
+ if((err != EAGAIN) && (err != EINTR))
+#endif
+ {
+ return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err)));
+ }
+#ifdef COMPILE_SSL_SUPPORT
+ }
+#endif
+ }
+ }
+
+ int diff = time(0) - startTime;
+ if(diff > iTimeoutInSecs)
+ return failure(__tr_no_lookup("Operation timed out"));
+
+ usleep(10000);
+ }
+
+ return true;
+}
+
+
+int KviHttpRequestThread::selectForReadStep()
+{
+ // calls select on the main socket
+ // returns 1 if there is data available for reading
+ // returns 0 if there is no data available but there was no error
+ // returns -1 if there was a critical error (socket closed)
+ fd_set readSet;
+
+ FD_ZERO(&readSet);
+
+ FD_SET(m_sock,&readSet);
+
+ struct timeval tmv;
+ tmv.tv_sec = 0;
+ tmv.tv_usec = 1000; // we wait 1000 usecs for an event
+
+
+ int nRet = kvi_socket_select(m_sock + 1,&readSet,0,0,&tmv);
+
+ if(nRet > 0)
+ {
+ if(FD_ISSET(m_sock,&readSet))
+ {
+ // ok
+ return 1;
+ }
+ } else {
+ if(nRet < 0)
+ {
+ int err = kvi_socket_error();
+#ifdef COMPILE_ON_WINDOWS
+ if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK))
+#else
+ if((err != EAGAIN) && (err != EINTR))
+#endif
+ {
+ failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err)));
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+bool KviHttpRequestThread::selectForRead(int iTimeoutInSecs)
+{
+ // waits for some data to arrive on the socket
+ // up to iTimeoutInSecs seconds
+ // returns true if data is available on the socket
+ // or false if there was a select() error or no data
+ // was available in the specified amount of time
+
+ time_t startTime = time(0);
+
+ for(;;)
+ {
+ if(!processInternalEvents())
+ {
+ return failure(); // ensure that the socket is closed
+ }
+
+ int nRet = selectForReadStep();
+
+ if(nRet < 0)return false;
+ if(nRet > 0)return true;
+
+ int diff = time(0) - startTime;
+ if(diff > iTimeoutInSecs)
+ return failure(__tr_no_lookup("Operation timed out (while selecting for read)"));
+
+ usleep(100000); // 1/10 sec
+ }
+
+ return false;
+}
+
+bool KviHttpRequestThread::readDataStep()
+{
+ unsigned char buffer[2048];
+ int readed;
+
+
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ readed = m_pSSL->read((char *)buffer,2048);
+ if(readed <= 0)
+ {
+ // ssl error....?
+ switch(m_pSSL->getProtocolError(readed))
+ {
+ case KviSSL::ZeroReturn:
+ readed = 0;
+ break;
+ case KviSSL::WantRead:
+ return selectForRead(120);
+ break;
+ case KviSSL::WantWrite:
+ return selectForWrite(120);
+ break;
+ case KviSSL::SyscallError:
+ {
+ int iE = m_pSSL->getLastError(true);
+ if(iE != 0)return sslFailure();
+ }
+ break;
+ case KviSSL::SSLError:
+ return sslFailure();
+ break;
+ default:
+ return sslFailure();
+ break;
+ }
+ }
+ } else {
+#endif
+ readed = kvi_socket_read(m_sock,buffer,2048);
+#ifdef COMPILE_SSL_SUPPORT
+ }
+#endif
+
+ if(readed > 0)
+ {
+ postEvent(m_pRequest,new KviThreadDataEvent<KviDataBuffer>(KVI_THREAD_EVENT_BINARYDATA,new KviDataBuffer(readed,buffer)));
+ } else {
+ if(readed < 0)
+ {
+ // Read error ?
+ int err = kvi_socket_error();
+#ifdef COMPILE_ON_WINDOWS
+ if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK))
+#else
+ if((err != EAGAIN) && (err != EINTR))
+#endif
+ {
+ // yes...read error
+ return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err)));
+ }
+ return selectForRead(120); // EINTR or EAGAIN...transient problem
+ } else {
+ // readed == 0
+ // Connection closed by remote host
+ postEvent(m_pRequest,new KviThreadEvent(KVI_THREAD_EVENT_SUCCESS));
+ return false;
+ }
+ }
+ return selectForRead(120);
+}
+
+void KviHttpRequestThread::run()
+{
+ // setup:
+ // nothing needed
+
+ // run:
+ runInternal();
+
+ // cleanup:
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ delete m_pSSL;
+ m_pSSL = 0;
+ }
+#endif
+
+ if(kvi_socket_isValid(m_sock))
+ {
+ kvi_socket_close(m_sock);
+ m_sock = KVI_INVALID_SOCKET;
+ }
+}
+
+void KviHttpRequestThread::runInternal()
+{
+#ifndef COMPILE_SSL_SUPPORT
+ if(m_bUseSSL)
+ {
+ failure(__tr_no_lookup("This KVIrc executable has no SSL support"));
+ return;
+ }
+#endif
+
+ if(!connectToRemoteHost())return;
+
+ postEvent(m_pRequest,new KviThreadEvent(KVI_HTTP_REQUEST_THREAD_EVENT_CONNECTED));
+
+ // FIXME: Other headers ?
+
+ KviStr szMethod;
+ switch(m_eRequestMethod)
+ {
+ case Head: szMethod = "HEAD"; break;
+ case Post: szMethod = "POST"; break;
+ case Get: szMethod = "GET"; break;
+ }
+
+ KviStr szRequest(KviStr::Format,"%s %s HTTP/1.1\r\n" \
+ "Host: %s\r\n" \
+ "Connection: Close\r\n" \
+ "User-Agent: KVIrc-http-slave/1.0.0\r\n" \
+ "Accept: */*\r\n",
+ szMethod.ptr(),KviQString::toUtf8(m_szPath).data(),KviQString::toUtf8(m_szHost).data());
+
+ if(m_uContentOffset > 0)
+ szRequest.append(KviStr::Format,"Range: bytes=%u-\r\n",m_uContentOffset);
+
+ if(m_eRequestMethod == Post)
+ {
+ szRequest.append(KviStr::Format,"Content-Type: application/x-www-form-urlencoded\r\n" \
+ "Content-Length: %u\r\n" \
+ "Cache-control: no-cache\r\n" \
+ "Pragma: no-cache\r\n",m_szPostData.length());
+ }
+
+ szRequest += "\r\n";
+
+ if(m_eRequestMethod == Post)
+ {
+ if(!m_szPostData.isEmpty())
+ szRequest.append(m_szPostData);
+ szRequest += "\r\n";
+ }
+
+ //debug("SENDING REQUEST:\n%s",szRequest.ptr());
+
+ if(!sendBuffer(szRequest.ptr(),szRequest.len(),60))return;
+
+ // now loop reading data
+ postEvent(m_pRequest,new KviThreadDataEvent<QString>(KVI_HTTP_REQUEST_THREAD_EVENT_REQUESTSENT,new QString(szRequest)));
+
+ for(;;)
+ {
+ if(!readDataStep())return;
+ }
+}
+
diff --git a/src/kvilib/net/kvi_http.h b/src/kvilib/net/kvi_http.h
new file mode 100644
index 00000000..1bd6a9d9
--- /dev/null
+++ b/src/kvilib/net/kvi_http.h
@@ -0,0 +1,209 @@
+#ifndef _KVI_HTTP_H_
+#define _KVI_HTTP_H_
+//=============================================================================
+//
+// File : kvi_http.h
+// Creation date : Sat Aug 17 13:43:31 2002 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002-2007 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. ,59 Temple Place - Suite 33, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "kvi_settings.h"
+#include "kvi_heapobject.h"
+#include "kvi_string.h"
+#include "kvi_thread.h"
+#include "kvi_sockettype.h"
+#include "kvi_databuffer.h"
+#include "kvi_inttypes.h"
+#include "kvi_url.h"
+
+#include <qobject.h>
+#include "kvi_pointerhashtable.h"
+#include "kvi_file.h"
+#include <qstringlist.h>
+
+class KviDns;
+class KviSSL;
+class KviHttpRequestThread;
+
+//
+// This class implements a HTTP protocol client.
+// It's able to send GET, POST and HEAD requests,
+// download stuff to a file or to a qt SLOT().
+//
+
+class KVILIB_API KviHttpRequest : public QObject, public KviHeapObject
+{
+ Q_OBJECT
+public:
+ enum ProcessingType
+ {
+ HeadersOnly, // Download headers only (HEAD request)
+ WholeFile, // Emit the data as whole file (binaryData() is emitted)
+ Blocks, // Emit the data as blocks (binaryData() is emitted)
+ Lines, // Emit the data as ASCII text lines (the client must take care of decoding the data)
+ StoreToFile // Store the data to a file
+ };
+ enum ExistingFileAction
+ {
+ Overwrite, // Overwrite existing file
+ RenameIncoming, // Automatically rename the incoming file
+ RenameExisting, // Automatically rename the existing file
+ Resume // Attempt to resume the file (get partial content)
+ };
+public:
+ KviHttpRequest();
+ ~KviHttpRequest();
+protected:
+ // data
+ KviUrl m_url;
+ QString m_szFileName;
+ ProcessingType m_eProcessingType;
+ ExistingFileAction m_eExistingFileAction;
+ void * m_pPrivateData;
+ unsigned int m_uMaxContentLength;
+ unsigned int m_uContentOffset;
+ QString m_szPostData;
+ // status
+ QString m_szLastError;
+ unsigned int m_uTotalSize;
+ unsigned int m_uReceivedSize;
+ // internal status
+ QString m_szIp;
+ KviDns * m_pDns;
+ KviHttpRequestThread * m_pThread;
+ KviDataBuffer * m_pBuffer;
+ bool m_bHeaderProcessed;
+ bool m_bChunkedTransferEncoding;
+ bool m_bGzip;
+ unsigned int m_uRemainingChunkSize;
+ bool m_bIgnoreRemainingData; // used in chunked transfer after the last chunk has been seen
+ KviFile * m_pFile;
+protected:
+ bool startDnsLookup();
+ virtual bool event(QEvent *e);
+ void processData(KviDataBuffer * data);
+ bool processHeader(KviStr &szHeader);
+ bool openFile();
+ void emitLines(KviDataBuffer * pDataBuffer);
+
+ void resetStatus();
+ void resetData();
+ void resetInternalStatus();
+protected slots:
+ void dnsLookupDone(KviDns *d);
+ void haveServerIp();
+public:
+ const KviUrl & url(){ return m_url; };
+ ProcessingType processingType(){ return m_eProcessingType; };
+ ExistingFileAction existingFileAction(){ return m_eExistingFileAction; };
+ const QString &fileName(){ return m_szFileName; };
+ void * privateData(){ return m_pPrivateData; };
+ unsigned int maxContentLength(){ return m_uMaxContentLength; };
+ unsigned int contentOffset(){ return m_uContentOffset; };
+ unsigned int totalSize(){ return m_uTotalSize; };
+ unsigned int receivedSize(){ return m_uReceivedSize; };
+
+ void reset();
+
+ void setPostData(const QString &szPostData){ m_szPostData = szPostData; };
+ void setUrl(const KviUrl &u){ m_url = u; };
+ void setProcessingType(ProcessingType t){ m_eProcessingType = t; };
+ void setExistingFileAction(ExistingFileAction a){ m_eExistingFileAction = a; };
+ void setFileName(const QString &szFileName){ m_szFileName = szFileName; };
+ void setPrivateData(void * ptr){ m_pPrivateData = ptr; };
+ void setMaxContentLength(int uMaxContentLength){ m_uMaxContentLength = uMaxContentLength; }; //0 means unlimited
+ // this will work regardless of ExistingFileAction : even if the file doesn't exist
+ void setContentOffset(int uContentOffset){ m_uContentOffset = uContentOffset; };
+
+ bool start();
+
+ // this is a shortcut for reset()+setUrl()+setProcessingType()+setFileName()+start()
+ bool get(const KviUrl &u,ProcessingType p = WholeFile,const QString &szFileName = QString::null);
+
+ const QString & lastError(){ return m_szLastError; };
+
+ void abort();
+signals:
+ void resolvingHost(const QString &hostname);
+ void contactingHost(const QString &ipandport);
+ void connectionEstabilished();
+ void receivedResponse(const QString &response);
+
+ void terminated(bool bSuccess);
+
+
+ void status(const QString &message);
+ void data(const KviStr &data);
+ void binaryData(const KviDataBuffer &data);
+ void header(KviPointerHashTable<const char *,KviStr> * hdr);
+ void requestSent(const QStringList &request);
+};
+
+
+class KviHttpRequestThread : public KviSensitiveThread
+{
+ friend class KviHttpRequest;
+public:
+ enum RequestMethod { Post, Get , Head };
+protected:
+ KviHttpRequestThread(KviHttpRequest * r,
+ const QString &szHost,
+ const QString &szIp,
+ unsigned short uPort,
+ const QString &szPath,
+ unsigned int uContentOffset,
+ RequestMethod m,
+ const QString &szPostData = QString::null,
+ bool bUseSSL = false);
+
+public:
+ ~KviHttpRequestThread();
+protected:
+ KviHttpRequest * m_pRequest;
+
+ QString m_szHost;
+ QString m_szIp;
+ QString m_szPath;
+ unsigned int m_uContentOffset;
+ RequestMethod m_eRequestMethod;
+ QString m_szPostData;
+
+ unsigned short m_uPort;
+ kvi_socket_t m_sock;
+ bool m_bUseSSL;
+#ifdef COMPILE_SSL_SUPPORT
+ KviSSL * m_pSSL;
+#endif
+protected:
+ int selectForReadStep();
+ bool selectForRead(int iTimeoutInSecs);
+ bool readDataStep();
+ bool sendBuffer(const char *buffer,int bufLen,int iTimeoutInSecs);
+ bool failure(const char *error=0);
+ bool sslFailure();
+ bool selectForWrite(int iTimeoutInSecs);
+ bool connectToRemoteHost();
+ bool processInternalEvents();
+ void runInternal();
+ virtual void run();
+};
+
+
+#endif //_KVI_HTTP_H_
diff --git a/src/kvilib/net/kvi_netutils.cpp b/src/kvilib/net/kvi_netutils.cpp
new file mode 100644
index 00000000..0cdb8b02
--- /dev/null
+++ b/src/kvilib/net/kvi_netutils.cpp
@@ -0,0 +1,1504 @@
+//=============================================================================
+
+//
+
+// File : kvi_netutlis.cpp
+
+// Creation date : Sun Jun 18 2000 18:37:27 by Szymon Stefanek
+
+//
+
+// This file is part of the KVirc irc client distribution
+
+// Copyright (C) 1999-2000 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.
+
+//
+
+//=============================================================================
+
+// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARGH!
+// This effect is caused by the combination of broken CVS installation and
+// the ugly windows "text mode" files
+
+#define __KVILIB__
+
+
+
+
+
+#define _KVI_NETUTILS_CPP_
+
+
+
+#include "kvi_netutils.h"
+
+#include "kvi_memmove.h"
+#include <qstringlist.h>
+
+
+#ifndef COMPILE_ON_WINDOWS
+
+#include <sys/time.h> // struct timeval
+
+#endif
+
+
+
+#include <sys/types.h>
+
+
+
+#include "kvi_qstring.h"
+
+
+
+#ifndef COMPILE_ON_WINDOWS
+
+ #include <unistd.h>
+
+ #include <netdb.h>
+
+#endif
+
+
+
+#ifdef COMPILE_GET_INTERFACE_ADDRESS
+
+ #include <sys/ioctl.h>
+
+ #include <net/if.h>
+
+#endif //COMPILE_GET_INTERFACE_ADDRESS
+
+
+
+#ifndef HAVE_INET_ATON
+
+
+
+
+
+// FIXME: #warning "Your system lacks the inet_aton function,"
+
+// FIXME: #warning "you're trying to compile this file without"
+
+// FIXME: #warning "the config.h created by the configure script,"
+
+// FIXME: #warning "Using own internal implementation of inet_aton."
+
+
+
+#include <ctype.h>
+
+
+
+
+
+// Need own inet_aton implementation
+
+
+
+//
+
+// Check whether "cp" is a valid ascii representation
+
+// of an Internet address and convert to a binary address.
+
+// Returns 1 if the address is valid, 0 if not.
+
+// This replaces inet_addr, the return value from which
+
+// cannot distinguish between failure and a local broadcast address.
+
+//
+
+// Original code comes from the ircd source.
+
+//
+
+
+
+bool kvi_stringIpToBinaryIp(const char *szIp,struct in_addr *address)
+
+{
+
+ register unsigned long val;
+
+ register int base, n;
+
+ register char c;
+
+ unsigned int parts[4];
+
+ register unsigned int *pp = parts;
+
+ if(!szIp)return false;
+
+ c = *szIp;
+
+ for(;;){
+
+ // Collect number up to ``.''.
+
+ // Values are specified as for C:
+
+ // 0x=hex, 0=octal, isdigit=decimal.
+
+ if(!isdigit(c))return false;
+
+ val = 0;
+
+ base = 10;
+
+ if(c == '0'){
+
+ c = *++szIp;
+
+ if((c == 'x')||(c == 'X'))base = 16, c = *++szIp;
+
+ else base = 8;
+
+ }
+
+ for (;;) {
+
+ if(isascii(c) && isdigit(c)) {
+
+ val = (val * base) + (c - '0');
+
+ c = *++szIp;
+
+ } else if (base == 16 && isascii(c) && isxdigit(c)) {
+
+ val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A'));
+
+ c = *++szIp;
+
+ } else break;
+
+ }
+
+ if(c == '.'){
+
+ // Internet format:
+
+ // a.b.c.d
+
+ // a.b.c (with c treated as 16 bits)
+
+ // a.b (with b treated as 24 bits)
+
+ if(pp >= (parts + 3)) return false;
+
+ *pp++ = val;
+
+ c = *++szIp;
+
+ } else break;
+
+ }
+
+ // Check for trailing characters.
+
+ if ((c != '\0') && (!isascii(c) || !isspace(c)))return false;
+
+ // Concact the address according to
+
+ // the number of parts specified.
+
+ n = pp - parts + 1;
+
+ switch (n) {
+
+ case 0: return false; // initial nondigit
+
+ case 1: break; // a -- 32 bits
+
+ case 2: // a.b -- 8.24 bits
+
+ if(val > 0xffffff) return false;
+
+ val |= parts[0] << 24;
+
+ break;
+
+ case 3: // a.b.c -- 8.8.16 bits
+
+ if(val > 0xffff)return false;
+
+ val |= (parts[0] << 24) | (parts[1] << 16);
+
+ break;
+
+ case 4: // a.b.c.d -- 8.8.8.8 bits
+
+ if(val > 0xff)return false;
+
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+
+ break;
+
+ }
+
+ if(address)address->s_addr = htonl(val);
+
+ return true;
+
+}
+
+
+
+#else //!HAVE_INET_ATON
+
+
+
+bool kvi_stringIpToBinaryIp(const char *szIp,struct in_addr *address)
+
+{
+
+ if(!szIp)return false;
+
+ return (inet_aton(szIp,address) != 0);
+
+}
+
+
+
+#endif //!HAVE_INET_ATON
+
+
+
+#ifndef HAVE_INET_NTOA
+
+
+
+// FIXME: #warning "Your system lacks the inet_ntoa function,"
+
+// FIXME: #warning "you're trying to compile this file without"
+
+// FIXME: #warning "the config.h created by the configure script,"
+
+// FIXME: #warning "Using own internal implementation of inet_ntoa."
+
+
+
+//
+
+// Original code comes from the ircd source.
+
+//
+
+
+
+bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer)
+
+{
+
+ unsigned char *s = (unsigned char *)&in;
+
+ int a,b,c,d;
+
+ a = (int)*s++;
+
+ b = (int)*s++;
+
+ c = (int)*s++;
+
+ d = (int)*s;
+
+ szBuffer.sprintf("%d.%d.%d.%d", a,b,c,d );
+
+ return true;
+
+}
+
+
+
+#else //HAVE_INET_NTOA
+
+
+
+bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer)
+
+{
+
+// FIXME: #warning "This is NOT thread safe!"
+
+ char * ptr = inet_ntoa(in);
+
+ if(!ptr)return false;
+
+ szBuffer = ptr;
+
+ return true;
+
+}
+
+
+
+#endif //HAVE_INET_NTOA
+
+
+
+bool kvi_isValidStringIp(const char *szIp)
+
+{
+
+ struct in_addr address;
+
+ if(!szIp)return false;
+
+ if(!isdigit(*szIp))return false;
+
+ return kvi_stringIpToBinaryIp(szIp,&address);
+
+}
+
+
+
+
+
+#ifdef COMPILE_IPV6_SUPPORT
+
+
+
+#ifdef COMPILE_ON_WINDOWS
+
+
+
+//#include <stdlib.h>
+
+//#include <sys/socket.h>
+
+//#include <arpa/inet.h>/
+
+//#include <errno.h>
+
+//#include "dietfeatures.h"
+
+
+
+static unsigned int scan_ip6(const char *s,char ip[16])
+
+{
+
+ unsigned int i;
+
+ unsigned int len=0;
+
+ unsigned long u;
+
+
+
+ char suffix[16];
+
+ unsigned int prefixlen=0;
+
+ unsigned int suffixlen=0;
+
+
+
+ for (i=0; i<16; i++) ip[i]=0;
+
+
+
+ for (;;) {
+
+ if (*s == ':') {
+
+ len++;
+
+ if (s[1] == ':') { /* Found "::", skip to part 2 */
+
+ s+=2;
+
+ len++;
+
+ break;
+
+ }
+
+ s++;
+
+ }
+
+ {
+
+ char *tmp;
+
+ u=strtoul(s,&tmp,16);
+
+ i=tmp-s;
+
+ }
+
+
+
+ if (!i) return 0;
+
+ if (prefixlen==12 && s[i]=='.') {
+
+ /* the last 4 bytes may be written as IPv4 address */
+
+ if (kvi_stringIpToBinaryIp(s,(struct in_addr*)(ip+12)))
+
+ return i+len;
+
+ else
+
+ return 0;
+
+ }
+
+ ip[prefixlen++] = (u >> 8);
+
+ ip[prefixlen++] = (u & 255);
+
+ s += i; len += i;
+
+ if (prefixlen==16)
+
+ return len;
+
+ }
+
+
+
+/* part 2, after "::" */
+
+ for (;;) {
+
+ if (*s == ':') {
+
+ if (suffixlen==0)
+
+ break;
+
+ s++;
+
+ len++;
+
+ } else if (suffixlen!=0)
+
+ break;
+
+ {
+
+ char *tmp;
+
+ u=strtol(s,&tmp,16);
+
+ i=tmp-s;
+
+ }
+
+ if (!i) {
+
+ if (*s) len--;
+
+ break;
+
+ }
+
+ if (suffixlen+prefixlen<=12 && s[i]=='.') {
+
+ if (kvi_stringIpToBinaryIp(s,(struct in_addr*)(suffix+suffixlen))) {
+
+ suffixlen+=4;
+
+ len+=(unsigned int)strlen(s);
+
+ break;
+
+ } else
+
+ prefixlen=12-suffixlen; /* make end-of-loop test true */
+
+ }
+
+ suffix[suffixlen++] = (u >> 8);
+
+ suffix[suffixlen++] = (u & 255);
+
+ s += i; len += i;
+
+ if (prefixlen+suffixlen==16)
+
+ break;
+
+ }
+
+ for (i=0; i<suffixlen; i++)
+
+ ip[16-suffixlen+i] = suffix[i];
+
+ return len;
+
+}
+
+
+
+#ifndef WIN2K
+
+
+
+int inet_pton(int AF, const char *CP, void *BUF) {
+
+ int len;
+
+ if (AF==AF_INET) {
+
+ if (!kvi_stringIpToBinaryIp(CP,(struct in_addr*)BUF))
+
+ return 0;
+
+ } else if (AF==AF_INET6) {
+
+ if (CP[len=scan_ip6(CP,(char *)BUF)])
+
+ return 0;
+
+ } else {
+
+ errno=WSAEPFNOSUPPORT;
+
+ return -1;
+
+ }
+
+ return 1;
+
+}
+
+
+
+#endif //WIN2K
+
+
+
+//#include <sys/socket.h>
+
+//#include <arpa/inet.h>
+
+
+
+//extern char *inet_ntoa_r(struct in_addr in,char* buf);
+
+
+
+static const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff};
+
+
+
+static char tohex(char hexdigit) {
+
+ return hexdigit>9?hexdigit+'a'-10:hexdigit+'0';
+
+}
+
+
+
+static int fmt_xlong(char* s,unsigned int i)
+
+{
+
+ char* bak=s;
+
+ *s=tohex((i>>12)&0xf); if (s!=bak || *s!='0') ++s;
+
+ *s=tohex((i>>8)&0xf); if (s!=bak || *s!='0') ++s;
+
+ *s=tohex((i>>4)&0xf); if (s!=bak || *s!='0') ++s;
+
+ *s=tohex(i&0xf);
+
+ return s-bak+1;
+
+}
+
+
+
+static unsigned int i2a(char* dest,unsigned int x)
+
+{
+
+ register unsigned int tmp=x;
+
+ register unsigned int len=0;
+
+ if (x>=100) { *dest++=tmp/100+'0'; tmp=tmp%100; ++len; }
+
+ if (x>=10) { *dest++=tmp/10+'0'; tmp=tmp%10; ++len; }
+
+ *dest++=tmp+'0';
+
+ return len+1;
+
+}
+
+
+
+char *inet_ntoa_r(struct in_addr in,char* buf)
+
+{
+
+ unsigned int len;
+
+ unsigned char *ip=(unsigned char*)&in;
+
+ len=i2a(buf,ip[0]); buf[len]='.'; ++len;
+
+ len+=i2a(buf+ len,ip[1]); buf[len]='.'; ++len;
+
+ len+=i2a(buf+ len,ip[2]); buf[len]='.'; ++len;
+
+ len+=i2a(buf+ len,ip[3]); buf[len]=0;
+
+ return buf;
+
+}
+
+
+
+
+
+unsigned int fmt_ip6(char *s,const char ip[16])
+
+{
+
+ unsigned int len;
+
+ unsigned int i;
+
+ unsigned int temp;
+
+ unsigned int compressing; // 0 not compressing , 1 compressing now , 2 already compressed once
+
+
+
+ len = 0;
+
+ compressing = 0;
+
+
+
+ for(int j=0;j<16;j+=2)
+
+ {
+
+ if (j==12 && !memcmp(ip,V4mappedprefix,12))
+
+ {
+
+ inet_ntoa_r(*(struct in_addr*)(ip+12),s);
+
+ temp=(unsigned int)strlen(s);
+
+ return len+temp;
+
+ }
+
+ temp = ((unsigned long) (unsigned char) ip[j] << 8) + (unsigned long) (unsigned char) ip[j+1];
+
+ if(temp == 0)
+
+ {
+
+ if(compressing == 0)
+
+ {
+
+ compressing=1;
+
+ if (j==0)
+
+ {
+
+ *s++=':';
+
+ ++len;
+
+ }
+
+ }
+
+ } else {
+
+ if(compressing == 1)
+
+ {
+
+ compressing=2; // don't do it again
+
+ *s++=':'; ++len;
+
+ }
+
+ i = fmt_xlong(s,temp);
+
+ len += i;
+
+ s += i;
+
+ if (j<14)
+
+ {
+
+ *s++ = ':';
+
+ ++len;
+
+ }
+
+ }
+
+ }
+
+ if(compressing == 1)
+
+ {
+
+ *s++=':';
+
+ ++len;
+
+ }
+
+ *s=0;
+
+ return len;
+
+}
+
+
+
+const char* inet_ntop(int AF, const void *CP, char *BUF, size_t LEN)
+
+{
+
+ char buf[100];
+
+ size_t len;
+
+ if (AF==AF_INET)
+
+ {
+
+ inet_ntoa_r(*(struct in_addr*)CP,buf);
+
+ len=strlen(buf);
+
+ } else if (AF==AF_INET6)
+
+ {
+
+ len=fmt_ip6(buf,(char *)CP);
+
+ } else
+
+ return 0;
+
+ if (len<LEN)
+
+ {
+
+ strcpy(BUF,buf);
+
+ return BUF;
+
+ }
+
+ return 0;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+#endif
+
+
+
+
+
+bool kvi_stringIpToBinaryIp_V6(const char *szIp,struct in6_addr *address)
+
+{
+
+ if(!szIp)return false;
+
+ return (inet_pton(AF_INET6,szIp,(void *)address) == 1);
+
+}
+
+
+
+bool kvi_isValidStringIp_V6(const char *szIp)
+
+{
+
+ struct in6_addr address;
+
+ if(!szIp)return false;
+
+ return kvi_stringIpToBinaryIp_V6(szIp,&address);
+
+}
+
+
+
+
+
+
+
+bool kvi_binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer)
+
+{
+
+ char buf[46];
+
+ bool bRet = inet_ntop(AF_INET6,(void *)&in,buf,46);
+
+ szBuffer= buf;
+
+ return bRet;
+
+}
+
+
+
+#endif
+
+
+
+#include <errno.h>
+
+
+
+bool kvi_select(int fd,bool * bCanRead,bool * bCanWrite,int iUSecs)
+
+{
+
+ // FIXME: This stuff should DIE!
+
+ fd_set rs;
+
+ fd_set ws;
+
+ FD_ZERO(&rs);
+
+ FD_ZERO(&ws);
+
+ FD_SET(fd,&rs);
+
+ FD_SET(fd,&ws);
+
+ struct timeval tv;
+
+ tv.tv_sec = 0;
+
+ tv.tv_usec = iUSecs;
+
+ int ret = select(fd + 1,&rs,&ws,0,&tv);
+
+ if(ret < 1)return false; // EINTR or ENOSTUFFATALL
+
+ *bCanRead = FD_ISSET(fd,&rs);
+
+ *bCanWrite = FD_ISSET(fd,&ws);
+
+ return true;
+
+}
+
+
+
+namespace KviNetUtils
+
+{
+
+ bool stringIpToBinaryIp(const QString &szStringIp,struct in_addr * address)
+ {
+#ifndef HAVE_INET_ATON
+ QString szAddr = szStringIp.simplifyWhiteSpace();
+ Q_UINT32 iAddr=0;
+ QStringList ipv4 = QStringList::split(".", szAddr, FALSE);
+ if (ipv4.count() == 4) {
+ int i = 0;
+ bool ok = TRUE;
+ while(ok && i < 4) {
+ uint byteValue = ipv4[i].toUInt(&ok);
+ if ( (byteValue > 255) && ok )
+ ok = FALSE;
+ if (ok)
+ iAddr = (iAddr << 8) + byteValue;
+ ++i;
+ }
+ if (ok)
+ {
+ if(address)address->s_addr = htonl(iAddr);
+ return true;
+ }
+ }
+ return FALSE;
+#else //HAVE_INET_ATON
+ if(szStringIp.isEmpty())return false;
+ return (inet_aton(KviQString::toUtf8(szStringIp).data(),address) != 0);
+#endif //HAVE_INET_ATON
+ }
+
+
+ bool isValidStringIp(const QString &szIp)
+
+ {
+
+ struct in_addr address;
+
+ if(szIp.isEmpty())return false;
+
+ if(!szIp[0].isNumber())return false;
+
+ return stringIpToBinaryIp(szIp,&address);
+
+ }
+
+
+
+#ifdef COMPILE_IPV6_SUPPORT
+
+ bool stringIpToBinaryIp_V6(const QString &szStringIp,struct in6_addr * address)
+
+ {
+
+ return (inet_pton(AF_INET6,KviQString::toUtf8(szStringIp).data(),(void *)address) == 1);
+
+ }
+
+
+
+ bool isValidStringIp_V6(const QString &szIp)
+
+ {
+
+ struct in6_addr address;
+
+ if(szIp.isEmpty())return false;
+
+ return stringIpToBinaryIp_V6(szIp,&address);
+
+ }
+
+ bool binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer)
+ {
+ char buf[46];
+ bool bRet = inet_ntop(AF_INET6,(void *)&in,buf,46);
+ szBuffer= buf;
+ return bRet;
+ }
+
+
+#endif //COMPILE_IPV6_SUPPORT
+
+
+
+ bool binaryIpToStringIp(struct in_addr in,QString &szBuffer)
+
+ {
+
+ char * ptr = inet_ntoa(in);
+
+ if(!ptr)return false;
+
+ szBuffer = ptr;
+
+ return true;
+
+ }
+
+
+
+ bool isRoutableIpString(const QString &szIpString)
+
+ {
+
+ struct in_addr a;
+
+ if(szIpString.isEmpty())return false;
+
+ stringIpToBinaryIp(szIpString,&a);
+
+ return isRoutableIp((const char *)&a);
+
+ }
+
+
+
+ bool isRoutableIp(const char * ipaddr)
+
+ {
+
+ if(!ipaddr)return false;
+
+ const unsigned char * ip = (const unsigned char *)ipaddr;
+
+ if(ip[0] == 0)return false; // old-style broadcast
+
+ if(ip[0] == 10)return false; // Class A VPN
+
+ if(ip[0] == 127)return false; // loopback
+
+ if((ip[0] == 172) && (ip[1] >= 16) && (ip[1] <= 31))return false; // Class B VPN
+
+ if((ip[0] == 192) && (ip[1] == 168))return false; // Class C VPN
+
+ if((ip[0] == 169) && (ip[1] == 254))return false; // APIPA
+
+ if((ip[0] == 192) && (ip[1] == 0) && (ip[2] == 2))return false; // Class B VPN
+
+ if(ip[0] >= 224)return false; // class D multicast and class E reserved
+
+
+
+ return true;
+
+ }
+
+
+
+ bool getInterfaceAddress(const QString &szInterfaceName,QString &szBuffer)
+
+ {
+
+#ifdef COMPILE_GET_INTERFACE_ADDRESS
+
+ struct sockaddr *sa;
+
+ struct sockaddr_in *sin;
+
+ struct ifreq ifr;
+
+ int len = szInterfaceName.length();
+
+ if(len > (IFNAMSIZ - 1))return false; // invalid interface anyway
+
+
+
+ kvi_memmove(ifr.ifr_name,KviQString::toUtf8(szInterfaceName).data(),len + 1);
+
+
+
+ int fd = socket(AF_INET,SOCK_STREAM,0);
+
+ if(fd < 0)return false;
+
+
+
+ if(ioctl(fd,SIOCGIFADDR,&ifr) == -1)return false; // supports only IPV4 ?
+
+
+
+ close(fd);
+
+
+
+ sa = (struct sockaddr *)&(ifr.ifr_addr);
+
+
+
+ if (sa->sa_family != AF_INET) return false;
+
+ sin = (struct sockaddr_in*) sa;
+
+ return binaryIpToStringIp(sin->sin_addr,szBuffer);
+
+ // (this seems to work for AF_INET only anyway)
+
+#else //!COMPILE_GET_INTERFACE_ADDRESS
+
+ return false;
+
+#endif //!COMPILE_GET_INTERFACE_ADDRESS
+
+ }
+
+
+
+ void formatNetworkBandwidthString(QString &szBuffer,unsigned int uBytesPerSec)
+
+ {
+
+ if(uBytesPerSec > (1024 * 1024))
+
+ {
+
+ unsigned int uMB = uBytesPerSec / (1024 * 1024);
+
+ unsigned int uRem = ((uBytesPerSec % (1024 * 1024)) * 100) / (1024 * 1024);
+
+ KviQString::sprintf(szBuffer,"%u.%u%u MB/s",uMB,uRem / 10,uRem % 10);
+
+ return;
+
+ }
+
+ if(uBytesPerSec >= 1024)
+
+ {
+
+ unsigned int uKB = uBytesPerSec / 1024;
+
+ unsigned int uRem = ((uBytesPerSec % 1024) * 100) / 1024;
+
+ KviQString::sprintf(szBuffer,"%u.%u%u KB/s",uKB,uRem / 10,uRem % 10);
+
+ return;
+
+ }
+
+ KviQString::sprintf(szBuffer,"%u B/s",uBytesPerSec);
+
+ }
+
+
+
+
+
+};
+
+
+
+bool kvi_getInterfaceAddress(const char * ifname,QString &buffer)
+
+{
+
+ debug("kvi_getInterfaceAddress is deprecated: use KviNetUtils::getInterfaceAddress");
+
+ QString szRet;
+
+ bool bRes = KviNetUtils::getInterfaceAddress(QString(ifname),szRet);
+
+ buffer = szRet;
+
+ return bRes;
+
+}
+
+
+
+bool kvi_isRoutableIpString(const char * ipstring)
+
+{
+
+ struct in_addr a;
+
+ if(!ipstring)return false;
+
+ kvi_stringIpToBinaryIp(ipstring,&a);
+
+ return kvi_isRoutableIp((const char *)&a);
+
+}
+
+
+
+bool kvi_isRoutableIp(const char * ipaddr)
+
+{
+
+ if(!ipaddr)return false;
+
+ const unsigned char * ip = (const unsigned char *)ipaddr;
+
+ if(ip[0] == 0)return false; // old-style broadcast
+
+ if(ip[0] == 10)return false; // Class A VPN
+
+ if(ip[0] == 127)return false; // loopback
+
+ if((ip[0] == 172) && (ip[1] >= 16) && (ip[1] <= 31))return false; // Class B VPN
+
+ if((ip[0] == 192) && (ip[1] == 168))return false; // Class C VPN
+
+ if((ip[0] == 169) && (ip[1] == 254))return false; // APIPA
+
+ if((ip[0] == 192) && (ip[1] == 0) && (ip[2] == 2))return false; // Class B VPN
+
+ if(ip[0] >= 224)return false; // class D multicast and class E reserved
+
+
+
+ return true;
+
+}
+
+
+
+bool kvi_getLocalHostAddress(QString &buffer)
+
+{
+
+ // This will work only on windoze...
+
+ char buf[1024];
+
+ if(gethostname(buf,1024) != 0)return false;
+
+ struct hostent * h = gethostbyname(buf);
+
+ if(!h)return false;
+
+ QString tmp;
+
+ int i=0;
+
+ while(h->h_addr_list[i])
+
+ {
+
+ if(kvi_binaryIpToStringIp(*((struct in_addr *)(h->h_addr_list[i])),tmp))
+
+ {
+
+ if(kvi_isRoutableIp(h->h_addr_list[i]))
+
+ {
+
+ buffer = tmp;
+
+ return true;
+
+ }
+
+ }
+
+ i++;
+
+ }
+
+ buffer = tmp;
+
+ return true;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+KviSockaddr::KviSockaddr(const char * szIpAddress,kvi_u32_t uPort,bool bIpV6,bool bUdp)
+
+{
+ struct addrinfo hints;
+ kvi_memset((void *)&hints,0,sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+#ifdef COMPILE_IPV6_SUPPORT
+ hints.ai_family = bIpV6 ? PF_INET6 : PF_INET;
+#else
+ hints.ai_family = PF_INET;
+#endif
+
+ hints.ai_socktype = bUdp ? SOCK_DGRAM : SOCK_STREAM;
+
+ hints.ai_protocol = 0;
+ m_pData = 0;
+ KviStr szPort(KviStr::Format,"%u",uPort);
+ getaddrinfo(szIpAddress,szPort.ptr(),&hints,(struct addrinfo **)&m_pData);
+
+}
+
+
+KviSockaddr::KviSockaddr(kvi_u32_t uPort,bool bIpV6,bool bUdp) // passive sockaddr
+
+{
+ struct addrinfo hints;
+ kvi_memset((void *)&hints,0,sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
+#ifdef COMPILE_IPV6_SUPPORT
+ hints.ai_family = bIpV6 ? PF_INET6 : PF_INET;
+#else
+ hints.ai_family = PF_INET;
+#endif
+ hints.ai_socktype = bUdp ? SOCK_DGRAM : SOCK_STREAM;
+ hints.ai_protocol = 0;
+ m_pData = 0;
+ KviStr szPort(KviStr::Format,"%u",uPort);
+ getaddrinfo(0,szPort.ptr(),&hints,(struct addrinfo **)&m_pData);
+
+}
+
+
+
+KviSockaddr::~KviSockaddr()
+
+{
+
+ if(m_pData)
+
+ {
+
+ freeaddrinfo((struct addrinfo *)m_pData);
+
+ m_pData = 0;
+
+ }
+
+}
+
+
+
+struct sockaddr * KviSockaddr::socketAddress()
+
+{
+
+ if(!m_pData)return 0;
+
+ return ((struct addrinfo *)m_pData)->ai_addr;
+
+}
+
+
+
+size_t KviSockaddr::addressLength()
+
+{
+
+ if(!m_pData)return 0;
+
+ return ((struct addrinfo *)m_pData)->ai_addrlen;
+
+}
+
+
+
+int KviSockaddr::addressFamily()
+
+{
+
+ if(!m_pData)return 0;
+
+ return ((struct addrinfo *)m_pData)->ai_family;
+
+}
+
+
+
+bool KviSockaddr::isIpV6()
+
+{
+
+ if(!m_pData)return false;
+
+#ifdef COMPILE_IPV6_SUPPORT
+
+ return false;
+
+#else
+
+ return (addressFamily() == AF_INET6);
+
+#endif
+
+}
+
+
+
+kvi_u32_t KviSockaddr::port()
+
+{
+ if(!m_pData)return 0;
+#ifdef COMPILE_IPV6_SUPPORT
+ switch(((struct addrinfo *)m_pData)->ai_family)
+ {
+ case AF_INET:
+ return ntohs(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_port);
+ break;
+ case AF_INET6:
+ return ntohs(((struct sockaddr_in6 *)(((struct addrinfo *)m_pData)->ai_addr))->sin6_port);
+ break;
+ }
+ return 0;
+#else
+ return ntohs(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_port);
+#endif
+
+}
+
+
+
+bool KviSockaddr::getStringAddress(QString &szBuffer)
+
+{
+
+ if(!m_pData)return 0;
+
+#ifdef COMPILE_IPV6_SUPPORT
+
+ switch(((struct addrinfo *)m_pData)->ai_family)
+
+ {
+
+ case AF_INET:
+
+ return kvi_binaryIpToStringIp(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_addr,szBuffer);
+
+ break;
+
+ case AF_INET6:
+
+ return kvi_binaryIpToStringIp_V6(((struct sockaddr_in6 *)(((struct addrinfo *)m_pData)->ai_addr))->sin6_addr,szBuffer);
+
+ break;
+
+ }
+
+ return false;
+
+#else
+
+ return kvi_binaryIpToStringIp(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_addr,szBuffer);
+
+#endif
+
+}
+
diff --git a/src/kvilib/net/kvi_netutils.h b/src/kvilib/net/kvi_netutils.h
new file mode 100644
index 00000000..b43326f0
--- /dev/null
+++ b/src/kvilib/net/kvi_netutils.h
@@ -0,0 +1,104 @@
+#ifndef _KVI_NETUTILS_H_
+#define _KVI_NETUTILS_H_
+
+//
+// File : kvi_netutlis.h
+// Creation date : Sun Jun 18 2000 18:37:27 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2000 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 "kvi_settings.h"
+#include "kvi_inttypes.h"
+
+#ifdef COMPILE_ON_WINDOWS
+ #include <winsock2.h>
+ #ifdef COMPILE_IPV6_SUPPORT
+ #ifdef WIN2K
+ #include <ws2ip6.h>
+ #else
+ #include <ws2tcpip.h>
+ //#include <tpipv6.h>
+ #define in6_addr in_addr6
+ #endif
+ #endif
+#else
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h> //in_addr
+ #include <arpa/inet.h> //inet_ntoa inet_ntop and inet_pton depend on this one.
+#endif
+
+#include "kvi_string.h"
+
+
+KVILIB_API extern bool kvi_isValidStringIp(const char * szIp);
+KVILIB_API extern bool kvi_stringIpToBinaryIp(const char * szIp,struct in_addr * address);
+KVILIB_API extern bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer);
+
+#ifdef COMPILE_IPV6_SUPPORT
+ KVILIB_API extern bool kvi_isValidStringIp_V6(const char * szIp);
+ KVILIB_API extern bool kvi_stringIpToBinaryIp_V6(const char * szIp,struct in6_addr * address);
+ KVILIB_API extern bool kvi_binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer);
+#endif
+
+class KVILIB_API KviSockaddr
+{
+public:
+ KviSockaddr(const char * szIpAddress,kvi_u32_t uPort,bool bIpV6,bool bUdp = false);
+ KviSockaddr(kvi_u32_t uPort,bool bIpV6,bool bUdp = false); // passive
+ ~KviSockaddr();
+private:
+ void * m_pData; //addrinfo
+public:
+ struct sockaddr * socketAddress();
+ size_t addressLength();
+ int addressFamily();
+ bool isIpV6();
+ bool getStringAddress(QString &szBuffer);
+ kvi_u32_t port();
+
+};
+
+
+KVILIB_API extern bool kvi_select(int fd,bool * bCanRead,bool * bCanWrite,int iUSecs = 0);
+KVILIB_API extern bool kvi_getInterfaceAddress(const char * ifname,QString &buffer);
+
+// Warning : NOT THREAD SAFE!
+KVILIB_API extern bool kvi_getLocalHostAddress(QString &buffer);
+KVILIB_API extern bool kvi_isRoutableIp(const char * ipaddr);
+KVILIB_API extern bool kvi_isRoutableIpString(const char * ipstring);
+
+namespace KviNetUtils
+{
+ KVILIB_API bool stringIpToBinaryIp(const QString &szStringIp,struct in_addr * address);
+ KVILIB_API bool isValidStringIp(const QString &szStringIp);
+ KVILIB_API bool binaryIpToStringIp(struct in_addr in,QString &szBuffer);
+ KVILIB_API bool getInterfaceAddress(const QString &szInterfaceName,QString &szBuffer);
+#ifdef COMPILE_IPV6_SUPPORT
+ KVILIB_API bool isValidStringIp_V6(const QString &szStringIp);
+ KVILIB_API bool stringIpToBinaryIp_V6(const QString &szStringIp,struct in6_addr * address);
+ KVILIB_API bool binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer);
+#endif
+ KVILIB_API bool isRoutableIp(const char * ipaddr);
+ KVILIB_API bool isRoutableIpString(const QString &szIpString);
+ KVILIB_API void formatNetworkBandwidthString(QString &szBuffer,unsigned int uBytesPerSec);
+};
+
+
+#endif //!_KVI_NETUTILS_H_
diff --git a/src/kvilib/net/kvi_socket.cpp b/src/kvilib/net/kvi_socket.cpp
new file mode 100644
index 00000000..9bd3de9e
--- /dev/null
+++ b/src/kvilib/net/kvi_socket.cpp
@@ -0,0 +1,31 @@
+//
+// File : kvi_socket.cpp
+// Creation date : Thu Sep 20 03:50:24 2001 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001 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.
+//
+
+#define _KVI_SOCKET_CPP_
+
+#define __KVILIB__
+
+#include "kvi_socket.h"
+#include "kvi_inttypes.h"
+
+KVILIB_API kvi_u64_t g_uOutgoingTraffic;
+KVILIB_API kvi_u64_t g_uIncomingTraffic;
diff --git a/src/kvilib/net/kvi_socket.h b/src/kvilib/net/kvi_socket.h
new file mode 100644
index 00000000..47d51510
--- /dev/null
+++ b/src/kvilib/net/kvi_socket.h
@@ -0,0 +1,356 @@
+#ifndef _KVI_SOCKET_H_
+#define _KVI_SOCKET_H_
+//=============================================================================
+//
+// File : kvi_socket.h
+// Creation date : Thu Sep 20 03:50:22 2001 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001 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.
+//
+//=============================================================================
+
+//=============================================================================
+// Socket stuff abstraction layer
+//=============================================================================
+
+#include "kvi_settings.h"
+#include "kvi_sockettype.h" // <--- this includes <winsock2.h> if needed
+
+#include <errno.h>
+
+#include "kvi_inttypes.h"
+
+//#ifndef _KVI_SOCKET_CPP_
+ extern KVILIB_API kvi_u64_t g_uOutgoingTraffic;
+ extern KVILIB_API kvi_u64_t g_uIncomingTraffic;
+//#endif //!_KVI_SOCKET_CPP_
+
+
+
+#ifdef COMPILE_ON_WINDOWS
+
+ #define KVI_INVALID_SOCKET INVALID_SOCKET
+
+#else
+
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/tcp.h>
+ #include <netinet/in.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+
+ #define KVI_INVALID_SOCKET (-1)
+
+#endif
+
+#ifndef MSG_NOSIGNAL
+ // At least solaris seems to not have it
+ #define MSG_NOSIGNAL 0
+#endif
+
+//#include "kvi_socketcalls.h"
+
+
+//================================================================================================
+// Constants for kvi_socket_create
+//
+
+#define KVI_SOCKET_PF_INET PF_INET
+#define KVI_SOCKET_PF_INET6 PF_INET6
+#define KVI_SOCKET_PF_UNIX PF_UNIX
+
+#define KVI_SOCKET_TYPE_STREAM SOCK_STREAM
+#define KVI_SOCKET_TYPE_DGRAM SOCK_DGRAM
+
+#define KVI_SOCKET_PROTO_TCP 0
+
+//================================================================================================
+// kvi_socket_create
+// kvi_socket_open
+//
+// Open a socket of the specified protocol family , type and protocol
+// You should always use the KVI_SOCKET_* constants as parameters
+// Returns KVI_INVALID_SOCKET if the socket creation has failed.
+// The returned socket is in blocking mode!
+//
+
+#define kvi_socket_open kvi_socket_create
+
+inline kvi_socket_t kvi_socket_create(int pf,int type,int proto)
+{
+ return (kvi_socket_t)socket(pf,type,proto);
+};
+
+//================================================================================================
+// kvi_socket_isValid
+//
+// Check if a socket is valid or not
+//
+
+inline void kvi_socket_flushTrafficCounters()
+{
+ g_uOutgoingTraffic = 0;
+ g_uIncomingTraffic = 0;
+}
+
+inline bool kvi_socket_isValid(kvi_socket_t sock)
+{
+ return (sock != ((kvi_socket_t)(KVI_INVALID_SOCKET)));
+}
+
+//================================================================================================
+// kvi_socket_destroy
+// kvi_socket_close
+//
+// Close a socket...that's all :)
+//
+
+#define kvi_socket_close kvi_socket_destroy
+
+inline void kvi_socket_destroy(kvi_socket_t sock)
+{
+#ifdef COMPILE_ON_WINDOWS
+ closesocket(sock);
+#else
+ close(sock);
+#endif
+};
+
+//================================================================================================
+// kvi_socket_setNonBlocking
+//
+// Sets the socket in nonBlocking mode. Obviously returns false in case of failure
+//
+
+inline bool kvi_socket_setNonBlocking(kvi_socket_t sock)
+{
+#ifdef COMPILE_ON_WINDOWS
+ unsigned long arg = 1;
+ return (ioctlsocket(sock,FIONBIO,(unsigned long FAR *)&arg) == 0);
+#else
+ return (fcntl(sock,F_SETFL,O_NONBLOCK) == 0);
+#endif
+};
+
+//================================================================================================
+// kvi_socket_bind
+//
+// Standard bind() call on the socket. Returns false in case of failure
+//
+
+inline bool kvi_socket_bind(kvi_socket_t sock,const struct sockaddr * sa,int salen)
+{
+ return (::bind(sock,sa,salen) == 0);
+};
+
+//================================================================================================
+// kvi_socket_connect
+//
+// Starts a connection to the specified remote address
+// returns false if the connection can not be started.
+// You might take a look at kvi_socket_errno() then.
+//
+
+inline bool kvi_socket_connect(kvi_socket_t sock,const struct sockaddr *sa,int salen)
+{
+#ifdef COMPILE_ON_WINDOWS
+ return (WSAConnect(sock,sa,salen,0,0,0,0) == 0);
+#else
+ return (::connect(sock,sa,salen) == 0);
+#endif
+};
+
+inline bool kvi_socket_recoverableConnectError(int err)
+{
+#ifdef COMPILE_ON_WINDOWS
+ return ((err == WSAEINPROGRESS) || (err == WSAEWOULDBLOCK));
+#else
+ return (err == EINPROGRESS);
+#endif
+};
+
+inline bool kvi_socket_recoverableError(int err)
+{
+#ifdef COMPILE_ON_WINDOWS
+ return ((err == WSAEWOULDBLOCK) || (err == EINTR) || (err == EAGAIN));
+#else
+ return ((err == EINTR) || (err = EAGAIN));
+#endif
+}
+
+//================================================================================================
+// kvi_socket_accept
+//
+// Standard accept() call. Returns KVI_INVALID_SOCKET in case of failure
+// You should check kvi_socket_errno() then.
+//
+
+inline kvi_socket_t kvi_socket_accept(kvi_socket_t sock,struct sockaddr *sa,int * salen)
+{
+#ifdef COMPILE_ON_WINDOWS
+ return (kvi_socket_t)::accept(sock,sa,salen);
+#else
+ return (kvi_socket_t)::accept(sock,sa,(socklen_t *)salen);
+#endif
+};
+
+//================================================================================================
+// kvi_socket_listen
+//
+// Standard listen() call. Returns false in case of failure
+// You should check kvi_socket_errno() then.
+//
+
+inline bool kvi_socket_listen(kvi_socket_t sock,int backlog)
+{
+ return (::listen(sock,backlog) == 0);
+};
+
+//================================================================================================
+// kvi_socket_select
+//
+// Standard select() call. This is complex so here is a mini-reminder:
+// nhpo is the number of the highest file descriptor in the sets plus one!
+// Returns the number of sockets with data available (or space available)
+// or something that is less than 0 in case of error. You should check kvi_socket_errno() then.
+//
+
+inline int kvi_socket_select(int nhpo,fd_set *r,fd_set *w,fd_set *e,struct timeval * t)
+{
+ return ::select(nhpo,r,w,e,t);
+};
+
+//================================================================================================
+// kvi_socket_send
+// kvi_socket_write
+//
+// Standard send() call. On UNIX ignores SIGPIPE. Returns the number of bytes sent or
+// -1 in case of failure. You should check kvi_socket_errno() then.
+//
+
+#define kvi_socket_write kvi_socket_send
+
+inline int kvi_socket_send(kvi_socket_t sock,const void * buf,int size)
+{
+ g_uOutgoingTraffic+=size;
+#ifdef COMPILE_ON_WINDOWS
+ return ::send(sock,(const char *)buf,size,0);
+#else
+ return ::send(sock,buf,size,MSG_NOSIGNAL | MSG_DONTWAIT);
+#endif
+};
+
+//================================================================================================
+// kvi_socket_recv
+// kvi_socket_read
+//
+// Standard read() call. On UNIX ignores SIGPIPE. Returns the number of bytes readed or
+// -1 in case of failure. You should check kvi_socket_errno() then.
+//
+
+#define kvi_socket_read kvi_socket_recv
+
+inline int kvi_socket_recv(kvi_socket_t sock,void * buf,int maxlen)
+{
+ int iReceived;
+#ifdef COMPILE_ON_WINDOWS
+ iReceived = ::recv(sock,(char *)buf,maxlen,0);
+#else
+ iReceived = ::recv(sock,buf,maxlen,MSG_NOSIGNAL);
+#endif
+ g_uIncomingTraffic+=iReceived;
+ return iReceived;
+};
+
+//================================================================================================
+// kvi_socket_getsockopt
+//
+// Standard getsockopt() call. Returns false in case of failure.
+// You should check kvi_socket_errno() then.
+//
+
+inline bool kvi_socket_getsockopt(kvi_socket_t sock,int level,int optname,void *optval,int *optlen)
+{
+#ifdef COMPILE_ON_WINDOWS
+ return (::getsockopt(sock,level,optname,(char FAR *)optval,optlen) == 0);
+#else
+ return (::getsockopt(sock,level,optname,optval,(socklen_t *)optlen) == 0);
+#endif
+}
+
+//================================================================================================
+// kvi_socket_setsockopt
+//
+// Standard setsockopt() call. Returns false in case of failure.
+// You should check kvi_socket_errno() then.
+//
+
+inline bool kvi_socket_setsockopt(kvi_socket_t sock,int level,int optname,const void *optval,int optlen)
+{
+#ifdef COMPILE_ON_WINDOWS
+ return (::setsockopt(sock,level,optname,(char FAR *)optval,optlen) == 0);
+#else
+ return (::setsockopt(sock,level,optname,optval,optlen) == 0);
+#endif
+}
+
+
+//================================================================================================
+// kvi_socket_disableNagle
+//
+// Disables the nagle algorithm (sets TCP_NODELAY)
+//
+
+/*
+ unused for now
+inline bool kvi_socket_disableNagle(kvi_socket_t sock)
+{
+ int opt = 1;
+ return kvi_socket_setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&opt,sizeof(opt));
+};
+*/
+
+//================================================================================================
+// kvi_socket_getsockname
+//
+// Standard getsockname() call. Returns false in case of failure.
+// You should check kvi_socket_errno() then.
+//
+
+inline bool kvi_socket_getsockname(kvi_socket_t sock,struct sockaddr * addr,int * addrlen)
+{
+#ifdef COMPILE_ON_WINDOWS
+ return (::getsockname(sock,addr,addrlen) == 0);
+#else
+ return (::getsockname(sock,addr,(socklen_t *)addrlen) == 0);
+#endif
+}
+
+inline int kvi_socket_error()
+{
+#ifdef COMPILE_ON_WINDOWS
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+
+#endif //_KVI_SOCKET_H_
diff --git a/src/kvilib/net/kvi_sockettype.h b/src/kvilib/net/kvi_sockettype.h
new file mode 100644
index 00000000..c8a45743
--- /dev/null
+++ b/src/kvilib/net/kvi_sockettype.h
@@ -0,0 +1,45 @@
+#ifndef _KVI_SOCKETTYPE_H_
+#define _KVI_SOCKETTYPE_H_
+//=============================================================================
+//
+// File : kvi_sockettype.h
+// Creation date : Thu Sep 20 05:41:46 2001 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001 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.
+//
+//=============================================================================
+
+//=============================================================================
+// Socket stuff abstraction layer
+//=============================================================================
+
+#include "kvi_settings.h"
+
+#ifdef COMPILE_ON_WINDOWS
+
+ #include <winsock2.h>
+
+ typedef SOCKET kvi_socket_t;
+
+#else
+
+ typedef int kvi_socket_t;
+
+#endif
+
+#endif //_KVI_SOCKETTYPE_H_
diff --git a/src/kvilib/net/kvi_ssl.cpp b/src/kvilib/net/kvi_ssl.cpp
new file mode 100644
index 00000000..6748e062
--- /dev/null
+++ b/src/kvilib/net/kvi_ssl.cpp
@@ -0,0 +1,687 @@
+//=============================================================================
+//
+// File : kvi_ssl.cpp
+// Creation date : Mon May 27 2002 21:36:12 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002-2004 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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#include "kvi_ssl.h"
+#include "kvi_locale.h"
+
+#ifdef COMPILE_SSL_SUPPORT
+
+#include "kvi_thread.h"
+#include "kvi_memmove.h"
+#include "kvi_malloc.h"
+
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/dh.h>
+
+#include <stdio.h>
+
+static bool g_bSSLInitialized = false;
+static KviMutex * g_pSSLMutex = 0;
+
+
+static inline void my_ssl_lock()
+{
+ g_pSSLMutex->lock();
+}
+
+static inline void my_ssl_unlock()
+{
+ g_pSSLMutex->unlock();
+}
+
+
+// THIS PART OF OpenSSL SUCKS
+
+static DH * dh_512 = 0;
+static DH * dh_1024 = 0;
+static DH * dh_2048 = 0;
+static DH * dh_4096 = 0;
+
+static unsigned char dh512_p[]={
+ 0x90,0x86,0xDD,0x06,0xE8,0x0F,0x10,0x86,0xF0,0x91,0xC5,0x55,
+ 0x4D,0x6B,0xAF,0x69,0x4F,0x01,0xED,0xF9,0x57,0x8F,0x3B,0xB8,
+ 0x9C,0x87,0xAE,0x85,0xC1,0xBF,0x57,0xA5,0xD5,0xBA,0x81,0x24,
+ 0xE7,0x99,0xE3,0xF6,0xCD,0xB4,0x41,0xB7,0x7F,0x6E,0x7B,0xB1,
+ 0xD2,0xF3,0xE9,0x0F,0xB9,0x0E,0x4D,0xEB,0x9D,0xD4,0xA9,0xE5,
+ 0x03,0x67,0xA7,0x27
+};
+static unsigned char dh512_g[]={ 0x05 };
+
+static unsigned char dh1024_p[]={
+ 0xA5,0x4C,0xB9,0xB9,0xC4,0x35,0x88,0x68,0x9B,0x79,0x48,0x6C,
+ 0x21,0xA7,0x8E,0xE2,0x9C,0xAF,0x2F,0x04,0xBF,0x45,0xBC,0xF5,
+ 0xAB,0x35,0x86,0xC8,0xBB,0x9B,0x75,0x18,0x7C,0x9B,0xAB,0xE8,
+ 0x52,0x7F,0x57,0x3E,0xD8,0x65,0x7D,0x2B,0xE1,0x6D,0x3D,0xA5,
+ 0x32,0xE8,0xA0,0x2B,0x7A,0x58,0x6B,0x47,0x16,0x4E,0xB1,0xFC,
+ 0x09,0xB7,0x7C,0xC6,0xE9,0x6E,0xC7,0xC7,0xA1,0x42,0x0F,0x4B,
+ 0x43,0xFB,0x58,0xBA,0xC7,0x66,0xD6,0xCA,0x6B,0xC7,0x45,0x7C,
+ 0x99,0xE4,0x46,0x02,0x93,0x3F,0x28,0xD2,0xCE,0x0C,0x8A,0xDD,
+ 0x6A,0x22,0x2E,0xA9,0x9A,0xCA,0x16,0x48,0x4E,0x67,0x4C,0xE9,
+ 0xC8,0x54,0xCD,0x18,0xC9,0xF3,0x30,0x3A,0x74,0xAB,0xF9,0xAF,
+ 0xE4,0xA4,0x0D,0x56,0x62,0x28,0x07,0xBF
+};
+static unsigned char dh1024_g[]={ 0x05 };
+
+static unsigned char dh2048_p[]={
+ 0xBF,0x67,0x7B,0x79,0xA5,0x22,0xD3,0xB5,0x0C,0x13,0xE6,0x92,
+ 0x54,0xFD,0x64,0xBF,0x57,0x25,0xBD,0x02,0x7C,0xFD,0x72,0x97,
+ 0x82,0xA4,0xA6,0x0A,0xB9,0xE6,0x4B,0xFA,0xBD,0xFA,0x71,0x8A,
+ 0x2E,0x36,0xF9,0x03,0x58,0x1B,0xB6,0x3A,0xFD,0x15,0xCC,0x87,
+ 0x5D,0x04,0xF7,0x45,0xE0,0xE2,0x34,0x7F,0x54,0x5F,0x5D,0x14,
+ 0xD3,0xCA,0x3E,0xFD,0x2A,0x92,0x10,0x89,0xA0,0xB0,0xB4,0xE5,
+ 0x80,0x05,0x13,0xBE,0xA3,0xD0,0x42,0x4B,0x98,0x44,0x54,0xB3,
+ 0xE0,0x23,0x26,0xF5,0x6B,0x0E,0x4D,0x2A,0x81,0xB2,0x8A,0x06,
+ 0xC8,0x00,0x9E,0xAB,0x1B,0x77,0xDC,0x87,0x9C,0x6C,0xD5,0xEE,
+ 0xB4,0xB4,0xDD,0xDA,0x3F,0x40,0xA3,0xFA,0xC1,0x1E,0xC0,0xA2,
+ 0x9E,0xB8,0xAC,0x31,0xE8,0x12,0x93,0x9C,0x71,0xF6,0xE7,0xF0,
+ 0x65,0x7F,0xA5,0x20,0xF7,0x49,0x3D,0xD6,0xF9,0xD3,0xF0,0x3F,
+ 0xB3,0xF0,0xD0,0x23,0x22,0x82,0xA5,0xDD,0xFB,0xD9,0x9C,0x7D,
+ 0xE7,0xA0,0x78,0xE8,0xF9,0x02,0x0C,0x2F,0x1D,0x52,0xC7,0x61,
+ 0xED,0xA0,0xC9,0x06,0x14,0xDF,0xE7,0xB1,0x1E,0x50,0x98,0x4F,
+ 0x10,0xB9,0x87,0x4C,0x1C,0x9C,0xB3,0xD2,0x98,0x23,0x7C,0x47,
+ 0xD2,0x3C,0xC5,0x29,0x65,0xC5,0x67,0x4E,0xC0,0x76,0x0F,0x43,
+ 0x27,0x28,0x89,0x69,0x30,0x7D,0x04,0xFD,0xF7,0x89,0xE5,0xD6,
+ 0xE6,0x97,0x7D,0xBB,0x54,0x5F,0xB7,0x94,0x1D,0xBC,0x82,0xAB,
+ 0x9A,0xF5,0x0A,0x0C,0x89,0x68,0xE7,0x0A,0x8C,0x2D,0x0D,0x82,
+ 0x44,0xA7,0xB8,0xF9,0x0B,0x8E,0xCB,0xA4,0x6A,0xA7,0xEC,0x5F,
+ 0x0A,0xF8,0x5F,0xE7
+};
+static unsigned char dh2048_g[]={ 0x05 };
+
+static unsigned char dh4096_p[]={
+ 0xFA,0x14,0x72,0x52,0xC1,0x4D,0xE1,0x5A,0x49,0xD4,0xEF,0x09,
+ 0x2D,0xC0,0xA8,0xFD,0x55,0xAB,0xD7,0xD9,0x37,0x04,0x28,0x09,
+ 0xE2,0xE9,0x3E,0x77,0xE2,0xA1,0x7A,0x18,0xDD,0x46,0xA3,0x43,
+ 0x37,0x23,0x90,0x97,0xF3,0x0E,0xC9,0x03,0x50,0x7D,0x65,0xCF,
+ 0x78,0x62,0xA6,0x3A,0x62,0x22,0x83,0xA1,0x2F,0xFE,0x79,0xBA,
+ 0x35,0xFF,0x59,0xD8,0x1D,0x61,0xDD,0x1E,0x21,0x13,0x17,0xFE,
+ 0xCD,0x38,0x87,0x9E,0xF5,0x4F,0x79,0x10,0x61,0x8D,0xD4,0x22,
+ 0xF3,0x5A,0xED,0x5D,0xEA,0x21,0xE9,0x33,0x6B,0x48,0x12,0x0A,
+ 0x20,0x77,0xD4,0x25,0x60,0x61,0xDE,0xF6,0xB4,0x4F,0x1C,0x63,
+ 0x40,0x8B,0x3A,0x21,0x93,0x8B,0x79,0x53,0x51,0x2C,0xCA,0xB3,
+ 0x7B,0x29,0x56,0xA8,0xC7,0xF8,0xF4,0x7B,0x08,0x5E,0xA6,0xDC,
+ 0xA2,0x45,0x12,0x56,0xDD,0x41,0x92,0xF2,0xDD,0x5B,0x8F,0x23,
+ 0xF0,0xF3,0xEF,0xE4,0x3B,0x0A,0x44,0xDD,0xED,0x96,0x84,0xF1,
+ 0xA8,0x32,0x46,0xA3,0xDB,0x4A,0xBE,0x3D,0x45,0xBA,0x4E,0xF8,
+ 0x03,0xE5,0xDD,0x6B,0x59,0x0D,0x84,0x1E,0xCA,0x16,0x5A,0x8C,
+ 0xC8,0xDF,0x7C,0x54,0x44,0xC4,0x27,0xA7,0x3B,0x2A,0x97,0xCE,
+ 0xA3,0x7D,0x26,0x9C,0xAD,0xF4,0xC2,0xAC,0x37,0x4B,0xC3,0xAD,
+ 0x68,0x84,0x7F,0x99,0xA6,0x17,0xEF,0x6B,0x46,0x3A,0x7A,0x36,
+ 0x7A,0x11,0x43,0x92,0xAD,0xE9,0x9C,0xFB,0x44,0x6C,0x3D,0x82,
+ 0x49,0xCC,0x5C,0x6A,0x52,0x42,0xF8,0x42,0xFB,0x44,0xF9,0x39,
+ 0x73,0xFB,0x60,0x79,0x3B,0xC2,0x9E,0x0B,0xDC,0xD4,0xA6,0x67,
+ 0xF7,0x66,0x3F,0xFC,0x42,0x3B,0x1B,0xDB,0x4F,0x66,0xDC,0xA5,
+ 0x8F,0x66,0xF9,0xEA,0xC1,0xED,0x31,0xFB,0x48,0xA1,0x82,0x7D,
+ 0xF8,0xE0,0xCC,0xB1,0xC7,0x03,0xE4,0xF8,0xB3,0xFE,0xB7,0xA3,
+ 0x13,0x73,0xA6,0x7B,0xC1,0x0E,0x39,0xC7,0x94,0x48,0x26,0x00,
+ 0x85,0x79,0xFC,0x6F,0x7A,0xAF,0xC5,0x52,0x35,0x75,0xD7,0x75,
+ 0xA4,0x40,0xFA,0x14,0x74,0x61,0x16,0xF2,0xEB,0x67,0x11,0x6F,
+ 0x04,0x43,0x3D,0x11,0x14,0x4C,0xA7,0x94,0x2A,0x39,0xA1,0xC9,
+ 0x90,0xCF,0x83,0xC6,0xFF,0x02,0x8F,0xA3,0x2A,0xAC,0x26,0xDF,
+ 0x0B,0x8B,0xBE,0x64,0x4A,0xF1,0xA1,0xDC,0xEE,0xBA,0xC8,0x03,
+ 0x82,0xF6,0x62,0x2C,0x5D,0xB6,0xBB,0x13,0x19,0x6E,0x86,0xC5,
+ 0x5B,0x2B,0x5E,0x3A,0xF3,0xB3,0x28,0x6B,0x70,0x71,0x3A,0x8E,
+ 0xFF,0x5C,0x15,0xE6,0x02,0xA4,0xCE,0xED,0x59,0x56,0xCC,0x15,
+ 0x51,0x07,0x79,0x1A,0x0F,0x25,0x26,0x27,0x30,0xA9,0x15,0xB2,
+ 0xC8,0xD4,0x5C,0xCC,0x30,0xE8,0x1B,0xD8,0xD5,0x0F,0x19,0xA8,
+ 0x80,0xA4,0xC7,0x01,0xAA,0x8B,0xBA,0x53,0xBB,0x47,0xC2,0x1F,
+ 0x6B,0x54,0xB0,0x17,0x60,0xED,0x79,0x21,0x95,0xB6,0x05,0x84,
+ 0x37,0xC8,0x03,0xA4,0xDD,0xD1,0x06,0x69,0x8F,0x4C,0x39,0xE0,
+ 0xC8,0x5D,0x83,0x1D,0xBE,0x6A,0x9A,0x99,0xF3,0x9F,0x0B,0x45,
+ 0x29,0xD4,0xCB,0x29,0x66,0xEE,0x1E,0x7E,0x3D,0xD7,0x13,0x4E,
+ 0xDB,0x90,0x90,0x58,0xCB,0x5E,0x9B,0xCD,0x2E,0x2B,0x0F,0xA9,
+ 0x4E,0x78,0xAC,0x05,0x11,0x7F,0xE3,0x9E,0x27,0xD4,0x99,0xE1,
+ 0xB9,0xBD,0x78,0xE1,0x84,0x41,0xA0,0xDF
+};
+static unsigned char dh4096_g[]={ 0x02 };
+
+static DH * my_get_dh(int keylength)
+{
+ DH * dh = 0;
+ unsigned char * p = 0;
+ unsigned char * g = 0;
+ int sp = 0;
+ int sg = 0;
+ switch(keylength)
+ {
+ case 512:
+ dh = dh_512;
+ p = dh512_p;
+ g = dh512_g;
+ sp = sizeof(dh512_p);
+ sg = sizeof(dh512_g);
+ break;
+ case 1024:
+ dh = dh_1024;
+ p = dh1024_p;
+ g = dh1024_g;
+ sp = sizeof(dh1024_p);
+ sg = sizeof(dh1024_g);
+ break;
+ case 2048:
+ dh = dh_2048;
+ p = dh2048_p;
+ g = dh2048_g;
+ sp = sizeof(dh2048_p);
+ sg = sizeof(dh2048_g);
+ break;
+ case 4096:
+ dh = dh_4096;
+ p = dh4096_p;
+ g = dh4096_g;
+ sp = sizeof(dh4096_p);
+ sg = sizeof(dh4096_g);
+ break;
+ default:
+ // What the hell do you want from me ?
+ debug("OpenSSL is asking for a DH param with keylen %d: no way :D",keylength);
+ break;
+
+ }
+
+ if(dh)return dh;
+ dh = DH_new();
+ if(!dh)return 0;
+ dh->p=BN_bin2bn(p,sp,0);
+ dh->g=BN_bin2bn(g,sg,0);
+ if((dh->p == 0) || (dh->g == 0))
+ {
+ DH_free(dh);
+ return 0;
+ }
+ return dh;
+}
+
+DH * my_ugly_dh_callback(SSL *s, int is_export, int keylength)
+{
+ my_ssl_lock();
+ DH *dh = my_get_dh(keylength);
+ my_ssl_unlock();
+ return dh;
+}
+
+void KviSSL::globalInit()
+{
+ if(g_pSSLMutex)return;
+ g_pSSLMutex = new KviMutex();
+}
+
+void KviSSL::globalDestroy()
+{
+ if(!g_pSSLMutex)return;
+ if(dh_512)DH_free(dh_512);
+ if(dh_1024)DH_free(dh_1024);
+ if(dh_2048)DH_free(dh_2048);
+ if(dh_4096)DH_free(dh_4096);
+ delete g_pSSLMutex;
+ g_pSSLMutex = 0;
+}
+
+KviSSL::KviSSL()
+{
+ my_ssl_lock();
+ if(!g_bSSLInitialized)
+ {
+ // FIXME: this should be done only if SSL is really needed
+ SSL_library_init();
+ SSL_load_error_strings();
+ g_bSSLInitialized = true;
+ }
+ my_ssl_unlock();
+ m_pSSL = 0;
+ m_pSSLCtx = 0;
+}
+
+KviSSL::~KviSSL()
+{
+ shutdown();
+}
+
+#ifdef COMPILE_ON_WINDOWS
+
+ // On windows we need to override new and delete operators
+ // to ensure that always the right new/delete pair is called for an object instance
+ // This bug is present in all the classes exported by a module that
+ // can be instantiated/destroyed from external modules.
+ // (this is a well known bug described in Q122675 of MSDN)
+
+ void * KviSSL::operator new(size_t tSize)
+ {
+ return kvi_malloc(tSize);
+ }
+
+ void KviSSL::operator delete(void * p)
+ {
+ kvi_free(p);
+ }
+
+#endif
+
+void KviSSL::shutdown()
+{
+ if(m_pSSL)
+ {
+ // At least attempt to shutdown the connection gracefully
+ SSL_shutdown(m_pSSL);
+ SSL_free(m_pSSL);
+ m_pSSL = 0;
+ }
+ if(m_pSSLCtx)
+ {
+ SSL_CTX_free(m_pSSLCtx);
+ m_pSSLCtx = 0;
+ }
+}
+
+
+bool KviSSL::initContext(Method m)
+{
+ if(m_pSSL)return false;
+ m_pSSLCtx = SSL_CTX_new(m == Client ? SSLv23_client_method() : SSLv23_server_method());
+ if(!m_pSSLCtx)return false;
+ // FIXME: this should be configurable ?
+ SSL_CTX_set_cipher_list(m_pSSLCtx,"ALL:eNULL");
+ SSL_CTX_set_tmp_dh_callback(m_pSSLCtx,my_ugly_dh_callback);
+ return true;
+}
+
+bool KviSSL::initSocket(kvi_socket_t fd)
+{
+ if(!m_pSSLCtx)return false;
+ m_pSSL = SSL_new(m_pSSLCtx);
+ if(!m_pSSL)return false;
+ if(!SSL_set_fd(m_pSSL,fd))return false;
+ return true;
+
+}
+
+static int cb(char *buf, int size, int rwflag, void *u)
+{
+ KviStr * p = (KviStr *)u;
+ int len = p->len();
+ if(len >= size)return 0;
+ kvi_memmove(buf,p->ptr(),len + 1);
+// debug("PASS REQYESTED: %s",p->ptr());
+ return len;
+}
+
+KviSSL::Result KviSSL::useCertificateFile(const char * cert,const char * pass)
+{
+ if(!m_pSSLCtx)return NotInitialized;
+ m_szPass = pass;
+ if(m_szPass.len() < 4)m_szPass.append("xxxx");
+ X509 * x509 = 0;
+
+ FILE * f = fopen(cert,"r");
+ if(!f)return FileIoError;
+
+// debug("READING CERTIFICATE %s",cert);
+ if(PEM_read_X509(f,&x509,cb,&m_szPass))
+ {
+ if(!SSL_CTX_use_certificate(m_pSSLCtx,x509))
+ {
+ X509_free(x509);
+ return SSLError;
+ }
+ }
+
+ fclose(f);
+ return Success;
+}
+
+
+KviSSL::Result KviSSL::usePrivateKeyFile(const char * key,const char * pass)
+{
+ if(!m_pSSLCtx)return NotInitialized;
+ m_szPass = pass;
+ if(m_szPass.len() < 4)m_szPass.append("xxxx");
+
+ EVP_PKEY * k = 0;
+
+ FILE * f = fopen(key,"r");
+ if(!f)return FileIoError;
+
+// debug("READING KEY %s",key);
+ if(PEM_read_PrivateKey(f,&k,cb,&m_szPass))
+ {
+ if(!SSL_CTX_use_PrivateKey(m_pSSLCtx,k))
+ {
+ EVP_PKEY_free(k);
+ return SSLError;
+ }
+ }
+
+ fclose(f);
+ return Success;
+}
+
+unsigned long KviSSL::getLastError(bool bPeek)
+{
+ return bPeek ? ERR_peek_error() : ERR_get_error();
+}
+
+bool KviSSL::getLastErrorString(KviStr &buffer,bool bPeek)
+{
+ unsigned long uErr = getLastError(bPeek);
+ if(uErr != 0)
+ {
+ const char * err = ERR_reason_error_string(uErr);
+ buffer = err ? err : "Unknown error";
+ return true;
+ }
+ return false;
+}
+
+KviSSL::Result KviSSL::connect()
+{
+ if(!m_pSSL)return NotInitialized;
+ int ret = SSL_connect(m_pSSL);
+ return connectOrAcceptError(ret);
+}
+
+KviSSL::Result KviSSL::accept()
+{
+ if(!m_pSSL)return NotInitialized;
+ int ret = SSL_accept(m_pSSL);
+ return connectOrAcceptError(ret);
+}
+
+KviSSL::Result KviSSL::connectOrAcceptError(int ret)
+{
+ switch(SSL_get_error(m_pSSL,ret))
+ {
+ case SSL_ERROR_NONE: return Success; break;
+ case SSL_ERROR_WANT_READ: return WantRead; break;
+ case SSL_ERROR_WANT_WRITE: return WantWrite; break;
+ case SSL_ERROR_ZERO_RETURN: return RemoteEndClosedConnection; break;
+ case SSL_ERROR_WANT_X509_LOOKUP: return ObscureError; break;
+ case SSL_ERROR_SYSCALL:
+ {
+ if(getLastError(true) != 0)return SSLError;
+ if(ret == 0)return RemoteEndClosedConnection;
+ return SyscallError;
+ }
+ break;
+ case SSL_ERROR_SSL: return SSLError; break;
+ default: return UnknownError; break;
+ }
+ return UnknownError;
+}
+
+int KviSSL::read(char * buffer,int len)
+{
+// if(!m_pSSL)return -1;
+ return SSL_read(m_pSSL,buffer,len);
+}
+int KviSSL::write(const char * buffer,int len)
+{
+// if(!m_pSSL)return -1;
+ return SSL_write(m_pSSL,buffer,len);
+}
+
+KviSSL::Result KviSSL::getProtocolError(int ret)
+{
+ if(!m_pSSL)return NotInitialized;
+ switch(SSL_get_error(m_pSSL,ret))
+ {
+ case SSL_ERROR_NONE: return Success; break;
+ case SSL_ERROR_WANT_READ: return WantRead; break;
+ case SSL_ERROR_WANT_WRITE: return WantWrite; break;
+ case SSL_ERROR_ZERO_RETURN: return ZeroReturn; break;
+ case SSL_ERROR_WANT_X509_LOOKUP: return ObscureError; break;
+ case SSL_ERROR_SYSCALL: return SyscallError; break;
+ case SSL_ERROR_SSL: return SSLError; break;
+ default: return UnknownError; break;
+ }
+ return UnknownError;
+}
+
+KviSSLCertificate * KviSSL::getPeerCertificate()
+{
+ if(!m_pSSL)return 0;
+ X509 * x509 = SSL_get_peer_certificate(m_pSSL);
+ if(!x509)return 0;
+ return new KviSSLCertificate(x509);
+}
+
+KviSSLCipherInfo * KviSSL::getCurrentCipherInfo()
+{
+ if(!m_pSSL)return 0;
+ SSL_CIPHER * c = SSL_get_current_cipher(m_pSSL);
+ if(!c)return 0;
+ return new KviSSLCipherInfo(c);
+}
+
+
+
+KviSSLCertificate::KviSSLCertificate(X509 * x509)
+{
+ m_pSubject = new KviPointerHashTable<const char *,KviStr>(17);
+ m_pSubject->setAutoDelete(true);
+ m_pIssuer = new KviPointerHashTable<const char *,KviStr>(17);
+ m_pIssuer->setAutoDelete(true);
+ m_pX509 = 0;
+ setX509(x509);
+}
+
+KviSSLCertificate::~KviSSLCertificate()
+{
+ X509_free(m_pX509);
+ delete m_pSubject;
+ delete m_pIssuer;
+}
+
+#ifdef COMPILE_ON_WINDOWS
+
+ // On windows we need to override new and delete operators
+ // to ensure that always the right new/delete pair is called for an object instance
+ // This bug is present in all the classes exported by a module that
+ // can be instantiated/destroyed from external modules.
+ // (this is a well known bug described in Q122675 of MSDN)
+
+ void * KviSSLCertificate::operator new(size_t tSize)
+ {
+ return kvi_malloc(tSize);
+ }
+
+ void KviSSLCertificate::operator delete(void * p)
+ {
+ kvi_free(p);
+ }
+
+#endif
+
+void KviSSLCertificate::setX509(X509 * x509)
+{
+ if(m_pX509)X509_free(m_pX509);
+ m_pX509 = x509;
+ m_iVersion = X509_get_version(x509);
+ extractSubject();
+ extractIssuer();
+ extractPubKeyInfo();
+ extractSerialNumber();
+ extractSignature();
+}
+
+void KviSSLCertificate::extractSubject()
+{
+ char buffer[1024];
+ char * t = X509_NAME_oneline(X509_get_subject_name(m_pX509),buffer,1024);
+ if (!t)return;
+ m_pSubject->clear();
+ splitX509String(m_pSubject,t);
+}
+
+void KviSSLCertificate::extractIssuer()
+{
+ char buffer[1024];
+ char * t = X509_NAME_oneline(X509_get_issuer_name(m_pX509),buffer,1024);
+ if (!t)return;
+ m_pIssuer->clear();
+ splitX509String(m_pIssuer,t);
+}
+
+void KviSSLCertificate::splitX509String(KviPointerHashTable<const char *,KviStr> * dict,const char * t)
+{
+ KviStr buf = t;
+ int cnt;
+ KviStr ** arr = buf.splitToArray('/',50,&cnt);
+ if(arr)
+ {
+ if(cnt > 0)
+ {
+ for(int i=0;i<cnt;i++)
+ {
+ int idx = arr[i]->findFirstIdx('=');
+ if(idx != -1)
+ {
+ KviStr szTok = arr[i]->left(idx);
+ arr[i]->cutLeft(idx + 1);
+ if(szTok.hasData() && arr[i]->hasData())
+ {
+ dict->replace(szTok.ptr(),new KviStr(arr[i]->ptr()));
+ }
+ }
+ }
+ }
+
+ KviStr::freeArray(arr);
+ }
+}
+
+
+const char * KviSSLCertificate::dictEntry(KviPointerHashTable<const char *,KviStr> * dict,const char * entry)
+{
+ KviStr * t = dict->find(entry);
+ if(!t)return __tr("Unknown");
+ return t->ptr();
+}
+
+
+/*
+void KviSSLCertificate::getPKeyType(int type,KviStr &buffer)
+{
+ switch(type)
+ {
+#ifndef NO_RSA
+ case EVP_PKEY_RSA: buffer = "RSA"; break;
+#endif
+#ifndef NO_DSA
+ case EVP_PKEY_DSA: buffer = "DSA"; break;
+#endif
+#ifndef NO_DH
+ case EVP_PKEY_DH: buffer = "DH"; break;
+#endif
+ case EVP_PKEY_NONE: buffer = "NONE"; break;
+ }
+}
+*/
+
+void KviSSLCertificate::extractPubKeyInfo()
+{
+ EVP_PKEY *p = X509_get_pubkey(m_pX509);
+ if(p)
+ {
+ m_iPubKeyBits = EVP_PKEY_bits(p);
+ m_szPubKeyType = (p->type == NID_undef) ? __tr("Unknown") : OBJ_nid2ln(p->type);
+// getPKeyType(p->type,m_szPubKeyType);
+ } else {
+ m_iPubKeyBits = 0;
+ m_szPubKeyType = "None";
+ }
+
+}
+
+void KviSSLCertificate::extractSerialNumber()
+{
+ ASN1_INTEGER * i = X509_get_serialNumber(m_pX509);
+ if(i)m_iSerialNumber = ASN1_INTEGER_get(i);
+ else m_iSerialNumber = -1;
+}
+
+void KviSSLCertificate::extractSignature()
+{
+ static char hexdigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+ //getPKeyType(X509_get_signature_type(m_pX509),m_szSignatureType);
+
+ int i = OBJ_obj2nid(m_pX509->sig_alg->algorithm);
+ m_szSignatureType = (i == NID_undef) ? __tr("Unknown") : OBJ_nid2ln(i);
+
+ m_szSignatureContents = "";
+
+ for(i = 0;i < m_pX509->signature->length;i++)
+ {
+ if(m_szSignatureContents.hasData())m_szSignatureContents.append(":");
+ m_szSignatureContents.append(hexdigits[(m_pX509->signature->data[i] & 0xf0) >> 4]);
+ m_szSignatureContents.append(hexdigits[(m_pX509->signature->data[i] & 0x0f)]);
+ }
+}
+
+/*
+const char * KviSSLCertificate::verify()
+{
+
+}
+*/
+
+
+KviSSLCipherInfo::KviSSLCipherInfo(SSL_CIPHER * c)
+{
+ m_szVersion = SSL_CIPHER_get_version(c);
+ m_iNumBitsUsed = SSL_CIPHER_get_bits(c,&m_iNumBits);
+ m_szName = SSL_CIPHER_get_name(c);
+ char buf[1024];
+ m_szDescription = SSL_CIPHER_description(c,buf,1024);
+}
+
+KviSSLCipherInfo::~KviSSLCipherInfo()
+{
+}
+
+#ifdef COMPILE_ON_WINDOWS
+
+ // On windows we need to override new and delete operators
+ // to ensure that always the right new/delete pair is called for an object instance
+ // This bug is present in all the classes exported by a module that
+ // can be instantiated/destroyed from external modules.
+ // (this is a well known bug described in Q122675 of MSDN)
+
+ void * KviSSLCipherInfo::operator new(size_t tSize)
+ {
+ return kvi_malloc(tSize);
+ }
+
+ void KviSSLCipherInfo::operator delete(void * p)
+ {
+ kvi_free(p);
+ }
+
+#endif
+
+#endif //COMPILE_SSL_SUPPORT
diff --git a/src/kvilib/net/kvi_ssl.h b/src/kvilib/net/kvi_ssl.h
new file mode 100644
index 00000000..5547ecbb
--- /dev/null
+++ b/src/kvilib/net/kvi_ssl.h
@@ -0,0 +1,180 @@
+#ifndef _KVI_SSL_H_
+#define _KVI_SSL_H_
+//
+// File : kvi_ssl.h
+// Creation date : Mon May 27 2002 21:36:12 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002 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 "kvi_settings.h"
+
+#ifdef COMPILE_SSL_SUPPORT
+
+#include "kvi_string.h"
+#include "kvi_sockettype.h"
+
+#include "kvi_pointerhashtable.h"
+
+#include <openssl/ssl.h>
+
+
+class KVILIB_API KviSSLCertificate
+{
+public:
+ KviSSLCertificate(X509 * x509);
+ ~KviSSLCertificate();
+protected:
+ X509 * m_pX509;
+ KviPointerHashTable<const char *,KviStr> * m_pSubject;
+ KviPointerHashTable<const char *,KviStr> * m_pIssuer;
+ int m_iPubKeyBits;
+ KviStr m_szPubKeyType;
+ int m_iSerialNumber;
+ int m_iVersion;
+ KviStr m_szSignatureType;
+ KviStr m_szSignatureContents;
+private:
+ void extractSubject();
+ void extractIssuer();
+ void extractPubKeyInfo();
+ void extractSerialNumber();
+ void extractSignature();
+ const char * dictEntry(KviPointerHashTable<const char *,KviStr> * dict,const char * entry);
+ void splitX509String(KviPointerHashTable<const char *,KviStr> * dict,const char * t);
+// void getPKeyType(int type,KviStr &buffer);
+public:
+ void setX509(X509 * x509);
+
+ const char * signatureType(){ return m_szSignatureType.ptr(); };
+ const char * signatureContents(){ return m_szSignatureContents.ptr(); };
+
+ const char * subjectCountry(){ return dictEntry(m_pSubject,"C"); };
+ const char * subjectStateOrProvince(){ return dictEntry(m_pSubject,"ST"); };
+ const char * subjectLocality(){ return dictEntry(m_pSubject,"L"); };
+ const char * subjectOrganization(){ return dictEntry(m_pSubject,"O"); };
+ const char * subjectOrganizationalUnit(){ return dictEntry(m_pSubject,"OU"); };
+ const char * subjectCommonName(){ return dictEntry(m_pSubject,"CN"); };
+
+ const char * issuerCountry(){ return dictEntry(m_pIssuer,"C"); };
+ const char * issuerStateOrProvince(){ return dictEntry(m_pIssuer,"ST"); };
+ const char * issuerLocality(){ return dictEntry(m_pIssuer,"L"); };
+ const char * issuerOrganization(){ return dictEntry(m_pIssuer,"O"); };
+ const char * issuerOrganizationalUnit(){ return dictEntry(m_pIssuer,"OU"); };
+ const char * issuerCommonName(){ return dictEntry(m_pIssuer,"CN"); };
+
+ int publicKeyBits(){ return m_iPubKeyBits; };
+ const char * publicKeyType(){ return m_szPubKeyType.ptr(); };
+
+ int serialNumber(){ return m_iSerialNumber; };
+
+ int version(){ return m_iVersion; };
+#ifdef COMPILE_ON_WINDOWS
+ // On windows we need to override new and delete operators
+ // to ensure that always the right new/delete pair is called for an object instance
+ // This bug is present in all the classes exported by a module that
+ // can be instantiated/destroyed from external modules.
+ // (this is a well known bug described in Q122675 of MSDN)
+ void * operator new(size_t tSize);
+ void operator delete(void * p);
+#endif
+};
+
+class KVILIB_API KviSSLCipherInfo
+{
+public:
+ KviSSLCipherInfo(SSL_CIPHER * c);
+ ~KviSSLCipherInfo();
+protected:
+ KviStr m_szVersion;
+ int m_iNumBits;
+ int m_iNumBitsUsed;
+ KviStr m_szName;
+ KviStr m_szDescription;
+public:
+ const char * name(){ return m_szName.ptr(); };
+ const char * description(){ return m_szDescription.ptr(); };
+ int bits(){ return m_iNumBits; };
+ int bitsUsed(){ return m_iNumBitsUsed; };
+ const char * version(){ return m_szVersion.ptr(); };
+#ifdef COMPILE_ON_WINDOWS
+ // On windows we need to override new and delete operators
+ // to ensure that always the right new/delete pair is called for an object instance
+ // This bug is present in all the classes exported by a module that
+ // can be instantiated/destroyed from external modules.
+ // (this is a well known bug described in Q122675 of MSDN)
+ void * operator new(size_t tSize);
+ void operator delete(void * p);
+#endif
+};
+
+#ifdef Success
+ #undef Success
+#endif
+
+
+class KVILIB_API KviSSL
+{
+public:
+ enum Method { Client , Server };
+ enum Result { Success , NotInitialized , WantRead , WantWrite , ZeroReturn , FileIoError ,
+ UnknownError , ObscureError , SSLError , SyscallError , RemoteEndClosedConnection };
+public:
+ KviSSL();
+ ~KviSSL();
+public:
+ SSL * m_pSSL;
+ SSL_CTX * m_pSSLCtx;
+ KviStr m_szPass;
+public:
+ static void globalInit();
+ static void globalDestroy();
+public:
+ bool initSocket(kvi_socket_t fd);
+ bool initContext(KviSSL::Method m);
+ void shutdown();
+ KviSSL::Result connect();
+ KviSSL::Result accept();
+ int read(char * buffer,int len);
+ int write(const char * buffer,int len);
+ // SSL ERRORS
+ unsigned long getLastError(bool bPeek = false);
+ bool getLastErrorString(KviStr &buffer,bool bPeek = false);
+ // Protocol error
+ KviSSL::Result getProtocolError(int ret);
+ KviSSLCertificate * getPeerCertificate();
+ KviSSLCipherInfo * getCurrentCipherInfo();
+ KviSSL::Result useCertificateFile(const char * cert,const char * pass);
+ KviSSL::Result usePrivateKeyFile(const char * key,const char * pass);
+#ifdef COMPILE_ON_WINDOWS
+ // On windows we need to override new and delete operators
+ // to ensure that always the right new/delete pair is called for an object instance
+ // This bug is present in all the classes exported by a module that
+ // can be instantiated/destroyed from external modules.
+ // (this is a well known bug described in Q122675 of MSDN)
+ void * operator new(size_t tSize);
+ void operator delete(void * p);
+#endif
+private:
+ KviSSL::Result connectOrAcceptError(int ret);
+};
+
+
+#endif //COMPILE_SSL_SUPPORT
+
+#endif //_KVI_SSL_H_
diff --git a/src/kvilib/net/kvi_url.cpp b/src/kvilib/net/kvi_url.cpp
new file mode 100644
index 00000000..f980729c
--- /dev/null
+++ b/src/kvilib/net/kvi_url.cpp
@@ -0,0 +1,164 @@
+//
+// File : kvi_url.cpp
+// Creation date : Sat Aug 17 14:09:18 2002 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002 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.
+//
+
+
+#define __KVILIB__
+
+
+#include "kvi_url.h"
+
+KviUrl::KviUrl()
+{
+}
+
+KviUrl::KviUrl(const KviUrl & u)
+{
+ *this = u;
+}
+
+KviUrl::KviUrl(const char * szUrl)
+{
+ m_szUrl = szUrl;
+ parse();
+}
+
+KviUrl::KviUrl(const QString &szUrl)
+{
+ m_szUrl = szUrl;
+ parse();
+}
+
+KviUrl::~KviUrl()
+{
+
+}
+
+void KviUrl::parse()
+{
+ m_szProtocol = "";
+ m_szHost = "";
+ m_szPath = "";
+ m_szUser = "";
+ m_szPass = "";
+
+ m_szUrl.stripWhiteSpace();
+
+ KviStr u = m_szUrl;
+
+ // proto
+
+ kvi_u32_t uDefaultPort = 80;
+
+ int i = u.findFirstIdx(":/");
+ if(i != -1)
+ {
+ // there is a protocol path
+ m_szProtocol = u.left(i);
+ u.cutLeft(i + 2);
+ u.stripLeft('/');
+ u.stripWhiteSpace();
+
+ // fix the default ports
+ if(kvi_strEqualCI(m_szProtocol,"https"))uDefaultPort = 443;
+ else if(kvi_strEqualCI(m_szProtocol,"ftp"))uDefaultPort = 21;
+ } else {
+ // no proto... assume http
+ u.stripLeft('/');
+ m_szProtocol = "http";
+ }
+
+ m_uPort = uDefaultPort;
+
+ // user and pass
+
+ i = u.findFirstIdx('@');
+
+ if(i != -1)
+ {
+ KviStr szUserPass = u.left(i);
+ szUserPass.stripWhiteSpace();
+ u.cutLeft(i + 1);
+
+ i = szUserPass.findFirstIdx(':');
+ if(i != -1)
+ {
+ m_szUser = szUserPass.left(i);
+ szUserPass.cutLeft(i + 1);
+ m_szPass = szUserPass;
+ m_szPass.stripWhiteSpace();
+ } else {
+ m_szUser = szUserPass;
+ }
+ }
+
+ // host
+
+ i = u.findFirstIdx('/');
+ if(i != -1)
+ {
+ KviStr h = u.left(i);
+ u.cutLeft(i + 1);
+ i = h.findFirstIdx(':');
+ if(i != -1)
+ {
+ // has a port part
+ m_szHost = h.left(i);
+ h.cutLeft(i + 1);
+ h.stripWhiteSpace();
+ bool bOk;
+ m_uPort = h.toUInt(&bOk);
+ if(!bOk)m_uPort = uDefaultPort;
+ } else {
+ // no port : assume default
+ m_szHost = h;
+ }
+ m_szPath = u;
+ } else {
+ m_szHost = u;
+ }
+
+ m_szHost.stripWhiteSpace();
+ m_szPath.stripWhiteSpace();
+ if(!m_szPath.firstCharIs('/'))m_szPath.prepend('/');
+}
+
+
+KviUrl & KviUrl::operator=(const char * szUrl)
+{
+ m_szUrl = szUrl;
+ parse();
+ return *this;
+}
+
+KviUrl & KviUrl::operator=(const KviUrl &u)
+{
+ m_szUrl = u.m_szUrl;
+ m_szProtocol = u.m_szProtocol;
+ m_szHost = u.m_szHost;
+ m_szPath = u.m_szPath;
+ m_szUser = u.m_szUser;
+ m_szPass = u.m_szPass;
+ m_uPort = u.m_uPort;
+ return *this;
+}
+
+
diff --git a/src/kvilib/net/kvi_url.h b/src/kvilib/net/kvi_url.h
new file mode 100644
index 00000000..89adeb9f
--- /dev/null
+++ b/src/kvilib/net/kvi_url.h
@@ -0,0 +1,63 @@
+#ifndef _KVI_URL_H_
+#define _KVI_URL_H_
+//
+// File : kvi_url.h
+// Creation date : Sat Aug 17 14:09:16 2002 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002 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 "kvi_string.h"
+#include "kvi_heapobject.h"
+#include "kvi_inttypes.h"
+
+class KVILIB_API KviUrl : public KviHeapObject
+{
+public:
+ KviUrl();
+ KviUrl(const char * szUrl);
+ KviUrl(const QString &szUrl);
+ KviUrl(const KviUrl &u);
+ ~KviUrl();
+protected:
+ KviStr m_szUrl;
+
+ KviStr m_szProtocol;
+ KviStr m_szHost;
+ KviStr m_szPath;
+ KviStr m_szUser;
+ KviStr m_szPass;
+ kvi_u32_t m_uPort;
+protected:
+ void parse();
+public:
+ const KviStr & url() const { return m_szUrl; };
+ const KviStr & protocol() const { return m_szProtocol; };
+ const KviStr & host() const { return m_szHost; };
+ const KviStr & path() const { return m_szPath; };
+ const KviStr & user() const { return m_szUser; };
+ const KviStr & pass() const { return m_szPass; };
+ kvi_u32_t port() const { return m_uPort; };
+
+ KviUrl & operator = (const char * szUrl);
+ KviUrl & operator = (const KviUrl &u);
+
+};
+
+
+#endif //_KVI_URL_H_
diff --git a/src/kvilib/net/moc_kvi_dns.cpp b/src/kvilib/net/moc_kvi_dns.cpp
new file mode 100644
index 00000000..5b8857a9
--- /dev/null
+++ b/src/kvilib/net/moc_kvi_dns.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+** KviDns meta object code from reading C++ file 'kvi_dns.h'
+**
+** Created: Sun Mar 23 20:56:20 2008
+** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#undef QT_NO_COMPAT
+#include "kvi_dns.h"
+#include <qmetaobject.h>
+#include <qapplication.h>
+
+#include <private/qucomextra_p.h>
+#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26)
+#error "This file was generated using the moc from 3.3.8. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+#include <qvariant.h>
+const char *KviDns::className() const
+{
+ return "KviDns";
+}
+
+QMetaObject *KviDns::metaObj = 0;
+static QMetaObjectCleanUp cleanUp_KviDns( "KviDns", &KviDns::staticMetaObject );
+
+#ifndef QT_NO_TRANSLATION
+QString KviDns::tr( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviDns", s, c, QApplication::DefaultCodec );
+ else
+ return QString::fromLatin1( s );
+}
+#ifndef QT_NO_TRANSLATION_UTF8
+QString KviDns::trUtf8( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviDns", s, c, QApplication::UnicodeUTF8 );
+ else
+ return QString::fromUtf8( s );
+}
+#endif // QT_NO_TRANSLATION_UTF8
+
+#endif // QT_NO_TRANSLATION
+
+QMetaObject* KviDns::staticMetaObject()
+{
+ if ( metaObj )
+ return metaObj;
+ QMetaObject* parentObject = QObject::staticMetaObject();
+ static const QUParameter param_signal_0[] = {
+ { 0, &static_QUType_ptr, "KviDns", QUParameter::In }
+ };
+ static const QUMethod signal_0 = {"lookupDone", 1, param_signal_0 };
+ static const QMetaData signal_tbl[] = {
+ { "lookupDone(KviDns*)", &signal_0, QMetaData::Private }
+ };
+#ifndef QT_NO_PROPERTIES
+ static const QMetaProperty props_tbl[1] = {
+ { "bool","blockingDelete", 0x12000001, &KviDns::metaObj, 0, -1 }
+ };
+#endif // QT_NO_PROPERTIES
+ metaObj = QMetaObject::new_metaobject(
+ "KviDns", parentObject,
+ 0, 0,
+ signal_tbl, 1,
+#ifndef QT_NO_PROPERTIES
+ props_tbl, 1,
+ 0, 0,
+#endif // QT_NO_PROPERTIES
+ 0, 0 );
+ cleanUp_KviDns.setMetaObject( metaObj );
+ return metaObj;
+}
+
+void* KviDns::qt_cast( const char* clname )
+{
+ if ( !qstrcmp( clname, "KviDns" ) )
+ return this;
+ if ( !qstrcmp( clname, "KviHeapObject" ) )
+ return (KviHeapObject*)this;
+ return QObject::qt_cast( clname );
+}
+
+#include <qobjectdefs.h>
+#include <qsignalslotimp.h>
+
+// SIGNAL lookupDone
+void KviDns::lookupDone( KviDns* t0 )
+{
+ if ( signalsBlocked() )
+ return;
+ QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 0 );
+ if ( !clist )
+ return;
+ QUObject o[2];
+ static_QUType_ptr.set(o+1,t0);
+ activate_signal( clist, o );
+}
+
+bool KviDns::qt_invoke( int _id, QUObject* _o )
+{
+ return QObject::qt_invoke(_id,_o);
+}
+
+bool KviDns::qt_emit( int _id, QUObject* _o )
+{
+ switch ( _id - staticMetaObject()->signalOffset() ) {
+ case 0: lookupDone((KviDns*)static_QUType_ptr.get(_o+1)); break;
+ default:
+ return QObject::qt_emit(_id,_o);
+ }
+ return TRUE;
+}
+#ifndef QT_NO_PROPERTIES
+
+bool KviDns::qt_property( int id, int f, QVariant* v)
+{
+ switch ( id - staticMetaObject()->propertyOffset() ) {
+ case 0: switch( f ) {
+ case 1: *v = QVariant( this->isRunning(), 0 ); break;
+ case 3: case 4: case 5: break;
+ default: return FALSE;
+ } break;
+ default:
+ return QObject::qt_property( id, f, v );
+ }
+ return TRUE;
+}
+
+bool KviDns::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; }
+#endif // QT_NO_PROPERTIES
diff --git a/src/kvilib/net/moc_kvi_http.cpp b/src/kvilib/net/moc_kvi_http.cpp
new file mode 100644
index 00000000..7ea9b591
--- /dev/null
+++ b/src/kvilib/net/moc_kvi_http.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+** KviHttpRequest meta object code from reading C++ file 'kvi_http.h'
+**
+** Created: Sun Mar 23 20:56:22 2008
+** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#undef QT_NO_COMPAT
+#include "kvi_http.h"
+#include <qmetaobject.h>
+#include <qapplication.h>
+
+#include <private/qucomextra_p.h>
+#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26)
+#error "This file was generated using the moc from 3.3.8. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+const char *KviHttpRequest::className() const
+{
+ return "KviHttpRequest";
+}
+
+QMetaObject *KviHttpRequest::metaObj = 0;
+static QMetaObjectCleanUp cleanUp_KviHttpRequest( "KviHttpRequest", &KviHttpRequest::staticMetaObject );
+
+#ifndef QT_NO_TRANSLATION
+QString KviHttpRequest::tr( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviHttpRequest", s, c, QApplication::DefaultCodec );
+ else
+ return QString::fromLatin1( s );
+}
+#ifndef QT_NO_TRANSLATION_UTF8
+QString KviHttpRequest::trUtf8( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviHttpRequest", s, c, QApplication::UnicodeUTF8 );
+ else
+ return QString::fromUtf8( s );
+}
+#endif // QT_NO_TRANSLATION_UTF8
+
+#endif // QT_NO_TRANSLATION
+
+QMetaObject* KviHttpRequest::staticMetaObject()
+{
+ if ( metaObj )
+ return metaObj;
+ QMetaObject* parentObject = QObject::staticMetaObject();
+ static const QUParameter param_slot_0[] = {
+ { "d", &static_QUType_ptr, "KviDns", QUParameter::In }
+ };
+ static const QUMethod slot_0 = {"dnsLookupDone", 1, param_slot_0 };
+ static const QUMethod slot_1 = {"haveServerIp", 0, 0 };
+ static const QMetaData slot_tbl[] = {
+ { "dnsLookupDone(KviDns*)", &slot_0, QMetaData::Protected },
+ { "haveServerIp()", &slot_1, QMetaData::Protected }
+ };
+ static const QUParameter param_signal_0[] = {
+ { "hostname", &static_QUType_QString, 0, QUParameter::In }
+ };
+ static const QUMethod signal_0 = {"resolvingHost", 1, param_signal_0 };
+ static const QUParameter param_signal_1[] = {
+ { "ipandport", &static_QUType_QString, 0, QUParameter::In }
+ };
+ static const QUMethod signal_1 = {"contactingHost", 1, param_signal_1 };
+ static const QUMethod signal_2 = {"connectionEstabilished", 0, 0 };
+ static const QUParameter param_signal_3[] = {
+ { "response", &static_QUType_QString, 0, QUParameter::In }
+ };
+ static const QUMethod signal_3 = {"receivedResponse", 1, param_signal_3 };
+ static const QUParameter param_signal_4[] = {
+ { "bSuccess", &static_QUType_bool, 0, QUParameter::In }
+ };
+ static const QUMethod signal_4 = {"terminated", 1, param_signal_4 };
+ static const QUParameter param_signal_5[] = {
+ { "message", &static_QUType_QString, 0, QUParameter::In }
+ };
+ static const QUMethod signal_5 = {"status", 1, param_signal_5 };
+ static const QUParameter param_signal_6[] = {
+ { "data", &static_QUType_ptr, "KviStr", QUParameter::In }
+ };
+ static const QUMethod signal_6 = {"data", 1, param_signal_6 };
+ static const QUParameter param_signal_7[] = {
+ { "data", &static_QUType_ptr, "KviDataBuffer", QUParameter::In }
+ };
+ static const QUMethod signal_7 = {"binaryData", 1, param_signal_7 };
+ static const QUParameter param_signal_8[] = {
+ { "hdr", &static_QUType_ptr, "KviPointerHashTable<const char*,KviStr>", QUParameter::In }
+ };
+ static const QUMethod signal_8 = {"header", 1, param_signal_8 };
+ static const QUParameter param_signal_9[] = {
+ { "request", &static_QUType_varptr, "\x04", QUParameter::In }
+ };
+ static const QUMethod signal_9 = {"requestSent", 1, param_signal_9 };
+ static const QMetaData signal_tbl[] = {
+ { "resolvingHost(const QString&)", &signal_0, QMetaData::Public },
+ { "contactingHost(const QString&)", &signal_1, QMetaData::Public },
+ { "connectionEstabilished()", &signal_2, QMetaData::Public },
+ { "receivedResponse(const QString&)", &signal_3, QMetaData::Public },
+ { "terminated(bool)", &signal_4, QMetaData::Public },
+ { "status(const QString&)", &signal_5, QMetaData::Public },
+ { "data(const KviStr&)", &signal_6, QMetaData::Public },
+ { "binaryData(const KviDataBuffer&)", &signal_7, QMetaData::Public },
+ { "header(KviPointerHashTable<const char*,KviStr>*)", &signal_8, QMetaData::Public },
+ { "requestSent(const QStringList&)", &signal_9, QMetaData::Public }
+ };
+ metaObj = QMetaObject::new_metaobject(
+ "KviHttpRequest", parentObject,
+ slot_tbl, 2,
+ signal_tbl, 10,
+#ifndef QT_NO_PROPERTIES
+ 0, 0,
+ 0, 0,
+#endif // QT_NO_PROPERTIES
+ 0, 0 );
+ cleanUp_KviHttpRequest.setMetaObject( metaObj );
+ return metaObj;
+}
+
+void* KviHttpRequest::qt_cast( const char* clname )
+{
+ if ( !qstrcmp( clname, "KviHttpRequest" ) )
+ return this;
+ if ( !qstrcmp( clname, "KviHeapObject" ) )
+ return (KviHeapObject*)this;
+ return QObject::qt_cast( clname );
+}
+
+// SIGNAL resolvingHost
+void KviHttpRequest::resolvingHost( const QString& t0 )
+{
+ activate_signal( staticMetaObject()->signalOffset() + 0, t0 );
+}
+
+// SIGNAL contactingHost
+void KviHttpRequest::contactingHost( const QString& t0 )
+{
+ activate_signal( staticMetaObject()->signalOffset() + 1, t0 );
+}
+
+// SIGNAL connectionEstabilished
+void KviHttpRequest::connectionEstabilished()
+{
+ activate_signal( staticMetaObject()->signalOffset() + 2 );
+}
+
+// SIGNAL receivedResponse
+void KviHttpRequest::receivedResponse( const QString& t0 )
+{
+ activate_signal( staticMetaObject()->signalOffset() + 3, t0 );
+}
+
+// SIGNAL terminated
+void KviHttpRequest::terminated( bool t0 )
+{
+ activate_signal_bool( staticMetaObject()->signalOffset() + 4, t0 );
+}
+
+// SIGNAL status
+void KviHttpRequest::status( const QString& t0 )
+{
+ activate_signal( staticMetaObject()->signalOffset() + 5, t0 );
+}
+
+#include <qobjectdefs.h>
+#include <qsignalslotimp.h>
+
+// SIGNAL data
+void KviHttpRequest::data( const KviStr& t0 )
+{
+ if ( signalsBlocked() )
+ return;
+ QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 6 );
+ if ( !clist )
+ return;
+ QUObject o[2];
+ static_QUType_ptr.set(o+1,&t0);
+ activate_signal( clist, o );
+}
+
+// SIGNAL binaryData
+void KviHttpRequest::binaryData( const KviDataBuffer& t0 )
+{
+ if ( signalsBlocked() )
+ return;
+ QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 7 );
+ if ( !clist )
+ return;
+ QUObject o[2];
+ static_QUType_ptr.set(o+1,&t0);
+ activate_signal( clist, o );
+}
+
+// SIGNAL header
+void KviHttpRequest::header( KviPointerHashTable<const char*,KviStr>* t0 )
+{
+ if ( signalsBlocked() )
+ return;
+ QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 8 );
+ if ( !clist )
+ return;
+ QUObject o[2];
+ static_QUType_ptr.set(o+1,t0);
+ activate_signal( clist, o );
+}
+
+// SIGNAL requestSent
+void KviHttpRequest::requestSent( const QStringList& t0 )
+{
+ if ( signalsBlocked() )
+ return;
+ QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 9 );
+ if ( !clist )
+ return;
+ QUObject o[2];
+ static_QUType_varptr.set(o+1,&t0);
+ activate_signal( clist, o );
+}
+
+bool KviHttpRequest::qt_invoke( int _id, QUObject* _o )
+{
+ switch ( _id - staticMetaObject()->slotOffset() ) {
+ case 0: dnsLookupDone((KviDns*)static_QUType_ptr.get(_o+1)); break;
+ case 1: haveServerIp(); break;
+ default:
+ return QObject::qt_invoke( _id, _o );
+ }
+ return TRUE;
+}
+
+bool KviHttpRequest::qt_emit( int _id, QUObject* _o )
+{
+ switch ( _id - staticMetaObject()->signalOffset() ) {
+ case 0: resolvingHost((const QString&)static_QUType_QString.get(_o+1)); break;
+ case 1: contactingHost((const QString&)static_QUType_QString.get(_o+1)); break;
+ case 2: connectionEstabilished(); break;
+ case 3: receivedResponse((const QString&)static_QUType_QString.get(_o+1)); break;
+ case 4: terminated((bool)static_QUType_bool.get(_o+1)); break;
+ case 5: status((const QString&)static_QUType_QString.get(_o+1)); break;
+ case 6: data((const KviStr&)*((const KviStr*)static_QUType_ptr.get(_o+1))); break;
+ case 7: binaryData((const KviDataBuffer&)*((const KviDataBuffer*)static_QUType_ptr.get(_o+1))); break;
+ case 8: header((KviPointerHashTable<const char*,KviStr>*)static_QUType_ptr.get(_o+1)); break;
+ case 9: requestSent((const QStringList&)*((const QStringList*)static_QUType_ptr.get(_o+1))); break;
+ default:
+ return QObject::qt_emit(_id,_o);
+ }
+ return TRUE;
+}
+#ifndef QT_NO_PROPERTIES
+
+bool KviHttpRequest::qt_property( int id, int f, QVariant* v)
+{
+ return QObject::qt_property( id, f, v);
+}
+
+bool KviHttpRequest::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; }
+#endif // QT_NO_PROPERTIES