1 /***************************************************************************
2                           cclient.cpp  -  description
3                              -------------------
4     begin                : Sun Sep 30 2001
5     copyright            : (C) 2001-2004 by Mathias Küster
6     email                : mathen@users.berlios.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "cclient.h"
19 
20 #include <stdio.h>
21 #include <sys/types.h>
22 
23 #ifndef WIN32
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netdb.h>
29 #endif
30 
31 #include "core/clist.h"
32 #include "dcobject.h"
33 #include "cquerymanager.h"
34 #include "cdownloadmanager.h"
35 #include "cconnectionmanager.h"
36 #include "cencrypt.h"
37 #include "cmessagehandler.h"
38 #include "cconfig.h"
39 #include "csearchmanager.h"
40 #include "clistenmanager.h"
41 #include "dclib-ssl-use.h"
42 
43 // need to decompress zpipe data
44 #include "core/czlib.h"
45 #include "core/cbytearray.h"
46 
47 // for DPRINTF
48 #include "dclib.h"
49 
50 // IsPrivateI4() and IsValidI4()
51 #include "core/cnetaddr.h"
52 
CClient(CString remoteEncoding)53 CClient::CClient( CString remoteEncoding ) : CDCProto( remoteEncoding )
54 {
55 	m_pCallback = 0;
56 
57 	m_bHandshake       = true;
58 	m_bHandleUserList  = true;
59 	m_bHandleSearch    = true;
60 	m_bHandleMyinfo    = true;
61 	m_bHandleForceMove = true;
62 	m_bHandleTransfer  = true;
63 	m_bUpdateMyinfo    = false;
64 	m_bSendMyinfo      = true;
65 	m_bSSLMode         = false;
66 	m_nNickListHandler = 0;
67 	m_bUsedPassword    = false;
68 
69 	// set reconnect parameter
70 	m_eReconnectState      = ersNONE;
71 	m_nReconnectCount      = 0;
72 	m_timeReconnectTimeout = 0;
73 	m_timeMyinfoTimeout    = 0;
74 
75 	// initialise settings used since hub supports message cannot be used
76 	m_bExtProtocol = false;
77 	m_bGotIP       = false;
78 
79 	// zpipe handling
80 	m_pZLib = 0;
81 	m_bZMode = false;
82 
83 	// message parser
84 	m_pMessageHandler = new CMessageHandler( remoteEncoding );
85 
86 #if DCLIB_HAS_SSL == 1
87 	if ( CConfig::Instance() )
88 	{
89 		m_MyInfo.m_bTLSFlag = ( CConfig::Instance()->GetTransferCert().NotEmpty() && CConfig::Instance()->GetTransferKey().NotEmpty() );
90 	}
91 #endif
92 }
93 
~CClient()94 CClient::~CClient()
95 {
96 	SetCallBackFunction(0);
97 
98 	delete m_pZLib;
99 	m_pZLib = 0;
100 
101 	delete m_pMessageHandler;
102 	m_pMessageHandler = 0;
103 }
104 
105 /** */
ConnectionState(eConnectionState state)106 void CClient::ConnectionState( eConnectionState state )
107 {
108 	int err = -1;
109 
110 	CMessageConnectionState *Object = new CMessageConnectionState();
111 
112 	if ( (state == estCONNECTED) ||
113 	     (state == estDISCONNECTED) )
114 	{
115 		// reset all values
116 		m_sBuffer.Empty();
117 		m_bHandshake        = true;
118 		m_timeMyinfoTimeout = time(0);
119 		m_nNickListHandler  = 0;
120 
121 		m_bExtProtocol = false;
122 		m_bGotIP       = false;
123 
124 		m_UserList.Clear();
125 
126 		m_bZMode = false;
127 		delete m_pZLib;
128 		m_pZLib = 0;
129 #if DCLIB_HAS_SSL == 1
130 		m_pMessageSSL.Init();
131 #endif
132 		// update reconnect state
133 		if ( state == estCONNECTED )
134 		{
135 			UpdateReconnect( ersNONE );
136 
137 			if ( m_bSSLMode && CConfig::Instance() )
138 			{
139 				if ( ChangeSocketMode( esmSSLCLIENT, CConfig::Instance()->GetTransferCert(), CConfig::Instance()->GetTransferKey() ) == false )
140 				{
141 					printf("change ssl mode failed\n");
142 				}
143 			}
144 		}
145 		else
146 		{
147 			if ( m_eReconnectState == ersFORCEMOVE )
148 			{
149 				UpdateReconnect( ersNONE );
150 			}
151 			else
152 			{
153 				UpdateReconnect( ersENABLED );
154 			}
155 		}
156 	}
157 
158 	Object->m_eState   = state;
159 	Object->m_sMessage = GetSocketError();
160 
161 	if ( m_pCallback != 0 )
162 	{
163 		err = m_pCallback->notify( this, Object );
164 	}
165 	else
166 	{
167 		err = DC_CallBack( Object );
168 	}
169 
170 	// callback failed
171 	if ( err == -1 )
172 	{
173 		delete Object;
174 	}
175 
176 	// update myinfo
177 	if ( m_bHandleMyinfo && CConnectionManager::Instance() )
178 	{
179 		CConnectionManager::Instance()->SendMyInfoToConnectedServers();
180 	}
181 }
182 
183 /** */
DataAvailable(const char * buffer,int len)184 void CClient::DataAvailable( const char * buffer, int len )
185 {
186 	CString s;
187 	int i = 0;
188 
189 	if ( len <= 0 )
190 	{
191 		return;
192 	}
193 
194 	// add traffic control
195 	CSocket::m_Traffic.AddTraffic(ettCONTROLRX,len);
196 
197 	if ( m_bZMode )
198 	{
199 		int inlen = len;
200 		CString trailing;
201 
202 		if ( m_pZLib == 0 )
203 		{
204 			m_pZLib = new CZLib();
205 		}
206 
207 		int outlen = 1024*100; // same as what CTransfer uses
208 		CByteArray * out = new CByteArray(outlen);
209 
210 		//printf( "before inlen=%d outlen=%d ", inlen, outlen );
211 		const int zlibstatus = m_pZLib->InflateZBlock( buffer, &inlen, (char*)out->Data(), &outlen );
212 		//printf( "after inlen=%d outlen=%d\n", inlen, outlen );
213 
214 		if ( zlibstatus == -1 )
215 		{
216 			printf("CClient: ZPipe decompress error, returning to normal mode\n");
217 			delete m_pZLib;
218 			m_pZLib = 0;
219 			m_bZMode = false;
220 		}
221 		else if ( zlibstatus == 0 )
222 		{
223 			//printf("ZPipe: finished decompressing data, leaving zmode\n");
224 			delete m_pZLib;
225 			m_pZLib = 0;
226 			m_bZMode = false;
227 
228 			/*
229 			 * Check for uncompressed data after compressed data.
230 			 * In 0.3.19 there was usually data after the compressed data
231 			 * which got ignored, because it put the compressed data
232 			 * into m_sBuffer and did not send it to zlib until
233 			 * some more data was received.
234 			 */
235 			if ( inlen < len )
236 			{
237 				trailing.Set( buffer+inlen, len-inlen );
238 			}
239 		}
240 
241 		if ( ((zlibstatus == 0) || (zlibstatus == 1)) && (outlen > 0) )
242 		{
243 			s = m_sBuffer + CString().Set((char*)out->Data(),outlen);
244 			m_sBuffer.Empty();
245 
246 			if ( trailing.NotEmpty() )
247 			{
248 				s += trailing;
249 			}
250 
251 			//printf("ZPipe result: '%s'\n",s.Data());
252 		}
253 
254 		delete out;
255 	}
256 	else
257 	{
258 		s = m_sBuffer + CString().Set(buffer,len);
259 
260 		/* contents of buffer have been used, empty it to make sure it does not get used again */
261 		m_sBuffer.Empty();
262 	}
263 
264 	/* If ZPipe is enabled, we must search forwards for $ZOn|
265 	 * in case there is a | within the compressed data.
266 	 *
267 	 * And since hub supports negotiation is useless, we had better
268 	 * assume ZPipe is always enabled.
269 	 */
270 	i = s.Find("$ZOn|");
271 	if ( i >= 0 )
272 	{
273 		/* Handle all messages up to but not including $ZOn| */
274 		HandleMessage( s.Mid(0,i) );
275 
276 		/* Handle $ZOn| and advance i */
277 		m_bZMode = true;
278 		i += 5;
279 
280 		if ( i < s.Length() )
281 		{
282 			/*
283 			 * Handle the compressed data.
284 			 */
285 			DataAvailable( s.Data()+i, s.Length()-i );
286 		}
287 
288 		return;
289 	}
290 
291 	/* No ZPipe support or $ZOn| not found */
292 	i = s.FindRev('|') + 1;
293 
294 	if ( i > 0 )
295 	{
296 		HandleMessage( s.Mid(0,i) );
297 	}
298 
299 	if ( i < s.Length() )
300 	{
301 		m_sBuffer = s.Mid( i, s.Length()-i );
302 	}
303 }
304 
305 /** */
DataTimeout()306 void CClient::DataTimeout()
307 {
308 	SendString("|");
309 }
310 
311 /** */
Notify()312 void CClient::Notify()
313 {
314 	if ( !CConfig::Instance() )
315 		return;
316 
317 	// check away mode
318 	if ( (m_bHandshake == false) && ((time(0)-m_timeMyinfoTimeout) >= 30) )
319 	{
320 		if ( CConfig::Instance()->GetAwayMode() != m_MyInfo.m_eAwayMode)
321 		{
322 			m_MyInfo.m_eAwayMode = CConfig::Instance()->GetAwayMode();
323 			m_bUpdateMyinfo = true;
324 		}
325 	}
326 
327 	if ( (m_bHandshake == false) && m_bUpdateMyinfo && ((time(0)-m_timeMyinfoTimeout) >= 30) )
328 	{
329 		m_bUpdateMyinfo     = false;
330 		m_timeMyinfoTimeout = time(0);
331 
332 		if ( m_bSendMyinfo )
333 			SendMyInfo( &m_MyInfo );
334 	}
335 
336 	if ( m_eReconnectState == ersENABLED )
337 	{
338 		if ( m_nReconnectCount >= CConfig::Instance()->GetReconnectCount() )
339 		{
340 			UpdateReconnect( ersNONE, 0 );
341 		}
342 		else
343 		{
344 			if ( GetConnectionState() != estNONE )
345 			{
346 				printf("warning, wrong reconnect state, you are connected !\n");
347 			}
348 
349 			// init timer
350 			if ( m_timeReconnectTimeout == 0 )
351 			{
352 				m_timeReconnectTimeout = time(0);
353 			}
354 
355 			if ( (time(0)-m_timeReconnectTimeout) >= CConfig::Instance()->GetReconnectTimeout() )
356 			{
357 				UpdateReconnect( ersNONE );
358 
359 				if ( CConfig::Instance()->GetReconnectCount() != 9999 )
360 				{
361 					m_nReconnectCount++;
362 				}
363 
364 				Connect();
365 			}
366 		}
367 	}
368 }
369 
370 /** */
UpdateReconnect(eReconnectState state,int count)371 void CClient::UpdateReconnect( eReconnectState state, int count )
372 {
373 	if ( !CConfig::Instance() )
374 		return;
375 
376 	// reconnect disabled
377 	if ( CConfig::Instance()->GetReconnectCount() == 0 )
378 	{
379 		m_eReconnectState = ersNONE;
380 		return;
381 	}
382 
383 	// don't change state if reconnect disables
384 	if ( (m_eReconnectState == ersDISABLED) && (state != ersNONE) )
385 	{
386 		return;
387 	}
388 
389 	// update state
390 	m_eReconnectState      = state;
391 	// reset timeout
392 	m_timeReconnectTimeout = 0;
393 	// update counter
394 	if ( count != -1 )
395 	{
396 		m_nReconnectCount = count;
397 	}
398 }
399 
400 /** */
HandleMessage(const CString & message)401 int CClient::HandleMessage( const CString & message )
402 {
403 	int err;
404 	int pointer;
405 	eDCMessage type;
406 	CDCMessage * Object = 0;
407 	CString sAnswer,s;
408 
409 	if ( message.IsEmpty() )
410 	{
411 		return 0;
412 	}
413 
414 	pointer = 0;
415 
416 	while( (type=m_pMessageHandler->Parse(&message,pointer,&Object)) != DC_MESSAGE_PARSE_ERROR )
417 	{
418 		if ( !Object )
419 		{
420 			continue;
421 		}
422 
423 		switch (type)
424 		{
425 			case DC_MESSAGE_LOCK:
426 			{
427 				CMessageLock * msg = (CMessageLock*)Object;
428 
429 				// only handle the first lock in handshake mode
430 				if ( m_bHandshake )
431 				{
432 #if DCLIB_HAS_SSL == 1
433 					if ( m_bSSLMode )
434 					{
435 						SendSSLInfo();
436 					}
437 #endif
438 					CEncrypt::Encrypt(msg->m_sData,sAnswer);
439 
440 					if ( msg->m_bExtProtocol )
441 					{
442 						/*
443 						 * Assumes NoHello NoGetINFO are supported.
444 						 * The hub may not inform us what is actually enabled in its supports.
445 						 */
446 						m_bExtProtocol = true;
447 
448 						// HubTopic No $Hellos No $GetINFO UserCommand
449 						/*
450 						 * UserIP2 now enabled always, if disabled we just do not use
451 						 * the value the hub gives us, but it gets stored in case
452 						 * the setting is changed without reconnecting to the hub.
453 						 *
454 						 * Similarly TTHSearch is always enabled because CConfig::Instance()->GetDisableHashList()
455 						 * only affects the hashing of new files. However NOTTH is added to the tag.
456 						 */
457 						s = "HubTopic NoHello NoGetINFO TTHSearch UserCommand UserIP2 ";
458 
459 						if ( CConfig::Instance() != 0 )
460 						{
461 							if ( CConfig::Instance()->GetZPipeEnabled() )
462 							{
463 								// this is what DC++ 0.699 sends
464 								// it may change later after testing finishes
465 								s += "ZPipe0 ";
466 							}
467 
468 							if ( CConfig::Instance()->GetCompressedTransfers() )
469 							{
470 								s += "GetZBlock ";
471 							}
472 						}
473 
474 						SendSupports(s);
475 						// quicklist ??? http://forum.dcstats.net/showthread.php?s=&threadid=802
476 					}
477 
478 					SendKey( sAnswer );
479 
480 					SendValidateNick( m_MyInfo.m_sNick );
481 				}
482 
483 				break;
484 			}
485 
486 			case DC_MESSAGE_LOGEDIN:
487 			{
488 				// update myinfo
489 //				if ( m_bHandleMyinfo )
490 //					CConnectionManager::Instance()->SendMyInfoToConnectedServers();
491 
492 				break;
493 			}
494 
495 			case DC_MESSAGE_HUBNAME:
496 			{
497 				CMessageHubName * msg = (CMessageHubName*)Object;
498 
499 				// set the old hubname in this message
500 				if ( GetHubName() != msg->m_sHubName )
501 					msg->m_sOldHubName = GetHubName();
502 				SetHubName(msg->m_sHubName);
503 
504 				break;
505 			}
506 
507 			case DC_MESSAGE_HUB_TOPIC:
508 			{
509 				CMessageHubTopic * msg = (CMessageHubTopic*) Object;
510 
511 				SetHubTopic(msg->m_sTopic);
512 
513 				break;
514 			}
515 
516 			case DC_MESSAGE_HELLO:
517 			{
518 				CMessageHello * msg = (CMessageHello*)Object;
519 
520 				if ( (msg->m_sNick == m_MyInfo.m_sNick) && m_bHandshake )
521 				{
522 					SendVersion();
523 
524 					// get nicklist
525 					if ( m_bHandleUserList )
526 						RequestNickList();
527 
528 					if ( m_bSendMyinfo )
529 						SendMyInfo( &m_MyInfo );
530 
531 					m_bHandshake = false;
532 
533 					// update myinfo
534 					if ( m_bHandleMyinfo && CConnectionManager::Instance() )
535 						CConnectionManager::Instance()->SendMyInfoToConnectedServers();
536 				}
537 				else if ( m_bHandleUserList )
538 				{
539 					m_UserList.AppendUser(msg->m_sNick);
540 				}
541 
542 				break;
543 			}
544 
545 			case DC_MESSAGE_MYINFO:
546 			{
547 				CMessageMyInfo * msg = (CMessageMyInfo*)Object;
548 
549 				if ( m_bHandleUserList )
550 				{
551 					if ( m_UserList.UpdateUser(msg) == false )
552 					{
553 						delete Object;
554 						Object = 0;
555 					}
556 				}
557 
558 				break;
559 			}
560 
561 			case DC_MESSAGE_QUIT:
562 			{
563 				CMessageQuit * msg = (CMessageQuit*)Object;
564 
565 				if ( m_bHandleUserList )
566 				{
567 					m_UserList.RemoveUser(msg->m_sNick);
568 #if DCLIB_HAS_SSL == 1
569 					m_pMessageSSL.LeaveHub(this,msg->m_sNick);
570 #endif
571 				}
572 
573 				break;
574 			}
575 
576 			case DC_MESSAGE_NICKLIST:
577 			{
578 				CMessageNickList * msg = (CMessageNickList*)Object;
579 
580 				if ( m_bHandleUserList )
581 				{
582 					// 0: update nicklist 1: requested nicklist
583 					if ( m_nNickListHandler == 1 )
584 					{
585 						m_UserList.Clear();
586 
587 						m_nNickListHandler = 0;
588 					}
589 
590 					m_UserList.InitUserList(msg);
591 
592 					if ( m_bExtProtocol == false )
593 					{
594 						for ( CString * nick = 0; (nick=msg->m_NickList.Next(nick))!=0; )
595 						{
596 							SendGetInfo(*nick,GetNick());
597 						}
598 					}
599 				}
600 
601 				break;
602 			}
603 
604 			case DC_MESSAGE_OPLIST:
605 			{
606 				CMessageOpList * msg = (CMessageOpList*)Object;
607 
608 				// operators allready in the userlist
609 				if ( m_bHandleUserList )
610 				{
611 					// init operator list
612 					m_UserList.InitOperatorList(msg);
613 				}
614 				break;
615 			}
616 
617 			case DC_MESSAGE_SEARCH_FILE:
618 			{
619 				bool search = true;
620 				CMessageSearchFile * msg = (CMessageSearchFile*)Object;
621 
622 				if ( m_bHandleSearch )
623 				{
624 					// check for loopback search
625 					if ( msg->m_bLocal )
626 					{
627 						if ( msg->m_sSource == GetNick() )
628 						{
629 							search = false;
630 						}
631 					}
632 					else
633 					{
634 						// disable global search, compare search with own ip and port
635 						// also check private address space settings and IP
636 						if ( CConfig::Instance() )
637 						{
638 							if ( (msg->m_nPort == CConfig::Instance()->GetUDPListenPort()) &&
639 							     (msg->m_sSource == GetExternalIP(false)) )
640 							{
641 								search = false;
642 							}
643 							else if ( ( CConfig::Instance()->GetCheckPrivateAddressSpace() &&
644 							            CNetAddr::IsPrivateI4(msg->m_sSource.Data()) ) ||
645 								  ( CConfig::Instance()->GetPrivateAddressSpaceOnly() &&
646 								    (CNetAddr::IsPrivateI4(msg->m_sSource.Data()) == false)) )
647 							{
648 								DPRINTF("Ignoring search from %s due to private address space settings\n",msg->m_sSource.Data());
649 								search = false;
650 							}
651 						}
652 					}
653 
654 					if ( search && (CQueryManager::Instance() != 0) )
655 					{
656 						CQueryManager::Instance()->SearchQuery( GetHubName(), GetResolvedIP(), GetNick(), msg );
657 					}
658 				}
659 
660 				break;
661 			}
662 
663 			case DC_MESSAGE_SEARCHRESULT:
664 			{
665 				// fix hub name
666 				CMessageSearchResult * msg = (CMessageSearchResult *) Object;
667 				if ( msg->m_sHubName == msg->m_sHubHost )
668 				{
669 					msg->m_sHubName = GetHubName();
670 				}
671 
672 				if ( CSearchManager::Instance() )
673 					if ( CSearchManager::Instance()->HandleSearch( msg ) )
674 						Object = 0;
675 				break;
676 			}
677 
678 			case DC_MESSAGE_CONNECTTOME:
679 			{
680 				CMessageConnectToMe * msg = (CMessageConnectToMe*) Object;
681 
682 				if ( m_bHandleTransfer )
683 				{
684 					if ( CDownloadManager::Instance() )
685 						CDownloadManager::Instance()->DLM_AddTransferRequest( msg->m_sHost, msg->m_nPort, msg->m_bCrypto, GetHubName(), GetHost() );
686 				}
687 
688 				break;
689 			}
690 
691 			case DC_MESSAGE_REVCONNECTTOME:
692 			{
693 				CMessageRevConnectToMe * msg = (CMessageRevConnectToMe*) Object;
694 
695 				if ( CConfig::Instance() && (GetMode() == ecmACTIVE) && m_bHandleTransfer )
696 				{
697 #if DCLIB_HAS_SSL == 1
698 					CMessageMyInfo usermyinfo;
699 					bool crypto = ( m_MyInfo.m_bTLSFlag && m_UserList.GetUserMyInfo(msg->m_sDstNick,&usermyinfo) && usermyinfo.m_bTLSFlag );
700 #else
701 					bool crypto = false;
702 #endif
703 					CString s = GetExternalIP( true, crypto );
704 
705 					if ( s.NotEmpty() )
706 					{
707 						if ( CDownloadManager::Instance() &&
708 						     CDownloadManager::Instance()->DLM_AddTransferRequest( msg->m_sDstNick, CString(), GetHubName(), GetHost() ) )
709 						{
710 							SendConnectToMe(msg->m_sDstNick,s,crypto);
711 						}
712 					}
713 				}
714 
715 				break;
716 			}
717 
718 			case DC_MESSAGE_FORCEMOVE:
719 			{
720 				CMessageForceMove * msg = (CMessageForceMove*) Object;
721 
722 				if ( CConfig::Instance() &&
723 				     CConfig::Instance()->GetForceMoveEnabled() && m_bHandleForceMove )
724 				{
725 					SetHubName(msg->m_sHost);
726 
727 					UpdateReconnect( ersFORCEMOVE, 0 );
728 
729 					Connect(msg->m_sHost,msg->m_nPort);
730 				}
731 
732 				break;
733 			}
734 
735 			case DC_MESSAGE_PRIVATECHAT:
736 			{
737 				CMessagePrivateChat * msg = (CMessagePrivateChat*) Object;
738 
739 				/* default to receiving all messages if no CConfig */
740 				if ( CConfig::Instance() &&
741 				     (CConfig::Instance()->GetChatRecvFromOffline() == false) &&
742 				     (m_UserList.IsUserOnline(msg->m_sSrcNick) == false) )
743 				{
744 					delete Object;
745 					Object = 0;
746 					msg = 0;
747 				}
748 #if DCLIB_HAS_SSL == 1
749 				if ( msg )
750 				{
751 					m_pMessageSSL.PrivateChat(this,msg);
752 				}
753 #endif
754 				break;
755 			}
756 
757 			case DC_MESSAGE_SUPPORTS:
758 			{
759 				/*
760 				 * Interesting. Since hubs may not send all the strings they support
761 				 * it turns out there is currently nothing we can do with the supports message.
762 				 */
763 
764 				break;
765 			}
766 
767 			case DC_MESSAGE_USERIP:
768 			{
769 				CMessageUserIP * msg = (CMessageUserIP*) Object;
770 
771 				std::list<CString>::const_iterator nick_it = msg->m_lNicks.begin();
772 				std::list<CString>::const_iterator ip_it = msg->m_lIPs.begin();
773 
774 				while ( (nick_it != msg->m_lNicks.end()) && (ip_it != msg->m_lIPs.end()) )
775 				{
776 					if ( m_bHandleUserList )
777 					{
778 						m_UserList.SetUserIP( *nick_it, *ip_it );
779 					}
780 
781 					if ( GetNick() == *nick_it )
782 					{
783 						if ( CNetAddr::IsValidI4( ip_it->Data() ) )
784 						{
785 							m_sExternalIP = *ip_it;
786 							m_bGotIP = true;
787 						}
788 					}
789 
790 					++nick_it;
791 					++ip_it;
792 				}
793 
794 				break;
795 			}
796 
797 			default:
798 			{
799 				break;
800 			}
801 		}
802 
803 		if (Object)
804 		{
805 			if ( m_pCallback != 0 )
806 			{
807 				err = m_pCallback->notify( this, Object );
808 			}
809 			else
810 			{
811 				err = DC_CallBack( Object );
812 			}
813 
814 			if ( err == -1 )
815 			{
816 				delete Object;
817 			}
818 		}
819 	}
820 
821 	return 0;
822 }
823 
824 /** */
SetUserTransferInfo(CString nick,CDCMessage * msg)825 bool CClient::SetUserTransferInfo( CString nick, CDCMessage * msg )
826 {
827 	int err;
828 	bool res = false;
829 	CMessageMyInfo myinfo,*mi;
830 
831 	if ( m_UserList.SetUserTransferInfo(nick,msg) )
832 	{
833 		if ( m_UserList.GetUserMyInfo( nick, &myinfo ) )
834 		{
835 			mi = new CMessageMyInfo();
836 			*mi = myinfo;
837 
838 			if ( m_pCallback != 0 )
839 			{
840 				err = m_pCallback->notify( this, mi );
841 			}
842 			else
843 			{
844 				err = DC_CallBack( mi );
845 			}
846 
847 			if ( err == -1 )
848 			{
849 				delete mi;
850 			}
851 
852 			res = true;
853 		}
854 	}
855 
856 	return res;
857 }
858 
859 /** send private message */
SendPrivateMessage(CString sNick,CString sTo,CString sMsg,CString sFromNick)860 int CClient::SendPrivateMessage( CString sNick, CString sTo, CString sMsg, CString sFromNick )
861 {
862 	int i=-1;
863 	CString s;
864 
865 	if ( (CConfig::Instance() && CConfig::Instance()->GetChatSendToOffline()) ||
866 	     m_UserList.IsUserOnline( sTo ) )
867 	{
868 #if DCLIB_HAS_SSL == 1
869 		s = m_pMessageSSL.EncryptMessage( this, sTo, sMsg );
870 
871 		if ( s.NotEmpty() )
872 		{
873 			sMsg = s;
874 		}
875 #endif
876 
877 		i = CDCProto::SendPrivateMessage( sNick, sTo, sMsg, sFromNick );
878 	}
879 
880 	return i;
881 }
882 
883 /** */
RequestNickList()884 int CClient::RequestNickList()
885 {
886 	int res = 0;
887 
888 	if ( m_nNickListHandler == 0 )
889 	{
890 		res = CDCProto::RequestNickList();
891 
892 		// if set, we will never recv a nicklist
893 		// hubs may not put NoGetINFO into their supports even if it is enabled
894 		if ( m_bExtProtocol == false )
895 		{
896 			m_nNickListHandler = 1;
897 		}
898 	}
899 	else
900 	{
901 		printf("We are still waiting for a NickList.\n");
902 	}
903 
904 	return res;
905 }
906 
907 /** */
Disconnect(bool force)908 int CClient::Disconnect( bool force )
909 {
910 	UpdateReconnect( ersDISABLED );
911 
912 	SetUsedPassword(false);
913 
914 	return CConnection::Disconnect(force);
915 }
916 
917 /** */
GetExternalIP(bool addport,bool crypto) const918 CString CClient::GetExternalIP( bool addport, bool crypto ) const
919 {
920 	/*
921 	 * If the hub does not support UserIP2 then the value we got from CConfig
922 	 * will be used.
923 	 */
924 	if ( CConfig::Instance() && (CConfig::Instance()->GetUserIP2Enabled() == false) )
925 	{
926 		return CConfig::Instance()->GetTCPHostString( addport, crypto );
927 	}
928 	else if ( m_bGotIP )
929 	{
930 		if ( addport )
931 		{
932 			unsigned int port = 0;
933 
934 			if ( crypto )
935 			{
936 				if ( CCryptoListenManager::Instance() )
937 				{
938 					port = CCryptoListenManager::Instance()->GetListenPort();
939 				}
940 			}
941 			else
942 			{
943 				if ( CListenManager::Instance() )
944 				{
945 					port = CListenManager::Instance()->GetListenPort();
946 				}
947 			}
948 
949 			if ( port != 0 )
950 			{
951 				return m_sExternalIP + ":" + CString::number(port);
952 			}
953 			else
954 			{
955 				return m_sExternalIP;
956 			}
957 		}
958 		else
959 		{
960 			return m_sExternalIP;
961 		}
962 	}
963 	else if ( CConfig::Instance() )
964 	{
965 		return CConfig::Instance()->GetTCPHostString( addport, crypto );
966 	}
967 	else
968 	{
969 		/* no IP from hub and no CConfig to get one from! */
970 		return "127.0.0.1";
971 	}
972 }
973 
974 /** */
SendSearch(CMessageSearchFile * msg)975 int CClient::SendSearch( CMessageSearchFile * msg )
976 {
977 
978 	if ( msg->m_bLocal )
979 	{
980 		/* fix nick for passive search */
981 		msg->m_sSource = GetNick();
982 	}
983 	else
984 	{
985 		/*
986 		 * GetExternalIP() handles if we have an IP from the hub and if we are supposed to use it or not
987 		 * it uses GetTCPHostString() but without adding the port this is the same as GetUDPHostString()
988 		 */
989 		msg->m_sSource = GetExternalIP(false,false) + ":" + CString::number(CConfig::Instance()->GetUDPListenPort());
990 	}
991 
992 	return CDCProto::SendSearch( msg );
993 }
994 
995 /** */
SendSSLInfo()996 void CClient::SendSSLInfo()
997 {
998 	CMessageLog * log1 = new CMessageLog();
999 
1000 	log1->sMessage  = GetSSLVersion();
1001 	log1->sMessage += " connection using ";
1002 	log1->sMessage += GetSSLCipher();
1003 
1004 	int err;
1005 	if ( m_pCallback )
1006 	{
1007 		err = m_pCallback->notify( this, log1 );
1008 	}
1009 	else
1010 	{
1011 		err = DC_CallBack( log1 );
1012 	}
1013 
1014 	if ( err == -1 )
1015 	{
1016 		delete log1;
1017 	}
1018 
1019 	CMessageLog * log2 = new CMessageLog();
1020 	log2->sMessage = VerifyPeerCertificate();
1021 
1022 	if ( m_pCallback )
1023 	{
1024 		err = m_pCallback->notify( this, log2 );
1025 	}
1026 	else
1027 	{
1028 		err = DC_CallBack( log2 );
1029 	}
1030 
1031 	if ( err == -1 )
1032 	{
1033 		delete log2;
1034 	}
1035 }
1036