1 //=============================================================================
2 //
3 //   File : KviIrcSocket.cpp
4 //   Creation date : Tue Jul 30 19:25:18 2002 GMT by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2002-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #include "KviIrcSocket.h"
26 #include "KviIrcServer.h"
27 #include "KviProxy.h"
28 #include "KviProxyDataBase.h"
29 #include "KviNetUtils.h"
30 #include "kvi_settings.h"
31 #include "KviLocale.h"
32 #include "KviMemory.h"
33 #include "kvi_debug.h"
34 #include "KviCString.h"
35 #include "KviOptions.h"
36 #include "KviConsoleWindow.h"
37 #include "kvi_out.h"
38 #include "KviIrcLink.h"
39 #include "KviIrcConnection.h"
40 #include "KviDataBuffer.h"
41 
42 #ifdef COMPILE_SSL_SUPPORT
43 #include "KviSSLMaster.h"
44 #endif
45 
46 #include <QTimer>
47 #include <QSocketNotifier>
48 #include <memory>
49 
50 #if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
51 #include <unistd.h> //for gettimeofday()
52 #endif
53 //#include <fcntl.h>
54 //#include <errno.h>
55 
56 // FIXME: #warning "Lag-o-meter"
57 
58 unsigned int g_uNextIrcLinkId = 1;
59 
KviIrcSocket(KviIrcLink * pLink)60 KviIrcSocket::KviIrcSocket(KviIrcLink * pLink)
61     : QObject(), m_pLink(pLink)
62 {
63 	m_uId = g_uNextIrcLinkId;
64 	g_uNextIrcLinkId++;
65 
66 	m_pConsole = m_pLink->console();
67 
68 	m_tAntiFloodLastMessageTime.tv_sec = 0;
69 	m_tAntiFloodLastMessageTime.tv_usec = 0;
70 
71 	if(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout) < 100)
72 		KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout) = 100; // this is our minimum, we don't want to lag the app
73 
74 	m_pFlushTimer = std::make_unique<QTimer>(); // queue flush timer
75 	connect(m_pFlushTimer.get(), SIGNAL(timeout()), this, SLOT(flushSendQueue()));
76 }
77 
~KviIrcSocket()78 KviIrcSocket::~KviIrcSocket()
79 {
80 	reset();
81 }
82 
reset()83 void KviIrcSocket::reset()
84 {
85 #ifdef COMPILE_SSL_SUPPORT
86 	if(m_pSSL)
87 	{
88 		KviSSLMaster::freeSSL(m_pSSL);
89 		m_pSSL = nullptr;
90 	}
91 #endif
92 	if(m_pIrcServer)
93 	{
94 		delete m_pIrcServer;
95 		m_pIrcServer = nullptr;
96 	}
97 
98 	if(m_pProxy)
99 	{
100 		delete m_pProxy;
101 		m_pProxy = nullptr;
102 	}
103 
104 	if(m_pRsn)
105 	{
106 		delete m_pRsn;
107 		m_pRsn = nullptr;
108 	}
109 
110 	if(m_pWsn)
111 	{
112 		delete m_pWsn;
113 		m_pWsn = nullptr;
114 	}
115 
116 	if(kvi_socket_isValid(m_sock))
117 	{
118 		kvi_socket_destroy(m_sock);
119 		m_sock = KVI_INVALID_SOCKET;
120 	}
121 
122 	if(m_pTimeoutTimer)
123 	{
124 		m_pTimeoutTimer->stop();
125 		delete m_pTimeoutTimer;
126 		m_pTimeoutTimer = nullptr;
127 	}
128 
129 	m_bInProcessData = false;
130 
131 	m_uReadBytes = 0;
132 	m_uSentBytes = 0;
133 	m_uSentPackets = 0;
134 	m_tAntiFloodLastMessageTime.tv_sec = 0;
135 	m_tAntiFloodLastMessageTime.tv_usec = 0;
136 
137 	m_bInProcessData = false;
138 
139 	if(m_pFlushTimer->isActive())
140 		m_pFlushTimer->stop();
141 
142 	queue_removeAllMessages();
143 
144 	setState(Idle);
145 }
146 
clearOutputQueue(bool bPrivateMessagesOnly)147 void KviIrcSocket::clearOutputQueue(bool bPrivateMessagesOnly)
148 {
149 	if(bPrivateMessagesOnly)
150 		queue_removePrivateMessages();
151 	else
152 		queue_removeAllMessages();
153 }
154 
outputQueueSize()155 unsigned int KviIrcSocket::outputQueueSize()
156 {
157 	KviIrcSocketMsgEntry * pMsg = m_pSendQueueTail;
158 	if(!pMsg)
159 		return 0;
160 
161 	unsigned int uCount = 0;
162 
163 	do
164 	{
165 		uCount++;
166 		pMsg = pMsg->next_ptr;
167 	} while(pMsg);
168 
169 	return uCount;
170 }
171 
outputSSLMessage(const QString & szMsg)172 void KviIrcSocket::outputSSLMessage(const QString & szMsg)
173 {
174 	m_pConsole->output(KVI_OUT_SSL, __tr2qs("[SSL]: %Q"), &szMsg);
175 }
176 
outputSSLError(const QString & szMsg)177 void KviIrcSocket::outputSSLError(const QString & szMsg)
178 {
179 	m_pConsole->output(KVI_OUT_SSL, __tr2qs("[SSL ERROR]: %Q"), &szMsg);
180 }
181 
outputProxyMessage(const QString & szMsg)182 void KviIrcSocket::outputProxyMessage(const QString & szMsg)
183 {
184 	for(const auto & it : szMsg.split('\n', QString::SkipEmptyParts))
185 	{
186 		QString szTemporary = it.trimmed();
187 		m_pConsole->output(KVI_OUT_SOCKETMESSAGE, __tr2qs("[PROXY]: %Q"), &szTemporary);
188 	}
189 }
190 
outputProxyError(const QString & szMsg)191 void KviIrcSocket::outputProxyError(const QString & szMsg)
192 {
193 	for(const auto & it : szMsg.split('\n', QString::SkipEmptyParts))
194 	{
195 		QString szTemporary = it.trimmed();
196 		m_pConsole->output(KVI_OUT_SOCKETERROR, __tr2qs("[PROXY ERROR]: %Q"), &szTemporary);
197 	}
198 }
199 
outputSocketMessage(const QString & szMsg)200 void KviIrcSocket::outputSocketMessage(const QString & szMsg)
201 {
202 	m_pConsole->output(KVI_OUT_SOCKETMESSAGE, __tr2qs("[SOCKET]: %Q"), &szMsg);
203 }
204 
outputSocketError(const QString & szMsg)205 void KviIrcSocket::outputSocketError(const QString & szMsg)
206 {
207 	m_pConsole->output(KVI_OUT_SOCKETERROR, __tr2qs("[SOCKET ERROR]: %Q"), &szMsg);
208 }
209 
outputSocketWarning(const QString & szMsg)210 void KviIrcSocket::outputSocketWarning(const QString & szMsg)
211 {
212 	m_pConsole->output(KVI_OUT_SOCKETWARNING, __tr2qs("[SOCKET WARNING]: %Q"), &szMsg);
213 }
214 
setState(SocketState state)215 void KviIrcSocket::setState(SocketState state)
216 {
217 	if(state != m_state)
218 	{
219 		m_state = state;
220 		m_pLink->socketStateChange();
221 	}
222 }
223 
raiseError(KviError::Code eError)224 void KviIrcSocket::raiseError(KviError::Code eError)
225 {
226 	m_eLastError = eError;
227 	//m_pConsole->socketError(iError);
228 	if((m_eLastError == KviError::RemoteEndClosedConnection) && (m_state == ProxyHttpError))
229 		outputSocketMessage(KviError::getDescription(eError));
230 	else
231 		outputSocketError(KviError::getDescription(eError));
232 }
233 
startConnection(KviIrcServer * pServer,KviProxy * pProxy,const char * pcBindAddress)234 KviError::Code KviIrcSocket::startConnection(KviIrcServer * pServer, KviProxy * pProxy, const char * pcBindAddress)
235 {
236 	// Attempts to establish an IRC connection
237 	// to the server specified by *srv.
238 	// Uses the proxy *prx if not 0
239 	if(m_state != Idle)
240 		return KviError::AnotherConnectionInProgress;
241 
242 	// Coherent state, thnx.
243 	reset();
244 
245 #ifndef COMPILE_SSL_SUPPORT
246 	if(pServer->useSSL())
247 	{
248 		return KviError::NoSSLSupport;
249 	}
250 #endif //COMPILE_SSL_SUPPORT
251 
252 	// Copy the server
253 	m_pIrcServer = new KviIrcServer(*pServer);
254 
255 	bool bTargetIPv6 = false;
256 	bool bNeedServerIp = !pProxy;
257 	if(pProxy)
258 		bNeedServerIp = ((pProxy->protocol() != KviProxy::Http) && (pProxy->protocol() != KviProxy::Socks5));
259 
260 	// We're going to check the addresses now
261 
262 	// check the proxy stuff...
263 	if(pProxy)
264 	{
265 		// Yeah...here comes the proxy
266 		m_pProxy = new KviProxy(*pProxy);
267 		// check the proxy IP address
268 		if(m_pProxy->isIPv6())
269 		{
270 // IPv6 proxy :) (STILL QUITE UNTESTED ?)
271 #ifdef COMPILE_IPV6_SUPPORT
272 			bTargetIPv6 = true;
273 			if(!KviNetUtils::isValidStringIPv6(m_pProxy->ip()))
274 				return KviError::InvalidProxyAddress;
275 			// SOCKSv4 does not support IPv6 addresses
276 			if(m_pProxy->protocol() == KviProxy::Socks4)
277 				return KviError::SocksV4LacksIPv6Support;
278 #else
279 			return KviError::NoIPv6Support;
280 #endif
281 		}
282 		else
283 		{
284 			// IPv4 proxy
285 			if(!KviNetUtils::isValidStringIp(m_pProxy->ip()))
286 				return KviError::InvalidProxyAddress;
287 		}
288 	}
289 
290 	if(bNeedServerIp)
291 	{
292 // check the IRC host IP
293 #ifdef COMPILE_IPV6_SUPPORT
294 		if(m_pIrcServer->isIPv6())
295 		{
296 			// We have an IPv6 server host (Interesting if proxy is IPv4)
297 			if(!KviNetUtils::isValidStringIPv6(m_pIrcServer->ip()))
298 				return KviError::InvalidIpAddress;
299 			if(!m_pProxy)
300 				bTargetIPv6 = true; // otherwise the proxy rules
301 		}
302 		else
303 		{
304 #endif
305 			// We have an IPv4 server host
306 			if(!KviNetUtils::isValidStringIp(m_pIrcServer->ip()))
307 				return KviError::InvalidIpAddress;
308 #ifdef COMPILE_IPV6_SUPPORT
309 		}
310 #endif
311 	}
312 
313 	KviSockaddr sa(pProxy ? m_pProxy->ip().toUtf8().data() : m_pIrcServer->ip().toUtf8().data(), pProxy ? m_pProxy->port() : m_pIrcServer->port(), bTargetIPv6);
314 
315 	if(!sa.socketAddress())
316 		return KviError::InvalidIpAddress;
317 
318 // create the socket
319 #ifdef COMPILE_IPV6_SUPPORT
320 	m_sock = kvi_socket_create(bTargetIPv6 ? KVI_SOCKET_PF_INET6 : KVI_SOCKET_PF_INET, KVI_SOCKET_TYPE_STREAM, KVI_SOCKET_PROTO_TCP);
321 #else
322 	m_sock = kvi_socket_create(KVI_SOCKET_PF_INET, KVI_SOCKET_TYPE_STREAM, KVI_SOCKET_PROTO_TCP);
323 #endif
324 
325 	if(m_sock < 0)
326 		return KviError::SocketCreationFailed;
327 
328 	if(pcBindAddress)
329 	{
330 		// we have to bind the socket to a local address
331 		KviSockaddr localSa(pcBindAddress, 0, bTargetIPv6);
332 		bool bBindOk = localSa.socketAddress();
333 
334 		if(bBindOk)
335 		{
336 			bBindOk = kvi_socket_bind(m_sock, localSa.socketAddress(), ((int)(localSa.addressLength())));
337 		}
338 
339 		QString szTmp;
340 		if(bBindOk)
341 		{
342 			if(_OUTPUT_VERBOSE)
343 				szTmp = QString(__tr2qs("Binding to local address %1")).arg(pcBindAddress);
344 			outputSocketMessage(szTmp);
345 		}
346 		else
347 		{
348 			if(_OUTPUT_VERBOSE)
349 				szTmp = QString(__tr2qs("Binding to local address %1 failed: the kernel will choose the correct interface")).arg(pcBindAddress);
350 			outputSocketWarning(szTmp);
351 		}
352 	}
353 
354 	// make it non blocking
355 	if(!kvi_socket_setNonBlocking(m_sock))
356 	{
357 		reset();
358 		return KviError::AsyncSocketFailed;
359 	}
360 
361 	if(!kvi_socket_connect(m_sock, sa.socketAddress(), ((int)(sa.addressLength()))))
362 	{
363 		// Oops!
364 		int iErr = kvi_socket_error();
365 
366 		if(!kvi_socket_recoverableConnectError(iErr))
367 		{
368 			// Oops!
369 			int iSockError = iErr;
370 			if(iSockError == 0)
371 			{
372 				// Zero error ?...let's look closer
373 				int iSize = sizeof(int);
374 				if(!kvi_socket_getsockopt(m_sock, SOL_SOCKET, SO_ERROR, (void *)&iSockError, &iSize))
375 					iSockError = 0;
376 			}
377 			// die :(
378 			reset();
379 			// And declare problems :)
380 			if(iSockError)
381 				return KviError::translateSystemError(iSockError);
382 			else
383 				return KviError::UnknownError; //Error 0 ?
384 		}
385 	}
386 
387 	// and setup the WRITE notifier...
388 	m_pWsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Write);
389 	QObject::connect(m_pWsn, SIGNAL(activated(int)), this, SLOT(writeNotifierFired(int)));
390 	m_pWsn->setEnabled(true);
391 
392 	// set the timer
393 	if(KVI_OPTION_UINT(KviOption_uintIrcSocketTimeout) < 5)
394 		KVI_OPTION_UINT(KviOption_uintIrcSocketTimeout) = 5;
395 
396 	m_pTimeoutTimer = new QTimer();
397 	QObject::connect(m_pTimeoutTimer, SIGNAL(timeout()), this, SLOT(connectionTimedOut()));
398 	m_pTimeoutTimer->setSingleShot(true);
399 	m_pTimeoutTimer->setInterval(KVI_OPTION_UINT(KviOption_uintIrcSocketTimeout) * 1000);
400 	m_pTimeoutTimer->start();
401 
402 	// and wait for connect
403 	setState(Connecting);
404 
405 	return KviError::Success;
406 }
407 
connectionTimedOut()408 void KviIrcSocket::connectionTimedOut()
409 {
410 	// the m_pTimeoutTimer fired :(
411 	raiseError(KviError::ConnectionTimedOut);
412 	reset();
413 }
414 
writeNotifierFired(int)415 void KviIrcSocket::writeNotifierFired(int)
416 {
417 	// kill the timeout timer
418 	if(m_pTimeoutTimer)
419 	{
420 		delete m_pTimeoutTimer;
421 		m_pTimeoutTimer = nullptr;
422 	}
423 
424 	// Check for errors...
425 	int iSockError;
426 	int iSize = sizeof(int);
427 	if(!kvi_socket_getsockopt(m_sock, SOL_SOCKET, SO_ERROR, (void *)&iSockError, &iSize))
428 		iSockError = -1;
429 
430 	//sockError = 0;
431 	if(iSockError != 0)
432 	{
433 		//failed
434 		KviError::Code eError;
435 		if(iSockError > 0)
436 			eError = KviError::translateSystemError(iSockError);
437 		else
438 			eError = KviError::UnknownError; //Error 0 ?
439 
440 		raiseError(eError);
441 		reset();
442 		return;
443 	}
444 
445 	// kill the write notifier
446 	delete m_pWsn;
447 	m_pWsn = nullptr;
448 
449 	//Successfully connected...
450 	connectionEstablished();
451 }
452 
connectionEstablished()453 void KviIrcSocket::connectionEstablished()
454 {
455 	if(m_sock == KVI_INVALID_SOCKET)
456 		return; // ops...disconnected in setState() ????
457 
458 	if(m_pProxy)
459 		connectedToProxy();
460 	else
461 		connectedToIrcServer();
462 }
463 
connectedToProxy()464 void KviIrcSocket::connectedToProxy()
465 {
466 	if(!m_pProxy)
467 		qDebug("WARNING: connectedToProxy() without a m_pProxy!");
468 
469 	// FIXME: Do we want to support SSL proxies ?
470 	//        it would be just a matter of SSL handshaking
471 	//        with the proxy
472 
473 	setState(ProxyLogin);
474 
475 	if(m_pRsn)
476 	{
477 		delete m_pRsn;
478 		m_pRsn = nullptr;
479 	}
480 
481 	m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
482 
483 	QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(readProxyData(int)));
484 
485 	switch(m_pProxy->protocol())
486 	{
487 		case KviProxy::Http:
488 			proxyLoginHttp();
489 			break;
490 		case KviProxy::Socks5:
491 			proxyLoginV5();
492 			break;
493 		default:
494 			proxyLoginV4();
495 			break;
496 	}
497 }
498 
readHttpProxyErrorData(int)499 void KviIrcSocket::readHttpProxyErrorData(int)
500 {
501 	char cBuffer[256];
502 	int iReadLength;
503 
504 	iReadLength = kvi_socket_recv(m_sock, cBuffer, 255);
505 	if(iReadLength <= 0)
506 	{
507 		handleInvalidSocketRead(iReadLength);
508 		return;
509 	}
510 
511 	outputProxyMessage(m_pConsole->decodeText(cBuffer));
512 }
513 
connectedToIrcServer()514 void KviIrcSocket::connectedToIrcServer()
515 {
516 #ifdef COMPILE_SSL_SUPPORT
517 	if(m_pIrcServer->useSSL())
518 	{
519 		enterSSLMode();
520 		return;
521 	}
522 #endif //COMPILE_SSL_SUPPORT
523 	linkUp();
524 }
525 
526 #ifdef COMPILE_SSL_SUPPORT
enterSSLMode()527 void KviIrcSocket::enterSSLMode()
528 {
529 	Q_ASSERT(!m_pSSL); // Don't call this function twice in a session
530 
531 	m_pSSL = KviSSLMaster::allocSSL(m_pConsole, m_sock, KviSSL::Client);
532 	if(!m_pSSL)
533 	{
534 		raiseSSLError();
535 		raiseError(KviError::SSLError);
536 		reset();
537 		return;
538 	}
539 	setState(SSLHandshake);
540 	doSSLHandshake(0);
541 }
542 #endif //COMPILE_SSL_SUPPORT
543 
readProxyData(int)544 void KviIrcSocket::readProxyData(int)
545 {
546 	char cBuffer[256];
547 	int iReadLength;
548 	/*
549 	// THIS IS WORKING CODE THAT SUPPORTS SSL PROXIES!
550 #ifdef COMPILE_SSL_SUPPORT
551 	if(m_pSSL)
552 	{
553 		readLength = m_pSSL->read(buffer,256);
554 		if(readLength <= 0)
555 		{
556 			// ssl error....?
557 			switch(m_pSSL->getProtocolError(readLength))
558 			{
559 				case KviSSL::ZeroReturn:
560 					readLength = 0;
561 				break;
562 				case KviSSL::WantRead:
563 				case KviSSL::WantWrite:
564 					// hmmm...
565 					return;
566 				break;
567 				case KviSSL::SyscallError:
568 				{
569 					int iE = m_pSSL->getLastError(true);
570 					if(iE != 0)
571 					{
572 						raiseSSLError();
573 						raiseError(KviError::SSLError);
574 						reset();
575 						return;
576 					}
577 				}
578 				break;
579 				case KviSSL::SSLError:
580 					raiseSSLError();
581 					raiseError(KviError::SSLError);
582 					reset();
583 					return;
584 				break;
585 				default:
586 					raiseError(KviError::SSLError);
587 					reset();
588 					return;
589 				break;
590 
591 			}
592 			handleInvalidSocketRead(readLength);
593 			return;
594 		}
595 	} else {
596 #endif
597 */
598 	iReadLength = kvi_socket_recv(m_sock, cBuffer, 255);
599 	if(iReadLength <= 0)
600 	{
601 		handleInvalidSocketRead(iReadLength);
602 		return;
603 	}
604 	/*
605 #ifdef COMPILE_SSL_SUPPORT
606 	}
607 #endif
608 */
609 	// we need at least two bytes...
610 	if(iReadLength < 2)
611 	{
612 		// a single byte of reply means:
613 		// - connection through a 1 bps modem
614 		// - a totally blocked network
615 		// - remote host is not a SOCKS/HTTP server
616 		// Anyway....it is always a meaningless reply
617 		// better to try again later :)
618 		raiseError(KviError::UnrecognizedProxyReply);
619 		reset();
620 		return;
621 	}
622 
623 	// handle the reply
624 	switch(m_state)
625 	{
626 		case ProxyFinalV4:
627 			//V4 final reply
628 			proxyHandleV4FinalReply((unsigned char)cBuffer[1]);
629 			break;
630 		case ProxySelectAuthMethodV5:
631 			//V5 method selection reply
632 			proxyHandleV5MethodReply((unsigned char)cBuffer[1]);
633 			break;
634 		case ProxyUserPassV5:
635 			//V5 user and pass reply
636 			proxyHandleV5AuthReply((unsigned char)cBuffer[1]);
637 			break;
638 		case ProxyFinalV5:
639 			//V5 final reply
640 			proxyHandleV5FinalReply((unsigned char)cBuffer[1]);
641 			break;
642 		case ProxyFinalHttp:
643 			//Http final reply
644 			cBuffer[iReadLength] = '\0';
645 			proxyHandleHttpFinalReply(cBuffer, iReadLength);
646 			break;
647 		default:
648 			// what ?
649 			raiseError(KviError::UnrecognizedProxyReply);
650 			reset();
651 			break;
652 	}
653 }
654 
proxyLoginHttp()655 void KviIrcSocket::proxyLoginHttp()
656 {
657 	// Well..this is just plain and easy: connect to the proxy machine
658 	// and say "CONNECT <irc.server>:<port> HTTP/<version>\n\n"
659 	// if it requires auth then say Proxy-Authorization: Basic user:passwd
660 	// Then expect a server reply header (2 newlines)
661 	// HTTP 200 = Success
662 	// HTTP Anything else = Failure
663 
664 	if(_OUTPUT_VERBOSE)
665 		outputProxyMessage(__tr2qs("Using HTTP protocol."));
666 
667 	setState(ProxyFinalHttp);
668 	KviCString szTmp(KviCString::Format, "CONNECT %s:%u HTTP/1.0\r\n", m_pIrcServer->hostName().toUtf8().data(), (unsigned int)(m_pIrcServer->port()));
669 
670 	szTmp.append(KviCString::Format, "User-Agent: KVIrc-ProxyClient/4.0\r\n");
671 
672 	if(m_pProxy->hasUser())
673 	{
674 		KviCString szAuth(KviCString::Format, "%s:%s", m_pProxy->user().toUtf8().data(), m_pProxy->pass().toUtf8().data());
675 		KviCString szEncoded;
676 		szEncoded.bufferToBase64(szAuth.ptr(), szAuth.len());
677 		szTmp.append(KviCString::Format, "Proxy-Authorization: Basic %s\r\n\r\n", szEncoded.ptr());
678 	}
679 	else
680 	{
681 		szTmp.append("\r\n");
682 	}
683 
684 	sendRawData(szTmp.ptr(), szTmp.len());
685 }
686 
proxyLoginV4()687 void KviIrcSocket::proxyLoginV4()
688 {
689 	// SOCKSv4 protocol
690 	//
691 	// 1) CONNECT
692 	//
693 	// The client connects to the SOCKS server and sends a CONNECT request when
694 	// it wants to establish a connection to an application server. The client
695 	// includes in the request packet the IP address and the port number of the
696 	// destination host, and userid, in the following format.
697 	//
698 	//                +----+----+----+----+----+----+----+----+----+----+....+----+
699 	//                | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
700 	//                +----+----+----+----+----+----+----+----+----+----+....+----+
701 	// # of bytes:       1    1      2              4           variable       1
702 	//
703 	// VN is the SOCKS protocol version number and should be 4. CD is the
704 	// SOCKS command code and should be 1 for CONNECT request. NULL is a byte
705 	// of all zero bits.
706 	//
707 	// The SOCKS server checks to see whether such a request should be granted
708 	// based on any combination of source IP address, destination IP address,
709 	// destination port number, the userid, and information it may obtain by
710 	// consulting IDENT, cf. RFC 1413.  If the request is granted, the SOCKS
711 	// server makes a connection to the specified port of the destination host.
712 	// A reply packet is sent to the client when this connection is established,
713 	// or when the request is rejected or the operation fails.
714 	//
715 	if(_OUTPUT_VERBOSE)
716 		outputProxyMessage(__tr2qs("Using SOCKSv4 protocol."));
717 
718 	m_pProxy->normalizeUserAndPass();
719 	// the protocol does not specify the "userid" format...
720 	// so build a userid from the pass and/or username...
721 
722 	KviCString szUserAndPass = m_pProxy->user();
723 	if(m_pProxy->hasPass())
724 	{
725 		if(szUserAndPass.hasData())
726 			szUserAndPass.append(' ');
727 		szUserAndPass.append(m_pProxy->pass());
728 	}
729 
730 	int iLen = szUserAndPass.len() + 9;
731 
732 	// build the request packet
733 	char * pcBufToSend = new char[iLen];
734 	pcBufToSend[0] = (unsigned char)4; //Version 4
735 	pcBufToSend[1] = (unsigned char)1; //Connect
736 
737 	quint16 port = (quint16)htons(m_pIrcServer->port());
738 	KviMemory::move((void *)(pcBufToSend + 2), (void *)&port, 2);
739 
740 	struct in_addr ircInAddr;
741 
742 	if(!KviNetUtils::stringIpToBinaryIp(m_pIrcServer->ip(), &ircInAddr))
743 		qDebug("SOCKET INTERNAL ERROR IN IPV4 (SOCKS4) ADDR CONVERSION");
744 
745 	quint32 host = (quint32)ircInAddr.s_addr;
746 	KviMemory::move((void *)(pcBufToSend + 4), (void *)&host, 4);
747 	KviMemory::move((void *)(pcBufToSend + 8), (void *)(szUserAndPass.ptr()), szUserAndPass.len());
748 
749 	pcBufToSend[iLen - 1] = '\0';
750 
751 	// send it into hyperspace...
752 	setState(ProxyFinalV4);
753 	sendRawData(pcBufToSend, iLen);
754 	delete[] pcBufToSend;
755 	// and wait for reply...
756 }
757 
proxyLoginV5()758 void KviIrcSocket::proxyLoginV5()
759 {
760 	// SOCKSv5 protocol.
761 	//
762 	// When a TCP-based client wishes to establish a connection to an object
763 	// that is reachable only via a firewall (such determination is left up
764 	// to the implementation), it must open a TCP connection to the
765 	// appropriate SOCKS port on the SOCKS server system.  The SOCKS service
766 	// is conventionally located on TCP port 1080.  If the connection
767 	// request succeeds, the client enters a negotiation for the
768 	// authentication method to be used, authenticates with the chosen
769 	// method, then sends a relay request.  The SOCKS server evaluates the
770 	// request, and either establishes the appropriate connection or denies
771 	// it.
772 	//
773 	// The client connects to the server, and sends a version
774 	// identifier/method selection message:
775 	//
776 	//                    +----+----------+----------+
777 	//                    |VER | NMETHODS | METHODS  |
778 	//                    +----+----------+----------+
779 	//                    | 1  |    1     | 1 to 255 |
780 	//                    +----+----------+----------+
781 	//
782 	// The VER field is set to X'05' for this version of the protocol.  The
783 	// NMETHODS field contains the number of method identifier octets that
784 	// appear in the METHODS field.
785 	// The values currently defined for METHOD are:
786 	//
787 	//      o  X'00' NO AUTHENTICATION REQUIRED
788 	//      o  X'01' GSSAPI
789 	//      o  X'02' USERNAME/PASSWORD
790 	//      o  X'03' CHAP
791 	//      o  X'04' to X'7F' IANA ASSIGNED
792 	//      o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
793 	//      o  X'FF' NO ACCEPTABLE METHODS
794 	//
795 
796 	if(_OUTPUT_VERBOSE)
797 		outputProxyMessage(__tr2qs("Using SOCKSv5 protocol."));
798 
799 	m_pProxy->normalizeUserAndPass();
800 	// the protocol does not specify the "userid" format...
801 	// so build a userid from the pass and/or username...
802 
803 	char cBufToSend[4];
804 	cBufToSend[0] = (unsigned char)5; //use version 5
805 	int iSendLen = 3;
806 
807 	if(!(m_pProxy->hasUser() || m_pProxy->hasPass()))
808 	{
809 		// no auth needed.
810 		cBufToSend[1] = (unsigned char)1; //select one method
811 		cBufToSend[2] = (unsigned char)0; //select method 0 : no auth
812 		if(_OUTPUT_VERBOSE)
813 			outputProxyMessage(__tr2qs("We can accept auth method 0 (no auth)"));
814 	}
815 	else
816 	{
817 		// we can provide a password and username if needed...
818 		cBufToSend[1] = (unsigned char)2; //select from two methods
819 		cBufToSend[2] = (unsigned char)0; //method 0 or
820 		cBufToSend[3] = (unsigned char)2; //method 2 username/pass auth
821 		iSendLen = 4;
822 		if(_OUTPUT_VERBOSE)
823 			outputProxyMessage(__tr2qs("We can accept auth method 0 (no auth) or 2 (user/pass)"));
824 	}
825 
826 	// notify the user before sending...since we may get disconnected
827 	setState(ProxySelectAuthMethodV5);
828 	sendRawData(cBufToSend, iSendLen);
829 	// and wait for response
830 }
831 
proxyAuthUserPassV5()832 void KviIrcSocket::proxyAuthUserPassV5()
833 {
834 	//   Once the SOCKS V5 server has started, and the client has selected the
835 	//   Username/Password Authentication protocol, the Username/Password
836 	//   subnegotiation begins.  This begins with the client producing a
837 	//   Username/Password request:
838 	//
839 	//           +----+------+----------+------+----------+
840 	//           |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
841 	//           +----+------+----------+------+----------+
842 	//           | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
843 	//           +----+------+----------+------+----------+
844 	//
845 	//   The VER field contains the current version of the subnegotiation,
846 	//   which is X'01'. The ULEN field contains the length of the UNAME field
847 	//   that follows. The UNAME field contains the username as known to the
848 	//   source operating system. The PLEN field contains the length of the
849 	//   PASSWD field that follows. The PASSWD field contains the password
850 	//   association with the given UNAME.
851 	//
852 	unsigned int uPass = (unsigned int)m_pProxy->passLen();
853 	unsigned int uUser = (unsigned int)m_pProxy->userLen();
854 
855 	if(uPass > 255)
856 		uPass = 255;
857 
858 	if(uUser > 255)
859 		uUser = 255;
860 
861 	int iLen = uPass + uUser + 3;
862 	char * pcBufToSend = new char[iLen];
863 
864 	//version x'01'
865 	pcBufToSend[0] = (unsigned char)1;
866 
867 	//length of the username
868 	pcBufToSend[1] = (unsigned char)uUser;
869 
870 	//username
871 	KviMemory::move((void *)(pcBufToSend + 2), (void *)m_pProxy->user().toUtf8().data(), uUser);
872 
873 	//length of the password
874 	pcBufToSend[2 + uUser] = (unsigned char)uPass;
875 	KviMemory::move((void *)(pcBufToSend + 3 + uUser), (void *)m_pProxy->pass().toUtf8().data(), uPass);
876 
877 	// spit out the buffer and wait
878 	setState(ProxyUserPassV5);
879 	sendRawData(pcBufToSend, iLen);
880 	delete[] pcBufToSend;
881 	// and wait for response...
882 }
883 
proxySendTargetDataV5()884 void KviIrcSocket::proxySendTargetDataV5()
885 {
886 	//   Once the method-dependent subnegotiation has completed, the client
887 	//   sends the request details.  If the negotiated method includes
888 	//   encapsulation for purposes of integrity checking and/or
889 	//   confidentiality, these requests MUST be encapsulated in the method-
890 	//   dependent encapsulation.
891 	//
892 	//   The SOCKS request is formed as follows:
893 	//
894 	//           +----+-----+------+------+----------+----------+
895 	//           |VER | CMD | FLAG | ATYP | DST.ADDR | DST.PORT |
896 	//           +----+-----+------+------+----------+----------+
897 	//           | 1  |  1  |  1   |  1   | Variable |    2     |
898 	//           +----+-----+------+------+----------+----------+
899 	//
900 	//   Where:
901 	//
902 	//      o VER    protocol version: X'05'
903 	//      o CMD
904 	//         o CONNECT X'01'
905 	//         o BIND X'02'
906 	//         o UDP ASSOCIATE X'03'
907 	//         o  X'04' to X'7F' IANA ASSIGNED
908 	//         o  X'80' to X'FF' RESERVED FOR PRIVATE METHODS
909 	//      o FLAG   command dependent flag (defaults to X'00')
910 	//      o ATYP   address type of following address
911 	//        o IP V4 address: X'01'
912 	//        o DOMAINNAME: X'03'
913 	//        o IP V6 address: X'04'
914 	//      o DST.ADDR       desired destination address
915 	//      o DST.PORT desired destination port in network octet
916 	//         order
917 	//
918 	//      The SOCKS server will typically evaluate the request based on
919 	//      source and destination addresses, and return one or more reply
920 	//      messages, as appropriate for the request type.
921 	//
922 	//   In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies
923 	//   the type of address contained within the field:
924 	//
925 	//             o  X'01'
926 	//
927 	//   The address is a version-4 IP address, with a length of 4 octets.
928 	//
929 	//             o  X'03'
930 	//
931 	//   The address field contains a fully-qualified domain name.  The first
932 	//   octet of the address field contains the number of octets of name that
933 	//   follow, there is no terminating NUL octet.
934 	//
935 	//             o  X'04'
936 	//
937 	//   The address is a version-6 IP address, with a length of 16 octets.
938 	bool bRemoteDns = !(
939 	    (
940 	        KviNetUtils::isValidStringIp(m_pIrcServer->ip())
941 #ifdef COMPILE_IPV6_SUPPORT
942 	        || KviNetUtils::isValidStringIPv6(m_pIrcServer->ip())
943 #endif
944 	            )
945 
946 	    && m_pIrcServer->cacheIp());
947 	int iBufLen = bRemoteDns ? 4 + 1 + m_pIrcServer->hostName().toUtf8().length() + 2
948 	                         : (m_pIrcServer->isIPv6() ? 22 : 10);
949 	char * pcBufToSend = (char *)KviMemory::allocate(sizeof(char) * iBufLen);
950 	pcBufToSend[0] = (unsigned char)5; //Proto 5
951 	pcBufToSend[1] = (unsigned char)1; //CONNECT
952 	pcBufToSend[2] = (unsigned char)0; //RSV
953 
954 	if(bRemoteDns)
955 	{
956 		bRemoteDns = true;
957 		pcBufToSend[3] = 3;
958 		pcBufToSend[4] = m_pIrcServer->hostName().toUtf8().length();
959 	}
960 	else
961 	{
962 		pcBufToSend[3] = (unsigned char)m_pIrcServer->isIPv6() ? 4 : 1; // IPv6 : IPv4
963 	}
964 
965 	if(bRemoteDns)
966 	{
967 		KviMemory::move((void *)(pcBufToSend + 5),
968 		    (void *)(m_pIrcServer->hostName().toUtf8().data()),
969 		    m_pIrcServer->hostName().toUtf8().length());
970 		quint16 port = (quint16)htons(m_pIrcServer->port());
971 		KviMemory::move((void *)(pcBufToSend + 4 + 1 + m_pIrcServer->hostName().toUtf8().length()), (void *)&port, 2);
972 	}
973 	else if(m_pIrcServer->isIPv6())
974 	{
975 #ifdef COMPILE_IPV6_SUPPORT
976 		struct in6_addr ircInAddr;
977 
978 		if(!KviNetUtils::stringIpToBinaryIp_V6(m_pIrcServer->ip(), &ircInAddr))
979 			qDebug("SOCKET INTERNAL ERROR IN IPV6 ADDR CONVERSION");
980 		KviMemory::move((void *)(pcBufToSend + 4), (void *)(&ircInAddr), 4);
981 		quint16 port = (quint16)htons(m_pIrcServer->port());
982 		KviMemory::move((void *)(pcBufToSend + 20), (void *)&port, 2);
983 #endif
984 	}
985 	else
986 	{
987 		struct in_addr ircInAddr;
988 
989 		if(!KviNetUtils::stringIpToBinaryIp(m_pIrcServer->ip(), &ircInAddr))
990 			qDebug("SOCKET INTERNAL ERROR IN IPV4 ADDR CONVERSION");
991 		quint32 host = (quint32)ircInAddr.s_addr;
992 		KviMemory::move((void *)(pcBufToSend + 4), (void *)&host, 4);
993 		quint16 port = (quint16)htons(m_pIrcServer->port());
994 		KviMemory::move((void *)(pcBufToSend + 8), (void *)&port, 2);
995 	}
996 
997 	// send it into hyperspace...
998 	setState(ProxyFinalV5);
999 	sendRawData(pcBufToSend, iBufLen);
1000 	KviMemory::free(pcBufToSend);
1001 	// and wait for reply...
1002 }
1003 
proxyHandleV5AuthReply(unsigned char cReply)1004 void KviIrcSocket::proxyHandleV5AuthReply(unsigned char cReply)
1005 {
1006 	//   The server verifies the supplied UNAME and PASSWD, and sends the
1007 	//   following response:
1008 	//
1009 	//                        +----+--------+
1010 	//                        |VER | STATUS |
1011 	//                        +----+--------+
1012 	//                        | 1  |   1    |
1013 	//                        +----+--------+
1014 	//
1015 	//   A STATUS field of X'00' indicates success. If the server returns a
1016 	//   `failure' (STATUS value other than X'00') status, it MUST close the
1017 	//   connection.
1018 	//
1019 	if(cReply == 0)
1020 	{
1021 		if(_OUTPUT_VERBOSE)
1022 			outputProxyMessage(__tr2qs("Proxy response: auth OK: access granted"));
1023 		proxySendTargetDataV5();
1024 		return;
1025 	}
1026 	raiseError(KviError::ProxyAuthFailed);
1027 	reset();
1028 }
1029 
proxyHandleV5MethodReply(unsigned char cReply)1030 void KviIrcSocket::proxyHandleV5MethodReply(unsigned char cReply)
1031 {
1032 	//   The server selects from one of the methods given in METHODS, and
1033 	//   sends a METHOD selection message:
1034 	//
1035 	//                            +----+--------+
1036 	//                            |VER | METHOD |
1037 	//                            +----+--------+
1038 	//                            | 1  |   1    |
1039 	//                            +----+--------+
1040 	//
1041 	//   If the selected METHOD is X'FF', none of the methods listed by the
1042 	//   client are acceptable, and the client MUST close the connection.
1043 	//
1044 	// The values currently defined for METHOD are:
1045 	//
1046 	//      o  X'00' NO AUTHENTICATION REQUIRED
1047 	//      o  X'01' GSSAPI
1048 	//      o  X'02' USERNAME/PASSWORD
1049 	//      o  X'03' CHAP
1050 	//      o  X'04' to X'7F' IANA ASSIGNED
1051 	//      o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
1052 	//      o  X'FF' NO ACCEPTABLE METHODS
1053 	//
1054 	if(cReply == 0)
1055 	{
1056 		if(_OUTPUT_VERBOSE)
1057 			outputProxyMessage(__tr2qs("Proxy response: auth method OK: using method 0 (no auth)"));
1058 		proxySendTargetDataV5();
1059 		return;
1060 	}
1061 
1062 	if(cReply == 2)
1063 	{
1064 		if(_OUTPUT_VERBOSE)
1065 			outputProxyMessage(__tr2qs("Proxy response: auth method OK: using method 2 (user/pass)"));
1066 		proxyAuthUserPassV5();
1067 		return;
1068 	}
1069 
1070 	//Request rejected
1071 	if(cReply == 0xFF)
1072 	{
1073 		raiseError(KviError::ProxyNoAcceptableAuthMethod);
1074 		reset();
1075 	}
1076 	else
1077 	{
1078 		// unrecognized...
1079 		raiseError(KviError::UnrecognizedProxyReply);
1080 		reset();
1081 	}
1082 }
1083 
proxyHandleV5FinalReply(unsigned char cReply)1084 void KviIrcSocket::proxyHandleV5FinalReply(unsigned char cReply)
1085 {
1086 	//
1087 	//   The SOCKS request information is sent by the client as soon as it has
1088 	//   established a connection to the SOCKS server, and completed the
1089 	//   authentication negotiations.  The server evaluates the request, and
1090 	//   returns a reply formed as follows:
1091 	//
1092 	//           +----+-----+------+------+----------+----------+
1093 	//           |VER | REP | FLAG | ATYP | BND.ADDR | BND.PORT |
1094 	//           +----+-----+------+------+----------+----------+
1095 	//           | 1  |  1  |  1   |  1   | Variable |    2     |
1096 	//           +----+-----+------+------+----------+----------+
1097 	//
1098 	//   Where:
1099 	//             o  VER    protocol version: X'05'
1100 	//             o  REP    Reply field:
1101 	//                o  X'00' succeeded
1102 	//                o  X'01' general SOCKS server failure
1103 	//                o  X'02' connection not allowed by ruleset
1104 	//                o  X'03' Network unreachable
1105 	//                o  X'04' Host unreachable
1106 	//                o  X'05' Connection refused
1107 	//                o  X'06' TTL expired
1108 	//                o  X'07' Command not supported
1109 	//                o  X'08' Address type not supported
1110 	//                o  X'09' Invalid address
1111 	//                o  X'0A' to X'FF' unassigned
1112 	//             o  FLAG   command dependent flag
1113 	//             o  ATYP   address type of following address
1114 	//                o  IP V4 address: X'01'
1115 	//                o  DOMAINNAME: X'03'
1116 	//                o  IP V6 address: X'04'
1117 	//             o  BND.ADDR       server bound address
1118 	//             o  BND.PORT       server bound port in network octet order
1119 	//
1120 	if(cReply == 0)
1121 	{
1122 		// Request granted
1123 		if(_OUTPUT_VERBOSE)
1124 			outputProxyMessage(__tr2qs("Proxy response: target data OK: request granted"));
1125 		connectedToIrcServer();
1126 	}
1127 	else
1128 	{
1129 		//Request rejected
1130 		KviError::Code eError;
1131 		switch(cReply)
1132 		{
1133 			case 1:
1134 				eError = KviError::ProxyReply01GeneralSOCKSFailure;
1135 				break;
1136 			case 2:
1137 				eError = KviError::ProxyReply02ConnectionNotAllowed;
1138 				break;
1139 			case 3:
1140 				eError = KviError::ProxyReply03NetworkUnreachable;
1141 				break;
1142 			case 4:
1143 				eError = KviError::ProxyReply04HostUnreachable;
1144 				break;
1145 			case 5:
1146 				eError = KviError::ProxyReply05ConnectionRefused;
1147 				break;
1148 			case 6:
1149 				eError = KviError::ProxyReply06TTLExpired;
1150 				break;
1151 			case 7:
1152 				eError = KviError::ProxyReply07CommandNotSupported;
1153 				break;
1154 			case 8:
1155 				eError = KviError::ProxyReply08AddressTypeNotSupported;
1156 				break;
1157 			case 9:
1158 				eError = KviError::ProxyReply09InvalidAddress;
1159 				break;
1160 			default:
1161 				eError = KviError::UnrecognizedProxyReply;
1162 				break;
1163 		}
1164 		raiseError(eError);
1165 		reset();
1166 	}
1167 }
1168 
proxyHandleV4FinalReply(unsigned char cReply)1169 void KviIrcSocket::proxyHandleV4FinalReply(unsigned char cReply)
1170 {
1171 	// If the request is granted, the SOCKS
1172 	// server makes a connection to the specified port of the destination host.
1173 	// A reply packet is sent to the client when this connection is established,
1174 	// or when the request is rejected or the operation fails.
1175 	//
1176 	//
1177 	//                +----+----+----+----+----+----+----+----+
1178 	//                | VN | CD | DSTPORT |      DSTIP        |
1179 	//                +----+----+----+----+----+----+----+----+
1180 	// # of bytes:       1    1      2              4
1181 	//
1182 	// VN is the version of the reply code and should be 0. CD is the result
1183 	// code with one of the following values:
1184 	//
1185 	//        90: request granted
1186 	//        91: request rejected or failed
1187 	//        92: request rejected because SOCKS server cannot connect to
1188 	//            identd on the client
1189 	//        93: request rejected because the client program and identd
1190 	//            report different user-ids
1191 	//
1192 	// The remaining fields are ignored.
1193 	//
1194 	// The SOCKS server closes its connection immediately after notifying
1195 	// the client of a failed or rejected request. For a successful request,
1196 	// the SOCKS server gets ready to relay traffic on both directions. This
1197 	// enables the client to do I/O on its connection as if it were directly
1198 	// connected to the application server.
1199 	if(cReply == 90)
1200 	{
1201 		// Request granted
1202 		if(_OUTPUT_VERBOSE)
1203 			outputProxyMessage(__tr2qs("Proxy response: target data OK: request granted"));
1204 		connectedToIrcServer();
1205 	}
1206 	else
1207 	{
1208 		//Request rejected
1209 		KviError::Code eError;
1210 		switch(cReply)
1211 		{
1212 			case 91:
1213 				eError = KviError::ProxyReply91RequestFailed;
1214 				break;
1215 			case 92:
1216 				eError = KviError::ProxyReply92IdentFailed;
1217 				break;
1218 			case 93:
1219 				eError = KviError::ProxyReply93IdentNotMatching;
1220 				break;
1221 			default:
1222 				eError = KviError::UnrecognizedProxyReply;
1223 				break;
1224 		}
1225 		raiseError(eError);
1226 		reset();
1227 	}
1228 	// Just looked out of the window...
1229 	// Hmmmm...strange light outside...
1230 	// Looked at the clock...6:34 !
1231 	// I think I'll go sleep.... :)
1232 }
1233 
proxyHandleHttpFinalReply(const char * pcBuffer,int)1234 void KviIrcSocket::proxyHandleHttpFinalReply(const char * pcBuffer, int)
1235 {
1236 	// Escape character is '^]'.
1237 	// CONNECT warszawa.irc.pl:6667 HTTP/1.0
1238 	//
1239 	// HTTP/1.0 200 Connection established
1240 
1241 	KviCString szTmp = pcBuffer;
1242 	// FIXME: #warning "We could even show the proxy output here...!"
1243 	szTmp.cutFromFirst('\n');
1244 	szTmp.trim();
1245 
1246 	if(kvi_strEqualCIN(szTmp.ptr(), "HTTP", 4))
1247 	{
1248 		int iIdx = szTmp.findFirstIdx(" 200 ");
1249 		if(iIdx != -1)
1250 		{
1251 			if(iIdx == szTmp.findFirstIdx(' '))
1252 			{
1253 				QString szMsg = __tr2qs("Proxy response: ");
1254 				szMsg += szTmp.ptr();
1255 				if(_OUTPUT_VERBOSE)
1256 					outputProxyMessage(szMsg);
1257 				connectedToIrcServer();
1258 				return;
1259 			}
1260 		}
1261 	}
1262 
1263 	outputProxyError(__tr2qs("Proxy said something about: \n"));
1264 	outputProxyMessage(m_pConsole->decodeText(pcBuffer));
1265 
1266 	//Read HTTP error page and show it
1267 
1268 	if(m_pWsn)
1269 	{
1270 		delete m_pWsn;
1271 		m_pWsn = nullptr;
1272 	}
1273 
1274 	if(m_pRsn)
1275 	{
1276 		delete m_pRsn;
1277 		m_pRsn = nullptr;
1278 	}
1279 
1280 	m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
1281 	QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(readHttpProxyErrorData(int)));
1282 	m_pRsn->setEnabled(true);
1283 
1284 	setState(ProxyHttpError);
1285 
1286 }
1287 
1288 //
1289 // SSL HANDSHAKE
1290 //
1291 
1292 #ifdef COMPILE_SSL_SUPPORT
printSSLPeerCertificate()1293 void KviIrcSocket::printSSLPeerCertificate()
1294 {
1295 	KviSSLCertificate * c = m_pSSL->getPeerCertificate();
1296 	if(c)
1297 	{
1298 		//m_pConsole->socketEvent(SSLCertificate,(void *)c);
1299 		if(_OUTPUT_VERBOSE)
1300 			KviSSLMaster::printSSLCertificate(m_pConsole, __tr("Server X509 certificate"), c);
1301 		delete c;
1302 	}
1303 	else
1304 	{
1305 		if(_OUTPUT_VERBOSE)
1306 			outputSSLMessage(__tr2qs("The server didn't provide a certificate"));
1307 	}
1308 }
1309 
printSSLCipherInfo()1310 void KviIrcSocket::printSSLCipherInfo()
1311 {
1312 	KviSSLCipherInfo * ci = m_pSSL->getCurrentCipherInfo();
1313 	if(ci)
1314 	{
1315 		KviSSLMaster::printSSLCipherInfo(m_pConsole, __tr("Current transmission cipher"), ci);
1316 		delete ci;
1317 	}
1318 	else
1319 	{
1320 		if(_OUTPUT_VERBOSE)
1321 			outputSSLMessage(__tr2qs("Unable to determine the current cipher"));
1322 	}
1323 }
1324 
raiseSSLError()1325 void KviIrcSocket::raiseSSLError()
1326 {
1327 	KviCString szBuffer;
1328 	while(m_pSSL->getLastErrorString(szBuffer))
1329 	{
1330 		outputSSLError(szBuffer.ptr());
1331 	}
1332 }
1333 #endif // COMPILE_SSL_SUPPORT
1334 
doSSLHandshake(int)1335 void KviIrcSocket::doSSLHandshake(int)
1336 {
1337 #ifdef COMPILE_SSL_SUPPORT
1338 	KVI_ASSERT(m_pSSL);
1339 
1340 	if(m_pRsn)
1341 	{
1342 		delete m_pRsn;
1343 		m_pRsn = nullptr;
1344 	}
1345 
1346 	if(m_pWsn)
1347 	{
1348 		delete m_pWsn;
1349 		m_pWsn = nullptr;
1350 	}
1351 
1352 	if(!m_pSSL)
1353 	{
1354 		qDebug("Oops! Have I lost the SSL class?");
1355 		reset();
1356 		return; // ops ?
1357 	}
1358 
1359 	switch(m_pSSL->connect())
1360 	{
1361 		case KviSSL::Success:
1362 			// done!
1363 			printSSLCipherInfo();
1364 			printSSLPeerCertificate();
1365 			linkUp();
1366 			break;
1367 		case KviSSL::WantRead:
1368 			m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
1369 			QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(doSSLHandshake(int)));
1370 			m_pRsn->setEnabled(true);
1371 			break;
1372 		case KviSSL::WantWrite:
1373 			m_pWsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Write);
1374 			QObject::connect(m_pWsn, SIGNAL(activated(int)), this, SLOT(doSSLHandshake(int)));
1375 			m_pWsn->setEnabled(true);
1376 			break;
1377 		case KviSSL::RemoteEndClosedConnection:
1378 			raiseError(KviError::RemoteEndClosedConnection);
1379 			reset();
1380 			break;
1381 		case KviSSL::SSLError:
1382 			raiseSSLError();
1383 			raiseError(KviError::SSLError);
1384 			reset();
1385 			break;
1386 		case KviSSL::SyscallError:
1387 		{
1388 			// syscall problem
1389 			int iErr = kvi_socket_error();
1390 			if(!kvi_socket_recoverableError(iErr))
1391 			{
1392 				// Declare problems :)
1393 				raiseError((iErr ? KviError::translateSystemError(iErr) : KviError::UnknownError));
1394 			}
1395 			else
1396 			{
1397 				// can recover ? (EAGAIN, EINTR ?)
1398 				m_pWsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Write);
1399 				QObject::connect(m_pWsn, SIGNAL(activated(int)), this, SLOT(doSSLHandshake(int)));
1400 				m_pWsn->setEnabled(true);
1401 				return;
1402 			}
1403 			reset();
1404 		}
1405 		break;
1406 		default:
1407 			raiseError(KviError::SSLError);
1408 			reset();
1409 			break;
1410 	}
1411 
1412 #else  //COMPILE_SSL_SUPPORT
1413 	qDebug("Oops! SSL handshake without SSL support. Aborting!");
1414 	exit(-1);
1415 #endif //COMPILE_SSL_SUPPORT
1416 }
1417 
1418 //
1419 // LINK UP
1420 //
1421 
linkUp()1422 void KviIrcSocket::linkUp()
1423 {
1424 	setState(Connected);
1425 
1426 	// the last check
1427 	if(m_sock == KVI_INVALID_SOCKET)
1428 		return; // ops...disconnected in setState() ????
1429 
1430 	// OK.. it seems that we're really up and running now!
1431 	if(m_pWsn)
1432 	{
1433 		delete m_pWsn;
1434 		m_pWsn = nullptr;
1435 	}
1436 
1437 	if(m_pRsn)
1438 	{
1439 		delete m_pRsn;
1440 		m_pRsn = nullptr;
1441 	}
1442 
1443 	m_pRsn = new QSocketNotifier((int)m_sock, QSocketNotifier::Read);
1444 	QObject::connect(m_pRsn, SIGNAL(activated(int)), this, SLOT(readData(int)));
1445 	m_pRsn->setEnabled(true);
1446 }
1447 
readData(int)1448 void KviIrcSocket::readData(int)
1449 {
1450 	//read data
1451 	char cBuffer[1025];
1452 	int iReadLength;
1453 #ifdef COMPILE_SSL_SUPPORT
1454 	if(m_pSSL)
1455 	{
1456 		iReadLength = m_pSSL->read(cBuffer, 1024);
1457 		if(iReadLength <= 0)
1458 		{
1459 			// ssl error....?
1460 			switch(m_pSSL->getProtocolError(iReadLength))
1461 			{
1462 				case KviSSL::ZeroReturn:
1463 					iReadLength = 0;
1464 					break;
1465 				case KviSSL::WantRead:
1466 				case KviSSL::WantWrite:
1467 					// hmmm...
1468 					return;
1469 					break;
1470 				case KviSSL::SyscallError:
1471 				{
1472 					int iE = m_pSSL->getLastError(true);
1473 					if(iE != 0)
1474 					{
1475 						raiseSSLError();
1476 						raiseError(KviError::SSLError);
1477 						reset();
1478 						return;
1479 					}
1480 				}
1481 				break;
1482 				case KviSSL::SSLError:
1483 					raiseSSLError();
1484 					raiseError(KviError::SSLError);
1485 					reset();
1486 					return;
1487 					break;
1488 				default:
1489 					raiseError(KviError::SSLError);
1490 					reset();
1491 					return;
1492 					break;
1493 			}
1494 			handleInvalidSocketRead(iReadLength);
1495 			return;
1496 		}
1497 	}
1498 	else
1499 	{
1500 #endif
1501 		iReadLength = kvi_socket_recv(m_sock, cBuffer, 1024);
1502 		if(iReadLength <= 0)
1503 		{
1504 			handleInvalidSocketRead(iReadLength);
1505 			return;
1506 		}
1507 #ifdef COMPILE_SSL_SUPPORT
1508 	}
1509 #endif
1510 
1511 	//terminate our buffer
1512 	(*(cBuffer + iReadLength)) = '\0';
1513 
1514 	m_uReadBytes += iReadLength;
1515 
1516 	// Shut up the socket notifier
1517 	// in case that we enter in a local loop somewhere
1518 	// while processing data...
1519 	m_pRsn->setEnabled(false);
1520 	// shut also the flushing of the message queue
1521 	// in this way we prevent disconnect detection
1522 	// during the processing of a message effectively
1523 	// making it always an asynchronous event.
1524 	m_bInProcessData = true;
1525 
1526 	m_pLink->processData(cBuffer, iReadLength);
1527 	// after this line there should be nothing that relies
1528 	// on the "connected" state of this socket.
1529 	// It may happen that it has been reset() in the middle of the processData() call
1530 	// and (unverified) it might have been even deleted.
1531 
1532 	// re-enable the socket notifier... (if it's still there)
1533 	if(m_pRsn)
1534 		m_pRsn->setEnabled(true);
1535 	// and the message queue flushing
1536 	m_bInProcessData = false;
1537 	// and flush the queue too!
1538 	if(m_pSendQueueHead)
1539 		flushSendQueue();
1540 }
1541 
abort()1542 void KviIrcSocket::abort()
1543 {
1544 	// flush the send queue if possible (and if not yet disconnected in fact)
1545 	if(m_state == Connected)
1546 		flushSendQueue();
1547 	if(m_state != Idle)
1548 		raiseError(KviError::OperationAborted);
1549 	// and reset
1550 	reset();
1551 }
1552 
handleInvalidSocketRead(int iReadLength)1553 void KviIrcSocket::handleInvalidSocketRead(int iReadLength)
1554 {
1555 	KVI_ASSERT(iReadLength <= 0);
1556 	if(iReadLength == 0)
1557 	{
1558 		raiseError(KviError::RemoteEndClosedConnection);
1559 		reset();
1560 	}
1561 	else
1562 	{
1563 		//check for transmission errors
1564 		int iErr = kvi_socket_error();
1565 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
1566 		if((iErr != EAGAIN) && (iErr != EINTR) && (iErr != WSAEWOULDBLOCK))
1567 #else
1568 		if((iErr != EAGAIN) && (iErr != EINTR))
1569 #endif
1570 		{
1571 			if(iErr > 0)
1572 				raiseError((KviError::translateSystemError(iErr)));
1573 			else
1574 				raiseError(KviError::RemoteEndClosedConnection);
1575 			reset();
1576 		} //else transient error...wait again...
1577 	}
1578 }
1579 
queue_insertMessage(KviIrcSocketMsgEntry * pMsg)1580 void KviIrcSocket::queue_insertMessage(KviIrcSocketMsgEntry * pMsg)
1581 {
1582 	KVI_ASSERT(pMsg);
1583 
1584 	pMsg->next_ptr = nullptr;
1585 
1586 	if(m_pSendQueueHead)
1587 	{
1588 		m_pSendQueueTail->next_ptr = pMsg;
1589 		m_pSendQueueTail = pMsg;
1590 	}
1591 	else
1592 	{
1593 		m_pSendQueueHead = pMsg;
1594 		m_pSendQueueTail = pMsg;
1595 	}
1596 }
1597 
free_msgEntry(KviIrcSocketMsgEntry * e)1598 void KviIrcSocket::free_msgEntry(KviIrcSocketMsgEntry * e)
1599 {
1600 	if(e->pData)
1601 		delete e->pData;
1602 
1603 	e->pData = nullptr;
1604 	KviMemory::free(e);
1605 }
1606 
queue_removeMessage()1607 bool KviIrcSocket::queue_removeMessage()
1608 {
1609 	KVI_ASSERT(m_pSendQueueTail);
1610 	KVI_ASSERT(m_pSendQueueHead);
1611 
1612 	if(m_pSendQueueHead->pData)
1613 		delete m_pSendQueueHead->pData;
1614 
1615 	KviIrcSocketMsgEntry * pEntry = m_pSendQueueHead;
1616 	m_pSendQueueHead = pEntry->next_ptr;
1617 	KviMemory::free((void *)pEntry);
1618 
1619 	if(m_pSendQueueHead == nullptr)
1620 	{
1621 		m_pSendQueueTail = nullptr;
1622 		return false;
1623 	}
1624 	else
1625 		return true;
1626 }
1627 
queue_removeAllMessages()1628 void KviIrcSocket::queue_removeAllMessages()
1629 {
1630 	if(m_pSendQueueHead)
1631 		while(queue_removeMessage())
1632 		{
1633 		}
1634 }
1635 
queue_removePrivateMessages()1636 void KviIrcSocket::queue_removePrivateMessages()
1637 {
1638 	KviIrcSocketMsgEntry * pPrevEntry = nullptr;
1639 	KviIrcSocketMsgEntry * pEntry = m_pSendQueueHead;
1640 	while(pEntry)
1641 	{
1642 		if(pEntry->pData->size() > 7)
1643 		{
1644 			if(kvi_strEqualCIN((char *)(pEntry->pData->data()), "PRIVMSG", 7))
1645 			{
1646 				// remove it
1647 				if(pPrevEntry)
1648 				{
1649 					pPrevEntry->next_ptr = pEntry->next_ptr;
1650 					if(!pPrevEntry->next_ptr)
1651 						m_pSendQueueTail = nullptr;
1652 					free_msgEntry(pEntry);
1653 					pEntry = pPrevEntry->next_ptr;
1654 				}
1655 				else
1656 				{
1657 					m_pSendQueueHead = pEntry->next_ptr;
1658 					if(!m_pSendQueueHead)
1659 						m_pSendQueueTail = nullptr;
1660 					free_msgEntry(pEntry);
1661 					pEntry = m_pSendQueueHead;
1662 				}
1663 				continue;
1664 			}
1665 		}
1666 		pPrevEntry = pEntry;
1667 		pEntry = pEntry->next_ptr;
1668 	}
1669 }
1670 
flushSendQueue()1671 void KviIrcSocket::flushSendQueue()
1672 {
1673 	// If we're called from the flush timer, stop it
1674 	if(m_pFlushTimer->isActive())
1675 		m_pFlushTimer->stop();
1676 
1677 	// OK...have something to send...
1678 	KVI_ASSERT(m_state != Idle);
1679 
1680 	struct timeval curTime;
1681 
1682 	while(m_pSendQueueHead)
1683 	{
1684 		if(KVI_OPTION_BOOL(KviOption_boolLimitOutgoingTraffic))
1685 		{
1686 			kvi_gettimeofday(&curTime);
1687 
1688 			int iTimeDiff = curTime.tv_usec - m_tAntiFloodLastMessageTime.tv_usec;
1689 			iTimeDiff += (curTime.tv_sec - m_tAntiFloodLastMessageTime.tv_sec) * 1000000;
1690 
1691 			if(((unsigned int)iTimeDiff) < KVI_OPTION_UINT(KviOption_uintOutgoingTrafficLimitUSeconds))
1692 			{
1693 				// need to wait for a while....
1694 				m_pFlushTimer->start(((KVI_OPTION_UINT(KviOption_uintOutgoingTrafficLimitUSeconds) - iTimeDiff) / 1000) + 1);
1695 				return;
1696 			} // else can send
1697 		}
1698 		// Write one data buffer...
1699 		int iResult;
1700 #ifdef COMPILE_SSL_SUPPORT
1701 		if(m_pSSL)
1702 		{
1703 			iResult = m_pSSL->write((char *)(m_pSendQueueHead->pData->data()), m_pSendQueueHead->pData->size());
1704 		}
1705 		else
1706 		{
1707 #endif
1708 			iResult = kvi_socket_send(m_sock, (char *)(m_pSendQueueHead->pData->data()), m_pSendQueueHead->pData->size());
1709 #ifdef COMPILE_SSL_SUPPORT
1710 		}
1711 #endif
1712 		if(iResult == (int)m_pSendQueueHead->pData->size())
1713 		{
1714 			// Successful send...remove this data buffer
1715 			m_uSentPackets++;
1716 			m_uSentBytes += iResult;
1717 			//if(m_pConsole->hasMonitors())outgoingMessageNotifyMonitors((char *)(m_pSendQueueHead->pData->data()),result);
1718 			queue_removeMessage();
1719 			if(KVI_OPTION_BOOL(KviOption_boolLimitOutgoingTraffic))
1720 			{
1721 				m_tAntiFloodLastMessageTime.tv_sec = curTime.tv_sec;
1722 				m_tAntiFloodLastMessageTime.tv_usec = curTime.tv_usec;
1723 			}
1724 			// And try next buffer...
1725 			continue;
1726 		}
1727 		else
1728 		{
1729 // Something wrong ?
1730 #ifdef COMPILE_SSL_SUPPORT
1731 			if(iResult <= 0)
1732 			{
1733 				if(m_pSSL)
1734 				{
1735 					// ops...might be an SSL error
1736 					switch(m_pSSL->getProtocolError(iResult))
1737 					{
1738 						case KviSSL::WantWrite:
1739 						case KviSSL::WantRead:
1740 							// Async continue...
1741 							m_pFlushTimer->start(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout));
1742 							return;
1743 							break;
1744 						case KviSSL::SyscallError:
1745 							if(iResult == 0)
1746 							{
1747 								raiseSSLError();
1748 								raiseError(KviError::RemoteEndClosedConnection);
1749 								reset();
1750 								return;
1751 							}
1752 							else
1753 							{
1754 								int iSSLErr = m_pSSL->getLastError(true);
1755 								if(iSSLErr != 0)
1756 								{
1757 									raiseSSLError();
1758 									raiseError(KviError::SSLError);
1759 									reset();
1760 									return;
1761 								}
1762 								else
1763 								{
1764 									goto handle_system_error;
1765 								}
1766 							}
1767 							break;
1768 						case KviSSL::SSLError:
1769 							raiseSSLError();
1770 							raiseError(KviError::SSLError);
1771 							reset();
1772 							return;
1773 							break;
1774 						default:
1775 							raiseError(KviError::SSLError);
1776 							reset();
1777 							return;
1778 							break;
1779 					}
1780 				}
1781 			}
1782 			else
1783 			{
1784 #else  // COMPILE_SSL_SUPPORT
1785 			if(iResult >= 0)
1786 			{
1787 				if(iResult > 0)
1788 				{
1789 #endif // COMPILE_SSL_SUPPORT
1790 
1791 				// Partial send...need to finish it later
1792 				m_pSendQueueHead->pData->remove(iResult);
1793 
1794 				m_uSentBytes += iResult;
1795 				if(_OUTPUT_VERBOSE)
1796 					outputSocketWarning(__tr2qs("Partial socket write: packet broken into smaller pieces."));
1797 #ifndef COMPILE_SSL_SUPPORT
1798 			}
1799 #endif // COMPILE_SSL_SUPPORT
1800 			// Async continue...
1801 			m_pFlushTimer->start(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout));
1802 			return;
1803 		}
1804 
1805 	handle_system_error:
1806 		// Oops...error ?
1807 		int iErr = kvi_socket_error();
1808 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
1809 		if((iErr == EAGAIN) || (iErr == EINTR) || (iErr == WSAEWOULDBLOCK))
1810 #else
1811 				if((iErr == EAGAIN) || (iErr == EINTR))
1812 #endif
1813 		{
1814 			// Transient error...partial send as before...
1815 			if(_OUTPUT_VERBOSE)
1816 				outputSocketWarning(__tr2qs("Partial socket write: packet broken into smaller pieces."));
1817 			// Async continue...
1818 			m_pFlushTimer->start(KVI_OPTION_UINT(KviOption_uintSocketQueueFlushTimeout));
1819 			return;
1820 		}
1821 		else
1822 		{
1823 			// Disconnected... :(
1824 			raiseError((KviError::translateSystemError(iErr)));
1825 			reset();
1826 			return;
1827 		}
1828 	}
1829 }
1830 //flushed completely ...
1831 }
1832 
1833 bool KviIrcSocket::getLocalHostIp(QString & szIp, bool bIPv6)
1834 {
1835 	if(m_state != Connected)
1836 		return false;
1837 
1838 	if(bIPv6)
1839 	{
1840 #ifdef COMPILE_IPV6_SUPPORT
1841 		struct sockaddr_in6 name;
1842 		int iLen = sizeof(name);
1843 		if(!kvi_socket_getsockname(m_sock, (struct sockaddr *)&name, &iLen))
1844 			return false;
1845 		//I assume that getsockname returns data in Network byte order...
1846 		//The man page misses to specify that...
1847 		if(!KviNetUtils::binaryIpToStringIp_V6(name.sin6_addr, szIp))
1848 			return false;
1849 
1850 		return true;
1851 #else
1852 			return false; // no support
1853 #endif
1854 	}
1855 
1856 	struct sockaddr_in name;
1857 	int iLen = sizeof(name);
1858 	if(!kvi_socket_getsockname(m_sock, (struct sockaddr *)&name, &iLen))
1859 		return false;
1860 	//I assume that getsockname returns data in Network byte order...
1861 	//The man page misses to specify that...
1862 	if(!KviNetUtils::binaryIpToStringIp(name.sin_addr, szIp))
1863 		return false;
1864 
1865 	return true;
1866 }
1867 
1868 /*
1869 bool KviIrcSocket::sendFmtData(const char *fmt,...)
1870 {
1871 	if(m_state != Connected)return false;
1872 	//new buffer
1873 	KviIrcSocketMsgEntry *ptr = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1874 	ptr->pData = new KviDataBuffer(512);
1875 	kvi_va_list(list);
1876 	kvi_va_start(list,fmt);
1877 	bool bTruncated;
1878 	//sprintf the buffer up to 512 chars (adds a CRLF too)
1879 	int iLen = kvi_irc_vsnprintf((char *)(ptr->pData->data()),fmt,list,&bTruncated);
1880 	kvi_va_end(list);
1881 	//adjust the buffer size
1882 	if(iLen < 512)ptr->pData->resize(iLen);
1883 	if(bTruncated)
1884 	{
1885 		if(_OUTPUT_VERBOSE)
1886 			outputSocketWarning(__tr2qs("Socket message truncated to 512 bytes."));
1887 	}
1888 
1889 	queue_insertMessage(ptr);
1890 	if(!m_bInProcessData)flushSendQueue();
1891 	return (m_state != Idle);
1892 }
1893 */
1894 /*
1895 bool KviIrcSocket::sendData(const char *buffer,int buflen)
1896 {
1897 	if(m_state != Connected)return false;
1898 	//new buffer
1899 	KviIrcSocketMsgEntry *ptr = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1900 	if(buflen < 0)buflen = strlen(buffer);
1901 	if(buflen > 510)
1902 	{
1903 		buflen = 510;
1904 		if(_OUTPUT_VERBOSE)
1905 			outputSocketWarning(__tr2qs("Socket message truncated to 512 bytes."));
1906 	}
1907 	ptr->pData = new KviDataBuffer(buflen + 2);
1908 	KviMemory::move(ptr->pData->data(),buffer,buflen);
1909 	*(ptr->pData->data()+buflen)='\r';
1910 	*(ptr->pData->data()+buflen+1)='\n';
1911 
1912 	queue_insertMessage(ptr);
1913 	if(!m_bInProcessData)flushSendQueue();
1914 	return (m_state != Idle);
1915 }
1916 */
1917 
1918 bool KviIrcSocket::sendRawData(const char * pcBuffer, int iBuflen)
1919 {
1920 	if((m_state == Idle) || (m_state == Connecting))
1921 		return false;
1922 
1923 	//new buffer
1924 	KviIrcSocketMsgEntry * pEntry = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1925 	pEntry->pData = new KviDataBuffer(iBuflen);
1926 
1927 	KviMemory::move(pEntry->pData->data(), pcBuffer, iBuflen);
1928 	queue_insertMessage(pEntry);
1929 
1930 	if(!m_bInProcessData)
1931 		flushSendQueue();
1932 
1933 	return (m_state != Idle);
1934 }
1935 
1936 bool KviIrcSocket::sendPacket(KviDataBuffer * pData)
1937 {
1938 	if(m_state != Connected)
1939 	{
1940 		delete pData;
1941 		pData = nullptr;
1942 		return false;
1943 	}
1944 
1945 	KviIrcSocketMsgEntry * pEntry = (KviIrcSocketMsgEntry *)KviMemory::allocate(sizeof(KviIrcSocketMsgEntry));
1946 	pEntry->pData = pData;
1947 	queue_insertMessage(pEntry);
1948 
1949 	if(!m_bInProcessData)
1950 		flushSendQueue();
1951 
1952 	return (m_state != Idle);
1953 }
1954